@ -25,9 +25,8 @@ import gcl
import gclient_utils
import gclient_utils
import scm
import scm
import presubmit_support
import presubmit_support
import upload
__version__ = ' 1. 1. 2'
__version__ = ' 1. 2'
# Constants
# Constants
@ -66,23 +65,6 @@ class NoTryServerAccess(Exception):
return self . args [ 0 ] + ' \n ' + HELP_STRING
return self . args [ 0 ] + ' \n ' + HELP_STRING
def PathDifference ( root , subpath ) :
""" Returns the difference subpath minus root. """
if subpath . find ( root ) != 0 :
return None
# If the root does not have a trailing \ or /, we add it so the returned path
# starts immediately after the seperator regardless of whether it is provided.
if not root . endswith ( os . sep ) :
root + = os . sep
return subpath [ len ( root ) : ]
def GetSourceRoot ( ) :
""" Returns the absolute directory one level up from the repository root. """
# TODO(maruel): This is odd to assume that '..' is the source root.
return os . path . abspath ( os . path . join ( gcl . GetRepositoryRoot ( ) , ' .. ' ) )
def GetTryServerSettings ( ) :
def GetTryServerSettings ( ) :
""" Grab try server settings local to the repository. """
""" Grab try server settings local to the repository. """
def _SafeResolve ( host ) :
def _SafeResolve ( host ) :
@ -124,61 +106,61 @@ class SCM(object):
def __init__ ( self , options ) :
def __init__ ( self , options ) :
self . options = options
self . options = options
def ProcessOptions ( self ) :
def GetFileNames ( self ) :
raise NotImplementedError
""" Return the list of files in the diff. """
return self . options . files
class SVN ( SCM ) :
class SVN ( SCM ) :
""" Gathers the options and diff for a subversion checkout. """
""" Gathers the options and diff for a subversion checkout. """
def GenerateDiff ( self , files , root ) :
def __init__ ( self , * args , * * kwargs ) :
SCM . __init__ ( self , * args , * * kwargs )
self . checkout_root = scm . SVN . GetCheckoutRoot ( os . getcwd ( ) )
self . options . files
if not self . options . diff :
# Generate the diff from the scm.
self . options . diff = self . _GenerateDiff ( )
if not self . options . email :
# Assumes the svn credential is an email address.
self . options . email = scm . SVN . GetEmail ( self . checkout_root )
def _GenerateDiff ( self ) :
""" Returns a string containing the diff for the given file list.
""" Returns a string containing the diff for the given file list.
The files in the list should either be absolute paths or relative to the
The files in the list should either be absolute paths or relative to the
given root . If no root directory is provided , the repository root will be
given root .
used .
"""
"""
previous_cwd = os . getcwd ( )
previous_cwd = os . getcwd ( )
os . chdir ( root or scm . SVN . GetCheckoutRoot ( previous_cwd ) )
os . chdir ( self . checkout_root )
if not self . options . files :
self . options . files = [ f [ 1 ] for f in scm . SVN . CaptureStatus ( None ) ]
# Directories will return None so filter them out.
# Directories will return None so filter them out.
diff = filter ( None , [ scm . SVN . DiffItem ( f ) for f in files ] )
diff = filter ( None , [ scm . SVN . DiffItem ( f ) for f in self . options . files ] )
os . chdir ( previous_cwd )
os . chdir ( previous_cwd )
return " " . join ( diff )
return " " . join ( diff )
def GetFileNames ( self ) :
""" Return the list of files in the diff. """
return self . change_info . GetFileNames ( )
def GetLocalRoot ( self ) :
def GetLocalRoot ( self ) :
""" Return the path of the repository root. """
""" Return the path of the repository root. """
return self . change_info . GetLocalRoot ( )
return self . checkout_root
def ProcessOptions ( self ) :
checkout_root = None
if not self . options . diff :
# Generate the diff with svn and write it to the submit queue path. The
# files are relative to the repository root, but we need patches relative
# to one level up from there (i.e., 'src'), so adjust both the file
# paths and the root of the diff.
# TODO(maruel): Remove this hack.
source_root = GetSourceRoot ( )
checkout_root = scm . SVN . GetCheckoutRoot ( os . getcwd ( ) )
prefix = PathDifference ( source_root , checkout_root )
adjusted_paths = [ os . path . join ( prefix , x ) for x in self . options . files ]
self . options . diff = self . GenerateDiff ( adjusted_paths , root = source_root )
self . change_info = gcl . LoadChangelistInfoForMultiple ( self . options . name ,
gcl . GetRepositoryRoot ( ) , True , True )
if not self . options . email :
checkout_root = checkout_root or scm . SVN . GetCheckoutRoot ( os . getcwd ( ) )
self . options . email = scm . SVN . GetEmail ( checkout_root )
class GIT ( SCM ) :
class GIT ( SCM ) :
""" Gathers the options and diff for a git checkout. """
""" Gathers the options and diff for a git checkout. """
def GenerateDiff ( self ) :
def __init__ ( self , * args , * * kwargs ) :
SCM . __init__ ( self , * args , * * kwargs )
self . checkout_root = os . path . abspath (
gclient_utils . CheckCall ( [ ' git ' , ' rev-parse ' , ' --show-cdup ' ] ) . strip ( ) )
if not self . options . diff :
self . options . diff = self . _GenerateDiff ( )
if not self . options . name :
self . options . name = self . _GetPatchName ( )
if not self . options . email :
self . options . email = scm . GIT . GetEmail ( ' . ' )
def _GenerateDiff ( self ) :
""" Get the diff we ' ll send to the try server. We ignore the files list. """
""" Get the diff we ' ll send to the try server. We ignore the files list. """
branch = upload . RunShell ( [ ' git ' , ' cl ' , ' upstream ' ] ) . strip ( )
branch = gclient_utils . CheckCall ( [ ' git ' , ' cl ' , ' upstream ' ] ) . strip ( )
diff = upload . RunShell ( [ ' git ' , ' diff-tree ' , ' -p ' , ' --no-prefix ' ,
diff = gclient_utils . CheckCall ( [ ' git ' , ' diff-tree ' , ' -p ' , ' --no-prefix ' ,
branch , ' HEAD ' ] ) . splitlines ( True )
branch , ' HEAD ' ] ) . splitlines ( True )
for i in range ( len ( diff ) ) :
for i in range ( len ( diff ) ) :
# In the case of added files, replace /dev/null with the path to the
# In the case of added files, replace /dev/null with the path to the
@ -187,34 +169,20 @@ class GIT(SCM):
diff [ i ] = ' --- %s ' % diff [ i + 1 ] [ 4 : ]
diff [ i ] = ' --- %s ' % diff [ i + 1 ] [ 4 : ]
return ' ' . join ( diff )
return ' ' . join ( diff )
def GetFileNames ( self ) :
def _GetPatchName ( self ) :
""" Return the list of files in the diff. """
return self . options . files
def GetLocalRoot ( self ) :
""" Return the path of the repository root. """
# TODO: check for errors here?
root = upload . RunShell ( [ ' git ' , ' rev-parse ' , ' --show-cdup ' ] ) . strip ( )
return os . path . abspath ( root )
def GetPatchName ( self ) :
""" Construct a name for this patch. """
""" Construct a name for this patch. """
# TODO: perhaps include the hash of the current commit, to distinguish
# TODO: perhaps include the hash of the current commit, to distinguish
# patches?
# patches?
branch = upload. RunShe ll( [ ' git ' , ' symbolic-ref ' , ' HEAD ' ] ) . strip ( )
branch = gclient_utils . CheckCall ( [ ' git ' , ' symbolic-ref ' , ' HEAD ' ] ) . strip ( )
if not branch . startswith ( ' refs/heads/ ' ) :
if not branch . startswith ( ' refs/heads/ ' ) :
# TODO(maruel): Find a better type.
# TODO(maruel): Find a better type.
raise NoTryServerAccess ( " Couldn ' t figure out branch name " )
raise NoTryServerAccess ( " Couldn ' t figure out branch name " )
branch = branch [ len ( ' refs/heads/ ' ) : ]
branch = branch [ len ( ' refs/heads/ ' ) : ]
return branch
return branch
def ProcessOptions ( self ) :
def GetLocalRoot ( self ) :
if not self . options . diff :
""" Return the path of the repository root. """
self . options . diff = self . GenerateDiff ( )
return self . checkout_root
if not self . options . name :
self . options . name = self . GetPatchName ( )
if not self . options . email :
self . options . email = scm . GIT . GetEmail ( ' . ' )
def _ParseSendChangeOptions ( options ) :
def _ParseSendChangeOptions ( options ) :
@ -365,17 +333,12 @@ def GuessVCS(options):
# Git has a command to test if you're in a git tree.
# Git has a command to test if you're in a git tree.
# Try running it, but don't die if we don't have git installed.
# Try running it, but don't die if we don't have git installed.
try :
try :
out , returncode = subprocess . Popen (
gclient_utils . CheckCall ( [ " git " , " rev-parse " , " --is-inside-work-tree " ] )
[ " git " , " rev-parse " , " --is-inside-work-tree " ] ,
shell = sys . platform . startswith ( ' win ' ) ,
stdout = subprocess . PIPE ) . communicate ( ) [ 0 ]
if returncode == 0 :
logging . info ( " Guessed VCS = Git " )
logging . info ( " Guessed VCS = Git " )
return GIT ( options )
return GIT ( options )
except OSError , ( errno , message ) :
except gclient_utils . CheckCallError , e :
if e rrno != 2 : # ENOENT -- they don't have git installed.
if e . retcode != 2 : # ENOENT -- they don't have git installed.
raise
raise
raise NoTryServerAccess ( " Could not guess version control system. "
raise NoTryServerAccess ( " Could not guess version control system. "
" Are you in a working copy directory? " )
" Are you in a working copy directory? " )
@ -520,7 +483,6 @@ def TryChange(argv,
# Process the VCS in any case at least to retrieve the email address.
# Process the VCS in any case at least to retrieve the email address.
try :
try :
options . scm = GuessVCS ( options )
options . scm = GuessVCS ( options )
options . scm . ProcessOptions ( )
except NoTryServerAccess , e :
except NoTryServerAccess , e :
# If we got the diff, we don't care.
# If we got the diff, we don't care.
if not options . diff :
if not options . diff :