Selaa lähdekoodia

Initial feature-dist

 * extends BaseDumper, implements interface
 * put $keys into BaseDumper

 * WIP WIP WIP WIP
 * BaseDumper for utilities
 * interface to enforce 'dump()'
 * feature:
   * supports git
   * supports zip output
   * basic test to cover feature

 * add @todo for later
 * add vendor namespace to package name

 * add extension to getFilename() so we don't need to switch in there (HT, @naderman)

 * add extension (obviously 'zip' in ZipDumper)

 * create archive in destination dir (provided by __construct())

 * condensed ZipDumper
 * moved code to BaseDumper (hopefully easier re-use)

 * use ProcessExecutor from BaseDumper

 * fix assignments in __construct()
 * allow injection of ProcessExecutor

 * fix parameters

 * fix regex

 * write in 'system temp dir'
 * update test case (oh look, a duplicate regex)

 * move working directory related to BaseDumper

 * add quotes

 * place holder for these methods

 * use PharData to create zip/tar when necessary

 * add placeholder calls
 * add call to package() using PharData

 * finish downloadHg(), downloadSvn()

 * put to use

 * make BaseDumper abstract (to force extension)
 * make BaseDumper implement Interface (makes for less code in the implementation)

new functionality for dumping as .tar.gz

tar instead of tar.gz, new abstract dumpertest class

creates a local git repo instead of fetching a remote one

more oo-ish version of it

no constructor

 * refactor tests to be less linux-specific (used Composer\Util to wrap calls)

 * make filename only the version

 * various cs fixes (idention, tabs/spaces, doc blocks, etc.)
 * fixed a typo'd exception name

 * refactored downloading:
   * removed download*() methods
   * added dep on Composer\Factory to setup a DownloadManager instance

 * update CS with feedback from @stof

 * ArrayDumper doesn't extend BaseDumper anymore (hence no conflict on the interface)
 * move keys from BaseDumper back to ArrayDumper
 * interface now declares dump() to always return void

Apparently I had to update the lock.

CS fixes (tabs for spaces)
Bugfix: sprintf() was missing.

Fix docblock for @stof. ;)

Pull in lock from master.

Update lock one more time (hope it still merges).

whitespace

Revert ArrayDumper static keys
Till Klampaeckel 13 vuotta sitten
vanhempi
commit
2acb033057

+ 166 - 0
src/Composer/Package/Dumper/BaseDumper.php

@@ -0,0 +1,166 @@
+<?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\Package\Dumper;
+
+use Composer\Package\PackageInterface;
+use Composer\Util\ProcessExecutor;
+use Composer\Downloader\GitDownloader;
+use Composer\Downloader\HgDownloader;
+use Composer\Downloader\SvnDownloader;
+use Composer\IO\NullIO;
+use Composer\Factory;
+
+/**
+ * @author Till Klampaeckel <till@php.net>
+ */
+abstract class BaseDumper implements DumperInterface
+{
+    /**
+     * Format: zip or tar.
+     * @var string
+     */
+    protected $format = '';
+
+    /**
+     * Path to where to dump the export to.
+     * @var mixed|null
+     */
+    protected $path;
+
+    /**
+     * @var ProcessExecutor
+     */
+    protected $process;
+
+    /**
+     * Working directory.
+     * @var string
+     */
+    protected $temp;
+
+    /**
+     * @param mixed                $path
+     * @param ProcessExecutor|null $process
+     *
+     * @throws \InvalidArgumentException
+     */
+    public function __construct($path = null, ProcessExecutor $process = null)
+    {
+        if (!empty($path)) {
+            if (!is_writable($path)) {
+                throw new \InvalidArgumentException("Not authorized to write to '{$path}'");
+            }
+            $this->path = $path;
+        }
+        $this->process = $process ?: new ProcessExecutor();
+        $this->temp    = sys_get_temp_dir();
+    }
+
+    /**
+     * @return \Composer\Downloader\DownloadManager
+     */
+    public function getDownloadManager()
+    {
+        $factory = new Factory;
+        $dm = $factory->createDownloadManager(new NullIO());
+        return $dm;
+    }
+
+    /**
+     * @param PackageInterface $package
+     * @param string           $extension
+     *
+     * @return string
+     * @throws \InvalidArgumentException When unknown 'format' is encountered.
+     */
+    public function getFilename(PackageInterface $package, $extension)
+    {
+        $name = $package->getPrettyVersion();
+        $fileName = sprintf('%s.%s', $name, $extension);
+        return $fileName;
+    }
+
+    /**
+     * @param PackageInterface $package
+     *
+     * @return string
+     * @throws \RuntimeException
+     */
+    protected function getAndEnsureWorkDirectory(PackageInterface $package)
+    {
+        $workDir = sprintf('%s/%s/%s', $this->temp, $this->format, $package->getName());
+        if (!file_exists($workDir)) {
+            mkdir($workDir, 0777, true);
+        }
+        if (!file_exists($workDir)) {
+            throw new \RuntimeException("Could not find '{$workDir}' directory.");
+        }
+        return $workDir;
+    }
+
+    /**
+     * Package the given directory into an archive.
+     *
+     * The format is most likely \Phar::TAR or \Phar::ZIP.
+     *
+     * @param string $filename
+     * @param string $workDir
+     * @param int    $format
+     *
+     * @throws \RuntimeException
+     */
+    protected function package($filename, $workDir, $format)
+    {
+        try {
+            $phar = new \PharData($filename, null, null, $format);
+            $phar->buildFromDirectory($workDir);
+        } catch (\UnexpectedValueException $e) {
+            $message  = "Original PHAR exception: " . (string) $e;
+            $message .= PHP_EOL . PHP_EOL;
+            $message .= sprintf("Could not create archive '%s' from '%s'.", $filename, $workDir);
+            throw new \RuntimeException($message);
+        }
+    }
+
+    /**
+     * @param string $fileName
+     * @param string $sourceRef
+     * @param string $workDir
+     */
+    protected function packageGit($fileName, $sourceRef, $workDir)
+    {
+        $command = sprintf(
+            'git archive --format %s --output %s %s',
+            $this->format,
+            escapeshellarg(sprintf('%s/%s', $this->path, $fileName)),
+            $sourceRef
+        );
+        $this->process->execute($command, $output, $workDir);
+    }
+
+    /**
+     * @param string $fileName
+     * @param string $sourceRef
+     * @param string $workDir
+     */
+    protected function packageHg($fileName, $sourceRef, $workDir)
+    {
+        $format  = ($this->format == 'tarball')?'tar':$this->format;
+        $command = sprintf(
+            'hg archive --rev %s --type %s %s',
+            $sourceRef,
+            $format,
+            escapeshellarg(sprintf('%s/%s', $this->path, $fileName))
+        );
+        $this->process->execute($command, $output, $workDir);
+    }
+}

+ 29 - 0
src/Composer/Package/Dumper/DumperInterface.php

@@ -0,0 +1,29 @@
+<?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\Package\Dumper;
+
+use Composer\Package\PackageInterface;
+
+/**
+ * @author Till Klampaeckel <till@php.net>
+ */
+interface DumperInterface
+{
+    /**
+     * Return value depends on implementation - e.g. generating a tar or zip the
+     * method currently returns void, the ArrayDumper returns an array.
+     *
+     * @param PackageInterface $package
+     *
+     * @return void
+     */
+    public function dump(PackageInterface $package);
+}

+ 57 - 0
src/Composer/Package/Dumper/TarDumper.php

@@ -0,0 +1,57 @@
+<?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\Package\Dumper;
+
+use Composer\Package\Dumper\BaseDumper;
+use Composer\Package\Dumper\DumperInterface;
+use Composer\Package\PackageInterface;
+use Composer\Util\ProcessExecutor;
+
+/**
+ * @author Ulf Härnhammar <ulfharn@gmail.com>
+ */
+class TarDumper extends BaseDumper
+{
+    protected $format = 'tar';
+
+    /**
+     * @param PackageInterface $package
+     * @throws \InvalidArgumentException
+     */
+    public function dump(PackageInterface $package)
+    {
+        $workDir = $this->getAndEnsureWorkDirectory($package);
+
+        $fileName   = $this->getFilename($package, 'tar');
+        $sourceType = $package->getSourceType();
+        $sourceRef  = $package->getSourceReference();
+
+        $dm = $this->getDownloadManager();
+        $dm->download($package, $workDir, true);
+
+        switch ($sourceType) {
+            case 'git':
+                $this->packageGit($fileName, $sourceRef, $workDir);
+                break;
+            case 'hg':
+                $this->packageHg($fileName, $sourceRef, $workDir);
+                break;
+            case 'svn':
+                $dir = $workDir . (substr($sourceRef, 0, 1) !== '/')?'/':'' . $sourceRef;
+                $this->package($fileName, $dir, \Phar::TAR);
+                break;
+            default:
+                throw new \InvalidArgumentException(
+                    "Unable to handle repositories of type '{$sourceType}'.");
+        }
+    }
+}

+ 56 - 0
src/Composer/Package/Dumper/ZipDumper.php

@@ -0,0 +1,56 @@
+<?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\Package\Dumper;
+
+use Composer\Package\Dumper\BaseDumper;
+use Composer\Package\Dumper\DumperInterface;
+use Composer\Package\PackageInterface;
+use Composer\Util\ProcessExecutor;
+
+/**
+ * @author Till Klampaeckel <till@php.net>
+ */
+class ZipDumper extends BaseDumper
+{
+    protected $format = 'zip';
+
+    /**
+     * @param PackageInterface $package
+     * @throws \InvalidArgumentException
+     */
+    public function dump(PackageInterface $package)
+    {
+        $workDir = $this->getAndEnsureWorkDirectory($package);
+
+        $fileName   = $this->getFilename($package, 'zip');
+        $sourceType = $package->getSourceType();
+        $sourceRef  = $package->getSourceReference();
+
+        $dm = $this->getDownloadManager();
+        $dm->download($package, $workDir, true);
+
+        switch ($sourceType) {
+            case 'git':
+                $this->packageGit($fileName, $sourceRef, $workDir);
+                break;
+            case 'hg':
+                $this->packageHg($fileName, $sourceRef, $workDir);
+                break;
+            case 'svn':
+                $dir = $workDir . (substr($sourceRef, 0, 1) !== '/')?'/':'' . $sourceRef;
+                $this->package($fileName, $dir, \Phar::ZIP);
+                break;
+            default:
+                throw new \InvalidArgumentException("Unable to handle repositories of type '{$sourceType}'.");
+        }
+    }
+}

+ 97 - 0
tests/Composer/Test/Package/Dumper/DumperTest.php

@@ -0,0 +1,97 @@
+<?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\Test\Package\Dumper;
+
+use Composer\Package\MemoryPackage;
+use Composer\Util\Filesystem;
+use Composer\Util\ProcessExecutor;
+
+abstract class DumperTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Composer\Util\Filesystem
+     */
+    protected $fs;
+
+    /**
+     * @var \Composer\Util\ProcessExecutor
+     */
+    protected $process;
+
+    /**
+     * @var string
+     */
+    protected $testdir = '';
+
+    public function setUp()
+    {
+        $this->fs      = new Filesystem;
+        $this->process = new ProcessExecutor;
+        $this->testdir = sys_get_temp_dir() . '/composer_dumpertest_git_repository' . mt_rand();
+    }
+
+    protected function getTestDir()
+    {
+        return $this->testdir;
+    }
+
+    /**
+     * Create local git repository to run tests against!
+     */
+    protected function setupGitRepo()
+    {
+        $td = $this->getTestDir();
+
+        $this->fs->removeDirectory($td);
+        $this->fs->ensureDirectoryExists($td);
+
+        $currentWorkDir = getcwd();
+        chdir($td);
+
+        $result = $this->process->execute("git init -q");
+        if ($result > 0) {
+            throw new \RuntimeException(
+                "Could not init: " . $this->process->getErrorOutput());
+        }
+        $result = file_put_contents('b', 'a');
+        if (false === $result) {
+            throw new \RuntimeException("Could not save file.");
+        }
+        $result = $this->process->execute("git add b && git commit -m 'commit b' -q");
+        if ($result > 0) {
+            throw new \RuntimeException(
+                "Could not init: " . $this->process->getErrorOutput());
+        }
+        chdir($currentWorkDir);
+    }
+
+    protected function removeGitRepo()
+    {
+        $td = $this->getTestDir();
+        $this->fs->removeDirectory($td);
+    }
+
+    protected function setupPackage()
+    {
+        $td = $this->getTestDir();
+        $package = new MemoryPackage('dumpertest/dumpertest', 'master', 'master');
+        $package->setSourceUrl("file://$td");
+        $package->setSourceReference('master');
+        $package->setSourceType('git');
+        return $package;
+    }
+
+    protected function getPackageFileName(MemoryPackage $package)
+    {
+        return $package->getVersion();
+    }
+}

+ 43 - 0
tests/Composer/Test/Package/Dumper/TarDumperTest.php

@@ -0,0 +1,43 @@
+<?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\Test\Package\Dumper;
+
+use Composer\Package\Dumper\TarDumper;
+
+class TarDumperTest extends DumperTest
+{
+    public function testThis()
+    {
+        $this->setupGitRepo();
+        $package = $this->setupPackage();
+        $name = $this->getPackageFileName($package);
+
+        $temp = sys_get_temp_dir();
+        $tar = new TarDumper($temp);
+        $tar->dump($package);
+
+        $dist = sprintf('%s/%s.tar',
+            $temp, $name
+        );
+        $this->assertFileExists($dist);
+        unlink($dist);
+        $this->removeGitRepo();
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testException()
+    {
+        new TarDumper("/totally-random-" . time());
+    }
+}

+ 43 - 0
tests/Composer/Test/Package/Dumper/ZipDumperTest.php

@@ -0,0 +1,43 @@
+<?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\Test\Package\Dumper;
+
+use Composer\Package\Dumper\ZipDumper;
+
+class ZipDumperTest extends DumperTest
+{
+    public function testThis()
+    {
+        $this->setupGitRepo();
+        $package = $this->setupPackage();
+        $name = $this->getPackageFileName($package);
+
+        $temp = sys_get_temp_dir();
+        $zip = new ZipDumper($temp);
+        $zip->dump($package);
+
+        $dist = sprintf('%s/%s.zip',
+            $temp, $name
+        );
+        $this->assertFileExists($dist);
+        unlink($dist);
+        $this->removeGitRepo();
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     */
+    public function testException()
+    {
+        new ZipDumper("/totally-random-" . time());
+    }
+}