From c6e4984a6243ab5f327205f48c2a66c6a6520026 Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Tue, 8 Nov 2011 09:14:34 +0100 Subject: [PATCH 1/9] New downloader for mercurial --- bin/composer | 1 + src/Composer/Downloader/HgDownloader.php | 74 ++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/Composer/Downloader/HgDownloader.php diff --git a/bin/composer b/bin/composer index b188aa337..15b9a907c 100755 --- a/bin/composer +++ b/bin/composer @@ -29,6 +29,7 @@ $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository'); // initialize download manager $dm = new Downloader\DownloadManager(); $dm->setDownloader('git', new Downloader\GitDownloader()); +$dm->setDownloader('hg', new Downloader\HgDownloader()); $dm->setDownloader('pear', new Downloader\PearDownloader()); $dm->setDownloader('zip', new Downloader\ZipDownloader()); diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php new file mode 100644 index 000000000..df0d6ae05 --- /dev/null +++ b/src/Composer/Downloader/HgDownloader.php @@ -0,0 +1,74 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Downloader; + +use Composer\Package\PackageInterface; + +/** + * @author Per Bernhardt + */ +class HgDownloader implements DownloaderInterface +{ + /** + * {@inheritDoc} + */ + public function getInstallationSource() + { + return 'source'; + } + + /** + * {@inheritDoc} + */ + public function download(PackageInterface $package, $path) + { + if (!$package->getSourceReference()) { + throw new \InvalidArgumentException('The given package is missing reference information'); + } + + $url = escapeshellarg($package->getSourceUrl()); + $ref = escapeshellarg($package->getSourceReference()); + system(sprintf('hg clone %s %s && cd %2$s && hg up %s', $url, $path, $ref)); + } + + /** + * {@inheritDoc} + */ + public function update(PackageInterface $initial, PackageInterface $target, $path) + { + if (!$target->getSourceReference()) { + throw new \InvalidArgumentException('The given package is missing reference information'); + } + + $this->enforceCleanDirectory($path); + system(sprintf('cd %s && hg pull && hg up %s', $path, $target->getSourceReference())); + } + + /** + * {@inheritDoc} + */ + public function remove(PackageInterface $package, $path) + { + $this->enforceCleanDirectory($path); + $fs = new Util\Filesystem(); + $fs->remove($path); + } + + private function enforceCleanDirectory($path) + { + exec(sprintf('cd %s && hg st', $path), $output); + if (implode('', $output)) { + throw new \RuntimeException('Source directory has uncommitted changes'); + } + } +} From ee4d4ee3fae26b87dbfca2b9fba8146dd1f04a50 Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Thu, 10 Nov 2011 11:58:48 +0100 Subject: [PATCH 2/9] Added HgDriver for the VcsRepository --- src/Composer/Repository/Vcs/HgDriver.php | 186 ++++++++++++++++++++++ src/Composer/Repository/VcsRepository.php | 2 +- 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/Composer/Repository/Vcs/HgDriver.php diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php new file mode 100644 index 000000000..6e58a3dda --- /dev/null +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -0,0 +1,186 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Repository\Vcs; + +use Composer\Json\JsonFile; + +/** + * @author Per Bernhardt + */ +class HgDriver implements VcsDriverInterface +{ + protected $url; + protected $tags; + protected $branches; + protected $rootIdentifier; + protected $infoCache = array(); + + public function __construct($url) + { + $this->url = $url; + $this->tmpDir = sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $url) . '/'; + } + + /** + * {@inheritDoc} + */ + public function initialize() + { + $url = escapeshellarg($this->url); + $tmpDir = escapeshellarg($this->tmpDir); + if (is_dir($this->tmpDir)) { + exec(sprintf('cd %s && hg pull -u', $tmpDir), $output); + } else { + exec(sprintf('hg clone %s %s', $url, $tmpDir), $output); + } + + $this->getTags(); + $this->getBranches(); + } + + /** + * {@inheritDoc} + */ + public function getRootIdentifier() + { + $tmpDir = escapeshellarg($this->tmpDir); + if (null === $this->rootIdentifier) { + exec(sprintf('cd %s && hg tip --template "{rev}:{node|short}" --color never', $tmpDir), $output); + $this->rootIdentifier = $output[0]; + } + return $this->rootIdentifier; + } + + /** + * {@inheritDoc} + */ + public function getUrl() + { + return $this->url; + } + + /** + * {@inheritDoc} + */ + public function getSource($identifier) + { + $label = array_search($identifier, (array) $this->tags) ?: $identifier; + + return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $label); + } + + /** + * {@inheritDoc} + */ + public function getDist($identifier) + { + return null; + } + + /** + * {@inheritDoc} + */ + public function getComposerInformation($identifier) + { + if (!isset($this->infoCache[$identifier])) { + exec(sprintf('cd %s && hg cat --color never -r %s composer.json', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output); + $composer = implode("\n", $output); + unset($output); + + if (!$composer) { + throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl()); + } + + $composer = JsonFile::parseJson($composer); + + if (!isset($composer['time'])) { + exec(sprintf('cd %s && hg log --template "{date|rfc822date}" -r %s', escapeshellarg($this->tmpDir), escapeshellarg($identifier)), $output); + $date = new \DateTime($output[0]); + $composer['time'] = $date->format('Y-m-d H:i:s'); + } + $this->infoCache[$identifier] = $composer; + } + + return $this->infoCache[$identifier]; + } + + /** + * {@inheritDoc} + */ + public function getTags() + { + if (null === $this->tags) { + exec(sprintf('cd %s && hg tags --color never', escapeshellarg($this->tmpDir)), $output); + foreach ($output as $key => $tag) { + preg_match('(^([^\s]+)[\s]+[\d+]:(.*)$)', $tag, $match); + $tags[$match[1]] = $match[2]; + } + unset($tags['tip']); + $this->tags = $tags; + } + + return $this->tags; + } + + /** + * {@inheritDoc} + */ + public function getBranches() + { + if (null === $this->branches) { + $branches = array(); + + exec(sprintf('cd %s && hg branches --color never', escapeshellarg($this->tmpDir)), $output); + foreach ($output as $key => $branch) { + preg_match('(^([^\s]+)[\s]+[\d+]:(.*)$)', $branch, $match); + $branches[$match[1]] = $match[2]; + } + + $this->branches = $branches; + } + + return $this->branches; + } + + /** + * {@inheritDoc} + */ + public function hasComposerFile($identifier) + { + try { + $this->getComposerInformation($identifier); + return true; + } catch (\Exception $e) { + } + + return false; + } + + /** + * {@inheritDoc} + */ + public static function supports($url, $deep = false) + { + if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) { + return true; + } + + if (!$deep) { + return false; + } + + exec(sprintf('hg identify %s', escapeshellarg($url)), $output); + + return (boolean) $output; + } +} diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index ff17e5342..d5c741532 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -32,7 +32,7 @@ class VcsRepository extends ArrayRepository $drivers = array( 'Composer\Repository\Vcs\GitHubDriver', 'Composer\Repository\Vcs\GitDriver', - 'Composer\Repository\Vcs\SvnDriver', + 'Composer\Repository\Vcs\HgDriver', ); foreach ($drivers as $driver) { From 3e5fd85768083473bdff475ce3630c03f7783f2e Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Thu, 10 Nov 2011 13:10:05 +0100 Subject: [PATCH 3/9] Fixed CS and unused variables --- src/Composer/Downloader/HgDownloader.php | 5 +-- src/Composer/Repository/Vcs/HgDriver.php | 42 ++++++++++++------------ 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index df0d6ae05..88264eb04 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -19,6 +19,7 @@ use Composer\Package\PackageInterface; */ class HgDownloader implements DownloaderInterface { + /** * {@inheritDoc} */ @@ -50,8 +51,8 @@ class HgDownloader implements DownloaderInterface throw new \InvalidArgumentException('The given package is missing reference information'); } - $this->enforceCleanDirectory($path); - system(sprintf('cd %s && hg pull && hg up %s', $path, $target->getSourceReference())); + $this->enforceCleanDirectory($path); + system(sprintf('cd %s && hg pull && hg up %s', $path, $target->getSourceReference())); } /** diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index 6e58a3dda..cf74621c6 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -26,7 +26,7 @@ class HgDriver implements VcsDriverInterface protected $infoCache = array(); public function __construct($url) - { + { $this->url = $url; $this->tmpDir = sys_get_temp_dir() . '/composer-' . preg_replace('{[^a-z0-9]}i', '-', $url) . '/'; } @@ -53,11 +53,11 @@ class HgDriver implements VcsDriverInterface */ public function getRootIdentifier() { - $tmpDir = escapeshellarg($this->tmpDir); - if (null === $this->rootIdentifier) { - exec(sprintf('cd %s && hg tip --template "{rev}:{node|short}" --color never', $tmpDir), $output); - $this->rootIdentifier = $output[0]; - } + $tmpDir = escapeshellarg($this->tmpDir); + if (null === $this->rootIdentifier) { + exec(sprintf('cd %s && hg tip --template "{rev}:{node|short}" --color never', $tmpDir), $output); + $this->rootIdentifier = $output[0]; + } return $this->rootIdentifier; } @@ -74,7 +74,7 @@ class HgDriver implements VcsDriverInterface */ public function getSource($identifier) { - $label = array_search($identifier, (array) $this->tags) ?: $identifier; + $label = array_search($identifier, (array)$this->tags) ? : $identifier; return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $label); } @@ -98,7 +98,7 @@ class HgDriver implements VcsDriverInterface unset($output); if (!$composer) { - throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl()); + throw new \UnexpectedValueException('Failed to retrieve composer information for identifier ' . $identifier . ' in ' . $this->getUrl()); } $composer = JsonFile::parseJson($composer); @@ -111,7 +111,7 @@ class HgDriver implements VcsDriverInterface $this->infoCache[$identifier] = $composer; } - return $this->infoCache[$identifier]; + return $this->infoCache[$identifier]; } /** @@ -121,12 +121,12 @@ class HgDriver implements VcsDriverInterface { if (null === $this->tags) { exec(sprintf('cd %s && hg tags --color never', escapeshellarg($this->tmpDir)), $output); - foreach ($output as $key => $tag) { - preg_match('(^([^\s]+)[\s]+[\d+]:(.*)$)', $tag, $match); - $tags[$match[1]] = $match[2]; - } + foreach ($output as $tag) { + preg_match('(^([^\s]+)[\s]+[\d+]:(.*)$)', $tag, $match); + $tags[$match[1]] = $match[2]; + } unset($tags['tip']); - $this->tags = $tags; + $this->tags = $tags; } return $this->tags; @@ -141,9 +141,9 @@ class HgDriver implements VcsDriverInterface $branches = array(); exec(sprintf('cd %s && hg branches --color never', escapeshellarg($this->tmpDir)), $output); - foreach ($output as $key => $branch) { - preg_match('(^([^\s]+)[\s]+[\d+]:(.*)$)', $branch, $match); - $branches[$match[1]] = $match[2]; + foreach ($output as $branch) { + preg_match('(^([^\s]+)[\s]+[\d+]:(.*)$)', $branch, $match); + $branches[$match[1]] = $match[2]; } $this->branches = $branches; @@ -171,16 +171,16 @@ class HgDriver implements VcsDriverInterface */ public static function supports($url, $deep = false) { - if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) { + if (preg_match('#(^(?:https?|ssh)://(?:[^@]@)?bitbucket.org|https://(?:.*?)\.kilnhg.com)#i', $url)) { return true; } if (!$deep) { return false; } - - exec(sprintf('hg identify %s', escapeshellarg($url)), $output); - return (boolean) $output; + exec(sprintf('hg identify %s', escapeshellarg($url)), $output); + + return (boolean)$output; } } From b0d2897af3406b6711aa1fc71241f8895c409203 Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Thu, 10 Nov 2011 13:12:19 +0100 Subject: [PATCH 4/9] Fixed unused variables. --- src/Composer/Repository/Vcs/GitDriver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Composer/Repository/Vcs/GitDriver.php b/src/Composer/Repository/Vcs/GitDriver.php index 69f24abdb..68a5285e0 100644 --- a/src/Composer/Repository/Vcs/GitDriver.php +++ b/src/Composer/Repository/Vcs/GitDriver.php @@ -46,7 +46,7 @@ class GitDriver implements VcsDriverInterface if (null === $this->rootIdentifier) { $this->rootIdentifier = 'master'; exec(sprintf('cd %s && git branch --no-color -r', escapeshellarg($this->tmpDir)), $output); - foreach ($output as $key => $branch) { + foreach ($output as $branch) { if ($branch && preg_match('{/HEAD +-> +[^/]+/(\S+)}', $branch, $match)) { $this->rootIdentifier = $match[1]; break; @@ -132,7 +132,7 @@ class GitDriver implements VcsDriverInterface $branches = array(); exec(sprintf('cd %s && git branch --no-color -rv', escapeshellarg($this->tmpDir)), $output); - foreach ($output as $key => $branch) { + foreach ($output as $branch) { if ($branch && !preg_match('{^ *[^/]+/HEAD }', $branch)) { preg_match('{^ *[^/]+/(\S+) *([a-f0-9]+) .*$}', $branch, $match); $branches[$match[1]] = $match[2]; From 38198a5f3635961b6019b3f7e6da8ac5a6523ec2 Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Thu, 10 Nov 2011 13:39:51 +0100 Subject: [PATCH 5/9] Fixed blank lines. --- src/Composer/Downloader/HgDownloader.php | 1 - src/Composer/Repository/Vcs/HgDriver.php | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index 88264eb04..a7dc3b03d 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -19,7 +19,6 @@ use Composer\Package\PackageInterface; */ class HgDownloader implements DownloaderInterface { - /** * {@inheritDoc} */ diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index cf74621c6..29af3199b 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -58,6 +58,7 @@ class HgDriver implements VcsDriverInterface exec(sprintf('cd %s && hg tip --template "{rev}:{node|short}" --color never', $tmpDir), $output); $this->rootIdentifier = $output[0]; } + return $this->rootIdentifier; } From ee508725c678950904ff047db355cbeda2ebc002 Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Sat, 12 Nov 2011 10:27:45 +0100 Subject: [PATCH 6/9] Simpler --- src/Composer/Downloader/HgDownloader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index a7dc3b03d..d5522954d 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -51,7 +51,7 @@ class HgDownloader implements DownloaderInterface } $this->enforceCleanDirectory($path); - system(sprintf('cd %s && hg pull && hg up %s', $path, $target->getSourceReference())); + system(sprintf('cd %s && hg pull -u %s', $path, $target->getSourceReference())); } /** From ad8e85ab3267b2a275439e53371dd752994d4004 Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Sat, 12 Nov 2011 12:05:27 +0100 Subject: [PATCH 7/9] Previous change was wrong... We want to update to a specific version, so hg pull -u won't work. --- src/Composer/Downloader/HgDownloader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index d5522954d..32d23b770 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -51,7 +51,7 @@ class HgDownloader implements DownloaderInterface } $this->enforceCleanDirectory($path); - system(sprintf('cd %s && hg pull -u %s', $path, $target->getSourceReference())); + system(sprintf('cd %s && hg pull && hg up %s', $path, escapeshellarg($target->getSourceReference()))); } /** From bf21dfeb31c4176af7fd7d47820f911b65bd5fba Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Sat, 12 Nov 2011 13:22:41 +0100 Subject: [PATCH 8/9] Added drivers for bitbucket (hg and git) --- .../Repository/Vcs/GitBitbucketDriver.php | 163 +++++++++++++++++ .../Repository/Vcs/HgBitbucketDriver.php | 164 ++++++++++++++++++ 2 files changed, 327 insertions(+) create mode 100644 src/Composer/Repository/Vcs/GitBitbucketDriver.php create mode 100644 src/Composer/Repository/Vcs/HgBitbucketDriver.php diff --git a/src/Composer/Repository/Vcs/GitBitbucketDriver.php b/src/Composer/Repository/Vcs/GitBitbucketDriver.php new file mode 100644 index 000000000..1ac4f85f3 --- /dev/null +++ b/src/Composer/Repository/Vcs/GitBitbucketDriver.php @@ -0,0 +1,163 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Repository\Vcs; + +use Composer\Json\JsonFile; + +/** + * @author Per Bernhardt + */ +class GitBitbucketDriver implements VcsDriverInterface +{ + protected $url; + protected $owner; + protected $repository; + protected $tags; + protected $branches; + protected $rootIdentifier; + protected $infoCache = array(); + + public function __construct($url) + { + $this->url = $url; + preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url, $match); + $this->owner = $match[1]; + $this->repository = $match[2]; + } + + /** + * {@inheritDoc} + */ + public function initialize() + { + } + + /** + * {@inheritDoc} + */ + public function getRootIdentifier() + { + if (null === $this->rootIdentifier) { + $repoData = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository), true); + $this->rootIdentifier = $repoData['main_branch'] ?: 'master'; + } + + return $this->rootIdentifier; + } + + /** + * {@inheritDoc} + */ + public function getUrl() + { + return $this->url; + } + + /** + * {@inheritDoc} + */ + public function getSource($identifier) + { + $label = array_search($identifier, $this->getTags()) ?: $identifier; + + return array('type' => 'git', 'url' => $this->getUrl(), 'reference' => $label); + } + + /** + * {@inheritDoc} + */ + public function getDist($identifier) + { + $label = array_search($identifier, $this->getTags()) ?: $identifier; + $url = 'https://bitbucket.org/'.$this->owner.'/'.$this->repository.'/get/'.$label.'.zip'; + + return array('type' => 'zip', 'url' => $url, 'reference' => $label, 'shasum' => ''); + } + + /** + * {@inheritDoc} + */ + public function getComposerInformation($identifier) + { + if (!isset($this->infoCache[$identifier])) { + $composer = @file_get_contents('https://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json'); + if (!$composer) { + throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl()); + } + + $composer = JsonFile::parseJson($composer); + + if (!isset($composer['time'])) { + $changeset = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true); + $composer['time'] = $changeset['timestamp']; + } + $this->infoCache[$identifier] = $composer; + } + + return $this->infoCache[$identifier]; + } + + /** + * {@inheritDoc} + */ + public function getTags() + { + if (null === $this->tags) { + $tagsData = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true); + $this->tags = array(); + foreach ($tagsData as $tag => $data) { + $this->tags[$tag] = $data['raw_node']; + } + } + + return $this->tags; + } + + /** + * {@inheritDoc} + */ + public function getBranches() + { + if (null === $this->branches) { + $branchData = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true); + $this->branches = array(); + foreach ($branchData as $branch => $data) { + $this->branches[$branch] = $data['raw_node']; + } + } + + return $this->branches; + } + + /** + * {@inheritDoc} + */ + public function hasComposerFile($identifier) + { + try { + $this->getComposerInformation($identifier); + return true; + } catch (\Exception $e) { + } + + return false; + } + + /** + * {@inheritDoc} + */ + public static function supports($url, $deep = false) + { + return preg_match('#^https://bitbucket\.org/([^/]+)/(.+?)\.git$#', $url, $match); + } +} diff --git a/src/Composer/Repository/Vcs/HgBitbucketDriver.php b/src/Composer/Repository/Vcs/HgBitbucketDriver.php new file mode 100644 index 000000000..9c1c82b3b --- /dev/null +++ b/src/Composer/Repository/Vcs/HgBitbucketDriver.php @@ -0,0 +1,164 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Repository\Vcs; + +use Composer\Json\JsonFile; + +/** + * @author Per Bernhardt + */ +class HgBitbucketDriver implements VcsDriverInterface +{ + protected $url; + protected $owner; + protected $repository; + protected $tags; + protected $branches; + protected $rootIdentifier; + protected $infoCache = array(); + + public function __construct($url) + { + $this->url = $url; + preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url, $match); + $this->owner = $match[1]; + $this->repository = $match[2]; + } + + /** + * {@inheritDoc} + */ + public function initialize() + { + } + + /** + * {@inheritDoc} + */ + public function getRootIdentifier() + { + if (null === $this->rootIdentifier) { + $repoData = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true); + $this->rootIdentifier = $repoData['tip']['raw_node']; + } + + return $this->rootIdentifier; + } + + /** + * {@inheritDoc} + */ + public function getUrl() + { + return $this->url; + } + + /** + * {@inheritDoc} + */ + public function getSource($identifier) + { + $label = array_search($identifier, $this->getTags()) ?: $identifier; + + return array('type' => 'hg', 'url' => $this->getUrl(), 'reference' => $label); + } + + /** + * {@inheritDoc} + */ + public function getDist($identifier) + { + $label = array_search($identifier, $this->getTags()) ?: $identifier; + $url = 'https://bitbucket.org/'.$this->owner.'/'.$this->repository.'/get/'.$label.'.zip'; + + return array('type' => 'zip', 'url' => $url, 'reference' => $label, 'shasum' => ''); + } + + /** + * {@inheritDoc} + */ + public function getComposerInformation($identifier) + { + if (!isset($this->infoCache[$identifier])) { + $composer = @file_get_contents('https://bitbucket.org/'.$this->owner.'/'.$this->repository.'/raw/'.$identifier.'/composer.json'); + if (!$composer) { + throw new \UnexpectedValueException('Failed to retrieve composer information for identifier '.$identifier.' in '.$this->getUrl()); + } + + $composer = JsonFile::parseJson($composer); + + if (!isset($composer['time'])) { + $changeset = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/changesets/'.$identifier), true); + $composer['time'] = $changeset['timestamp']; + } + $this->infoCache[$identifier] = $composer; + } + + return $this->infoCache[$identifier]; + } + + /** + * {@inheritDoc} + */ + public function getTags() + { + if (null === $this->tags) { + $tagsData = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/tags'), true); + $this->tags = array(); + foreach ($tagsData as $tag => $data) { + $this->tags[$tag] = $data['raw_node']; + } + unset($this->tags['tip']); + } + + return $this->tags; + } + + /** + * {@inheritDoc} + */ + public function getBranches() + { + if (null === $this->branches) { + $branchData = json_decode(file_get_contents('https://api.bitbucket.org/1.0/repositories/'.$this->owner.'/'.$this->repository.'/branches'), true); + $this->branches = array(); + foreach ($branchData as $branch => $data) { + $this->branches[$branch] = $data['raw_node']; + } + } + + return $this->branches; + } + + /** + * {@inheritDoc} + */ + public function hasComposerFile($identifier) + { + try { + $this->getComposerInformation($identifier); + return true; + } catch (\Exception $e) { + } + + return false; + } + + /** + * {@inheritDoc} + */ + public static function supports($url, $deep = false) + { + return preg_match('#^https://bitbucket\.org/([^/]+)/([^/]+)/?$#', $url, $match); + } +} From b969309440b9ea72d62ec1aba987b850fd45a1df Mon Sep 17 00:00:00 2001 From: Per Bernhardt Date: Sat, 12 Nov 2011 13:23:47 +0100 Subject: [PATCH 9/9] Register new drivers... --- src/Composer/Repository/VcsRepository.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index d5c741532..20ed87805 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -31,7 +31,9 @@ class VcsRepository extends ArrayRepository $drivers = array( 'Composer\Repository\Vcs\GitHubDriver', + 'Composer\Repository\Vcs\GitBitbucketDriver', 'Composer\Repository\Vcs\GitDriver', + 'Composer\Repository\Vcs\HgBitbucketDriver', 'Composer\Repository\Vcs\HgDriver', );