diff options
-rw-r--r-- | Biz/Bild.nix | 2 | ||||
-rw-r--r-- | Biz/Bild/Builder.nix | 11 | ||||
-rw-r--r-- | Biz/Bild/Deps/exllama.nix | 1 | ||||
-rw-r--r-- | Biz/Bild/Deps/llama-cpp.nix | 1 | ||||
-rw-r--r-- | Biz/Bild/Deps/nostr-rs-relay.nix | 2 | ||||
-rw-r--r-- | Biz/Bild/Example.py | 13 | ||||
-rw-r--r-- | Biz/Bild/Sources.nix | 2 | ||||
-rw-r--r-- | Biz/Cloud/Comms.nix | 2 | ||||
-rw-r--r-- | Biz/Cloud/Comms/Jitsi.nix | 2 | ||||
-rw-r--r-- | Biz/Cloud/Comms/Mumble.nix | 2 | ||||
-rw-r--r-- | Biz/Cloud/NostrRelay.nix | 2 | ||||
-rw-r--r-- | Biz/Cloud/Web.nix | 2 | ||||
-rwxr-xr-x | Biz/Dragons/main.py | 69 | ||||
-rwxr-xr-x | Biz/Ide/mktags | 2 | ||||
-rwxr-xr-x | Biz/Ide/repl | 1 | ||||
-rw-r--r-- | Biz/Lint.hs | 12 | ||||
-rw-r--r-- | Biz/Nixpert.nix | 2 | ||||
-rwxr-xr-x | Biz/Que/Client.py | 36 |
18 files changed, 103 insertions, 61 deletions
diff --git a/Biz/Bild.nix b/Biz/Bild.nix index dca1b3b..918d6b1 100644 --- a/Biz/Bild.nix +++ b/Biz/Bild.nix @@ -146,7 +146,7 @@ rec { } // { env = ghc; }; env = let - linters = with nixpkgs.pkgs; [ ormolu hlint deadnix indent ]; + linters = with nixpkgs.pkgs; [ ormolu hlint deadnix indent black]; in nixpkgs.pkgs.mkShell { name = "bizdev"; # this should just be dev tools diff --git a/Biz/Bild/Builder.nix b/Biz/Bild/Builder.nix index 214c110..2b1403a 100644 --- a/Biz/Bild/Builder.nix +++ b/Biz/Bild/Builder.nix @@ -59,10 +59,13 @@ in { buildInputs = sysdeps_; checkInputs = [(private.pythonWith (p: with p; [black mypy pylint]))]; checkPhase = '' - black --quiet --exclude 'setup\.py$' --check . - pylint --errors-only . - mypy --strict --no-error-summary --exclude 'setup\.py$' . - python -m ${main} test + check() { + $@ || { echo "fail: $name: $3"; exit 1; } + } + check python -m black --quiet --exclude 'setup\.py$' --check . + check python -m pylint --errors-only . + check python -m mypy --strict --no-error-summary --exclude 'setup\.py$' . + check python -m ${main} test ''; preBuild = '' # initialize possibly-empty subdirectories as python modules diff --git a/Biz/Bild/Deps/exllama.nix b/Biz/Bild/Deps/exllama.nix index 54d6df1..1f7e529 100644 --- a/Biz/Bild/Deps/exllama.nix +++ b/Biz/Bild/Deps/exllama.nix @@ -2,7 +2,6 @@ , sources , buildPythonPackage , pythonOlder -, fetchFromGitHub , torch # tested on 2.0.1 and 2.1.0 (nightly) with cu118 , safetensors , sentencepiece diff --git a/Biz/Bild/Deps/llama-cpp.nix b/Biz/Bild/Deps/llama-cpp.nix index 85bd778..b247252 100644 --- a/Biz/Bild/Deps/llama-cpp.nix +++ b/Biz/Bild/Deps/llama-cpp.nix @@ -1,5 +1,4 @@ { stdenv -, pkgs , sources , python3 , cmake diff --git a/Biz/Bild/Deps/nostr-rs-relay.nix b/Biz/Bild/Deps/nostr-rs-relay.nix index 83d477c..bb0a1cd 100644 --- a/Biz/Bild/Deps/nostr-rs-relay.nix +++ b/Biz/Bild/Deps/nostr-rs-relay.nix @@ -1,4 +1,4 @@ -{ lib, fetchFromSourcehut, rustPlatform, pkg-config, openssl }: +{ fetchFromSourcehut, rustPlatform, pkg-config, openssl }: rustPlatform.buildRustPackage rec { pname = "nostr-rs-relay"; diff --git a/Biz/Bild/Example.py b/Biz/Bild/Example.py index 78a8a6a..25686fa 100644 --- a/Biz/Bild/Example.py +++ b/Biz/Bild/Example.py @@ -1,15 +1,16 @@ +""" +Example Python file that also serves as a test case for bild. +fernet.""" # : out example # : dep cryptography import sys -from typing import List - -from cryptography.fernet import Fernet +import cryptography.fernet def cryptic_hello(name: str) -> str: "Example taken from `cryptography` docs." - key = Fernet.generate_key() - f = Fernet(key) + key = cryptography.fernet.Fernet.generate_key() + f = cryptography.fernet.Fernet(key) token = f.encrypt(hello(name).encode("utf-8")) ret = f.decrypt(token).decode("utf-8") assert ret == hello(name) @@ -17,10 +18,12 @@ def cryptic_hello(name: str) -> str: def hello(name: str) -> str: + "Say hello" return f"Hello {name}" def main() -> None: + "Entrypoint" if "test" in sys.argv: print("testing success") print(cryptic_hello("world")) diff --git a/Biz/Bild/Sources.nix b/Biz/Bild/Sources.nix index 1938409..927683a 100644 --- a/Biz/Bild/Sources.nix +++ b/Biz/Bild/Sources.nix @@ -126,6 +126,7 @@ let optionalAttrs = cond: as: if cond then as else {}; # fetchTarball version that is compatible between all the versions of Nix + # deadnix: skip builtins_fetchTarball = { url, name ? null, sha256 }@attrs: let inherit (builtins) lessThan nixVersion fetchTarball; @@ -136,6 +137,7 @@ let fetchTarball attrs; # fetchurl version that is compatible between all the versions of Nix + # deadnix: skip builtins_fetchurl = { url, name ? null, sha256 }@attrs: let inherit (builtins) lessThan nixVersion fetchurl; diff --git a/Biz/Cloud/Comms.nix b/Biz/Cloud/Comms.nix index 64fe7c7..700296d 100644 --- a/Biz/Cloud/Comms.nix +++ b/Biz/Cloud/Comms.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ... }: +{ ... }: { imports = [ diff --git a/Biz/Cloud/Comms/Jitsi.nix b/Biz/Cloud/Comms/Jitsi.nix index 30e6b44..17aeced 100644 --- a/Biz/Cloud/Comms/Jitsi.nix +++ b/Biz/Cloud/Comms/Jitsi.nix @@ -1,4 +1,4 @@ -{ config, pkgs, ... }: +{ config, ... }: { services.jitsi-meet = { diff --git a/Biz/Cloud/Comms/Mumble.nix b/Biz/Cloud/Comms/Mumble.nix index fed305e..d728a07 100644 --- a/Biz/Cloud/Comms/Mumble.nix +++ b/Biz/Cloud/Comms/Mumble.nix @@ -1,4 +1,4 @@ -{ config, pkgs, ... }: +{ config, ... }: # mumble and related services let diff --git a/Biz/Cloud/NostrRelay.nix b/Biz/Cloud/NostrRelay.nix index d8ffd3a..73c1366 100644 --- a/Biz/Cloud/NostrRelay.nix +++ b/Biz/Cloud/NostrRelay.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{ config, pkgs, ... }: let ports = import ./Ports.nix; diff --git a/Biz/Cloud/Web.nix b/Biz/Cloud/Web.nix index 3afc2ae..913bded 100644 --- a/Biz/Cloud/Web.nix +++ b/Biz/Cloud/Web.nix @@ -1,4 +1,4 @@ -{ config, pkgs, ... }: +{ config, ... }: let rootDomain = config.networking.domain; diff --git a/Biz/Dragons/main.py b/Biz/Dragons/main.py index bb10441..7813f45 100755 --- a/Biz/Dragons/main.py +++ b/Biz/Dragons/main.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# : out dragons.py """ Analyze developer allocation across a codebase. """ @@ -10,15 +11,16 @@ import os import re import subprocess import sys +import typing -def find_user(line): +def find_user(line: str) -> typing.Any: """Given 'Ben Sima <ben@bsima.me>', finds `Ben Sima'. Returns the first matching string.""" return re.findall(r"^[^<]*", line)[0].strip() -def authors_for(path, active_users): +def authors_for(path: str, active_users: typing.List[str]) -> typing.Dict[str, str]: """Return a dictionary of {author: commits} for given path. Usernames not in the 'active_users' list will be filtered out.""" raw = subprocess.check_output( @@ -35,10 +37,10 @@ def authors_for(path, active_users): return data -def mailmap_users(): +def mailmap_users() -> typing.List[str]: """Returns users from the .mailmap file.""" users = [] - with open(".mailmap") as file: + with open(".mailmap", encoding="utf-8") as file: lines = file.readlines() for line in lines: users.append(find_user(line)) @@ -48,7 +50,7 @@ def mailmap_users(): MAX_SCORE = 10 -def score(blackhole, liability, good, total): +def score(blackhole: float, liability: float, good: int, total: int) -> float: "Calculate the score." weights = { "blackhole": 0.5, @@ -65,9 +67,10 @@ def score(blackhole, liability, good, total): ) -def get_args(): +def get_args() -> typing.Any: "Parse CLI arguments." cli = argparse.ArgumentParser(description=__doc__) + cli.add_argument("test", action="store_true", help="run the test suite") cli.add_argument("repo", default=".", help="the git repo to run on", metavar="REPO") cli.add_argument( "-b", @@ -88,7 +91,11 @@ def get_args(): help="print stale files (haven't been touched in 6 months)", ) cli.add_argument( - "-i", "--ignored", nargs="+", default=[], help="patterns to ignore in paths", + "-i", + "--ignored", + nargs="+", + default=[], + help="patterns to ignore in paths", ) cli.add_argument( "--active-users", @@ -106,19 +113,7 @@ def get_args(): return cli.parse_args() -def guard_git(repo): - "Guard against non-git repos." - is_git = subprocess.run( - ["git", "rev-parse"], - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - check=False, - ).returncode - if is_git != 0: - sys.exit(f"error: not a git repository: {repo}") - - -def staleness(path, now): +def staleness(path: str, now: datetime.datetime) -> int: "How long has it been since this file was touched?" timestamp = datetime.datetime.strptime( subprocess.check_output(["git", "log", "-n1", "--pretty=%aI", path]) @@ -133,7 +128,9 @@ def staleness(path, now): class Repo: "Represents a repo and stats for the repo." - def __init__(self, ignored_paths, active_users): + def __init__( + self, ignored_paths: typing.List[str], active_users: typing.List[str] + ) -> None: self.paths = [ p for p in subprocess.check_output(["git", "ls-files", "--no-deleted"]) @@ -158,7 +155,7 @@ class Repo: if _staleness > 180: self.stale[path] = _staleness - def print_blackholes(self, full): + def print_blackholes(self, full: bool) -> None: "Print number of blackholes, or list of all blackholes." # note: file renames may result in false positives n_blackhole = len(self.blackholes) @@ -167,7 +164,7 @@ class Repo: for path in self.blackholes: print(f" {path}") - def print_liabilities(self, full): + def print_liabilities(self, full: bool) -> None: "Print number of liabilities, or list of all liabilities." n_liabilities = len(self.liabilities) print(f"Liabilities: {n_liabilities}") @@ -175,20 +172,17 @@ class Repo: for path, authors in self.liabilities.items(): print(f" {path} ({', '.join(authors)})") - def print_score(self): + def print_score(self) -> None: "Print the overall score." n_total = len(self.stats.keys()) n_blackhole = len(self.blackholes) n_liabilities = len(self.liabilities) n_good = n_total - n_blackhole - n_liabilities print("Total:", n_total) - print( - "Score: {:.2f}/{}".format( - score(n_blackhole, n_liabilities, n_good, n_total), MAX_SCORE - ) - ) + this_score = score(n_blackhole, n_liabilities, n_good, n_total) + print(f"Score: {this_score:.2f}/{MAX_SCORE}".format()) - def print_stale(self, full): + def print_stale(self, full: bool) -> None: "Print stale files" n_stale = len(self.stale) print(f"Stale files: {n_stale}") @@ -197,8 +191,23 @@ class Repo: print(f" {path} ({days} days)") +def guard_git(repo: Repo) -> None: + "Guard against non-git repos." + is_git = subprocess.run( + ["git", "rev-parse"], + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + check=False, + ).returncode + if is_git != 0: + sys.exit(f"error: not a git repository: {repo}") + + if __name__ == "__main__": ARGS = get_args() + if ARGS.test: + print("ok") + sys.exit() logging.basicConfig(stream=sys.stderr, level=ARGS.verbosity.upper()) logging.debug("starting") diff --git a/Biz/Ide/mktags b/Biz/Ide/mktags index ebad39a..b984fb1 100755 --- a/Biz/Ide/mktags +++ b/Biz/Ide/mktags @@ -2,7 +2,7 @@ # # script to generate tags automatically if there are none. # - set -euxo pipefail + set -euo pipefail files=$@ vimtags=${BIZ_ROOT:?}/tags emacstags=${BIZ_ROOT:?}/TAGS diff --git a/Biz/Ide/repl b/Biz/Ide/repl index e62c7b2..5a7b615 100755 --- a/Biz/Ide/repl +++ b/Biz/Ide/repl @@ -63,6 +63,7 @@ fi command=bash ;; Py) + langdeps="$langdeps pylint mypy" flags+=(--packages "$BILD.private.$packageSet (p: with p; [$langdeps])") command=${CMD:-"python -i $targets"} ;; diff --git a/Biz/Lint.hs b/Biz/Lint.hs index f9b16d0..be73229 100644 --- a/Biz/Lint.hs +++ b/Biz/Lint.hs @@ -123,6 +123,14 @@ hlint = fixArgs = Nothing } +black :: Linter +black = + Linter + { exe = "black", + checkArgs = ["--check"], + fixArgs = Just [] + } + deadnix :: Linter deadnix = Linter @@ -164,7 +172,9 @@ runOne mode root cwd path_ = results +> traverse_ printResult >> results [ lint mode ormolu path_, lint mode hlint path_ ] - Just (Namespace _ Py) -> [] -- python linters are run in Builder.nix checkPhase + Just (Namespace _ Py) -> + [ lint mode black path_ + ] Just (Namespace _ Sh) -> [lint mode shellcheck path_] Just (Namespace _ Nix) -> [lint mode deadnix path_] Just (Namespace _ Scm) -> [pure <| NoOp path_] diff --git a/Biz/Nixpert.nix b/Biz/Nixpert.nix index d6d6d4f..faf27b2 100644 --- a/Biz/Nixpert.nix +++ b/Biz/Nixpert.nix @@ -1,4 +1,4 @@ -{ config, pkgs, ... }: +{ pkgs, ... }: let salespage = pkgs.runCommand "salespage" {} '' diff --git a/Biz/Que/Client.py b/Biz/Que/Client.py index 58877bf..90e560f 100755 --- a/Biz/Que/Client.py +++ b/Biz/Que/Client.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# : out que """ simple client for que.run """ @@ -15,6 +16,7 @@ import textwrap import time import urllib.parse import urllib.request as request +import typing MAX_TIMEOUT = 9999999 RETRIES = 10 @@ -22,7 +24,7 @@ DELAY = 3 BACKOFF = 1 -def auth(args): +def auth(args: argparse.Namespace) -> typing.Union[str, None]: "Returns the auth key for the given ns from ~/.config/que.conf" logging.debug("auth") namespace = args.target.split("/")[0] @@ -36,7 +38,7 @@ def auth(args): return cfg[namespace]["key"] -def autodecode(bytestring): +def autodecode(bytestring: bytes) -> typing.Any: """Attempt to decode bytes into common codecs, preferably utf-8. If no decoding is available, just return the raw bytes. @@ -54,12 +56,18 @@ def autodecode(bytestring): return bytestring -def retry(exception, tries=RETRIES, delay=DELAY, backoff=BACKOFF): +@typing.no_type_check +def retry( + exception: str, + tries: typing.Any = RETRIES, + delay: typing.Any = DELAY, + backoff: typing.Any = BACKOFF, +) -> typing.Any: "Decorator for retrying an action." - def decorator(func): + def decorator(func: typing.Any) -> typing.Any: @functools.wraps(func) - def func_retry(*args, **kwargs): + def func_retry(*args: typing.Any, **kwargs: typing.Any) -> typing.Any: mtries, mdelay = tries, delay while mtries > 1: try: @@ -77,10 +85,11 @@ def retry(exception, tries=RETRIES, delay=DELAY, backoff=BACKOFF): return decorator +@typing.no_type_check @retry(urllib.error.URLError) @retry(http.client.IncompleteRead) @retry(http.client.RemoteDisconnected) -def send(args): +def send(args: argparse.Namespace) -> None: "Send a message to the que." logging.debug("send") key = auth(args) @@ -93,12 +102,14 @@ def send(args): if args.serve: logging.debug("serve") while not time.sleep(1): + # pylint: disable=consider-using-with request.urlopen(req, data=data, timeout=MAX_TIMEOUT) else: + # pylint: disable=consider-using-with request.urlopen(req, data=data, timeout=MAX_TIMEOUT) -def then(args, msg): +def then(args: argparse.Namespace, msg: str) -> None: "Perform an action when passed `--then`." if args.then: logging.debug("then") @@ -109,10 +120,11 @@ def then(args, msg): ) +@typing.no_type_check @retry(urllib.error.URLError) @retry(http.client.IncompleteRead) @retry(http.client.RemoteDisconnected) -def recv(args): +def recv(args: argparse.Namespace) -> None: "Receive a message from the que." logging.debug("recv on: %s", args.target) if args.poll: @@ -127,7 +139,7 @@ def recv(args): if args.poll: logging.debug("polling") while not time.sleep(1): - reply =_req.readline() + reply = _req.readline() if reply: msg = autodecode(reply) logging.debug("read") @@ -141,7 +153,7 @@ def recv(args): then(args, msg) -def get_args(): +def get_args() -> argparse.Namespace: "Command line parser" cli = argparse.ArgumentParser( description=__doc__, @@ -150,6 +162,7 @@ def get_args(): between attempts.""" ), ) + cli.add_argument("test", action="store_true", help="run tests") cli.add_argument("--debug", action="store_true", help="log to stderr") cli.add_argument( "--host", default="http://que.run", help="where que-server is running" @@ -192,6 +205,9 @@ def get_args(): if __name__ == "__main__": ARGV = get_args() + if ARGV.test: + print("ok") + sys.exit() if ARGV.debug: logging.basicConfig( format="%(asctime)s: %(levelname)s: %(message)s", |