diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index 91432ae9b..7af40e14d 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -23,6 +23,9 @@ class InstallCommand { $this->composer = $composer; + // TODO this needs a parameter to enable installing from source (i.e. git clone, instead of downloading archives) + $sourceInstall = false; + $config = $this->loadConfig(); foreach ($config['repositories'] as $name => $spec) { @@ -50,11 +53,25 @@ class InstallCommand if (!isset($package)) { throw new \UnexpectedValueException('Could not find package '.$name.' in any of your repositories'); } - $downloader = $composer->getDownloader($package->getSourceType()); - $installer = $composer->getInstaller($package->getType()); - $lock[$name] = $installer->install($package, $downloader); - echo '> '.$name.' installed'.PHP_EOL; + echo '> Installing '.$package->getName().PHP_EOL; + if ($sourceInstall) { + // TODO + } else { + if ($package->getDistType()) { + $downloader = $composer->getDownloader($package->getDistType()); + $type = 'dist'; + } elseif ($package->getSourceType()) { + echo 'Package '.$package->getName().' has no dist url, installing from source instead.'; + $downloader = $composer->getDownloader($package->getSourceType()); + $type = 'source'; + } else { + throw new \UnexpectedValueException('Package '.$package->getName().' has no source or dist URL.'); + } + $installer = $composer->getInstaller($package->getType()); + $lock[$name] = $installer->install($package, $downloader, $type); + } } + echo '> Done'.PHP_EOL; $this->storeLockFile($lock); } diff --git a/src/Composer/Downloader/GitDownloader.php b/src/Composer/Downloader/GitDownloader.php index da5c75351..b4193b612 100644 --- a/src/Composer/Downloader/GitDownloader.php +++ b/src/Composer/Downloader/GitDownloader.php @@ -26,7 +26,7 @@ class GitDownloader $this->clone = $clone; } - public function download(PackageInterface $package, $path) + public function download(PackageInterface $package, $path, $url, $checksum = null) { if (!is_dir($path)) { if (file_exists($path)) { @@ -37,9 +37,9 @@ class GitDownloader } } if ($this->clone) { - system('git clone '.escapeshellarg($package->getSourceUrl()).' -b master '.escapeshellarg($path.'/'.$package->getName())); + system('git clone '.escapeshellarg($url).' -b master '.escapeshellarg($path.'/'.$package->getName())); } else { - system('git archive --format=tar --prefix='.escapeshellarg($package->getName()).' --remote='.escapeshellarg($package->getSourceUrl()).' master | tar -xf -'); + system('git archive --format=tar --prefix='.escapeshellarg($package->getName()).' --remote='.escapeshellarg($url).' master | tar -xf -'); } } } \ No newline at end of file diff --git a/src/Composer/Downloader/PearDownloader.php b/src/Composer/Downloader/PearDownloader.php index a52811a67..c36022248 100644 --- a/src/Composer/Downloader/PearDownloader.php +++ b/src/Composer/Downloader/PearDownloader.php @@ -20,7 +20,7 @@ use Composer\Package\PackageInterface; */ class PearDownloader { - public function download(PackageInterface $package, $path) + public function download(PackageInterface $package, $path, $url, $checksum = null) { $targetPath = $path . "/" . $package->getName(); if (!is_dir($targetPath)) { @@ -35,17 +35,20 @@ class PearDownloader $cwd = getcwd(); chdir($targetPath); - $source = $package->getSourceUrl(); - $tarName = basename($source); + $tarName = basename($url); - echo 'Downloading '.$source.' to '.$targetPath.'/'.$tarName.PHP_EOL; - copy($package->getSourceUrl(), './'.$tarName); + echo 'Downloading '.$url.' to '.$targetPath.'/'.$tarName.PHP_EOL; + copy($url, './'.$tarName); if (!file_exists($tarName)) { throw new \UnexpectedValueException($package->getName().' could not be saved into '.$tarName.', make sure the' .' directory is writable and you have internet connectivity.'); } + if ($checksum && hash_file('sha1', './'.$tarName) !== $checksum) { + throw new \UnexpectedValueException('The checksum verification failed for the '.$package->getName().' archive (downloaded from '.$url.'). Installation aborted.'); + } + echo 'Unpacking archive'.PHP_EOL; exec('tar -xzf "'.escapeshellarg($tarName).'"'); diff --git a/src/Composer/Downloader/ZipDownloader.php b/src/Composer/Downloader/ZipDownloader.php index 9fef0f9e8..afbe0c687 100644 --- a/src/Composer/Downloader/ZipDownloader.php +++ b/src/Composer/Downloader/ZipDownloader.php @@ -19,27 +19,58 @@ use Composer\Package\PackageInterface; */ class ZipDownloader { - public function download(PackageInterface $package, $path) + public function download(PackageInterface $package, $path, $url, $checksum = null) { if (!class_exists('ZipArchive')) { throw new \UnexpectedValueException('You need the zip extension enabled to use the ZipDownloader'); } - $tmpName = tempnam(sys_get_temp_dir(), ''); - copy($package->getSourceUrl(), $tmpName); + $targetPath = $path . "/" . $package->getName(); + if (!is_dir($targetPath)) { + if (file_exists($targetPath)) { + throw new \UnexpectedValueException($targetPath.' exists and is not a directory.'); + } + if (!mkdir($targetPath, 0777, true)) { + throw new \UnexpectedValueException($targetPath.' does not exist and could not be created.'); + } + } - if (!file_exists($tmpName)) { - throw new \UnexpectedValueException($path.' could not be saved into '.$tmpName.', make sure the' + $zipName = $targetPath.'/'.basename($url, '.zip').'.zip'; + echo 'Downloading '.$url.' to '.$zipName.PHP_EOL; + copy($url, $zipName); + + if (!file_exists($zipName)) { + throw new \UnexpectedValueException($path.' could not be saved into '.$zipName.', make sure the' .' directory is writable and you have internet connectivity.'); } - $zipArchive = new ZipArchive(); + if ($checksum && hash_file('sha1', $zipName) !== $checksum) { + throw new \UnexpectedValueException('The checksum verification failed for the '.$package->getName().' archive (downloaded from '.$url.'). Installation aborted.'); + } - if (true === ($retval = $zipArchive->open($tmpName))) { - $zipArchive->extractTo($path.'/'.$package->getName()); + $zipArchive = new \ZipArchive(); + + echo 'Unpacking archive'.PHP_EOL; + if (true === ($retval = $zipArchive->open($zipName))) { + $targetPath = $path.'/'.$package->getName(); + $zipArchive->extractTo($targetPath); $zipArchive->close(); + echo 'Cleaning up'.PHP_EOL; + unlink($zipName); + if (false !== strpos($url, '//github.com/')) { + $contentDir = glob($targetPath.'/*'); + if (1 === count($contentDir)) { + $contentDir = $contentDir[0]; + foreach (array_merge(glob($contentDir.'/.*'), glob($contentDir.'/*')) as $file) { + if (trim(basename($file), '.')) { + rename($file, $targetPath.'/'.basename($file)); + } + } + rmdir($contentDir); + } + } } else { - throw new \UnexpectedValueException($tmpName.' is not a valid zip archive, got error code '.$retval); + throw new \UnexpectedValueException($zipName.' is not a valid zip archive, got error code '.$retval); } } } \ No newline at end of file diff --git a/src/Composer/Installer/LibraryInstaller.php b/src/Composer/Installer/LibraryInstaller.php index 9ea5c7f71..717647f58 100644 --- a/src/Composer/Installer/LibraryInstaller.php +++ b/src/Composer/Installer/LibraryInstaller.php @@ -26,9 +26,15 @@ class LibraryInstaller $this->dir = $dir; } - public function install(PackageInterface $package, $downloader) + public function install(PackageInterface $package, $downloader, $type) { - $downloader->download($package, $this->dir); + if ($type === 'dist') { + $downloader->download($package, $this->dir, $package->getDistUrl(), $package->getDistSha1Checksum()); + } elseif ($type === 'source') { + $downloader->download($package, $this->dir, $package->getSourceUrl()); + } else { + throw new \InvalidArgumentException('Type must be one of (dist, source), '.$type.' given.'); + } return array('version' => $package->getVersion()); } } \ No newline at end of file diff --git a/src/Composer/Repository/ComposerRepository.php b/src/Composer/Repository/ComposerRepository.php index 769747a58..9eea15f0b 100644 --- a/src/Composer/Repository/ComposerRepository.php +++ b/src/Composer/Repository/ComposerRepository.php @@ -51,6 +51,10 @@ class ComposerRepository extends ArrayRepository $package->setSourceType($rev['source']['type']); $package->setSourceUrl($rev['source']['url']); + $package->setDistType($rev['dist']['type']); + $package->setDistUrl($rev['dist']['url']); + $package->setDistSha1Checksum($rev['dist']['shasum']); + if (isset($rev['license'])) { $package->setLicense($rev['license']); } diff --git a/src/Composer/Repository/GitRepository.php b/src/Composer/Repository/GitRepository.php index 696b1fc6d..8eb0f95da 100644 --- a/src/Composer/Repository/GitRepository.php +++ b/src/Composer/Repository/GitRepository.php @@ -18,6 +18,8 @@ use Composer\Package\Link; use Composer\Package\LinkConstraint\VersionConstraint; /** + * FIXME This is majorly broken and incomplete, it was an experiment + * * @author Jordi Boggiano */ class GitRepository extends ArrayRepository diff --git a/src/Composer/Repository/PearRepository.php b/src/Composer/Repository/PearRepository.php index 7a66de69d..6fc4e94f4 100644 --- a/src/Composer/Repository/PearRepository.php +++ b/src/Composer/Repository/PearRepository.php @@ -74,8 +74,8 @@ class PearRepository extends ArrayRepository $version = BasePackage::parseVersion($pearVersion); $package = new MemoryPackage($packageName, $version['version'], $version['type']); - $package->setSourceType('pear'); - $package->setSourceUrl($this->url.'/get/'.$packageName.'-'.$pearVersion.".tgz"); + $package->setDistType('pear'); + $package->setDistUrl($this->url.'/get/'.$packageName.'-'.$pearVersion.".tgz"); $depsLink = $releaseLink . "/deps.".$pearVersion.".txt"; $deps = file_get_contents($depsLink);