Hello community,
here is the log from the commit of package platformsh-cli for openSUSE:Factory checked in at 2017-05-03 15:57:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/platformsh-cli (Old)
and /work/SRC/openSUSE:Factory/.platformsh-cli.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "platformsh-cli"
Wed May 3 15:57:06 2017 rev:9 rq:492384 version:3.15.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/platformsh-cli/platformsh-cli.changes 2017-04-28 09:13:56.784641352 +0200
+++ /work/SRC/openSUSE:Factory/.platformsh-cli.new/platformsh-cli.changes 2017-05-03 15:57:07.808734039 +0200
@@ -1,0 +2,26 @@
+Mon May 01 23:05:14 UTC 2017 - jimmy@boombatower.com
+
+- Update to version 3.15.3:
+ * Fix wrong array keys in certificate:add
+ * Trigger patch in platformsh/client package to actually apply
+ * Document PLATFORMSH_CLI_TOKEN variable, with a warning
+ * Do not check for updates immediately after install
+ * Since we have the filename, the Phar can run directly
+ * No need to write to user config for updates check
+ * Release v3.15.3
+
+-------------------------------------------------------------------
+Mon May 01 16:30:03 UTC 2017 - jimmy@boombatower.com
+
+- Update to version 3.15.2:
+ * Explain that auto-provisioned certificates can't be deleted
+ * Show issuer in certificate:list
+ * Allow partial match on ID in certificate:delete
+ * Use RequestTty only for certain commands, when stdin is a tty
+ * Add --raw option to sql command
+ * SSH commands need to show errors
+ * Downgrade Process, avoiding apparent segfault
+ * Ensure running another command doesn't wipe necessary service data
+ * Release v3.15.2
+
+-------------------------------------------------------------------
Old:
----
platformsh-cli-3.15.1.tar.xz
New:
----
platformsh-cli-3.15.3.tar.xz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ platformsh-cli.spec ++++++
--- /var/tmp/diff_new_pack.FvdPk2/_old 2017-05-03 15:57:08.728604177 +0200
+++ /var/tmp/diff_new_pack.FvdPk2/_new 2017-05-03 15:57:08.732603612 +0200
@@ -17,7 +17,7 @@
Name: platformsh-cli
-Version: 3.15.1
+Version: 3.15.3
Release: 0
Summary: The unified tool for managing your Platform.sh services from the command line.
# See licenses.txt for dependency licenses.
++++++ _service ++++++
--- /var/tmp/diff_new_pack.FvdPk2/_old 2017-05-03 15:57:08.776597401 +0200
+++ /var/tmp/diff_new_pack.FvdPk2/_new 2017-05-03 15:57:08.776597401 +0200
@@ -2,7 +2,7 @@
<service name="tar_scm" mode="disabled">
<param name="versionformat">@PARENT_TAG@</param>
<param name="versionrewrite-pattern">v(.*)</param>
- <param name="revision">refs/tags/v3.15.1</param>
+ <param name="revision">refs/tags/v3.15.3</param>
<param name="url">git://github.com/platformsh/platformsh-cli.git</param>
<param name="scm">git</param>
<param name="changesgenerate">enable</param>
++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.FvdPk2/_old 2017-05-03 15:57:08.796594578 +0200
+++ /var/tmp/diff_new_pack.FvdPk2/_new 2017-05-03 15:57:08.796594578 +0200
@@ -1,6 +1,6 @@
<servicedata>
<service name="tar_scm">
<param name="url">git://github.com/platformsh/platformsh-cli.git</param>
- <param name="changesrevision">75e6ca004b80b07475892f2feb89e1cda8a17c36</param>
+ <param name="changesrevision">3fff2c671e63c504259be508cdc4d2771862d051</param>
</service>
</servicedata>
++++++ licenses.txt ++++++
--- /var/tmp/diff_new_pack.FvdPk2/_old 2017-05-03 15:57:08.860585544 +0200
+++ /var/tmp/diff_new_pack.FvdPk2/_new 2017-05-03 15:57:08.864584980 +0200
@@ -28,5 +28,5 @@
symfony/filesystem v3.2.7 MIT
symfony/finder v3.2.7 MIT
symfony/polyfill-mbstring v1.3.0 MIT
-symfony/process v3.2.7 MIT
+symfony/process v3.2.4 MIT
symfony/yaml v3.2.7 MIT
++++++ platformsh-cli-3.15.1.tar.xz -> platformsh-cli-3.15.3.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/README.md new/platformsh-cli-3.15.3/README.md
--- old/platformsh-cli-3.15.1/README.md 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/README.md 2017-05-02 00:40:27.000000000 +0200
@@ -185,6 +185,7 @@
```yaml
api:
# A path (relative or absolute) to a file containing an API token.
+ # The file should be stored with minimal permissions.
# Run 'platform logout --all' if you change this value.
token_file: null
@@ -208,6 +209,7 @@
* `PLATFORMSH_CLI_DEBUG`: set to 1 to enable cURL debugging
* `PLATFORMSH_CLI_DISABLE_CACHE`: set to 1 to disable caching
* `PLATFORMSH_CLI_SESSION_ID`: change user session (default 'default')
+* `PLATFORMSH_CLI_TOKEN`: an API token. _Warning_: storing a secret in an environment variable can be insecure. It is usually preferable to use `config.yaml` as above.
* `PLATFORMSH_CLI_UPDATES_CHECK`: set to 0 to disable the automatic updates check
* `http_proxy` or `https_proxy`: specify a proxy for connecting to Platform.sh
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/composer.json new/platformsh-cli-3.15.3/composer.json
--- old/platformsh-cli-3.15.1/composer.json 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/composer.json 2017-05-02 00:40:27.000000000 +0200
@@ -13,7 +13,7 @@
"symfony/yaml": "^3.0 || ^2.6",
"symfony/finder": "^3.0",
"symfony/filesystem": "^3.0",
- "symfony/process": "^3.0 !=3.2.5 !=3.2.6",
+ "symfony/process": "^3.0 !=3.2.5 !=3.2.6 !=3.2.7",
"stecman/symfony-console-completion": "~0.7",
"symfony/event-dispatcher": "^3.0",
"padraic/phar-updater": "^1.0",
@@ -49,5 +49,10 @@
],
"bin": [
"bin/platform"
- ]
+ ],
+ "extra": {
+ "patches": {
+ "commerceguys/guzzle-oauth2-plugin": {}
+ }
+ }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/composer.lock new/platformsh-cli-3.15.3/composer.lock
--- old/platformsh-cli-3.15.1/composer.lock 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/composer.lock 2017-05-02 00:40:27.000000000 +0200
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "45c0dda3a1b95ceb517677403cf37592",
+ "content-hash": "c3322283a273a90a18178d15f6e44acc",
"packages": [
{
"name": "cocur/slugify",
@@ -91,6 +91,11 @@
"phpunit/phpunit": "~4.5"
},
"type": "library",
+ "extra": {
+ "patches_applied": {
+ "Make it possible to get the access token without triggering a refresh": "https://github.com/pjcdawkins/guzzle-oauth2-plugin/commit/d2d720015813185d1a..."
+ }
+ },
"autoload": {
"psr-4": {
"CommerceGuys\\Guzzle\\Oauth2\\": "src"
@@ -1269,16 +1274,16 @@
},
{
"name": "symfony/process",
- "version": "v3.2.7",
+ "version": "v3.2.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282"
+ "reference": "0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/57fdaa55827ae14d617550e...",
- "reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282",
+ "url": "https://api.github.com/repos/symfony/process/zipball/0ab87c1e7570b3534a6e51e...",
+ "reference": "0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856",
"shasum": ""
},
"require": {
@@ -1314,7 +1319,7 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
- "time": "2017-03-27T18:07:02+00:00"
+ "time": "2017-02-16T14:07:22+00:00"
},
{
"name": "symfony/yaml",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/config.yaml new/platformsh-cli-3.15.3/config.yaml
--- old/platformsh-cli-3.15.1/config.yaml 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/config.yaml 2017-05-02 00:40:27.000000000 +0200
@@ -1,7 +1,7 @@
# Metadata about the CLI application itself.
application:
name: 'Platform.sh CLI'
- version: '3.15.1'
+ version: '3.15.3'
executable: 'platform'
phar: 'platform.phar'
package_name: 'platformsh/cli'
@@ -74,7 +74,7 @@
# Automatic updates.
# This can be overridden in the user config file.
updates:
- last_checked: null
+ last_checked: ~
check_interval: 86400
# Overridden by {application.env_prefix}UPDATES_CHECK env var.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateAddCommand.php new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateAddCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateAddCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateAddCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -35,9 +35,9 @@
return 1;
}
- list($certificate, $key, $chain) = (new SslUtil())->validate($certPath, $keyPath, $chainPaths);
+ $options = (new SslUtil())->validate($certPath, $keyPath, $chainPaths);
- $result = $project->addCertificate($certificate, $key, $chain);
+ $result = $project->addCertificate($options['certificate'], $options['key'], $options['chain']);
if (!$input->getOption('no-wait')) {
/** @var \Platformsh\Cli\Service\ActivityMonitor $activityMonitor */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateDeleteCommand.php new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateDeleteCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateDeleteCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateDeleteCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -1,6 +1,7 @@
setName('certificate:delete')
->setDescription('Delete a certificate from the project')
- ->addArgument('id', InputArgument::REQUIRED, 'The full certificate ID');
+ ->addArgument('id', InputArgument::REQUIRED, 'The certificate ID (or the start of it)');
$this->addProjectOption();
}
@@ -32,8 +33,12 @@
$certificate = $project->getCertificate($id);
if (!$certificate) {
- $this->stdErr->writeln(sprintf('Certificate not found: <error>%s</error>', $id));
- return 1;
+ try {
+ $certificate = $this->api()->matchPartialId($id, $project->getCertificates(), 'Certificate');
+ } catch (\InvalidArgumentException $e) {
+ $this->stdErr->writeln($e->getMessage());
+ return 1;
+ }
}
/** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */
@@ -42,7 +47,16 @@
return 1;
}
- $result = $certificate->delete();
+ try {
+ $result = $certificate->delete();
+ } catch (BadResponseException $e) {
+ if (($response = $e->getResponse()) && $response->getStatusCode() === 403 && $certificate->is_provisioned) {
+ $this->stdErr->writeln(sprintf('The certificate <error>%s</error> is automatically provisioned; it cannot be deleted.', $certificate->id));
+ return 1;
+ }
+
+ throw $e;
+ }
$this->stdErr->writeln(sprintf('The certificate <info>%s</info> has been deleted.', $certificate->id));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateGetCommand.php new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateGetCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateGetCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateGetCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -30,10 +30,10 @@
$id = $input->getArgument('id');
$cert = $project->getCertificate($id);
if (!$cert) {
- $cert = $this->matchCertificateId($id, $project->getCertificates());
- if (!$cert) {
- $this->stdErr->writeln(sprintf('Certificate not found: %s', $id));
-
+ try {
+ $cert = $this->api()->matchPartialId($id, $project->getCertificates(), 'Certificate');
+ } catch (\InvalidArgumentException $e) {
+ $this->stdErr->writeln($e->getMessage());
return 1;
}
}
@@ -45,23 +45,4 @@
return 0;
}
-
- /**
- * @param string $id
- * @param \Platformsh\Client\Model\Certificate[] $certs
- *
- * @return \Platformsh\Client\Model\Certificate|null
- */
- protected function matchCertificateId($id, array $certs)
- {
- if (strlen($id) > 5) {
- foreach ($certs as $candidate) {
- if (strpos($candidate->id, $id) === 0) {
- return $candidate;
- }
- }
- }
-
- return null;
- }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateListCommand.php new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateListCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Certificate/CertificateListCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Certificate/CertificateListCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -58,7 +58,7 @@
/** @var \Platformsh\Cli\Service\PropertyFormatter $propertyFormatter */
$propertyFormatter = $this->getService('property_formatter');
- $header = ['ID', 'Domain(s)', 'Created', 'Expires'];
+ $header = ['ID', 'Domain(s)', 'Created', 'Expires', 'Issuer'];
$rows = [];
foreach ($certs as $cert) {
$rows[] = [
@@ -66,6 +66,7 @@
implode("\n", $cert->domains),
$propertyFormatter->format($cert->created_at, 'created_at'),
$propertyFormatter->format($cert->expires_at, 'expires_at'),
+ $this->getCertificateIssuerByAlias($cert, 'commonName') ?: '',
];
}
@@ -128,4 +129,20 @@
}
}
}
+
+ /**
+ * @param \Platformsh\Client\Model\Certificate $cert
+ * @param string $alias
+ *
+ * @return string|bool
+ */
+ protected function getCertificateIssuerByAlias(Certificate $cert, $alias) {
+ foreach ($cert->issuer as $issuer) {
+ if (isset($issuer['alias'], $issuer['value']) && $issuer['alias'] === $alias) {
+ return $issuer['value'];
+ }
+ }
+
+ return false;
+ }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/CommandBase.php new/platformsh-cli-3.15.3/src/Command/CommandBase.php
--- old/platformsh-cli-3.15.1/src/Command/CommandBase.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/CommandBase.php 2017-05-02 00:40:27.000000000 +0200
@@ -13,6 +13,7 @@
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException as ConsoleInvalidArgumentException;
+use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@@ -222,37 +223,46 @@
/**
* Check for updates.
- *
- * @param bool $reset
*/
- protected function checkUpdates($reset = false)
+ protected function checkUpdates()
{
- if (!$reset && self::$checkedUpdates) {
+ // Avoid checking more than once in this process.
+ if (self::$checkedUpdates) {
return;
}
self::$checkedUpdates = true;
- // Check that this instance of the CLI was installed as a Phar.
- if (!extension_loaded('Phar') || !\Phar::running(false)) {
+ // Check that the Phar extension is available.
+ if (!extension_loaded('Phar')) {
return;
}
- $timestamp = time();
- $config = $this->config();
+ // Get the filename of the Phar, or stop if this instance of the CLI is
+ // not a Phar.
+ $pharFilename = \Phar::running(false);
+ if (!$pharFilename) {
+ return;
+ }
+ // Check if updates are configured.
+ $config = $this->config();
if (!$config->get('updates.check')) {
return;
- } elseif (!$reset
- && $config->get('updates.last_checked') > $timestamp - $config->get('updates.check_interval')) {
+ }
+
+ // Determine an embargo time, after which updates can be checked.
+ $timestamp = time();
+ $embargoTime = $timestamp - $config->get('updates.check_interval');
+
+ // Stop if updates were last checked after the embargo time.
+ if ($config->has('updates.last_checked') && $config->get('updates.last_checked') > $embargoTime) {
return;
}
- $config->writeUserConfig([
- 'updates' => [
- 'check' => true,
- 'last_checked' => $timestamp,
- ],
- ]);
+ // Stop if the Phar was updated after the embargo time.
+ if (filemtime($pharFilename) > $embargoTime) {
+ return;
+ }
// Ensure classes are auto-loaded if they may be needed after the
// update.
@@ -284,14 +294,17 @@
$exitCode = 0;
list($currentMajorVersion,) = explode('.', $currentVersion, 2);
list($newMajorVersion,) = explode('.', $newVersion, 2);
- if ($newMajorVersion === $currentMajorVersion && isset($GLOBALS['argv'])) {
- $originalCommand = implode(' ', array_map('escapeshellarg', $GLOBALS['argv']));
+ if ($newMajorVersion === $currentMajorVersion
+ && isset($this->input)
+ && $this->input instanceof ArgvInput
+ && is_executable($pharFilename)) {
+ $originalCommand = $this->input->__toString();
$questionText = "\n"
. 'Original command: <info>' . $originalCommand . '</info>'
. "\n\n" . 'Continue?';
if ($questionHelper->confirm($questionText)) {
$this->stdErr->writeln('');
- $exitCode = $shell->executeSimple($originalCommand);
+ $exitCode = $shell->executeSimple(escapeshellarg($pharFilename) . ' ' . $originalCommand);
}
}
exit($exitCode);
@@ -921,12 +934,19 @@
$this->debug('Running command: ' . $name);
- $this->container()->reset();
+ // Give the other command an entirely new service container, because the
+ // "input" and "output" parameters, and all their dependents, need to
+ // change.
+ $container = self::$container;
+ self::$container = null;
$application->setCurrentCommand($command);
$result = $command->run($cmdInput, $output ?: $this->output);
$application->setCurrentCommand($this);
+ // Restore the old service container.
+ self::$container = $container;
+
return $result;
}
@@ -1079,4 +1099,14 @@
return $this->synopsis[$key];
}
+
+ /**
+ * @param resource|int $descriptor
+ *
+ * @return bool
+ */
+ protected function isTerminal($descriptor)
+ {
+ return !function_exists('posix_isatty') || posix_isatty($descriptor);
+ }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Db/DbSqlCommand.php new/platformsh-cli-3.15.3/src/Command/Db/DbSqlCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Db/DbSqlCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Db/DbSqlCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -7,6 +7,7 @@
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class DbSqlCommand extends CommandBase
@@ -17,7 +18,8 @@
$this->setName('db:sql')
->setAliases(['sql'])
->setDescription('Run SQL on the remote database')
- ->addArgument('query', InputArgument::OPTIONAL, 'An SQL statement to execute');
+ ->addArgument('query', InputArgument::OPTIONAL, 'An SQL statement to execute')
+ ->addOption('raw', null, InputOption::VALUE_NONE, 'Produce raw, non-tabular output');
$this->addProjectOption()->addEnvironmentOption()->addAppOption();
Relationships::configureInput($this->getDefinition());
Ssh::configureInput($this->getDefinition());
@@ -44,27 +46,38 @@
return 1;
}
+ $query = $input->getArgument('query');
+
switch ($database['scheme']) {
case 'pgsql':
$sqlCommand = 'psql ' . $relationships->getSqlCommandArgs('psql', $database);
- $queryOption = ' -c ';
+ if ($query) {
+ if ($input->getOption('raw')) {
+ $sqlCommand .= ' -t';
+ }
+ $sqlCommand .= ' -c ' . escapeshellarg($query);
+ }
break;
default:
$sqlCommand = 'mysql --no-auto-rehash ' . $relationships->getSqlCommandArgs('mysql', $database);
- $queryOption = ' --execute ';
+ if ($query) {
+ if ($input->getOption('raw')) {
+ $sqlCommand .= ' --batch --raw';
+ }
+ $sqlCommand .= ' --execute ' . escapeshellarg($query);
+ }
break;
}
- $query = $input->getArgument('query');
- if ($query) {
- $sqlCommand .= $queryOption . escapeshellarg($query);
- }
-
/** @var \Platformsh\Cli\Service\Ssh $ssh */
$ssh = $this->getService('ssh');
- $sshCommand = $ssh->getSshCommand();
+ $sshOptions = [];
+ if ($this->isTerminal(STDIN)) {
+ $sshOptions['RequestTty'] = 'yes';
+ }
+ $sshCommand = $ssh->getSshCommand($sshOptions);
$sshCommand .= ' ' . escapeshellarg($sshUrl)
. ' ' . escapeshellarg($sqlCommand);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Environment/EnvironmentPushCommand.php new/platformsh-cli-3.15.3/src/Command/Environment/EnvironmentPushCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Environment/EnvironmentPushCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Environment/EnvironmentPushCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -145,7 +145,7 @@
$extraSshOptions = [];
$env = [];
if ($input->getOption('no-wait')) {
- $extraSshOptions[] = 'SendEnv PLATFORMSH_PUSH_NO_WAIT';
+ $extraSshOptions['SendEnv'] = 'PLATFORMSH_PUSH_NO_WAIT';
$env['PLATFORMSH_PUSH_NO_WAIT'] = '1';
}
$git->setSshCommand($ssh->getSshCommand($extraSshOptions));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Environment/EnvironmentSshCommand.php new/platformsh-cli-3.15.3/src/Command/Environment/EnvironmentSshCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Environment/EnvironmentSshCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Environment/EnvironmentSshCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -50,7 +50,12 @@
/** @var \Platformsh\Cli\Service\Ssh $ssh */
$ssh = $this->getService('ssh');
- $command = $ssh->getSshCommand() . ' ' . escapeshellarg($sshUrl);
+ $sshOptions = [];
+ if ($this->isTerminal(STDIN)) {
+ $sshOptions['RequestTty'] = 'yes';
+ }
+ $command = $ssh->getSshCommand($sshOptions);
+ $command .= ' ' . escapeshellarg($sshUrl);
if ($remoteCommand) {
$command .= ' ' . escapeshellarg($remoteCommand);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Command/Self/SelfUpdateCommand.php new/platformsh-cli-3.15.3/src/Command/Self/SelfUpdateCommand.php
--- old/platformsh-cli-3.15.1/src/Command/Self/SelfUpdateCommand.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Command/Self/SelfUpdateCommand.php 2017-05-02 00:40:27.000000000 +0200
@@ -47,7 +47,7 @@
/**
* {@inheritdoc}
*/
- protected function checkUpdates($reset = false)
+ protected function checkUpdates()
{
// Don't check for updates automatically when running self-update.
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Service/Api.php new/platformsh-cli-3.15.3/src/Service/Api.php
--- old/platformsh-cli-3.15.1/src/Service/Api.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Service/Api.php 2017-05-02 00:40:27.000000000 +0200
@@ -39,7 +39,7 @@
protected $apiTokenType = 'exchange';
/** @var PlatformClient */
- protected $client;
+ protected static $client;
/** @var Environment[] */
protected static $environmentsCache = [];
@@ -83,13 +83,15 @@
$this->apiToken = $this->config->get('api.token');
$this->apiTokenType = 'exchange';
$this->sessionId = 'api-token';
- } elseif ($this->config->has('api.access_token_file')) {
+ } elseif ($this->config->has('api.access_token_file') || $this->config->has('api.access_token')) {
// Permanent, personal access token (deprecated) - an OAuth 2.0
// bearer token which is used directly in API requests.
- $this->apiToken = $this->loadTokenFromFile($this->config->get('api.access_token_file'));
- $this->apiTokenType = 'access';
- } elseif ($this->config->has('api.access_token')) {
- $this->apiToken = $this->config->get('api.access_token');
+ @trigger_error('This type of API token (a permanent access token) is deprecated. Please generate a new API token when possible.', E_USER_DEPRECATED);
+ if ($this->config->has('api.access_token_file')) {
+ $this->apiToken = $this->loadTokenFromFile($this->config->get('api.access_token_file'));
+ } else {
+ $this->apiToken = $this->config->get('api.access_token');
+ }
$this->apiTokenType = 'access';
}
}
@@ -154,7 +156,7 @@
*/
public function getClient($autoLogin = true)
{
- if (!isset($this->client)) {
+ if (!isset(self::$client)) {
$connectorOptions = [];
$connectorOptions['accounts'] = $this->config->get('api.accounts_api_url');
$connectorOptions['verify'] = !$this->config->get('api.skip_ssl');
@@ -186,14 +188,14 @@
$session->setId('cli-' . $this->sessionId);
$session->setStorage(new File($this->config->getUserConfigDir() . '/.session'));
- $this->client = new PlatformClient($connector);
+ self::$client = new PlatformClient($connector);
if ($autoLogin && !$connector->isLoggedIn()) {
$this->dispatcher->dispatch('login_required');
}
}
- return $this->client;
+ return self::$client;
}
/**
@@ -558,4 +560,37 @@
return sprintf($pattern, $tag, $title, $project->id);
}
+
+ /**
+ * Get a resource, matching on the beginning of the ID.
+ *
+ * @param string $id
+ * @param ApiResource[] $resources
+ * @param string $name
+ *
+ * @return ApiResource
+ * The resource, if one (and only one) is matched.
+ */
+ public function matchPartialId($id, array $resources, $name = 'Resource')
+ {
+ $matched = array_filter($resources, function (ApiResource $resource) use ($id) {
+ return strpos($resource->getProperty('id'), $id) === 0;
+ });
+
+ if (count($matched) > 1) {
+ $matchedIds = array_map(function (ApiResource $resource) {
+ return $resource->id;
+ }, $matched);
+ throw new \InvalidArgumentException(sprintf(
+ 'The partial ID "<error>%s</error>" is ambiguous; it matches the following %s IDs: %s',
+ $id,
+ strtolower($name),
+ "\n " . implode("\n ", $matchedIds)
+ ));
+ } elseif (count($matched) === 0) {
+ throw new \InvalidArgumentException(sprintf('%s not found: "<error>%s</error>"', $name, $id));
+ }
+
+ return reset($matched);
+ }
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Service/Config.php new/platformsh-cli-3.15.3/src/Service/Config.php
--- old/platformsh-cli-3.15.1/src/Service/Config.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Service/Config.php 2017-05-02 00:40:27.000000000 +0200
@@ -142,32 +142,6 @@
return $this->userConfig;
}
- /**
- * Update user configuration.
- *
- * @param array $config
- */
- public function writeUserConfig(array $config)
- {
- $dir = $this->getUserConfigDir();
- if (!is_dir($dir) && !mkdir($dir, 0700, true)) {
- trigger_error('Failed to create user config directory: ' . $dir, E_USER_WARNING);
- }
- $existingConfig = $this->getUserConfig();
- $config = array_replace_recursive($existingConfig, $config);
- $configFile = $dir . '/config.yaml';
- $new = !file_exists($configFile);
- if (file_put_contents($configFile, Yaml::dump($config, 10)) === false) {
- trigger_error('Failed to write user config to: ' . $configFile, E_USER_WARNING);
- }
- // If the config file was newly created, then chmod to be r/w only by
- // the user.
- if ($new) {
- chmod($configFile, 0600);
- }
- $this->userConfig = $config;
- }
-
protected function applyUserConfigOverrides()
{
// A whitelist of allowed overrides.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.15.1/src/Service/Ssh.php new/platformsh-cli-3.15.3/src/Service/Ssh.php
--- old/platformsh-cli-3.15.1/src/Service/Ssh.php 2017-04-26 16:54:54.000000000 +0200
+++ new/platformsh-cli-3.15.3/src/Service/Ssh.php 2017-05-02 00:40:27.000000000 +0200
@@ -38,17 +38,9 @@
$options = array_merge($this->getSshOptions(), $extraOptions);
$args = [];
- if ($this->output->isDebug()) {
- $args[] = '-vv';
- } elseif ($this->output->isVeryVerbose()) {
- $args[] = '-v';
- } elseif ($this->output->isQuiet()) {
- $args[] = '-q';
- }
-
- foreach ($options as $option) {
+ foreach ($options as $name => $value) {
$args[] = '-o';
- $args[] = $option;
+ $args[] = $name . ' ' . $value;
}
return $args;
@@ -63,19 +55,23 @@
{
$options = [];
- $options[] = 'SendEnv TERM';
+ $options['SendEnv'] = 'TERM';
if ($this->input->hasOption('identity-file') && $this->input->getOption('identity-file')) {
$file = $this->input->getOption('identity-file');
if (!file_exists($file)) {
throw new \InvalidArgumentException('Identity file not found: ' . $file);
}
- $options[] = 'IdentitiesOnly yes';
- $options[] = 'IdentityFile ' . $file;
+ $options['IdentitiesOnly'] = 'yes';
+ $options['IdentityFile'] = $file;
}
- if ($this->output->isDecorated()) {
- $options[] = 'RequestTty yes';
+ if ($this->output->isDebug()) {
+ $options['LogLevel'] = 'DEBUG';
+ } elseif ($this->output->isVeryVerbose()) {
+ $options['LogLevel'] = 'VERBOSE';
+ } elseif ($this->output->isQuiet()) {
+ $options['LogLevel'] = 'QUIET';
}
return $options;
++++++ platformsh-cli-vendor.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/autoload.php new/vendor/autoload.php
--- old/vendor/autoload.php 2017-04-26 18:40:07.063327027 +0200
+++ new/vendor/autoload.php 2017-05-02 01:05:16.417576043 +0200
@@ -4,4 +4,4 @@
require_once __DIR__ . '/composer/autoload_real.php';
-return ComposerAutoloaderInitb0c98a3a98d513ba273f445467f7f7fe::getLoader();
+return ComposerAutoloaderInit89af1a5db1fd8f018f647d41d92d023b::getLoader();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/commerceguys/guzzle-oauth2-plugin/PATCHES.txt new/vendor/commerceguys/guzzle-oauth2-plugin/PATCHES.txt
--- old/vendor/commerceguys/guzzle-oauth2-plugin/PATCHES.txt 1970-01-01 01:00:00.000000000 +0100
+++ new/vendor/commerceguys/guzzle-oauth2-plugin/PATCHES.txt 2017-05-02 01:05:15.569568170 +0200
@@ -0,0 +1,7 @@
+This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)
+Patches applied to this directory:
+
+Make it possible to get the access token without triggering a refresh
+Source: https://github.com/pjcdawkins/guzzle-oauth2-plugin/commit/d2d720015813185d1a...
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/commerceguys/guzzle-oauth2-plugin/src/Oauth2Subscriber.php new/vendor/commerceguys/guzzle-oauth2-plugin/src/Oauth2Subscriber.php
--- old/vendor/commerceguys/guzzle-oauth2-plugin/src/Oauth2Subscriber.php 2015-12-13 00:27:25.000000000 +0100
+++ new/vendor/commerceguys/guzzle-oauth2-plugin/src/Oauth2Subscriber.php 2017-05-02 01:05:15.569568170 +0200
@@ -110,16 +110,18 @@
/**
* Get the access token.
*
+ * @param bool $refresh Whether to refresh the token, if possible.
+ *
* @return AccessToken|null Oauth2 access token
*/
- public function getAccessToken()
+ public function getAccessToken($refresh = true)
{
if ($this->accessToken && $this->accessToken->isExpired()) {
// The access token has expired.
$this->accessToken = null;
}
- if (null === $this->accessToken) {
+ if (null === $this->accessToken && $refresh) {
// Try to acquire a new access token from the server.
$this->accessToken = $this->acquireAccessToken();
if ($this->accessToken) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/composer/autoload_real.php new/vendor/composer/autoload_real.php
--- old/vendor/composer/autoload_real.php 2017-04-26 18:40:07.063327027 +0200
+++ new/vendor/composer/autoload_real.php 2017-05-02 01:05:16.417576043 +0200
@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
-class ComposerAutoloaderInitb0c98a3a98d513ba273f445467f7f7fe
+class ComposerAutoloaderInit89af1a5db1fd8f018f647d41d92d023b
{
private static $loader;
@@ -19,15 +19,15 @@
return self::$loader;
}
- spl_autoload_register(array('ComposerAutoloaderInitb0c98a3a98d513ba273f445467f7f7fe', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInit89af1a5db1fd8f018f647d41d92d023b', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
- spl_autoload_unregister(array('ComposerAutoloaderInitb0c98a3a98d513ba273f445467f7f7fe', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInit89af1a5db1fd8f018f647d41d92d023b', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
- call_user_func(\Composer\Autoload\ComposerStaticInitb0c98a3a98d513ba273f445467f7f7fe::getInitializer($loader));
+ call_user_func(\Composer\Autoload\ComposerStaticInit89af1a5db1fd8f018f647d41d92d023b::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
@@ -48,19 +48,19 @@
$loader->register(true);
if ($useStaticLoader) {
- $includeFiles = Composer\Autoload\ComposerStaticInitb0c98a3a98d513ba273f445467f7f7fe::$files;
+ $includeFiles = Composer\Autoload\ComposerStaticInit89af1a5db1fd8f018f647d41d92d023b::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
- composerRequireb0c98a3a98d513ba273f445467f7f7fe($fileIdentifier, $file);
+ composerRequire89af1a5db1fd8f018f647d41d92d023b($fileIdentifier, $file);
}
return $loader;
}
}
-function composerRequireb0c98a3a98d513ba273f445467f7f7fe($fileIdentifier, $file)
+function composerRequire89af1a5db1fd8f018f647d41d92d023b($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/composer/autoload_static.php new/vendor/composer/autoload_static.php
--- old/vendor/composer/autoload_static.php 2017-04-26 18:40:07.063327027 +0200
+++ new/vendor/composer/autoload_static.php 2017-05-02 01:05:16.417576043 +0200
@@ -4,7 +4,7 @@
namespace Composer\Autoload;
-class ComposerStaticInitb0c98a3a98d513ba273f445467f7f7fe
+class ComposerStaticInit89af1a5db1fd8f018f647d41d92d023b
{
public static $files = array (
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
@@ -183,9 +183,9 @@
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
- $loader->prefixLengthsPsr4 = ComposerStaticInitb0c98a3a98d513ba273f445467f7f7fe::$prefixLengthsPsr4;
- $loader->prefixDirsPsr4 = ComposerStaticInitb0c98a3a98d513ba273f445467f7f7fe::$prefixDirsPsr4;
- $loader->classMap = ComposerStaticInitb0c98a3a98d513ba273f445467f7f7fe::$classMap;
+ $loader->prefixLengthsPsr4 = ComposerStaticInit89af1a5db1fd8f018f647d41d92d023b::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInit89af1a5db1fd8f018f647d41d92d023b::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInit89af1a5db1fd8f018f647d41d92d023b::$classMap;
}, null, ClassLoader::class);
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/composer/installed.json new/vendor/composer/installed.json
--- old/vendor/composer/installed.json 2017-04-26 18:40:05.951316552 +0200
+++ new/vendor/composer/installed.json 2017-05-02 01:05:15.813570436 +0200
@@ -561,6 +561,11 @@
},
"time": "2015-12-12T23:27:25+00:00",
"type": "library",
+ "extra": {
+ "patches_applied": {
+ "Make it possible to get the access token without triggering a refresh": "https://github.com/pjcdawkins/guzzle-oauth2-plugin/commit/d2d720015813185d1a..."
+ }
+ },
"installation-source": "dist",
"autoload": {
"psr-4": {
@@ -1310,23 +1315,23 @@
},
{
"name": "symfony/process",
- "version": "v3.2.7",
- "version_normalized": "3.2.7.0",
+ "version": "v3.2.4",
+ "version_normalized": "3.2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282"
+ "reference": "0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/57fdaa55827ae14d617550e...",
- "reference": "57fdaa55827ae14d617550ebe71a820f0a5e2282",
+ "url": "https://api.github.com/repos/symfony/process/zipball/0ab87c1e7570b3534a6e51e...",
+ "reference": "0ab87c1e7570b3534a6e51eb4ca8e9f6d7327856",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
- "time": "2017-03-27T18:07:02+00:00",
+ "time": "2017-02-16T14:07:22+00:00",
"type": "library",
"extra": {
"branch-alias": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/symfony/process/Process.php new/vendor/symfony/process/Process.php
--- old/vendor/symfony/process/Process.php 2017-03-27 20:07:02.000000000 +0200
+++ new/vendor/symfony/process/Process.php 2017-02-16 15:07:22.000000000 +0100
@@ -169,6 +169,7 @@
$this->setTimeout($timeout);
$this->useFileHandles = '\\' === DIRECTORY_SEPARATOR;
$this->pty = false;
+ $this->enhanceWindowsCompatibility = true;
$this->enhanceSigchildCompatibility = '\\' !== DIRECTORY_SEPARATOR && $this->isSigchildEnabled();
$this->options = array_replace(array('suppress_errors' => true, 'binary_pipes' => true), $options);
}
@@ -265,25 +266,24 @@
$this->callback = $this->buildCallback($callback);
$this->hasCallback = null !== $callback;
$descriptors = $this->getDescriptors();
- $inheritEnv = $this->inheritEnv;
$commandline = $this->commandline;
+ $envline = '';
- $env = $this->env;
- $envBackup = array();
- if (null !== $env && $inheritEnv) {
+ if (null !== $this->env && $this->inheritEnv) {
if ('\\' === DIRECTORY_SEPARATOR && !empty($this->options['bypass_shell']) && !$this->enhanceWindowsCompatibility) {
throw new LogicException('The "bypass_shell" option must be false to inherit environment variables while enhanced Windows compatibility is off');
}
-
- foreach ($env as $k => $v) {
- $envBackup[$k] = getenv($k);
- putenv(false === $v || null === $v ? $k : "$k=$v");
+ $env = '\\' === DIRECTORY_SEPARATOR ? '(SET %s)&&' : 'export %s;';
+ foreach ($this->env as $k => $v) {
+ $envline .= sprintf($env, ProcessUtils::escapeArgument("$k=$v"));
}
$env = null;
+ } else {
+ $env = $this->env;
}
if ('\\' === DIRECTORY_SEPARATOR && $this->enhanceWindowsCompatibility) {
- $commandline = 'cmd /V:ON /E:ON /D /C "('.$commandline.')';
+ $commandline = 'cmd /V:ON /E:ON /D /C "('.$envline.$commandline.')';
foreach ($this->processPipes->getFiles() as $offset => $filename) {
$commandline .= ' '.$offset.'>'.ProcessUtils::escapeArgument($filename);
}
@@ -297,20 +297,18 @@
$descriptors[3] = array('pipe', 'w');
// See https://unix.stackexchange.com/questions/71205/background-process-pipe-input
- $commandline = '{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
+ $commandline = $envline.'{ ('.$this->commandline.') <&3 3<&- 3>/dev/null & } 3<&0;';
$commandline .= 'pid=$!; echo $pid >&3; wait $pid; code=$?; echo $code >&3; exit $code';
// Workaround for the bug, when PTS functionality is enabled.
// @see : https://bugs.php.net/69442
$ptsWorkaround = fopen(__FILE__, 'r');
+ } elseif ('' !== $envline) {
+ $commandline = $envline.$commandline;
}
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $env, $this->options);
- foreach ($envBackup as $k => $v) {
- putenv(false === $v ? $k : "$k=$v");
- }
-
if (!is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
}
@@ -379,7 +377,7 @@
if (null !== $callback) {
if (!$this->processPipes->haveReadSupport()) {
$this->stop(0);
- throw new \LogicException('Pass the callback to the Process::start method or enableOutput to use a callback with Process::wait');
+ throw new \LogicException('Pass the callback to the Process:start method or enableOutput to use a callback with Process::wait');
}
$this->callback = $this->buildCallback($callback);
}
@@ -1106,7 +1104,10 @@
return !is_array($value);
});
- $this->env = $env;
+ $this->env = array();
+ foreach ($env as $key => $value) {
+ $this->env[$key] = (string) $value;
+ }
return $this;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/symfony/process/Tests/ExecutableFinderTest.php new/vendor/symfony/process/Tests/ExecutableFinderTest.php
--- old/vendor/symfony/process/Tests/ExecutableFinderTest.php 2017-03-27 20:07:02.000000000 +0200
+++ new/vendor/symfony/process/Tests/ExecutableFinderTest.php 2017-02-16 15:07:22.000000000 +0100
@@ -11,13 +11,12 @@
namespace Symfony\Component\Process\Tests;
-use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\ExecutableFinder;
/**
* @author Chris Smith