llvm.org GIT mirror llvm / d403ad1
[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 Reid Kleckner 2 years ago
1 changed file(s) with 60 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
5050
5151 VERBOSE = False
5252 QUIET = False
53 dev_null_fd = None
5354
5455
5556 def eprint(*args, **kwargs):
8182 d = head
8283
8384
84 def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True):
85 def get_dev_null():
86 """Lazily create a /dev/null fd for use in shell()"""
87 global dev_null_fd
88 if dev_null_fd is None:
89 dev_null_fd = open(os.devnull, 'w')
90 return dev_null_fd
91
92
93 def shell(cmd, strip=True, cwd=None, stdin=None, die_on_failure=True,
94 ignore_errors=False):
8595 log_verbose('Running: %s' % ' '.join(cmd))
8696
97 err_pipe = subprocess.PIPE
98 if ignore_errors:
99 # Silence errors if requested.
100 err_pipe = get_dev_null()
101
87102 start = time.time()
88 p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE,
89 stderr=subprocess.PIPE, stdin=subprocess.PIPE)
103 p = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=err_pipe,
104 stdin=subprocess.PIPE)
90105 stdout, stderr = p.communicate(input=stdin)
91106 elapsed = time.time() - start
92107
93108 log_verbose('Command took %0.1fs' % elapsed)
94109
95 if p.returncode == 0:
96 if stderr:
110 if p.returncode == 0 or ignore_errors:
111 if stderr and not ignore_errors:
97112 eprint('`%s` printed to stderr:' % ' '.join(cmd))
98113 eprint(stderr.rstrip())
99114 if strip:
114129
115130 def svn(cwd, *cmd, **kwargs):
116131 # TODO: Better way to do default arg when we have *cmd?
117 return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None))
132 return shell(['svn'] + list(cmd), cwd=cwd, stdin=kwargs.get('stdin', None),
133 ignore_errors=kwargs.get('ignore_errors', None))
118134
119135
120136 def get_default_rev_range():
172188 die("Can't initialize svn staging dir (%s)" % svn_root)
173189
174190
191 def fix_eol_style_native(rev, sr, svn_sr_path):
192 """Fix line endings before applying patches with Unix endings
193
194 SVN on Windows will check out files with CRLF for files with the
195 svn:eol-style property set to "native". This breaks `git apply`, which
196 typically works with Unix-line ending patches. Work around the problem here
197 by doing a dos2unix up front for files with svn:eol-style set to "native".
198 SVN will not commit a mass line ending re-doing because it detects the line
199 ending format for files with this property.
200 """
201 files = git('diff-tree', '--no-commit-id', '--name-only', '-r', rev, '--',
202 sr).split('\n')
203 files = [f.split('/', 1)[1] for f in files]
204 # Use ignore_errors because 'svn propget' prints errors if the file doesn't
205 # have the named property. There doesn't seem to be a way to suppress that.
206 eol_props = svn(svn_sr_path, 'propget', 'svn:eol-style', *files,
207 ignore_errors=True).split('\n')
208 crlf_files = []
209 for eol_prop in eol_props:
210 if not eol_prop:
211 continue
212 prop_parts = eol_prop.rsplit(' - ', 1)
213 if len(prop_parts) != 2:
214 eprint("unable to parse svn propget line:")
215 eprint(eol_prop)
216 continue
217 (f, eol_style) = prop_parts
218 if eol_style == 'native':
219 crlf_files.append(f)
220 # Reformat all files with native SVN line endings to Unix format. SVN knows
221 # files with native line endings are text files. It will commit just the
222 # diff, and not a mass line ending change.
223 shell(['dos2unix', '-q'] + crlf_files, cwd=svn_sr_path)
224
225
175226 def svn_push_one_rev(svn_repo, rev, dry_run):
176227 files = git('diff-tree', '--no-commit-id', '--name-only', '-r',
177228 rev).split('\n')
185236 (rev, status))
186237
187238 for sr in subrepos:
239 svn_sr_path = os.path.join(svn_repo, GIT_TO_SVN_DIR[sr])
240 if os.name == 'nt':
241 fix_eol_style_native(rev, sr, svn_sr_path)
188242 diff = git('show', '--binary', rev, '--', sr, strip=False)
189 svn_sr_path = os.path.join(svn_repo, GIT_TO_SVN_DIR[sr])
190243 # git is the only thing that can handle its own patches...
191244 log_verbose('Apply patch: %s' % diff)
192245 try: