├── .gitignore
├── README.md
├── _cli_stub.php
├── build.xml
├── composer.json
├── composer.lock
├── example-config.php
├── magento-tar-to-connect.phar
├── magento-tar-to-connect.php
├── src
└── magento
│ └── downloader
│ └── lib
│ └── Mage
│ ├── Archive
│ ├── Abstract.php
│ ├── Helper
│ │ └── File.php
│ ├── Interface.php
│ └── Tar.php
│ └── Exception.php
└── tests
├── AuthorTest.php
├── ExampleTest.php
├── MagentoTarToConnectBaseTest.php
├── WhoTestsTheTestsTest.php
└── fixtures
├── Pulsestorm_Better404.tar
├── first.tar
└── first.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor/
2 | /tests/fixtures/build
3 | /tests/fixtures/build-artifacts
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MagentoTarToConnect
2 | ===================
3 |
4 | A small shell script to automatically package tar archives into Magento's Connect 2.0 format.
5 |
6 | ### Description
7 |
8 | Under the hood Magento Connect 2.0 packages (Magento Connect 2.0 was introduced around the time of Magento CE 1.5) are actually tar'ed and gziped files with a specially formatted package manifest. Well, they're almost `tar` and `gzip` files. Magento implemented their own archiving and unarchiving code in PHP, and this code occasionally has problems with tar archives created via standard OS tools.
9 |
10 | This shell script will take a standard tar archive, untar it, build the Connect `package.xml` manifest, and then re-tar and gzip the files **using Magento's code** (included in the `vendor` library here, but you can substitute your own). This decreases the likelihood your package will be incompatible with Magento Connect.
11 |
12 | ## Usage
13 |
14 | The syntax for using this script is as following
15 |
16 | $ ./magento-tar-to-connect.php example-config.php
17 |
18 | Where `example-config.php` is a PHP file which returns a set of configuration key/value pairs. These key/value pairs provide the script with the location of an archive file, the output location, as well as the bare minimum Magento Connect fields needed to create a valid extension. An example file might look something like this
19 |
20 | '/fakehome/Documents/github/Pulsestorm/var/build',
26 | 'archive_files' => 'Pulstorm_Example.tar',
27 |
28 | //The Magento Connect extension name. Must be unique on Magento Connect
29 | //Has no relation to your code module name. Will be the Connect extension name
30 | 'extension_name' => 'Pulstorm_Example',
31 |
32 | //Your extension version. By default, if you're creating an extension from a
33 | //single Magento module, the tar-to-connect script will look to make sure this
34 | //matches the module version. You can skip this check by setting the
35 | //skip_version_compare value to true
36 | 'extension_version' => '1.0.3',
37 | 'skip_version_compare' => false,
38 |
39 | //You can also have the package script use the version in the module you
40 | //are packaging with.
41 | 'auto_detect_version' => false,
42 |
43 | //Where on your local system you'd like to build the files to
44 | 'path_output' => '/fakehome/Pulsestorm/var/build-connect',
45 |
46 | //Magento Connect license value.
47 | 'stability' => 'stable',
48 |
49 | //Magento Connect license value
50 | 'license' => 'MIT',
51 |
52 | //Magento Connect channel value. This should almost always (always?) be community
53 | 'channel' => 'community',
54 |
55 | //Magento Connect information fields.
56 | 'summary' => 'Provides navigation shortcuts for the admin console\'s navigation and global search',
57 | 'description' => 'This extension provides Magento admin console users with an "application launcher". This application launcher provides instant access to the admin console\'s navigation, every system configuration search section, as well as the Magento global search. The Pulse Storm launcher is a free, open source, must have extension for anyone working with Magento. ',
58 | 'notes' => 'Typo fixes, properly aborts ajax requests.',
59 |
60 | //Magento Connect author information. If author_email is foo@example.com, script will
61 | //prompt you for the correct name. Should match your http://www.magentocommerce.com/
62 | //login email address
63 | 'author_name' => 'Alan Storm',
64 | 'author_user' => 'alanstorm',
65 | 'author_email' => 'foo@example.com',
66 |
67 | //PHP min/max fields for Connect. I don't know if anyone uses these, but you should
68 | //probably check that they're accurate
69 | 'php_min' => '5.2.0',
70 | 'php_max' => '6.0.0'
71 | );
72 |
73 | ## Building a `phar` with Phing
74 |
75 | The project also includes a `phing` build.xml file. You can use this to create an executable `phar` of the script. If you're not familiar, a `phar` is sort of like a stand alone PHP executable. You can [read more here](http://php.net/phar).
76 |
77 | $ phing create_phar
78 |
79 | This will create a new `magento-tar-to-connect.phar` file in the main project directory.
80 |
81 | ## Running the script stand alone
82 |
83 | If you don't know how to use `phing` or `phar` files, you can run the scripts by copying
84 |
85 | 1. `magento-tar-to-connect.php`
86 | 2. And the `src/magento` folder
87 |
88 | To wherever you run your scripts from.
89 |
90 | ## Composer and Unit Tests
91 |
92 | [PHP Composer](https://getcomposer.org/) is not required to run this project. However, we've included `composer.json` for installing `phpunit`. After running `composer install` or `composer update`, you'll be able to run the unit tests with the following
93 |
94 | vendor/bin/phpunit tests
95 |
96 | Tests should be placed in
97 |
98 | tests/
99 |
100 | See the test file
101 |
102 | tests/ExampleTest.php
103 |
104 | for instructions on how to load a test fixture (i.e. archive), and automatically build a `tgz` Magento connect extension from it.
--------------------------------------------------------------------------------
/_cli_stub.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | setPharMode(true);
8 | // $application->run();
9 |
10 | __HALT_COMPILER();
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pulsestorm/magento-tar-to-connect",
3 | "description": "A duct-tape shell script for packaging Magento Extenstions",
4 | "authors": [
5 | {
6 | "name": "Alan Storm",
7 | "email": "astorm@alanstorm.com"
8 | }
9 | ],
10 | "require": {
11 |
12 | },
13 | "require-dev": {
14 | "phpunit/phpunit": "4.2.*",
15 | "pear/archive_tar": "1.3.*"
16 | },
17 | "autoload": {
18 | "classmap": [
19 | "tests/MagentoTarToConnectBaseTest.php"
20 | ]
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "ce2901b464a4811d5fc585a394507f85",
8 | "packages": [
9 |
10 | ],
11 | "packages-dev": [
12 | {
13 | "name": "ocramius/instantiator",
14 | "version": "1.1.3",
15 | "source": {
16 | "type": "git",
17 | "url": "https://github.com/Ocramius/Instantiator.git",
18 | "reference": "e24a12178906ff2e7471b8aaf3a0eb789b59f881"
19 | },
20 | "dist": {
21 | "type": "zip",
22 | "url": "https://api.github.com/repos/Ocramius/Instantiator/zipball/e24a12178906ff2e7471b8aaf3a0eb789b59f881",
23 | "reference": "e24a12178906ff2e7471b8aaf3a0eb789b59f881",
24 | "shasum": ""
25 | },
26 | "require": {
27 | "ocramius/lazy-map": "1.0.*",
28 | "php": "~5.3"
29 | },
30 | "require-dev": {
31 | "athletic/athletic": "~0.1.8",
32 | "ext-pdo": "*",
33 | "ext-phar": "*",
34 | "phpunit/phpunit": "~4.0",
35 | "squizlabs/php_codesniffer": "2.0.*@ALPHA"
36 | },
37 | "type": "library",
38 | "extra": {
39 | "branch-alias": {
40 | "dev-master": "2.0.x-dev"
41 | }
42 | },
43 | "autoload": {
44 | "psr-0": {
45 | "Instantiator\\": "src"
46 | }
47 | },
48 | "notification-url": "https://packagist.org/downloads/",
49 | "license": [
50 | "MIT"
51 | ],
52 | "authors": [
53 | {
54 | "name": "Marco Pivetta",
55 | "email": "ocramius@gmail.com",
56 | "homepage": "http://ocramius.github.com/"
57 | }
58 | ],
59 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
60 | "homepage": "https://github.com/Ocramius/Instantiator",
61 | "keywords": [
62 | "constructor",
63 | "instantiate"
64 | ],
65 | "time": "2014-08-25 14:48:16"
66 | },
67 | {
68 | "name": "ocramius/lazy-map",
69 | "version": "1.0.0",
70 | "source": {
71 | "type": "git",
72 | "url": "https://github.com/Ocramius/LazyMap.git",
73 | "reference": "7fe3d347f5e618bcea7d39345ff83f3651d8b752"
74 | },
75 | "dist": {
76 | "type": "zip",
77 | "url": "https://api.github.com/repos/Ocramius/LazyMap/zipball/7fe3d347f5e618bcea7d39345ff83f3651d8b752",
78 | "reference": "7fe3d347f5e618bcea7d39345ff83f3651d8b752",
79 | "shasum": ""
80 | },
81 | "require": {
82 | "php": ">=5.3.3"
83 | },
84 | "require-dev": {
85 | "athletic/athletic": "~0.1.6",
86 | "phpmd/phpmd": "1.5.*",
87 | "phpunit/phpunit": ">=3.7",
88 | "satooshi/php-coveralls": "~0.6",
89 | "squizlabs/php_codesniffer": "1.4.*"
90 | },
91 | "type": "library",
92 | "extra": {
93 | "branch-alias": {
94 | "dev-master": "1.0.x-dev"
95 | }
96 | },
97 | "autoload": {
98 | "psr-0": {
99 | "LazyMap\\": "src"
100 | }
101 | },
102 | "notification-url": "https://packagist.org/downloads/",
103 | "license": [
104 | "MIT"
105 | ],
106 | "authors": [
107 | {
108 | "name": "Marco Pivetta",
109 | "email": "ocramius@gmail.com",
110 | "homepage": "http://ocramius.github.com/",
111 | "role": "Developer"
112 | }
113 | ],
114 | "description": "A library that provides lazy instantiation logic for a map of objects",
115 | "homepage": "https://github.com/Ocramius/LazyMap",
116 | "keywords": [
117 | "lazy",
118 | "lazy instantiation",
119 | "lazy loading",
120 | "map",
121 | "service location"
122 | ],
123 | "time": "2013-11-09 22:30:54"
124 | },
125 | {
126 | "name": "pear/archive_tar",
127 | "version": "1.3.11",
128 | "source": {
129 | "type": "git",
130 | "url": "https://github.com/pear/Archive_Tar.git",
131 | "reference": "23341344e19bbab1056cf2d2773f28cfccf787a3"
132 | },
133 | "dist": {
134 | "type": "zip",
135 | "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/23341344e19bbab1056cf2d2773f28cfccf787a3",
136 | "reference": "23341344e19bbab1056cf2d2773f28cfccf787a3",
137 | "shasum": ""
138 | },
139 | "require": {
140 | "php": ">=4.3.0"
141 | },
142 | "type": "library",
143 | "autoload": {
144 | "psr-0": {
145 | "Archive_Tar": ""
146 | }
147 | },
148 | "notification-url": "https://packagist.org/downloads/",
149 | "license": [
150 | "BSD-3-Clause"
151 | ],
152 | "authors": [
153 | {
154 | "name": "Michiel Rook",
155 | "email": "mrook@php.net",
156 | "role": "Lead"
157 | },
158 | {
159 | "name": "Vincent Blavet",
160 | "email": "vincent@phpconcept.net"
161 | },
162 | {
163 | "name": "Greg Beaver",
164 | "email": "greg@chiaraquartet.net"
165 | }
166 | ],
167 | "description": "Tar file management class",
168 | "homepage": "https://github.com/pear/Archive_Tar",
169 | "keywords": [
170 | "archive",
171 | "tar"
172 | ],
173 | "time": "2013-02-09 11:44:32"
174 | },
175 | {
176 | "name": "phpunit/php-code-coverage",
177 | "version": "2.0.11",
178 | "source": {
179 | "type": "git",
180 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
181 | "reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7"
182 | },
183 | "dist": {
184 | "type": "zip",
185 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/53603b3c995f5aab6b59c8e08c3a663d2cc810b7",
186 | "reference": "53603b3c995f5aab6b59c8e08c3a663d2cc810b7",
187 | "shasum": ""
188 | },
189 | "require": {
190 | "php": ">=5.3.3",
191 | "phpunit/php-file-iterator": "~1.3",
192 | "phpunit/php-text-template": "~1.2",
193 | "phpunit/php-token-stream": "~1.3",
194 | "sebastian/environment": "~1.0",
195 | "sebastian/version": "~1.0"
196 | },
197 | "require-dev": {
198 | "ext-xdebug": ">=2.1.4",
199 | "phpunit/phpunit": "~4.1"
200 | },
201 | "suggest": {
202 | "ext-dom": "*",
203 | "ext-xdebug": ">=2.2.1",
204 | "ext-xmlwriter": "*"
205 | },
206 | "type": "library",
207 | "extra": {
208 | "branch-alias": {
209 | "dev-master": "2.0.x-dev"
210 | }
211 | },
212 | "autoload": {
213 | "classmap": [
214 | "src/"
215 | ]
216 | },
217 | "notification-url": "https://packagist.org/downloads/",
218 | "include-path": [
219 | ""
220 | ],
221 | "license": [
222 | "BSD-3-Clause"
223 | ],
224 | "authors": [
225 | {
226 | "name": "Sebastian Bergmann",
227 | "email": "sb@sebastian-bergmann.de",
228 | "role": "lead"
229 | }
230 | ],
231 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
232 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
233 | "keywords": [
234 | "coverage",
235 | "testing",
236 | "xunit"
237 | ],
238 | "time": "2014-08-31 06:33:04"
239 | },
240 | {
241 | "name": "phpunit/php-file-iterator",
242 | "version": "1.3.4",
243 | "source": {
244 | "type": "git",
245 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
246 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb"
247 | },
248 | "dist": {
249 | "type": "zip",
250 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb",
251 | "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb",
252 | "shasum": ""
253 | },
254 | "require": {
255 | "php": ">=5.3.3"
256 | },
257 | "type": "library",
258 | "autoload": {
259 | "classmap": [
260 | "File/"
261 | ]
262 | },
263 | "notification-url": "https://packagist.org/downloads/",
264 | "include-path": [
265 | ""
266 | ],
267 | "license": [
268 | "BSD-3-Clause"
269 | ],
270 | "authors": [
271 | {
272 | "name": "Sebastian Bergmann",
273 | "email": "sb@sebastian-bergmann.de",
274 | "role": "lead"
275 | }
276 | ],
277 | "description": "FilterIterator implementation that filters files based on a list of suffixes.",
278 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
279 | "keywords": [
280 | "filesystem",
281 | "iterator"
282 | ],
283 | "time": "2013-10-10 15:34:57"
284 | },
285 | {
286 | "name": "phpunit/php-text-template",
287 | "version": "1.2.0",
288 | "source": {
289 | "type": "git",
290 | "url": "https://github.com/sebastianbergmann/php-text-template.git",
291 | "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a"
292 | },
293 | "dist": {
294 | "type": "zip",
295 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
296 | "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a",
297 | "shasum": ""
298 | },
299 | "require": {
300 | "php": ">=5.3.3"
301 | },
302 | "type": "library",
303 | "autoload": {
304 | "classmap": [
305 | "Text/"
306 | ]
307 | },
308 | "notification-url": "https://packagist.org/downloads/",
309 | "include-path": [
310 | ""
311 | ],
312 | "license": [
313 | "BSD-3-Clause"
314 | ],
315 | "authors": [
316 | {
317 | "name": "Sebastian Bergmann",
318 | "email": "sb@sebastian-bergmann.de",
319 | "role": "lead"
320 | }
321 | ],
322 | "description": "Simple template engine.",
323 | "homepage": "https://github.com/sebastianbergmann/php-text-template/",
324 | "keywords": [
325 | "template"
326 | ],
327 | "time": "2014-01-30 17:20:04"
328 | },
329 | {
330 | "name": "phpunit/php-timer",
331 | "version": "1.0.5",
332 | "source": {
333 | "type": "git",
334 | "url": "https://github.com/sebastianbergmann/php-timer.git",
335 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c"
336 | },
337 | "dist": {
338 | "type": "zip",
339 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
340 | "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c",
341 | "shasum": ""
342 | },
343 | "require": {
344 | "php": ">=5.3.3"
345 | },
346 | "type": "library",
347 | "autoload": {
348 | "classmap": [
349 | "PHP/"
350 | ]
351 | },
352 | "notification-url": "https://packagist.org/downloads/",
353 | "include-path": [
354 | ""
355 | ],
356 | "license": [
357 | "BSD-3-Clause"
358 | ],
359 | "authors": [
360 | {
361 | "name": "Sebastian Bergmann",
362 | "email": "sb@sebastian-bergmann.de",
363 | "role": "lead"
364 | }
365 | ],
366 | "description": "Utility class for timing",
367 | "homepage": "https://github.com/sebastianbergmann/php-timer/",
368 | "keywords": [
369 | "timer"
370 | ],
371 | "time": "2013-08-02 07:42:54"
372 | },
373 | {
374 | "name": "phpunit/php-token-stream",
375 | "version": "1.3.0",
376 | "source": {
377 | "type": "git",
378 | "url": "https://github.com/sebastianbergmann/php-token-stream.git",
379 | "reference": "f8d5d08c56de5cfd592b3340424a81733259a876"
380 | },
381 | "dist": {
382 | "type": "zip",
383 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876",
384 | "reference": "f8d5d08c56de5cfd592b3340424a81733259a876",
385 | "shasum": ""
386 | },
387 | "require": {
388 | "ext-tokenizer": "*",
389 | "php": ">=5.3.3"
390 | },
391 | "require-dev": {
392 | "phpunit/phpunit": "~4.2"
393 | },
394 | "type": "library",
395 | "extra": {
396 | "branch-alias": {
397 | "dev-master": "1.3-dev"
398 | }
399 | },
400 | "autoload": {
401 | "classmap": [
402 | "src/"
403 | ]
404 | },
405 | "notification-url": "https://packagist.org/downloads/",
406 | "license": [
407 | "BSD-3-Clause"
408 | ],
409 | "authors": [
410 | {
411 | "name": "Sebastian Bergmann",
412 | "email": "sebastian@phpunit.de"
413 | }
414 | ],
415 | "description": "Wrapper around PHP's tokenizer extension.",
416 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/",
417 | "keywords": [
418 | "tokenizer"
419 | ],
420 | "time": "2014-08-31 06:12:13"
421 | },
422 | {
423 | "name": "phpunit/phpunit",
424 | "version": "4.2.6",
425 | "source": {
426 | "type": "git",
427 | "url": "https://github.com/sebastianbergmann/phpunit.git",
428 | "reference": "c28a790620fe30b049bb693be1ef9cd4e0fe906c"
429 | },
430 | "dist": {
431 | "type": "zip",
432 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c28a790620fe30b049bb693be1ef9cd4e0fe906c",
433 | "reference": "c28a790620fe30b049bb693be1ef9cd4e0fe906c",
434 | "shasum": ""
435 | },
436 | "require": {
437 | "ext-dom": "*",
438 | "ext-json": "*",
439 | "ext-pcre": "*",
440 | "ext-reflection": "*",
441 | "ext-spl": "*",
442 | "php": ">=5.3.3",
443 | "phpunit/php-code-coverage": "~2.0",
444 | "phpunit/php-file-iterator": "~1.3.1",
445 | "phpunit/php-text-template": "~1.2",
446 | "phpunit/php-timer": "~1.0.2",
447 | "phpunit/phpunit-mock-objects": "~2.2",
448 | "sebastian/comparator": "~1.0",
449 | "sebastian/diff": "~1.1",
450 | "sebastian/environment": "~1.0",
451 | "sebastian/exporter": "~1.0",
452 | "sebastian/version": "~1.0",
453 | "symfony/yaml": "~2.0"
454 | },
455 | "suggest": {
456 | "phpunit/php-invoker": "~1.1"
457 | },
458 | "bin": [
459 | "phpunit"
460 | ],
461 | "type": "library",
462 | "extra": {
463 | "branch-alias": {
464 | "dev-master": "4.2.x-dev"
465 | }
466 | },
467 | "autoload": {
468 | "classmap": [
469 | "src/"
470 | ]
471 | },
472 | "notification-url": "https://packagist.org/downloads/",
473 | "include-path": [
474 | "",
475 | "../../symfony/yaml/"
476 | ],
477 | "license": [
478 | "BSD-3-Clause"
479 | ],
480 | "authors": [
481 | {
482 | "name": "Sebastian Bergmann",
483 | "email": "sebastian@phpunit.de",
484 | "role": "lead"
485 | }
486 | ],
487 | "description": "The PHP Unit Testing framework.",
488 | "homepage": "http://www.phpunit.de/",
489 | "keywords": [
490 | "phpunit",
491 | "testing",
492 | "xunit"
493 | ],
494 | "time": "2014-09-14 09:31:24"
495 | },
496 | {
497 | "name": "phpunit/phpunit-mock-objects",
498 | "version": "2.2.1",
499 | "source": {
500 | "type": "git",
501 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
502 | "reference": "b241b18d87a47093f20fae8b0ba40379b00bd53a"
503 | },
504 | "dist": {
505 | "type": "zip",
506 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/b241b18d87a47093f20fae8b0ba40379b00bd53a",
507 | "reference": "b241b18d87a47093f20fae8b0ba40379b00bd53a",
508 | "shasum": ""
509 | },
510 | "require": {
511 | "ocramius/instantiator": "~1.0",
512 | "php": ">=5.3.3",
513 | "phpunit/php-text-template": "~1.2"
514 | },
515 | "require-dev": {
516 | "phpunit/phpunit": "~4.2"
517 | },
518 | "suggest": {
519 | "ext-soap": "*"
520 | },
521 | "type": "library",
522 | "extra": {
523 | "branch-alias": {
524 | "dev-master": "2.2.x-dev"
525 | }
526 | },
527 | "autoload": {
528 | "classmap": [
529 | "src/"
530 | ]
531 | },
532 | "notification-url": "https://packagist.org/downloads/",
533 | "license": [
534 | "BSD-3-Clause"
535 | ],
536 | "authors": [
537 | {
538 | "name": "Sebastian Bergmann",
539 | "email": "sb@sebastian-bergmann.de",
540 | "role": "lead"
541 | }
542 | ],
543 | "description": "Mock Object library for PHPUnit",
544 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
545 | "keywords": [
546 | "mock",
547 | "xunit"
548 | ],
549 | "time": "2014-09-06 17:32:37"
550 | },
551 | {
552 | "name": "sebastian/comparator",
553 | "version": "1.0.0",
554 | "source": {
555 | "type": "git",
556 | "url": "https://github.com/sebastianbergmann/comparator.git",
557 | "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2"
558 | },
559 | "dist": {
560 | "type": "zip",
561 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2",
562 | "reference": "f7069ee51fa9fb6c038e16a9d0e3439f5449dcf2",
563 | "shasum": ""
564 | },
565 | "require": {
566 | "php": ">=5.3.3",
567 | "sebastian/diff": "~1.1",
568 | "sebastian/exporter": "~1.0"
569 | },
570 | "require-dev": {
571 | "phpunit/phpunit": "~4.1"
572 | },
573 | "type": "library",
574 | "extra": {
575 | "branch-alias": {
576 | "dev-master": "1.0.x-dev"
577 | }
578 | },
579 | "autoload": {
580 | "classmap": [
581 | "src/"
582 | ]
583 | },
584 | "notification-url": "https://packagist.org/downloads/",
585 | "license": [
586 | "BSD-3-Clause"
587 | ],
588 | "authors": [
589 | {
590 | "name": "Sebastian Bergmann",
591 | "email": "sebastian@phpunit.de",
592 | "role": "lead"
593 | },
594 | {
595 | "name": "Jeff Welch",
596 | "email": "whatthejeff@gmail.com"
597 | },
598 | {
599 | "name": "Volker Dusch",
600 | "email": "github@wallbash.com"
601 | },
602 | {
603 | "name": "Bernhard Schussek",
604 | "email": "bschussek@2bepublished.at"
605 | }
606 | ],
607 | "description": "Provides the functionality to compare PHP values for equality",
608 | "homepage": "http://www.github.com/sebastianbergmann/comparator",
609 | "keywords": [
610 | "comparator",
611 | "compare",
612 | "equality"
613 | ],
614 | "time": "2014-05-02 07:05:58"
615 | },
616 | {
617 | "name": "sebastian/diff",
618 | "version": "1.1.0",
619 | "source": {
620 | "type": "git",
621 | "url": "https://github.com/sebastianbergmann/diff.git",
622 | "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d"
623 | },
624 | "dist": {
625 | "type": "zip",
626 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d",
627 | "reference": "1e091702a5a38e6b4c1ba9ca816e3dd343df2e2d",
628 | "shasum": ""
629 | },
630 | "require": {
631 | "php": ">=5.3.3"
632 | },
633 | "type": "library",
634 | "extra": {
635 | "branch-alias": {
636 | "dev-master": "1.1-dev"
637 | }
638 | },
639 | "autoload": {
640 | "classmap": [
641 | "src/"
642 | ]
643 | },
644 | "notification-url": "https://packagist.org/downloads/",
645 | "license": [
646 | "BSD-3-Clause"
647 | ],
648 | "authors": [
649 | {
650 | "name": "Sebastian Bergmann",
651 | "email": "sebastian@phpunit.de",
652 | "role": "lead"
653 | },
654 | {
655 | "name": "Kore Nordmann",
656 | "email": "mail@kore-nordmann.de"
657 | }
658 | ],
659 | "description": "Diff implementation",
660 | "homepage": "http://www.github.com/sebastianbergmann/diff",
661 | "keywords": [
662 | "diff"
663 | ],
664 | "time": "2013-08-03 16:46:33"
665 | },
666 | {
667 | "name": "sebastian/environment",
668 | "version": "1.0.0",
669 | "source": {
670 | "type": "git",
671 | "url": "https://github.com/sebastianbergmann/environment.git",
672 | "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a"
673 | },
674 | "dist": {
675 | "type": "zip",
676 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/79517609ec01139cd7e9fded0dd7ce08c952ef6a",
677 | "reference": "79517609ec01139cd7e9fded0dd7ce08c952ef6a",
678 | "shasum": ""
679 | },
680 | "require": {
681 | "php": ">=5.3.3"
682 | },
683 | "require-dev": {
684 | "phpunit/phpunit": "4.0.*@dev"
685 | },
686 | "type": "library",
687 | "extra": {
688 | "branch-alias": {
689 | "dev-master": "1.0.x-dev"
690 | }
691 | },
692 | "autoload": {
693 | "classmap": [
694 | "src/"
695 | ]
696 | },
697 | "notification-url": "https://packagist.org/downloads/",
698 | "license": [
699 | "BSD-3-Clause"
700 | ],
701 | "authors": [
702 | {
703 | "name": "Sebastian Bergmann",
704 | "email": "sebastian@phpunit.de",
705 | "role": "lead"
706 | }
707 | ],
708 | "description": "Provides functionality to handle HHVM/PHP environments",
709 | "homepage": "http://www.github.com/sebastianbergmann/environment",
710 | "keywords": [
711 | "Xdebug",
712 | "environment",
713 | "hhvm"
714 | ],
715 | "time": "2014-02-18 16:17:19"
716 | },
717 | {
718 | "name": "sebastian/exporter",
719 | "version": "1.0.1",
720 | "source": {
721 | "type": "git",
722 | "url": "https://github.com/sebastianbergmann/exporter.git",
723 | "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529"
724 | },
725 | "dist": {
726 | "type": "zip",
727 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529",
728 | "reference": "1f9a98e6f5dfe0524cb8c6166f7c82f3e9ae1529",
729 | "shasum": ""
730 | },
731 | "require": {
732 | "php": ">=5.3.3"
733 | },
734 | "require-dev": {
735 | "phpunit/phpunit": "4.0.*@dev"
736 | },
737 | "type": "library",
738 | "extra": {
739 | "branch-alias": {
740 | "dev-master": "1.0.x-dev"
741 | }
742 | },
743 | "autoload": {
744 | "classmap": [
745 | "src/"
746 | ]
747 | },
748 | "notification-url": "https://packagist.org/downloads/",
749 | "license": [
750 | "BSD-3-Clause"
751 | ],
752 | "authors": [
753 | {
754 | "name": "Sebastian Bergmann",
755 | "email": "sebastian@phpunit.de",
756 | "role": "lead"
757 | },
758 | {
759 | "name": "Jeff Welch",
760 | "email": "whatthejeff@gmail.com"
761 | },
762 | {
763 | "name": "Volker Dusch",
764 | "email": "github@wallbash.com"
765 | },
766 | {
767 | "name": "Adam Harvey",
768 | "email": "aharvey@php.net",
769 | "role": "Lead"
770 | },
771 | {
772 | "name": "Bernhard Schussek",
773 | "email": "bschussek@2bepublished.at"
774 | }
775 | ],
776 | "description": "Provides the functionality to export PHP variables for visualization",
777 | "homepage": "http://www.github.com/sebastianbergmann/exporter",
778 | "keywords": [
779 | "export",
780 | "exporter"
781 | ],
782 | "time": "2014-02-16 08:26:31"
783 | },
784 | {
785 | "name": "sebastian/version",
786 | "version": "1.0.3",
787 | "source": {
788 | "type": "git",
789 | "url": "https://github.com/sebastianbergmann/version.git",
790 | "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43"
791 | },
792 | "dist": {
793 | "type": "zip",
794 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
795 | "reference": "b6e1f0cf6b9e1ec409a0d3e2f2a5fb0998e36b43",
796 | "shasum": ""
797 | },
798 | "type": "library",
799 | "autoload": {
800 | "classmap": [
801 | "src/"
802 | ]
803 | },
804 | "notification-url": "https://packagist.org/downloads/",
805 | "license": [
806 | "BSD-3-Clause"
807 | ],
808 | "authors": [
809 | {
810 | "name": "Sebastian Bergmann",
811 | "email": "sebastian@phpunit.de",
812 | "role": "lead"
813 | }
814 | ],
815 | "description": "Library that helps with managing the version number of Git-hosted PHP projects",
816 | "homepage": "https://github.com/sebastianbergmann/version",
817 | "time": "2014-03-07 15:35:33"
818 | },
819 | {
820 | "name": "symfony/yaml",
821 | "version": "v2.5.4",
822 | "target-dir": "Symfony/Component/Yaml",
823 | "source": {
824 | "type": "git",
825 | "url": "https://github.com/symfony/Yaml.git",
826 | "reference": "01a7695bcfb013d0a15c6757e15aae120342986f"
827 | },
828 | "dist": {
829 | "type": "zip",
830 | "url": "https://api.github.com/repos/symfony/Yaml/zipball/01a7695bcfb013d0a15c6757e15aae120342986f",
831 | "reference": "01a7695bcfb013d0a15c6757e15aae120342986f",
832 | "shasum": ""
833 | },
834 | "require": {
835 | "php": ">=5.3.3"
836 | },
837 | "type": "library",
838 | "extra": {
839 | "branch-alias": {
840 | "dev-master": "2.5-dev"
841 | }
842 | },
843 | "autoload": {
844 | "psr-0": {
845 | "Symfony\\Component\\Yaml\\": ""
846 | }
847 | },
848 | "notification-url": "https://packagist.org/downloads/",
849 | "license": [
850 | "MIT"
851 | ],
852 | "authors": [
853 | {
854 | "name": "Symfony Community",
855 | "homepage": "http://symfony.com/contributors"
856 | },
857 | {
858 | "name": "Fabien Potencier",
859 | "email": "fabien@symfony.com"
860 | }
861 | ],
862 | "description": "Symfony Yaml Component",
863 | "homepage": "http://symfony.com",
864 | "time": "2014-08-31 03:22:04"
865 | }
866 | ],
867 | "aliases": [
868 |
869 | ],
870 | "minimum-stability": "stable",
871 | "stability-flags": [
872 |
873 | ],
874 | "prefer-stable": false,
875 | "platform": [
876 |
877 | ],
878 | "platform-dev": [
879 |
880 | ]
881 | }
882 |
--------------------------------------------------------------------------------
/example-config.php:
--------------------------------------------------------------------------------
1 | '/fakehome/Documents/github/Pulsestorm/var/build',
7 | 'archive_files' => 'Pulstorm_Example.tar',
8 |
9 | //The Magento Connect extension name. Must be unique on Magento Connect
10 | //Has no relation to your code module name. Will be the Connect extension name
11 | 'extension_name' => 'Pulstorm_Example',
12 |
13 | //Your extension version. By default, if you're creating an extension from a
14 | //single Magento module, the tar-to-connect script will look to make sure this
15 | //matches the module version. You can skip this check by setting the
16 | //skip_version_compare value to true
17 | 'extension_version' => '1.0.3',
18 | 'skip_version_compare' => false,
19 |
20 | //You can also have the package script use the version in the module you
21 | //are packaging with.
22 | 'auto_detect_version' => false,
23 |
24 | //Where on your local system you'd like to build the files to
25 | 'path_output' => '/fakehome/Pulsestorm/var/build-connect',
26 |
27 | //Magento Connect license value.
28 | 'stability' => 'stable',
29 |
30 | //Magento Connect license value
31 | 'license' => 'MIT',
32 |
33 | //Magento Connect channel value. This should almost always (always?) be community
34 | 'channel' => 'community',
35 |
36 | //Magento Connect information fields.
37 | 'summary' => 'Provides navigation shortcuts for the admin console\'s navigation and gloal search',
38 | 'description' => 'This extension provides Magento admin console users with an "application launcher". This application launcher provides instant access to the admin console\'s navigation, every system configuration search section, as well as the Magento global search. The Pulse Storm launcher is a free, open source, must have extension for anyone working with Magento. ',
39 | 'notes' => 'Typo fixes, properly aborts ajax requests.',
40 |
41 | //Magento Connect author information. If author_email is foo@example.com, script will
42 | //prompt you for the correct name. Should match your http://www.magentocommerce.com/
43 | //login email address
44 | 'author_name' => 'Alan Storm',
45 | 'author_user' => 'alanstorm',
46 | 'author_email' => 'foo@example.com',
47 |
48 | // Optional: adds additional author nodes to package.xml
49 | 'additional_authors' => array(
50 | array(
51 | 'author_name' => 'Mike West',
52 | 'author_user' => 'micwest',
53 | 'author_email' => 'foo2@example.com',
54 | ),
55 | array(
56 | 'author_name' => 'Reggie Gabriel',
57 | 'author_user' => 'rgabriel',
58 | 'author_email' => 'foo3@example.com',
59 | ),
60 | ),
61 |
62 | //PHP min/max fields for Connect. I don't know if anyone uses these, but you should
63 | //probably check that they're accurate
64 | 'php_min' => '5.2.0',
65 | 'php_max' => '6.0.0',
66 |
67 | //PHP extension dependencies. An array containing one or more of either:
68 | // - a single string (the name of the extension dependency); use this if the
69 | // extension version does not matter
70 | // - an associative array with 'name', 'min', and 'max' keys which correspond
71 | // to the extension's name and min/max required versions
72 | //Example:
73 | // array('json', array('name' => 'mongo', 'min' => '1.3.0', 'max' => '1.4.0'))
74 | 'extensions' => array()
75 | );
76 |
--------------------------------------------------------------------------------
/magento-tar-to-connect.phar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/astorm/MagentoTarToConnect/4533f0aa683d58622783d3a4d614ff97e5345c7a/magento-tar-to-connect.phar
--------------------------------------------------------------------------------
/magento-tar-to-connect.php:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php
2 | xpath("dir[@name='".$part."']");
78 | if(count($nodes) > 0)
79 | {
80 | $node = array_pop($nodes);
81 | }
82 | else
83 | {
84 | $node = $node->addChild('dir');
85 | $node->addAttribute('name', $part);
86 | }
87 | }
88 |
89 | $node = $node->addChild('file');
90 | $node->addAttribute('name',$single_file);
91 | $node->addAttribute('hash',md5_file($full_dir));
92 | }
93 |
94 | static public function createPackageXml($files, $base_dir, $config)
95 | {
96 | $xml = simplexml_load_string('');
97 | $xml->name = $config['extension_name'];
98 | $xml->version = $config['extension_version'];
99 | $xml->stability = $config['stability'];
100 | $xml->license = $config['license'];
101 | $xml->channel = $config['channel'];
102 | $xml->extends = '';
103 | $xml->summary = $config['summary'];
104 | $xml->description = $config['description'];
105 | $xml->notes = $config['notes'];
106 |
107 | $authors = $xml->addChild('authors');
108 | foreach (self::getAuthorData($config) as $oneAuthor) {
109 | $author = $authors->addChild('author');
110 | $author->name = $oneAuthor['author_name'];
111 | $author->user = $oneAuthor['author_user'];
112 | $author->email = $oneAuthor['author_email'];
113 | }
114 |
115 | $xml->date = date('Y-m-d');
116 | $xml->time = date('G:i:s');
117 | $xml->compatible = '';
118 | $dependencies = $xml->addChild('dependencies');
119 | $required = $dependencies->addChild('required');
120 | $php = $required->addChild('php');
121 | $php->min = $config['php_min']; //'5.2.0';
122 | $php->max = $config['php_max']; //'6.0.0';
123 |
124 | // add php extension dependencies
125 | if (is_array($config['extensions'])) {
126 | foreach ($config['extensions'] as $extinfo) {
127 | $extension = $required->addChild('extension');
128 | if (is_array($extinfo)) {
129 | $extension->name = $extinfo['name'];
130 | $extension->min = isset($extinfo['min']) ? $extinfo['min'] : "";
131 | $extension->max = isset($extinfo['max']) ? $extinfo['max'] : "";
132 | } else {
133 | $extension->name = $extinfo;
134 | $extension->min = "";
135 | $extension->max = "";
136 | }
137 | }
138 | }
139 |
140 | $node = $xml->addChild('contents');
141 | $node = $node->addChild('target');
142 | $node->addAttribute('name', 'mage');
143 |
144 | // $files = $this->recursiveGlob($temp_dir);
145 | // $files = array_unique($files);
146 | $temp_dir = false;
147 | foreach($files as $file)
148 | {
149 | //$this->addFileNode($node,$temp_dir,$file);
150 | self::createPackageXmlAddNode($node, $file, $base_dir);
151 | }
152 | //file_put_contents($temp_dir . '/package.xml', $xml->asXml());
153 |
154 | return $xml->asXml();
155 | }
156 |
157 | static public function getTempDir()
158 | {
159 | $name = tempnam(sys_get_temp_dir(),'tmp');
160 | unlink($name);
161 | $name = $name;
162 | mkdir($name,0777,true);
163 | return $name;
164 | }
165 |
166 | static public function validateConfig($config)
167 | {
168 | $keys = array('base_dir','archive_files','path_output',
169 | );
170 | foreach($keys as $key)
171 | {
172 | if(!array_key_exists($key, $config))
173 | {
174 | self::error("Config file missing key [$key]");
175 | }
176 | }
177 |
178 | if($config['author_email'] == 'foo@example.com')
179 | {
180 | $email = self::input("Email Address is configured with foo@example.com. Enter a new address");
181 | if(trim($email) != '')
182 | {
183 | $config['author_email'] = trim($email);
184 | }
185 | }
186 |
187 | if(!array_key_exists('extensions', $config))
188 | {
189 | $config['extensions'] = null;
190 | }
191 | return $config;
192 |
193 |
194 | }
195 |
196 | static public function loadConfig($config_name=false)
197 | {
198 | if(!$config_name)
199 | {
200 | $config_name = basename(__FILE__,'php') . 'config.php';
201 | }
202 | if(!file_exists($config_name))
203 | {
204 | self::error("Could not find $config_name. Create this file, or pass in an alternate");
205 | }
206 | $config = include $config_name;
207 |
208 | $config = self::validateConfig($config);
209 | return $config;
210 | }
211 |
212 | static public function getModuleVersion($files)
213 | {
214 | $configs = array();
215 | foreach($files as $file)
216 | {
217 | if(basename($file) == 'config.xml')
218 | {
219 | $configs[] = $file;
220 | }
221 | }
222 |
223 | foreach($configs as $file)
224 | {
225 | $xml = simplexml_load_file($file);
226 | $version_strings = $xml->xpath('//version');
227 | foreach($version_strings as $version)
228 | {
229 | $version = (string) $version;
230 | if(!empty($version))
231 | {
232 | return (string)$version;
233 | }
234 | }
235 | }
236 |
237 | foreach($configs as $file)
238 | {
239 | $xml = simplexml_load_file($file);
240 | $modules = $xml->xpath('//modules');
241 | foreach($modules[0] as $module)
242 | {
243 | $version = (string)$module->version;
244 | if(!empty($version))
245 | {
246 | return $version;
247 | }
248 | }
249 | }
250 | }
251 |
252 | static public function checkModuleVersionVsPackageVersion($files, $extension_version)
253 | {
254 | $configs = array();
255 | foreach($files as $file)
256 | {
257 | if(basename($file) == 'config.xml')
258 | {
259 | $configs[] = $file;
260 | }
261 | }
262 |
263 | foreach($configs as $file)
264 | {
265 | $xml = simplexml_load_file($file);
266 | $version_strings = $xml->xpath('//version');
267 | foreach($version_strings as $version)
268 | {
269 | if($version != $extension_version)
270 | {
271 | self::error(
272 | "Extension Version [$extension_version] does not match " .
273 | "module version [$version] found in a config.xml file. Add " .
274 | "'skip_version_compare' => true to configuration to skip this check."
275 | );
276 | }
277 | }
278 | }
279 | }
280 |
281 | static public function buildExtensionFromConfig($config)
282 | {
283 | ob_start();
284 |
285 | # extract and validate config values
286 | $base_dir = $config['base_dir']; //'/Users/alanstorm/Documents/github/Pulsestorm/var/build';
287 | if($base_dir['0'] !== '/')
288 | {
289 | $base_dir = getcwd() . '/' . $base_dir;
290 | }
291 | $archive_files = $config['archive_files']; //'Pulsestorm_Modulelist.tar';
292 | $path_output = $config['path_output']; //'/Users/alanstorm/Desktop/working';
293 | $archive_connect = $config['extension_name'] . '-' . $config['extension_version'] . '.tgz';
294 | ###--------------------------------------------------
295 |
296 | # make sure the archive we're creating exists
297 | if(!file_exists($base_dir . '/' . $archive_files))
298 | {
299 | self::error('Can\'t find specified archive, bailing' . "\n[" . $base_dir . '/' . $archive_files.']');
300 | exit;
301 | }
302 | ###--------------------------------------------------
303 |
304 | # create a temporary directory, move to temporary
305 | $temp_dir = self::getTempDir();
306 | chdir($temp_dir);
307 | ###--------------------------------------------------
308 |
309 | # copy and extract archive
310 | shell_exec("cp '" . $base_dir . "/" . $archive_files . "' " . $temp_dir);
311 | if (preg_match('/\.zip$/', $archive_files)) {
312 | shell_exec("unzip -o '" . $temp_dir . "/" . $archive_files . "'");
313 | } else {
314 | shell_exec("tar -xvf '" . $temp_dir . "/" . $archive_files . "'");
315 | }
316 | shell_exec("rm '" . $temp_dir . "/" . $archive_files . "'");
317 | ###--------------------------------------------------
318 |
319 | # get a lsit of all the files without directories
320 | $all = self::globRecursive($temp_dir . '/*');
321 | $dirs = self::globRecursive($temp_dir .'/*',GLOB_ONLYDIR);
322 | $files = array_diff($all, $dirs);
323 | ###--------------------------------------------------
324 |
325 | # now that we've extracted the files, yoink the version number from the config
326 | # this only works is auto_detect_version is true. Also, may not return what
327 | # you expect if your connect extension includes multiple Magento modules
328 | if(isset($config['auto_detect_version']) && $config['auto_detect_version'] == true)
329 | {
330 | $config['extension_version'] = self::getModuleVersion($files);
331 | $archive_connect = $config['extension_name'] . '-' . $config['extension_version'] . '.tgz';
332 | }
333 | ###--------------------------------------------------
334 |
335 | # checks that your Magento Connect extension version matches the version of your
336 | # modules file. Probably redundant if auto_detect_version is true
337 | if(!$config['skip_version_compare'])
338 | {
339 | self::checkModuleVersionVsPackageVersion($files, $config['extension_version']);
340 | }
341 | ###--------------------------------------------------
342 |
343 | # creates the base extension package.xml file
344 | $xml = self::createPackageXml($files,$temp_dir,$config);
345 | file_put_contents($temp_dir . '/package.xml',$xml);
346 | self::output($temp_dir);
347 | ###--------------------------------------------------
348 |
349 | # create the base output folder if it doesn't exist
350 | if(!is_dir($path_output))
351 | {
352 | mkdir($path_output, 0777, true);
353 | }
354 | ###--------------------------------------------------
355 |
356 | # use Magento architve to tar up the files
357 | $archiver = new Mage_Archive_Tar;
358 | $archiver->pack($temp_dir,$path_output.'/'.$archive_files,true);
359 | ###--------------------------------------------------
360 |
361 | # zip up the archive
362 | shell_exec("gzip '" . $path_output . "/" . $archive_files . "'");
363 | shell_exec("mv '" . $path_output . "/" . $archive_files . ".gz' '" . $path_output . "/" . $archive_connect . "'");
364 | ###--------------------------------------------------
365 |
366 | # Creating extension xml for connect using the extension name
367 | self::createExtensionXml($files, $config, $temp_dir, $path_output);
368 | ###--------------------------------------------------
369 |
370 | # Report on what we did
371 | self::output('');
372 | self::output('Build Complete');
373 | self::output('--------------------------------------------------');
374 | self::output( "Built tgz in $path_output\n");
375 |
376 | self::output(
377 | "Built XML for Connect Manager in" . "\n\n" .
378 |
379 | " $path_output/var/connect " . "\n\n" .
380 |
381 | "place in `/path/to/magento/var/connect to load extension in Connect Manager");
382 |
383 | ###--------------------------------------------------
384 |
385 | return ob_get_clean();
386 | }
387 |
388 | static public function main($argv)
389 | {
390 | $this_script = array_shift($argv);
391 | $config_file = array_shift($argv);
392 | $config = self::loadConfig($config_file);
393 |
394 | self::output(
395 | self::buildExtensionFromConfig($config)
396 | );
397 |
398 | }
399 | /**
400 | * extrapolate the target module using the file absolute path
401 | * @param string $filePath
402 | * @return string
403 | */
404 | static public function extractTarget($filePath)
405 | {
406 | foreach (self::getTargetMap() as $tMap) {
407 | $pattern = '#' . $tMap['path'] . '#';
408 | if (preg_match($pattern, $filePath)) {
409 | return $tMap['target'];
410 | }
411 | }
412 | return 'mage';
413 | }
414 | /**
415 | * get target map
416 | * @return array
417 | */
418 | static public function getTargetMap()
419 | {
420 | return array(
421 | array('path' => 'app/etc', 'target' => 'mageetc'),
422 | array('path' => 'app/code/local', 'target' => 'magelocal'),
423 | array('path' => 'app/code/community', 'target' => 'magecommunity'),
424 | array('path' => 'app/code/core', 'target' => 'magecore'),
425 | array('path' => 'app/design', 'target' => 'magedesign'),
426 | array('path' => 'lib', 'target' => 'magelib'),
427 | array('path' => 'app/locale', 'target' => 'magelocale'),
428 | array('path' => 'media/', 'target' => 'magemedia'),
429 | array('path' => 'skin/', 'target' => 'mageskin'),
430 | array('path' => 'http://', 'target' => 'mageweb'),
431 | array('path' => 'https://', 'target' => 'mageweb'),
432 | array('path' => 'Test/', 'target' => 'magetest'),
433 | );
434 | }
435 | static public function createExtensionXml($files, $config, $tempDir, $path_output)
436 | {
437 | $extensionPath = $tempDir . DIRECTORY_SEPARATOR . 'var/connect/';
438 | if (!is_dir($extensionPath)) {
439 | mkdir($extensionPath, 0777, true);
440 | }
441 | $extensionFileName = $extensionPath . $config['extension_name'] . '.xml';
442 | file_put_contents($extensionFileName, self::buildExtensionXml($files, $config));
443 |
444 | shell_exec("cp -Rf '" . $tempDir . DIRECTORY_SEPARATOR . "var' '" . $path_output . "'");
445 | }
446 | static public function buildExtensionXml($files, $config)
447 | {
448 | $xml = simplexml_load_string('<_/>');
449 | $build_data = self::getBuildData($xml, $files, $config);
450 |
451 | foreach ($build_data as $key => $value) {
452 | if (is_array($value) && is_callable($key)) {
453 | call_user_func_array($key, $value);
454 | } else {
455 | self::addChildNode($xml, $key, $value);
456 | }
457 | }
458 |
459 | return $xml->asXml();
460 | }
461 | /**
462 | * Get an array of data to build the extension xml. The array of data will contains the key necessary
463 | * to build each node and key that are actual callback functions to be called to build sub-section of the xml.
464 | * @param SimpleXMLElement $xml
465 | * @param array $files
466 | * @param array $config
467 | * @return array
468 | */
469 | static public function getBuildData(SimpleXMLElement $xml, array $files, array $config)
470 | {
471 | return array(
472 | 'form_key' => isset($config['form_key']) ? $config['form_key'] : uniqid(),
473 | '_create' => isset($config['_create']) ? $config['_create'] : '',
474 | 'name' => $config['extension_name'],
475 | 'channel'=> $config['channel'],
476 | 'Pulsestorm_MagentoTarToConnect::buildVersionIdsNode' => array($xml),
477 | 'summary' => $config['summary'],
478 | 'description' => $config['description'],
479 | 'license' => $config['license'],
480 | 'license_uri' => isset($config['license_uri']) ? $config['license_uri'] : '',
481 | 'version' => $config['extension_version'],
482 | 'stability' => $config['stability'],
483 | 'notes' => $config['notes'],
484 | 'Pulsestorm_MagentoTarToConnect::buildAuthorsNode' => array($xml, $config),
485 | 'Pulsestorm_MagentoTarToConnect::buildPhpDependsNode' => array($xml, $config),
486 | 'Pulsestorm_MagentoTarToConnect::buildContentsNode' => array($xml, $files)
487 | );
488 | }
489 | /**
490 | * Remove a passed in file absolute path and return the relative path to the Magento application file context.
491 | * @param string $file
492 | * @return string
493 | */
494 | static public function extractRelativePath($file)
495 | {
496 | $pattern = '/app\/etc\/|app\/code\/community\/|app\/code\/local\/|app\/design\/|lib\/|app\/locale\/|skin\/|js\//';
497 | $relativePath = self::splitFilePath($file, $pattern);
498 | if ($file !== $relativePath) {
499 | return $relativePath;
500 | }
501 | $shellDir = 'shell';
502 | $relativePath = self::splitFilePath($file, '/' . $shellDir . '\//');
503 | return ($file !== $relativePath) ? $shellDir . DIRECTORY_SEPARATOR . $relativePath : $file;
504 | }
505 | /**
506 | * Split a file path using the passed in pattern and file absolute path and return
507 | * the relative path to the file.
508 | * @param string $file
509 | * @param string $pattern
510 | * @return string The relative path to file
511 | */
512 | static public function splitFilePath($file, $pattern)
513 | {
514 | $splitPath = preg_split($pattern, $file, -1);
515 | return (count($splitPath) > 1) ? $splitPath[1] : $file;
516 | }
517 | /**
518 | * Build 'contents' node including all its child nodes.
519 | * @param SimpleXMLElement $xml
520 | * @param array $files
521 | * @return void
522 | */
523 | static public function buildContentsNode(SimpleXMLElement $xml, array $files)
524 | {
525 | $node = self::addChildNode($xml, 'contents', '');
526 | $call_backs = array(
527 | 'target' => 'Pulsestorm_MagentoTarToConnect::extractTarget',
528 | 'path' => 'Pulsestorm_MagentoTarToConnect::extractRelativePath',
529 | 'type' => 'file',
530 | 'include'=> '',
531 | 'ignore' => ''
532 | );
533 |
534 | $parent_nodes = array_reduce(array_keys($call_backs), function ($item, $key) use ($node) {
535 | $item[$key] = Pulsestorm_MagentoTarToConnect::addChildNode($node, $key, '');
536 | return $item;
537 | });
538 |
539 | // Adding empty node, this is a workaround for the Magento connect bug.
540 | // When no empty nodes are added the first file is removed from the package extension.
541 | foreach ($parent_nodes as $child_key => $child_node) {
542 | self::addChildNode($child_node, $child_key, '');
543 | }
544 |
545 | foreach ($files as $file) {
546 | foreach ($parent_nodes as $key => $child_node) {
547 | $call_back = $call_backs[$key];
548 | $value = ($call_back === 'file') ? $call_back : (is_callable($call_back) ? call_user_func_array($call_back, array($file)) : $call_back);
549 | self::addChildNode($child_node, $key, $value);
550 | }
551 | }
552 | }
553 | /**
554 | * Add a 'depends_php_min' node and a 'depends_php_max' to the passed in SimpleXMLElement class instance object.
555 | * @param SimpleXMLElement $xml
556 | * @param array $config
557 | * @return void
558 | */
559 | static public function buildPhpDependsNode(SimpleXMLElement $xml, array $config)
560 | {
561 | $data = array('depends_php_min' => 'php_min', 'depends_php_max' => 'php_max');
562 | foreach ($data as $key => $cfg_key) {
563 | self::addChildNode($xml, $key, $config[$cfg_key]);
564 | }
565 | }
566 | /**
567 | * Get author data, which is a combination of author data and additional authors data from the configuration.
568 | * @param array $config
569 | * @return array
570 | */
571 | static public function getAuthorData(array $config)
572 | {
573 | $authorList[0] = array(
574 | 'author_name' => $config['author_name'],
575 | 'author_user' => $config['author_user'],
576 | 'author_email' => $config['author_email'],
577 | );
578 | if (array_key_exists('additional_authors', $config)) {
579 | $authorList = array_merge($authorList, $config['additional_authors']);
580 | }
581 | return $authorList;
582 | }
583 | /**
584 | * Get a specific author information by key.
585 | * @param array $authorList
586 | * @param string $key
587 | * @return array
588 | */
589 | static public function getAuthorInfoByKey(array $authorList, $key)
590 | {
591 | return array_map(function($author) use ($key) { return $author[$key]; }, $authorList);
592 | }
593 | /**
594 | * Build 'authors' node including all its child nodes.
595 | * @param SimpleXMLElement $xml
596 | * @param array $config
597 | * @return void
598 | */
599 | static public function buildAuthorsNode(SimpleXMLElement $xml, array $config)
600 | {
601 | $meta = array('name' => 'author_name', 'user' => 'author_user', 'email' => 'author_email');
602 | $authorList = self::getAuthorData($config);
603 | $authors = self::addChildNode($xml, 'authors', '');
604 | foreach ($meta as $key => $cfg_key) {
605 | $parentNode = self::addChildNode($authors, $key, '');
606 | foreach (self::getAuthorInfoByKey($authorList, $cfg_key) as $value) {
607 | self::addChildNode($parentNode, $key, $value);
608 | }
609 | }
610 | }
611 | /**
612 | * Build 'version_ids' node including all its child nodes.
613 | * @param SimpleXMLElement $xml
614 | * @return void
615 | */
616 | static public function buildVersionIdsNode(SimpleXMLElement $xml)
617 | {
618 | $key = 'version_ids';
619 | $parentNode = self::addChildNode($xml, $key, '');
620 | foreach (array(2, 1) as $version) {
621 | self::addChildNode($parentNode, $key, $version);
622 | }
623 | }
624 | /**
625 | * Add child node to a passed in SimpleXMLElement class instance object.
626 | * @param SimpleXMLElement $context
627 | * @param string $name
628 | * @param string $value
629 | * @return SimpleXMLElement
630 | */
631 | static public function addChildNode(SimpleXMLElement $context, $name, $value='')
632 | {
633 | $child = $context->addChild($name);
634 | if (trim($value)) {
635 | $child->{0} = $value;
636 | }
637 | return $child;
638 | }
639 | }
640 | if(isset($argv))
641 | {
642 | Pulsestorm_MagentoTarToConnect::main($argv);
643 | }
644 |
--------------------------------------------------------------------------------
/src/magento/downloader/lib/Mage/Archive/Abstract.php:
--------------------------------------------------------------------------------
1 |
33 | */
34 | class Mage_Archive_Abstract
35 | {
36 | /**
37 | * Write data to file. If file can't be opened - throw exception
38 | *
39 | * @param string $destination
40 | * @param string $data
41 | * @return boolean
42 | * @throws Mage_Exception
43 | */
44 | protected function _writeFile($destination, $data)
45 | {
46 | $destination = trim($destination);
47 | if(false === file_put_contents($destination, $data)) {
48 | throw new Mage_Exception("Can't write to file: " . $destination);
49 | }
50 | return true;
51 | }
52 |
53 | /**
54 | * Read data from file. If file can't be opened, throw to exception.
55 | *
56 | * @param string $source
57 | * @return string
58 | * @throws Mage_Exception
59 | */
60 | protected function _readFile($source)
61 | {
62 | $data = '';
63 | if (is_file($source) && is_readable($source)) {
64 | $data = @file_get_contents($source);
65 | if ($data === false) {
66 | throw new Mage_Exception("Can't get contents from: " . $source);
67 | }
68 | }
69 | return $data;
70 | }
71 |
72 | /**
73 | * Get file name from source (URI) without last extension.
74 | *
75 | * @param string $source
76 | * @param bool $withExtension
77 | * @return mixed|string
78 | */
79 | public function getFilename($source, $withExtension=false)
80 | {
81 | $file = str_replace(dirname($source) . DS, '', $source);
82 | if (!$withExtension) {
83 | $file = substr($file, 0, strrpos($file, '.'));
84 | }
85 | return $file;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/magento/downloader/lib/Mage/Archive/Helper/File.php:
--------------------------------------------------------------------------------
1 |
33 | */
34 | class Mage_Archive_Helper_File
35 | {
36 | /**
37 | * Full path to directory where file located
38 | *
39 | * @var string
40 | */
41 | protected $_fileLocation;
42 |
43 | /**
44 | * File name
45 | *
46 | * @var string
47 | */
48 | protected $_fileName;
49 |
50 | /**
51 | * Full path (directory + filename) to file
52 | *
53 | * @var string
54 | */
55 | protected $_filePath;
56 |
57 | /**
58 | * File permissions that will be set if file opened in write mode
59 | *
60 | * @var int
61 | */
62 | protected $_chmod;
63 |
64 | /**
65 | * File handler
66 | *
67 | * @var pointer
68 | */
69 | protected $_fileHandler;
70 |
71 | /**
72 | * Set file path via constructor
73 | *
74 | * @param string $filePath
75 | */
76 | public function __construct($filePath)
77 | {
78 | $pathInfo = pathinfo($filePath);
79 |
80 | $this->_filePath = $filePath;
81 | $this->_fileLocation = isset($pathInfo['dirname']) ? $pathInfo['dirname'] : '';
82 | $this->_fileName = isset($pathInfo['basename']) ? $pathInfo['basename'] : '';
83 | }
84 |
85 | /**
86 | * Close file if it's not closed before object destruction
87 | */
88 | public function __destruct()
89 | {
90 | if ($this->_fileHandler) {
91 | $this->_close();
92 | }
93 | }
94 |
95 | /**
96 | * Open file
97 | *
98 | * @param string $mode
99 | * @param int $chmod
100 | * @throws Mage_Exception
101 | */
102 | public function open($mode = 'w+', $chmod = 0666)
103 | {
104 | if ($this->_isWritableMode($mode)) {
105 | if (!is_writable($this->_fileLocation)) {
106 | throw new Mage_Exception('Permission denied to write to ' . $this->_fileLocation);
107 | }
108 |
109 | if (is_file($this->_filePath) && !is_writable($this->_filePath)) {
110 | throw new Mage_Exception("Can't open file " . $this->_fileName . " for writing. Permission denied.");
111 | }
112 | }
113 |
114 | if ($this->_isReadableMode($mode) && (!is_file($this->_filePath) || !is_readable($this->_filePath))) {
115 | if (!is_file($this->_filePath)) {
116 | throw new Mage_Exception('File ' . $this->_filePath . ' does not exist');
117 | }
118 |
119 | if (!is_readable($this->_filePath)) {
120 | throw new Mage_Exception('Permission denied to read file ' . $this->_filePath);
121 | }
122 | }
123 |
124 | $this->_open($mode);
125 |
126 | $this->_chmod = $chmod;
127 | }
128 |
129 | /**
130 | * Write data to file
131 | *
132 | * @param string $data
133 | */
134 | public function write($data)
135 | {
136 | $this->_checkFileOpened();
137 | $this->_write($data);
138 | }
139 |
140 | /**
141 | * Read data from file
142 | *
143 | * @param int $length
144 | * @return string|boolean
145 | */
146 | public function read($length = 4096)
147 | {
148 | $data = false;
149 | $this->_checkFileOpened();
150 | if ($length > 0) {
151 | $data = $this->_read($length);
152 | }
153 |
154 | return $data;
155 | }
156 |
157 | /**
158 | * Check whether end of file reached
159 | *
160 | * @return boolean
161 | */
162 | public function eof()
163 | {
164 | $this->_checkFileOpened();
165 | return $this->_eof();
166 | }
167 |
168 | /**
169 | * Close file
170 | */
171 | public function close()
172 | {
173 | $this->_checkFileOpened();
174 | $this->_close();
175 | $this->_fileHandler = false;
176 | @chmod($this->_filePath, $this->_chmod);
177 | }
178 |
179 | /**
180 | * Implementation of file opening
181 | *
182 | * @param string $mode
183 | * @throws Mage_Exception
184 | */
185 | protected function _open($mode)
186 | {
187 | $this->_fileHandler = @fopen($this->_filePath, $mode);
188 |
189 | if (false === $this->_fileHandler) {
190 | throw new Mage_Exception('Failed to open file ' . $this->_filePath);
191 | }
192 | }
193 |
194 | /**
195 | * Implementation of writing data to file
196 | *
197 | * @param string $data
198 | * @throws Mage_Exception
199 | */
200 | protected function _write($data)
201 | {
202 | $result = @fwrite($this->_fileHandler, $data);
203 |
204 | if (false === $result) {
205 | throw new Mage_Exception('Failed to write data to ' . $this->_filePath);
206 | }
207 | }
208 |
209 | /**
210 | * Implementation of file reading
211 | *
212 | * @param int $length
213 | * @throws Mage_Exception
214 | */
215 | protected function _read($length)
216 | {
217 | $result = fread($this->_fileHandler, $length);
218 |
219 | if (false === $result) {
220 | throw new Mage_Exception('Failed to read data from ' . $this->_filePath);
221 | }
222 |
223 | return $result;
224 | }
225 |
226 | /**
227 | * Implementation of EOF indicator
228 | *
229 | * @return boolean
230 | */
231 | protected function _eof()
232 | {
233 | return feof($this->_fileHandler);
234 | }
235 |
236 | /**
237 | * Implementation of file closing
238 | */
239 | protected function _close()
240 | {
241 | fclose($this->_fileHandler);
242 | }
243 |
244 | /**
245 | * Check whether requested mode is writable mode
246 | *
247 | * @param string $mode
248 | */
249 | protected function _isWritableMode($mode)
250 | {
251 | return preg_match('/(^[waxc])|(\+$)/', $mode);
252 | }
253 |
254 | /**
255 | * Check whether requested mode is readable mode
256 | *
257 | * @param string $mode
258 | */
259 | protected function _isReadableMode($mode) {
260 | return !$this->_isWritableMode($mode);
261 | }
262 |
263 | /**
264 | * Check whether file is opened
265 | *
266 | * @throws Mage_Exception
267 | */
268 | protected function _checkFileOpened()
269 | {
270 | if (!$this->_fileHandler) {
271 | throw new Mage_Exception('File not opened');
272 | }
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/src/magento/downloader/lib/Mage/Archive/Interface.php:
--------------------------------------------------------------------------------
1 |
33 | */
34 | interface Mage_Archive_Interface
35 | {
36 | /**
37 | * Pack file or directory.
38 | *
39 | * @param string $source
40 | * @param string $destination
41 | * @return string
42 | */
43 | public function pack($source, $destination);
44 |
45 | /**
46 | * Unpack file or directory.
47 | *
48 | * @param string $source
49 | * @param string $destination
50 | * @return string
51 | */
52 | public function unpack($source, $destination);
53 | }
54 |
--------------------------------------------------------------------------------
/src/magento/downloader/lib/Mage/Archive/Tar.php:
--------------------------------------------------------------------------------
1 |
33 | */
34 | class Mage_Archive_Tar extends Mage_Archive_Abstract implements Mage_Archive_Interface
35 | {
36 | /**
37 | * Tar block size
38 | *
39 | * @const int
40 | */
41 | const TAR_BLOCK_SIZE = 512;
42 |
43 | /**
44 | * Keep file or directory for packing.
45 | *
46 | * @var string
47 | */
48 | protected $_currentFile;
49 |
50 | /**
51 | * Keep path to file or directory for packing.
52 | *
53 | * @var mixed
54 | */
55 | protected $_currentPath;
56 |
57 | /**
58 | * Skip first level parent directory. Example:
59 | * use test/fip.php instead test/test/fip.php;
60 | *
61 | * @var mixed
62 | */
63 | protected $_skipRoot;
64 |
65 | /**
66 | * Tarball data writer
67 | *
68 | * @var Mage_Archive_Helper_File
69 | */
70 | protected $_writer;
71 |
72 | /**
73 | * Tarball data reader
74 | *
75 | * @var Mage_Archive_Helper_File
76 | */
77 | protected $_reader;
78 |
79 | /**
80 | * Path to file where tarball should be placed
81 | *
82 | * @var string
83 | */
84 | protected $_destinationFilePath;
85 |
86 | /**
87 | * Initialize tarball writer
88 | *
89 | * @return Mage_Archive_Tar
90 | */
91 | protected function _initWriter()
92 | {
93 | $this->_writer = new Mage_Archive_Helper_File($this->_destinationFilePath);
94 | $this->_writer->open('w');
95 |
96 | return $this;
97 | }
98 |
99 | /**
100 | * Returns string that is used for tar's header parsing
101 | *
102 | * @return string
103 | */
104 | protected static final function _getFormatParseHeader()
105 | {
106 | return 'a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2version/'
107 | . 'a32uname/a32gname/a8devmajor/a8devminor/a155prefix/a12closer';
108 | }
109 |
110 | /**
111 | * Destroy tarball writer
112 | *
113 | * @return Mage_Archive_Tar
114 | */
115 | protected function _destroyWriter()
116 | {
117 | if ($this->_writer instanceof Mage_Archive_Helper_File) {
118 | $this->_writer->close();
119 | $this->_writer = null;
120 | }
121 |
122 | return $this;
123 | }
124 |
125 | /**
126 | * Get tarball writer
127 | *
128 | * @return Mage_Archive_Helper_File
129 | */
130 | protected function _getWriter()
131 | {
132 | if (!$this->_writer) {
133 | $this->_initWriter();
134 | }
135 |
136 | return $this->_writer;
137 | }
138 |
139 | /**
140 | * Initialize tarball reader
141 | *
142 | * @return Mage_Archive_Tar
143 | */
144 | protected function _initReader()
145 | {
146 | $this->_reader = new Mage_Archive_Helper_File($this->_getCurrentFile());
147 | $this->_reader->open('r');
148 |
149 | return $this;
150 | }
151 |
152 | /**
153 | * Destroy tarball reader
154 | *
155 | * @return Mage_Archive_Tar
156 | */
157 | protected function _destroyReader()
158 | {
159 | if ($this->_reader instanceof Mage_Archive_Helper_File) {
160 | $this->_reader->close();
161 | $this->_reader = null;
162 | }
163 |
164 | return $this;
165 | }
166 |
167 | /**
168 | * Get tarball reader
169 | *
170 | * @return Mage_Archive_Helper_File
171 | */
172 | protected function _getReader()
173 | {
174 | if (!$this->_reader) {
175 | $this->_initReader();
176 | }
177 |
178 | return $this->_reader;
179 | }
180 |
181 | /**
182 | * Set option that define ability skip first catalog level.
183 | *
184 | * @param mixed $skipRoot
185 | * @return Mage_Archive_Tar
186 | */
187 | protected function _setSkipRoot($skipRoot)
188 | {
189 | $this->_skipRoot = $skipRoot;
190 | return $this;
191 | }
192 |
193 | /**
194 | * Set file which is packing.
195 | *
196 | * @param string $file
197 | * @return Mage_Archive_Tar
198 | */
199 | protected function _setCurrentFile($file)
200 | {
201 | $this->_currentFile = $file .((!is_link($file) && is_dir($file) && substr($file, -1) != DS) ? DS : '');
202 | return $this;
203 | }
204 |
205 | /**
206 | * Set path to file where tarball should be placed
207 | *
208 | * @param string $destinationFilePath
209 | * @return Mage_Archive_Tar
210 | */
211 | protected function _setDestinationFilePath($destinationFilePath)
212 | {
213 | $this->_destinationFilePath = $destinationFilePath;
214 | return $this;
215 | }
216 |
217 | /**
218 | * Retrieve file which is packing.
219 | *
220 | * @return string
221 | */
222 | protected function _getCurrentFile()
223 | {
224 | return $this->_currentFile;
225 | }
226 |
227 | /**
228 | * Set path to file which is packing.
229 | *
230 | * @param string $path
231 | * @return Mage_Archive_Tar
232 | */
233 | protected function _setCurrentPath($path)
234 | {
235 | if ($this->_skipRoot && is_dir($path)) {
236 | $this->_currentPath = $path.(substr($path, -1)!=DS?DS:'');
237 | } else {
238 | $this->_currentPath = dirname($path) . DS;
239 | }
240 | return $this;
241 | }
242 |
243 | /**
244 | * Retrieve path to file which is packing.
245 | *
246 | * @return string
247 | */
248 | protected function _getCurrentPath()
249 | {
250 | return $this->_currentPath;
251 | }
252 |
253 | /**
254 | * Walk through directory and add to tar file or directory.
255 | * Result is packed string on TAR format.
256 | *
257 | * @deprecated after 1.7.0.0
258 | * @param boolean $skipRoot
259 | * @return string
260 | */
261 | protected function _packToTar($skipRoot=false)
262 | {
263 | $file = $this->_getCurrentFile();
264 | $header = '';
265 | $data = '';
266 | if (!$skipRoot) {
267 | $header = $this->_composeHeader();
268 | $data = $this->_readFile($file);
269 | $data = str_pad($data, floor(((is_dir($file) ? 0 : filesize($file)) + 512 - 1) / 512) * 512, "\0");
270 | }
271 | $sub = '';
272 | if (is_dir($file)) {
273 | $treeDir = scandir($file);
274 | if (empty($treeDir)) {
275 | throw new Mage_Exception('Can\'t scan dir: ' . $file);
276 | }
277 | array_shift($treeDir); /* remove './'*/
278 | array_shift($treeDir); /* remove '../'*/
279 | foreach ($treeDir as $item) {
280 | $sub .= $this->_setCurrentFile($file.$item)->_packToTar(false);
281 | }
282 | }
283 | $tarData = $header . $data . $sub;
284 | $tarData = str_pad($tarData, floor((strlen($tarData) - 1) / 1536) * 1536, "\0");
285 | return $tarData;
286 | }
287 |
288 | /**
289 | * Recursively walk through file tree and create tarball
290 | *
291 | * @param boolean $skipRoot
292 | * @param boolean $finalize
293 | * @throws Mage_Exception
294 | */
295 | protected function _createTar($skipRoot = false, $finalize = false)
296 | {
297 | if (!$skipRoot) {
298 | $this->_packAndWriteCurrentFile();
299 | }
300 |
301 | $file = $this->_getCurrentFile();
302 |
303 | if (is_dir($file)) {
304 | $dirFiles = scandir($file);
305 |
306 | if (false === $dirFiles) {
307 | throw new Mage_Exception('Can\'t scan dir: ' . $file);
308 | }
309 |
310 | array_shift($dirFiles); /* remove './'*/
311 | array_shift($dirFiles); /* remove '../'*/
312 |
313 | foreach ($dirFiles as $item) {
314 | $this->_setCurrentFile($file . $item)->_createTar();
315 | }
316 | }
317 |
318 | if ($finalize) {
319 | $this->_getWriter()->write(str_repeat("\0", self::TAR_BLOCK_SIZE * 12));
320 | }
321 | }
322 |
323 | /**
324 | * Write current file to tarball
325 | */
326 | protected function _packAndWriteCurrentFile()
327 | {
328 | $archiveWriter = $this->_getWriter();
329 | $archiveWriter->write($this->_composeHeader());
330 |
331 | $currentFile = $this->_getCurrentFile();
332 |
333 | $fileSize = 0;
334 |
335 | if (is_file($currentFile) && !is_link($currentFile)) {
336 | $fileReader = new Mage_Archive_Helper_File($currentFile);
337 | $fileReader->open('r');
338 |
339 | while (!$fileReader->eof()) {
340 | $archiveWriter->write($fileReader->read());
341 | }
342 |
343 | $fileReader->close();
344 |
345 | $fileSize = filesize($currentFile);
346 | }
347 |
348 | $appendZerosCount = (self::TAR_BLOCK_SIZE - $fileSize % self::TAR_BLOCK_SIZE) % self::TAR_BLOCK_SIZE;
349 | $archiveWriter->write(str_repeat("\0", $appendZerosCount));
350 | }
351 |
352 | /**
353 | * Compose header for current file in TAR format.
354 | * If length of file's name greater 100 characters,
355 | * method breaks header into two pieces. First contains
356 | * header and data with long name. Second contain only header.
357 | *
358 | * @param boolean $long
359 | * @return string
360 | */
361 | protected function _composeHeader($long = false)
362 | {
363 | $file = $this->_getCurrentFile();
364 | $path = $this->_getCurrentPath();
365 | $infoFile = stat($file);
366 | $nameFile = str_replace($path, '', $file);
367 | $nameFile = str_replace('\\', '/', $nameFile);
368 | $packedHeader = '';
369 | $longHeader = '';
370 | if (!$long && strlen($nameFile)>100) {
371 | $longHeader = $this->_composeHeader(true);
372 | $longHeader .= str_pad($nameFile, floor((strlen($nameFile) + 512 - 1) / 512) * 512, "\0");
373 | }
374 | $header = array();
375 | $header['100-name'] = $long?'././@LongLink':substr($nameFile, 0, 100);
376 | $header['8-mode'] = $long ? ' '
377 | : str_pad(substr(sprintf("%07o", $infoFile['mode']),-4), 6, '0', STR_PAD_LEFT);
378 | $header['8-uid'] = $long || $infoFile['uid']==0?"\0\0\0\0\0\0\0":sprintf("%07o", $infoFile['uid']);
379 | $header['8-gid'] = $long || $infoFile['gid']==0?"\0\0\0\0\0\0\0":sprintf("%07o", $infoFile['gid']);
380 | $header['12-size'] = $long ? sprintf("%011o", strlen($nameFile)) : sprintf("%011o", is_dir($file)
381 | ? 0 : filesize($file));
382 | $header['12-mtime'] = $long?'00000000000':sprintf("%011o", $infoFile['mtime']);
383 | $header['8-check'] = sprintf('% 8s', '');
384 | $header['1-type'] = $long ? 'L' : (is_link($file) ? 2 : (is_dir($file) ? 5 : 0));
385 | $header['100-symlink'] = is_link($file) ? readlink($file) : '';
386 | $header['6-magic'] = 'ustar ';
387 | $header['2-version'] = ' ';
388 | $a=function_exists('posix_getpwuid')?posix_getpwuid (fileowner($file)):array('name'=>'');
389 | $header['32-uname'] = $a['name'];
390 | $a=function_exists('posix_getgrgid')?posix_getgrgid (filegroup($file)):array('name'=>'');
391 | $header['32-gname'] = $a['name'];
392 | $header['8-devmajor'] = '';
393 | $header['8-devminor'] = '';
394 | $header['155-prefix'] = '';
395 | $header['12-closer'] = '';
396 |
397 | $packedHeader = '';
398 | foreach ($header as $key=>$element) {
399 | $length = explode('-', $key);
400 | $packedHeader .= pack('a' . $length[0], $element);
401 | }
402 |
403 | $checksum = 0;
404 | for ($i = 0; $i < 512; $i++) {
405 | $checksum += ord(substr($packedHeader, $i, 1));
406 | }
407 | $packedHeader = substr_replace($packedHeader, sprintf("%07o", $checksum)."\0", 148, 8);
408 |
409 | return $longHeader . $packedHeader;
410 | }
411 |
412 | /**
413 | * Read TAR string from file, and unpacked it.
414 | * Create files and directories information about discribed
415 | * in the string.
416 | *
417 | * @param string $destination path to file is unpacked
418 | * @return array list of files
419 | * @throws Mage_Exception
420 | */
421 | protected function _unpackCurrentTar($destination)
422 | {
423 | $archiveReader = $this->_getReader();
424 | $list = array();
425 |
426 | while (!$archiveReader->eof()) {
427 | $header = $this->_extractFileHeader();
428 |
429 | if (!$header) {
430 | continue;
431 | }
432 |
433 | $currentFile = $destination . $header['name'];
434 | $dirname = dirname($currentFile);
435 |
436 | if (in_array($header['type'], array("0",chr(0), ''))) {
437 |
438 | if(!file_exists($dirname)) {
439 | $mkdirResult = @mkdir($dirname, 0777, true);
440 |
441 | if (false === $mkdirResult) {
442 | throw new Mage_Exception('Failed to create directory ' . $dirname);
443 | }
444 | }
445 |
446 | $this->_extractAndWriteFile($header, $currentFile);
447 | $list[] = $currentFile;
448 |
449 | } elseif ($header['type'] == '5') {
450 |
451 | if(!file_exists($dirname)) {
452 | $mkdirResult = @mkdir($currentFile, $header['mode'], true);
453 |
454 | if (false === $mkdirResult) {
455 | throw new Mage_Exception('Failed to create directory ' . $currentFile);
456 | }
457 | }
458 | $list[] = $currentFile . DS;
459 | } elseif ($header['type'] == '2') {
460 |
461 | $symlinkResult = @symlink($header['symlink'], $currentFile);
462 |
463 | if (false === $symlinkResult) {
464 | throw new Mage_Exception('Failed to create symlink ' . $currentFile . ' to ' . $header['symlink']);
465 | }
466 | }
467 | }
468 |
469 | return $list;
470 | }
471 |
472 | /**
473 | * Get header from TAR string and unpacked it by format.
474 | *
475 | * @deprecated after 1.7.0.0
476 | * @param resource $pointer
477 | * @return string
478 | */
479 | protected function _parseHeader(&$pointer)
480 | {
481 | $firstLine = fread($pointer, 512);
482 |
483 | if (strlen($firstLine)<512){
484 | return false;
485 | }
486 |
487 | $fmt = self::_getFormatParseHeader();
488 | $header = unpack ($fmt, $firstLine);
489 |
490 | $header['mode']=$header['mode']+0;
491 | $header['uid']=octdec($header['uid']);
492 | $header['gid']=octdec($header['gid']);
493 | $header['size']=octdec($header['size']);
494 | $header['mtime']=octdec($header['mtime']);
495 | $header['checksum']=octdec($header['checksum']);
496 |
497 | if ($header['type'] == "5") {
498 | $header['size'] = 0;
499 | }
500 |
501 | $checksum = 0;
502 | $firstLine = substr_replace($firstLine, ' ', 148, 8);
503 | for ($i = 0; $i < 512; $i++) {
504 | $checksum += ord(substr($firstLine, $i, 1));
505 | }
506 |
507 | $isUstar = 'ustar' == strtolower(substr($header['magic'], 0, 5));
508 |
509 | $checksumOk = $header['checksum'] == $checksum;
510 | if (isset($header['name']) && $checksumOk) {
511 | if ($header['name'] == '././@LongLink' && $header['type'] == 'L') {
512 | $realName = substr(fread($pointer, floor(($header['size'] + 512 - 1) / 512) * 512), 0, $header['size']);
513 | $headerMain = $this->_parseHeader($pointer);
514 | $headerMain['name'] = $realName;
515 | return $headerMain;
516 | } else {
517 | if ($header['size']>0) {
518 | $header['data'] = substr(fread($pointer, floor(($header['size'] + 512 - 1) / 512) * 512), 0, $header['size']);
519 | } else {
520 | $header['data'] = '';
521 | }
522 | return $header;
523 | }
524 | }
525 | return false;
526 | }
527 |
528 | /**
529 | * Read and decode file header information from tarball
530 | *
531 | * @return array|boolean
532 | */
533 | protected function _extractFileHeader()
534 | {
535 | $archiveReader = $this->_getReader();
536 |
537 | $headerBlock = $archiveReader->read(self::TAR_BLOCK_SIZE);
538 |
539 | if (strlen($headerBlock) < self::TAR_BLOCK_SIZE) {
540 | return false;
541 | }
542 |
543 | $header = unpack(self::_getFormatParseHeader(), $headerBlock);
544 |
545 | $header['mode'] = octdec($header['mode']);
546 | $header['uid'] = octdec($header['uid']);
547 | $header['gid'] = octdec($header['gid']);
548 | $header['size'] = octdec($header['size']);
549 | $header['mtime'] = octdec($header['mtime']);
550 | $header['checksum'] = octdec($header['checksum']);
551 |
552 | if ($header['type'] == "5") {
553 | $header['size'] = 0;
554 | }
555 |
556 | $checksum = 0;
557 | $headerBlock = substr_replace($headerBlock, ' ', 148, 8);
558 |
559 | for ($i = 0; $i < 512; $i++) {
560 | $checksum += ord(substr($headerBlock, $i, 1));
561 | }
562 |
563 | $checksumOk = $header['checksum'] == $checksum;
564 | if (isset($header['name']) && $checksumOk) {
565 |
566 | if (!($header['name'] == '././@LongLink' && $header['type'] == 'L')) {
567 | $header['name'] = trim($header['name']);
568 | return $header;
569 | }
570 |
571 | $realNameBlockSize = floor(($header['size'] + self::TAR_BLOCK_SIZE - 1) / self::TAR_BLOCK_SIZE)
572 | * self::TAR_BLOCK_SIZE;
573 | $realNameBlock = $archiveReader->read($realNameBlockSize);
574 | $realName = substr($realNameBlock, 0, $header['size']);
575 |
576 | $headerMain = $this->_extractFileHeader();
577 | $headerMain['name'] = trim($realName);
578 | return $headerMain;
579 | }
580 |
581 | return false;
582 | }
583 |
584 | /**
585 | * Extract next file from tarball by its $header information and save it to $destination
586 | *
587 | * @param array $fileHeader
588 | * @param string $destination
589 | */
590 | protected function _extractAndWriteFile($fileHeader, $destination)
591 | {
592 | $fileWriter = new Mage_Archive_Helper_File($destination);
593 | $fileWriter->open('w', $fileHeader['mode']);
594 |
595 | $archiveReader = $this->_getReader();
596 |
597 | $filesize = $fileHeader['size'];
598 | $bytesExtracted = 0;
599 |
600 | while ($filesize > $bytesExtracted && !$archiveReader->eof()) {
601 | $block = $archiveReader->read(self::TAR_BLOCK_SIZE);
602 | $nonExtractedBytesCount = $filesize - $bytesExtracted;
603 |
604 | $data = substr($block, 0, $nonExtractedBytesCount);
605 | $fileWriter->write($data);
606 |
607 | $bytesExtracted += strlen($block);
608 | }
609 | }
610 |
611 | /**
612 | * Pack file to TAR (Tape Archiver).
613 | *
614 | * @param string $source
615 | * @param string $destination
616 | * @param boolean $skipRoot
617 | * @return string
618 | */
619 | public function pack($source, $destination, $skipRoot = false)
620 | {
621 | $this->_setSkipRoot($skipRoot);
622 | $source = realpath($source);
623 | $tarData = $this->_setCurrentPath($source)
624 | ->_setDestinationFilePath($destination)
625 | ->_setCurrentFile($source);
626 |
627 | $this->_initWriter();
628 | $this->_createTar($skipRoot, true);
629 | $this->_destroyWriter();
630 |
631 | return $destination;
632 | }
633 |
634 | /**
635 | * Unpack file from TAR (Tape Archiver).
636 | *
637 | * @param string $source
638 | * @param string $destination
639 | * @return string
640 | */
641 | public function unpack($source, $destination)
642 | {
643 | $this->_setCurrentFile($source)
644 | ->_setCurrentPath($source);
645 |
646 | $this->_initReader();
647 | $this->_unpackCurrentTar($destination);
648 | $this->_destroyReader();
649 |
650 | return $destination;
651 | }
652 |
653 | /**
654 | * Extract one file from TAR (Tape Archiver).
655 | *
656 | * @param string $file
657 | * @param string $source
658 | * @param string $destination
659 | * @return string
660 | */
661 | public function extract($file, $source, $destination)
662 | {
663 | $this->_setCurrentFile($source);
664 | $this->_initReader();
665 |
666 | $archiveReader = $this->_getReader();
667 | $extractedFile = '';
668 |
669 | while (!$archiveReader->eof()) {
670 | $header = $this->_extractFileHeader();
671 | if ($header['name'] == $file) {
672 | $extractedFile = $destination . basename($header['name']);
673 | $this->_extractAndWriteFile($header, $extractedFile);
674 | break;
675 | }
676 |
677 | if ($header['type'] != 5){
678 | $skipBytes = floor(($header['size'] + self::TAR_BLOCK_SIZE - 1) / self::TAR_BLOCK_SIZE)
679 | * self::TAR_BLOCK_SIZE;
680 | $archiveReader->read($skipBytes);
681 | }
682 | }
683 |
684 | $this->_destroyReader();
685 | return $extractedFile;
686 | }
687 | }
688 |
--------------------------------------------------------------------------------
/src/magento/downloader/lib/Mage/Exception.php:
--------------------------------------------------------------------------------
1 |
33 | */
34 | class Mage_Exception extends Exception
35 | {}
36 |
--------------------------------------------------------------------------------
/tests/AuthorTest.php:
--------------------------------------------------------------------------------
1 | _buildExtensionFromFixture('Pulsestorm_Better404.tar');
15 | $xml_gui = simplexml_load_file($results['connect_xml']);
16 | $xml_package = simplexml_load_file($results['extracted'] . '/package.xml');
17 |
18 | $names_package = array();
19 | foreach($xml_package->authors->children() as $author)
20 | {
21 | $names_package[] = (string) $author->name;
22 | }
23 |
24 | foreach($xml_gui->authors->name->children() as $author)
25 | {
26 | $names_gui[] = (string) $author;
27 | }
28 |
29 | $this->assertEquals($names_package, $names_gui);
30 | }
31 | }
--------------------------------------------------------------------------------
/tests/ExampleTest.php:
--------------------------------------------------------------------------------
1 | _buildExtensionFromFixture('first.tar');
17 |
18 | //if you don't like the default configuration we used, specify your own
19 | $config = $this->_getBaseExtensionConfig('Pulsestorm_Better404.tar');
20 | $config['extension_name'] = 'Pulsestorm_Better404';
21 | $results_second = $this->_buildExtensionFromFixture('Pulsestorm_Better404.tar', $config);
22 |
23 | //The results array has three keys
24 | $results_first['extension']; //path to the built extension
25 | $results_first['connect_xml']; //path to the built adminhtml connect XML file
26 | $results_first['extracted']; //path to a tmp folder with an already extracted tgz
27 | //that is, the build extension extracted to a folder
28 |
29 | //With the information in the three tests above, you're free to test anything
30 | //about the built extension, and with the fixtures folder being a simple drop
31 | //drop in, you're free to create clear reproducable bug reports
32 |
33 | $this->assertTrue(file_exists($results_first['extracted'] . '/package.xml'));
34 | $this->assertTrue(file_exists($results_second['extracted'] . '/package.xml'));
35 | }
36 | }
--------------------------------------------------------------------------------
/tests/MagentoTarToConnectBaseTest.php:
--------------------------------------------------------------------------------
1 | _getBaseBuildArtifactsPath();
14 | if(!file_exists($path_build_artifacts))
15 | {
16 | mkdir($path_build_artifacts);
17 | }
18 |
19 | $path_build = $this->_getBaseBuildPath();
20 | //if there's a build folder, move it to artifacts
21 | if(file_exists($path_build))
22 | {
23 | rename($path_build, $path_build_artifacts . '/' . uniqid());
24 | }
25 |
26 | //create a build folder
27 | mkdir($path_build);
28 | }
29 |
30 | public function testSetup()
31 | {
32 | $this->assertTrue(true);
33 | }
34 |
35 | protected function _getBaseExtensionConfig($fixture, $extension_name='Pulsestorm_Unittest', $extension_version='1.0.0',
36 | $author_email='testing@example.com')
37 | {
38 | $base_repo_path = $this->_getBaseRespoitoryPath();
39 | $config = include $base_repo_path . '/' . self::EXAMPLE_CONFIG;
40 |
41 | $config['base_dir'] = $this->_getBaseBuildPath();
42 | $config['archive_files'] = $fixture;
43 | $config['extension_name'] = $extension_name;
44 | $config['extension_version'] = $extension_version;
45 | $config['path_output'] = $this->_getBaseBuildPath();
46 | $config['author_email'] = $author_email;
47 | $config['skip_version_compare'] = true;
48 | return $config;
49 | }
50 |
51 | protected function _buildExtensionFromFixture($fixture,$config=false)
52 | {
53 | $path_fixture = $this->_getFixturePath($fixture);
54 | $this->_copyFixtureToBuild($path_fixture);
55 |
56 | if(!$config)
57 | {
58 | $config = $this->_getBaseExtensionConfig($fixture);
59 | }
60 |
61 |
62 | Pulsestorm_MagentoTarToConnect::buildExtensionFromConfig($config);
63 |
64 | $path_extension = $this->_getBaseBuildPath() . '/' .
65 | $config['extension_name'] . '-' .
66 | $config['extension_version'] . '.tgz';
67 |
68 | $path_connectxml = $this->_getBaseBuildPath() . '/var/connect/' .
69 | $config['extension_name'] . '.xml';
70 |
71 | $untared = $this->_untarIntoTemp($path_extension);
72 |
73 | $results = array();
74 | $results['extension'] = $path_extension;
75 | $results['extracted'] = $untared;
76 | $results['connect_xml'] = $path_connectxml;
77 | return $results;
78 |
79 | }
80 |
81 | protected function _getBaseRespoitoryPath()
82 | {
83 | return realpath((__DIR__ . '/../'));
84 | }
85 |
86 | protected function _untarIntoTemp($path)
87 | {
88 | $original_dir = getcwd();
89 |
90 | //create a temp file, turn it into a directory
91 | $dir = tempnam('/tmp','mt2c');;
92 | unlink($dir);
93 | mkdir($dir);
94 | chdir($dir);
95 |
96 | $tar = new Archive_Tar($path);
97 | $tar->extract('.');
98 | chdir($original_dir);
99 | return $dir;
100 | }
101 |
102 | protected function _getFixturePath($name)
103 | {
104 | return realpath(__DIR__) . '/fixtures/' . $name;
105 | }
106 |
107 | protected function _copyFixtureToBuild($path)
108 | {
109 | $path_new = dirname($path) . '/build/' . basename($path);
110 | copy($path, $path_new);
111 | return $path_new;
112 | }
113 |
114 | protected function _getBaseBuildArtifactsPath()
115 | {
116 | return $this->_getBaseBuildPath() . self::PATH_BUILD_ARTIFACTS_SUFFIX;
117 | }
118 | protected function _getBaseBuildPath()
119 | {
120 | return $this->_getBaseRespoitoryPath() . self::PATH_BUILD;
121 | }
122 | }
--------------------------------------------------------------------------------
/tests/WhoTestsTheTestsTest.php:
--------------------------------------------------------------------------------
1 | _getFixturePath('first.txt');
7 | $this->assertTrue(file_exists($fixture));
8 | }
9 |
10 | public function testGetTarFixture()
11 | {
12 | $fixture = $this->_getFixturePath('first.tar');
13 | $path = $this->_untarIntoTemp($fixture);
14 |
15 | // echo "\n",$path . '/first.txt',"\n";
16 | $this->assertTrue(file_exists($path . '/first.txt'));
17 | }
18 |
19 | public function testCanReadExampleConfig()
20 | {
21 | return $this->assertTrue(
22 | file_exists($this->_getBaseRespoitoryPath() . '/' . self::EXAMPLE_CONFIG)
23 | );
24 | }
25 |
26 | public function testCopyFixtureToBuild()
27 | {
28 | $fixture = $this->_getFixturePath('first.tar');
29 | $this->_copyFixtureToBuild($fixture);
30 |
31 | $this->assertTrue(file_exists(
32 | $this->_getBaseBuildPath() . '/first.tar'
33 | ));
34 | }
35 |
36 | public function testRunTarToConnect()
37 | {
38 | $results = $this->_buildExtensionFromFixture('first.tar');
39 | $this->assertTrue(file_exists($results['extension']));
40 | }
41 |
42 | public function testRunTarToConnectNamedNonDefault()
43 | {
44 | $fixture = 'first.tar';
45 | $name = 'Pulsestorm_Unittestdifferent';
46 | $config = $this->_getBaseExtensionConfig($fixture);
47 | $config['extension_name'] = $name;
48 |
49 | $results = $this->_buildExtensionFromFixture('first.tar', $config);
50 | $this->assertTrue((boolean)strpos($results['extension'], $name));
51 | $this->assertTrue(file_exists($results['extension']));
52 | }
53 |
54 | public function testRunTarToConnectAndTmpExtraction()
55 | {
56 | $results = $this->_buildExtensionFromFixture('first.tar');
57 |
58 | $this->assertTrue(file_exists($results['extracted'] . '/package.xml'));
59 | $this->assertTrue(file_exists($results['extracted'] . '/first.txt'));
60 | }
61 |
62 | public function testBetter404()
63 | {
64 | $results = $this->_buildExtensionFromFixture('Pulsestorm_Better404.tar');
65 | $this->assertTrue(file_exists($results['extension']));
66 | $this->assertTrue(file_exists($results['extension']));
67 | $this->assertTrue(file_exists($results['connect_xml']));
68 | }
69 | }
--------------------------------------------------------------------------------
/tests/fixtures/Pulsestorm_Better404.tar:
--------------------------------------------------------------------------------
1 | app/code/community/Pulsestorm/Better404/ 000755 000765 000000 00000000000 12232106127 021560 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/Block/ 000755 000765 000000 00000000000 12255012032 022606 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/controllers/ 000755 000765 000000 00000000000 12255004711 024127 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/etc/ 000755 000765 000000 00000000000 12255004723 022337 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/Helper/ 000755 000765 000000 00000000000 12232106127 022777 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/layouts/ 000755 000765 000000 00000000000 12232106127 023260 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/Model/ 000755 000765 000000 00000000000 12255012121 022613 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/sql/ 000755 000765 000000 00000000000 12232106127 022357 5 ustar 00alanstorm wheel 000000 000000 app/code/community/Pulsestorm/Better404/Model/Lint.php 000644 000765 000024 00000013206 12255012121 024241 0 ustar 00alanstorm staff 000000 000000 _initRouters();
18 | $this->_initClaimed();
19 | }
20 |
21 | protected function _getConfigNodesWithRouters()
22 | {
23 | return array('frontend', 'admin');
24 | }
25 |
26 | protected function _initClaimed()
27 | {
28 | $module = $this->getUrlModuleName();
29 | $this->_claimed = array();
30 |
31 | $nodes = $this->_getConfigNodesWithRouters();
32 | foreach($nodes as $node)
33 | {
34 | //front name
35 | foreach($this->_routers[$node] as $router)
36 | {
37 | $args = $router->args;
38 | if(!$args)
39 | {
40 | continue;
41 | }
42 | if((string)$args->frontName == $module)
43 | {
44 | $this->_claimed[] = $router;
45 | }
46 | }
47 | }
48 | return $this->_claimed;
49 | }
50 |
51 | public function getClaimed()
52 | {
53 | return $this->_claimed;
54 | }
55 |
56 | protected function _initRouters()
57 | {
58 | $config = Mage::getConfig();
59 | $nodes = $this->_getConfigNodesWithRouters();
60 | foreach($nodes as $node)
61 | {
62 | $frontend = $config->getNode($node);
63 | foreach($frontend->routers->children() as $router)
64 | {
65 | $this->_routers[$node][$router->getName()] = $router;
66 | }
67 | }
68 | }
69 |
70 | public function getUrlOriginalPath()
71 | {
72 | if(!$this->_originalPath)
73 | {
74 | $this->_originalPath = Mage::app()->getRequest()->getOriginalPathInfo();
75 | }
76 | return $this->_originalPath;
77 | }
78 |
79 | public function getUrlModuleName()
80 | {
81 | if(!$this->_inferedModule)
82 | {
83 | $path = $this->getUrlOriginalPath();
84 | $path = trim($path, '/');
85 | $path = explode('/', $path);
86 | $this->_inferedModule = array_shift($path);
87 | }
88 | return $this->_inferedModule;
89 | }
90 |
91 | public function getUrlControllerName()
92 | {
93 | if(!$this->_inferedController)
94 | {
95 | $path = $this->getUrlOriginalPath();
96 | $path = trim($path, '/');
97 | $path = explode('/', $path);
98 | $this->_inferedController = array_key_exists(1,$path) ? $path[1] : 'index';
99 | }
100 | return $this->_inferedController;
101 | }
102 |
103 | public function getUrlActionName()
104 | {
105 | if(!$this->_inferedAction)
106 | {
107 | $path = $this->getUrlOriginalPath();
108 | $path = trim($path, '/');
109 | $path = explode('/', $path);
110 | $this->_inferedAction = array_key_exists(2,$path) ? $path[2] : 'index';
111 | }
112 | return $this->_inferedAction;
113 | }
114 |
115 | public function getControllerInformation($module_name)
116 | {
117 | if(!$this->_controllerInformation)
118 | {
119 | $router_object = new Mage_Core_Controller_Varien_Router_Standard;
120 | $this->_controllerInformation = array();
121 | $this->_controllerInformation['class_file'] = $router_object->getControllerFileName($module_name, $this->getUrlControllerName());
122 | $this->_controllerInformation['class_name'] = $router_object->getControllerClassName($module_name, $this->getUrlControllerName());
123 | }
124 | return $this->_controllerInformation;
125 | }
126 |
127 | public function getActionMethodExists($controller_name,$action)
128 | {
129 | $info = $this->getControllerInformation($this->getUrlModuleName());
130 | require_once $info['class_file'];
131 | $r = new ReflectionClass($controller_name);
132 | return $r->hasMethod($action . 'Action');
133 | }
134 |
135 | public function getClaimedByName()
136 | {
137 | $claimed = $this->getClaimed();
138 | return (string) $claimed[0]->args->module;
139 | }
140 |
141 | public function getControllerClassExists($module_name)
142 | {
143 | $info = $this->getControllerInformation($module_name);
144 | $tokens = token_get_all(file_get_contents($info['class_file']));
145 |
146 | $state = self::STATE_NEUTRAL;
147 | foreach($tokens as $token)
148 | {
149 | if(!is_array($token)) //skip single character tokens
150 | {
151 | continue;
152 | }
153 | $constant_value = $token[0];
154 | $real_value = $token[1];
155 | $token_name = token_name($constant_value);
156 | if($token_name == 'T_CLASS')
157 | {
158 | $state = self::STATE_CLASS_DEF;
159 | }
160 | if($state != self::STATE_CLASS_DEF)
161 | {
162 | continue;
163 | }
164 | //first T_STRING after
165 | if($token_name == 'T_STRING')
166 | {
167 | return $info['class_name'] == $real_value;
168 | }
169 | }
170 | return false;
171 | }
172 |
173 | public function getExtraModules()
174 | {
175 |
176 | $claimed = $this->getClaimed();
177 | $router = array_shift($claimed);
178 | $args = $router->args;
179 | if(!$args)
180 | {
181 | return array();
182 | }
183 |
184 | $modules = $args->modules;
185 | if(!$modules)
186 | {
187 | return array();
188 | }
189 |
190 | $return = array();
191 | foreach($modules->children() as $module)
192 | {
193 | $return[] = (string) $module;
194 | }
195 | return $return;
196 | }
197 | } app/code/community/Pulsestorm/Better404/Model/Observer.php 000644 000765 000024 00000001640 12254733752 025144 0 ustar 00alanstorm staff 000000 000000 _is404())
203 | {
204 | return;
205 | }
206 |
207 | $layout = $observer->getLayout();
208 | $block = $layout->getBlock('cms.wrapper');
209 | if(!$block)
210 | {
211 | return;
212 | }
213 | $layout->unsetBlock('cms.wrapper');
214 | $block = $layout->createBlock('pulsestorm_better404/404','cms.wrapper');
215 | $block->setBlock('cms.wrapper', $block);
216 | }
217 |
218 | protected function _is404()
219 | {
220 | $headers = Mage::app()->getResponse()->getHeaders();
221 | foreach($headers as $header)
222 | {
223 | if(strToLower($header['name']) != 'status')
224 | {
225 | continue;
226 | }
227 |
228 | if(strpos($header['value'],'404') !== false)
229 | {
230 | return true;
231 | }
232 | }
233 | return false;
234 | }
235 | } app/code/community/Pulsestorm/Better404/etc/config.xml 000644 000765 000024 00000001655 12255004722 024341 0 ustar 00alanstorm staff 000000 000000
236 |
237 |
238 |
239 | 0.1.0
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 | Pulsestorm_Better404_Model
248 |
249 |
250 |
251 |
252 |
253 | Pulsestorm_Better404_Block
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 | singleton
262 | pulsestorm_better404/observer
263 | addExtraBlocks
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 | app/code/community/Pulsestorm/Better404/Block/404.php 000644 000765 000024 00000004221 12255012032 023632 0 ustar 00alanstorm staff 000000 000000 _initLint();
278 | $this->setTemplate('pulsestorm_better404/404.phtml');
279 | }
280 |
281 | public function getClaimedByName()
282 | {
283 | return $this->_lint->getClaimedByName();
284 | }
285 |
286 | public function getUrlOriginalPath()
287 | {
288 | return $this->_lint->getUrlOriginalPath();
289 | }
290 |
291 | public function getClaimed()
292 | {
293 | return $this->_lint->getClaimed();
294 | }
295 |
296 | public function getUrlModuleName()
297 | {
298 | return $this->_lint->getUrlModuleName();
299 | }
300 |
301 | public function getUrlControllerName()
302 | {
303 | return $this->_lint->getUrlControllerName();
304 | }
305 |
306 | public function getUrlActionName()
307 | {
308 | return $this->_lint->getUrlActionName();
309 | }
310 |
311 | public function getControllerFilePath($module_name)
312 | {
313 | $info = $this->_lint->getControllerInformation($module_name);
314 | return $info['class_file'];
315 | }
316 |
317 | /**
318 | * Crude state machine to check if the class exists
319 | */
320 | public function getControllerClassExists($module_name)
321 | {
322 | return $this->_lint->getControllerClassExists($module_name);
323 | }
324 |
325 | public function getControllerInformation($module_name)
326 | {
327 | return $this->_lint->getControllerInformation($module_name);
328 | }
329 |
330 | public function getControllerClassName($module_name)
331 | {
332 | $info = $this->_lint->getControllerInformation($module_name);
333 | return $info['class_name'];
334 | }
335 |
336 | public function getControllerFileExists($module_name)
337 | {
338 | $info = $this->_lint->getControllerInformation($module_name);
339 | return file_exists($info['class_file']);
340 | }
341 |
342 | public function getActionMethodExists($controller_name, $action)
343 | {
344 | return $this->_lint->getActionMethodExists($controller_name, $action);
345 | }
346 |
347 | public function getExtraModules()
348 | {
349 | return $this->_lint->getExtraModules();
350 | }
351 | protected function _initLint()
352 | {
353 | $this->_lint = Mage::getModel('pulsestorm_better404/lint');
354 | return $this->_lint;
355 | }
356 | } app/etc/modules/Pulsestorm_Better404.xml 000644 000765 000024 00000000252 12232106127 021653 0 ustar 00alanstorm staff 000000 000000 truecommunity