Skip to content

Commit

Permalink
print update more stats when evaluating locally
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 committed Jan 2, 2020
1 parent 3fae656 commit e704d6a
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 43 deletions.
1 change: 1 addition & 0 deletions nixpkgs_review/nix.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from .utils import ROOT, info, sh, warn, escape_attr


@dataclass
class Attr:
name: str
Expand Down
125 changes: 107 additions & 18 deletions nixpkgs_review/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import subprocess
import sys
import xml.etree.ElementTree as ET
from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional, Pattern, Set, Tuple
from typing import IO, Dict, List, Optional, Pattern, Set, Tuple

from .builddir import Builddir
from .github import GithubClient
Expand All @@ -30,6 +31,49 @@ def native_packages(packages_per_system: Dict[str, Set[str]]) -> Set[str]:
return set(packages_per_system[system.stdout.decode("utf-8")])


def print_packages(names: List[str], msg: str,) -> None:
if len(names) == 0:
return
plural = "s" if len(names) == 0 else ""

print(f"{len(names)} package{plural} {msg}:")
print(" ".join(names))
print("")


@dataclass
class Package:
pname: str
version: str
attr_path: str
store_path: str
homepage: Optional[str]
description: Optional[str]
position: Optional[str]
old_pkg: "Optional[Package]" = field(init=False)


def print_updates(changed_pkgs: List[Package], removed_pkgs: List[Package]) -> None:
new = []
updated = []
for pkg in changed_pkgs:
if pkg.old_pkg is None:
if pkg.version != "":
new.append(f"{pkg.pname} (init at {pkg.version})")
else:
new.append(pkg.pname)
elif pkg.old_pkg.version != pkg.version:
updated.append(f"{pkg.pname} ({pkg.old_pkg.version}{pkg.version})")
else:
updated.append(pkg.pname)

removed = list(f"{p.pname} (†{pkg.version})" for p in removed_pkgs)

print_packages(new, "added")
print_packages(updated, "updated")
print_packages(removed, "removed")


class Review:
def __init__(
self,
Expand Down Expand Up @@ -88,8 +132,10 @@ def build_commit(

merged_packages = list_packages(str(self.worktree_dir()), check_meta=True)

attrs = differences(base_packages, merged_packages)
return self.build(attrs, self.build_args)
changed_pkgs, removed_pkgs = differences(base_packages, merged_packages)
changed_attrs = set(p.attr_path for p in changed_pkgs)
print_updates(changed_pkgs, removed_pkgs)
return self.build(changed_attrs, self.build_args)

def git_worktree(self, commit: str) -> None:
sh(["git", "worktree", "add", self.worktree_dir(), commit])
Expand Down Expand Up @@ -153,26 +199,58 @@ def review_commit(
self.start_review(self.build_commit(branch_rev, reviewed_commit, staged))


PackageSet = Set[Tuple[str, str]]
def parse_packages_xml(stdout: IO[bytes]) -> List[Package]:
packages: List[Package] = []
path = None
context = ET.iterparse(stdout, events=("start", "end"))
for (event, elem) in context:
if elem.tag == "item":
if event == "start":
attrs = elem.attrib
homepage = None
description = None
position = None
else:
assert attrs is not None
assert path is not None
pkg = Package(
pname=attrs["pname"],
version=attrs["version"],
attr_path=attrs["attrPath"],
store_path=path,
homepage=homepage,
description=description,
position=position,
)
packages.append(pkg)
elif event == "start" and elem.tag == "output" and elem.attrib["name"] == "out":
path = elem.attrib["path"]
elif event == "start" and elem.tag == "meta":
name = elem.attrib["name"]
if name not in ["homepage", "description", "position"]:
continue
if elem.attrib["type"] == "strings":
values = (e.attrib["value"] for e in elem.getchildren())
value = ", ".join(values)
else:
value = elem.attrib["value"]
if name == "homepage":
homepage = value
elif name == "description":
description = value
elif name == "position":
position = value
return packages


def list_packages(path: str, check_meta: bool = False) -> PackageSet:
def list_packages(path: str, check_meta: bool = False) -> List[Package]:
cmd = ["nix-env", "-f", path, "-qaP", "--xml", "--out-path", "--show-trace"]
if check_meta:
cmd.append("--meta")
info("$ " + " ".join(cmd))
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
packages = set()
with proc as nix_env:
context = ET.iterparse(nix_env.stdout, events=("start",))
for (event, elem) in context:
if elem.tag == "item":
attrib = elem.attrib["attrPath"]
elif elem.tag == "output":
assert attrib is not None
path = elem.attrib["path"]
packages.add((attrib, path))
return packages
return parse_packages_xml(nix_env.stdout)


def package_attrs(
Expand Down Expand Up @@ -253,9 +331,20 @@ def fetch_refs(repo: str, *refs: str) -> List[str]:
return shas


def differences(old: PackageSet, new: PackageSet) -> Set[str]:
raw = new - old
return {l[0] for l in raw}
def differences(
old: List[Package], new: List[Package]
) -> Tuple[List[Package], List[Package]]:
old_attrs = dict((pkg.attr_path, pkg) for pkg in old)
changed_packages = []
for new_pkg in new:
old_pkg = old_attrs.get(new_pkg.attr_path, None)
if old_pkg is None or old_pkg.store_path != new_pkg.store_path:
new_pkg.old_pkg = old_pkg
changed_packages.append(new_pkg)
if old_pkg:
del old_attrs[old_pkg.attr_path]

return (changed_packages, list(old_attrs.values()))


def review_local_revision(
Expand Down
50 changes: 25 additions & 25 deletions nixpkgs_review/tests/assets/package_list_after.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
<items>
<item attrPath="pong3d" name="3dpong-0.5" system="x86_64-linux">
<output name="out" path="/nix/store/3zxskid4z49biinlzs07w6knn9vfwd5j-3dpong-0.5" />
<meta name="available" type="bool" value="true" />
<meta name="description" type="string" value="One or two player 3d sports game based on Pong from Atari" />
<meta name="homepage" type="string" value="http://www.newbreedsoftware.com/3dpong/" />
<meta name="license" type="strings">
<string type="url" value="http://spdx.org/licenses/GPL-2.0+.html" />
<string type="shortName" value="gpl2Plus" />
<string type="fullName" value="GNU General Public License v2.0 or later" />
<string type="spdxId" value="GPL-2.0+" />
</meta>
<meta name="name" type="string" value="3dpong-0.5" />
<meta name="outputsToInstall" type="strings">
<string value="out" />
</meta>
<meta name="platforms" type="strings">
<string value="aarch64-linux" />
<string value="armv5tel-linux" />
<string value="armv6l-linux" />
<string value="armv7l-linux" />
<string value="mipsel-linux" />
<string value="i686-linux" />
<string value="x86_64-linux" />
</meta>
<meta name="position" type="string" value="/home/joerg/git/nixpkgs/pkgs/games/pong3d/default.nix:19" />
<item attrPath="pong3d" name="3dpong-0.5" pname="3dpong" system="x86_64-linux" version="0.5">
<output name="out" path="/nix/store/3zxskid4z49biinlzs07w6knn9vfwd5j-3dpong-0.5" />
<meta name="available" type="bool" value="true" />
<meta name="description" type="string" value="One or two player 3d sports game based on Pong from Atari" />
<meta name="homepage" type="string" value="http://www.newbreedsoftware.com/3dpong/" />
<meta name="license" type="strings">
<string type="url" value="http://spdx.org/licenses/GPL-2.0+.html" />
<string type="shortName" value="gpl2Plus" />
<string type="fullName" value="GNU General Public License v2.0 or later" />
<string type="spdxId" value="GPL-2.0+" />
</meta>
<meta name="name" type="string" value="3dpong-0.5" />
<meta name="outputsToInstall" type="strings">
<string value="out" />
</meta>
<meta name="platforms" type="strings">
<string value="aarch64-linux" />
<string value="armv5tel-linux" />
<string value="armv6l-linux" />
<string value="armv7l-linux" />
<string value="mipsel-linux" />
<string value="i686-linux" />
<string value="x86_64-linux" />
</meta>
<meta name="position" type="string" value="/home/joerg/git/nixpkgs/pkgs/games/pong3d/default.nix:19" />
</item>
</items>

0 comments on commit e704d6a

Please sign in to comment.