2012-03-22 16:18:24 +00:00
< ? php
2012-03-24 21:39:34 +00:00
2012-03-22 16:18:24 +00:00
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Composer\Util ;
2014-05-30 15:14:43 +00:00
use Composer\Config ;
2012-03-22 16:18:24 +00:00
use Composer\IO\IOInterface ;
/**
* @ author Till Klampaeckel < till @ php . net >
2012-03-24 22:05:13 +00:00
* @ author Jordi Boggiano < j . boggiano @ seld . be >
2012-03-22 16:18:24 +00:00
*/
class Svn
{
2013-06-14 21:32:27 +00:00
const MAX_QTY_AUTH_TRIES = 5 ;
2012-03-22 16:18:24 +00:00
/**
2012-03-24 22:05:13 +00:00
* @ var array
2012-03-22 16:18:24 +00:00
*/
protected $credentials ;
/**
2012-03-23 15:03:52 +00:00
* @ var bool
2012-03-22 16:18:24 +00:00
*/
protected $hasAuth ;
/**
2012-03-23 15:03:52 +00:00
* @ var \Composer\IO\IOInterface
2012-03-22 16:18:24 +00:00
*/
protected $io ;
/**
2012-03-23 15:03:52 +00:00
* @ var string
2012-03-22 16:18:24 +00:00
*/
protected $url ;
2012-03-22 17:40:18 +00:00
/**
2012-03-23 15:03:52 +00:00
* @ var bool
2012-03-22 17:40:18 +00:00
*/
2012-03-24 22:08:43 +00:00
protected $cacheCredentials = true ;
2012-03-22 17:40:18 +00:00
2012-03-24 23:29:14 +00:00
/**
* @ var ProcessExecutor
*/
protected $process ;
2013-06-14 21:32:27 +00:00
/**
2015-09-28 09:51:14 +00:00
* @ var int
2013-06-14 21:32:27 +00:00
*/
protected $qtyAuthTries = 0 ;
2014-05-30 15:14:43 +00:00
/**
* @ var \Composer\Config
*/
protected $config ;
2012-03-22 16:18:24 +00:00
/**
* @ param string $url
* @ param \Composer\IO\IOInterface $io
2014-07-16 13:17:38 +00:00
* @ param Config $config
2012-03-24 23:29:14 +00:00
* @ param ProcessExecutor $process
2012-03-22 16:18:24 +00:00
*/
2014-05-30 15:14:43 +00:00
public function __construct ( $url , IOInterface $io , Config $config , ProcessExecutor $process = null )
2012-03-22 16:18:24 +00:00
{
$this -> url = $url ;
$this -> io = $io ;
2014-05-30 15:14:43 +00:00
$this -> config = $config ;
2012-03-24 23:29:14 +00:00
$this -> process = $process ? : new ProcessExecutor ;
}
2014-02-19 09:55:00 +00:00
public static function cleanEnv ()
{
// clean up env for OSX, see https://github.com/composer/composer/issues/2146#issuecomment-35478940
putenv ( " DYLD_LIBRARY_PATH " );
2015-03-06 16:20:27 +00:00
unset ( $_SERVER [ 'DYLD_LIBRARY_PATH' ]);
2014-02-19 09:55:00 +00:00
}
2012-03-24 23:29:14 +00:00
/**
* Execute an SVN command and try to fix up the process with credentials
* if necessary .
*
2012-06-23 09:58:18 +00:00
* @ param string $command SVN command to run
* @ param string $url SVN url
* @ param string $cwd Working directory
* @ param string $path Target for a checkout
* @ param bool $verbose Output all output to the user
2012-03-24 23:29:14 +00:00
*
* @ throws \RuntimeException
2015-09-28 09:51:14 +00:00
* @ return string
2012-03-24 23:29:14 +00:00
*/
2012-04-04 07:36:04 +00:00
public function execute ( $command , $url , $cwd = null , $path = null , $verbose = false )
2012-03-24 23:29:14 +00:00
{
2016-03-01 13:19:44 +00:00
if ( preg_match ( '{^(http|svn):}i' , $url ) && $this -> config -> get ( 'secure-http' )) {
throw new TransportException ( " Your configuration does not allow connection to $url . See https://getcomposer.org/doc/06-config.md#secure-http for details. " );
}
2012-03-24 23:29:14 +00:00
$svnCommand = $this -> getCommand ( $command , $url , $path );
2012-04-04 07:36:04 +00:00
$output = null ;
$io = $this -> io ;
$handler = function ( $type , $buffer ) use ( & $output , $io , $verbose ) {
if ( $type !== 'out' ) {
return ;
}
2013-10-18 09:45:05 +00:00
if ( 'Redirecting to URL ' === substr ( $buffer , 0 , 19 )) {
return ;
}
2012-04-04 07:36:04 +00:00
$output .= $buffer ;
if ( $verbose ) {
2015-02-06 12:52:44 +00:00
$io -> writeError ( $buffer , false );
2012-04-04 07:36:04 +00:00
}
};
$status = $this -> process -> execute ( $svnCommand , $handler , $cwd );
2012-03-24 23:29:14 +00:00
if ( 0 === $status ) {
return $output ;
}
2015-04-27 13:26:32 +00:00
$errorOutput = $this -> process -> getErrorOutput ();
2015-04-28 11:23:00 +00:00
$fullOutput = implode ( " \n " , array ( $output , $errorOutput ));
2012-03-24 23:29:14 +00:00
// the error is not auth-related
2015-04-27 13:26:32 +00:00
if ( false === stripos ( $fullOutput , 'Could not authenticate to server:' )
&& false === stripos ( $fullOutput , 'authorization failed' )
&& false === stripos ( $fullOutput , 'svn: E170001:' )
&& false === stripos ( $fullOutput , 'svn: E215004:' )) {
throw new \RuntimeException ( $fullOutput );
2012-03-24 23:29:14 +00:00
}
2014-05-30 15:14:43 +00:00
if ( ! $this -> hasAuth ()) {
$this -> doAuthDance ();
2012-03-24 23:29:14 +00:00
}
2013-06-14 21:32:27 +00:00
// try to authenticate if maximum quantity of tries not reached
2014-05-30 15:14:43 +00:00
if ( $this -> qtyAuthTries ++ < self :: MAX_QTY_AUTH_TRIES ) {
2012-03-24 23:29:14 +00:00
// restart the process
2012-04-04 07:36:04 +00:00
return $this -> execute ( $command , $url , $cwd , $path , $verbose );
2012-03-24 23:29:14 +00:00
}
throw new \RuntimeException (
2015-04-28 09:19:29 +00:00
'wrong credentials provided (' . $fullOutput . ')'
2012-03-24 23:29:14 +00:00
);
2012-03-22 16:18:24 +00:00
}
2014-09-16 13:16:55 +00:00
/**
2015-09-28 09:51:14 +00:00
* @ param bool $cacheCredentials
2014-09-16 13:16:55 +00:00
*/
public function setCacheCredentials ( $cacheCredentials )
{
$this -> cacheCredentials = $cacheCredentials ;
}
2012-03-22 17:40:18 +00:00
/**
* Repositories requests credentials , let ' s put them in .
*
2014-05-30 15:14:43 +00:00
* @ throws \RuntimeException
2015-09-28 09:51:14 +00:00
* @ return \Composer\Util\Svn
2012-03-22 17:40:18 +00:00
*/
2012-03-24 23:29:14 +00:00
protected function doAuthDance ()
2012-03-22 17:40:18 +00:00
{
2014-05-30 15:14:43 +00:00
// cannot ask for credentials in non interactive mode
if ( ! $this -> io -> isInteractive ()) {
throw new \RuntimeException (
'can not ask for authentication in non interactive mode'
);
}
2015-02-06 12:52:44 +00:00
$this -> io -> writeError ( " The Subversion server ( { $this -> url } ) requested credentials: " );
2012-03-22 17:40:18 +00:00
2012-03-24 22:05:13 +00:00
$this -> hasAuth = true ;
$this -> credentials [ 'username' ] = $this -> io -> ask ( " Username: " );
$this -> credentials [ 'password' ] = $this -> io -> askAndHideAnswer ( " Password: " );
2012-03-22 17:40:18 +00:00
2012-03-24 22:08:43 +00:00
$this -> cacheCredentials = $this -> io -> askConfirmation ( " Should Subversion cache these credentials? (yes/no) " , true );
2012-03-22 17:40:18 +00:00
return $this ;
}
2012-03-22 16:18:24 +00:00
/**
* A method to create the svn commands run .
*
* @ param string $cmd Usually 'svn ls' or something like that .
* @ param string $url Repo URL .
2012-03-24 23:29:14 +00:00
* @ param string $path Target for a checkout
2012-03-22 16:18:24 +00:00
*
* @ return string
*/
2012-03-24 23:29:14 +00:00
protected function getCommand ( $cmd , $url , $path = null )
2012-03-22 16:18:24 +00:00
{
$cmd = sprintf ( '%s %s%s %s' ,
$cmd ,
'--non-interactive ' ,
$this -> getCredentialString (),
2014-09-24 16:30:12 +00:00
ProcessExecutor :: escape ( $url )
2012-03-22 16:18:24 +00:00
);
2012-03-24 22:05:13 +00:00
if ( $path ) {
2014-09-24 16:30:12 +00:00
$cmd .= ' ' . ProcessExecutor :: escape ( $path );
2012-03-22 16:18:24 +00:00
}
2012-03-24 21:47:16 +00:00
2012-03-22 16:18:24 +00:00
return $cmd ;
}
/**
* Return the credential string for the svn command .
*
* Adds -- no - auth - cache when credentials are present .
*
* @ return string
*/
2012-03-24 23:29:14 +00:00
protected function getCredentialString ()
2012-03-22 16:18:24 +00:00
{
2012-03-24 22:05:13 +00:00
if ( ! $this -> hasAuth ()) {
2012-03-22 16:18:24 +00:00
return '' ;
}
2012-03-24 22:05:13 +00:00
2012-03-22 16:18:24 +00:00
return sprintf (
' %s--username %s --password %s ' ,
$this -> getAuthCache (),
2014-09-24 16:30:12 +00:00
ProcessExecutor :: escape ( $this -> getUsername ()),
ProcessExecutor :: escape ( $this -> getPassword ())
2012-03-22 16:18:24 +00:00
);
}
/**
* Get the password for the svn command . Can be empty .
*
* @ throws \LogicException
2015-09-28 09:51:14 +00:00
* @ return string
2012-03-22 16:18:24 +00:00
*/
2012-03-24 23:29:14 +00:00
protected function getPassword ()
2012-03-22 16:18:24 +00:00
{
if ( $this -> credentials === null ) {
2012-03-24 22:05:13 +00:00
throw new \LogicException ( " No svn auth detected. " );
2012-03-22 16:18:24 +00:00
}
2012-03-24 22:05:13 +00:00
return isset ( $this -> credentials [ 'password' ]) ? $this -> credentials [ 'password' ] : '' ;
2012-03-22 16:18:24 +00:00
}
/**
* Get the username for the svn command .
*
* @ throws \LogicException
2015-09-28 09:51:14 +00:00
* @ return string
2012-03-22 16:18:24 +00:00
*/
2012-03-24 23:29:14 +00:00
protected function getUsername ()
2012-03-22 16:18:24 +00:00
{
if ( $this -> credentials === null ) {
2012-03-24 22:05:13 +00:00
throw new \LogicException ( " No svn auth detected. " );
2012-03-22 16:18:24 +00:00
}
2012-03-24 22:05:13 +00:00
return $this -> credentials [ 'username' ];
2012-03-22 16:18:24 +00:00
}
/**
* Detect Svn Auth .
*
2012-06-23 09:58:18 +00:00
* @ return bool
2012-03-22 16:18:24 +00:00
*/
2012-03-24 23:29:14 +00:00
protected function hasAuth ()
2012-03-22 16:18:24 +00:00
{
2012-03-24 22:05:13 +00:00
if ( null !== $this -> hasAuth ) {
2012-03-22 16:18:24 +00:00
return $this -> hasAuth ;
}
2014-05-30 15:14:43 +00:00
if ( false === $this -> createAuthFromConfig ()) {
$this -> createAuthFromUrl ();
2012-03-22 16:18:24 +00:00
}
2014-05-30 15:14:43 +00:00
return $this -> hasAuth ;
2012-03-24 22:05:13 +00:00
}
/**
* Return the no - auth - cache switch .
*
* @ return string
*/
protected function getAuthCache ()
{
return $this -> cacheCredentials ? '' : '--no-auth-cache ' ;
2012-03-22 16:18:24 +00:00
}
2014-05-30 15:14:43 +00:00
/**
* Create the auth params from the configuration file .
*
* @ return bool
*/
2014-06-03 11:34:58 +00:00
private function createAuthFromConfig ()
2014-05-30 15:14:43 +00:00
{
if ( ! $this -> config -> has ( 'http-basic' )) {
return $this -> hasAuth = false ;
}
$authConfig = $this -> config -> get ( 'http-basic' );
2014-06-05 09:14:29 +00:00
$host = parse_url ( $this -> url , PHP_URL_HOST );
if ( isset ( $authConfig [ $host ])) {
$this -> credentials [ 'username' ] = $authConfig [ $host ][ 'username' ];
$this -> credentials [ 'password' ] = $authConfig [ $host ][ 'password' ];
2014-05-30 15:14:43 +00:00
return $this -> hasAuth = true ;
}
return $this -> hasAuth = false ;
}
/**
* Create the auth params from the url
*
* @ return bool
*/
2014-06-03 11:34:58 +00:00
private function createAuthFromUrl ()
2014-05-30 15:14:43 +00:00
{
$uri = parse_url ( $this -> url );
if ( empty ( $uri [ 'user' ])) {
return $this -> hasAuth = false ;
}
$this -> credentials [ 'username' ] = $uri [ 'user' ];
if ( ! empty ( $uri [ 'pass' ])) {
$this -> credentials [ 'password' ] = $uri [ 'pass' ];
}
return $this -> hasAuth = true ;
}
2012-05-22 10:07:08 +00:00
}