Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
codemod: prefix MIT Rust libraries with "sapling-"
Summary: Prefix with `sapling-` so we can publish the crates without worrying much about conflicting. `features`, `dependencies` in `Cargo.toml` are updated too. `streampager` is prefixed too so it does not conflict with upstream. This is done by the script: ```python import ast, copy, glob, json, os, re, sys from collections import defaultdict from functools import partial class Ignored: def __getattr__(self, _name): return Ignored() def __call__(self, *args, **kwargs): return Ignored() def __add__(self, _rhs): return Ignored() def __getitem__(self, _name): return Ignored() def parse_targets(code, path): """extract rust_library infos from TARGET files""" result = [] def rust_library(**kwargs): line_no = sys._getframe(1).f_lineno result.append( { "autocargo": kwargs.get("autocargo") or {}, "name": kwargs.get("crate") or kwargs.get("name"), "line": line_no, } ) locals = defaultdict(Ignored) locals.update( { "rust_library": rust_library, "rust_python_library": rust_library, "hg_binary": rust_library, "glob": (lambda *a, **k: []), "get_oss_suffix": (lambda: ""), } ) try: exec(code, globals(), locals) except Exception: print(f'When processing {path}') raise return result def rewrite_arg(code, line_no, arg_name, arg_value): """rewrite an argument from a function call""" lines = code.splitlines(True) # assuming `code` is formatted, find "{arg_name} = " range for start_line_no in range(line_no, len(lines)): if f"{arg_name} = " in lines[start_line_no]: break else: lines.insert(line_no + 1, f"{arg_name} = {repr(arg_value)},\n") new_code = "".join(lines) return new_code for end_line_no in range(start_line_no + 1, len(lines)): test_code = "f(\n" + "".join(lines[start_line_no:end_line_no]) + "\n)" try: ast.parse(test_code) except Exception: continue new_code = ( "".join(lines[:start_line_no]) + f"{arg_name} = {repr(arg_value)},\n" + "".join(lines[end_line_no:]) ) return new_code else: raise RuntimeError("did not find the matching end-line") def prefix_name_autocargo(autocargo, name): if "cargo_toml_config" not in autocargo: autocargo["cargo_toml_config"] = {} for key in ["package", "lib"]: if key not in autocargo["cargo_toml_config"]: autocargo["cargo_toml_config"][key] = {} autocargo["cargo_toml_config"]["package"]["name"] = "sapling-" + name autocargo["cargo_toml_config"]["lib"]["name"] = name def _rewrite_dep(override, renamed): for key in ("dependencies", "dev-dependencies"): if key in override: old_value = override[key] new_value = {renamed.get(k) or k: v for k, v in old_value.items()} override[key] = new_value def update_dep_overrides_autocargo(autocargo, renamed): orig_autocargo = copy.deepcopy(autocargo) override = (autocargo.get("cargo_toml_config") or {}).get("dependencies_override") or {} _rewrite_dep(override, renamed) target = override.get("target") if target is not None: for key, value in target.items(): _rewrite_dep(value, renamed) # features def rewrite_feature(name, all_feature_names): if "/" in name: left, right = name.split("/", 1) return "%s/%s" % (renamed.get(left) or left, right) elif name.startswith("dep:"): rest = name.split(":", 1)[1] return "dep:%s" % (renamed.get(rest) or rest,) elif name in all_feature_names: return name else: return renamed.get(name) or name features = (autocargo.get("cargo_toml_config") or {}).get("features") or {} all_feature_names = set(features) for name, values in features.items(): new_values = [rewrite_feature(v, all_feature_names) for v in values] features[name] = new_values changed = orig_autocargo != autocargo return changed def main(): renamed = {} # First pass - rename for path in glob.glob("scm/lib/**/TARGETS", recursive=True): if "third" in path and "streampager" not in path: continue orig_code = code = open(path, "rb").read().decode() license_path = os.path.join(os.path.dirname(path), "LICENSE") is_mit = "/lib/streampager/" in path if not is_mit and os.path.exists(license_path): is_mit = "MIT" in open(license_path).read() if not is_mit: continue parsed = parse_targets(code, path) for item in reversed(parsed): renamed[item["name"]] = "sapling-" + item["name"] prefix_name_autocargo(item["autocargo"], item["name"]) code = rewrite_arg(code, item["line"], "autocargo", item["autocargo"]) if orig_code != code: print(path) open(path, "wb").write(code.encode()) # Second pass - update dep overrides for path in list(glob.glob("**/TARGETS", recursive=True)): if "third" in path or path in {"scm/tests/TARGETS"} or "hg-server" in path: continue orig_code = code = open(path, "rb").read().decode() parsed = parse_targets(code, path) # print(parsed) any_changed = False for item in reversed(parsed): changed = update_dep_overrides_autocargo(item["autocargo"], renamed) if changed: any_changed = True code = rewrite_arg(code, item["line"], "autocargo", item["autocargo"]) if any_changed: # print(path) open(path, "wb").write(code.encode()) if __name__ == "__main__": main() ``` Reviewed By: lmvasquezg Differential Revision: D65716841 fbshipit-source-id: 0865864c9a888e262aae75b3a41afe7e0a61ae9a
- Loading branch information