Merge branch '3.4' into 4.0
* 3.4: [HttpKernel] Fixed invalid REMOTE_ADDR in inline subrequest when configuring trusted proxy with subnet [FrameworkBundle] fixed guard event names for transitions [DI] Improve class named servics error message [HttpFoundation] fixed using _method parameter with invalid type [Intl] Replace svn with git in the icu data update script [HttpFoundation] Fix Cookie::isCleared
This commit is contained in:
commit
e0ce427aef
@ -525,7 +525,9 @@ class FrameworkExtension extends Extension
|
|||||||
$guard = new Definition(Workflow\EventListener\GuardListener::class);
|
$guard = new Definition(Workflow\EventListener\GuardListener::class);
|
||||||
$guard->setPrivate(true);
|
$guard->setPrivate(true);
|
||||||
$configuration = array();
|
$configuration = array();
|
||||||
foreach ($workflow['transitions'] as $transitionName => $config) {
|
foreach ($workflow['transitions'] as $config) {
|
||||||
|
$transitionName = $config['name'];
|
||||||
|
|
||||||
if (!isset($config['guard'])) {
|
if (!isset($config['guard'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,15 @@ class CheckDefinitionValidityPass implements CompilerPassInterface
|
|||||||
throw new RuntimeException(sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id));
|
throw new RuntimeException(sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id));
|
||||||
}
|
}
|
||||||
if (class_exists($id) || interface_exists($id, false)) {
|
if (class_exists($id) || interface_exists($id, false)) {
|
||||||
|
if (0 === strpos($id, '\\') && 1 < substr_count($id, '\\')) {
|
||||||
|
throw new RuntimeException(sprintf(
|
||||||
|
'The definition for "%s" has no class attribute, and appears to reference a class or interface. '
|
||||||
|
.'Please specify the class attribute explicitly or remove the leading backslash by renaming '
|
||||||
|
.'the service to "%s" to get rid of this error.',
|
||||||
|
$id, substr($id, 1)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
throw new RuntimeException(sprintf(
|
throw new RuntimeException(sprintf(
|
||||||
'The definition for "%s" has no class attribute, and appears to reference a '
|
'The definition for "%s" has no class attribute, and appears to reference a '
|
||||||
.'class or interface in the global namespace. Leaving out the "class" attribute '
|
.'class or interface in the global namespace. Leaving out the "class" attribute '
|
||||||
|
@ -1238,6 +1238,30 @@ class ContainerBuilderTest extends TestCase
|
|||||||
$container->compile();
|
$container->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||||
|
* @expectedExceptionMessage The definition for "\DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.
|
||||||
|
*/
|
||||||
|
public function testNoClassFromGlobalNamespaceClassIdWithLeadingSlash()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('\\'.\DateTime::class);
|
||||||
|
$container->compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||||
|
* @expectedExceptionMessage The definition for "\Symfony\Component\DependencyInjection\Tests\FooClass" has no class attribute, and appears to reference a class or interface. Please specify the class attribute explicitly or remove the leading backslash by renaming the service to "Symfony\Component\DependencyInjection\Tests\FooClass" to get rid of this error.
|
||||||
|
*/
|
||||||
|
public function testNoClassFromNamespaceClassIdWithLeadingSlash()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$container->register('\\'.FooClass::class);
|
||||||
|
$container->compile();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
|
||||||
* @expectedExceptionMessage The definition for "123_abc" has no class.
|
* @expectedExceptionMessage The definition for "123_abc" has no class.
|
||||||
|
@ -266,7 +266,7 @@ class Cookie
|
|||||||
*/
|
*/
|
||||||
public function isCleared()
|
public function isCleared()
|
||||||
{
|
{
|
||||||
return $this->expire < time();
|
return 0 !== $this->expire && $this->expire < time();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1221,7 +1221,10 @@ class Request
|
|||||||
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
|
if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
|
||||||
$this->method = strtoupper($method);
|
$this->method = strtoupper($method);
|
||||||
} elseif (self::$httpMethodParameterOverride) {
|
} elseif (self::$httpMethodParameterOverride) {
|
||||||
$this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
|
$method = $this->request->get('_method', $this->query->get('_method', 'POST'));
|
||||||
|
if (\is_string($method)) {
|
||||||
|
$this->method = strtoupper($method);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,18 @@ class CookieTest extends TestCase
|
|||||||
$cookie = new Cookie('foo', 'bar', time() - 20);
|
$cookie = new Cookie('foo', 'bar', time() - 20);
|
||||||
|
|
||||||
$this->assertTrue($cookie->isCleared(), '->isCleared() returns true if the cookie has expired');
|
$this->assertTrue($cookie->isCleared(), '->isCleared() returns true if the cookie has expired');
|
||||||
|
|
||||||
|
$cookie = new Cookie('foo', 'bar');
|
||||||
|
|
||||||
|
$this->assertFalse($cookie->isCleared());
|
||||||
|
|
||||||
|
$cookie = new Cookie('foo', 'bar', 0);
|
||||||
|
|
||||||
|
$this->assertFalse($cookie->isCleared());
|
||||||
|
|
||||||
|
$cookie = new Cookie('foo', 'bar', -1);
|
||||||
|
|
||||||
|
$this->assertFalse($cookie->isCleared());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testToString()
|
public function testToString()
|
||||||
|
@ -848,6 +848,11 @@ class RequestTest extends TestCase
|
|||||||
$request->setMethod('POST');
|
$request->setMethod('POST');
|
||||||
$request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
|
$request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete');
|
||||||
$this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override if defined and POST');
|
$this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override if defined and POST');
|
||||||
|
|
||||||
|
$request = new Request();
|
||||||
|
$request->setMethod('POST');
|
||||||
|
$request->query->set('_method', array('delete', 'patch'));
|
||||||
|
$this->assertSame('POST', $request->getMethod(), '->getMethod() returns the request method if invalid type is defined in query');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,8 +115,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
$server['HTTP_X_FORWARDED_FOR'] = ($currentXForwardedFor ? $currentXForwardedFor.', ' : '').$request->getClientIp();
|
$server['HTTP_X_FORWARDED_FOR'] = ($currentXForwardedFor ? $currentXForwardedFor.', ' : '').$request->getClientIp();
|
||||||
}
|
}
|
||||||
|
|
||||||
$trustedProxies = Request::getTrustedProxies();
|
$server['REMOTE_ADDR'] = $this->resolveTrustedProxy();
|
||||||
$server['REMOTE_ADDR'] = $trustedProxies ? reset($trustedProxies) : '127.0.0.1';
|
|
||||||
|
|
||||||
unset($server['HTTP_IF_MODIFIED_SINCE']);
|
unset($server['HTTP_IF_MODIFIED_SINCE']);
|
||||||
unset($server['HTTP_IF_NONE_MATCH']);
|
unset($server['HTTP_IF_NONE_MATCH']);
|
||||||
@ -133,6 +132,17 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer
|
|||||||
return $subRequest;
|
return $subRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function resolveTrustedProxy()
|
||||||
|
{
|
||||||
|
if (!$trustedProxies = Request::getTrustedProxies()) {
|
||||||
|
return '127.0.0.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$firstTrustedProxy = reset($trustedProxies);
|
||||||
|
|
||||||
|
return false !== ($i = strpos($firstTrustedProxy, '/')) ? substr($firstTrustedProxy, 0, $i) : $firstTrustedProxy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@ -195,6 +195,25 @@ class InlineFragmentRendererTest extends TestCase
|
|||||||
Request::setTrustedProxies(array(), -1);
|
Request::setTrustedProxies(array(), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testIpAddressOfRangedTrustedProxyIsSetAsRemote()
|
||||||
|
{
|
||||||
|
$expectedSubRequest = Request::create('/');
|
||||||
|
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
||||||
|
$expectedSubRequest->server->set('REMOTE_ADDR', '1.1.1.1');
|
||||||
|
$expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1'));
|
||||||
|
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
|
||||||
|
|
||||||
|
Request::setTrustedProxies(array('1.1.1.1/24'), -1);
|
||||||
|
|
||||||
|
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
|
||||||
|
|
||||||
|
$request = Request::create('/');
|
||||||
|
$request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
|
||||||
|
$strategy->render('/', $request);
|
||||||
|
|
||||||
|
Request::setTrustedProxies(array(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Kernel expecting a request equals to $request
|
* Creates a Kernel expecting a request equals to $request
|
||||||
* Allows delta in comparison in case REQUEST_TIME changed by 1 second.
|
* Allows delta in comparison in case REQUEST_TIME changed by 1 second.
|
||||||
|
@ -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
|
|
@ -25,8 +25,7 @@ use Symfony\Component\Intl\Data\Provider\RegionDataProvider;
|
|||||||
use Symfony\Component\Intl\Data\Provider\ScriptDataProvider;
|
use Symfony\Component\Intl\Data\Provider\ScriptDataProvider;
|
||||||
use Symfony\Component\Intl\Intl;
|
use Symfony\Component\Intl\Intl;
|
||||||
use Symfony\Component\Intl\Locale;
|
use Symfony\Component\Intl\Locale;
|
||||||
use Symfony\Component\Intl\Util\IcuVersion;
|
use Symfony\Component\Intl\Util\GitRepository;
|
||||||
use Symfony\Component\Intl\Util\SvnRepository;
|
|
||||||
|
|
||||||
require_once __DIR__.'/common.php';
|
require_once __DIR__.'/common.php';
|
||||||
require_once __DIR__.'/autoload.php';
|
require_once __DIR__.'/autoload.php';
|
||||||
@ -40,7 +39,7 @@ Usage: php update-data.php <path/to/icu/source> <path/to/icu/build>
|
|||||||
|
|
||||||
Updates the ICU data for Symfony to the latest version of ICU.
|
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.
|
repository source in the first optional argument.
|
||||||
|
|
||||||
If you also built the repository before, you can pass the directory where that
|
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.');
|
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) {
|
if ($argc >= 2) {
|
||||||
$sourceDir = $argv[1];
|
$repoDir = $argv[1];
|
||||||
$svn = new SvnRepository($sourceDir);
|
$git = new GitRepository($repoDir);
|
||||||
|
|
||||||
echo "Using existing SVN repository at {$sourceDir}.\n";
|
echo "Using the existing git repository at {$repoDir}.\n";
|
||||||
} else {
|
} 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';
|
$repoDir = sys_get_temp_dir().'/icu-data';
|
||||||
$svn = SvnRepository::download($urls[$shortIcuVersion], $sourceDir);
|
$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) {
|
if ($argc >= 3) {
|
||||||
$buildDir = $argv[2];
|
$buildDir = $argv[2];
|
||||||
} else {
|
} else {
|
||||||
@ -265,23 +258,23 @@ $generator->generateData($config);
|
|||||||
|
|
||||||
echo "Resource bundle compilation complete.\n";
|
echo "Resource bundle compilation complete.\n";
|
||||||
|
|
||||||
$svnInfo = <<<SVN_INFO
|
$gitInfo = <<<GIT_INFO
|
||||||
SVN information
|
Git information
|
||||||
===============
|
===============
|
||||||
|
|
||||||
URL: {$svn->getUrl()}
|
URL: {$git->getUrl()}
|
||||||
Revision: {$svn->getLastCommit()->getRevision()}
|
Revision: {$git->getLastCommitHash()}
|
||||||
Author: {$svn->getLastCommit()->getAuthor()}
|
Author: {$git->getLastAuthor()}
|
||||||
Date: {$svn->getLastCommit()->getDate()}
|
Date: {$git->getLastAuthoredDate()->format('c')}
|
||||||
|
|
||||||
SVN_INFO;
|
GIT_INFO;
|
||||||
|
|
||||||
foreach ($targetDirs as $targetDir) {
|
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';
|
$versionFile = $targetDir.'/version.txt';
|
||||||
|
|
||||||
|
7
src/Symfony/Component/Intl/Resources/data/git-info.txt
Normal file
7
src/Symfony/Component/Intl/Resources/data/git-info.txt
Normal file
@ -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
|
@ -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
|
|
73
src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php
Normal file
73
src/Symfony/Component/Intl/Tests/Util/GitRepositoryTest.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
}
|
108
src/Symfony/Component/Intl/Util/GitRepository.php
Normal file
108
src/Symfony/Component/Intl/Util/GitRepository.php
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public function __construct(string $path)
|
||||||
|
{
|
||||||
|
$this->path = $path;
|
||||||
|
|
||||||
|
$this->getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function download(string $remote, string $targetDir): self
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,62 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the Symfony package.
|
|
||||||
*
|
|
||||||
* (c) Fabien Potencier <fabien@symfony.com>
|
|
||||||
*
|
|
||||||
* 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 <bschussek@gmail.com>
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,140 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the Symfony package.
|
|
||||||
*
|
|
||||||
* (c) Fabien Potencier <fabien@symfony.com>
|
|
||||||
*
|
|
||||||
* 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 <bschussek@gmail.com>
|
|
||||||
*/
|
|
||||||
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(string $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;
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user