Skip to content

Commit

Permalink
refactor: unify lockfile generation functions
Browse files Browse the repository at this point in the history
- combine cargo and npm lockfile generation into a single function
- use parameters to handle different types and configurations
- reduce code duplication and improve maintainability
  • Loading branch information
Moraxyc committed Dec 16, 2024
1 parent e117034 commit f763ab3
Showing 1 changed file with 37 additions and 91 deletions.
128 changes: 37 additions & 91 deletions nix_update/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,79 +268,33 @@ def update_cargo_lock(
print(line, end="")


def generate_cargo_lock(opts: Options, filename: str) -> None:
@contextmanager
def disable_copystat():
_orig = shutil.copystat
shutil.copystat = lambda *args, **kwargs: None
try:
yield
finally:
shutil.copystat = _orig

getSrcAndCargo = textwrap.dedent(f"""
{get_package(opts)}.overrideAttrs (old: {{
cargoDeps = null;
cargoVendorDir = ".";
postUnpack = ''
cp -pr --reflink=auto -- $sourceRoot $out
mkdir -p "$out/nix-support"
command -v cargo > $out/nix-support/cargo-bin || {{
echo "no cargo executable found in native build inputs" >&2
exit 1
}}
exit
'';
outputs = [ "out" ];
separateDebugInfo = false;
}})
""")

res = run(
[
"nix",
"build",
"-L",
"--no-link",
"--impure",
"--print-out-paths",
"--expr",
getSrcAndCargo,
def generate_lockfile(opts: Options, filename: str, type: str) -> None:
if type == "cargo":
cmd = [
"generate-lockfile",
"--manifest-path",
f"{opts.lockfile_metadata_path}/Cargo.toml",
]
+ opts.extra_flags,
)
src = Path(res.stdout.strip())

with tempfile.TemporaryDirectory() as tempdir:
with disable_copystat():
shutil.copytree(src, tempdir, dirs_exist_ok=True, copy_function=shutil.copy)

cargo_bin = (src / "nix-support" / "cargo-bin").read_text().rstrip("\n")

run(
[
cargo_bin,
"generate-lockfile",
"--manifest-path",
f"{opts.lockfile_metadata_path}/Cargo.toml",
],
cwd=tempdir,
)

if (
lockfile_in_subdir := Path(tempdir)
/ opts.lockfile_metadata_path
/ "Cargo.lock"
).exists():
# if Cargo.toml is outside a workspace, Cargo.lock is generated in the same directory as Cargo.toml
lockfile = lockfile_in_subdir
else:
lockfile = Path(tempdir) / "Cargo.lock"

shutil.copy(lockfile, Path(filename).parent / "Cargo.lock")

bin_name = "cargo"
lockfile_name = "Cargo.lock"
extra_nix_override = """
cargoDeps = null;
cargoVendorDir = ".";
"""
elif type == "npm":
cmd = [
"install",
"--package-lock-only",
"--prefix",
opts.lockfile_metadata_path,
]
bin_name = "npm"
lockfile_name = "package-lock.json"
extra_nix_override = """
npmDeps = null;
npmDepsHash = null;
"""

def generate_npm_lock(opts: Options, filename: str) -> None:
@contextmanager
def disable_copystat():
_orig = shutil.copystat
Expand All @@ -350,16 +304,15 @@ def disable_copystat():
finally:
shutil.copystat = _orig

getSrcAndNpm = textwrap.dedent(
getSrcAndBin = textwrap.dedent(
f"""
{get_package(opts)}.overrideAttrs (old: {{
npmDeps = null;
npmDepsHash = null;
{extra_nix_override}
postUnpack = ''
cp -pr --reflink=auto -- $sourceRoot $out
mkdir -p "$out/nix-support"
command -v npm > $out/nix-support/npm-bin || {{
echo "no npm executable found in native build inputs" >&2
command -v {bin_name} > $out/nix-support/{bin_name}-bin || {{
echo "no {bin_name} executable found in native build inputs" >&2
exit 1
}}
exit
Expand All @@ -379,7 +332,7 @@ def disable_copystat():
"--impure",
"--print-out-paths",
"--expr",
getSrcAndNpm,
getSrcAndBin,
]
+ opts.extra_flags,
)
Expand All @@ -389,30 +342,23 @@ def disable_copystat():
with disable_copystat():
shutil.copytree(src, tempdir, dirs_exist_ok=True, copy_function=shutil.copy)

npm_bin = (src / "nix-support" / "npm-bin").read_text().rstrip("\n")
bin_path = (src / "nix-support" / f"{bin_name}-bin").read_text().rstrip("\n")

run(
[
npm_bin,
"install",
"--package-lock-only",
"--prefix",
opts.lockfile_metadata_path,
],
[bin_path] + cmd,
cwd=tempdir,
)

if (
lockfile_in_subdir := Path(tempdir)
/ opts.lockfile_metadata_path
/ "package-lock.json"
/ lockfile_name
).exists():
# if package.json is outside a workspace, package0lock.json is generated in the same directory as package.json
lockfile = lockfile_in_subdir
else:
lockfile = Path(tempdir) / "package-lock.json"
lockfile = Path(tempdir) / lockfile_name

shutil.copy(lockfile, Path(filename).parent / "package-lock.json")
shutil.copy(lockfile, Path(filename).parent / lockfile_name)


def update_composer_deps_hash(opts: Options, filename: str, current_hash: str) -> None:
Expand Down Expand Up @@ -585,7 +531,7 @@ def update(opts: Options) -> Package:

if package.npm_deps:
if opts.generate_lockfile:
generate_npm_lock(opts, package.filename)
generate_lockfile(opts, package.filename, "npm")
update_npm_deps_hash(opts, package.filename, package.npm_deps)

if package.pnpm_deps:
Expand All @@ -607,7 +553,7 @@ def update(opts: Options) -> Package:
package.cargo_lock, CargoLockInStore
):
if opts.generate_lockfile:
generate_cargo_lock(opts, package.filename)
generate_lockfile(opts, package.filename, "cargo")
else:
update_cargo_lock(opts, package.filename, package.cargo_lock)

Expand Down

0 comments on commit f763ab3

Please sign in to comment.