Skip to content

Commit

Permalink
Merge pull request #362 from Mic92/error-handling
Browse files Browse the repository at this point in the history
print better errors when external commands fail
  • Loading branch information
Mic92 authored Sep 15, 2023
2 parents bb56149 + def79fa commit 5fa8538
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 28 deletions.
6 changes: 5 additions & 1 deletion nixpkgs_review/builddir.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
os.environ.update(self.environ)

with DisableKeyboardInterrupt():
sh(["git", "worktree", "remove", "-f", str(self.worktree_dir)])
res = sh(["git", "worktree", "remove", "-f", str(self.worktree_dir)])
if res.returncode != 0:
warn(
f"Failed to remove worktree at {self.worktree_dir}. Please remove it manually. Git failed with: {res.returncode}"
)

self.overlay.cleanup()
10 changes: 7 additions & 3 deletions nixpkgs_review/cli/pr.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import argparse
import re
import subprocess
import sys
from contextlib import ExitStack

from ..allow import AllowedFeatures
from ..builddir import Builddir
from ..buildenv import Buildenv
from ..errors import NixpkgsReviewError
from ..review import CheckoutOption, Review
from ..utils import warn
from .utils import ensure_github_token
Expand Down Expand Up @@ -45,9 +45,11 @@ def pr_command(args: argparse.Namespace) -> str:

allow = AllowedFeatures(args.allow)

builddir = None
with Buildenv(
allow.aliases, args.extra_nixpkgs_config
) as nixpkgs_config, ExitStack() as stack:
review = None
for pr in prs:
builddir = stack.enter_context(Builddir(f"pr-{pr}"))
try:
Expand All @@ -72,12 +74,14 @@ def pr_command(args: argparse.Namespace) -> str:
extra_nixpkgs_config=args.extra_nixpkgs_config,
)
contexts.append((pr, builddir.path, review.build_pr(pr)))
except subprocess.CalledProcessError:
warn(f"https://github.com/NixOS/nixpkgs/pull/{pr} failed to build")
except NixpkgsReviewError as e:
warn(f"https://github.com/NixOS/nixpkgs/pull/{pr} failed to build: {e}")
assert review is not None

for pr, path, attrs in contexts:
review.start_review(attrs, path, pr, args.post_result, args.print_result)

if len(contexts) != len(prs):
sys.exit(1)
assert builddir is not None
return str(builddir.path)
4 changes: 4 additions & 0 deletions nixpkgs_review/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class NixpkgsReviewError(Exception):
"""Base class for exceptions in this module."""

pass
20 changes: 7 additions & 13 deletions nixpkgs_review/nix.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from typing import Any

from .allow import AllowedFeatures
from .errors import NixpkgsReviewError
from .utils import ROOT, escape_attr, info, sh, warn


Expand Down Expand Up @@ -66,7 +67,7 @@ def nix_shell(
args = [nix_shell, str(shell), "--nix-path", nix_path]
if run:
args.extend(["--run", run])
sh(args, cwd=cache_directory, check=False)
sh(args, cwd=cache_directory)


def _nix_shell_sandbox(
Expand Down Expand Up @@ -222,16 +223,12 @@ def nix_eval(
f"(import {eval_script} {{ attr-json = {attr_json.name}; }})",
]

try:
nix_eval = subprocess.run(
cmd, check=True, stdout=subprocess.PIPE, text=True
)
except subprocess.CalledProcessError:
warn(
nix_eval = subprocess.run(cmd, stdout=subprocess.PIPE, text=True)
if nix_eval.returncode != 0:
delete = False
raise NixpkgsReviewError(
f"{' '.join(cmd)} failed to run, {attr_json.name} was stored inspection"
)
delete = False
raise

return _nix_eval_filter(json.loads(nix_eval.stdout))
finally:
Expand Down Expand Up @@ -293,10 +290,7 @@ def nix_build(
str(build),
] + shlex.split(args)

try:
sh(command)
except subprocess.CalledProcessError:
pass
sh(command)
return attrs


Expand Down
44 changes: 35 additions & 9 deletions nixpkgs_review/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from .allow import AllowedFeatures
from .builddir import Builddir
from .errors import NixpkgsReviewError
from .github import GithubClient
from .nix import Attr, nix_build, nix_eval, nix_shell
from .report import Report
Expand Down Expand Up @@ -123,7 +124,13 @@ def worktree_dir(self) -> str:
return str(self.builddir.worktree_dir)

def git_merge(self, commit: str) -> None:
sh(["git", "merge", "--no-commit", "--no-ff", commit], cwd=self.worktree_dir())
res = sh(
["git", "merge", "--no-commit", "--no-ff", commit], cwd=self.worktree_dir()
)
if res.returncode != 0:
raise NixpkgsReviewError(
f"Failed to merge {commit} into {self.worktree_dir()}. git merge failed with exit code {res.returncode}"
)

def apply_unstaged(self, staged: bool = False) -> None:
args = ["git", "--no-pager", "diff", "--no-ext-diff"]
Expand Down Expand Up @@ -175,7 +182,11 @@ def build_commit(
return self.build(changed_attrs, self.build_args)

def git_worktree(self, commit: str) -> None:
sh(["git", "worktree", "add", self.worktree_dir(), commit])
res = sh(["git", "worktree", "add", self.worktree_dir(), commit])
if res.returncode != 0:
raise NixpkgsReviewError(
f"Failed to add worktree for {commit} in {self.worktree_dir()}. git worktree failed with exit code {res.returncode}"
)

def checkout_pr(self, base_rev: str, pr_rev: str) -> None:
if self.checkout == CheckoutOption.MERGE:
Expand Down Expand Up @@ -232,10 +243,13 @@ def build_pr(self, pr_number: int) -> list[Attr]:
else:
run = subprocess.run(
["git", "merge-base", merge_rev, pr_rev],
check=True,
stdout=subprocess.PIPE,
text=True,
)
if run.returncode != 0:
raise NixpkgsReviewError(
f"Failed to get the merge base of {merge_rev} with PR {pr_rev}"
)
base_rev = run.stdout.strip()

if packages_per_system is None:
Expand Down Expand Up @@ -379,7 +393,12 @@ def list_packages(
cmd.append("--meta")
info("$ " + " ".join(cmd))
with tempfile.NamedTemporaryFile(mode="w") as tmp:
subprocess.run(cmd, stdout=tmp, check=True)
res = subprocess.run(cmd, stdout=tmp)
if res.returncode != 0:
raise NixpkgsReviewError(
"Failed to list packages: nix-env failed with exit code %d"
% res.returncode
)
tmp.flush()
with open(tmp.name) as f:
return parse_packages_xml(f)
Expand Down Expand Up @@ -501,13 +520,20 @@ def fetch_refs(repo: str, *refs: str) -> list[str]:
cmd = ["git", "-c", "fetch.prune=false", "fetch", "--no-tags", "--force", repo]
for i, ref in enumerate(refs):
cmd.append(f"{ref}:refs/nixpkgs-review/{i}")
sh(cmd)
res = sh(cmd)
if res.returncode != 0:
raise NixpkgsReviewError(
f"Failed to fetch {refs} from {repo}. git fetch failed with exit code {res.returncode}"
)
shas = []
for i, ref in enumerate(refs):
out = subprocess.check_output(
["git", "rev-parse", "--verify", f"refs/nixpkgs-review/{i}"], text=True
)
shas.append(out.strip())
cmd = ["git", "rev-parse", "--verify", f"refs/nixpkgs-review/{i}"]
out = subprocess.run(cmd, text=True, stdout=subprocess.PIPE)
if out.returncode != 0:
raise NixpkgsReviewError(
f"Failed to fetch {ref} from {repo} with command: {''.join(cmd)}"
)
shas.append(out.stdout.strip())
return shas


Expand Down
4 changes: 2 additions & 2 deletions nixpkgs_review/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ def wrapper(text: str) -> None:


def sh(
command: list[str], cwd: Path | str | None = None, check: bool = True
command: list[str], cwd: Path | str | None = None
) -> "subprocess.CompletedProcess[str]":
info("$ " + " ".join(command))
return subprocess.run(command, cwd=cwd, check=check, text=True)
return subprocess.run(command, cwd=cwd, text=True)


def verify_commit_hash(commit: str) -> str:
Expand Down

0 comments on commit 5fa8538

Please sign in to comment.