Skip to content

Commit

Permalink
move scripts to nur subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 committed Aug 10, 2018
1 parent 5c35d41 commit 475851a
Show file tree
Hide file tree
Showing 13 changed files with 427 additions and 272 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# mypy
.mypy_cache/
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,14 +214,14 @@ $ git clone https://github.com/nix-community/NUR
}
```

At the moment each URL must point to a git repository. By running `nur/update.py`
At the moment each URL must point to a git repository. By running `bin/nur update`
the corresponding `repos.json.lock` is updated and the repository is tested. This will
perform also an evaluation check, which must be passed for your repository. Commit the changed
`repos.json` but NOT `repos.json.lock`

```
$ git add repos.json
$ ./nur/format_manifest.py # ensure repos.json is sorted alphabetically
$ ./bin/nur format-manifest # ensure repos.json is sorted alphabetically
$ git commit -m "add <your-repo-name> repository"
$ git push
```
Expand Down
12 changes: 12 additions & 0 deletions bin/nur
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env nix-shell
#!nix-shell -p python3 -p nix-prefetch-git -p nix -i python3
import sys
import os

sys.path.insert(0, os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))

from nur import main

if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions ci/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ fi

export encrypted_025d6e877aa4_key= encrypted_025d6e877aa4_iv=

./nur/format-manifest.py
./bin/nur format-manifest
if [ -n "$(git diff --exit-code repos.json)" ]; then
echo "repos.json was not formatted before committing repos.json:" >&2
git diff --exit-code repos.json
echo "Please run ./nur/format-manifest.py and updates repos.json accordingly!" >&2
exit 1
fi

./nur/update.py
./bin/nur update
nix-build

# Pull requests and commits to other branches shouldn't try to deploy, just build to verify
Expand Down
36 changes: 36 additions & 0 deletions nur/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import argparse
import sys
from typing import List

from .format_manifest import format_manifest_command
from .index import index_command
from .update import update_command

# from .build import build_channel_command


def parse_arguments(argv: List[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(
prog=argv[0], description="nur management commands"
)

subparsers = parser.add_subparsers(description="subcommands")

# build_channel = subparsers.add_parser("build-channel")
# build_channel.set_defaults(func=build_channel_command)

format_manifest = subparsers.add_parser("format-manifest")
format_manifest.set_defaults(func=format_manifest_command)

update = subparsers.add_parser("update")
update.set_defaults(func=update_command)

index = subparsers.add_parser("index")
index.set_defaults(func=index_command)

return parser.parse_args(argv[1:])


def main() -> None:
args = parse_arguments(sys.argv)
args.func(args)
7 changes: 7 additions & 0 deletions nur/channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from pathlib import Path

from .path import LOCK_PATH, MANIFEST_PATH


def build_channel_command(_path: str):
pass
2 changes: 2 additions & 0 deletions nur/error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class NurError(Exception):
pass
13 changes: 3 additions & 10 deletions nur/format-manifest.py → nur/format_manifest.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
#!/usr/bin/env nix-shell
#!nix-shell -p python3 -i python3

import json
import shutil
from pathlib import Path
from argparse import Namespace

ROOT = Path(__file__).parent.parent
from .path import ROOT


def main() -> None:
def format_manifest_command(args: Namespace) -> None:
path = ROOT.joinpath("repos.json")
manifest = json.load(open(path))
tmp_path = str(path) + ".tmp"
with open(tmp_path, "w+") as tmp:
json.dump(manifest, tmp, indent=4, sort_keys=True)
tmp.write("\n")
shutil.move(tmp_path, path)


if __name__ == "__main__":
main()
49 changes: 49 additions & 0 deletions nur/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import json
import subprocess
from argparse import Namespace
from pathlib import Path
from tempfile import NamedTemporaryFile
from typing import Any, Dict

from .path import ROOT


def index_repo(repo: str, expression_file: str) -> Dict[str, Any]:
fetch_source_cmd = [
"nix-build",
str(ROOT),
"-A",
f"repo-sources.{repo}",
"--no-out-link",
]

repo_path = subprocess.check_output(fetch_source_cmd).strip()

expression_path = Path(repo_path.decode("utf-8")).joinpath(expression_file)

with NamedTemporaryFile(mode="w") as f:
expr = f"with import <nixpkgs> {{}}; callPackage {expression_path} {{}}"
f.write(expr)
f.flush()
query_cmd = ["nix-env", "-qa", "*", "--json", "-f", str(f.name)]
out = subprocess.check_output(query_cmd).strip()
raw_pkgs = json.loads(out)
pkgs = {}
for name, pkg in raw_pkgs.items():
pkg["_attr"] = name
pkgs[f"nur.repos.{repo}.{name}"] = pkg
return pkgs


def index_command(args: Namespace) -> None:
manifest_path = ROOT.joinpath("repos.json")
with open(manifest_path) as f:
manifest = json.load(f)
repos = manifest.get("repos", [])
pkgs: Dict[str, Any] = {}

for (repo, data) in repos.items():
pkgs.update(index_repo(repo, data.get("file", "default.nix")))

with open(ROOT.joinpath("packages.json"), "w") as f:
json.dump(pkgs, f, indent=4)
118 changes: 118 additions & 0 deletions nur/manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import json
from enum import Enum, auto
from pathlib import Path
from typing import Dict, List, Optional, Union
from urllib.parse import ParseResult, urlparse

Url = ParseResult


class LockedVersion:
def __init__(
self, url: Url, rev: str, sha256: str, submodules: bool = False
) -> None:
self.url = url
self.rev = rev
self.sha256 = sha256
self.submodules = submodules

def as_json(self) -> Dict[str, Union[bool, str]]:
d = dict(
url=self.url.geturl(),
rev=self.rev,
sha256=self.sha256,
)
if self.submodules:
d["submodules"] = self.submodules
return d


class RepoType(Enum):
GITHUB = auto()
GITLAB = auto()
GIT = auto()

@staticmethod
def from_repo(repo: "Repo", type_: str) -> "RepoType":
if repo.submodules:
return RepoType.GIT
if repo.url.hostname == "github.com":
return RepoType.GITHUB
if repo.url.hostname == "gitlab.com" or type_ == "gitlab":
return RepoType.GITLAB
else:
return RepoType.GIT


class Repo:
def __init__(
self,
name: str,
url: Url,
submodules: bool,
type_: str,
file_: Optional[str],
locked_version: Optional[LockedVersion],
) -> None:
self.name = name
self.url = url
self.submodules = submodules
if file_ is None:
self.file = "default.nix"
else:
self.file = file_
self.locked_version = None

if (
locked_version is not None
and locked_version.url != url.geturl()
and locked_version.submodules == submodules
):
self.locked_version = locked_version

self.type = RepoType.from_repo(self, type_)


class Manifest:
def __init__(self, repos: List[Repo]) -> None:
self.repos = repos


def _load_locked_versions(path: Path) -> Dict[str, LockedVersion]:
with open(path) as f:
data = json.load(f)

locked_versions = {}

for name, repo in data["repos"].items():
url = urlparse(repo["url"])
rev = repo["rev"]
sha256 = repo["sha256"]
locked_versions[name] = LockedVersion(url, rev, sha256)

return locked_versions


def load_locked_versions(path: Path) -> Dict[str, LockedVersion]:
if path.exists():
return _load_locked_versions(path)
else:
return {}


def load_manifest(manifest_path: Union[str, Path], lock_path) -> Manifest:
locked_versions = load_locked_versions(lock_path)

with open(manifest_path) as f:
data = json.load(f)

repos = []
for name, repo in data["repos"].items():
url = urlparse(repo["url"])
submodules = repo.get("submodules", False)
file_ = repo.get("file", "default.nix")
type_ = repo.get("type", None)
locked_version = locked_versions.get(name)
repos.append(Repo(name, url, submodules, type_, file_, locked_version))

return Manifest(repos)
20 changes: 20 additions & 0 deletions nur/path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import subprocess
from pathlib import Path

ROOT = Path(__file__).parent.parent.resolve()
LOCK_PATH = ROOT.joinpath("repos.json.lock")
MANIFEST_PATH = ROOT.joinpath("repos.json")
EVALREPO_PATH = ROOT.joinpath("lib/evalRepo.nix")

_NIXPKGS_PATH = None


def nixpkgs_path() -> str:
global _NIXPKGS_PATH
if _NIXPKGS_PATH is not None:
return _NIXPKGS_PATH
cmd = ["nix-instantiate", "--find-file", "nixpkgs"]
path = subprocess.check_output(cmd).decode("utf-8").strip()
_NIXPKGS_PATH = str(Path(path).resolve())

return _NIXPKGS_PATH
Loading

0 comments on commit 475851a

Please sign in to comment.