@ -10,6 +10,7 @@ import logging
import os
import os
import re
import re
import sys
import sys
import tempfile
import time
import time
from xml . etree import ElementTree
from xml . etree import ElementTree
@ -779,19 +780,30 @@ class SVN(object):
expected relative path .
expected relative path .
full_move means that move or copy operations should completely recreate the
full_move means that move or copy operations should completely recreate the
files , usually in the prospect to apply the patch for a try job . """
files , usually in the prospect to apply the patch for a try job . """
# Use "svn info" output instead of os.path.isdir because the latter fails
# If the user specified a custom diff command in their svn config file,
# when the file is deleted.
# then it'll be used when we do svn diff, which we don't want to happen
return SVN . _DiffItemInternal (
# since we want the unified diff. Using --diff-cmd=diff doesn't always
filename ,
# work, since they can have another diff executable in their path that
cwd ,
# gives different line endings. So we use a bogus temp directory as the
SVN . CaptureLocalInfo ( [ filename ] , cwd ) ,
# config directory, which gets around these problems.
full_move ,
bogus_dir = tempfile . mkdtemp ( )
revision )
try :
# Use "svn info" output instead of os.path.isdir because the latter fails
# when the file is deleted.
return SVN . _DiffItemInternal (
filename ,
cwd ,
SVN . CaptureLocalInfo ( [ filename ] , cwd ) ,
bogus_dir ,
full_move ,
revision )
finally :
gclient_utils . RemoveDirectory ( bogus_dir )
@staticmethod
@staticmethod
def _DiffItemInternal ( filename , cwd , info , full_move , revision ) :
def _DiffItemInternal ( filename , cwd , info , bogus_dir, full_move, revision ) :
""" Grabs the diff data. """
""" Grabs the diff data. """
command = [ " diff " , " --internal-diff " , filename ]
command = [ " diff " , " -- config-dir" , bogus_dir , filename ]
if revision :
if revision :
command . extend ( [ ' --revision ' , revision ] )
command . extend ( [ ' --revision ' , revision ] )
data = None
data = None
@ -859,66 +871,76 @@ class SVN(object):
if os . path . normcase ( path ) . startswith ( root ) :
if os . path . normcase ( path ) . startswith ( root ) :
return path [ len ( root ) : ]
return path [ len ( root ) : ]
return path
return path
# Cleanup filenames
# If the user specified a custom diff command in their svn config file,
filenames = [ RelativePath ( f , root ) for f in filenames ]
# then it'll be used when we do svn diff, which we don't want to happen
# Get information about the modified items (files and directories)
# since we want the unified diff. Using --diff-cmd=diff doesn't always
data = dict ( [ ( f , SVN . CaptureLocalInfo ( [ f ] , root ) ) for f in filenames ] )
# work, since they can have another diff executable in their path that
diffs = [ ]
# gives different line endings. So we use a bogus temp directory as the
if full_move :
# config directory, which gets around these problems.
# Eliminate modified files inside moved/copied directory.
bogus_dir = tempfile . mkdtemp ( )
for ( filename , info ) in data . iteritems ( ) :
try :
if SVN . IsMovedInfo ( info ) and info . get ( " Node Kind " ) == " directory " :
# Cleanup filenames
# Remove files inside the directory.
filenames = [ RelativePath ( f , root ) for f in filenames ]
filenames = [ f for f in filenames
# Get information about the modified items (files and directories)
if not f . startswith ( filename + os . path . sep ) ]
data = dict ( [ ( f , SVN . CaptureLocalInfo ( [ f ] , root ) ) for f in filenames ] )
for filename in data . keys ( ) :
diffs = [ ]
if not filename in filenames :
if full_move :
# Remove filtered out items.
# Eliminate modified files inside moved/copied directory.
del data [ filename ]
for ( filename , info ) in data . iteritems ( ) :
else :
if SVN . IsMovedInfo ( info ) and info . get ( " Node Kind " ) == " directory " :
metaheaders = [ ]
# Remove files inside the directory.
for ( filename , info ) in data . iteritems ( ) :
filenames = [ f for f in filenames
if SVN . IsMovedInfo ( info ) :
if not f . startswith ( filename + os . path . sep ) ]
# for now, the most common case is a head copy,
for filename in data . keys ( ) :
# so let's just encode that as a straight up cp.
if not filename in filenames :
srcurl = info . get ( ' Copied From URL ' )
# Remove filtered out items.
file_root = info . get ( ' Repository Root ' )
del data [ filename ]
rev = int ( info . get ( ' Copied From Rev ' ) )
else :
assert srcurl . startswith ( file_root )
metaheaders = [ ]
src = srcurl [ len ( file_root ) + 1 : ]
for ( filename , info ) in data . iteritems ( ) :
try :
if SVN . IsMovedInfo ( info ) :
srcinfo = SVN . CaptureRemoteInfo ( srcurl )
# for now, the most common case is a head copy,
except subprocess2 . CalledProcessError , e :
# so let's just encode that as a straight up cp.
if not ' Not a valid URL ' in e . stderr :
srcurl = info . get ( ' Copied From URL ' )
raise
file_root = info . get ( ' Repository Root ' )
# Assume the file was deleted. No idea how to figure out at which
rev = int ( info . get ( ' Copied From Rev ' ) )
# revision the file was deleted.
assert srcurl . startswith ( file_root )
srcinfo = { ' Revision ' : rev }
src = srcurl [ len ( file_root ) + 1 : ]
if ( srcinfo . get ( ' Revision ' ) != rev and
try :
SVN . Capture ( [ ' diff ' , ' --internal-diff ' , ' -r ' , ' %d :head ' % rev ,
srcinfo = SVN . CaptureRemoteInfo ( srcurl )
srcurl ] , cwd ) ) :
except subprocess2 . CalledProcessError , e :
metaheaders . append ( " #$ svn cp -r %d %s %s "
if not ' Not a valid URL ' in e . stderr :
" ### WARNING: note non-trunk copy \n " %
raise
( rev , src , filename ) )
# Assume the file was deleted. No idea how to figure out at which
else :
# revision the file was deleted.
metaheaders . append ( " #$ cp %s %s \n " % ( src , filename ) )
srcinfo = { ' Revision ' : rev }
if ( srcinfo . get ( ' Revision ' ) != rev and
if metaheaders :
SVN . Capture ( [ ' diff ' , ' -r ' , ' %d :head ' % rev , srcurl ] , cwd ) ) :
diffs . append ( " ### BEGIN SVN COPY METADATA \n " )
metaheaders . append ( " #$ svn cp -r %d %s %s "
diffs . extend ( metaheaders )
" ### WARNING: note non-trunk copy \n " %
diffs . append ( " ### END SVN COPY METADATA \n " )
( rev , src , filename ) )
# Now ready to do the actual diff.
else :
for filename in sorted ( data . iterkeys ( ) ) :
metaheaders . append ( " #$ cp %s %s \n " % ( src ,
diffs . append ( SVN . _DiffItemInternal ( filename , cwd , data [ filename ] ,
filename ) )
full_move , revision ) )
# Use StringIO since it can be messy when diffing a directory move with
if metaheaders :
# full_move=True.
diffs . append ( " ### BEGIN SVN COPY METADATA \n " )
buf = cStringIO . StringIO ( )
diffs . extend ( metaheaders )
for d in filter ( None , diffs ) :
diffs . append ( " ### END SVN COPY METADATA \n " )
buf . write ( d )
# Now ready to do the actual diff.
result = buf . getvalue ( )
for filename in sorted ( data . iterkeys ( ) ) :
buf . close ( )
diffs . append ( SVN . _DiffItemInternal (
return result
filename , cwd , data [ filename ] , bogus_dir , full_move , revision ) )
# Use StringIO since it can be messy when diffing a directory move with
# full_move=True.
buf = cStringIO . StringIO ( )
for d in filter ( None , diffs ) :
buf . write ( d )
result = buf . getvalue ( )
buf . close ( )
return result
finally :
gclient_utils . RemoveDirectory ( bogus_dir )
@staticmethod
@staticmethod
def GetEmail ( cwd ) :
def GetEmail ( cwd ) :