From 770292a42cf28440a01dfa2c21f16130b4a383c2 Mon Sep 17 00:00:00 2001 From: ntoniazzi Date: Tue, 11 Dec 2012 11:49:30 +0100 Subject: [PATCH 1/9] Conforming to XDG Base Directory Specification (http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) --- src/Composer/Factory.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index d02f68d41..c2565c0b4 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -42,7 +42,11 @@ class Factory if (defined('PHP_WINDOWS_VERSION_MAJOR')) { $home = getenv('APPDATA') . '/Composer'; } else { - $home = rtrim(getenv('HOME'), '/') . '/.composer'; + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = rtrim(getenv('HOME'), '/') . '/.config'; + } + $home = $xdgConfig . '/composer'; } } if (!$cacheDir) { @@ -53,7 +57,11 @@ class Factory $cacheDir = getenv('APPDATA') . '/Composer/cache'; } } else { - $cacheDir = $home.'/cache'; + $xdgCache = getenv('XDG_CACHE_HOME'); + if (!$xdgCache) { + $xdgCache = rtrim(getenv('HOME'), '/') . '/.cache'; + } + $cacheDir = $xdgCache . '/composer'; } } From 6821e3efcc49a813b76f59bce6a625b14d88ab13 Mon Sep 17 00:00:00 2001 From: ntoniazzi Date: Wed, 2 Jan 2013 13:48:00 +0100 Subject: [PATCH 2/9] Conforming to XDG Base Directory Specification (http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) --- doc/03-cli.md | 8 +++++--- doc/04-schema.md | 5 +++-- src/Composer/Factory.php | 34 +++++++++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 870509c3a..7bec79bba 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -400,9 +400,11 @@ The `COMPOSER_HOME` var allows you to change the composer home directory. This is a hidden, global (per-user on the machine) directory that is shared between all projects. -By default it points to `/home//.composer` on *nix, -`/Users//.composer` on OSX and -`C:\Users\\AppData\Roaming\Composer` on Windows. +By default it points to `C:\Users\\AppData\Roaming\Composer` on Windows +and `/Users//.composer` on OSX. On *nix systems that follow the [XDG Base +Directory Specifications](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html), +it points to `$XDG_CONFIG_HOME/composer`. On other *nix systems, it points to +`/home//.composer`. #### COMPOSER_HOME/config.json diff --git a/doc/04-schema.md b/doc/04-schema.md index 71c4fd692..0f7096f12 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -598,8 +598,9 @@ The following options are supported: `{"github.com": "oauthtoken"}` as the value of this option will use `oauthtoken` to access private repositories on github and to circumvent the low IP-based rate limiting of their API. -* **cache-dir:** Defaults to `$home/cache` on unix systems and - `C:\Users\\AppData\Local\Composer` on Windows. Stores all the caches +* **cache-dir:** Defaults to `C:\Users\\AppData\Local\Composer` on Windows, + `$XDG_CACHE_HOME/composer` on unix systems that follow the XDG Base Directory + Specifications, and `$home/cache` on other unix systems. Stores all the caches used by composer. See also [COMPOSER_HOME](03-cli.md#composer-home). * **cache-files-dir:** Defaults to `$cache-dir/files`. Stores the zip archives of packages. diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index c2565c0b4..2dbf52dfa 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -38,15 +38,21 @@ class Factory // determine home and cache dirs $home = getenv('COMPOSER_HOME'); $cacheDir = getenv('COMPOSER_CACHE_DIR'); + $userDir = rtrim(getenv('HOME'), '/'); + $followXDG = false; if (!$home) { if (defined('PHP_WINDOWS_VERSION_MAJOR')) { $home = getenv('APPDATA') . '/Composer'; - } else { + } elseif (getenv('XDG_CONFIG_DIRS')) { + // XDG Base Directory Specifications + $followXDG = true; $xdgConfig = getenv('XDG_CONFIG_HOME'); if (!$xdgConfig) { - $xdgConfig = rtrim(getenv('HOME'), '/') . '/.config'; + $xdgConfig = $userDir . '/.config'; } $home = $xdgConfig . '/composer'; + } else { + $home = $userDir . '/.composer'; } } if (!$cacheDir) { @@ -56,15 +62,20 @@ class Factory } else { $cacheDir = getenv('APPDATA') . '/Composer/cache'; } - } else { + } elseif (getenv('XDG_CONFIG_DIRS')) { + $followXDG = true; $xdgCache = getenv('XDG_CACHE_HOME'); if (!$xdgCache) { - $xdgCache = rtrim(getenv('HOME'), '/') . '/.cache'; + $xdgCache = $userDir . '/.cache'; } $cacheDir = $xdgCache . '/composer'; + + + } else { + $cacheDir = $home . '/.cache'; } } - + // Protect directory against web access. Since HOME could be // the www-data's user home and be web-accessible it is a // potential security risk @@ -77,6 +88,19 @@ class Factory } } + // Move content of old composer dir to XDG + if ($followXDG && file_exists($userDir . '/.composer')) { + // migrate to XDG + @rename($userDir . '/.composer/config.json', $home . '/config.json'); + @unlink($userDir . '/.composer/.htaccess'); + @unlink($userDir . '/.composer/cache/.htaccess'); + foreach (glob($userDir . '/.composer/cache/*') as $oldCacheDir) { + @rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); + } + @rmdir($userDir . '/.composer/cache'); + @rmdir($userDir . '/.composer'); + } + $config = new Config(); // add dirs to the config From 50c6c100fa65a47f112197408d93169d0dba9b0f Mon Sep 17 00:00:00 2001 From: Nicolas Toniazzi Date: Thu, 16 Oct 2014 14:39:48 +0200 Subject: [PATCH 3/9] Added support for backup PHARs --- src/Composer/Command/SelfUpdateCommand.php | 2 +- src/Composer/Config.php | 2 + src/Composer/Factory.php | 138 +++++++++++++-------- 3 files changed, 90 insertions(+), 52 deletions(-) diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 13abee32b..2975a7fa0 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -61,7 +61,7 @@ EOT $config = Factory::createConfig(); $remoteFilesystem = new RemoteFilesystem($this->getIO(), $config); $cacheDir = $config->get('cache-dir'); - $rollbackDir = $config->get('home'); + $rollbackDir = $config->get('data-dir'); $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; // check if current dir is writable and if not try the cache dir from settings diff --git a/src/Composer/Config.php b/src/Composer/Config.php index d5b41efe2..478dad84a 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -28,6 +28,7 @@ class Config 'vendor-dir' => 'vendor', 'bin-dir' => '{$vendor-dir}/bin', 'cache-dir' => '{$home}/cache', + 'data-dir' => '{$home}', 'cache-files-dir' => '{$cache-dir}/files', 'cache-repo-dir' => '{$cache-dir}/repo', 'cache-vcs-dir' => '{$cache-dir}/vcs', @@ -151,6 +152,7 @@ class Config case 'vendor-dir': case 'bin-dir': case 'process-timeout': + case 'data-dir': case 'cache-dir': case 'cache-files-dir': case 'cache-repo-dir': diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 10a3c3cab..229c4653c 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -36,6 +36,7 @@ use Composer\Package\Version\VersionParser; */ class Factory { + /** * @return string * @throws \RuntimeException @@ -43,29 +44,28 @@ class Factory protected static function getHomeDir() { $home = getenv('COMPOSER_HOME'); - $cacheDir = getenv('COMPOSER_CACHE_DIR'); - if (!getenv('HOME')) { - throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); - } - $userDir = rtrim(getenv('HOME'), '/'); - $followXDG = false; - if (!$home) { if (defined('PHP_WINDOWS_VERSION_MAJOR')) { if (!getenv('APPDATA')) { throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly'); } - $home = getenv('APPDATA') . '/Composer'; - } elseif (getenv('XDG_CONFIG_DIRS')) { - // XDG Base Directory Specifications - $followXDG = true; - $xdgConfig = getenv('XDG_CONFIG_HOME'); - if (!$xdgConfig) { - $xdgConfig = $userDir . '/.config'; - } - $home = $xdgConfig . '/composer'; + $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; } else { - $home = $userDir . '/.composer'; + if (!getenv('HOME')) { + throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + $userDir = rtrim(getenv('HOME'), '/'); + + if (getenv('XDG_CONFIG_DIRS')) { + // XDG Base Directory Specifications + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = $userDir . '/.config'; + } + $home = $xdgConfig . '/composer'; + } else { + $home = $userDir . '/composer'; + } } } @@ -87,23 +87,47 @@ class Factory } else { $cacheDir = $home . '/cache'; } - $cacheDir = strtr($cacheDir, '\\', '/'); } elseif (getenv('XDG_CONFIG_DIRS')) { - $followXDG = true; $xdgCache = getenv('XDG_CACHE_HOME'); if (!$xdgCache) { - $xdgCache = $userDir . '/.cache'; + $xdgCache = $home . '/.cache'; } $cacheDir = $xdgCache . '/composer'; } else { - $cacheDir = $home . '/.cache'; + $cacheDir = $home . '/cache'; } } return $cacheDir; } + /** + * @param string $home + * + * @return string + */ + protected static function getDataDir($home) + { + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + $dataDir = strtr($home, '\\', '/'); + } elseif (getenv('XDG_CONFIG_DIRS')) { + $xdgData = getenv('XDG_DATA_HOME'); + if (!$xdgData) { + if (!getenv('HOME')) { + throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + $userDir = rtrim(getenv('HOME'), '/'); + $xdgData = $userDir . '/.local/share'; + } + $dataDir = $xdgData . '/composer'; + } else { + $dataDir = $home; + } + + return $dataDir; + } + /** * @param IOInterface|null $io * @return Config @@ -113,11 +137,12 @@ class Factory // determine home and cache dirs $home = self::getHomeDir(); $cacheDir = self::getCacheDir($home); + $dataDir = self::getDataDir($home); // Protect directory against web access. Since HOME could be // the www-data's user home and be web-accessible it is a // potential security risk - foreach (array($home, $cacheDir) as $dir) { + foreach (array($home, $cacheDir, $dataDir) as $dir) { if (!file_exists($dir . '/.htaccess')) { if (!is_dir($dir)) { @mkdir($dir, 0777, true); @@ -127,22 +152,34 @@ class Factory } // Move content of old composer dir to XDG - if ($followXDG && file_exists($userDir . '/.composer')) { - // migrate to XDG - @rename($userDir . '/.composer/config.json', $home . '/config.json'); - @unlink($userDir . '/.composer/.htaccess'); - @unlink($userDir . '/.composer/cache/.htaccess'); - foreach (glob($userDir . '/.composer/cache/*') as $oldCacheDir) { - @rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); + if (getenv('XDG_CONFIG_DIRS') !== false && getenv('COMPOSER_HOME') === false && getenv('COMPOSER_CACHE_DIR') === false) { + $userDir = rtrim(getenv('HOME'), '/'); + $oldComposerHome = $userDir . '/.composer'; + if (file_exists($oldComposerHome)) { + // migrate to XDG + foreach (glob($oldComposerHome . '/*.json') as $file) { + rename($file, $home . '/' . basename($file)); + } + + foreach (glob($oldComposerHome . '/*.phar') as $file) { + rename($file, $dataDir . '/' . basename($file)); + } + + foreach (glob($oldComposerHome . '/cache/*') as $oldCacheDir) { + rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); + } + + unlink($oldComposerHome . '/.htaccess'); + unlink($oldComposerHome . '/cache/.htaccess'); + rmdir($oldComposerHome . '/cache'); + rmdir($oldComposerHome); } - @rmdir($userDir . '/.composer/cache'); - @rmdir($userDir . '/.composer'); } $config = new Config(); // add dirs to the config - $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir))); + $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir, 'data-dir' => $dataDir))); // load global config $file = new JsonFile($home.'/config.json'); @@ -169,14 +206,14 @@ class Factory public static function getComposerFile() { - return trim(getenv('COMPOSER')) ?: './composer.json'; + return trim(getenv('COMPOSER')) ? : './composer.json'; } public static function createAdditionalStyles() { return array( 'highlight' => new OutputFormatterStyle('red'), - 'warning' => new OutputFormatterStyle('black', 'yellow'), + 'warning' => new OutputFormatterStyle('black', 'yellow'), ); } @@ -192,15 +229,15 @@ class Factory throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager'); } $factory = new static; - $rm = $factory->createRepositoryManager($io, $config); + $rm = $factory->createRepositoryManager($io, $config); } foreach ($config->getRepositories() as $index => $repo) { if (!is_array($repo)) { - throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') should be an array, '.gettype($repo).' given'); + throw new \UnexpectedValueException('Repository ' . $index . ' (' . json_encode($repo) . ') should be an array, ' . gettype($repo) . ' given'); } if (!isset($repo['type'])) { - throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined'); + throw new \UnexpectedValueException('Repository ' . $index . ' (' . json_encode($repo) . ') must have a type defined'); } $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index; while (isset($repos[$name])) { @@ -232,16 +269,16 @@ class Factory if (is_string($localConfig)) { $composerFile = $localConfig; - $file = new JsonFile($localConfig, new RemoteFilesystem($io)); + $file = new JsonFile($localConfig, new RemoteFilesystem($io)); if (!$file->exists()) { if ($localConfig === './composer.json' || $localConfig === 'composer.json') { - $message = 'Composer could not find a composer.json file in '.getcwd(); + $message = 'Composer could not find a composer.json file in ' . getcwd(); } else { - $message = 'Composer could not find the config file: '.$localConfig; + $message = 'Composer could not find the config file: ' . $localConfig; } $instructions = 'To initialize a project, please create a composer.json file as described in the http://getcomposer.org/ "Getting Started" section'; - throw new \InvalidArgumentException($message.PHP_EOL.$instructions); + throw new \InvalidArgumentException($message . PHP_EOL . $instructions); } $file->validateSchema(JsonFile::LAX_SCHEMA); @@ -269,7 +306,7 @@ class Factory $io->loadConfiguration($config); $vendorDir = $config->get('vendor-dir'); - $binDir = $config->get('bin-dir'); + $binDir = $config->get('bin-dir'); // setup process timeout ProcessExecutor::setTimeout((int) $config->get('process-timeout')); @@ -288,7 +325,7 @@ class Factory $this->addLocalRepository($rm, $vendorDir); // load package - $parser = new VersionParser; + $parser = new VersionParser; $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, new ProcessExecutor($io)); $package = $loader->load($localConfig); @@ -314,7 +351,7 @@ class Factory $this->createDefaultInstallers($im, $composer, $io); $globalRepository = $this->createGlobalRepository($config, $vendorDir); - $pm = $this->createPluginManager($composer, $io, $globalRepository); + $pm = $this->createPluginManager($composer, $io, $globalRepository); $composer->setPluginManager($pm); if (!$disablePlugins) { @@ -326,10 +363,8 @@ class Factory // init locker if possible if (isset($composerFile)) { - $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION) - ? substr($composerFile, 0, -4).'lock' - : $composerFile . '.lock'; - $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile)); + $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION) ? substr($composerFile, 0, -4) . 'lock' : $composerFile . '.lock'; + $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile)); $composer->setLocker($locker); } @@ -364,10 +399,10 @@ class Factory */ protected function addLocalRepository(RepositoryManager $rm, $vendorDir) { - $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed.json'))); + $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir . '/composer/installed.json'))); } - /** + /** * @param Config $config * @param string $vendorDir * @return Repository\InstalledFilesystemRepository|null @@ -378,7 +413,7 @@ class Factory return null; } - $path = $config->get('home').'/vendor/composer/installed.json'; + $path = $config->get('home') . '/vendor/composer/installed.json'; if (!file_exists($path)) { return null; } @@ -506,4 +541,5 @@ class Factory return $factory->createComposer($io, $config, $disablePlugins); } + } From c6860400f0814094cd4acf1c5b13d5f5868684d0 Mon Sep 17 00:00:00 2001 From: ntoniazzi Date: Tue, 11 Dec 2012 11:49:30 +0100 Subject: [PATCH 4/9] Conforming to XDG Base Directory Specification (http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) --- src/Composer/Factory.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 4f7bfefd8..cc20cd575 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -50,10 +50,11 @@ class Factory } $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; } else { - if (!getenv('HOME')) { - throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = rtrim(getenv('HOME'), '/') . '/.config'; } - $home = rtrim(getenv('HOME'), '/') . '/.composer'; + $home = $xdgConfig . '/composer'; } } @@ -77,7 +78,11 @@ class Factory } $cacheDir = strtr($cacheDir, '\\', '/'); } else { - $cacheDir = $home.'/cache'; + $xdgCache = getenv('XDG_CACHE_HOME'); + if (!$xdgCache) { + $xdgCache = rtrim(getenv('HOME'), '/') . '/.cache'; + } + $cacheDir = $xdgCache . '/composer'; } } From b79f38fd9949601ce53df8fbed646ca26d8dbee7 Mon Sep 17 00:00:00 2001 From: ntoniazzi Date: Wed, 2 Jan 2013 13:48:00 +0100 Subject: [PATCH 5/9] Conforming to XDG Base Directory Specification (http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) --- doc/03-cli.md | 8 +++--- doc/04-schema.md | 15 +++-------- src/Composer/Factory.php | 54 +++++++++++++++++++++++----------------- 3 files changed, 39 insertions(+), 38 deletions(-) diff --git a/doc/03-cli.md b/doc/03-cli.md index 7fcafc2d6..dd708100c 100644 --- a/doc/03-cli.md +++ b/doc/03-cli.md @@ -598,9 +598,11 @@ The `COMPOSER_HOME` var allows you to change the composer home directory. This is a hidden, global (per-user on the machine) directory that is shared between all projects. -By default it points to `/home//.composer` on \*nix, -`/Users//.composer` on OSX and -`C:\Users\\AppData\Roaming\Composer` on Windows. +By default it points to `C:\Users\\AppData\Roaming\Composer` on Windows +and `/Users//.composer` on OSX. On *nix systems that follow the [XDG Base +Directory Specifications](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html), +it points to `$XDG_CONFIG_HOME/composer`. On other *nix systems, it points to +`/home//.composer`. #### COMPOSER_HOME/config.json diff --git a/doc/04-schema.md b/doc/04-schema.md index c768edb72..3a40d5d93 100644 --- a/doc/04-schema.md +++ b/doc/04-schema.md @@ -754,18 +754,9 @@ The following options are supported: `{"github.com": "oauthtoken"}` as the value of this option will use `oauthtoken` to access private repositories on github and to circumvent the low IP-based rate limiting of their API. - [Read more](articles/troubleshooting.md#api-rate-limit-and-oauth-tokens) - on how to get an OAuth token for GitHub. -* **http-basic:** A list of domain names and username/passwords to authenticate - against them. For example using - `{"example.org": {"username": "alice", "password": "foo"}` as the value of this option will let composer authenticate against example.org. -* **vendor-dir:** Defaults to `vendor`. You can install dependencies into a - different directory if you want to. `$HOME` and `~` will be replaced by your - home directory's path in vendor-dir and all `*-dir` options below. -* **bin-dir:** Defaults to `vendor/bin`. If a project includes binaries, they - will be symlinked into this directory. -* **cache-dir:** Defaults to `$home/cache` on unix systems and - `C:\Users\\AppData\Local\Composer` on Windows. Stores all the caches +* **cache-dir:** Defaults to `C:\Users\\AppData\Local\Composer` on Windows, + `$XDG_CACHE_HOME/composer` on unix systems that follow the XDG Base Directory + Specifications, and `$home/cache` on other unix systems. Stores all the caches used by composer. See also [COMPOSER_HOME](03-cli.md#composer-home). * **cache-files-dir:** Defaults to `$cache-dir/files`. Stores the zip archives of packages. diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index cc20cd575..0dddab3df 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -43,18 +43,22 @@ class Factory protected static function getHomeDir() { $home = getenv('COMPOSER_HOME'); + $cacheDir = getenv('COMPOSER_CACHE_DIR'); + $userDir = rtrim(getenv('HOME'), '/'); + $followXDG = false; if (!$home) { if (defined('PHP_WINDOWS_VERSION_MAJOR')) { - if (!getenv('APPDATA')) { - throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly'); - } - $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; - } else { + $home = getenv('APPDATA') . '/Composer'; + } elseif (getenv('XDG_CONFIG_DIRS')) { + // XDG Base Directory Specifications + $followXDG = true; $xdgConfig = getenv('XDG_CONFIG_HOME'); if (!$xdgConfig) { - $xdgConfig = rtrim(getenv('HOME'), '/') . '/.config'; + $xdgConfig = $userDir . '/.config'; } $home = $xdgConfig . '/composer'; + } else { + $home = $userDir . '/.composer'; } } @@ -76,29 +80,20 @@ class Factory } else { $cacheDir = $home . '/cache'; } - $cacheDir = strtr($cacheDir, '\\', '/'); - } else { + } elseif (getenv('XDG_CONFIG_DIRS')) { + $followXDG = true; $xdgCache = getenv('XDG_CACHE_HOME'); if (!$xdgCache) { - $xdgCache = rtrim(getenv('HOME'), '/') . '/.cache'; + $xdgCache = $userDir . '/.cache'; } $cacheDir = $xdgCache . '/composer'; + + + } else { + $cacheDir = $home . '/.cache'; } } - - return $cacheDir; - } - - /** - * @param IOInterface|null $io - * @return Config - */ - public static function createConfig(IOInterface $io = null) - { - // determine home and cache dirs - $home = self::getHomeDir(); - $cacheDir = self::getCacheDir($home); - + // Protect directory against web access. Since HOME could be // the www-data's user home and be web-accessible it is a // potential security risk @@ -111,6 +106,19 @@ class Factory } } + // Move content of old composer dir to XDG + if ($followXDG && file_exists($userDir . '/.composer')) { + // migrate to XDG + @rename($userDir . '/.composer/config.json', $home . '/config.json'); + @unlink($userDir . '/.composer/.htaccess'); + @unlink($userDir . '/.composer/cache/.htaccess'); + foreach (glob($userDir . '/.composer/cache/*') as $oldCacheDir) { + @rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); + } + @rmdir($userDir . '/.composer/cache'); + @rmdir($userDir . '/.composer'); + } + $config = new Config(); // add dirs to the config From 83a144128527b5b74189b50d14124b56121599ca Mon Sep 17 00:00:00 2001 From: Nicolas Toniazzi Date: Thu, 16 Oct 2014 14:39:48 +0200 Subject: [PATCH 6/9] Added support for backup PHARs --- src/Composer/Command/SelfUpdateCommand.php | 2 +- src/Composer/Config.php | 2 + src/Composer/Factory.php | 154 ++++++++++++++------- 3 files changed, 109 insertions(+), 49 deletions(-) diff --git a/src/Composer/Command/SelfUpdateCommand.php b/src/Composer/Command/SelfUpdateCommand.php index 13abee32b..2975a7fa0 100644 --- a/src/Composer/Command/SelfUpdateCommand.php +++ b/src/Composer/Command/SelfUpdateCommand.php @@ -61,7 +61,7 @@ EOT $config = Factory::createConfig(); $remoteFilesystem = new RemoteFilesystem($this->getIO(), $config); $cacheDir = $config->get('cache-dir'); - $rollbackDir = $config->get('home'); + $rollbackDir = $config->get('data-dir'); $localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0]; // check if current dir is writable and if not try the cache dir from settings diff --git a/src/Composer/Config.php b/src/Composer/Config.php index bd5d86895..b6ef01aa4 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -28,6 +28,7 @@ class Config 'vendor-dir' => 'vendor', 'bin-dir' => '{$vendor-dir}/bin', 'cache-dir' => '{$home}/cache', + 'data-dir' => '{$home}', 'cache-files-dir' => '{$cache-dir}/files', 'cache-repo-dir' => '{$cache-dir}/repo', 'cache-vcs-dir' => '{$cache-dir}/vcs', @@ -157,6 +158,7 @@ class Config case 'vendor-dir': case 'bin-dir': case 'process-timeout': + case 'data-dir': case 'cache-dir': case 'cache-files-dir': case 'cache-repo-dir': diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 0dddab3df..0c68adf5b 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -36,6 +36,7 @@ use Composer\Package\Version\VersionParser; */ class Factory { + /** * @return string * @throws \RuntimeException @@ -43,22 +44,28 @@ class Factory protected static function getHomeDir() { $home = getenv('COMPOSER_HOME'); - $cacheDir = getenv('COMPOSER_CACHE_DIR'); - $userDir = rtrim(getenv('HOME'), '/'); - $followXDG = false; if (!$home) { if (defined('PHP_WINDOWS_VERSION_MAJOR')) { - $home = getenv('APPDATA') . '/Composer'; - } elseif (getenv('XDG_CONFIG_DIRS')) { - // XDG Base Directory Specifications - $followXDG = true; - $xdgConfig = getenv('XDG_CONFIG_HOME'); - if (!$xdgConfig) { - $xdgConfig = $userDir . '/.config'; + if (!getenv('APPDATA')) { + throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly'); } - $home = $xdgConfig . '/composer'; + $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; } else { - $home = $userDir . '/.composer'; + if (!getenv('HOME')) { + throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + $userDir = rtrim(getenv('HOME'), '/'); + + if (getenv('XDG_CONFIG_DIRS')) { + // XDG Base Directory Specifications + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = $userDir . '/.config'; + } + $home = $xdgConfig . '/composer'; + } else { + $home = $userDir . '/composer'; + } } } @@ -80,24 +87,64 @@ class Factory } else { $cacheDir = $home . '/cache'; } + $cacheDir = strtr($cacheDir, '\\', '/'); } elseif (getenv('XDG_CONFIG_DIRS')) { - $followXDG = true; $xdgCache = getenv('XDG_CACHE_HOME'); if (!$xdgCache) { - $xdgCache = $userDir . '/.cache'; + $xdgCache = $home . '/.cache'; } $cacheDir = $xdgCache . '/composer'; } else { - $cacheDir = $home . '/.cache'; + $cacheDir = $home . '/cache'; } } - + + return $cacheDir; + } + + /** + * @param string $home + * + * @return string + */ + protected static function getDataDir($home) + { + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + $dataDir = strtr($home, '\\', '/'); + } elseif (getenv('XDG_CONFIG_DIRS')) { + $xdgData = getenv('XDG_DATA_HOME'); + if (!$xdgData) { + if (!getenv('HOME')) { + throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + $userDir = rtrim(getenv('HOME'), '/'); + $xdgData = $userDir . '/.local/share'; + } + $dataDir = $xdgData . '/composer'; + } else { + $dataDir = $home; + } + + return $dataDir; + } + + /** + * @param IOInterface|null $io + * @return Config + */ + public static function createConfig(IOInterface $io = null) + { + // determine home and cache dirs + $home = self::getHomeDir(); + $cacheDir = self::getCacheDir($home); + $dataDir = self::getDataDir($home); + // Protect directory against web access. Since HOME could be // the www-data's user home and be web-accessible it is a // potential security risk - foreach (array($home, $cacheDir) as $dir) { + foreach (array($home, $cacheDir, $dataDir) as $dir) { if (!file_exists($dir . '/.htaccess')) { if (!is_dir($dir)) { @mkdir($dir, 0777, true); @@ -107,22 +154,34 @@ class Factory } // Move content of old composer dir to XDG - if ($followXDG && file_exists($userDir . '/.composer')) { - // migrate to XDG - @rename($userDir . '/.composer/config.json', $home . '/config.json'); - @unlink($userDir . '/.composer/.htaccess'); - @unlink($userDir . '/.composer/cache/.htaccess'); - foreach (glob($userDir . '/.composer/cache/*') as $oldCacheDir) { - @rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); + if (getenv('XDG_CONFIG_DIRS') !== false && getenv('COMPOSER_HOME') === false && getenv('COMPOSER_CACHE_DIR') === false) { + $userDir = rtrim(getenv('HOME'), '/'); + $oldComposerHome = $userDir . '/.composer'; + if (file_exists($oldComposerHome)) { + // migrate to XDG + foreach (glob($oldComposerHome . '/*.json') as $file) { + rename($file, $home . '/' . basename($file)); + } + + foreach (glob($oldComposerHome . '/*.phar') as $file) { + rename($file, $dataDir . '/' . basename($file)); + } + + foreach (glob($oldComposerHome . '/cache/*') as $oldCacheDir) { + rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); + } + + unlink($oldComposerHome . '/.htaccess'); + unlink($oldComposerHome . '/cache/.htaccess'); + rmdir($oldComposerHome . '/cache'); + rmdir($oldComposerHome); } - @rmdir($userDir . '/.composer/cache'); - @rmdir($userDir . '/.composer'); } $config = new Config(); // add dirs to the config - $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir))); + $config->merge(array('config' => array('home' => $home, 'cache-dir' => $cacheDir, 'data-dir' => $dataDir))); // load global config $file = new JsonFile($home.'/config.json'); @@ -149,14 +208,14 @@ class Factory public static function getComposerFile() { - return trim(getenv('COMPOSER')) ?: './composer.json'; + return trim(getenv('COMPOSER')) ? : './composer.json'; } public static function createAdditionalStyles() { return array( 'highlight' => new OutputFormatterStyle('red'), - 'warning' => new OutputFormatterStyle('black', 'yellow'), + 'warning' => new OutputFormatterStyle('black', 'yellow'), ); } @@ -172,15 +231,15 @@ class Factory throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager'); } $factory = new static; - $rm = $factory->createRepositoryManager($io, $config); + $rm = $factory->createRepositoryManager($io, $config); } foreach ($config->getRepositories() as $index => $repo) { if (!is_array($repo)) { - throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') should be an array, '.gettype($repo).' given'); + throw new \UnexpectedValueException('Repository ' . $index . ' (' . json_encode($repo) . ') should be an array, ' . gettype($repo) . ' given'); } if (!isset($repo['type'])) { - throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined'); + throw new \UnexpectedValueException('Repository ' . $index . ' (' . json_encode($repo) . ') must have a type defined'); } $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index; while (isset($repos[$name])) { @@ -212,16 +271,16 @@ class Factory if (is_string($localConfig)) { $composerFile = $localConfig; - $file = new JsonFile($localConfig, new RemoteFilesystem($io)); + $file = new JsonFile($localConfig, new RemoteFilesystem($io)); if (!$file->exists()) { if ($localConfig === './composer.json' || $localConfig === 'composer.json') { - $message = 'Composer could not find a composer.json file in '.getcwd(); + $message = 'Composer could not find a composer.json file in ' . getcwd(); } else { - $message = 'Composer could not find the config file: '.$localConfig; + $message = 'Composer could not find the config file: ' . $localConfig; } $instructions = 'To initialize a project, please create a composer.json file as described in the http://getcomposer.org/ "Getting Started" section'; - throw new \InvalidArgumentException($message.PHP_EOL.$instructions); + throw new \InvalidArgumentException($message . PHP_EOL . $instructions); } $file->validateSchema(JsonFile::LAX_SCHEMA); @@ -249,7 +308,7 @@ class Factory $io->loadConfiguration($config); $vendorDir = $config->get('vendor-dir'); - $binDir = $config->get('bin-dir'); + $binDir = $config->get('bin-dir'); // setup process timeout ProcessExecutor::setTimeout((int) $config->get('process-timeout')); @@ -268,7 +327,7 @@ class Factory $this->addLocalRepository($rm, $vendorDir); // load package - $parser = new VersionParser; + $parser = new VersionParser; $loader = new Package\Loader\RootPackageLoader($rm, $config, $parser, new ProcessExecutor($io)); $package = $loader->load($localConfig); @@ -294,7 +353,7 @@ class Factory $this->createDefaultInstallers($im, $composer, $io); $globalRepository = $this->createGlobalRepository($config, $vendorDir); - $pm = $this->createPluginManager($composer, $io, $globalRepository); + $pm = $this->createPluginManager($composer, $io, $globalRepository); $composer->setPluginManager($pm); if (!$disablePlugins) { @@ -306,10 +365,8 @@ class Factory // init locker if possible if (isset($composerFile)) { - $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION) - ? substr($composerFile, 0, -4).'lock' - : $composerFile . '.lock'; - $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile)); + $lockFile = "json" === pathinfo($composerFile, PATHINFO_EXTENSION) ? substr($composerFile, 0, -4) . 'lock' : $composerFile . '.lock'; + $locker = new Package\Locker($io, new JsonFile($lockFile, new RemoteFilesystem($io, $config)), $rm, $im, md5_file($composerFile)); $composer->setLocker($locker); } @@ -344,12 +401,12 @@ class Factory */ protected function addLocalRepository(RepositoryManager $rm, $vendorDir) { - $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/composer/installed.json'))); + $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir . '/composer/installed.json'))); } - /** - * @param Config $config - * @param string $vendorDir + /** + * @param Config $config + * @param string $vendorDir * @return Repository\InstalledFilesystemRepository|null */ protected function createGlobalRepository(Config $config, $vendorDir) @@ -358,7 +415,7 @@ class Factory return null; } - $path = $config->get('home').'/vendor/composer/installed.json'; + $path = $config->get('home') . '/vendor/composer/installed.json'; if (!file_exists($path)) { return null; } @@ -486,4 +543,5 @@ class Factory return $factory->createComposer($io, $config, $disablePlugins); } + } From d3e6a464d6afe841c7e9387c94a2ed1596032cc4 Mon Sep 17 00:00:00 2001 From: Nicolas Toniazzi Date: Mon, 15 Dec 2014 14:21:03 +0100 Subject: [PATCH 7/9] Fix home directory when system does not support XDG --- src/Composer/Factory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index ad37cb594..20b1deee4 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -64,7 +64,7 @@ class Factory } $home = $xdgConfig . '/composer'; } else { - $home = $userDir . '/composer'; + $home = $userDir . '/.composer'; } } } From 1a5b87442ab784775a247b088a3f70123c1cd557 Mon Sep 17 00:00:00 2001 From: Nicolas Toniazzi Date: Mon, 15 Dec 2014 15:10:15 +0100 Subject: [PATCH 8/9] Fix directory paths when using XDG --- src/Composer/Factory.php | 44 +++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 20b1deee4..54e8ee589 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -37,6 +37,20 @@ use Composer\Package\Version\VersionParser; class Factory { + /** + * @return string + * @throws \RuntimeException + */ + private static function getUserDir() + { + if (!getenv('HOME')) { + throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + $userDir = rtrim(getenv('HOME'), '/'); + + return $userDir; + } + /** * @return string * @throws \RuntimeException @@ -51,10 +65,7 @@ class Factory } $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; } else { - if (!getenv('HOME')) { - throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); - } - $userDir = rtrim(getenv('HOME'), '/'); + $userDir = self::getUserDir(); if (getenv('XDG_CONFIG_DIRS')) { // XDG Base Directory Specifications @@ -88,14 +99,18 @@ class Factory $cacheDir = $home . '/cache'; } $cacheDir = strtr($cacheDir, '\\', '/'); - } elseif (getenv('XDG_CONFIG_DIRS')) { - $xdgCache = getenv('XDG_CACHE_HOME'); - if (!$xdgCache) { - $xdgCache = $home . '/.cache'; - } - $cacheDir = $xdgCache . '/composer'; } else { - $cacheDir = $home . '/cache'; + $userDir = self::getUserDir(); + + if (getenv('XDG_CONFIG_DIRS')) { + $xdgCache = getenv('XDG_CACHE_HOME'); + if (!$xdgCache) { + $xdgCache = $userDir . '/.cache'; + } + $cacheDir = $xdgCache . '/composer'; + } else { + $cacheDir = $home . '/cache'; + } } } @@ -114,10 +129,7 @@ class Factory } elseif (getenv('XDG_CONFIG_DIRS')) { $xdgData = getenv('XDG_DATA_HOME'); if (!$xdgData) { - if (!getenv('HOME')) { - throw new \RuntimeException('The HOME or COMPOSER_HOME environment variable must be set for composer to run correctly'); - } - $userDir = rtrim(getenv('HOME'), '/'); + $userDir = self::getUserDir(); $xdgData = $userDir . '/.local/share'; } $dataDir = $xdgData . '/composer'; @@ -490,7 +502,7 @@ class Factory */ protected function createPluginManager(Composer $composer, IOInterface $io, RepositoryInterface $globalRepository = null) { - return new Plugin\PluginManager($composer, $io, $globalRepository); + return new Plugin\PluginManager($io, $composer, $globalRepository); } /** From e8a6cb536bf202b8e36937218117f36d5fffaad3 Mon Sep 17 00:00:00 2001 From: Nicolas Toniazzi Date: Wed, 22 Jul 2015 10:38:12 +0200 Subject: [PATCH 9/9] Change detection of config/cache/data dirs --- src/Composer/Factory.php | 166 +++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 69 deletions(-) diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 2496692ed..19261739f 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -35,6 +35,21 @@ use Composer\Package\Version\VersionParser; */ class Factory { + /** + * + * @return boolean + */ + private static function useXdg() + { + foreach (array_keys($_SERVER) as $key) { + if (substr($key, 0, 4) === 'XDG_') { + return true; + } + } + + return false; + } + /** * @return string * @throws \RuntimeException @@ -56,28 +71,40 @@ class Factory protected static function getHomeDir() { $home = getenv('COMPOSER_HOME'); - if (!$home) { - if (defined('PHP_WINDOWS_VERSION_MAJOR')) { - if (!getenv('APPDATA')) { - throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly'); - } - $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; - } else { - $userDir = self::getUserDir(); - - if (getenv('XDG_CONFIG_DIRS')) { - // XDG Base Directory Specifications - $xdgConfig = getenv('XDG_CONFIG_HOME'); - if (!$xdgConfig) { - $xdgConfig = $userDir . '/.config'; - } - $home = $xdgConfig . '/composer'; - } else { - $home = $userDir . '/.composer'; - } - } + if ($home) { + return $home; } + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + if (!getenv('APPDATA')) { + throw new \RuntimeException('The APPDATA or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + $home = strtr(getenv('APPDATA'), '\\', '/') . '/Composer'; + + return $home; + } + + $userDir = self::getUserDir(); + + if (is_dir($userDir . '/.composer')) { + $home = $userDir . '/.composer'; + + return $home; + } + + if (self::useXdg()) { + // XDG Base Directory Specifications + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = $userDir . '/.config'; + } + $home = $xdgConfig . '/composer'; + + return $home; + } + + $home = $userDir . '/.composer'; + return $home; } @@ -89,29 +116,41 @@ class Factory protected static function getCacheDir($home) { $cacheDir = getenv('COMPOSER_CACHE_DIR'); - if (!$cacheDir) { - if (defined('PHP_WINDOWS_VERSION_MAJOR')) { - if ($cacheDir = getenv('LOCALAPPDATA')) { - $cacheDir .= '/Composer'; - } else { - $cacheDir = $home . '/cache'; - } - $cacheDir = strtr($cacheDir, '\\', '/'); - } else { - $userDir = self::getUserDir(); - - if (getenv('XDG_CONFIG_DIRS')) { - $xdgCache = getenv('XDG_CACHE_HOME'); - if (!$xdgCache) { - $xdgCache = $userDir . '/.cache'; - } - $cacheDir = $xdgCache . '/composer'; - } else { - $cacheDir = $home . '/cache'; - } - } + if ($cacheDir) { + return $cacheDir; } + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + if ($cacheDir = getenv('LOCALAPPDATA')) { + $cacheDir .= '/Composer'; + } else { + $cacheDir = $home . '/cache'; + } + $cacheDir = strtr($cacheDir, '\\', '/'); + + return $cacheDir; + } + + $userDir = self::getUserDir(); + + if ($home === $userDir . '/.composer' && is_dir($home . '/cache')) { + $cacheDir = $home . '/cache'; + + return $cacheDir; + } + + if (self::useXdg()) { + $xdgCache = getenv('XDG_CACHE_HOME'); + if (!$xdgCache) { + $xdgCache = $userDir . '/.cache'; + } + $cacheDir = $xdgCache . '/composer'; + + return $cacheDir; + } + + $cacheDir = $home . '/cache'; + return $cacheDir; } @@ -124,17 +163,31 @@ class Factory { if (defined('PHP_WINDOWS_VERSION_MAJOR')) { $dataDir = strtr($home, '\\', '/'); - } elseif (getenv('XDG_CONFIG_DIRS')) { + + return $dataDir; + } + + $userDir = self::getUserDir(); + + if ($home === $userDir . '/.composer') { + $cacheDir = $home; + + return $cacheDir; + } + + if (self::useXdg()) { $xdgData = getenv('XDG_DATA_HOME'); if (!$xdgData) { $userDir = self::getUserDir(); $xdgData = $userDir . '/.local/share'; } $dataDir = $xdgData . '/composer'; - } else { - $dataDir = $home; + + return $dataDir; } + $dataDir = $home; + return $dataDir; } @@ -163,31 +216,6 @@ class Factory } } - // Move content of old composer dir to XDG - if (getenv('XDG_CONFIG_DIRS') !== false && getenv('COMPOSER_HOME') === false && getenv('COMPOSER_CACHE_DIR') === false) { - $userDir = rtrim(getenv('HOME'), '/'); - $oldComposerHome = $userDir . '/.composer'; - if (file_exists($oldComposerHome)) { - // migrate to XDG - foreach (glob($oldComposerHome . '/*.json') as $file) { - rename($file, $home . '/' . basename($file)); - } - - foreach (glob($oldComposerHome . '/*.phar') as $file) { - rename($file, $dataDir . '/' . basename($file)); - } - - foreach (glob($oldComposerHome . '/cache/*') as $oldCacheDir) { - rename($oldCacheDir, $cacheDir . '/' . basename($oldCacheDir)); - } - - unlink($oldComposerHome . '/.htaccess'); - unlink($oldComposerHome . '/cache/.htaccess'); - rmdir($oldComposerHome . '/cache'); - rmdir($oldComposerHome); - } - } - $config = new Config(true, $cwd); // add dirs to the config