Skip to content

Commit

Permalink
Merge pull request #7 from clue/add-install
Browse files Browse the repository at this point in the history
Add feature to download/install given package from packagist
  • Loading branch information
clue committed Aug 12, 2013
2 parents c4dbd3b + c6bbda6 commit 6c49d69
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 26 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# CHANGELOG

This file is a manually maintained list of changes for each release. Feel free
to add your changes here when sending pull requests. Also send corrections if
you spot any mistakes.

## 0.1.0 (2013-xx-xx)

* Feature: Packages can now automatically be downloaded and installed prior to generating phar (#7)

## 0.0.2 (2013-05-25)

* Feature: Bundle complete project directories

## 0.0.1 (2013-05-18)

* First tagged release

5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"require": {
"herrera-io/box": "~1.2",
"symfony/console": "~2.1",
"symfony/finder": "~2.1"
"symfony/finder": "~2.1",
"symfony/process": "~2.1"
},
"autoload": {
"psr-0": {"Clue": "src/"}
Expand All @@ -16,6 +17,6 @@
"extra": {
"phar": {
"bundler": "composer"
}
}
}
}
79 changes: 66 additions & 13 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/Clue/PharComposer/Bundler/Base.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ protected function addDirectory($dir)
->ignoreVCS(true)
->in($dir);

$this->pharcomposer->log(' adding "' . $dir .'" as "' . $this->pharcomposer->getPathLocalToBase($dir).'"...');
$this->pharcomposer->log(' adding "' . $dir .'" as "' . $this->pharcomposer->getPathLocalToBase($dir) . '"');
$this->box->buildFromIterator($iterator, $this->pharcomposer->getBase());
}

protected function addFile($file)
{
$local = $this->pharcomposer->getPathLocalToBase($file);
$this->pharcomposer->log(' adding "' . $file .'" as "' . $local.'"...');
$this->pharcomposer->log(' adding "' . $file .'" as "' . $local . '"');
$this->box->addFile($file, $local);
}
}
2 changes: 1 addition & 1 deletion src/Clue/PharComposer/Bundler/Complete.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function build(PharComposer $pharcomposer, Box $box, Package $package)
->exclude($package->getPathVendor())
->in($package->getDirectory());

$pharcomposer->log(' Adding whole project directory "' . $package->getDirectory() . '"...');
$pharcomposer->log(' Adding whole project directory "' . $package->getDirectory() . '"');
$box->buildFromIterator($iterator, $pharcomposer->getBase());
}
}
91 changes: 90 additions & 1 deletion src/Clue/PharComposer/Command/Build.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
use Symfony\Component\Console\Output\OutputInterface;
use Clue\PharComposer\PharComposer;
use InvalidArgumentException;
use UnexpectedValueException;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ExecutableFinder;

class Build extends Command
{
Expand All @@ -31,7 +35,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
return;
}

$output->writeln('<info>Your configuration disables writing phar files (phar.readonly = On), trying to re-spawn with correct config...');
$output->writeln('<info>Your configuration disables writing phar files (phar.readonly = On), trying to re-spawn with correct config');
sleep(1);

$args = array_merge(array('php', '-d phar.readonly=off'), $_SERVER['argv']);
Expand All @@ -42,6 +46,43 @@ protected function execute(InputInterface $input, OutputInterface $output)
}

$path = $input->getArgument('path');

if ($this->isPackageName($path)) {
if (is_dir($path)) {
$output->writeln('<info>There\'s also a directory with the given name</info>');
}
$package = $path;

$path = sys_get_temp_dir() . '/phar-composer' . mt_rand(0,9);
while (is_dir($path)) {
$path .= mt_rand(0, 9);
}

$finder = new ExecutableFinder();
if (is_file('composer.phar')) {
$command = $finder->find('php', '/usr/bin/php') . ' composer.phar';
} else {
$command = $finder->find('composer', '/usr/bin/composer');
}

$output->write('Installing <info>' . $package . '</info> to temporary directory <info>' . $path . '</info> (using <info>' . $command . '</info>)');


$command .= ' create-project ' . escapeshellarg($package) . ' ' . escapeshellarg($path) . ' --no-dev --no-progress --no-scripts';

$time = microtime(true);
try {
$this->exec($command, $output);
}
catch (UnexpectedValueException $e) {
throw new UnexpectedValueException('Installing package via composer failed', 0, $e);
}

$time = max(microtime(true) - $time, 0);
$output->writeln('');
$output->writeln(' <info>OK</info> - Downloading package completed after ' . round($time, 1) . 's');
}

if (is_dir($path)) {
$path = rtrim($path, '/') . '/composer.json';
}
Expand Down Expand Up @@ -85,6 +126,54 @@ protected function execute(InputInterface $input, OutputInterface $output)
$pharcomposer->setTarget($target);
}

$time = microtime(true);
$pharcomposer->build();

$time = max(microtime(true) - $time, 0);
$output->writeln('');
$output->writeln(' <info>OK</info> - Creating <info>' . $pharcomposer->getTarget() .'</info> completed after ' . round($time, 1) . 's');
}

private function isPackageName($path)
{
return !!preg_match('/^[^\s\/]+\/[^\s\/]+(\:[^\s]+)?$/i', $path);
}

private function exec($cmd, OutputInterface $output)
{
$ok = true;
$nl = true;

$process = new Process($cmd);
$process->start();
$code = $process->wait(function($type, $data) use ($output, &$ok, &$nl) {
if ($nl === true) {
$data = "\n" . $data;
$nl = false;
}
if (substr($data, -1) === "\n") {
$nl = true;
$data = substr($data, 0, -1);
}
$data = str_replace("\n", "\n ", $data);

if ($type === Process::OUT) {
$output->write($data);
} else {
$output->write($data);
$ok = false;
}
});
if ($nl) {
$output->writeln('');
}

if ($code !== 0) {
throw new UnexpectedValueException('Error status code: ' . $process->getExitCodeText() . ' (code ' . $code . ')');
}

if (!$ok) {
throw new UnexpectedValueException('Error output present');
}
}
}
14 changes: 7 additions & 7 deletions src/Clue/PharComposer/PharComposer.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ public function build()
}

$target = $this->getTarget();
$this->log('Start creating "'.$target.'"...');
$this->log('Start creating "'.$target.'"');
if (file_exists($target)) {
$this->log('Remove existing file...');
$this->log(' - Remove existing file');
if(unlink($target) === false) {
throw new UnexpectedValueException('Unable to remove existing phar archive "'.$target.'"');
}
Expand All @@ -143,10 +143,10 @@ public function build()
$box = Box::create($target);
$box->getPhar()->startBuffering();

$this->log('Adding main package...');
$this->log(' - Adding main package');
$this->addPackage($this->getPackageRoot(), $box);

$this->log('Adding composer base files...');
$this->log(' - Adding composer base files');
// explicitly add composer autoloader
$box->addFile($pathVendor . 'autoload.php');

Expand All @@ -156,12 +156,12 @@ public function build()
$box->buildFromIterator(new \GlobIterator($pathVendor . 'composer/*.*', \FilesystemIterator::KEY_AS_FILENAME), $this->getBase());

foreach ($this->getPackagesDependencies() as $package) {
$this->log('Adding dependency "' . $package->getName() . '" from "' . $this->getPathLocalToBase($package->getDirectory()) .'"...');
$this->log(' - Adding dependency "' . $package->getName() . '" from "' . $this->getPathLocalToBase($package->getDirectory()) . '"');
$this->addPackage($package, $box);
}


$this->log('Setting main/stub...');
$this->log(' - Setting main/stub');
$chmod = 0755;
$main = $this->getMain();
if ($main === null) {
Expand Down Expand Up @@ -190,7 +190,7 @@ public function build()
$box->getPhar()->stopBuffering();

if ($chmod !== null) {
$this->log(' Applying chmod ' . sprintf('%04o', $chmod) . '...');
$this->log(' Applying chmod ' . sprintf('%04o', $chmod));
if (chmod($target, $chmod) === false) {
throw new UnexpectedValueException('Unable to chmod target file "' . $target .'"');
}
Expand Down

0 comments on commit 6c49d69

Please sign in to comment.