[PATCH] D32452: [git-llvm] Make `push` work on CRLF files with svn:eol-style=native

Reid Kleckner via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 24 13:58:25 PDT 2017


rnk created this revision.

`git apply` on Windows doesn't work right now 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 mass
reformatting, it knows the file is a text file because of the
svn:eol-style property.


https://reviews.llvm.org/D32452

Files:
  llvm/utils/git-svn/git-llvm


Index: llvm/utils/git-svn/git-llvm
===================================================================
--- llvm/utils/git-svn/git-llvm
+++ llvm/utils/git-svn/git-llvm
@@ -82,19 +82,25 @@
         d = head
 
 
-def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True):
+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 = open(os.devnull, 'w')
+
     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 +121,8 @@
 
 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 +180,34 @@
         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:
+        (f, eol_style) = eol_prop.strip().split(' - ')
+        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 +221,10 @@
             (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:


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D32452.96465.patch
Type: text/x-patch
Size: 3826 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170424/491d9cab/attachment.bin>


More information about the llvm-commits mailing list