Skip to content

Commit

Permalink
splitting patch strategy (sh and patch files)
Browse files Browse the repository at this point in the history
  • Loading branch information
adragus-inviqa committed May 11, 2015
1 parent acd6e01 commit ecf6617
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 66 deletions.
16 changes: 0 additions & 16 deletions src/Inviqa/Downloader/Composer.php

This file was deleted.

36 changes: 36 additions & 0 deletions src/Inviqa/Patch/DotPatch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Inviqa\Patch;

use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessUtils;
use Symfony\Component\Process\Exception\ProcessFailedException;

class DotPatch extends Patch
{
const TYPE = 'patch';

/**
* @throws ProcessFailedException
* @return boolean
*/
protected function doApply()
{
$patchPath = ProcessUtils::escapeArgument($this->getPatchTemporaryPath());
$process = new Process("patch -p 1 < $patchPath");
$process->mustRun();
return $process->getExitCode() === 0;
}

protected function canApply()
{
$patchPath = ProcessUtils::escapeArgument($this->getPatchTemporaryPath());
$process = new Process("patch --dry-run -p 1 < $patchPath");
try {
$process->mustRun();
return $process->getExitCode() === 0;
} catch (\Exception $e) {
return false;
}
}
}
26 changes: 26 additions & 0 deletions src/Inviqa/Patch/Factory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Inviqa\Patch;

class Factory
{
/**
* @param string $patchName
* @param string $patchGroup
* @param array $patchDetails
* @return Patch
*/
public static function create($patchName, $patchGroup, array $patchDetails)
{
if (empty($patchDetails['type'])) {
$patchDetails['type'] = DotPatch::TYPE;
}

$type = $patchDetails['type'] === DotPatch::TYPE ? 'DotPatch' : 'Shell';
$patchClass = '\\Inviqa\\Patch\\' . $type;

$patch = new $patchClass($patchName, $patchGroup, $patchDetails);

return $patch;
}
}
203 changes: 203 additions & 0 deletions src/Inviqa/Patch/Patch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php

namespace Inviqa\Patch;

use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\Output;

abstract class Patch
{
private $group;

private $name;

private $title;

private $description;

private $url;

private $tempPatchFilePath;

/**
* @var Output
*/
private $output;

private $log;

/**
* @return boolean
*/
abstract protected function doApply();

/**
* @return boolean
*/
abstract protected function canApply();

public function __construct($name, $group, array $details)
{
$this->setName($name);
$this->setGroup($group);

if (!empty($details['url'])) {
$this->setUrl($details['url']);
}
}

/**
* @return boolean|null
* @throws \Exception
*/
public final function apply()
{
$namespace = $this->getNamespace();
if ($this->canApply()) {
$res = (bool) $this->doApply();

if ($res) {
$this->getOutput()->writeln("<info>Patch $namespace successfully applied.</info>");
} else {
$this->getOutput()->writeln("<comment>Patch $namespace was not applied.</comment>");
}

return $res;
}
$this->getOutput()->writeln("<comment>Patch $namespace skipped. Patch was already applied?</comment>");
return null;
}

/**
* @return string
*/
public function getNamespace()
{
return $this->getGroup() . '/' . $this->getName();
}

/**
* @return string
*/
public function getGroup()
{
return $this->group;
}

/**
* @param string $group
*/
protected function setGroup($group)
{
$this->group = $group;
}

/**
* @return string
*/
public function getName()
{
return $this->name;
}

/**
* @param string $name
*/
protected function setName($name)
{
$this->name = $name;
}

/**
* @return string
*/
public function getTitle()
{
return $this->title;
}

/**
* @param string $title
*/
protected function setTitle($title)
{
$this->title = $title;
}

/**
* @return string
*/
public function getDescription()
{
return $this->description;
}

/**
* @param string $description
*/
protected function setDescription($description)
{
$this->description = $description;
}

/**
* @return string
*/
public function getUrl()
{
return $this->url;
}

/**
* @param string $url
*/
protected function setUrl($url)
{
$this->url = $url;
}

/**
* @return string
* @throws \Exception
*/
protected function getPatchTemporaryPath()
{
if (is_null($this->tempPatchFilePath)) {
$this->getOutput()->writeln("<info>Fetching patch {$this->getNamespace()}</info>");

if (!$this->getUrl()) {
return $this->tempPatchFilePath = '';
}

if (!$patch = file_get_contents($this->getUrl())) {
throw new \Exception("Could not get contents from {$this->getUrl()}");
}

$patchFilePath = sprintf("%s/%s_%s.patch", sys_get_temp_dir(), $this->getGroup(), $this->getName());
file_put_contents($patchFilePath, $patch);

$this->tempPatchFilePath = $patchFilePath;
}

return $this->tempPatchFilePath;
}

/**
* @return Output
*/
public function getOutput()
{
if (!$this->output) {
$this->output = new ConsoleOutput();
}
return $this->output;
}

/**
* @param Output $output
*/
public function setOutput(Output $output)
{
$this->output = $output;
}
}
18 changes: 18 additions & 0 deletions src/Inviqa/Patch/Shell.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Inviqa\Patch;

class Shell extends Patch
{
const TYPE = 'shell';

protected function doApply()
{
return true;
}

protected function canApply()
{
return true;
}
}
61 changes: 11 additions & 50 deletions src/Inviqa/Patcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@

namespace Inviqa;

use Inviqa\Downloader\Composer as composerDownloader;
use Inviqa\Patch\Factory;
use Inviqa\Patch\Patch;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
use \Symfony\Component\Process\ProcessUtils;

class Patcher
{
private $patchFiles = [];

/** @var ConsoleOutput */
private $output;

Expand All @@ -23,58 +19,23 @@ public function patch(\Composer\Script\Event $event)
$this->output = new ConsoleOutput();
$this->event = $event;

$this->fetchPatches();
$this->applyPatches();
}

private function fetchPatches()
{
$downloader = new composerDownloader();
$extra = $this->event->getComposer()->getPackage()->getExtra();

foreach ($extra['patches'] as $patchGroupName => $patchGroup) {
foreach ($patchGroup as $patchName => $patchInfo) {
$patchNamespace = $patchGroupName . '/' . $patchName;
$this->output->writeln("<info>Fetching patch $patchNamespace</info>");
$patchContent = $downloader->getContents($patchInfo['url'], $patchGroupName . '_' . $patchName);
$this->patchFiles[$patchNamespace] = $patchContent;
}
}
}

private function applyPatches()
{
$this->output->writeln("<info>Applying patches...</info>");

foreach ($this->patchFiles as $patchNamespace => $filesToPatch) {
if (!$this->canApplyPatch($filesToPatch)) {
$this->output->writeln('<comment>Patch skipped. Patch was already applied?</comment>');
continue;
}

$process = new Process("patch -p 1 < " . ProcessUtils::escapeArgument($filesToPatch));
try {
$process->mustRun();
$this->output->writeln("<info>Patch $patchNamespace successfully applied.</info>");
} catch (\Exception $e) {
$this->output->getErrorOutput()->writeln("<error>Error applying patch $patchNamespace:</error>");
$this->output->getErrorOutput()->writeln("<error>{$e->getMessage()}</error>");
foreach ($patchGroup as $patchName => $patchDetails) {
$patch = Factory::create($patchName, $patchGroupName, $patchDetails);
$patch->setOutput($this->output);
$this->applyPatch($patch);
}
}
}

/**
* @param $filesToPatch
* @return bool
*/
private function canApplyPatch($filesToPatch)
private function applyPatch(Patch $patch)
{
$process = new Process("patch --dry-run -p 1 < " . ProcessUtils::escapeArgument($filesToPatch));
try {
$process->mustRun();
return $process->getExitCode() === 0;
} catch (ProcessFailedException $e) {
return false;
$patch->apply();
} catch (\Exception $e) {
$this->output->writeln("<error>Error applying patch {$patch->getNamespace()}:</error>");
$this->output->writeln("<error>{$e->getMessage()}</error>");
}
}
}

0 comments on commit ecf6617

Please sign in to comment.