summaryrefslogtreecommitdiff
path: root/utils/git-svn
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2017-04-24 22:09:08 +0000
committerReid Kleckner <rnk@google.com>2017-04-24 22:09:08 +0000
commitd403ad1ed05397955873db29b9e3fc3e4e89a2bd (patch)
tree7dfce6e59228be2dad181ff9a89cfa22530be431 /utils/git-svn
parent87f63fed9365450f3e11256241a3f3538fe0d4f6 (diff)
[git-llvm] Make `push` work on CRLF files with svn:eol-style=native
Summary: `git apply` on Windows doesn't work for files that SVN checks out as CRLF. There is no way to force SVN to check everything out with Unix line endings on Windows. Files with svn:eol-style=native will always come out with CRLF, breaking `git apply`, which wants Unix line endings. My workaround is to list all files with this property set in the change, and run `dos2unix` on them. SVN doesn't commit a massive line ending change because the svn:eol-style property indicates that these are text files. Tested on r301245. Reviewers: zturner, jlebar Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32452 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301262 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/git-svn')
-rwxr-xr-xutils/git-svn/git-llvm67
1 files changed, 60 insertions, 7 deletions
diff --git a/utils/git-svn/git-llvm b/utils/git-svn/git-llvm
index 3dd3ff7dc39..8d427860a39 100755
--- a/utils/git-svn/git-llvm
+++ b/utils/git-svn/git-llvm
@@ -51,6 +51,7 @@ GIT_TO_SVN_DIR.update({'clang': 'cfe/trunk'})
VERBOSE = False
QUIET = False
+dev_null_fd = None
def eprint(*args, **kwargs):
@@ -82,19 +83,33 @@ def first_dirname(d):
d = head
-def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True):
+def get_dev_null():
+ """Lazily create a /dev/null fd for use in shell()"""
+ global dev_null_fd
+ if dev_null_fd is None:
+ dev_null_fd = open(os.devnull, 'w')
+ return dev_null_fd
+
+
+def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True,
+ ignore_errors=False):
log_verbose('Running: %s' % ' '.join(cmd))
+ err_pipe = subprocess.PIPE
+ if ignore_errors:
+ # Silence errors if requested.
+ err_pipe = get_dev_null()
+
start = time.time()
- p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, stdin=subprocess.PIPE)
+ p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=err_pipe,
+ stdin=subprocess.PIPE)
stdout, stderr = p.communicate(input=stdin)
elapsed = time.time() - start
log_verbose('Command took %0.1fs' % elapsed)
- if p.returncode == 0:
- if stderr:
+ if p.returncode == 0 or ignore_errors:
+ if stderr and not ignore_errors:
eprint('`%s` printed to stderr:' % ' '.join(cmd))
eprint(stderr.rstrip())
if strip:
@@ -115,7 +130,8 @@ def git(*cmd, **kwargs):
def svn(cwd, *cmd, **kwargs):
# TODO: Better way to do default arg when we have *cmd?
- return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None))
+ return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None),
+ ignore_errors=kwargs.get('ignore_errors', None))
def get_default_rev_range():
@@ -173,6 +189,41 @@ def svn_init(svn_root):
die("Can't initialize svn staging dir (%s)" % svn_root)
+def fix_eol_style_native(rev, sr, svn_sr_path):
+ """Fix line endings before applying patches with Unix endings
+
+ SVN on Windows will check out files with CRLF for files with the
+ svn:eol-style property set to "native". This breaks `git apply`, which
+ typically works with Unix-line ending patches. Work around the problem here
+ by doing a dos2unix up front for files with svn:eol-style set to "native".
+ SVN will not commit a mass line ending re-doing because it detects the line
+ ending format for files with this property.
+ """
+ files = git('diff-tree', '--no-commit-id', '--name-only', '-r', rev, '--',
+ sr).split('\n')
+ files = [f.split('/', 1)[1] for f in files]
+ # Use ignore_errors because 'svn propget' prints errors if the file doesn't
+ # have the named property. There doesn't seem to be a way to suppress that.
+ eol_props = svn(svn_sr_path, 'propget', 'svn:eol-style', *files,
+ ignore_errors=True).split('\n')
+ crlf_files = []
+ for eol_prop in eol_props:
+ if not eol_prop:
+ continue
+ prop_parts = eol_prop.rsplit(' - ', 1)
+ if len(prop_parts) != 2:
+ eprint("unable to parse svn propget line:")
+ eprint(eol_prop)
+ continue
+ (f, eol_style) = prop_parts
+ if eol_style == 'native':
+ crlf_files.append(f)
+ # Reformat all files with native SVN line endings to Unix format. SVN knows
+ # files with native line endings are text files. It will commit just the
+ # diff, and not a mass line ending change.
+ shell(['dos2unix', '-q'] + crlf_files, cwd=svn_sr_path)
+
+
def svn_push_one_rev(svn_repo, rev, dry_run):
files = git('diff-tree', '--no-commit-id', '--name-only', '-r',
rev).split('\n')
@@ -186,8 +237,10 @@ def svn_push_one_rev(svn_repo, rev, dry_run):
(rev, status))
for sr in subrepos:
- diff = git('show', '--binary', rev, '--', sr, strip=False)
svn_sr_path = os.path.join(svn_repo, GIT_TO_SVN_DIR[sr])
+ if os.name == 'nt':
+ fix_eol_style_native(rev, sr, svn_sr_path)
+ diff = git('show', '--binary', rev, '--', sr, strip=False)
# git is the only thing that can handle its own patches...
log_verbose('Apply patch: %s' % diff)
try: