def generate_ifdefined(all_patches): """Update autogenerated ifdefined patches, which can be used to selectively disable features at compile time.""" enabled_patches = dict([(i, patch) for i, patch in all_patches.iteritems() if not patch.disabled]) for i, patch in enabled_patches.iteritems(): if patch.ifdefined is None: continue filename = os.path.join(patch.directory, config.path_IfDefined) with open(filename, "wb") as fp: fp.write("From: Wine Staging Team <*****@*****.**>\n") fp.write("Subject: Autogenerated #ifdef patch for %s.\n" % patch.name) fp.write("\n") depends = resolve_dependencies(enabled_patches, i) for f in patch.modified_files: # Reconstruct the state after applying the dependencies original = get_wine_file(f) for _, (_, p) in select_patches(enabled_patches, depends, f).iteritems(): original = patchutils.apply_patch(original, p, fuzz=0) # Now apply the main patch p = extract_patch(patch, f)[1] patched = patchutils.apply_patch(original, p, fuzz=0) # Now get the diff between both diff = patchutils.generate_ifdef_patch(original, patched, ifdef=patch.ifdefined) if diff is not None: fp.write("diff --git a/%s b/%s\n" % (f, f)) fp.write("--- a/%s\n" % f) fp.write("+++ b/%s\n" % f) while True: buf = diff.read(16384) if buf == "": break fp.write(buf) diff.close() # Close the file fp.close() # Add changes to git subprocess.call(["git", "add", filename]) # Add the autogenerated file as a last patch patch.files.append(os.path.basename(filename)) for p in patchutils.read_patch(filename): assert p.modified_file in patch.modified_files patch.patches.append(p)
def read_patchset(revision=None): """Read information about all patchsets for a specific revision.""" unique_id = itertools.count() all_patches = {} name_to_id = {} # Read in sorted order (to ensure created Makefile doesn't change too much) for name, directory in sorted( enum_directories(revision, config.path_patches)): patch = PatchSet(name, directory) if revision is None: # If its the latest revision, then request additional information if not os.path.isdir(directory): raise RuntimeError("Unable to open directory %s" % directory) # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): try: patch.depends, patch.fixes, patch.disabled, patch.ifdefined = \ read_definition(revision, os.path.join(config.path_patches, patch.name), name_to_id) except IOError: patch.depends, patch.fixes, patch.disabled, patch.ifdefined = set( ), [], False, None return all_patches
def generate_ifdefined(all_patches, skip_checks=False): """Update autogenerated ifdefined patches, which can be used to selectively disable features at compile time.""" for i, patch in all_patches.iteritems(): if patch.ifdefined is None: continue if patch.disabled: continue filename = os.path.join(patch.directory, config.path_IfDefined) headers = { 'author': "Wine Staging Team", 'email': "*****@*****.**", 'subject': "Autogenerated #ifdef patch for %s." % patch.name } if skip_checks: patch.files = [os.path.basename(filename)] continue with open(filename, "wb") as fp: fp.write("From: %s <%s>\n" % (headers['author'], headers['email'])) fp.write("Subject: %s\n" % headers['subject']) fp.write("\n") fp.write("Based on patches by:\n") for author, email in sorted(set([(p.patch_author, p.patch_email) for p in patch.patches])): fp.write(" %s <%s>\n" % (author, email)) fp.write("\n") depends = resolve_dependencies(all_patches, i) for f in sorted(patch.modified_files): # Reconstruct the state after applying the dependencies original = get_wine_file(f) selected_patches = select_patches(all_patches, depends, f) failed = [] try: for j in depends: failed.append(j) original = patchutils.apply_patch(original, selected_patches[j][1], fuzz=0) except patchutils.PatchApplyError: raise PatchUpdaterError("Changes to file %s don't apply: %s" % (f, ", ".join([all_patches[j].name for j in failed]))) # Now apply the main patch p = extract_patch(patch, f)[1] try: failed.append(i) patched = patchutils.apply_patch(original, p, fuzz=0) except patchutils.PatchApplyError: raise PatchUpdaterError("Changes to file %s don't apply: %s" % (f, ", ".join([all_patches[j].name for j in failed]))) # Now get the diff between both diff = patchutils.generate_ifdef_patch(original, patched, ifdef=patch.ifdefined) if diff is not None: fp.write("diff --git a/%s b/%s\n" % (f, f)) fp.write("--- a/%s\n" % f) fp.write("+++ b/%s\n" % f) while True: buf = diff.read(16384) if buf == "": break fp.write(buf) diff.close() # Close the file fp.close() # Add changes to git subprocess.call(["git", "add", filename]) # Add the autogenerated file as a last patch patch.files = [os.path.basename(filename)] for p in patch.patches: p.filename = None p.modified_file = None for p in patchutils.read_patch(filename): assert p.modified_file in patch.modified_files p.patch_author = None patch.patches.append(p)
def load_patchsets(): """Read information about all patchsets.""" unique_id = itertools.count() all_patches = {} name_to_id = {} for name, directory in enum_patchsets(config.path_patches): patch = PatchSet(name, directory) # Load the definition file try: with open(os.path.join(directory, "definition")) as fp: for line in fp: if line.startswith("#"): continue tmp = line.split(":", 1) if len(tmp) != 2: continue patch.config.append((tmp[0].lower(), tmp[1].strip())) except IOError: pass # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if ("exclude", f) in patch.config: continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): for key, val in patch.config: if key == "depends": if not name_to_id.has_key(val): raise PatchUpdaterError("Definition file for %s references unknown dependency %s" % (patch.name, val)) patch.depends.add(name_to_id[val]) elif key == "apply-after": for j, other_patch in all_patches.iteritems(): if i != j and any([fnmatch.fnmatch(f, val) for f in other_patch.modified_files]): patch.auto_depends.add(j) elif key == "apply-before": for j, other_patch in all_patches.iteritems(): if i != j and any([fnmatch.fnmatch(f, val) for f in other_patch.modified_files]): other_patch.auto_depends.add(i) elif key == "fixes": r = re.match("^\\[ *(!)? *([0-9]+) *\\](.*)$", val) if r: sync = (r.group(1) != "!") bugid = int(r.group(2)) patch.fixes.append((sync, bugid, r.group(3).strip())) continue patch.fixes.append((False, None, val)) elif key == "disabled": patch.disabled = _parse_int(val) elif key == "exclude": pass # Already processed above elif key == "ifdefined": patch.ifdefined = val else: print "WARNING: Ignoring unknown command in definition file for %s: %s" % (patch.name, line) # Filter autodepends on disabled patchsets for i, patch in all_patches.iteritems(): patch.auto_depends = set([j for j in patch.auto_depends if not all_patches[j].disabled]) return all_patches
def generate_ifdefined(all_patches, skip_checks=False): """Update autogenerated ifdefined patches, which can be used to selectively disable features at compile time.""" enabled_patches = dict([(i, patch) for i, patch in all_patches.iteritems() if not patch.disabled]) for i, patch in enabled_patches.iteritems(): if patch.ifdefined is None: continue filename = os.path.join(patch.directory, config.path_IfDefined) headers = { 'author': "Wine Staging Team", 'email': "*****@*****.**", 'subject': "Autogenerated #ifdef patch for %s." % patch.name } if skip_checks: patch.files = [os.path.basename(filename)] continue with open(filename, "wb") as fp: fp.write("From: %s <%s>\n" % (headers['author'], headers['email'])) fp.write("Subject: %s\n" % headers['subject']) fp.write("\n") fp.write("Based on patches by:\n") for author, email in sorted(set([(p.patch_author, p.patch_email) for p in patch.patches])): fp.write(" %s <%s>\n" % (author, email)) fp.write("\n") depends = resolve_dependencies(enabled_patches, i) for f in sorted(patch.modified_files): # Reconstruct the state after applying the dependencies original = get_wine_file(f) selected_patches = select_patches(enabled_patches, depends, f) failed = [] try: for j in depends: failed.append(j) original = patchutils.apply_patch(original, selected_patches[j][1], fuzz=0) except patchutils.PatchApplyError: raise PatchUpdaterError("Changes to file %s don't apply: %s" % (f, ", ".join([all_patches[j].name for j in failed]))) # Now apply the main patch p = extract_patch(patch, f)[1] try: failed.append(i) patched = patchutils.apply_patch(original, p, fuzz=0) except patchutils.PatchApplyError: raise PatchUpdaterError("Changes to file %s don't apply: %s" % (f, ", ".join([all_patches[j].name for j in failed]))) # Now get the diff between both diff = patchutils.generate_ifdef_patch(original, patched, ifdef=patch.ifdefined) if diff is not None: fp.write("diff --git a/%s b/%s\n" % (f, f)) fp.write("--- a/%s\n" % f) fp.write("+++ b/%s\n" % f) while True: buf = diff.read(16384) if buf == "": break fp.write(buf) diff.close() # Close the file fp.close() # Add changes to git subprocess.call(["git", "add", filename]) # Add the autogenerated file as a last patch patch.files = [os.path.basename(filename)] for p in patch.patches: p.filename = None p.modified_file = None for p in patchutils.read_patch(filename): assert p.modified_file in patch.modified_files p.patch_author = None patch.patches.append(p)
def load_patchsets(): """Read information about all patchsets.""" unique_id = itertools.count() all_patches = {} name_to_id = {} categories = {} for name, directory in enum_patchsets(config.path_patches): patch = PatchSet(name, directory) # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): filename = os.path.join(os.path.join(config.path_patches, patch.name), "definition") try: with open(filename) as fp: content = fp.read() except IOError: continue # Skip this definition file for line in content.split("\n"): if line.startswith("#"): continue tmp = line.split(":", 1) if len(tmp) != 2: continue key, val = tmp[0].lower(), tmp[1].strip() if key == "depends": if not name_to_id.has_key(val): raise PatchUpdaterError("Definition file %s references unknown dependency %s" % (filename, val)) patch.depends.add(name_to_id[val]) elif key == "apply-after": for j, other_patch in all_patches.iteritems(): if i != j and any([fnmatch.fnmatch(f, val) for f in other_patch.modified_files]): patch.auto_depends.add(j) elif key == "apply-before": for j, other_patch in all_patches.iteritems(): if i != j and any([fnmatch.fnmatch(f, val) for f in other_patch.modified_files]): other_patch.auto_depends.add(i) elif key == "category": val = "category-%s" % val if name_to_id.has_key(val): raise PatchUpdaterError("Category name in definition file %s collides with patchset %s" % (filename, val)) patch.categories.append(val) elif key == "fixes": r = re.match("^\\[ *(!)? *([0-9]+) *\\](.*)$", val) if r: sync = (r.group(1) != "!") bugid = int(r.group(2)) patch.fixes.append((sync, bugid, r.group(3).strip())) continue patch.fixes.append((False, None, val)) elif key == "disabled": patch.disabled = _parse_int(val) elif key == "ifdefined": patch.ifdefined = val else: print "WARNING: Ignoring unknown command in definition file %s: %s" % (filename, line) # If patch is not disabled then finally add it to the category if patch.disabled: continue for category in patch.categories: if not categories.has_key(category): categories[category] = set() categories[category].add(i) # Filter autodepends on disabled patchsets for i, patch in all_patches.iteritems(): patch.auto_depends = set([j for j in patch.auto_depends if not all_patches[j].disabled]) # Add virtual targets for all the categories for category, indices in categories.iteritems(): patch = PatchSet(category, directory) patch.is_category = True patch.depends = indices i = next(unique_id) all_patches[i] = patch name_to_id[name] = i return all_patches
def read_patchset(revision = None): """Read information about all patchsets for a specific revision.""" unique_id = itertools.count() all_patches = {} name_to_id = {} all_bugids = set() categories = {} # Read in sorted order (to ensure created Makefile doesn't change too much) for name, directory in sorted(enum_directories(revision, config.path_patches)): patch = PatchSet(name, directory) if revision is None: # If its the latest revision, then request additional information if not os.path.isdir(directory): raise RuntimeError("Unable to open directory %s" % directory) # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): try: filename = os.path.join(os.path.join(config.path_patches, patch.name), "definition") if revision is None: with open(filename) as fp: content = fp.read() else: filename = "%s:%s" % (revision, filename) content = subprocess.check_output(["git", "show", filename], stderr=_devnull) except (IOError, subprocess.CalledProcessError): continue # Skip this definition file for line in content.split("\n"): if line.startswith("#"): continue tmp = line.split(":", 1) if len(tmp) != 2: continue key, val = tmp[0].lower(), tmp[1].strip() if key == "depends": if not name_to_id.has_key(val): raise PatchUpdaterError("Definition file %s references unknown dependency %s" % (filename, val)) patch.depends.add(name_to_id[val]) elif key == "apply-after": for j, other_patch in all_patches.iteritems(): if i != j and any([fnmatch.fnmatch(f, val) for f in other_patch.modified_files]): patch.auto_depends.add(j) elif key == "category": val = "category-%s" % val if name_to_id.has_key(val): raise PatchUpdaterError("Category name in definition file %s collides with patchset %s" % (filename, val)) patch.categories.append(val) elif key == "fixes": r = re.match("^[0-9]+$", val) if r: bugid = int(val) patch.fixes.append((bugid, None)) all_bugids.add(bugid) continue r = re.match("^\\[ *([0-9]+) *\\](.*)$", val) if r: bugid = int(r.group(1)) patch.fixes.append((bugid, r.group(2).strip())) all_bugids.add(bugid) continue patch.fixes.append((None, val)) elif key == "disabled": patch.disabled = _parse_int(val) elif key == "ifdefined": patch.ifdefined = val elif revision is None: print "WARNING: Ignoring unknown command in definition file %s: %s" % (filename, line) # If patch is not disabled then finally add it to the category if not patch.disabled: for category in patch.categories: if not categories.has_key(category): categories[category] = set() categories[category].add(i) # Add virtual targets for all the categories for category, indices in categories.iteritems(): patch = PatchSet(category, directory) patch.is_category = True patch.depends = indices i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # To simplify the task of keeping the bug list up-to-date, list all bugs # which might require attention. if revision is None: once = True for bugid, bug in sorted(_winebugs_query(all_bugids).items()): if bug['bug_status'] not in ["UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED"]: if once: print "" print "WARNING: The following bugs might require attention:" print "" once = False print " #%d - \"%s\" - %s %s" % (bugid, bug['short_desc'], bug['bug_status'], bug['resolution'] if bug['resolution'] else "") print "" return all_patches
def read_patchset(revision=None): """Read information about all patchsets for a specific revision.""" unique_id = itertools.count() all_patches = {} name_to_id = {} all_bugids = set() categories = {} # Read in sorted order (to ensure created Makefile doesn't change too much) for name, directory in sorted( enum_directories(revision, config.path_patches)): patch = PatchSet(name, directory) if revision is None: # If its the latest revision, then request additional information if not os.path.isdir(directory): raise RuntimeError("Unable to open directory %s" % directory) # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): try: filename = os.path.join( os.path.join(config.path_patches, patch.name), "definition") if revision is None: with open(filename) as fp: content = fp.read() else: filename = "%s:%s" % (revision, filename) content = subprocess.check_output(["git", "show", filename], stderr=_devnull) except (IOError, subprocess.CalledProcessError): continue # Skip this definition file for line in content.split("\n"): if line.startswith("#"): continue tmp = line.split(":", 1) if len(tmp) != 2: continue key, val = tmp[0].lower(), tmp[1].strip() if key == "depends": if not name_to_id.has_key(val): raise PatchUpdaterError( "Definition file %s references unknown dependency %s" % (filename, val)) patch.depends.add(name_to_id[val]) elif key == "apply-after": for j, other_patch in all_patches.iteritems(): if i != j and any([ fnmatch.fnmatch(f, val) for f in other_patch.modified_files ]): patch.auto_depends.add(j) elif key == "apply-before": for j, other_patch in all_patches.iteritems(): if i != j and any([ fnmatch.fnmatch(f, val) for f in other_patch.modified_files ]): other_patch.auto_depends.add(i) elif key == "category": val = "category-%s" % val if name_to_id.has_key(val): raise PatchUpdaterError( "Category name in definition file %s collides with patchset %s" % (filename, val)) patch.categories.append(val) elif key == "fixes": r = re.match("^[0-9]+$", val) if r: bugid = int(val) patch.fixes.append((bugid, None)) all_bugids.add(bugid) continue r = re.match("^\\[ *([0-9]+) *\\](.*)$", val) if r: bugid = int(r.group(1)) patch.fixes.append((bugid, r.group(2).strip())) all_bugids.add(bugid) continue patch.fixes.append((None, val)) elif key == "disabled": patch.disabled = _parse_int(val) elif key == "ifdefined": patch.ifdefined = val elif revision is None: print "WARNING: Ignoring unknown command in definition file %s: %s" % ( filename, line) # If patch is not disabled then finally add it to the category if not patch.disabled: for category in patch.categories: if not categories.has_key(category): categories[category] = set() categories[category].add(i) # Add virtual targets for all the categories for category, indices in categories.iteritems(): patch = PatchSet(category, directory) patch.is_category = True patch.depends = indices i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # To simplify the task of keeping the bug list up-to-date, list all bugs # which might require attention. if revision is None: once = True for bugid, bug in sorted(_winebugs_query(all_bugids).items()): if bug['bug_status'] not in [ "UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED" ]: if once: print "" print "WARNING: The following bugs might require attention:" print "" once = False print " #%d - \"%s\" - %s %s" % ( bugid, bug['short_desc'], bug['bug_status'], bug['resolution'] if bug['resolution'] else "") print "" return all_patches
def load_patchsets(): """Read information about all patchsets.""" unique_id = itertools.count() all_patches = {} name_to_id = {} categories = {} for name, directory in enum_patchsets(config.path_patches): patch = PatchSet(name, directory) # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): filename = os.path.join(os.path.join(config.path_patches, patch.name), "definition") try: with open(filename) as fp: content = fp.read() except IOError: continue # Skip this definition file for line in content.split("\n"): if line.startswith("#"): continue tmp = line.split(":", 1) if len(tmp) != 2: continue key, val = tmp[0].lower(), tmp[1].strip() if key == "depends": if not name_to_id.has_key(val): raise PatchUpdaterError( "Definition file %s references unknown dependency %s" % (filename, val)) patch.depends.add(name_to_id[val]) elif key == "apply-after": for j, other_patch in all_patches.iteritems(): if i != j and any([ fnmatch.fnmatch(f, val) for f in other_patch.modified_files ]): patch.auto_depends.add(j) elif key == "apply-before": for j, other_patch in all_patches.iteritems(): if i != j and any([ fnmatch.fnmatch(f, val) for f in other_patch.modified_files ]): other_patch.auto_depends.add(i) elif key == "category": val = "category-%s" % val if name_to_id.has_key(val): raise PatchUpdaterError( "Category name in definition file %s collides with patchset %s" % (filename, val)) patch.categories.append(val) elif key == "fixes": r = re.match("^\\[ *(!)? *([0-9]+) *\\](.*)$", val) if r: sync = (r.group(1) != "!") bugid = int(r.group(2)) patch.fixes.append((sync, bugid, r.group(3).strip())) continue patch.fixes.append((False, None, val)) elif key == "disabled": patch.disabled = _parse_int(val) elif key == "ifdefined": patch.ifdefined = val else: print "WARNING: Ignoring unknown command in definition file %s: %s" % ( filename, line) # If patch is not disabled then finally add it to the category if patch.disabled: continue for category in patch.categories: if not categories.has_key(category): categories[category] = set() categories[category].add(i) # Filter autodepends on disabled patchsets for i, patch in all_patches.iteritems(): patch.auto_depends = set( [j for j in patch.auto_depends if not all_patches[j].disabled]) # Add virtual targets for all the categories for category, indices in categories.iteritems(): patch = PatchSet(category, directory) patch.is_category = True patch.depends = indices i = next(unique_id) all_patches[i] = patch name_to_id[name] = i return all_patches
def read_patchset(revision=None): """Read information about all patchsets for a specific revision.""" unique_id = itertools.count() all_patches = {} name_to_id = {} # Read in sorted order (to ensure created Makefile doesn't change too much) for name, directory in sorted( enum_directories(revision, config.path_patches)): patch = PatchSet(name, directory) if revision is None: # If its the latest revision, then request additional information if not os.path.isdir(directory): raise RuntimeError("Unable to open directory %s" % directory) # Enumerate .patch files in the given directory, enumerate individual patches and affected files for f in sorted(os.listdir(directory)): if not re.match("^[0-9]{4}-.*\\.patch$", f): continue if f.startswith(config.path_IfDefined): continue if not os.path.isfile(os.path.join(directory, f)): continue patch.files.append(f) for p in patchutils.read_patch(os.path.join(directory, f)): patch.modified_files.add(p.modified_file) patch.patches.append(p) # No single patch within this directory, ignore it if len(patch.patches) == 0: del patch continue i = next(unique_id) all_patches[i] = patch name_to_id[name] = i # Now read the definition files in a second step for i, patch in all_patches.iteritems(): try: filename = os.path.join( os.path.join(config.path_patches, patch.name), "definition") if revision is None: with open(filename) as fp: content = fp.read() else: filename = "%s:%s" % (revision, filename) content = subprocess.check_output(["git", "show", filename], stderr=_devnull) except (IOError, subprocess.CalledProcessError): continue # Skip this definition file for line in content.split("\n"): if line.startswith("#"): continue tmp = line.split(":", 1) if len(tmp) != 2: continue key, val = tmp[0].lower(), tmp[1].strip() if key == "depends": if not name_to_id.has_key(val): raise PatchUpdaterError( "Definition file %s references unknown dependency %s" % (filename, val)) patch.depends.add(name_to_id[val]) elif key == "apply-after": for j, other_patch in all_patches.iteritems(): if i != j and any([ fnmatch.fnmatch(f, val) for f in other_patch.modified_files ]): patch.auto_depends.add(j) elif key == "fixes": r = re.match("^[0-9]+$", val) if r: patch.fixes.append((int(val), None)) continue r = re.match("^\\[ *([0-9]+) *\\](.*)$", val) if r: patch.fixes.append((int(r.group(1)), r.group(2).strip())) continue patch.fixes.append((None, val)) elif key == "disabled": patch.disabled = _parse_int(val) elif key == "ifdefined": patch.ifdefined = val elif revision is None: print "WARNING: Ignoring unknown command in definition file %s: %s" % ( filename, line) return all_patches