From ebdf972e49c3596447b8b724df7f33bd60b1be6f Mon Sep 17 00:00:00 2001 From: Jakub Zalas Date: Thu, 26 Jul 2018 16:51:50 +0100 Subject: [PATCH] [Intl] Replace svn with git in the icu data update script --- .../Component/Intl/Resources/bin/icu.ini | 20 --- .../Intl/Resources/bin/update-data.php | 67 ++++----- .../Intl/Resources/data/git-info.txt | 7 + .../Intl/Resources/data/svn-info.txt | 7 - .../Intl/Tests/Util/GitRepositoryTest.php | 73 +++++++++ .../Component/Intl/Util/GitRepository.php | 117 +++++++++++++++ src/Symfony/Component/Intl/Util/SvnCommit.php | 62 -------- .../Component/Intl/Util/SvnRepository.php | 140 ------------------ 8 files changed, 227 insertions(+), 266 deletions(-) delete mode 100644 src/Symfony/Component/Intl/Resources/bin/icu.ini create mode 100644 src/Symfony/Component/Intl/Resources/data/git-info.txt delete mode 100644 src/Symfony/Component/Intl/Resources/data/svn-info.txt create mode 100644 src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php create mode 100644 src/Symfony/Component/Intl/Util/GitRepository.php delete mode 100644 src/Symfony/Component/Intl/Util/SvnCommit.php delete mode 100644 src/Symfony/Component/Intl/Util/SvnRepository.php diff --git a/src/Symfony/Component/Intl/Resources/bin/icu.ini b/src/Symfony/Component/Intl/Resources/bin/icu.ini deleted file mode 100644 index 9845e0bb1a..0000000000 --- a/src/Symfony/Component/Intl/Resources/bin/icu.ini +++ /dev/null @@ -1,20 +0,0 @@ -; ICU data source URLs -; We use always the latest release of a major version. -4.0 = http://source.icu-project.org/repos/icu/icu/tags/release-4-0-1/source -4.2 = http://source.icu-project.org/repos/icu/icu/tags/release-4-2-1/source -4.4 = http://source.icu-project.org/repos/icu/icu/tags/release-4-4-2/source -4.6 = http://source.icu-project.org/repos/icu/icu/tags/release-4-6-1/source -4.8 = http://source.icu-project.org/repos/icu/icu/tags/release-4-8-1-1/source -49 = http://source.icu-project.org/repos/icu/icu/tags/release-49-1-2/source -50 = http://source.icu-project.org/repos/icu/icu/tags/release-50-1-2/source -51 = http://source.icu-project.org/repos/icu/icu/tags/release-51-2/source -52 = http://source.icu-project.org/repos/icu/icu/tags/release-52-1/source -53 = http://source.icu-project.org/repos/icu/icu/tags/release-53-1/source -54 = http://source.icu-project.org/repos/icu/icu/tags/release-54-1/source -55 = http://source.icu-project.org/repos/icu/icu/tags/release-55-1/source -57 = http://source.icu-project.org/repos/icu/icu/tags/release-57-1/source -58 = http://source.icu-project.org/repos/icu/tags/release-58-2/icu4c/source -59 = http://source.icu-project.org/repos/icu/tags/release-59-1/icu4c/source -60 = http://source.icu-project.org/repos/icu/tags/release-60-2/icu4c/source -61 = http://source.icu-project.org/repos/icu/tags/release-61-1/icu4c/source -62 = http://source.icu-project.org/repos/icu/tags/release-62-1/icu4c/source diff --git a/src/Symfony/Component/Intl/Resources/bin/update-data.php b/src/Symfony/Component/Intl/Resources/bin/update-data.php index 80a34fe152..7238f46880 100644 --- a/src/Symfony/Component/Intl/Resources/bin/update-data.php +++ b/src/Symfony/Component/Intl/Resources/bin/update-data.php @@ -25,8 +25,7 @@ use Symfony\Component\Intl\Data\Provider\RegionDataProvider; use Symfony\Component\Intl\Data\Provider\ScriptDataProvider; use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Locale; -use Symfony\Component\Intl\Util\IcuVersion; -use Symfony\Component\Intl\Util\SvnRepository; +use Symfony\Component\Intl\Util\GitRepository; require_once __DIR__.'/common.php'; require_once __DIR__.'/autoload.php'; @@ -40,7 +39,7 @@ Usage: php update-data.php Updates the ICU data for Symfony to the latest version of ICU. -If you downloaded the SVN repository before, you can pass the path to the +If you downloaded the git repository before, you can pass the path to the repository source in the first optional argument. If you also built the repository before, you can pass the directory where that @@ -64,37 +63,31 @@ if (!Intl::isExtensionLoaded()) { bailout('The intl extension for PHP is not installed.'); } -$filesystem = new Filesystem(); -$urls = parse_ini_file(__DIR__.'/icu.ini'); - -echo "icu.ini parsed. Available versions:\n"; - -$maxVersion = 0; - -foreach ($urls as $urlVersion => $url) { - $maxVersion = IcuVersion::compare($maxVersion, $urlVersion, '<') - ? $urlVersion - : $maxVersion; - - echo " $urlVersion\n"; -} - -$shortIcuVersion = strip_minor_versions($maxVersion); - if ($argc >= 2) { - $sourceDir = $argv[1]; - $svn = new SvnRepository($sourceDir); + $repoDir = $argv[1]; + $git = new GitRepository($repoDir); - echo "Using existing SVN repository at {$sourceDir}.\n"; + echo "Using the existing git repository at {$repoDir}.\n"; } else { - echo "Starting SVN checkout for version $shortIcuVersion. This may take a while...\n"; + echo "Starting git clone. This may take a while...\n"; - $sourceDir = sys_get_temp_dir().'/icu-data/'.$shortIcuVersion.'/source'; - $svn = SvnRepository::download($urls[$shortIcuVersion], $sourceDir); + $repoDir = sys_get_temp_dir().'/icu-data'; + $git = GitRepository::download('https://github.com/unicode-org/icu.git', $repoDir); - echo "SVN checkout to {$sourceDir} complete.\n"; + echo "Git clone to {$repoDir} complete.\n"; } +$gitTag = $git->getLastTag(function ($tag) { + return preg_match('#^release-[0-9]{1,}-[0-9]{1}$#', $tag); +}); +$shortIcuVersion = strip_minor_versions(preg_replace('#release-([0-9]{1,})-([0-9]{1,})#', '$1.$2', $gitTag)); + +echo "Checking out `{$gitTag}` for version `{$shortIcuVersion}`...\n"; +$git->checkout('tags/'.$gitTag); + +$filesystem = new Filesystem(); +$sourceDir = $repoDir.'/icu4c/source'; + if ($argc >= 3) { $buildDir = $argv[2]; } else { @@ -265,23 +258,23 @@ $generator->generateData($config); echo "Resource bundle compilation complete.\n"; -$svnInfo = <<getUrl()} -Revision: {$svn->getLastCommit()->getRevision()} -Author: {$svn->getLastCommit()->getAuthor()} -Date: {$svn->getLastCommit()->getDate()} +URL: {$git->getUrl()} +Revision: {$git->getLastCommitHash()} +Author: {$git->getLastAuthor()} +Date: {$git->getLastAuthoredDate()->format('c')} -SVN_INFO; +GIT_INFO; foreach ($targetDirs as $targetDir) { - $svnInfoFile = $targetDir.'/svn-info.txt'; + $gitInfoFile = $targetDir.'/git-info.txt'; - file_put_contents($svnInfoFile, $svnInfo); + file_put_contents($gitInfoFile, $gitInfo); - echo "Wrote $svnInfoFile.\n"; + echo "Wrote $gitInfoFile.\n"; $versionFile = $targetDir.'/version.txt'; diff --git a/src/Symfony/Component/Intl/Resources/data/git-info.txt b/src/Symfony/Component/Intl/Resources/data/git-info.txt new file mode 100644 index 0000000000..fe7ce33232 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/git-info.txt @@ -0,0 +1,7 @@ +Git information +=============== + +URL: https://github.com/unicode-org/icu.git +Revision: 4a3ba8eee90ea1414d4f7ee36563e6c9b28fda96 +Author: Yoshito Umaoka +Date: 2018-06-20T05:34:56+00:00 diff --git a/src/Symfony/Component/Intl/Resources/data/svn-info.txt b/src/Symfony/Component/Intl/Resources/data/svn-info.txt deleted file mode 100644 index 556c6cf358..0000000000 --- a/src/Symfony/Component/Intl/Resources/data/svn-info.txt +++ /dev/null @@ -1,7 +0,0 @@ -SVN information -=============== - -URL: http://source.icu-project.org/repos/icu/tags/release-62-1/icu4c/source -Revision: 41542 -Author: yoshito -Date: 2018-06-20T05:34:56.496986Z diff --git a/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php b/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php new file mode 100644 index 0000000000..a9eb531907 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Tests\Util; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Intl\Util\GitRepository; + +/** + * @group intl-data + */ +class GitRepositoryTest extends TestCase +{ + private $targetDir; + + const REPO_URL = 'https://github.com/symfony/intl.git'; + + /** + * @before + * @after + */ + protected function cleanup() + { + $this->targetDir = sys_get_temp_dir().'/GitRepositoryTest/source'; + + $fs = new Filesystem(); + $fs->remove($this->targetDir); + } + + public function testItThrowsAnExceptionIfInitialisedWithNonGitDirectory() + { + $this->expectException('Symfony\Component\Intl\Exception\RuntimeException'); + + @mkdir($this->targetDir, '0777', true); + + new GitRepository($this->targetDir); + } + + public function testItClonesTheRepository() + { + $git = GitRepository::download(self::REPO_URL, $this->targetDir); + + $this->assertInstanceOf('Symfony\Component\Intl\Util\GitRepository', $git); + $this->assertDirectoryExists($this->targetDir.'/.git'); + $this->assertSame($this->targetDir, $git->getPath()); + $this->assertSame(self::REPO_URL, $git->getUrl()); + $this->assertRegExp('#^[0-9a-z]{40}$#', $git->getLastCommitHash()); + $this->assertNotEmpty($git->getLastAuthor()); + $this->assertInstanceOf('DateTime', $git->getLastAuthoredDate()); + $this->assertStringMatchesFormat('v%s', $git->getLastTag()); + $this->assertStringMatchesFormat('v3%s', $git->getLastTag(function ($tag) { return 0 === strpos($tag, 'v3'); })); + } + + public function testItCheckoutsToTheLastTag() + { + $git = GitRepository::download(self::REPO_URL, $this->targetDir); + $lastCommitHash = $git->getLastCommitHash(); + $lastV3Tag = $git->getLastTag(function ($tag) { return 0 === strpos($tag, 'v3'); }); + + $git->checkout($lastV3Tag); + + $this->assertNotEquals($lastCommitHash, $git->getLastCommitHash()); + } +} diff --git a/src/Symfony/Component/Intl/Util/GitRepository.php b/src/Symfony/Component/Intl/Util/GitRepository.php new file mode 100644 index 0000000000..35020c6706 --- /dev/null +++ b/src/Symfony/Component/Intl/Util/GitRepository.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Intl\Util; + +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Intl\Exception\RuntimeException; + +/** + * @internal + */ +final class GitRepository +{ + private $path; + + /** + * @param string $path + */ + public function __construct($path) + { + $this->path = $path; + + $this->getUrl(); + } + + /** + * @param string $remote + * @param string $targetDir + * + * @return GitRepository + */ + public static function download($remote, $targetDir) + { + self::exec('which git', 'The command "git" is not installed.'); + + $filesystem = new Filesystem(); + + if (!$filesystem->exists($targetDir.'/.git')) { + $filesystem->remove($targetDir); + $filesystem->mkdir($targetDir); + + self::exec(sprintf('git clone %s %s', escapeshellarg($remote), escapeshellarg($targetDir))); + } + + return new self(realpath($targetDir)); + } + + public function getPath() + { + return $this->path; + } + + public function getUrl() + { + return $this->getLastLine($this->execInPath('git config --get remote.origin.url')); + } + + public function getLastCommitHash() + { + return $this->getLastLine($this->execInPath('git log -1 --format="%H"')); + } + + public function getLastAuthor() + { + return $this->getLastLine($this->execInPath('git log -1 --format="%an"')); + } + + public function getLastAuthoredDate() + { + return new \DateTime($this->getLastLine($this->execInPath('git log -1 --format="%ai"'))); + } + + public function getLastTag(callable $filter = null) + { + $tags = $this->execInPath('git tag -l --sort=v:refname'); + + if (null !== $filter) { + $tags = array_filter($tags, $filter); + } + + return $this->getLastLine($tags); + } + + public function checkout($branch) + { + $this->execInPath(sprintf('git checkout %s', escapeshellarg($branch))); + } + + private function execInPath($command) + { + return self::exec(sprintf('cd %s && %s', escapeshellarg($this->path), $command)); + } + + private static function exec($command, $customErrorMessage = null) + { + exec(sprintf('%s 2>&1', $command), $output, $result); + + if (0 !== $result) { + throw new RuntimeException(null !== $customErrorMessage ? $customErrorMessage : sprintf('The `%s` command failed.', $command)); + } + + return $output; + } + + private function getLastLine(array $output) + { + return array_pop($output); + } +} diff --git a/src/Symfony/Component/Intl/Util/SvnCommit.php b/src/Symfony/Component/Intl/Util/SvnCommit.php deleted file mode 100644 index f83958fe38..0000000000 --- a/src/Symfony/Component/Intl/Util/SvnCommit.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Intl\Util; - -/** - * An SVN commit. - * - * @author Bernhard Schussek - */ -class SvnCommit -{ - private $svnInfo; - - /** - * Creates a commit from the given "svn info" data. - * - * @param \SimpleXMLElement $svnInfo the XML result from the "svn info" command - */ - public function __construct(\SimpleXMLElement $svnInfo) - { - $this->svnInfo = $svnInfo; - } - - /** - * Returns the revision of the commit. - * - * @return string The revision of the commit - */ - public function getRevision() - { - return (string) $this->svnInfo['revision']; - } - - /** - * Returns the author of the commit. - * - * @return string The author name - */ - public function getAuthor() - { - return (string) $this->svnInfo->author; - } - - /** - * Returns the date of the commit. - * - * @return string The commit date - */ - public function getDate() - { - return (string) $this->svnInfo->date; - } -} diff --git a/src/Symfony/Component/Intl/Util/SvnRepository.php b/src/Symfony/Component/Intl/Util/SvnRepository.php deleted file mode 100644 index 9716a5425e..0000000000 --- a/src/Symfony/Component/Intl/Util/SvnRepository.php +++ /dev/null @@ -1,140 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Intl\Util; - -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Intl\Exception\RuntimeException; - -/** - * A SVN repository containing ICU data. - * - * @author Bernhard Schussek - */ -class SvnRepository -{ - /** - * @var string The path to the repository - */ - private $path; - - /** - * @var \SimpleXMLElement - */ - private $svnInfo; - - /** - * @var SvnCommit - */ - private $lastCommit; - - /** - * Downloads the ICU data for the given version. - * - * @param string $url The URL to download from - * @param string $targetDir The directory in which to store the repository - * - * @return static - * - * @throws RuntimeException if an error occurs during the download - */ - public static function download($url, $targetDir) - { - exec('which svn', $output, $result); - - if (0 !== $result) { - throw new RuntimeException('The command "svn" is not installed.'); - } - - $filesystem = new Filesystem(); - - if (!$filesystem->exists($targetDir.'/.svn')) { - $filesystem->remove($targetDir); - $filesystem->mkdir($targetDir); - - exec('svn checkout '.$url.' '.$targetDir, $output, $result); - - if (0 !== $result) { - throw new RuntimeException('The SVN checkout of '.$url.'failed.'); - } - } - - return new static(realpath($targetDir)); - } - - /** - * Reads the SVN repository at the given path. - * - * @param string $path The path to the repository - */ - public function __construct($path) - { - $this->path = $path; - } - - /** - * Returns the path to the repository. - * - * @return string The path to the repository - */ - public function getPath() - { - return $this->path; - } - - /** - * Returns the URL of the repository. - * - * @return string The URL of the repository - */ - public function getUrl() - { - return (string) $this->getSvnInfo()->entry->url; - } - - /** - * Returns the last commit of the repository. - * - * @return SvnCommit The last commit - */ - public function getLastCommit() - { - if (null === $this->lastCommit) { - $this->lastCommit = new SvnCommit($this->getSvnInfo()->entry->commit); - } - - return $this->lastCommit; - } - - /** - * Returns information about the SVN repository. - * - * @return \SimpleXMLElement The XML result from the "svn info" command - * - * @throws RuntimeException if the "svn info" command failed - */ - private function getSvnInfo() - { - if (null === $this->svnInfo) { - exec('svn info --xml '.$this->path, $output, $result); - - $svnInfo = simplexml_load_string(implode("\n", $output)); - - if (0 !== $result) { - throw new RuntimeException('svn info failed'); - } - - $this->svnInfo = $svnInfo; - } - - return $this->svnInfo; - } -}