瀏覽代碼

Add command to install a package as a new project into a non-existant directory. This fetches the given package from packagist or a different packagist-source and installs it into a given path.

Benjamin Eberlei 13 年之前
父節點
當前提交
bbf745f3e6

+ 121 - 0
src/Composer/Command/InstallProjectCommand.php

@@ -0,0 +1,121 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Output\OutputInterface;
+use Composer\IO\IOInterface;
+use Composer\Downloader\DownloadManager;
+use Composer\Downloader;
+use Composer\Repository\ComposerRepository;
+use Composer\Installer\ProjectInstaller;
+
+/**
+ * Install a package as new project into new directory.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class InstallProjectCommand extends Command
+{
+    protected function configure()
+    {
+        $this
+            ->setName('install-project')
+            ->setDescription('Install a package as new project into given directory.')
+            ->setDefinition(array(
+                new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
+                new InputOption('packagist-url', null, InputOption::VALUE_REQUIRED, 'Pick a different packagist url to look for the package.'),
+                new InputArgument('package', InputArgument::REQUIRED),
+                new InputArgument('version', InputArgument::OPTIONAL),
+                new InputArgument('directory', InputArgument::OPTIONAL),
+            ))
+            ->setHelp(<<<EOT
+The <info>install-project</info> command installs a given package into a new directory.
+You can use this command to bootstrap new projects or setup a clean installation for
+new developers of your project.
+
+<info>php composer.phar install-project vendor/project intodirectory</info>
+
+To setup a developer workable version you should create the project using the source
+controlled code by appending the <info>'--prefer-source'</info> flag.
+
+To install a package from another packagist repository than the default one you
+can pass the <info>'--packagist-url=http://mypackagist.org'</info> flag.
+
+EOT
+            )
+        ;
+    }
+
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $io = $this->getApplication()->getIO();
+
+        return $this->installProject(
+            $io,
+            $input->getArgument('package'),
+            $input->getArgument('directory'),
+            $input->getArgument('version'),
+            (Boolean)$input->getOption('prefer-source'),
+            $input->getOption('packagist-url')
+        );
+    }
+
+    public function installProject(IOInterface $io, $packageName, $directory = null, $version = null, $preferSource = false, $packagistUrl = null)
+    {
+        $dm = $this->createDownloadManager($io);
+        if ($preferSource) {
+            $dm->setPreferSource(true);
+        }
+
+        if ($packagistUrl === null) {
+            $sourceRepo = new ComposerRepository(array('url' => 'http://packagist.org'));
+        } else {
+            $sourceRepo = new ComposerRepository(array('url' => $packagistUrl));
+        }
+        $package = $sourceRepo->findPackage($packageName, $version);
+        if (!$package) {
+            throw new \InvalidArgumentException("Could not find package $packageName with version $version.");
+        }
+
+        if ($directory === null) {
+            $parts = explode("/", $packageName);
+            $directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts);
+        }
+
+        $projectInstaller = new ProjectInstaller($directory, $dm);
+        $projectInstaller->install($package);
+
+        $io->write('Created new project directory for ' . $package->getName(), true);
+        $io->write('Next steps:', true);
+        $io->write('1. cd ' . $directory, true);
+        $io->write('2. composer install', true);
+    }
+
+    protected function createDownloadManager(IOInterface $io)
+    {
+        $dm = new Downloader\DownloadManager();
+        $dm->setDownloader('git',  new Downloader\GitDownloader($io));
+        $dm->setDownloader('svn',  new Downloader\SvnDownloader($io));
+        $dm->setDownloader('hg', new Downloader\HgDownloader($io));
+        $dm->setDownloader('pear', new Downloader\PearDownloader($io));
+        $dm->setDownloader('zip',  new Downloader\ZipDownloader($io));
+        $dm->setDownloader('tar',  new Downloader\TarDownloader($io));
+        $dm->setDownloader('phar',  new Downloader\PharDownloader($io));
+
+        return $dm;
+    }
+}
+

+ 1 - 0
src/Composer/Console/Application.php

@@ -107,6 +107,7 @@ class Application extends BaseApplication
         $this->add(new Command\DependsCommand());
         $this->add(new Command\InitCommand());
         $this->add(new Command\InstallCommand());
+        $this->add(new Command\InstallProjectCommand());
         $this->add(new Command\UpdateCommand());
         $this->add(new Command\SearchCommand());
         $this->add(new Command\ValidateCommand());

+ 111 - 0
src/Composer/Installer/ProjectInstaller.php

@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Installer;
+
+use Composer\DependencyResolver\Operation\OperationInterface;
+use Composer\Package\PackageInterface;
+use Composer\Downloader\DownloadManager;
+
+/**
+ * Project Installer is used to install a single package into a directory as
+ * root project.
+ *
+ * @author Benjamin Eberlei <kontakt@beberlei.de>
+ */
+class ProjectInstaller implements InstallerInterface
+{
+    private $installPath;
+    private $downloadManager;
+
+    public function __construct($installPath, DownloadManager $dm)
+    {
+        $this->installPath = $installPath;
+        $this->downloadManager = $dm;
+    }
+
+    /**
+     * Decides if the installer supports the given type
+     *
+     * @param   string  $packageType
+     * @return  Boolean
+     */
+    public function supports($packageType)
+    {
+        return true;
+    }
+
+    /**
+     * Checks that provided package is installed.
+     *
+     * @param   PackageInterface    $package    package instance
+     *
+     * @return  Boolean
+     */
+    public function isInstalled(PackageInterface $package)
+    {
+        return false;
+    }
+
+    /**
+     * Installs specific package.
+     *
+     * @param   PackageInterface    $package    package instance
+     */
+    public function install(PackageInterface $package)
+    {
+        $installPath = $this->installPath;
+        if (file_exists($installPath)) {
+            throw new \InvalidArgumentException("Project directory $installPath already exists.");
+        }
+        if (!file_exists(dirname($installPath))) {
+            throw new \InvalidArgumentException("Project root " . dirname($installPath) . " does not exist.");
+        }
+        mkdir($installPath, 0777);
+        $this->downloadManager->download($package, $installPath);
+    }
+
+    /**
+     * Updates specific package.
+     *
+     * @param   PackageInterface    $initial    already installed package version
+     * @param   PackageInterface    $target     updated version
+     *
+     * @throws  InvalidArgumentException        if $from package is not installed
+     */
+    public function update(PackageInterface $initial, PackageInterface $target)
+    {
+        throw new \InvalidArgumentException("not supported");
+    }
+
+    /**
+     * Uninstalls specific package.
+     *
+     * @param   PackageInterface    $package    package instance
+     */
+    public function uninstall(PackageInterface $package)
+    {
+        throw new \InvalidArgumentException("not supported");
+    }
+
+    /**
+     * Returns the installation path of a package
+     *
+     * @param   PackageInterface    $package
+     * @return  string path
+     */
+    public function getInstallPath(PackageInterface $package)
+    {
+        return $this->installPath;
+    }
+}
+