diff --git a/Repository/Vcs/GitDriver.php b/Repository/Vcs/GitDriver.php
index 6a695a56..0ba185c6 100644
--- a/Repository/Vcs/GitDriver.php
+++ b/Repository/Vcs/GitDriver.php
@@ -12,7 +12,10 @@
namespace Fxp\Composer\AssetPlugin\Repository\Vcs;
use Composer\Cache;
+use Composer\IO\IOInterface;
use Composer\Repository\Vcs\GitDriver as BaseGitDriver;
+use Composer\Util\Filesystem;
+use Composer\Util\Git as GitUtil;
/**
* Git vcs driver.
@@ -35,4 +38,58 @@ public function getComposerInformation($identifier)
return ProcessUtil::getComposerInformation($this->cache, $this->infoCache, $this->repoConfig['asset-type'], $this->process, $identifier, $resource, sprintf('git show %s', $resource), sprintf('git log -1 --format=%%at %s', escapeshellarg($identifier)), $this->repoDir, '@');
}
+
+ /**
+ * {@inheritDoc}
+ */
+ public function initialize()
+ {
+ /* @var AssetRepositoryManager $arm */
+ $arm = $this->repoConfig['asset-repository-manager'];
+
+ $skipSync = false;
+ if (null !== ($skip = $arm->getConfig()->get('git-skip-update'))) {
+ $localUrl = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
+ // check if local copy exists and if it is a git repository and that modification time is within threshold
+ if (is_dir($localUrl) && is_file($localUrl.'/config') && filemtime($localUrl) > strtotime('-'.$skip)) {
+ $skipSync = true;
+ $this->io->write('(skip update) ', false, IOInterface::VERBOSE);
+ }
+ }
+
+ // copied from parent::initialize()
+ if (Filesystem::isLocalPath($this->url)) {
+ $this->url = preg_replace('{[\\/]\.git/?$}', '', $this->url);
+ $this->repoDir = $this->url;
+ $cacheUrl = realpath($this->url);
+ } else {
+ $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . preg_replace('{[^a-z0-9.]}i', '-', $this->url) . '/';
+
+ GitUtil::cleanEnv();
+
+ $fs = new Filesystem();
+ $fs->ensureDirectoryExists(dirname($this->repoDir));
+
+ if (!is_writable(dirname($this->repoDir))) {
+ throw new \RuntimeException('Can not clone '.$this->url.' to access package information. The "'.dirname($this->repoDir).'" directory is not writable by the current user.');
+ }
+
+ if (preg_match('{^ssh://[^@]+@[^:]+:[^0-9]+}', $this->url)) {
+ throw new \InvalidArgumentException('The source URL '.$this->url.' is invalid, ssh URLs should have a port number after ":".'."\n".'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.');
+ }
+
+ $gitUtil = new GitUtil($this->io, $this->config, $this->process, $fs);
+ // patched line, sync from local dir without modifying url
+ if (!$skipSync && !$gitUtil->syncMirror($this->url, $this->repoDir)) {
+ $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated');
+ }
+
+ $cacheUrl = $this->url;
+ }
+
+ $this->getTags();
+ $this->getBranches();
+
+ $this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
+ }
}
diff --git a/Resources/doc/schema.md b/Resources/doc/schema.md
index 3bbbd720..eb36c26e 100644
--- a/Resources/doc/schema.md
+++ b/Resources/doc/schema.md
@@ -49,6 +49,16 @@ The plugin can override the main file definitions of the Bower packages. To over
definitions specify the packages and their main file array as name/value pairs. For an example
see the [usage informations](index.md#override-the-main-files-for-bower).
+##### config.fxp-asset.git-skip-update (root-only)
+
+The plugin can skip updating meta-data in git repositories for given amount of time, i.e. `6 hours`, `3 days` or `1 week`.
+
+ "config": {
+ "fxp-asset": {
+ "git-skip-update": "2 days"
+ }
+ }
+
### Mapping asset file to composer package
##### NPM mapping
diff --git a/Tests/Repository/Vcs/GitDriverTest.php b/Tests/Repository/Vcs/GitDriverTest.php
index 9ebda6aa..fa0f7637 100644
--- a/Tests/Repository/Vcs/GitDriverTest.php
+++ b/Tests/Repository/Vcs/GitDriverTest.php
@@ -15,6 +15,7 @@
use Composer\IO\IOInterface;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
+use Fxp\Composer\AssetPlugin\Repository\AssetRepositoryManager;
use Fxp\Composer\AssetPlugin\Repository\Vcs\GitDriver;
/**
@@ -29,15 +30,34 @@ class GitDriverTest extends \PHPUnit_Framework_TestCase
*/
private $config;
+ /**
+ * @var AssetRepositoryManager|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $assetRepositoryManager;
+
public function setUp()
{
+ $assetConfig = new \Fxp\Composer\AssetPlugin\Config\Config(array('git-skip-update' => '1 hour'));
+
+ /* @var AssetRepositoryManager|\PHPUnit_Framework_MockObject_MockObject $arm */
+ $this->assetRepositoryManager = $this->getMockBuilder(AssetRepositoryManager::class)->disableOriginalConstructor()->getMock();
+ $this->assetRepositoryManager->expects($this->any())
+ ->method('getConfig')
+ ->willReturn($assetConfig);
+
$this->config = new Config();
$this->config->merge(array(
'config' => array(
'home' => sys_get_temp_dir().'/composer-test',
'cache-repo-dir' => sys_get_temp_dir().'/composer-test-cache',
+ 'cache-vcs-dir' => sys_get_temp_dir().'/composer-test-cache',
),
));
+
+ // Mock for skip asset
+ $fs = new Filesystem();
+ $fs->ensureDirectoryExists(sys_get_temp_dir().'/composer-test-cache/https---github.com-fxpio-composer-asset-plugin.git');
+ file_put_contents(sys_get_temp_dir().'/composer-test-cache/https---github.com-fxpio-composer-asset-plugin.git/config', '');
}
public function tearDown()
@@ -71,6 +91,7 @@ public function testPublicRepositoryWithEmptyComposer($type, $filename)
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
+ 'asset-repository-manager' => $this->assetRepositoryManager,
);
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
@@ -96,6 +117,65 @@ public function testPublicRepositoryWithEmptyComposer($type, $filename)
$this->assertSame($validEmpty, $gitDriver->getComposerInformation($identifier));
}
+ /**
+ * @dataProvider getAssetTypes
+ *
+ * @param string $type
+ * @param string $filename
+ */
+ public function testPublicRepositoryWithSkipUpdate($type, $filename)
+ {
+ $repoUrl = 'https://github.com/fxpio/composer-asset-plugin.git';
+ $identifier = '92bebbfdcde75ef2368317830e54b605bc938123';
+ $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
+
+ $repoConfig = array(
+ 'url' => $repoUrl,
+ 'asset-type' => $type,
+ 'filename' => $filename,
+ 'asset-repository-manager' => $this->assetRepositoryManager,
+ );
+
+ $process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
+ $process->expects($this->any())
+ ->method('splitLines')
+ ->will($this->returnValue(array()));
+ $process->expects($this->any())
+ ->method('execute')
+ ->will($this->returnCallback(function ($command, &$output = null) use ($identifier, $repoConfig) {
+ if ($command === sprintf('git show %s', sprintf('%s:%s', escapeshellarg($identifier), $repoConfig['filename']))) {
+ $output = '{"name": "foo"}';
+ } elseif (false !== strpos($command, 'git log')) {
+ $date = new \DateTime(null, new \DateTimeZone('UTC'));
+ $output = $date->getTimestamp();
+ }
+
+ return 0;
+ }));
+
+ /* @var IOInterface $io */
+ /* @var ProcessExecutor $process */
+
+ $gitDriver1 = new GitDriver($repoConfig, $io, $this->config, $process, null);
+ $gitDriver1->initialize();
+
+ $gitDriver2 = new GitDriver($repoConfig, $io, $this->config, $process, null);
+ $gitDriver2->initialize();
+
+ $validEmpty = array(
+ '_nonexistent_package' => true,
+ );
+
+ $composer1 = $gitDriver1->getComposerInformation($identifier);
+ $composer2 = $gitDriver2->getComposerInformation($identifier);
+
+ $this->assertNotNull($composer1);
+ $this->assertNotNull($composer2);
+ $this->assertSame($composer1, $composer2);
+ $this->assertNotSame($validEmpty, $composer1);
+ $this->assertNotSame($validEmpty, $composer2);
+ }
+
/**
* @dataProvider getAssetTypes
*
@@ -110,6 +190,7 @@ public function testPublicRepositoryWithCodeCache($type, $filename)
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
+ 'asset-repository-manager' => $this->assetRepositoryManager,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
@@ -156,6 +237,7 @@ public function testPublicRepositoryWithFilesystemCache($type, $filename)
'url' => $repoUrl,
'asset-type' => $type,
'filename' => $filename,
+ 'asset-repository-manager' => $this->assetRepositoryManager,
);
$io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
$process = $this->getMockBuilder('Composer\Util\ProcessExecutor')->getMock();
diff --git a/Tests/Repository/Vcs/GitHubDriverTest.php b/Tests/Repository/Vcs/GitHubDriverTest.php
index 4c007ff7..32836f79 100644
--- a/Tests/Repository/Vcs/GitHubDriverTest.php
+++ b/Tests/Repository/Vcs/GitHubDriverTest.php
@@ -49,8 +49,13 @@ public function setUp()
),
));
+ $assetConfig = new \Fxp\Composer\AssetPlugin\Config\Config(array());
+
$this->assetRepositoryManager = $this->getMockBuilder(AssetRepositoryManager::class)
->disableOriginalConstructor()->getMock();
+ $this->assetRepositoryManager->expects($this->any())
+ ->method('getConfig')
+ ->willReturn($assetConfig);
}
public function tearDown()