diff --git a/script/lib/git.py b/script/lib/git.py index cc82ec9c1076..0edcd98ea025 100644 --- a/script/lib/git.py +++ b/script/lib/git.py @@ -47,7 +47,7 @@ def get_repo_root(path): def am(repo, patch_data, threeway=False, directory=None, exclude=None, - committer_name=None, committer_email=None): + committer_name=None, committer_email=None, keep_cr=True): args = [] if threeway: args += ['--3way'] @@ -56,6 +56,10 @@ def am(repo, patch_data, threeway=False, directory=None, exclude=None, if exclude is not None: for path_pattern in exclude: args += ['--exclude', path_pattern] + if keep_cr is True: + # Keep the CR of CRLF in case any patches target files with Windows line + # endings. + args += ['--keep-cr'] root_args = ['-C', repo] if committer_name is not None: @@ -230,7 +234,9 @@ def split_patches(patch_data): """Split a concatenated series of patches into N separate patches""" patches = [] patch_start = re.compile('^From [0-9a-f]+ ') - for line in patch_data.splitlines(): + # Keep line endings in case any patches target files with CRLF. + keep_line_endings = True + for line in patch_data.splitlines(keep_line_endings): if patch_start.match(line): patches.append([]) patches[-1].append(line) @@ -246,13 +252,23 @@ def munge_subject_to_filename(subject): def get_file_name(patch): """Return the name of the file to which the patch should be written""" + file_name = None for line in patch: if line.startswith('Patch-Filename: '): - return line[len('Patch-Filename: '):] + file_name = line[len('Patch-Filename: '):] + break # If no patch-filename header, munge the subject. - for line in patch: - if line.startswith('Subject: '): - return munge_subject_to_filename(line[len('Subject: '):]) + if not file_name: + for line in patch: + if line.startswith('Subject: '): + file_name = munge_subject_to_filename(line[len('Subject: '):]) + break + return file_name.rstrip('\n') + + +def join_patch(patch): + """Joins and formats patch contents""" + return ''.join(remove_patch_filename(patch)).rstrip('\n') + '\n' def remove_patch_filename(patch): @@ -294,10 +310,8 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False): for patch in patches: filename = get_file_name(patch) filepath = posixpath.join(out_dir, filename) - existing_patch = io.open(filepath, 'r', encoding='utf-8').read() - formatted_patch = ( - '\n'.join(remove_patch_filename(patch)).rstrip('\n') + '\n' - ) + existing_patch = io.open(filepath, 'rb').read() + formatted_patch = join_patch(patch) if formatted_patch != existing_patch: patch_count += 1 if patch_count > 0: @@ -322,12 +336,11 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False): for patch in patches: filename = get_file_name(patch) file_path = posixpath.join(out_dir, filename) - formatted_patch = ( - '\n'.join(remove_patch_filename(patch)).rstrip('\n') + '\n' - ) + formatted_patch = join_patch(patch) + # Write in binary mode to retain mixed line endings on write. with io.open( - file_path, 'w', newline='\n', encoding='utf-8' + file_path, 'wb' ) as f: - f.write(formatted_patch) + f.write(formatted_patch.encode('utf-8')) pl.write(filename + '\n') diff --git a/script/lint.js b/script/lint.js index 70f6a51693f7..a194aacb7b76 100755 --- a/script/lint.js +++ b/script/lint.js @@ -207,7 +207,7 @@ const LINTERS = [{ console.warn(`Patch file '${f}' has no description. Every patch must contain a justification for why the patch exists and the plan for its removal.`); return false; } - const trailingWhitespace = patchText.split('\n').filter(line => line.startsWith('+')).some(line => /\s+$/.test(line)); + const trailingWhitespace = patchText.split(/\r?\n/).some(line => line.startsWith('+') && /\s+$/.test(line)); if (trailingWhitespace) { console.warn(`Patch file '${f}' has trailing whitespace on some lines.`); return false;