From 0e00601e070c5c71e6d3a6478fa61198e30c2964 Mon Sep 17 00:00:00 2001 From: Vijaya Chandran Mani Date: Tue, 26 Mar 2019 09:14:17 +0000 Subject: [PATCH] #71 - Robustness: Have fallbacks if http://cgit.drupalcode.org is not available (#100) --- .scenarios.lock/phpunit4/composer.json | 2 +- .scenarios.lock/phpunit4/composer.lock | 188 +++++++++++++------------ .travis.yml | 1 + README.md | 15 ++ composer.lock | 4 +- src/FileFetcher.php | 55 +++++++- src/Handler.php | 44 +++++- src/PrestissimoFileFetcher.php | 30 ++-- tests/FetcherTest.php | 6 +- 9 files changed, 226 insertions(+), 119 deletions(-) diff --git a/.scenarios.lock/phpunit4/composer.json b/.scenarios.lock/phpunit4/composer.json index 52d5a59..eb5fa02 100644 --- a/.scenarios.lock/phpunit4/composer.json +++ b/.scenarios.lock/phpunit4/composer.json @@ -4,7 +4,7 @@ "type": "composer-plugin", "license": "GPL-2.0-or-later", "require": { - "php": ">=5.4.5", + "php": "^5.5.9|>=7.0.8", "composer-plugin-api": "^1.0.0", "composer/semver": "^1.4" }, diff --git a/.scenarios.lock/phpunit4/composer.lock b/.scenarios.lock/phpunit4/composer.lock index 084a62b..c234829 100644 --- a/.scenarios.lock/phpunit4/composer.lock +++ b/.scenarios.lock/phpunit4/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "445ab29fa63d93c2f4ff7da62f90de16", + "content-hash": "421671c61c80e5b56a0317e25a7c457b", "packages": [ { "name": "composer/semver", @@ -72,16 +72,16 @@ "packages-dev": [ { "name": "composer/ca-bundle", - "version": "1.1.1", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169" + "reference": "8afa52cd417f4ec417b4bfe86b68106538a87660" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d2c0a83b7533d6912e8d516756ebd34f893e9169", - "reference": "d2c0a83b7533d6912e8d516756ebd34f893e9169", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8afa52cd417f4ec417b4bfe86b68106538a87660", + "reference": "8afa52cd417f4ec417b4bfe86b68106538a87660", "shasum": "" }, "require": { @@ -124,7 +124,7 @@ "ssl", "tls" ], - "time": "2018-03-29T19:57:20+00:00" + "time": "2018-10-18T06:09:13+00:00" }, { "name": "composer/composer", @@ -132,12 +132,12 @@ "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "837ad7c14e8ce364296e0d0600d04c415b6e359d" + "reference": "154ae6fae28c210cd6cf5d76aace04aefef1ca65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/837ad7c14e8ce364296e0d0600d04c415b6e359d", - "reference": "837ad7c14e8ce364296e0d0600d04c415b6e359d", + "url": "https://api.github.com/repos/composer/composer/zipball/154ae6fae28c210cd6cf5d76aace04aefef1ca65", + "reference": "154ae6fae28c210cd6cf5d76aace04aefef1ca65", "shasum": "" }, "require": { @@ -173,7 +173,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -204,20 +204,20 @@ "dependency", "package" ], - "time": "2018-06-07T09:15:18+00:00" + "time": "2019-01-03T09:53:00+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "cb17687e9f936acd7e7245ad3890f953770dec1b" + "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/cb17687e9f936acd7e7245ad3890f953770dec1b", - "reference": "cb17687e9f936acd7e7245ad3890f953770dec1b", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7a9556b22bd9d4df7cad89876b00af58ef20d3a2", + "reference": "7a9556b22bd9d4df7cad89876b00af58ef20d3a2", "shasum": "" }, "require": { @@ -265,20 +265,20 @@ "spdx", "validator" ], - "time": "2018-04-30T10:33:04+00:00" + "time": "2018-11-01T09:45:54+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.1.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08" + "reference": "dc523135366eb68f22268d069ea7749486458562" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/c919dc6c62e221fc6406f861ea13433c0aa24f08", - "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562", + "reference": "dc523135366eb68f22268d069ea7749486458562", "shasum": "" }, "require": { @@ -309,7 +309,7 @@ "Xdebug", "performance" ], - "time": "2018-04-11T15:42:36+00:00" + "time": "2018-11-29T10:59:02+00:00" }, { "name": "doctrine/instantiator", @@ -367,16 +367,16 @@ }, { "name": "g1a/composer-test-scenarios", - "version": "2.1.0", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/g1a/composer-test-scenarios.git", - "reference": "4c2b990712dbcb87a0ab618e46f908c731c3a0bb" + "reference": "a166fd15191aceab89f30c097e694b7cf3db4880" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/g1a/composer-test-scenarios/zipball/4c2b990712dbcb87a0ab618e46f908c731c3a0bb", - "reference": "4c2b990712dbcb87a0ab618e46f908c731c3a0bb", + "url": "https://api.github.com/repos/g1a/composer-test-scenarios/zipball/a166fd15191aceab89f30c097e694b7cf3db4880", + "reference": "a166fd15191aceab89f30c097e694b7cf3db4880", "shasum": "" }, "bin": [ @@ -396,7 +396,7 @@ } ], "description": "Useful scripts for testing multiple sets of Composer dependencies.", - "time": "2018-06-10T21:56:28+00:00" + "time": "2018-08-08T23:37:23+00:00" }, { "name": "justinrainbow/json-schema", @@ -612,16 +612,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.7.6", + "version": "1.8.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712" + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712", - "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", "shasum": "" }, "require": { @@ -633,12 +633,12 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7.x-dev" + "dev-master": "1.8.x-dev" } }, "autoload": { @@ -671,7 +671,7 @@ "spy", "stub" ], - "time": "2018-04-18T13:57:24+00:00" + "time": "2018-08-05T17:53:17+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1051,16 +1051,16 @@ }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "shasum": "" }, "require": { @@ -1094,7 +1094,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2018-11-20T15:27:04+00:00" }, { "name": "sebastian/comparator", @@ -1563,16 +1563,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "2.9.1", + "version": "2.9.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62" + "reference": "2acf168de78487db620ab4bc524135a13cfe6745" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/dcbed1074f8244661eecddfc2a675430d8d33f62", - "reference": "dcbed1074f8244661eecddfc2a675430d8d33f62", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", + "reference": "2acf168de78487db620ab4bc524135a13cfe6745", "shasum": "" }, "require": { @@ -1637,20 +1637,20 @@ "phpcs", "standards" ], - "time": "2017-05-22T02:43:20+00:00" + "time": "2018-11-07T22:31:41+00:00" }, { "name": "symfony/console", - "version": "v3.4.11", + "version": "v3.4.21", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "36f83f642443c46f3cf751d4d2ee5d047d757a27" + "reference": "a700b874d3692bc8342199adfb6d3b99f62cc61a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/36f83f642443c46f3cf751d4d2ee5d047d757a27", - "reference": "36f83f642443c46f3cf751d4d2ee5d047d757a27", + "url": "https://api.github.com/repos/symfony/console/zipball/a700b874d3692bc8342199adfb6d3b99f62cc61a", + "reference": "a700b874d3692bc8342199adfb6d3b99f62cc61a", "shasum": "" }, "require": { @@ -1706,20 +1706,20 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-05-16T08:49:21+00:00" + "time": "2019-01-04T04:42:43+00:00" }, { "name": "symfony/debug", - "version": "v3.4.11", + "version": "v3.4.21", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68" + "reference": "26d7f23b9bd0b93bee5583e4d6ca5cb1ab31b186" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/b28fd73fefbac341f673f5efd707d539d6a19f68", - "reference": "b28fd73fefbac341f673f5efd707d539d6a19f68", + "url": "https://api.github.com/repos/symfony/debug/zipball/26d7f23b9bd0b93bee5583e4d6ca5cb1ab31b186", + "reference": "26d7f23b9bd0b93bee5583e4d6ca5cb1ab31b186", "shasum": "" }, "require": { @@ -1762,20 +1762,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-05-16T14:03:39+00:00" + "time": "2019-01-01T13:45:19+00:00" }, { "name": "symfony/filesystem", - "version": "v3.4.11", + "version": "v3.4.21", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0" + "reference": "c24ce3d18ccc9bb9d7e1d6ce9330fcc6061cafde" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0", - "reference": "8e03ca3fa52a0f56b87506f38cf7bd3f9442b3a0", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/c24ce3d18ccc9bb9d7e1d6ce9330fcc6061cafde", + "reference": "c24ce3d18ccc9bb9d7e1d6ce9330fcc6061cafde", "shasum": "" }, "require": { @@ -1812,20 +1812,20 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2018-05-16T08:49:21+00:00" + "time": "2019-01-01T13:45:19+00:00" }, { "name": "symfony/finder", - "version": "v3.4.11", + "version": "v3.4.21", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "472a92f3df8b247b49ae364275fb32943b9656c6" + "reference": "3f2a2ab6315dd7682d4c16dcae1e7b95c8b8555e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/472a92f3df8b247b49ae364275fb32943b9656c6", - "reference": "472a92f3df8b247b49ae364275fb32943b9656c6", + "url": "https://api.github.com/repos/symfony/finder/zipball/3f2a2ab6315dd7682d4c16dcae1e7b95c8b8555e", + "reference": "3f2a2ab6315dd7682d4c16dcae1e7b95c8b8555e", "shasum": "" }, "require": { @@ -1861,29 +1861,32 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-05-16T08:49:21+00:00" + "time": "2019-01-01T13:45:19+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.8.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", - "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", + "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "suggest": { + "ext-ctype": "For best performance" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -1916,20 +1919,20 @@ "polyfill", "portable" ], - "time": "2018-04-30T19:57:29+00:00" + "time": "2018-08-06T14:22:27+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.8.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "3296adf6a6454a050679cde90f95350ad604b171" + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", - "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "shasum": "" }, "require": { @@ -1941,7 +1944,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.8-dev" + "dev-master": "1.9-dev" } }, "autoload": { @@ -1975,20 +1978,20 @@ "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-09-21T13:07:52+00:00" }, { "name": "symfony/process", - "version": "v3.4.11", + "version": "v3.4.21", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "4cbf2db9abcb01486a21b7a059e03a62fae63187" + "reference": "0d41dd7d95ed179aed6a13393b0f4f97bfa2d25c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/4cbf2db9abcb01486a21b7a059e03a62fae63187", - "reference": "4cbf2db9abcb01486a21b7a059e03a62fae63187", + "url": "https://api.github.com/repos/symfony/process/zipball/0d41dd7d95ed179aed6a13393b0f4f97bfa2d25c", + "reference": "0d41dd7d95ed179aed6a13393b0f4f97bfa2d25c", "shasum": "" }, "require": { @@ -2024,20 +2027,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-05-16T08:49:21+00:00" + "time": "2019-01-02T21:24:08+00:00" }, { "name": "symfony/yaml", - "version": "v3.4.11", + "version": "v3.4.21", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0" + "reference": "554a59a1ccbaac238a89b19c8e551a556fd0e2ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/c5010cc1692ce1fa328b1fb666961eb3d4a85bb0", - "reference": "c5010cc1692ce1fa328b1fb666961eb3d4a85bb0", + "url": "https://api.github.com/repos/symfony/yaml/zipball/554a59a1ccbaac238a89b19c8e551a556fd0e2ea", + "reference": "554a59a1ccbaac238a89b19c8e551a556fd0e2ea", "shasum": "" }, "require": { @@ -2083,24 +2086,25 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-05-03T23:18:14+00:00" + "time": "2019-01-01T13:45:19+00:00" }, { "name": "webmozart/assert", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "phpunit/phpunit": "^4.6", @@ -2133,7 +2137,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2018-12-25T11:19:39+00:00" } ], "aliases": [], @@ -2144,7 +2148,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.4.5" + "php": "^5.5.9|>=7.0.8" }, "platform-dev": [], "platform-overrides": { diff --git a/.travis.yml b/.travis.yml index ba2f61e..6e47b29 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,7 @@ install: before_script: - git config --global user.email "travisci@example.com" - git config --global user.name "Travis CI Test" + - export COMPOSER_PROCESS_TIMEOUT=600 script: - composer test diff --git a/README.md b/README.md index 8e7291e..69f179a 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,21 @@ The `source` option may be used to specify the URL to download the scaffold files from; the default source is drupal.org. The literal string `{version}` in the `source` option is replaced with the current version of Drupal core being updated prior to download. +You can also define `source` as an array to have fallbacks in case of +any HTTP issues. + +```json +{ + "extra": { + "drupal-scaffold": { + "source": [ + "https://cgit.drupalcode.org/drupal/plain/{path}?h={version}", + "https://raw.githubusercontent.com/drupal/drupal/{version}/{path}" + ] + } + } +} +``` With the `drupal-scaffold` option `excludes`, you can provide additional paths that should not be copied or overwritten. The plugin provides no excludes by diff --git a/composer.lock b/composer.lock index 707e504..2fa2c27 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cc2cd84cd41c52965cd00f2e515bb6d3", + "content-hash": "c6f275dbfe63c4cfa101ba653aac235e", "packages": [ { "name": "composer/semver", @@ -2481,7 +2481,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=5.4.5" + "php": "^5.5.9|>=7.0.8" }, "platform-dev": [], "platform-overrides": { diff --git a/src/FileFetcher.php b/src/FileFetcher.php index 59b9227..ac38390 100644 --- a/src/FileFetcher.php +++ b/src/FileFetcher.php @@ -49,13 +49,19 @@ class FileFetcher { */ protected $fs; + /** + * @var array + * + * A list of potential errors. + */ + protected $errors = []; + /** * Constructs this FileFetcher object. */ - public function __construct(RemoteFilesystem $remoteFilesystem, $source, IOInterface $io, $progress = TRUE) { + public function __construct(RemoteFilesystem $remoteFilesystem, IOInterface $io, $progress = TRUE) { $this->remoteFilesystem = $remoteFilesystem; $this->io = $io; - $this->source = $source; $this->fs = new Filesystem(); $this->progress = $progress; } @@ -64,23 +70,39 @@ public function __construct(RemoteFilesystem $remoteFilesystem, $source, IOInter * Downloads all required files and writes it to the file system. */ public function fetch($version, $destination, $override) { + $errors = []; + foreach ($this->filenames as $sourceFilename => $filename) { $target = "$destination/$filename"; if ($override || !file_exists($target)) { $url = $this->getUri($sourceFilename, $version); $this->fs->ensureDirectoryExists($destination . '/' . dirname($filename)); + if ($this->progress) { $this->io->writeError(" - $filename ($url): ", FALSE); - $this->remoteFilesystem->copy($url, $url, $target, $this->progress); - // Used to put a new line because the remote file system does not put - // one. + try { + $this->remoteFilesystem->copy($url, $url, $target, $this->progress); + } catch(\Exception $e) { + $errors[] = $url; + } + // New line because the remoteFilesystem does not put one. $this->io->writeError(''); } else { - $this->remoteFilesystem->copy($url, $url, $target, $this->progress); + try { + $this->remoteFilesystem->copy($url, $url, $target, $this->progress); + } catch(\Exception $e) { + $errors[] = $url; + } } } } + + if ($errors) { + $this->addError('Failed to download: ' . "\r\n" . implode("\r\n", $errors)); + return FALSE; + } + return TRUE; } /** @@ -90,6 +112,27 @@ public function setFilenames(array $filenames) { $this->filenames = $filenames; } + /** + * Set source. + */ + public function setSource($source) { + $this->source = $source; + } + + /** + * Set error. + */ + public function addError($error) { + $this->errors[] = $error; + } + + /** + * Get errors. + */ + public function getErrors() { + return $this->errors; + } + /** * Replace filename and version in the source pattern with their values. */ diff --git a/src/Handler.php b/src/Handler.php index 23cb9d9..51f1233 100644 --- a/src/Handler.php +++ b/src/Handler.php @@ -149,6 +149,7 @@ public function downloadScaffold() { // Collect options, excludes and settings files. $options = $this->getOptions(); $files = array_diff($this->getIncludes(), $this->getExcludes()); + $files = array_combine($files, $files); // Call any pre-scaffold scripts that may be defined. $dispatcher = new EventDispatcher($this->composer, $this->io); @@ -158,12 +159,39 @@ public function downloadScaffold() { $remoteFs = new RemoteFilesystem($this->io); - $fetcher = new PrestissimoFileFetcher($remoteFs, $options['source'], $this->io, $this->progress, $this->composer->getConfig()); - $fetcher->setFilenames(array_combine($files, $files)); - $fetcher->fetch($version, $webroot, TRUE); + $fetcher = new PrestissimoFileFetcher($remoteFs, $this->io, $this->progress, $this->composer->getConfig()); + $sources = (array) $options['source']; + $all_succeeded = FALSE; - $fetcher->setFilenames($this->getInitial()); - $fetcher->fetch($version, $webroot, FALSE); + do { + $source = current($sources); + + $fetcher->setSource($source); + + $fetcher->setFilenames($files); + if ($fetcher->fetch($version, $webroot, TRUE)) { + $fetcher->setFilenames($this->getInitial()); + if ($fetcher->fetch($version, $webroot, FALSE)) { + $all_succeeded = TRUE; + break; + } + } + + // If here, it means that the fetch for this source has failed. + $next_source = next($sources); + + $this->io->writeError(''); + $this->io->writeError(" - Has failed with the " . (!$next_source ? 'last ' : '') . "source: $source", TRUE); + if ($next_source) { + $this->io->writeError(" - Now trying with the source: $next_source", TRUE); + } + $this->io->writeError(''); + + } while($next_source); + + if (!$all_succeeded) { + throw new \Exception(implode("\r\n\r\n", $fetcher->getErrors())); + } // Call post-scaffold scripts. $dispatcher->dispatch(self::POST_DRUPAL_SCAFFOLD_CMD); @@ -343,8 +371,10 @@ protected function getOptions() { 'excludes' => [], 'includes' => [], 'initial' => [], - 'source' => 'https://cgit.drupalcode.org/drupal/plain/{path}?h={version}', - // Github: https://raw.githubusercontent.com/drupal/drupal/{version}/{path} + 'source' => [ + 'https://cgit.drupalcode.org/drupal/plain/{path}?h={version}', + 'https://raw.githubusercontent.com/drupal/drupal/{version}/{path}' + ], ]; return $options; } diff --git a/src/PrestissimoFileFetcher.php b/src/PrestissimoFileFetcher.php index 30b7c23..25dccd7 100644 --- a/src/PrestissimoFileFetcher.php +++ b/src/PrestissimoFileFetcher.php @@ -22,8 +22,8 @@ class PrestissimoFileFetcher extends FileFetcher { /** * Constructs this PrestissimoFileFetcher object. */ - public function __construct(RemoteFilesystem $remoteFilesystem, $source, IOInterface $io, $progress = TRUE, Config $config) { - parent::__construct($remoteFilesystem, $source, $io, $progress); + public function __construct(RemoteFilesystem $remoteFilesystem, IOInterface $io, $progress = TRUE, Config $config) { + parent::__construct($remoteFilesystem, $io, $progress); $this->config = $config; } @@ -32,10 +32,9 @@ public function __construct(RemoteFilesystem $remoteFilesystem, $source, IOInter */ public function fetch($version, $destination, $override) { if (class_exists(CurlMulti::class)) { - $this->fetchWithPrestissimo($version, $destination, $override); - return; + return $this->fetchWithPrestissimo($version, $destination, $override); } - parent::fetch($version, $destination, $override); + return parent::fetch($version, $destination, $override); } /** @@ -57,7 +56,7 @@ protected function fetchWithPrestissimo($version, $destination, $override) { $errors = []; $totalCnt = count($requests); if ($totalCnt == 0) { - return; + return TRUE; } $multi = new CurlMulti(); @@ -70,6 +69,9 @@ protected function fetchWithPrestissimo($version, $destination, $override) { $failureCnt += $result['failureCnt']; if (isset($result['errors'])) { $errors += $result['errors']; + foreach ($result['errors'] as $url => $error) { + $this->io->writeError(" - Downloading $successCnt/$totalCnt: $url (failed)", TRUE); + } } if ($this->progress) { foreach ($result['urls'] as $url) { @@ -78,10 +80,20 @@ protected function fetchWithPrestissimo($version, $destination, $override) { } } while ($multi->remain()); - $urls = array_keys($errors); - if ($urls) { - throw new \Exception('Failed to download ' . implode(", ", $urls)); + if ($errors) { + $this->addError('Failed to download: ' . "\r\n" . implode("\r\n", array_keys($errors))); + $errors_extra = []; + foreach($errors as $error) { + if ($error !== "0: " && !isset($errors_extra[$error])) { + $errors_extra[$error] = $error; + } + } + if ($errors_extra) { + $this->addError(implode("\r\n", $errors_extra)); + } + return FALSE; } + return TRUE; } } diff --git a/tests/FetcherTest.php b/tests/FetcherTest.php index ea822f9..df2a973 100644 --- a/tests/FetcherTest.php +++ b/tests/FetcherTest.php @@ -57,7 +57,8 @@ protected function ensureDirectoryExistsAndClear($directory) { } public function testFetch() { - $fetcher = new FileFetcher(new RemoteFilesystem(new NullIO()), 'https://cgit.drupalcode.org/drupal/plain/{path}?h={version}', new NullIO()); + $fetcher = new FileFetcher(new RemoteFilesystem(new NullIO()), new NullIO()); + $fetcher->setSource('https://cgit.drupalcode.org/drupal/plain/{path}?h={version}'); $fetcher->setFilenames([ '.htaccess' => '.htaccess', 'sites/default/default.settings.php' => 'sites/default/default.settings.php', @@ -68,7 +69,8 @@ public function testFetch() { } public function testInitialFetch() { - $fetcher = new FileFetcher(new RemoteFilesystem(new NullIO()), 'https://cgit.drupalcode.org/drupal/plain/{path}?h={version}', new NullIO()); + $fetcher = new FileFetcher(new RemoteFilesystem(new NullIO()), new NullIO()); + $fetcher->setSource('https://cgit.drupalcode.org/drupal/plain/{path}?h={version}'); $fetcher->setFilenames([ 'sites/default/default.settings.php' => 'sites/default/settings.php', ]);