Merge master into staging-next
This commit is contained in:
commit
209e8d0932
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -39,7 +39,7 @@
|
|||||||
/pkgs/top-level/stage.nix @nbp @Ericson2314 @matthewbauer
|
/pkgs/top-level/stage.nix @nbp @Ericson2314 @matthewbauer
|
||||||
/pkgs/top-level/splice.nix @Ericson2314 @matthewbauer
|
/pkgs/top-level/splice.nix @Ericson2314 @matthewbauer
|
||||||
/pkgs/top-level/release-cross.nix @Ericson2314 @matthewbauer
|
/pkgs/top-level/release-cross.nix @Ericson2314 @matthewbauer
|
||||||
/pkgs/stdenv/generic @Ericson2314 @matthewbauer
|
/pkgs/stdenv/generic @Ericson2314 @matthewbauer @cab404
|
||||||
/pkgs/stdenv/cross @Ericson2314 @matthewbauer
|
/pkgs/stdenv/cross @Ericson2314 @matthewbauer
|
||||||
/pkgs/build-support/cc-wrapper @Ericson2314 @orivej
|
/pkgs/build-support/cc-wrapper @Ericson2314 @orivej
|
||||||
/pkgs/build-support/bintools-wrapper @Ericson2314 @orivej
|
/pkgs/build-support/bintools-wrapper @Ericson2314 @orivej
|
||||||
|
32
nixos/lib/test-driver/default.nix
Normal file
32
nixos/lib/test-driver/default.nix
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{ lib
|
||||||
|
, python3Packages
|
||||||
|
, enableOCR ? false
|
||||||
|
, qemu_pkg ? qemu_test
|
||||||
|
, coreutils
|
||||||
|
, imagemagick_light
|
||||||
|
, libtiff
|
||||||
|
, netpbm
|
||||||
|
, qemu_test
|
||||||
|
, socat
|
||||||
|
, tesseract4
|
||||||
|
, vde2
|
||||||
|
}:
|
||||||
|
|
||||||
|
python3Packages.buildPythonApplication rec {
|
||||||
|
pname = "nixos-test-driver";
|
||||||
|
version = "1.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
propagatedBuildInputs = [ coreutils netpbm python3Packages.colorama python3Packages.ptpython qemu_pkg socat vde2 ]
|
||||||
|
++ (lib.optionals enableOCR [ imagemagick_light tesseract4 ]);
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
|
checkInputs = with python3Packages; [ mypy pylint black ];
|
||||||
|
checkPhase = ''
|
||||||
|
mypy --disallow-untyped-defs \
|
||||||
|
--no-implicit-optional \
|
||||||
|
--ignore-missing-imports ${src}/test_driver
|
||||||
|
pylint --errors-only ${src}/test_driver
|
||||||
|
black --check --diff ${src}/test_driver
|
||||||
|
'';
|
||||||
|
}
|
13
nixos/lib/test-driver/setup.py
Normal file
13
nixos/lib/test-driver/setup.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="nixos-test-driver",
|
||||||
|
version='1.0',
|
||||||
|
packages=find_packages(),
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
"nixos-test-driver=test_driver:main",
|
||||||
|
"generate-driver-symbols=test_driver:generate_driver_symbols"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
100
nixos/lib/test-driver/test_driver/__init__.py
Executable file
100
nixos/lib/test-driver/test_driver/__init__.py
Executable file
@ -0,0 +1,100 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import ptpython.repl
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
from test_driver.driver import Driver
|
||||||
|
|
||||||
|
|
||||||
|
class EnvDefault(argparse.Action):
|
||||||
|
"""An argpars Action that takes values from the specified
|
||||||
|
environment variable as the flags default value.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs): # type: ignore
|
||||||
|
if not default and envvar:
|
||||||
|
if envvar in os.environ:
|
||||||
|
if nargs is not None and (nargs.isdigit() or nargs in ["*", "+"]):
|
||||||
|
default = os.environ[envvar].split()
|
||||||
|
else:
|
||||||
|
default = os.environ[envvar]
|
||||||
|
kwargs["help"] = (
|
||||||
|
kwargs["help"] + f" (default from environment: {default})"
|
||||||
|
)
|
||||||
|
if required and default:
|
||||||
|
required = False
|
||||||
|
super(EnvDefault, self).__init__(
|
||||||
|
default=default, required=required, nargs=nargs, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None): # type: ignore
|
||||||
|
setattr(namespace, self.dest, values)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"-K",
|
||||||
|
"--keep-vm-state",
|
||||||
|
help="re-use a VM state coming from a previous run",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"-I",
|
||||||
|
"--interactive",
|
||||||
|
help="drop into a python repl and run the tests interactively",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--start-scripts",
|
||||||
|
metavar="START-SCRIPT",
|
||||||
|
action=EnvDefault,
|
||||||
|
envvar="startScripts",
|
||||||
|
nargs="*",
|
||||||
|
help="start scripts for participating virtual machines",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--vlans",
|
||||||
|
metavar="VLAN",
|
||||||
|
action=EnvDefault,
|
||||||
|
envvar="vlans",
|
||||||
|
nargs="*",
|
||||||
|
help="vlans to span by the driver",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"testscript",
|
||||||
|
action=EnvDefault,
|
||||||
|
envvar="testScript",
|
||||||
|
help="the test script to run",
|
||||||
|
type=Path,
|
||||||
|
)
|
||||||
|
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
if not args.keep_vm_state:
|
||||||
|
rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state")
|
||||||
|
|
||||||
|
with Driver(
|
||||||
|
args.start_scripts, args.vlans, args.testscript.read_text(), args.keep_vm_state
|
||||||
|
) as driver:
|
||||||
|
if args.interactive:
|
||||||
|
ptpython.repl.embed(driver.test_symbols(), {})
|
||||||
|
else:
|
||||||
|
tic = time.time()
|
||||||
|
driver.run_tests()
|
||||||
|
toc = time.time()
|
||||||
|
rootlog.info(f"test script finished in {(toc-tic):.2f}s")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_driver_symbols() -> None:
|
||||||
|
"""
|
||||||
|
This generates a file with symbols of the test-driver code that can be used
|
||||||
|
in user's test scripts. That list is then used by pyflakes to lint those
|
||||||
|
scripts.
|
||||||
|
"""
|
||||||
|
d = Driver([], [], "")
|
||||||
|
test_symbols = d.test_symbols()
|
||||||
|
with open("driver-symbols", "w") as fp:
|
||||||
|
fp.write(",".join(test_symbols.keys()))
|
161
nixos/lib/test-driver/test_driver/driver.py
Normal file
161
nixos/lib/test-driver/test_driver/driver.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Iterator, List
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
from test_driver.machine import Machine, NixStartScript, retry
|
||||||
|
from test_driver.vlan import VLan
|
||||||
|
|
||||||
|
|
||||||
|
class Driver:
|
||||||
|
"""A handle to the driver that sets up the environment
|
||||||
|
and runs the tests"""
|
||||||
|
|
||||||
|
tests: str
|
||||||
|
vlans: List[VLan]
|
||||||
|
machines: List[Machine]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
start_scripts: List[str],
|
||||||
|
vlans: List[int],
|
||||||
|
tests: str,
|
||||||
|
keep_vm_state: bool = False,
|
||||||
|
):
|
||||||
|
self.tests = tests
|
||||||
|
|
||||||
|
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
||||||
|
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
||||||
|
|
||||||
|
with rootlog.nested("start all VLans"):
|
||||||
|
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
|
||||||
|
|
||||||
|
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
|
||||||
|
for s in scripts:
|
||||||
|
yield NixStartScript(s)
|
||||||
|
|
||||||
|
self.machines = [
|
||||||
|
Machine(
|
||||||
|
start_command=cmd,
|
||||||
|
keep_vm_state=keep_vm_state,
|
||||||
|
name=cmd.machine_name,
|
||||||
|
tmp_dir=tmp_dir,
|
||||||
|
)
|
||||||
|
for cmd in cmd(start_scripts)
|
||||||
|
]
|
||||||
|
|
||||||
|
def __enter__(self) -> "Driver":
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *_: Any) -> None:
|
||||||
|
with rootlog.nested("cleanup"):
|
||||||
|
for machine in self.machines:
|
||||||
|
machine.release()
|
||||||
|
|
||||||
|
def subtest(self, name: str) -> Iterator[None]:
|
||||||
|
"""Group logs under a given test name"""
|
||||||
|
with rootlog.nested(name):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
rootlog.error(f'Test "{name}" failed with error: "{e}"')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def test_symbols(self) -> Dict[str, Any]:
|
||||||
|
@contextmanager
|
||||||
|
def subtest(name: str) -> Iterator[None]:
|
||||||
|
return self.subtest(name)
|
||||||
|
|
||||||
|
general_symbols = dict(
|
||||||
|
start_all=self.start_all,
|
||||||
|
test_script=self.test_script,
|
||||||
|
machines=self.machines,
|
||||||
|
vlans=self.vlans,
|
||||||
|
driver=self,
|
||||||
|
log=rootlog,
|
||||||
|
os=os,
|
||||||
|
create_machine=self.create_machine,
|
||||||
|
subtest=subtest,
|
||||||
|
run_tests=self.run_tests,
|
||||||
|
join_all=self.join_all,
|
||||||
|
retry=retry,
|
||||||
|
serial_stdout_off=self.serial_stdout_off,
|
||||||
|
serial_stdout_on=self.serial_stdout_on,
|
||||||
|
Machine=Machine, # for typing
|
||||||
|
)
|
||||||
|
machine_symbols = {m.name: m for m in self.machines}
|
||||||
|
# If there's exactly one machine, make it available under the name
|
||||||
|
# "machine", even if it's not called that.
|
||||||
|
if len(self.machines) == 1:
|
||||||
|
(machine_symbols["machine"],) = self.machines
|
||||||
|
vlan_symbols = {
|
||||||
|
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
|
||||||
|
}
|
||||||
|
print(
|
||||||
|
"additionally exposed symbols:\n "
|
||||||
|
+ ", ".join(map(lambda m: m.name, self.machines))
|
||||||
|
+ ",\n "
|
||||||
|
+ ", ".join(map(lambda v: f"vlan{v.nr}", self.vlans))
|
||||||
|
+ ",\n "
|
||||||
|
+ ", ".join(list(general_symbols.keys()))
|
||||||
|
)
|
||||||
|
return {**general_symbols, **machine_symbols, **vlan_symbols}
|
||||||
|
|
||||||
|
def test_script(self) -> None:
|
||||||
|
"""Run the test script"""
|
||||||
|
with rootlog.nested("run the VM test script"):
|
||||||
|
symbols = self.test_symbols() # call eagerly
|
||||||
|
exec(self.tests, symbols, None)
|
||||||
|
|
||||||
|
def run_tests(self) -> None:
|
||||||
|
"""Run the test script (for non-interactive test runs)"""
|
||||||
|
self.test_script()
|
||||||
|
# TODO: Collect coverage data
|
||||||
|
for machine in self.machines:
|
||||||
|
if machine.is_up():
|
||||||
|
machine.execute("sync")
|
||||||
|
|
||||||
|
def start_all(self) -> None:
|
||||||
|
"""Start all machines"""
|
||||||
|
with rootlog.nested("start all VMs"):
|
||||||
|
for machine in self.machines:
|
||||||
|
machine.start()
|
||||||
|
|
||||||
|
def join_all(self) -> None:
|
||||||
|
"""Wait for all machines to shut down"""
|
||||||
|
with rootlog.nested("wait for all VMs to finish"):
|
||||||
|
for machine in self.machines:
|
||||||
|
machine.wait_for_shutdown()
|
||||||
|
|
||||||
|
def create_machine(self, args: Dict[str, Any]) -> Machine:
|
||||||
|
rootlog.warning(
|
||||||
|
"Using legacy create_machine(), please instantiate the"
|
||||||
|
"Machine class directly, instead"
|
||||||
|
)
|
||||||
|
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
||||||
|
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
||||||
|
|
||||||
|
if args.get("startCommand"):
|
||||||
|
start_command: str = args.get("startCommand", "")
|
||||||
|
cmd = NixStartScript(start_command)
|
||||||
|
name = args.get("name", cmd.machine_name)
|
||||||
|
else:
|
||||||
|
cmd = Machine.create_startcommand(args) # type: ignore
|
||||||
|
name = args.get("name", "machine")
|
||||||
|
|
||||||
|
return Machine(
|
||||||
|
tmp_dir=tmp_dir,
|
||||||
|
start_command=cmd,
|
||||||
|
name=name,
|
||||||
|
keep_vm_state=args.get("keep_vm_state", False),
|
||||||
|
allow_reboot=args.get("allow_reboot", False),
|
||||||
|
)
|
||||||
|
|
||||||
|
def serial_stdout_on(self) -> None:
|
||||||
|
rootlog._print_serial_logs = True
|
||||||
|
|
||||||
|
def serial_stdout_off(self) -> None:
|
||||||
|
rootlog._print_serial_logs = False
|
101
nixos/lib/test-driver/test_driver/logger.py
Normal file
101
nixos/lib/test-driver/test_driver/logger.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
from colorama import Style
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from typing import Any, Dict, Iterator
|
||||||
|
from queue import Queue, Empty
|
||||||
|
from xml.sax.saxutils import XMLGenerator
|
||||||
|
import codecs
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.logfile = os.environ.get("LOGFILE", "/dev/null")
|
||||||
|
self.logfile_handle = codecs.open(self.logfile, "wb")
|
||||||
|
self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8")
|
||||||
|
self.queue: "Queue[Dict[str, str]]" = Queue()
|
||||||
|
|
||||||
|
self.xml.startDocument()
|
||||||
|
self.xml.startElement("logfile", attrs={})
|
||||||
|
|
||||||
|
self._print_serial_logs = True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _eprint(*args: object, **kwargs: Any) -> None:
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
self.xml.endElement("logfile")
|
||||||
|
self.xml.endDocument()
|
||||||
|
self.logfile_handle.close()
|
||||||
|
|
||||||
|
def sanitise(self, message: str) -> str:
|
||||||
|
return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C")
|
||||||
|
|
||||||
|
def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str:
|
||||||
|
if "machine" in attributes:
|
||||||
|
return "{}: {}".format(attributes["machine"], message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
def log_line(self, message: str, attributes: Dict[str, str]) -> None:
|
||||||
|
self.xml.startElement("line", attributes)
|
||||||
|
self.xml.characters(message)
|
||||||
|
self.xml.endElement("line")
|
||||||
|
|
||||||
|
def info(self, *args, **kwargs) -> None: # type: ignore
|
||||||
|
self.log(*args, **kwargs)
|
||||||
|
|
||||||
|
def warning(self, *args, **kwargs) -> None: # type: ignore
|
||||||
|
self.log(*args, **kwargs)
|
||||||
|
|
||||||
|
def error(self, *args, **kwargs) -> None: # type: ignore
|
||||||
|
self.log(*args, **kwargs)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
|
||||||
|
self._eprint(self.maybe_prefix(message, attributes))
|
||||||
|
self.drain_log_queue()
|
||||||
|
self.log_line(message, attributes)
|
||||||
|
|
||||||
|
def log_serial(self, message: str, machine: str) -> None:
|
||||||
|
self.enqueue({"msg": message, "machine": machine, "type": "serial"})
|
||||||
|
if self._print_serial_logs:
|
||||||
|
self._eprint(
|
||||||
|
Style.DIM + "{} # {}".format(machine, message) + Style.RESET_ALL
|
||||||
|
)
|
||||||
|
|
||||||
|
def enqueue(self, item: Dict[str, str]) -> None:
|
||||||
|
self.queue.put(item)
|
||||||
|
|
||||||
|
def drain_log_queue(self) -> None:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
item = self.queue.get_nowait()
|
||||||
|
msg = self.sanitise(item["msg"])
|
||||||
|
del item["msg"]
|
||||||
|
self.log_line(msg, item)
|
||||||
|
except Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
|
||||||
|
self._eprint(self.maybe_prefix(message, attributes))
|
||||||
|
|
||||||
|
self.xml.startElement("nest", attrs={})
|
||||||
|
self.xml.startElement("head", attributes)
|
||||||
|
self.xml.characters(message)
|
||||||
|
self.xml.endElement("head")
|
||||||
|
|
||||||
|
tic = time.time()
|
||||||
|
self.drain_log_queue()
|
||||||
|
yield
|
||||||
|
self.drain_log_queue()
|
||||||
|
toc = time.time()
|
||||||
|
self.log("(finished: {}, in {:.2f} seconds)".format(message, toc - tic))
|
||||||
|
|
||||||
|
self.xml.endElement("nest")
|
||||||
|
|
||||||
|
|
||||||
|
rootlog = Logger()
|
424
nixos/lib/test-driver/test-driver.py → nixos/lib/test-driver/test_driver/machine.py
Executable file → Normal file
424
nixos/lib/test-driver/test-driver.py → nixos/lib/test-driver/test_driver/machine.py
Executable file → Normal file
@ -1,19 +1,11 @@
|
|||||||
#! /somewhere/python3
|
from contextlib import _GeneratorContextManager
|
||||||
from contextlib import contextmanager, _GeneratorContextManager
|
|
||||||
from queue import Queue, Empty
|
|
||||||
from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List, Iterable
|
|
||||||
from xml.sax.saxutils import XMLGenerator
|
|
||||||
from colorama import Style
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import queue
|
from queue import Queue
|
||||||
import io
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
|
||||||
import threading
|
|
||||||
import argparse
|
|
||||||
import base64
|
import base64
|
||||||
import codecs
|
import io
|
||||||
import os
|
import os
|
||||||
import ptpython.repl
|
import queue
|
||||||
import pty
|
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
@ -21,8 +13,10 @@ import socket
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
import unicodedata
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
|
||||||
CHAR_TO_KEY = {
|
CHAR_TO_KEY = {
|
||||||
"A": "shift-a",
|
"A": "shift-a",
|
||||||
@ -88,115 +82,10 @@ CHAR_TO_KEY = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.logfile = os.environ.get("LOGFILE", "/dev/null")
|
|
||||||
self.logfile_handle = codecs.open(self.logfile, "wb")
|
|
||||||
self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8")
|
|
||||||
self.queue: "Queue[Dict[str, str]]" = Queue()
|
|
||||||
|
|
||||||
self.xml.startDocument()
|
|
||||||
self.xml.startElement("logfile", attrs={})
|
|
||||||
|
|
||||||
self._print_serial_logs = True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _eprint(*args: object, **kwargs: Any) -> None:
|
|
||||||
print(*args, file=sys.stderr, **kwargs)
|
|
||||||
|
|
||||||
def close(self) -> None:
|
|
||||||
self.xml.endElement("logfile")
|
|
||||||
self.xml.endDocument()
|
|
||||||
self.logfile_handle.close()
|
|
||||||
|
|
||||||
def sanitise(self, message: str) -> str:
|
|
||||||
return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C")
|
|
||||||
|
|
||||||
def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str:
|
|
||||||
if "machine" in attributes:
|
|
||||||
return "{}: {}".format(attributes["machine"], message)
|
|
||||||
return message
|
|
||||||
|
|
||||||
def log_line(self, message: str, attributes: Dict[str, str]) -> None:
|
|
||||||
self.xml.startElement("line", attributes)
|
|
||||||
self.xml.characters(message)
|
|
||||||
self.xml.endElement("line")
|
|
||||||
|
|
||||||
def info(self, *args, **kwargs) -> None: # type: ignore
|
|
||||||
self.log(*args, **kwargs)
|
|
||||||
|
|
||||||
def warning(self, *args, **kwargs) -> None: # type: ignore
|
|
||||||
self.log(*args, **kwargs)
|
|
||||||
|
|
||||||
def error(self, *args, **kwargs) -> None: # type: ignore
|
|
||||||
self.log(*args, **kwargs)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
|
|
||||||
self._eprint(self.maybe_prefix(message, attributes))
|
|
||||||
self.drain_log_queue()
|
|
||||||
self.log_line(message, attributes)
|
|
||||||
|
|
||||||
def log_serial(self, message: str, machine: str) -> None:
|
|
||||||
self.enqueue({"msg": message, "machine": machine, "type": "serial"})
|
|
||||||
if self._print_serial_logs:
|
|
||||||
self._eprint(
|
|
||||||
Style.DIM + "{} # {}".format(machine, message) + Style.RESET_ALL
|
|
||||||
)
|
|
||||||
|
|
||||||
def enqueue(self, item: Dict[str, str]) -> None:
|
|
||||||
self.queue.put(item)
|
|
||||||
|
|
||||||
def drain_log_queue(self) -> None:
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
item = self.queue.get_nowait()
|
|
||||||
msg = self.sanitise(item["msg"])
|
|
||||||
del item["msg"]
|
|
||||||
self.log_line(msg, item)
|
|
||||||
except Empty:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
|
|
||||||
self._eprint(self.maybe_prefix(message, attributes))
|
|
||||||
|
|
||||||
self.xml.startElement("nest", attrs={})
|
|
||||||
self.xml.startElement("head", attributes)
|
|
||||||
self.xml.characters(message)
|
|
||||||
self.xml.endElement("head")
|
|
||||||
|
|
||||||
tic = time.time()
|
|
||||||
self.drain_log_queue()
|
|
||||||
yield
|
|
||||||
self.drain_log_queue()
|
|
||||||
toc = time.time()
|
|
||||||
self.log("(finished: {}, in {:.2f} seconds)".format(message, toc - tic))
|
|
||||||
|
|
||||||
self.xml.endElement("nest")
|
|
||||||
|
|
||||||
|
|
||||||
rootlog = Logger()
|
|
||||||
|
|
||||||
|
|
||||||
def make_command(args: list) -> str:
|
def make_command(args: list) -> str:
|
||||||
return " ".join(map(shlex.quote, (map(str, args))))
|
return " ".join(map(shlex.quote, (map(str, args))))
|
||||||
|
|
||||||
|
|
||||||
def retry(fn: Callable, timeout: int = 900) -> None:
|
|
||||||
"""Call the given function repeatedly, with 1 second intervals,
|
|
||||||
until it returns True or a timeout is reached.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for _ in range(timeout):
|
|
||||||
if fn(False):
|
|
||||||
return
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
if not fn(True):
|
|
||||||
raise Exception(f"action timed out after {timeout} seconds")
|
|
||||||
|
|
||||||
|
|
||||||
def _perform_ocr_on_screenshot(
|
def _perform_ocr_on_screenshot(
|
||||||
screenshot_path: str, model_ids: Iterable[int]
|
screenshot_path: str, model_ids: Iterable[int]
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
@ -228,6 +117,20 @@ def _perform_ocr_on_screenshot(
|
|||||||
return model_results
|
return model_results
|
||||||
|
|
||||||
|
|
||||||
|
def retry(fn: Callable, timeout: int = 900) -> None:
|
||||||
|
"""Call the given function repeatedly, with 1 second intervals,
|
||||||
|
until it returns True or a timeout is reached.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for _ in range(timeout):
|
||||||
|
if fn(False):
|
||||||
|
return
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
if not fn(True):
|
||||||
|
raise Exception(f"action timed out after {timeout} seconds")
|
||||||
|
|
||||||
|
|
||||||
class StartCommand:
|
class StartCommand:
|
||||||
"""The Base Start Command knows how to append the necesary
|
"""The Base Start Command knows how to append the necesary
|
||||||
runtime qemu options as determined by a particular test driver
|
runtime qemu options as determined by a particular test driver
|
||||||
@ -1066,286 +969,3 @@ class Machine:
|
|||||||
self.shell.close()
|
self.shell.close()
|
||||||
self.monitor.close()
|
self.monitor.close()
|
||||||
self.serial_thread.join()
|
self.serial_thread.join()
|
||||||
|
|
||||||
|
|
||||||
class VLan:
|
|
||||||
"""This class handles a VLAN that the run-vm scripts identify via its
|
|
||||||
number handles. The network's lifetime equals the object's lifetime.
|
|
||||||
"""
|
|
||||||
|
|
||||||
nr: int
|
|
||||||
socket_dir: Path
|
|
||||||
|
|
||||||
process: subprocess.Popen
|
|
||||||
pid: int
|
|
||||||
fd: io.TextIOBase
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Vlan Nr. {self.nr}>"
|
|
||||||
|
|
||||||
def __init__(self, nr: int, tmp_dir: Path):
|
|
||||||
self.nr = nr
|
|
||||||
self.socket_dir = tmp_dir / f"vde{self.nr}.ctl"
|
|
||||||
|
|
||||||
# TODO: don't side-effect environment here
|
|
||||||
os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir)
|
|
||||||
|
|
||||||
rootlog.info("start vlan")
|
|
||||||
pty_master, pty_slave = pty.openpty()
|
|
||||||
|
|
||||||
self.process = subprocess.Popen(
|
|
||||||
["vde_switch", "-s", self.socket_dir, "--dirmode", "0700"],
|
|
||||||
stdin=pty_slave,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE,
|
|
||||||
shell=False,
|
|
||||||
)
|
|
||||||
self.pid = self.process.pid
|
|
||||||
self.fd = os.fdopen(pty_master, "w")
|
|
||||||
self.fd.write("version\n")
|
|
||||||
|
|
||||||
# TODO: perl version checks if this can be read from
|
|
||||||
# an if not, dies. we could hang here forever. Fix it.
|
|
||||||
assert self.process.stdout is not None
|
|
||||||
self.process.stdout.readline()
|
|
||||||
if not (self.socket_dir / "ctl").exists():
|
|
||||||
rootlog.error("cannot start vde_switch")
|
|
||||||
|
|
||||||
rootlog.info(f"running vlan (pid {self.pid})")
|
|
||||||
|
|
||||||
def __del__(self) -> None:
|
|
||||||
rootlog.info(f"kill vlan (pid {self.pid})")
|
|
||||||
self.fd.close()
|
|
||||||
self.process.terminate()
|
|
||||||
|
|
||||||
|
|
||||||
class Driver:
|
|
||||||
"""A handle to the driver that sets up the environment
|
|
||||||
and runs the tests"""
|
|
||||||
|
|
||||||
tests: str
|
|
||||||
vlans: List[VLan]
|
|
||||||
machines: List[Machine]
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
start_scripts: List[str],
|
|
||||||
vlans: List[int],
|
|
||||||
tests: str,
|
|
||||||
keep_vm_state: bool = False,
|
|
||||||
):
|
|
||||||
self.tests = tests
|
|
||||||
|
|
||||||
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
|
||||||
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
|
||||||
|
|
||||||
with rootlog.nested("start all VLans"):
|
|
||||||
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
|
|
||||||
|
|
||||||
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
|
|
||||||
for s in scripts:
|
|
||||||
yield NixStartScript(s)
|
|
||||||
|
|
||||||
self.machines = [
|
|
||||||
Machine(
|
|
||||||
start_command=cmd,
|
|
||||||
keep_vm_state=keep_vm_state,
|
|
||||||
name=cmd.machine_name,
|
|
||||||
tmp_dir=tmp_dir,
|
|
||||||
)
|
|
||||||
for cmd in cmd(start_scripts)
|
|
||||||
]
|
|
||||||
|
|
||||||
def __enter__(self) -> "Driver":
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, *_: Any) -> None:
|
|
||||||
with rootlog.nested("cleanup"):
|
|
||||||
for machine in self.machines:
|
|
||||||
machine.release()
|
|
||||||
|
|
||||||
def subtest(self, name: str) -> Iterator[None]:
|
|
||||||
"""Group logs under a given test name"""
|
|
||||||
with rootlog.nested(name):
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
rootlog.error(f'Test "{name}" failed with error: "{e}"')
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def test_symbols(self) -> Dict[str, Any]:
|
|
||||||
@contextmanager
|
|
||||||
def subtest(name: str) -> Iterator[None]:
|
|
||||||
return self.subtest(name)
|
|
||||||
|
|
||||||
general_symbols = dict(
|
|
||||||
start_all=self.start_all,
|
|
||||||
test_script=self.test_script,
|
|
||||||
machines=self.machines,
|
|
||||||
vlans=self.vlans,
|
|
||||||
driver=self,
|
|
||||||
log=rootlog,
|
|
||||||
os=os,
|
|
||||||
create_machine=self.create_machine,
|
|
||||||
subtest=subtest,
|
|
||||||
run_tests=self.run_tests,
|
|
||||||
join_all=self.join_all,
|
|
||||||
retry=retry,
|
|
||||||
serial_stdout_off=self.serial_stdout_off,
|
|
||||||
serial_stdout_on=self.serial_stdout_on,
|
|
||||||
Machine=Machine, # for typing
|
|
||||||
)
|
|
||||||
machine_symbols = {m.name: m for m in self.machines}
|
|
||||||
# If there's exactly one machine, make it available under the name
|
|
||||||
# "machine", even if it's not called that.
|
|
||||||
if len(self.machines) == 1:
|
|
||||||
(machine_symbols["machine"],) = self.machines
|
|
||||||
vlan_symbols = {
|
|
||||||
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
|
|
||||||
}
|
|
||||||
print(
|
|
||||||
"additionally exposed symbols:\n "
|
|
||||||
+ ", ".join(map(lambda m: m.name, self.machines))
|
|
||||||
+ ",\n "
|
|
||||||
+ ", ".join(map(lambda v: f"vlan{v.nr}", self.vlans))
|
|
||||||
+ ",\n "
|
|
||||||
+ ", ".join(list(general_symbols.keys()))
|
|
||||||
)
|
|
||||||
return {**general_symbols, **machine_symbols, **vlan_symbols}
|
|
||||||
|
|
||||||
def test_script(self) -> None:
|
|
||||||
"""Run the test script"""
|
|
||||||
with rootlog.nested("run the VM test script"):
|
|
||||||
symbols = self.test_symbols() # call eagerly
|
|
||||||
exec(self.tests, symbols, None)
|
|
||||||
|
|
||||||
def run_tests(self) -> None:
|
|
||||||
"""Run the test script (for non-interactive test runs)"""
|
|
||||||
self.test_script()
|
|
||||||
# TODO: Collect coverage data
|
|
||||||
for machine in self.machines:
|
|
||||||
if machine.is_up():
|
|
||||||
machine.execute("sync")
|
|
||||||
|
|
||||||
def start_all(self) -> None:
|
|
||||||
"""Start all machines"""
|
|
||||||
with rootlog.nested("start all VMs"):
|
|
||||||
for machine in self.machines:
|
|
||||||
machine.start()
|
|
||||||
|
|
||||||
def join_all(self) -> None:
|
|
||||||
"""Wait for all machines to shut down"""
|
|
||||||
with rootlog.nested("wait for all VMs to finish"):
|
|
||||||
for machine in self.machines:
|
|
||||||
machine.wait_for_shutdown()
|
|
||||||
|
|
||||||
def create_machine(self, args: Dict[str, Any]) -> Machine:
|
|
||||||
rootlog.warning(
|
|
||||||
"Using legacy create_machine(), please instantiate the"
|
|
||||||
"Machine class directly, instead"
|
|
||||||
)
|
|
||||||
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
|
||||||
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
|
||||||
|
|
||||||
if args.get("startCommand"):
|
|
||||||
start_command: str = args.get("startCommand", "")
|
|
||||||
cmd = NixStartScript(start_command)
|
|
||||||
name = args.get("name", cmd.machine_name)
|
|
||||||
else:
|
|
||||||
cmd = Machine.create_startcommand(args) # type: ignore
|
|
||||||
name = args.get("name", "machine")
|
|
||||||
|
|
||||||
return Machine(
|
|
||||||
tmp_dir=tmp_dir,
|
|
||||||
start_command=cmd,
|
|
||||||
name=name,
|
|
||||||
keep_vm_state=args.get("keep_vm_state", False),
|
|
||||||
allow_reboot=args.get("allow_reboot", False),
|
|
||||||
)
|
|
||||||
|
|
||||||
def serial_stdout_on(self) -> None:
|
|
||||||
rootlog._print_serial_logs = True
|
|
||||||
|
|
||||||
def serial_stdout_off(self) -> None:
|
|
||||||
rootlog._print_serial_logs = False
|
|
||||||
|
|
||||||
|
|
||||||
class EnvDefault(argparse.Action):
|
|
||||||
"""An argpars Action that takes values from the specified
|
|
||||||
environment variable as the flags default value.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs): # type: ignore
|
|
||||||
if not default and envvar:
|
|
||||||
if envvar in os.environ:
|
|
||||||
if nargs is not None and (nargs.isdigit() or nargs in ["*", "+"]):
|
|
||||||
default = os.environ[envvar].split()
|
|
||||||
else:
|
|
||||||
default = os.environ[envvar]
|
|
||||||
kwargs["help"] = (
|
|
||||||
kwargs["help"] + f" (default from environment: {default})"
|
|
||||||
)
|
|
||||||
if required and default:
|
|
||||||
required = False
|
|
||||||
super(EnvDefault, self).__init__(
|
|
||||||
default=default, required=required, nargs=nargs, **kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None): # type: ignore
|
|
||||||
setattr(namespace, self.dest, values)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"-K",
|
|
||||||
"--keep-vm-state",
|
|
||||||
help="re-use a VM state coming from a previous run",
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"-I",
|
|
||||||
"--interactive",
|
|
||||||
help="drop into a python repl and run the tests interactively",
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"--start-scripts",
|
|
||||||
metavar="START-SCRIPT",
|
|
||||||
action=EnvDefault,
|
|
||||||
envvar="startScripts",
|
|
||||||
nargs="*",
|
|
||||||
help="start scripts for participating virtual machines",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"--vlans",
|
|
||||||
metavar="VLAN",
|
|
||||||
action=EnvDefault,
|
|
||||||
envvar="vlans",
|
|
||||||
nargs="*",
|
|
||||||
help="vlans to span by the driver",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"testscript",
|
|
||||||
action=EnvDefault,
|
|
||||||
envvar="testScript",
|
|
||||||
help="the test script to run",
|
|
||||||
type=Path,
|
|
||||||
)
|
|
||||||
|
|
||||||
args = arg_parser.parse_args()
|
|
||||||
|
|
||||||
if not args.keep_vm_state:
|
|
||||||
rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state")
|
|
||||||
|
|
||||||
with Driver(
|
|
||||||
args.start_scripts, args.vlans, args.testscript.read_text(), args.keep_vm_state
|
|
||||||
) as driver:
|
|
||||||
if args.interactive:
|
|
||||||
ptpython.repl.embed(driver.test_symbols(), {})
|
|
||||||
else:
|
|
||||||
tic = time.time()
|
|
||||||
driver.run_tests()
|
|
||||||
toc = time.time()
|
|
||||||
rootlog.info(f"test script finished in {(toc-tic):.2f}s")
|
|
58
nixos/lib/test-driver/test_driver/vlan.py
Normal file
58
nixos/lib/test-driver/test_driver/vlan.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import pty
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
|
||||||
|
|
||||||
|
class VLan:
|
||||||
|
"""This class handles a VLAN that the run-vm scripts identify via its
|
||||||
|
number handles. The network's lifetime equals the object's lifetime.
|
||||||
|
"""
|
||||||
|
|
||||||
|
nr: int
|
||||||
|
socket_dir: Path
|
||||||
|
|
||||||
|
process: subprocess.Popen
|
||||||
|
pid: int
|
||||||
|
fd: io.TextIOBase
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Vlan Nr. {self.nr}>"
|
||||||
|
|
||||||
|
def __init__(self, nr: int, tmp_dir: Path):
|
||||||
|
self.nr = nr
|
||||||
|
self.socket_dir = tmp_dir / f"vde{self.nr}.ctl"
|
||||||
|
|
||||||
|
# TODO: don't side-effect environment here
|
||||||
|
os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir)
|
||||||
|
|
||||||
|
rootlog.info("start vlan")
|
||||||
|
pty_master, pty_slave = pty.openpty()
|
||||||
|
|
||||||
|
self.process = subprocess.Popen(
|
||||||
|
["vde_switch", "-s", self.socket_dir, "--dirmode", "0700"],
|
||||||
|
stdin=pty_slave,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
shell=False,
|
||||||
|
)
|
||||||
|
self.pid = self.process.pid
|
||||||
|
self.fd = os.fdopen(pty_master, "w")
|
||||||
|
self.fd.write("version\n")
|
||||||
|
|
||||||
|
# TODO: perl version checks if this can be read from
|
||||||
|
# an if not, dies. we could hang here forever. Fix it.
|
||||||
|
assert self.process.stdout is not None
|
||||||
|
self.process.stdout.readline()
|
||||||
|
if not (self.socket_dir / "ctl").exists():
|
||||||
|
rootlog.error("cannot start vde_switch")
|
||||||
|
|
||||||
|
rootlog.info(f"running vlan (pid {self.pid})")
|
||||||
|
|
||||||
|
def __del__(self) -> None:
|
||||||
|
rootlog.info(f"kill vlan (pid {self.pid})")
|
||||||
|
self.fd.close()
|
||||||
|
self.process.terminate()
|
@ -16,65 +16,6 @@ rec {
|
|||||||
|
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
|
|
||||||
# Reifies and correctly wraps the python test driver for
|
|
||||||
# the respective qemu version and with or without ocr support
|
|
||||||
pythonTestDriver = {
|
|
||||||
qemu_pkg ? pkgs.qemu_test
|
|
||||||
, enableOCR ? false
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
name = "nixos-test-driver";
|
|
||||||
testDriverScript = ./test-driver/test-driver.py;
|
|
||||||
ocrProg = tesseract4.override { enableLanguages = [ "eng" ]; };
|
|
||||||
imagemagick_tiff = imagemagick_light.override { inherit libtiff; };
|
|
||||||
in stdenv.mkDerivation {
|
|
||||||
inherit name;
|
|
||||||
|
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
|
||||||
buildInputs = [ (python3.withPackages (p: [ p.ptpython p.colorama ])) ];
|
|
||||||
checkInputs = with python3Packages; [ pylint black mypy ];
|
|
||||||
|
|
||||||
dontUnpack = true;
|
|
||||||
|
|
||||||
preferLocalBuild = true;
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
python <<EOF
|
|
||||||
from pydoc import importfile
|
|
||||||
with open('driver-symbols', 'w') as fp:
|
|
||||||
t = importfile('${testDriverScript}')
|
|
||||||
d = t.Driver([],[],"")
|
|
||||||
test_symbols = d.test_symbols()
|
|
||||||
fp.write(','.join(test_symbols.keys()))
|
|
||||||
EOF
|
|
||||||
'';
|
|
||||||
|
|
||||||
doCheck = true;
|
|
||||||
checkPhase = ''
|
|
||||||
mypy --disallow-untyped-defs \
|
|
||||||
--no-implicit-optional \
|
|
||||||
--ignore-missing-imports ${testDriverScript}
|
|
||||||
pylint --errors-only ${testDriverScript}
|
|
||||||
black --check --diff ${testDriverScript}
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase =
|
|
||||||
''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp ${testDriverScript} $out/bin/nixos-test-driver
|
|
||||||
chmod u+x $out/bin/nixos-test-driver
|
|
||||||
# TODO: copy user script part into this file (append)
|
|
||||||
|
|
||||||
wrapProgram $out/bin/nixos-test-driver \
|
|
||||||
--argv0 ${name} \
|
|
||||||
--prefix PATH : "${lib.makeBinPath [ qemu_pkg vde2 netpbm coreutils socat ]}" \
|
|
||||||
${lib.optionalString enableOCR
|
|
||||||
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
|
|
||||||
|
|
||||||
install -m 0644 -vD driver-symbols $out/nix-support/driver-symbols
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# Run an automated test suite in the given virtual network.
|
# Run an automated test suite in the given virtual network.
|
||||||
runTests = { driver, pos }:
|
runTests = { driver, pos }:
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
@ -112,8 +53,15 @@ rec {
|
|||||||
, passthru ? {}
|
, passthru ? {}
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# FIXME: get this pkg from the module system
|
# Reifies and correctly wraps the python test driver for
|
||||||
testDriver = pythonTestDriver { inherit qemu_pkg enableOCR;};
|
# the respective qemu version and with or without ocr support
|
||||||
|
testDriver = pkgs.callPackage ./test-driver {
|
||||||
|
inherit enableOCR;
|
||||||
|
qemu_pkg = qemu_test;
|
||||||
|
imagemagick_light = imagemagick_light.override { inherit libtiff; };
|
||||||
|
tesseract4 = tesseract4.override { enableLanguages = [ "eng" ]; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
testDriverName =
|
testDriverName =
|
||||||
let
|
let
|
||||||
@ -178,10 +126,11 @@ rec {
|
|||||||
echo -n "$testScript" > $out/test-script
|
echo -n "$testScript" > $out/test-script
|
||||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
|
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
|
||||||
|
|
||||||
|
${testDriver}/bin/generate-driver-symbols
|
||||||
${lib.optionalString (!skipLint) ''
|
${lib.optionalString (!skipLint) ''
|
||||||
PYFLAKES_BUILTINS="$(
|
PYFLAKES_BUILTINS="$(
|
||||||
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
|
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
|
||||||
< ${lib.escapeShellArg "${testDriver}/nix-support/driver-symbols"}
|
< ${lib.escapeShellArg "driver-symbols"}
|
||||||
)" ${python3Packages.pyflakes}/bin/pyflakes $out/test-script
|
)" ${python3Packages.pyflakes}/bin/pyflakes $out/test-script
|
||||||
''}
|
''}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
let
|
let
|
||||||
pname = "trezor-suite";
|
pname = "trezor-suite";
|
||||||
version = "21.11.2";
|
version = "21.12.2";
|
||||||
name = "${pname}-${version}";
|
name = "${pname}-${version}";
|
||||||
|
|
||||||
suffix = {
|
suffix = {
|
||||||
@ -19,8 +19,8 @@ let
|
|||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://github.com/trezor/${pname}/releases/download/v${version}/Trezor-Suite-${version}-${suffix}.AppImage";
|
url = "https://github.com/trezor/${pname}/releases/download/v${version}/Trezor-Suite-${version}-${suffix}.AppImage";
|
||||||
sha512 = { # curl -Lfs https://github.com/trezor/trezor-suite/releases/latest/download/latest-linux{-arm64,}.yml | grep ^sha512 | sed 's/: /-/'
|
sha512 = { # curl -Lfs https://github.com/trezor/trezor-suite/releases/latest/download/latest-linux{-arm64,}.yml | grep ^sha512 | sed 's/: /-/'
|
||||||
aarch64-linux = "sha512-QX5Ak2F1aD846BuGNcP1K/2c77Ut3LK3UiXsUPqiSBGZ9YRgdzROqdGjCVnTBBhxeCfGYQDhWmpuOpNbLr4eYg==";
|
aarch64-linux = "sha512-LzcTFSNN/loYaTDt+QpW8QpSgOTw2097IYdc7mC57Mn4NR/X2hycYZ9ZfZjBh9QFfVu/4R3UN2sA177v6Inomg==";
|
||||||
x86_64-linux = "sha512-ckMlZoLEq3aLzyhoWf2rRE3XxNQhqo6rUHF2NKoV08sXz+Zth2Lk+P3te1vwFQl+Efryl84RTwVGWKmloZ8k9A==";
|
x86_64-linux = "sha512-W/voBZrXaJVDN4eSUDD6lyBR9BqboD2k2/azI1pWm1NFUmDZFM+OGzyiPB3n+6SziAhca32Ot5Wy27sfmIjh3g==";
|
||||||
}.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
|
}.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,8 +34,8 @@ let
|
|||||||
qonlinetranslator = fetchFromGitHub {
|
qonlinetranslator = fetchFromGitHub {
|
||||||
owner = "crow-translate";
|
owner = "crow-translate";
|
||||||
repo = "QOnlineTranslator";
|
repo = "QOnlineTranslator";
|
||||||
rev = "df89083d2f680a8f856b1df00b8846f995cf1fae";
|
rev = "1.5.2";
|
||||||
sha256 = "sha256-I64KGInnYd/QdI5kANJERsF95wMvRlr8kgQhUqXXN/0=";
|
sha256 = "sha256-iGi25aKwff2hNNx6o4kHZV8gVbEQcMgpTTvop3CoLjM=";
|
||||||
};
|
};
|
||||||
circleflags = fetchFromGitHub {
|
circleflags = fetchFromGitHub {
|
||||||
owner = "HatScripts";
|
owner = "HatScripts";
|
||||||
@ -52,13 +52,13 @@ let
|
|||||||
in
|
in
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "crow-translate";
|
pname = "crow-translate";
|
||||||
version = "2.8.7";
|
version = "2.9.1";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "crow-translate";
|
owner = "crow-translate";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "sha256-0bq9itbFyzdOhdNuUtdCYLTCIhc91MM+YRhJgXC5PPw=";
|
sha256 = "sha256-7Zb6PZO8eLeGPEZD37ja+LZydIQdsgy5gMAMtlS4k5Y=";
|
||||||
};
|
};
|
||||||
|
|
||||||
patches = [
|
patches = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
diff --git i/CMakeLists.txt w/CMakeLists.txt
|
diff --git i/CMakeLists.txt w/CMakeLists.txt
|
||||||
index faa9417..059b899 100644
|
index 375b17c..106efa9 100644
|
||||||
--- i/CMakeLists.txt
|
--- i/CMakeLists.txt
|
||||||
+++ w/CMakeLists.txt
|
+++ w/CMakeLists.txt
|
||||||
@@ -101,13 +101,11 @@ qt5_add_translation(QM_FILES
|
@@ -114,13 +114,11 @@ qt5_add_translation(QM_FILES
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file(src/cmake.h.in cmake.h)
|
configure_file(src/cmake.h.in cmake.h)
|
||||||
@ -19,7 +19,7 @@ index faa9417..059b899 100644
|
|||||||
src/addlanguagedialog.cpp
|
src/addlanguagedialog.cpp
|
||||||
src/addlanguagedialog.ui
|
src/addlanguagedialog.ui
|
||||||
diff --git i/cmake/ExternalLibraries.cmake w/cmake/ExternalLibraries.cmake
|
diff --git i/cmake/ExternalLibraries.cmake w/cmake/ExternalLibraries.cmake
|
||||||
index e2501e1..e15ce6c 100644
|
index c92e745..f265f03 100644
|
||||||
--- i/cmake/ExternalLibraries.cmake
|
--- i/cmake/ExternalLibraries.cmake
|
||||||
+++ w/cmake/ExternalLibraries.cmake
|
+++ w/cmake/ExternalLibraries.cmake
|
||||||
@@ -2,34 +2,28 @@ include(FetchContent)
|
@@ -2,34 +2,28 @@ include(FetchContent)
|
||||||
@ -46,7 +46,7 @@ index e2501e1..e15ce6c 100644
|
|||||||
|
|
||||||
FetchContent_Declare(QOnlineTranslator
|
FetchContent_Declare(QOnlineTranslator
|
||||||
- GIT_REPOSITORY https://github.com/crow-translate/QOnlineTranslator
|
- GIT_REPOSITORY https://github.com/crow-translate/QOnlineTranslator
|
||||||
- GIT_TAG df89083d2f680a8f856b1df00b8846f995cf1fae
|
- GIT_TAG 1.5.2
|
||||||
+ SOURCE_DIR @qonlinetranslator@
|
+ SOURCE_DIR @qonlinetranslator@
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
diff --git i/src/settings/appsettings.cpp w/src/settings/appsettings.cpp
|
diff --git i/src/settings/appsettings.cpp w/src/settings/appsettings.cpp
|
||||||
index aa8b357..15e4f74 100644
|
index a73371b..b9d66ca 100644
|
||||||
--- i/src/settings/appsettings.cpp
|
--- i/src/settings/appsettings.cpp
|
||||||
+++ w/src/settings/appsettings.cpp
|
+++ w/src/settings/appsettings.cpp
|
||||||
@@ -81,7 +81,7 @@ void AppSettings::applyLanguage(QLocale::Language lang)
|
@@ -75,7 +75,7 @@ void AppSettings::applyLocale(const QLocale &locale)
|
||||||
QLocale::setDefault(locale);
|
const QLocale newLocale = locale == defaultLocale() ? QLocale::system() : locale;
|
||||||
|
QLocale::setDefault(newLocale);
|
||||||
s_appTranslator.load(locale, QStringLiteral(PROJECT_NAME), QStringLiteral("_"), QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("translations"), QStandardPaths::LocateDirectory));
|
s_appTranslator.load(newLocale, QStringLiteral(PROJECT_NAME), QStringLiteral("_"), QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("translations"), QStandardPaths::LocateDirectory));
|
||||||
- s_qtTranslator.load(locale, QStringLiteral("qtbase"), QStringLiteral("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
- s_qtTranslator.load(newLocale, QStringLiteral("qt"), QStringLiteral("_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
|
||||||
+ s_qtTranslator.load(locale, QStringLiteral("qtbase"), QStringLiteral("_"), QLatin1String("@qttranslations@/translations"));
|
+ s_qtTranslator.load(newLocale, QStringLiteral("qt"), QStringLiteral("_"), QLatin1String("@qttranslations@/translations"));
|
||||||
}
|
}
|
||||||
|
|
||||||
QLocale::Language AppSettings::defaultLanguage()
|
QLocale AppSettings::defaultLocale()
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
{ fetchurl, lib, stdenv, makeDesktopItem, makeWrapper, unzip, jdk }:
|
{ fetchurl, lib, stdenv, makeDesktopItem, makeWrapper, unzip, jre, copyDesktopItems }:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "gpsprune";
|
pname = "gpsprune";
|
||||||
version = "20.4";
|
version = "21";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://activityworkshop.net/software/gpsprune/gpsprune_${version}.jar";
|
url = "https://activityworkshop.net/software/gpsprune/gpsprune_${version}.jar";
|
||||||
sha256 = "sha256-ZTYkKyu0/axf2uLUmQHRW/2bQ6p2zK7xBF66ozbPS2c=";
|
sha256 = "sha256-FS6nf8K+qfEWDCQwmoxH1laJIONMtwmb/H89SVJtV1E=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
dontUnpack = true;
|
||||||
buildInputs = [ jdk ];
|
|
||||||
|
|
||||||
desktopItem = makeDesktopItem {
|
nativeBuildInputs = [ makeWrapper copyDesktopItems ];
|
||||||
|
buildInputs = [ jre ];
|
||||||
|
|
||||||
|
desktopItems = [
|
||||||
|
(makeDesktopItem {
|
||||||
name = "gpsprune";
|
name = "gpsprune";
|
||||||
exec = "gpsprune";
|
exec = "gpsprune";
|
||||||
icon = "gpsprune";
|
icon = "gpsprune";
|
||||||
@ -20,24 +23,26 @@ stdenv.mkDerivation rec {
|
|||||||
genericName = "GPS Data Editor";
|
genericName = "GPS Data Editor";
|
||||||
comment = meta.description;
|
comment = meta.description;
|
||||||
categories = "Education;Geoscience;";
|
categories = "Education;Geoscience;";
|
||||||
};
|
})
|
||||||
|
];
|
||||||
|
|
||||||
buildCommand = ''
|
installPhase = ''
|
||||||
mkdir -p $out/bin $out/share/java
|
runHook preInstall
|
||||||
cp -v $src $out/share/java/gpsprune.jar
|
|
||||||
makeWrapper ${jdk}/bin/java $out/bin/gpsprune \
|
install -Dm644 ${src} $out/share/java/gpsprune.jar
|
||||||
|
makeWrapper ${jre}/bin/java $out/bin/gpsprune \
|
||||||
--add-flags "-jar $out/share/java/gpsprune.jar"
|
--add-flags "-jar $out/share/java/gpsprune.jar"
|
||||||
mkdir -p $out/share/applications
|
|
||||||
cp $desktopItem/share/applications"/"* $out/share/applications
|
|
||||||
mkdir -p $out/share/pixmaps
|
mkdir -p $out/share/pixmaps
|
||||||
${unzip}/bin/unzip -p $src tim/prune/gui/images/window_icon_64.png > $out/share/pixmaps/gpsprune.png
|
${unzip}/bin/unzip -p $src tim/prune/gui/images/window_icon_64.png > $out/share/pixmaps/gpsprune.png
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
'';
|
'';
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "Application for viewing, editing and converting GPS coordinate data";
|
description = "Application for viewing, editing and converting GPS coordinate data";
|
||||||
homepage = "https://activityworkshop.net/software/gpsprune/";
|
homepage = "https://activityworkshop.net/software/gpsprune/";
|
||||||
license = licenses.gpl2Plus;
|
license = licenses.gpl2Plus;
|
||||||
maintainers = [ maintainers.rycee ];
|
maintainers = with maintainers; [ rycee ];
|
||||||
platforms = platforms.all;
|
platforms = platforms.all;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@
|
|||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "jgmenu";
|
pname = "jgmenu";
|
||||||
version = "4.3.0";
|
version = "4.4.0";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "johanmalm";
|
owner = "johanmalm";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-+JO/A7+6/yeYz0tP7vxSi04cS1bEet+3sAs7CYXKxI8=";
|
sha256 = "sha256-REzrN4tz+cFmKyJeOPOkzjvthsJdY3GButF7RdnzviE=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"beta": {
|
"beta": {
|
||||||
"version": "97.0.4692.36",
|
"version": "97.0.4692.45",
|
||||||
"sha256": "0p0f19svnymql8skx6alb6zy4fmc5115dc2avs8h2mca1q8n5r0s",
|
"sha256": "1x55hys3340inrwwp4lzw5vq3vrg56288m746d4p2ligvsy19byp",
|
||||||
"sha256bin64": "08p0rwn4jglrzma1vf4jnyqaffnk0c8xwc7jkgfpkasm43d72zim",
|
"sha256bin64": "1jyhq27fb4pzbxlg0ssfz66hza9g8cbsqyx70ydkjqs9sf4yqqcw",
|
||||||
"deps": {
|
"deps": {
|
||||||
"gn": {
|
"gn": {
|
||||||
"version": "2021-11-03",
|
"version": "2021-11-03",
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "qownnotes";
|
pname = "qownnotes";
|
||||||
version = "21.11.4";
|
version = "21.12.1";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "https://download.tuxfamily.org/${pname}/src/${pname}-${version}.tar.xz";
|
url = "https://download.tuxfamily.org/${pname}/src/${pname}-${version}.tar.xz";
|
||||||
# Fetch the checksum of current version with curl:
|
# Fetch the checksum of current version with curl:
|
||||||
# curl https://download.tuxfamily.org/qownnotes/src/qownnotes-<version>.tar.xz.sha256
|
# curl https://download.tuxfamily.org/qownnotes/src/qownnotes-<version>.tar.xz.sha256
|
||||||
sha256 = "3eb025873160cecd4fa35ae5079c150d4aa5dd3152fd58c5e216b592af43e8dc";
|
sha256 = "sha256-gTxt3U2/x3VMWYU9cb5FPRvqezdn2K6VGYwEKBi5xFk=";
|
||||||
};
|
};
|
||||||
|
|
||||||
nativeBuildInputs = [ qmake qttools ];
|
nativeBuildInputs = [ qmake qttools ];
|
||||||
|
@ -27,13 +27,13 @@
|
|||||||
|
|
||||||
mkDerivation rec {
|
mkDerivation rec {
|
||||||
pname = "haruna";
|
pname = "haruna";
|
||||||
version = "0.7.2";
|
version = "0.7.3";
|
||||||
|
|
||||||
src = fetchFromGitLab {
|
src = fetchFromGitLab {
|
||||||
owner = "multimedia";
|
owner = "multimedia";
|
||||||
repo = "haruna";
|
repo = "haruna";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-0s4v3YJhSssp2S9mppMXq0AtWXPIaqOYWPmJgKjXjDE=";
|
sha256 = "sha256-pFrmTaRvsqxJw34VULzfjx2k56kJgkB96nJtai2D1wY=";
|
||||||
domain = "invent.kde.org";
|
domain = "invent.kde.org";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,14 +17,14 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
version = "3.42.1";
|
version = "3.42.2";
|
||||||
pname = "gpaste";
|
pname = "gpaste";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "Keruspe";
|
owner = "Keruspe";
|
||||||
repo = "GPaste";
|
repo = "GPaste";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-yoJ/k9cXXF5ELKF0JXGtxsUjfQ/S1sccLRQOQG7YMXo=";
|
sha256 = "sha256-VWtq1jPwUHHIDpVaSYQ0FiihlfulRofFmacMyv/buMw=";
|
||||||
};
|
};
|
||||||
|
|
||||||
patches = [
|
patches = [
|
||||||
|
@ -49,7 +49,7 @@ buildPythonPackage rec {
|
|||||||
];
|
];
|
||||||
|
|
||||||
pytestFlagsArray = [
|
pytestFlagsArray = [
|
||||||
"--numprocesses" "auto"
|
"--numprocesses" "$NIX_BUILD_CORES"
|
||||||
];
|
];
|
||||||
|
|
||||||
preCheck = ''
|
preCheck = ''
|
||||||
|
@ -1,21 +1,43 @@
|
|||||||
{ buildPythonPackage, fetchFromGitHub, pillow, scipy, numpy, pytestCheckHook, imread, freeimage, lib, stdenv }:
|
{ buildPythonPackage
|
||||||
|
, fetchFromGitHub
|
||||||
|
, fetchpatch
|
||||||
|
, pillow
|
||||||
|
, scipy
|
||||||
|
, numpy
|
||||||
|
, pytestCheckHook
|
||||||
|
, imread
|
||||||
|
, freeimage
|
||||||
|
, lib
|
||||||
|
, stdenv
|
||||||
|
}:
|
||||||
|
|
||||||
buildPythonPackage rec {
|
buildPythonPackage rec {
|
||||||
pname = "mahotas";
|
pname = "mahotas";
|
||||||
version = "1.4.11";
|
version = "1.4.12";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "luispedro";
|
owner = "luispedro";
|
||||||
repo = "mahotas";
|
repo = "mahotas";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "029gvy1fb855pvxvy8zwj44k4s7qpqi0161bg5wldfiprrysn1kw";
|
sha256 = "1n19yha1cqyx7hnlici1wkl7n68dh0vbpsyydfhign2c0w9jvg42";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
patches = [
|
||||||
|
(fetchpatch {
|
||||||
|
name = "fix-freeimage-tests.patch";
|
||||||
|
url = "https://github.com/luispedro/mahotas/commit/08cc4aa0cbd5dbd4c37580d52b822810c03b2c69.patch";
|
||||||
|
sha256 = "0389sz7fyl8h42phw8sn4pxl4wc3brcrj9d05yga21gzil9bfi23";
|
||||||
|
excludes = [ "ChangeLog" ];
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
propagatedBuildInputs = [ numpy imread pillow scipy freeimage ];
|
propagatedBuildInputs = [ numpy imread pillow scipy freeimage ];
|
||||||
checkInputs = [ pytestCheckHook ];
|
checkInputs = [ pytestCheckHook ];
|
||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
substituteInPlace mahotas/io/freeimage.py --replace "/opt/local/lib" "${freeimage}/lib"
|
substituteInPlace mahotas/io/freeimage.py \
|
||||||
|
--replace "ctypes.util.find_library('freeimage')" 'True' \
|
||||||
|
--replace 'ctypes.CDLL(libname)' 'np.ctypeslib.load_library("libfreeimage", "${freeimage}/lib")'
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# tests must be run in the build directory
|
# tests must be run in the build directory
|
||||||
@ -31,6 +53,11 @@ buildPythonPackage rec {
|
|||||||
"test_haralick3d"
|
"test_haralick3d"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pythonImportsCheck = [
|
||||||
|
"mahotas"
|
||||||
|
"mahotas.freeimage"
|
||||||
|
];
|
||||||
|
|
||||||
disabled = stdenv.isi686; # Failing tests
|
disabled = stdenv.isi686; # Failing tests
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
{ lib
|
||||||
|
, buildPythonPackage
|
||||||
|
, dnspython
|
||||||
|
, fetchFromGitHub
|
||||||
|
, ldap3
|
||||||
|
, pyasn1
|
||||||
|
, pycryptodome
|
||||||
|
, pythonOlder
|
||||||
|
, pytz
|
||||||
|
, six
|
||||||
|
}:
|
||||||
|
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "ms-active-directory";
|
||||||
|
version = "1.12.1";
|
||||||
|
format = "setuptools";
|
||||||
|
|
||||||
|
disabled = pythonOlder "3.8";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "zorn96";
|
||||||
|
repo = "ms_active_directory";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-mErQib8xTgo29iPAtiLnhxLXyFboAzyEW9A/QMseM6k=";
|
||||||
|
};
|
||||||
|
|
||||||
|
propagatedBuildInputs = [
|
||||||
|
dnspython
|
||||||
|
ldap3
|
||||||
|
pyasn1
|
||||||
|
pycryptodome
|
||||||
|
pytz
|
||||||
|
six
|
||||||
|
];
|
||||||
|
|
||||||
|
# Module has no tests
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
pythonImportsCheck = [
|
||||||
|
"ms_active_directory"
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Python module for integrating with Microsoft Active Directory domains";
|
||||||
|
homepage = "https://github.com/zorn96/ms_active_directory/";
|
||||||
|
license = with licenses; [ mit ];
|
||||||
|
maintainers = with maintainers; [ fab ];
|
||||||
|
};
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
{ lib, stdenv, autoreconfHook, pkg-config, SDL2, SDL2_mixer, SDL2_net, fetchFromGitHub, python2 }:
|
{ lib, stdenv, autoreconfHook, pkg-config, SDL2, SDL2_mixer, SDL2_net, fetchFromGitHub, python3 }:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
pname = "crispy-doom";
|
pname = "crispy-doom";
|
||||||
@ -13,10 +13,10 @@ stdenv.mkDerivation rec {
|
|||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
sed -e 's#/games#/bin#g' -i src{,/setup}/Makefile.am
|
sed -e 's#/games#/bin#g' -i src{,/setup}/Makefile.am
|
||||||
for script in $(grep -lr '^#!/usr/bin/env python$'); do patchShebangs $script; done
|
for script in $(grep -lr '^#!/usr/bin/env python3$'); do patchShebangs $script; done
|
||||||
'';
|
'';
|
||||||
|
|
||||||
nativeBuildInputs = [ autoreconfHook pkg-config python2 ];
|
nativeBuildInputs = [ autoreconfHook pkg-config python3 ];
|
||||||
buildInputs = [ SDL2 SDL2_mixer SDL2_net ];
|
buildInputs = [ SDL2 SDL2_mixer SDL2_net ];
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
version = "2.0.66";
|
version = "2.0.69";
|
||||||
pname = "munin";
|
pname = "munin";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "munin-monitoring";
|
owner = "munin-monitoring";
|
||||||
repo = "munin";
|
repo = "munin";
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "sha256-1aikMRY1YiSQNUnYqsw1Eew9D9JHbkX+BXNCof6YK50=";
|
sha256 = "sha256-p273O5JLFX1dA2caV3lVVL9YNTcGMSrC7DWieUfUmqI=";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
let lib = import ../../../lib; in lib.makeOverridable (
|
let lib = import ../../../lib; stdenv-overridable = lib.makeOverridable (
|
||||||
|
|
||||||
{ name ? "stdenv", preHook ? "", initialPath
|
argsStdenv@{ name ? "stdenv", preHook ? "", initialPath
|
||||||
|
|
||||||
, # If we don't have a C compiler, we might either have `cc = null` or `cc =
|
, # If we don't have a C compiler, we might either have `cc = null` or `cc =
|
||||||
# throw ...`, but if we do have a C compiler we should definiely have `cc !=
|
# throw ...`, but if we do have a C compiler we should definiely have `cc !=
|
||||||
@ -81,8 +81,10 @@ let
|
|||||||
|
|
||||||
defaultBuildInputs = extraBuildInputs;
|
defaultBuildInputs = extraBuildInputs;
|
||||||
|
|
||||||
|
stdenv = (stdenv-overridable argsStdenv);
|
||||||
|
|
||||||
# The stdenv that we are producing.
|
# The stdenv that we are producing.
|
||||||
stdenv =
|
in
|
||||||
derivation (
|
derivation (
|
||||||
lib.optionalAttrs (allowedRequisites != null) {
|
lib.optionalAttrs (allowedRequisites != null) {
|
||||||
allowedRequisites = allowedRequisites
|
allowedRequisites = allowedRequisites
|
||||||
@ -172,6 +174,5 @@ let
|
|||||||
# "lift" packages like curl from the final stdenv for Linux to
|
# "lift" packages like curl from the final stdenv for Linux to
|
||||||
# all-packages.nix for that platform (meaning that it has a line
|
# all-packages.nix for that platform (meaning that it has a line
|
||||||
# like curl = if stdenv ? curl then stdenv.curl else ...).
|
# like curl = if stdenv ? curl then stdenv.curl else ...).
|
||||||
// extraAttrs;
|
// extraAttrs
|
||||||
|
); in stdenv-overridable
|
||||||
in stdenv)
|
|
||||||
|
@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
rustPlatform.buildRustPackage rec {
|
rustPlatform.buildRustPackage rec {
|
||||||
pname = "code-minimap";
|
pname = "code-minimap";
|
||||||
version = "0.6.1";
|
version = "0.6.2";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "wfxr";
|
owner = "wfxr";
|
||||||
repo = pname;
|
repo = pname;
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "sha256-eCHmMtndcQJqKmjxhkcLvjMUXApkSnH+7qyG7PDfcwo=";
|
sha256 = "sha256-nUEmlKqCskPEQCOS2NC6jF4yVDarJeb3p+BKZq/2qvw=";
|
||||||
};
|
};
|
||||||
|
|
||||||
cargoSha256 = "sha256-wKCANWznOJMlQ8T2q39NNNRmgPYMpbkJhXpxojusNsE=";
|
cargoSha256 = "sha256-yjjoQYYWK9/9fOP5ICnhpuF/07SyCszB9GCDr0GJ0v0=";
|
||||||
|
|
||||||
buildInputs = lib.optional stdenv.isDarwin libiconv;
|
buildInputs = lib.optional stdenv.isDarwin libiconv;
|
||||||
|
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
{ lib, stdenv, rustPlatform, fetchFromGitHub, llvmPackages, sqlite, installShellFiles, Security, libiconv }:
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, rustPlatform
|
||||||
|
, fetchFromGitHub
|
||||||
|
, llvmPackages
|
||||||
|
, sqlite
|
||||||
|
, installShellFiles
|
||||||
|
, Security
|
||||||
|
, libiconv
|
||||||
|
, innernet
|
||||||
|
, testVersion
|
||||||
|
}:
|
||||||
|
|
||||||
rustPlatform.buildRustPackage rec {
|
rustPlatform.buildRustPackage rec {
|
||||||
pname = "innernet";
|
pname = "innernet";
|
||||||
version = "1.5.1";
|
version = "1.5.2";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "tonarino";
|
owner = "tonarino";
|
||||||
repo = "innernet";
|
repo = "innernet";
|
||||||
rev = "v${version}";
|
rev = "v${version}";
|
||||||
sha256 = "1ja7khvc4cy317ckglnlf11wfmin62ihic061phdp6rmfv95cza0";
|
sha256 = "141zjfl125m5lrimam1dbpk40dqfq4vnaz42sbiq1v1avyg684fq";
|
||||||
};
|
};
|
||||||
cargoSha256 = "18xpwav48xv7xm7r3w9qplmv2i18cg09pkahyvs5l4akdjgxyw10";
|
cargoSha256 = "0559d0ayysvqs4k46fhgd4r8wa89abgx6rvhlh0gnlnga8vacpw5";
|
||||||
|
|
||||||
nativeBuildInputs = with llvmPackages; [
|
nativeBuildInputs = with llvmPackages; [
|
||||||
llvm
|
llvm
|
||||||
@ -28,21 +39,10 @@ rustPlatform.buildRustPackage rec {
|
|||||||
installShellCompletion doc/innernet-server.completions.{bash,fish,zsh}
|
installShellCompletion doc/innernet-server.completions.{bash,fish,zsh}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
doInstallCheck = true;
|
passthru.tests = {
|
||||||
installCheckPhase = ''
|
serverVersion = testVersion { package = innernet; command = "innernet-server --version"; };
|
||||||
if [[ "$("$out/bin/${pname}"-server --version)" == "${pname}-server ${version}" ]]; then
|
version = testVersion { package = innernet; command = "innernet --version"; };
|
||||||
echo '${pname}-server smoke check passed'
|
};
|
||||||
else
|
|
||||||
echo '${pname}-server smoke check failed'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if [[ "$("$out/bin/${pname}" --version)" == "${pname} ${version}" ]]; then
|
|
||||||
echo '${pname} smoke check passed'
|
|
||||||
else
|
|
||||||
echo '${pname} smoke check failed'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
description = "A private network system that uses WireGuard under the hood";
|
description = "A private network system that uses WireGuard under the hood";
|
||||||
|
@ -38,6 +38,13 @@ let
|
|||||||
rev = "yaml-cpp-${version}";
|
rev = "yaml-cpp-${version}";
|
||||||
sha256 = "0ykkxzxcwwiv8l8r697gyqh1nl582krpvi7m7l6b40ijnk4pw30s";
|
sha256 = "0ykkxzxcwwiv8l8r697gyqh1nl582krpvi7m7l6b40ijnk4pw30s";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
patches = [
|
||||||
|
(fetchpatch {
|
||||||
|
url = "https://github.com/jbeder/yaml-cpp/commit/4f48727b365962e31451cd91027bd797bc7d2ee7.patch";
|
||||||
|
sha256 = "sha256-jarZAh7NgwL3xXzxijDiAQmC/EC2WYfNMkYHEIQBPhM=";
|
||||||
|
})
|
||||||
|
];
|
||||||
});
|
});
|
||||||
in
|
in
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
|
@ -5007,6 +5007,8 @@ in {
|
|||||||
|
|
||||||
mrkd = callPackage ../development/python-modules/mrkd { };
|
mrkd = callPackage ../development/python-modules/mrkd { };
|
||||||
|
|
||||||
|
ms-active-directory = callPackage ../development/python-modules/ms-active-directory { };
|
||||||
|
|
||||||
ms-cv = callPackage ../development/python-modules/ms-cv { };
|
ms-cv = callPackage ../development/python-modules/ms-cv { };
|
||||||
|
|
||||||
msal = callPackage ../development/python-modules/msal { };
|
msal = callPackage ../development/python-modules/msal { };
|
||||||
|
Loading…
Reference in New Issue
Block a user