mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-11-04 11:50:04 +00:00
Compare commits
45 Commits
staging
...
staging-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
575fbaf778 | ||
|
|
1b0661cb8e | ||
|
|
a43b7eab39 | ||
|
|
f43d13a970 | ||
|
|
43be3d4cfb | ||
|
|
abae798b6c | ||
|
|
cf9a0df709 | ||
|
|
4d7096f6c6 | ||
|
|
fadbd12b88 | ||
|
|
12214b623a | ||
|
|
3328cd18b2 | ||
|
|
0fa2336746 | ||
|
|
3b574a194d | ||
|
|
573530121c | ||
|
|
7de48641a5 | ||
|
|
0032afe410 | ||
|
|
ea33e2134e | ||
|
|
0835e2960f | ||
|
|
7732580291 | ||
|
|
70cffbcf42 | ||
|
|
2c4e5922cf | ||
|
|
964de0a0cf | ||
|
|
f4b42644cb | ||
|
|
2d5423b857 | ||
|
|
ad8d8b2dd6 | ||
|
|
fdc0faecfb | ||
|
|
addb72b9dc | ||
|
|
48b13a3d84 | ||
|
|
957f263e78 | ||
|
|
e9035336b3 | ||
|
|
74801e0478 | ||
|
|
045ca2d4ec | ||
|
|
f8e3bf8a2e | ||
|
|
1de0066f4b | ||
|
|
7d47ee0895 | ||
|
|
55a9de48ba | ||
|
|
c3c3cb0a91 | ||
|
|
4f64ec7425 | ||
|
|
0d3c836963 | ||
|
|
f65c491441 | ||
|
|
fa391feabe | ||
|
|
e5d47c704e | ||
|
|
45e574d8f1 | ||
|
|
43e45601c1 | ||
|
|
5563d930fa |
@@ -31,7 +31,7 @@ pkgs.mkShell {
|
||||
|
||||
## Packaging guide {#sec-language-ocaml-packaging}
|
||||
|
||||
OCaml libraries are installed in `$out/lib/ocaml/${ocaml.version}/site-lib/`, or in the same directory of the `dev` output (see `buildDunePackage` below). Such directories are automatically added to the `$OCAMLPATH` environment variable when building another package that depends on them or when opening a `nix-shell`.
|
||||
OCaml libraries should be installed in `$(out)/lib/ocaml/${ocaml.version}/site-lib/`. Such directories are automatically added to the `$OCAMLPATH` environment variable when building another package that depends on them or when opening a `nix-shell`.
|
||||
|
||||
Given that most of the OCaml ecosystem is now built with dune, nixpkgs includes a convenience build support function called `buildDunePackage` that will build an OCaml package using dune, OCaml and findlib and any additional dependencies provided as `buildInputs` or `propagatedBuildInputs`.
|
||||
|
||||
@@ -139,29 +139,6 @@ buildDunePackage (finalAttrs: {
|
||||
})
|
||||
```
|
||||
|
||||
Unless the package sets `outputs`, `buildDunePackage` builds separate outputs,
|
||||
and points `$OCAMLFIND_DESTDIR` to `dev`:
|
||||
|
||||
- `out` contains what the package produces for use at runtime, such as
|
||||
executables.
|
||||
- `dev` contains the OCaml libraries and the propagated dependencies needed to
|
||||
build other packages against them. It is selected automatically when the
|
||||
package is used as a build input.
|
||||
- `man` contains the man pages. Like `out`, it is installed by default.
|
||||
- `doc` contains the documentation, such as the README and license files.
|
||||
|
||||
This keeps build-time only OCaml dependencies out of the runtime closure of
|
||||
executables. Code that refers to the library directory of such a package must
|
||||
use its `dev` output, for example `${lib.getDev menhirLib}/lib/ocaml` or
|
||||
`lib.makeSearchPathOutput "dev" "lib/ocaml/${ocaml.version}/site-lib"`.
|
||||
Likewise, installing the library into a profile or environment requires its
|
||||
`dev` output, e.g. `ocamlPackages.menhirLib.dev`.
|
||||
|
||||
Toplevels and programs that load plugins need their own OCaml library at
|
||||
runtime, and the two outputs would refer to each other. Set
|
||||
`outputs = [ "out" ];` for such packages, and for packages whose custom
|
||||
`installPhase` installs everything into `$out`.
|
||||
|
||||
The build will automatically fail if two distinct versions of the same library
|
||||
are added to `buildInputs` (which usually happens transitively because of
|
||||
`propagatedBuildInputs`). Set `dontDetectOcamlConflicts` to true to disable this
|
||||
|
||||
@@ -246,46 +246,6 @@ To disable the SwiftPM install phase, include the following in your derivation:
|
||||
{ dontUseSwiftpmInstall = true; }
|
||||
```
|
||||
|
||||
## Swift Macros {#ssec-swift-macros}
|
||||
|
||||
Nixpkgs includes the stdlib macros (ObservationMacros and SwiftMacros) and FoundationMacros in the toolchain.
|
||||
Packages that need macros for Apple frameworks on Darwin have two options:
|
||||
- `open-apple-macros` provides open-source implementations of FoundationModelsMacros and SwiftUIMacros; or
|
||||
- `darwin.xcode-macros` provides macro libraries from Xcode not otherwise included in the toolchain, but they are unfree.
|
||||
|
||||
Add the appropriate package to `depsBuildBuild` (because they are compiler plugins that run on the build platform).
|
||||
If you need to manually specify the path for a package because it or its build system invokes `swiftc` directly:
|
||||
|
||||
### `open-apple-macros` {#ssec-swift-macros-open-apple-macros}
|
||||
```nix
|
||||
{
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
swiftc \
|
||||
-external-plugin-path ${open-apple-macros}/lib/swift/host/plugins#${open-apple-macros}/libexec/swift/plugins/OpenAppleMacrosServer \
|
||||
-disable-sandbox \
|
||||
*.swift \
|
||||
-o the_binary
|
||||
runHook postBuild
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
### `darwin.xcode-macros` {#ssec-swift-macros-xcode-macros}
|
||||
```nix
|
||||
{
|
||||
# For `darwin.xcode-macros`
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
swiftc \
|
||||
-plugin-path ${darwin.xcode-macros}/lib/swift/host/plugins \
|
||||
*.swift \
|
||||
-o the_binary
|
||||
runHook postBuild
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
## Hooks {#ssec-swift-hooks}
|
||||
|
||||
Swift provides the following hooks to automate builds and unpack dependencies:
|
||||
|
||||
@@ -4660,15 +4660,6 @@
|
||||
"ssec-swiftpm-install-phase": [
|
||||
"index.html#ssec-swiftpm-install-phase"
|
||||
],
|
||||
"ssec-swift-macros": [
|
||||
"index.html#ssec-swift-macros"
|
||||
],
|
||||
"ssec-swift-macros-open-apple-macros": [
|
||||
"index.html#ssec-swift-macros-open-apple-macros"
|
||||
],
|
||||
"ssec-swift-macros-xcode-macros": [
|
||||
"index.html#ssec-swift-macros-xcode-macros"
|
||||
],
|
||||
"ssec-swift-hooks": [
|
||||
"index.html#ssec-swift-hooks"
|
||||
],
|
||||
|
||||
@@ -59,11 +59,6 @@
|
||||
|
||||
- `paperless-manage` now uses `runuser` instead of automatically calling `sudo` to set user/group before running. Invoke the script with `sudo paperless-manage` or an equivalent elevation tool of your choice
|
||||
|
||||
- OpenSSL now prefers the system CA bundle at `/etc/ssl/certs/ca-certificates.crt` on both Linux and Darwin, falling back to `/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt` only when the system bundle is absent.
|
||||
Previously, Darwin used the default Nix profile bundle directly.
|
||||
An existing but unreadable or invalid system bundle does not trigger the fallback.
|
||||
Explicit `NIX_SSL_CERT_FILE` and `SSL_CERT_FILE` overrides still take precedence.
|
||||
|
||||
- `hyperfine` has been updated from 1.21.0 to 2.0.0, which contains several breaking changes:
|
||||
- Benchmarked commands are now executed directly instead of through an intermediate shell. Pass `-S`/`--shell=default` to restore the previous behavior.
|
||||
- The `--export-json` format has changed (schema version 2); tools consuming the exported JSON must be updated.
|
||||
@@ -106,13 +101,6 @@
|
||||
By the time of this release, Homebrew will offer only limited [Tier 3](https://docs.brew.sh/Support-Tiers#tier-3) support for the platform, but MacPorts will likely continue to support it for a long time.
|
||||
We also recommend users consider installing NixOS, which should continue to run on essentially all Intel Macs, especially after Apple stops security support for macOS 26 in 2028.
|
||||
|
||||
- `ocamlPackages.buildDunePackage` now builds packages with `out`, `dev`, `man` and `doc` outputs by default, unless they set `outputs`.
|
||||
The OCaml libraries are installed into `dev`, man pages into `man`, documentation into `doc`, and `out` only contains what is needed at runtime, such as executables. This removes build-time only OCaml dependencies from the closure of tools like `patdiff`.
|
||||
Code that refers to `${ocamlPackages.foo}/lib/ocaml` must use `${lib.getDev ocamlPackages.foo}/lib/ocaml` instead.
|
||||
Installing such a library into a profile or environment (for example with `home.packages`, `environment.systemPackages` or `nix profile add`) no longer provides its `lib/ocaml` directory; install `ocamlPackages.foo.dev` instead.
|
||||
|
||||
- The `bin` and `lib` outputs of `ocamlPackages.odoc`, `ocamlPackages.crunch`, `ocamlPackages.mdx` and `ocamlPackages.tw` were removed. Use the package itself for the executables, and its `dev` output for the OCaml library.
|
||||
|
||||
- `bundlerApp` now sets `__structuredAttrs = true` for its result package.
|
||||
Out-of-tree packages passing `postBuild` to `bundlerApp` should examine if their `postBuild` commands are compatible with structured attributes.
|
||||
|
||||
@@ -216,10 +204,6 @@
|
||||
|
||||
- `zerofs` has been updated from `1.x` to `2.x` which is a breaking change. Volumes created by earlier releases are refused at open with a clear error. There is no migration tool; older volumes remain readable and writable by the release that created them.
|
||||
|
||||
- `python3Packages.buildPythonPackage` and `python3Packages.buildPythonApplication` now warn in the presence of `unittestFlagsArray`.
|
||||
Please use [`unittestFlags`](#using-unittestcheckhook) instead.
|
||||
If modifying the Nix expression is not feasible, users can remediate the warning by overriding `unittestFlagsArray` with `null` or `[ ]`.
|
||||
|
||||
- `keycloak.plugins.keycloak-metrics-spi` has been removed. Keycloak exposes Prometheus metrics natively on its management interface; enable them with the `metrics-enabled` setting (and `event-metrics-user-enabled` for login and event counters). See [Gaining insights with metrics](https://www.keycloak.org/observability/configuration-metrics).
|
||||
|
||||
- `alps` has been rewritten upstream, see [upstream repository](https://github.com/migadu/alps) for documentation.
|
||||
@@ -281,8 +265,6 @@
|
||||
|
||||
- `tcl.mkTclDerivation` now enables `strictDeps` and `__structuredAttrs`.
|
||||
|
||||
- `rustPlatform.cargoSetupHook` now forces several common C libraries to be linked to the Nixpkgs library rather than the vendored library. These include: aws-lc, openssl, libz, libsqlite3, zstd, libgit2, sodium, rustonig, libssh2, nginx, duckdb, and jemalloc. Set `dontCargoUseSystemLibs = true;` to opt out.
|
||||
|
||||
- `rssguard` 5.x uses a new database layer. Regenerate your database after upgrading, following the [RSS Guard migration notes](https://rssguard.readthedocs.io/en/stable/contrib/migrate.html).
|
||||
|
||||
- `pdns` has been updated from `5.0.x` to `5.1.x`. Please be sure to review the [Upgrade Notes](https://doc.powerdns.com/authoritative/upgrading.html#to-5-1-0) before upgrading. Namely LUA record updates are no longer allowed by default, and the embedded webserver no longer includes a `access-control-allow-origin: *` header by default.
|
||||
@@ -497,7 +479,7 @@
|
||||
SingularityCE 4.6.0 was the last release.
|
||||
Use Apptainer (`apptainer`) instead.
|
||||
|
||||
- Swift has been upgraded to Swift 6.4.0 from Swift 5.10.1.
|
||||
- Swift has been upgraded to Swift 6.3.3 from Swift 5.10.1.
|
||||
The Swift packaging has been rewritten.
|
||||
|
||||
## Nixpkgs Library {#sec-nixpkgs-release-26.11-lib}
|
||||
|
||||
@@ -1198,9 +1198,6 @@ They cannot be overridden without rebuilding the package.
|
||||
|
||||
If dependencies should be resolved at runtime, use `--suffix` to append fallback values to `PATH`.
|
||||
|
||||
`makeBinaryWrapper` refuses a `--prefix` or `--suffix` value that would introduce an empty segment (an empty value, or a leading, trailing or doubled separator), because many `PATH`-like variables interpret an empty segment as the current directory.
|
||||
For variables where an empty segment is useful and safe, such as `LUA_PATH` where `;;` stands for the default search path, use `--prefix-unchecked` or `--suffix-unchecked` instead.
|
||||
|
||||
There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh` for the `makeWrapper` implementation and in `nixpkgs/pkgs/by-name/ma/makeBinaryWrapper/make-binary-wrapper.sh` for the `makeBinaryWrapper` implementation.
|
||||
|
||||
`wrapProgram` is a convenience function you probably want to use most of the time, implemented by both `makeWrapper` and `makeBinaryWrapper`.
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
+nixpkgs.url = "https://channels.nixos.org/nixos-26.05/nixexprs.tar.zst";
|
||||
```
|
||||
|
||||
- GNOME has been updated to version 51. Refer to the [GNOME release notes](https://release.gnome.org/51/) for more details.
|
||||
|
||||
- `sing-box` now supports NaïveProxy outbounds.
|
||||
|
||||
## New Modules {#sec-release-26.11-new-modules}
|
||||
|
||||
@@ -41,8 +41,7 @@ mkdir -p $out/tarball
|
||||
|
||||
rm env-vars
|
||||
|
||||
# Store optimization can change hardlink topology without changing input NARs.
|
||||
time tar --hard-dereference --sort=name --mtime='@1' --owner=0 --group=0 --numeric-owner -c * $extraArgs | $compressCommand > $out/tarball/$fileName.tar${extension}
|
||||
time tar --sort=name --mtime='@1' --owner=0 --group=0 --numeric-owner -c * $extraArgs | $compressCommand > $out/tarball/$fileName.tar${extension}
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
echo $system > $out/nix-support/system
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
junit-xml,
|
||||
ptpython,
|
||||
pydantic,
|
||||
pytest,
|
||||
python,
|
||||
ovmfvartool,
|
||||
remote-pdb,
|
||||
@@ -80,11 +81,14 @@ buildPythonApplication {
|
||||
doCheck = true;
|
||||
|
||||
nativeCheckInputs = [
|
||||
pytest
|
||||
ruff
|
||||
ty
|
||||
];
|
||||
|
||||
checkPhase = ''
|
||||
echo -e "\x1b[32m## run doctests\x1b[0m"
|
||||
pytest --doctest-modules -p no:cacheprovider test_driver
|
||||
echo -e "\x1b[32m## run ty\x1b[0m"
|
||||
# Installation adds the driver to PYTHONPATH; keep ty imports in the source tree.
|
||||
PYTHONPATH=".:$PYTHONPATH" ty check --error-on-warning test_driver extract-docstrings.py
|
||||
|
||||
@@ -87,6 +87,30 @@ def get_tmp_dir() -> Path:
|
||||
|
||||
|
||||
def pythonize_name(name: str) -> str:
|
||||
"""Turn a machine name into a valid Python identifier.
|
||||
|
||||
Names that already are valid identifiers stay the same:
|
||||
|
||||
>>> pythonize_name("node_1")
|
||||
'node_1'
|
||||
|
||||
Every character that is not allowed in an identifier becomes "_":
|
||||
|
||||
>>> pythonize_name("my-vm")
|
||||
'my_vm'
|
||||
>>> pythonize_name("web.example.org")
|
||||
'web_example_org'
|
||||
>>> pythonize_name("münchen")
|
||||
'm_nchen'
|
||||
|
||||
A leading digit is replaced rather than prefixed, so it gets lost, while
|
||||
digits later in the name are kept:
|
||||
|
||||
>>> pythonize_name("1node")
|
||||
'_node'
|
||||
>>> pythonize_name("12node")
|
||||
'_2node'
|
||||
"""
|
||||
return re.sub(r"^[^A-Za-z_]|[^A-Za-z0-9_]", "_", name)
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,22 @@ def as_timedelta(duration: Duration) -> dt.timedelta:
|
||||
Bare numbers are interpreted as seconds. This keeps existing test scripts
|
||||
that pass plain integers working while `datetime.timedelta` becomes the preferred
|
||||
way to express durations.
|
||||
|
||||
>>> as_timedelta(dt.timedelta(minutes=1))
|
||||
datetime.timedelta(seconds=60)
|
||||
>>> as_timedelta(90)
|
||||
datetime.timedelta(seconds=90)
|
||||
>>> as_timedelta(1.5)
|
||||
datetime.timedelta(seconds=1, microseconds=500000)
|
||||
|
||||
A `bool` is an `int` in Python, but it is never a valid duration:
|
||||
|
||||
>>> as_timedelta(True)
|
||||
Traceback (most recent call last):
|
||||
TypeError: expected a duration, got bool: True
|
||||
>>> as_timedelta("1")
|
||||
Traceback (most recent call last):
|
||||
TypeError: expected a timedelta, int, or float duration, got str
|
||||
"""
|
||||
if isinstance(duration, dt.timedelta):
|
||||
return duration
|
||||
@@ -27,7 +43,13 @@ def as_timedelta(duration: Duration) -> dt.timedelta:
|
||||
|
||||
|
||||
def as_seconds(duration: Duration) -> float:
|
||||
"""Coerce a `Duration` into a floating-point number of seconds."""
|
||||
"""Coerce a `Duration` into a floating-point number of seconds.
|
||||
|
||||
>>> as_seconds(90)
|
||||
90.0
|
||||
>>> as_seconds(dt.timedelta(minutes=1, milliseconds=500))
|
||||
60.5
|
||||
"""
|
||||
return as_timedelta(duration).total_seconds()
|
||||
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@ class TerminalLogger(AbstractLogger):
|
||||
elapsed = time.monotonic() - self._start_time
|
||||
if "machine" in attributes:
|
||||
message = f"{attributes['machine']}: {message}"
|
||||
return f"[{elapsed:.2f}s] {message}"
|
||||
return Style.DIM + f"[{elapsed:.2f}s]" + Style.RESET_ALL + f" {message}" # ty: ignore[unsupported-operator]
|
||||
|
||||
@staticmethod
|
||||
def _eprint(*args: object, **kwargs: Any) -> None:
|
||||
@@ -322,10 +322,27 @@ class XMLLogger(AbstractLogger):
|
||||
self.xml.endDocument()
|
||||
self.logfile_handle.close()
|
||||
|
||||
def sanitise(self, message: str) -> str:
|
||||
@staticmethod
|
||||
def sanitise(message: str) -> str:
|
||||
r"""Remove the characters of Unicode's "Other" categories, such as
|
||||
control characters, from serial output before it is written to XML.
|
||||
|
||||
>>> XMLLogger.sanitise("booting\x00...\x07")
|
||||
'booting...'
|
||||
>>> XMLLogger.sanitise("Grüße")
|
||||
'Grüße'
|
||||
"""
|
||||
return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C")
|
||||
|
||||
def maybe_prefix(self, message: str, attributes: dict[str, str]) -> str:
|
||||
@staticmethod
|
||||
def maybe_prefix(message: str, attributes: dict[str, str]) -> str:
|
||||
"""Prefix the message with the name of the machine, if there is one.
|
||||
|
||||
>>> XMLLogger.maybe_prefix("booting", {"machine": "server"})
|
||||
'server: booting'
|
||||
>>> XMLLogger.maybe_prefix("booting", {})
|
||||
'booting'
|
||||
"""
|
||||
if "machine" in attributes:
|
||||
return f"{attributes['machine']}: {message}"
|
||||
return message
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import platform
|
||||
import queue
|
||||
import re
|
||||
import select
|
||||
import selectors
|
||||
import shlex
|
||||
import shutil
|
||||
import socket
|
||||
@@ -139,7 +139,22 @@ XDOTOOL_MODIFIER_ALIASES = {
|
||||
def xdotool_key_sequence(key: str) -> str:
|
||||
"""Translate a QEMU-style key chord to xdotool syntax.
|
||||
|
||||
For example, "ctrl-alt-ret" becomes "ctrl+alt+Return".
|
||||
>>> xdotool_key_sequence("ctrl-alt-ret")
|
||||
'ctrl+alt+Return'
|
||||
>>> xdotool_key_sequence("meta_l-x")
|
||||
'super+x'
|
||||
>>> xdotool_key_sequence("alt-f4")
|
||||
'alt+F4'
|
||||
|
||||
A modifier on its own is a regular key:
|
||||
|
||||
>>> xdotool_key_sequence("shift")
|
||||
'Shift_L'
|
||||
|
||||
A "-" that follows a modifier is the key itself, not a separator:
|
||||
|
||||
>>> xdotool_key_sequence("ctrl--")
|
||||
'ctrl+-'
|
||||
"""
|
||||
parts = key.split("-")
|
||||
modifiers = []
|
||||
@@ -154,9 +169,42 @@ def xdotool_key_sequence(key: str) -> str:
|
||||
|
||||
|
||||
def make_command(args: list) -> str:
|
||||
"""Join arguments into a shell command, quoting each one as a single word.
|
||||
|
||||
>>> make_command(["echo", "a b", 1])
|
||||
"echo 'a b' 1"
|
||||
>>> make_command(["ls", "*"])
|
||||
"ls '*'"
|
||||
"""
|
||||
return " ".join(map(shlex.quote, (map(str, args))))
|
||||
|
||||
|
||||
def parse_systemctl_property(line: str) -> tuple[str, str] | None:
|
||||
"""Split a line of `systemctl show` output into its property and value.
|
||||
|
||||
>>> parse_systemctl_property("Id=foo.service")
|
||||
('Id', 'foo.service')
|
||||
|
||||
Only the first "=" separates the two, and values can be empty:
|
||||
|
||||
>>> parse_systemctl_property("Environment=A=1 B=2")
|
||||
('Environment', 'A=1 B=2')
|
||||
>>> parse_systemctl_property("Description=")
|
||||
('Description', '')
|
||||
|
||||
Lines that aren't properties yield `None`:
|
||||
|
||||
>>> parse_systemctl_property("") is None
|
||||
True
|
||||
>>> parse_systemctl_property("no property") is None
|
||||
True
|
||||
"""
|
||||
match = re.match(r"^([^=]+)=(.*)$", line)
|
||||
if match is None:
|
||||
return None
|
||||
return match[1], match[2]
|
||||
|
||||
|
||||
def retry(
|
||||
fn: Callable,
|
||||
timeout_seconds: int | dt.timedelta | None = None,
|
||||
@@ -217,6 +265,13 @@ class QemuStartCommand:
|
||||
These Nix commands have the particular characteristic that the
|
||||
machine name can be extracted out of them via a regex match.
|
||||
(Admittedly a _very_ implicit contract, TODO fix this eventually.)
|
||||
|
||||
>>> QemuStartCommand("/nix/store/hash-nixos-vm/bin/run-foo-vm").machine_name
|
||||
'foo'
|
||||
>>> QemuStartCommand("run-foo-bar-vm").machine_name
|
||||
'foo-bar'
|
||||
>>> QemuStartCommand("/some/script").machine_name
|
||||
'machine'
|
||||
"""
|
||||
match = re.search("run-(.+)-vm$", self._cmd)
|
||||
name = "machine"
|
||||
@@ -397,6 +452,29 @@ class BaseMachine(ABC):
|
||||
"""Shutdown the machine gracefully, waiting for it to exit."""
|
||||
...
|
||||
|
||||
@staticmethod
|
||||
def _systemctl_command(q: str, user: str | None = None) -> str:
|
||||
r"""Build a `systemctl` command, or a `systemctl --user` one for `user`.
|
||||
|
||||
>>> print(BaseMachine._systemctl_command("list-jobs --no-pager"))
|
||||
systemctl list-jobs --no-pager
|
||||
>>> print(BaseMachine._systemctl_command("list-jobs --no-pager", "alice"))
|
||||
su -l alice --shell /bin/sh -c $'XDG_RUNTIME_DIR=/run/user/`id -u` systemctl --user list-jobs --no-pager'
|
||||
|
||||
Single quotes survive the surrounding `$'...'`:
|
||||
|
||||
>>> print(BaseMachine._systemctl_command("show 'foo bar'", "alice"))
|
||||
su -l alice --shell /bin/sh -c $'XDG_RUNTIME_DIR=/run/user/`id -u` systemctl --user show \'foo bar\''
|
||||
"""
|
||||
if user is None:
|
||||
return f"systemctl {q}"
|
||||
escaped = q.replace("'", "\\'")
|
||||
return (
|
||||
f"su -l {user} --shell /bin/sh -c "
|
||||
"$'XDG_RUNTIME_DIR=/run/user/`id -u` "
|
||||
f"systemctl --user {escaped}'"
|
||||
)
|
||||
|
||||
def systemctl(self, q: str, user: str | None = None) -> tuple[int, str]:
|
||||
"""
|
||||
Runs `systemctl` commands with optional support for
|
||||
@@ -411,14 +489,7 @@ class BaseMachine(ABC):
|
||||
machine.systemctl("list-jobs --no-pager", "any-user")
|
||||
```
|
||||
"""
|
||||
if user is not None:
|
||||
q = q.replace("'", "\\'")
|
||||
return self.execute(
|
||||
f"su -l {user} --shell /bin/sh -c "
|
||||
"$'XDG_RUNTIME_DIR=/run/user/`id -u` "
|
||||
f"systemctl --user {q}'"
|
||||
)
|
||||
return self.execute(f"systemctl {q}")
|
||||
return self.execute(self._systemctl_command(q, user))
|
||||
|
||||
def wait_for_unit(
|
||||
self,
|
||||
@@ -467,17 +538,10 @@ class BaseMachine(ABC):
|
||||
+ f" failed with exit code {status}"
|
||||
)
|
||||
|
||||
line_pattern = re.compile(r"^([^=]+)=(.*)$")
|
||||
|
||||
def tuple_from_line(line: str) -> tuple[str, str]:
|
||||
match = line_pattern.match(line)
|
||||
assert match is not None
|
||||
return match[1], match[2]
|
||||
|
||||
return dict(
|
||||
tuple_from_line(line)
|
||||
parsed
|
||||
for line in lines.split("\n")
|
||||
if line_pattern.match(line)
|
||||
if (parsed := parse_systemctl_property(line)) is not None
|
||||
)
|
||||
|
||||
def get_unit_property(
|
||||
@@ -505,12 +569,12 @@ class BaseMachine(ABC):
|
||||
f"produced invalid output: {lines}"
|
||||
)
|
||||
|
||||
line_pattern = re.compile(r"^([^=]+)=(.*)$")
|
||||
match = line_pattern.match(lines)
|
||||
assert match is not None, invalid_output_message
|
||||
parsed = parse_systemctl_property(lines)
|
||||
assert parsed is not None, invalid_output_message
|
||||
|
||||
assert match[1] == property, invalid_output_message
|
||||
return match[2]
|
||||
name, value = parsed
|
||||
assert name == property, invalid_output_message
|
||||
return value
|
||||
|
||||
def require_unit_state(self, unit: str, require_state: str = "active") -> None:
|
||||
"""
|
||||
@@ -742,7 +806,7 @@ class BaseMachine(ABC):
|
||||
)
|
||||
if ret.returncode != 0:
|
||||
raise MachineError(
|
||||
f"Cannot convert screenshot (pnmtopng returned code {ret.returncode})"
|
||||
f"{self.name}: Cannot convert screenshot (pnmtopng returned code {ret.returncode})"
|
||||
)
|
||||
|
||||
def get_screen_text_variants(self) -> list[str]:
|
||||
@@ -1178,15 +1242,18 @@ class QemuMachine(BaseMachine):
|
||||
"""Debugging: Dump the contents of the TTY<n>"""
|
||||
self.execute(f"fold -w 80 /dev/vcs{tty} | systemd-cat")
|
||||
|
||||
def _execute(
|
||||
self,
|
||||
command: str,
|
||||
check_return: bool = True,
|
||||
check_output: bool = True,
|
||||
timeout: dt.timedelta | None = dt.timedelta(minutes=15),
|
||||
) -> tuple[int, str]:
|
||||
self.connect()
|
||||
@staticmethod
|
||||
def _shell_command(command: str, timeout: dt.timedelta | None) -> str:
|
||||
"""Build the line that runs `command` over the shell of the machine.
|
||||
|
||||
The command runs with strict shell options, and its output gets
|
||||
base64-encoded so that it can be read back as a single line:
|
||||
|
||||
>>> print(QemuMachine._shell_command("echo 'hi'", dt.timedelta(seconds=10)))
|
||||
timeout 10.0 bash -c 'set -euo pipefail; echo '"'"'hi'"'"'' | (base64 -w 0; echo)
|
||||
>>> print(QemuMachine._shell_command("true", None).strip())
|
||||
bash -c 'set -euo pipefail; true' | (base64 -w 0; echo)
|
||||
"""
|
||||
# Always run command with shell opts
|
||||
command = f"set -euo pipefail; {command}"
|
||||
|
||||
@@ -1196,12 +1263,19 @@ class QemuMachine(BaseMachine):
|
||||
|
||||
# While sh is bash on NixOS, this is not the case for every distro.
|
||||
# We explicitly call bash here to allow for the driver to boot other distros as well.
|
||||
out_command = (
|
||||
f"{timeout_str} bash -c {shlex.quote(command)} | (base64 -w 0; echo)\n"
|
||||
)
|
||||
return f"{timeout_str} bash -c {shlex.quote(command)} | (base64 -w 0; echo)"
|
||||
|
||||
def _execute(
|
||||
self,
|
||||
command: str,
|
||||
check_return: bool = True,
|
||||
check_output: bool = True,
|
||||
timeout: dt.timedelta | None = dt.timedelta(minutes=15),
|
||||
) -> tuple[int, str]:
|
||||
self.connect()
|
||||
|
||||
assert self.shell
|
||||
self.shell.send(out_command.encode())
|
||||
self.shell.send(f"{self._shell_command(command, timeout)}\n".encode())
|
||||
|
||||
if not check_output:
|
||||
return (-2, "")
|
||||
@@ -1335,16 +1409,6 @@ class QemuMachine(BaseMachine):
|
||||
Wait for a connection to the guest root shell
|
||||
"""
|
||||
|
||||
def shell_ready(timeout: dt.timedelta) -> bool:
|
||||
"""We sent some data from the backdoor service running on the guest
|
||||
to indicate that the backdoor shell is ready.
|
||||
As soon as we read some data from the socket here, we assume that
|
||||
our root shell is operational.
|
||||
"""
|
||||
assert self.shell
|
||||
(ready, _, _) = select.select([self.shell], [], [], timeout.total_seconds())
|
||||
return bool(ready)
|
||||
|
||||
if self.connected:
|
||||
return
|
||||
|
||||
@@ -1354,9 +1418,15 @@ class QemuMachine(BaseMachine):
|
||||
assert self.shell
|
||||
|
||||
tic = time.monotonic()
|
||||
sel = selectors.DefaultSelector()
|
||||
sel.register(self.shell, selectors.EVENT_READ)
|
||||
|
||||
for _ in range(10):
|
||||
if shell_ready(timeout=dt.timedelta(seconds=30)):
|
||||
# We sent some data from the backdoor service running on the guest
|
||||
# to indicate that the backdoor shell is ready.
|
||||
# As soon as we read some data from the socket here, we assume that
|
||||
# our root shell is operational.
|
||||
if sel.select(timeout=30):
|
||||
break
|
||||
self.log("Guest root shell did not produce any data yet...")
|
||||
self.log(
|
||||
@@ -1477,6 +1547,7 @@ class QemuMachine(BaseMachine):
|
||||
s = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM)
|
||||
s.bind(str(path))
|
||||
s.listen(1)
|
||||
s.setblocking(False)
|
||||
return s
|
||||
|
||||
monitor_socket = create_socket(clear(self.monitor_path))
|
||||
@@ -1498,8 +1569,10 @@ class QemuMachine(BaseMachine):
|
||||
would block forever if QEMU exits before connecting.
|
||||
"""
|
||||
assert self.process
|
||||
while True:
|
||||
readable, _, _ = select.select([sock], [], [], 1.0)
|
||||
sel = selectors.DefaultSelector()
|
||||
sel.register(sock, selectors.EVENT_READ)
|
||||
for _ in range(60):
|
||||
readable = sel.select(1)
|
||||
if readable:
|
||||
conn, _ = sock.accept()
|
||||
return conn
|
||||
@@ -1509,8 +1582,11 @@ class QemuMachine(BaseMachine):
|
||||
if self.process.stdout:
|
||||
output = self.process.stdout.read().decode(errors="ignore")
|
||||
raise MachineError(
|
||||
f"QEMU process exited with code {rc} before connecting to {name} socket.\n{output}"
|
||||
f"{self.name}: QEMU process exited with code {rc} before connecting to {name} socket.\n{output}"
|
||||
)
|
||||
raise MachineError(
|
||||
f"{self.name}: Timed out waiting for QEMU connection on {name} socket"
|
||||
)
|
||||
|
||||
self.monitor = accept_or_fail(monitor_socket, "monitor")
|
||||
self.shell = accept_or_fail(shell_socket, "shell")
|
||||
@@ -1690,7 +1766,19 @@ class NspawnMachine(BaseMachine):
|
||||
vnc: NspawnVnc | None
|
||||
|
||||
@staticmethod
|
||||
def machine_name_from_start_command(start_command: str) -> str:
|
||||
def _machine_name_from_start_command(start_command: str) -> str:
|
||||
"""Extract the machine name from a start script of a container.
|
||||
|
||||
>>> NspawnMachine._machine_name_from_start_command(
|
||||
... "/nix/store/hash-container/bin/run-foo-nspawn"
|
||||
... )
|
||||
'foo'
|
||||
>>> NspawnMachine._machine_name_from_start_command("run-foo-bar-nspawn")
|
||||
'foo-bar'
|
||||
>>> NspawnMachine._machine_name_from_start_command("/some/script")
|
||||
Traceback (most recent call last):
|
||||
AssertionError: Could not extract node name from /some/script
|
||||
"""
|
||||
match = re.search("run-(.+)-nspawn", os.path.basename(start_command))
|
||||
assert match is not None, f"Could not extract node name from {start_command}"
|
||||
return match.group(1)
|
||||
@@ -1710,7 +1798,7 @@ class NspawnMachine(BaseMachine):
|
||||
# See analogous TODO in `QemuStartCommand::machine_name`.
|
||||
super().__init__(
|
||||
out_dir=out_dir,
|
||||
name=name or self.machine_name_from_start_command(start_command),
|
||||
name=name or self._machine_name_from_start_command(start_command),
|
||||
logger=logger,
|
||||
callbacks=callbacks,
|
||||
tmp_dir=tmp_dir,
|
||||
@@ -1743,6 +1831,33 @@ class NspawnMachine(BaseMachine):
|
||||
with self.nested("waiting for the X11 server"):
|
||||
retry(check_x, as_timedelta(timeout))
|
||||
|
||||
@staticmethod
|
||||
def _xdotool_command(key: str) -> str:
|
||||
"""Build the xdotool command that presses a QEMU-style key.
|
||||
|
||||
Literal characters get typed to avoid key syntax, e.g. "+" as a chord
|
||||
separator:
|
||||
|
||||
>>> print(NspawnMachine._xdotool_command("a"))
|
||||
xdotool type --clearmodifiers --delay 0 -- a
|
||||
>>> print(NspawnMachine._xdotool_command("+"))
|
||||
xdotool type --clearmodifiers --delay 0 -- +
|
||||
|
||||
Everything else is a key chord:
|
||||
|
||||
>>> print(NspawnMachine._xdotool_command("ctrl-alt-ret"))
|
||||
xdotool key --clearmodifiers ctrl+alt+Return
|
||||
>>> print(NspawnMachine._xdotool_command("\\n"))
|
||||
xdotool key --clearmodifiers Return
|
||||
"""
|
||||
if len(key) == 1 and key.isprintable():
|
||||
return make_command(
|
||||
["xdotool", "type", "--clearmodifiers", "--delay", 0, "--", key]
|
||||
)
|
||||
return make_command(
|
||||
["xdotool", "key", "--clearmodifiers", xdotool_key_sequence(key)]
|
||||
)
|
||||
|
||||
def send_key(
|
||||
self,
|
||||
key: str,
|
||||
@@ -1752,25 +1867,7 @@ class NspawnMachine(BaseMachine):
|
||||
_warn_if_numeric_duration(delay, "send_key")
|
||||
context = self.nested(f"sending key {repr(key)}") if log else nullcontext()
|
||||
with context:
|
||||
# Type literal characters to avoid key syntax, e.g. "+" as a chord separator.
|
||||
if len(key) == 1 and key.isprintable():
|
||||
command = [
|
||||
"xdotool",
|
||||
"type",
|
||||
"--clearmodifiers",
|
||||
"--delay",
|
||||
0,
|
||||
"--",
|
||||
key,
|
||||
]
|
||||
else:
|
||||
command = [
|
||||
"xdotool",
|
||||
"key",
|
||||
"--clearmodifiers",
|
||||
xdotool_key_sequence(key),
|
||||
]
|
||||
self.succeed(make_command(command))
|
||||
self.succeed(self._xdotool_command(key))
|
||||
if delay is not None:
|
||||
time.sleep(as_seconds(delay))
|
||||
|
||||
@@ -1799,7 +1896,7 @@ class NspawnMachine(BaseMachine):
|
||||
ret = subprocess.run(["xwdtopnm", xwd_path], stdout=ppm)
|
||||
if ret.returncode != 0:
|
||||
raise MachineError(
|
||||
f"Cannot convert screenshot (xwdtopnm returned code {ret.returncode})"
|
||||
f"{self.name}: Cannot convert screenshot (xwdtopnm returned code {ret.returncode})"
|
||||
)
|
||||
yield ppm_path
|
||||
|
||||
@@ -1836,6 +1933,28 @@ class NspawnMachine(BaseMachine):
|
||||
def is_up(self) -> bool:
|
||||
return self.process is not None
|
||||
|
||||
@staticmethod
|
||||
def _parse_sd_notify(data: bytes) -> tuple[bool, int | None]:
|
||||
"""Extract readiness and the leader PID from an `sd_notify` datagram.
|
||||
|
||||
>>> NspawnMachine._parse_sd_notify(b"READY=1\\n")
|
||||
(True, None)
|
||||
>>> NspawnMachine._parse_sd_notify(b"X_NSPAWN_LEADER_PID=42\\n")
|
||||
(False, 42)
|
||||
>>> NspawnMachine._parse_sd_notify(b"X_NSPAWN_LEADER_PID=42\\nREADY=1\\n")
|
||||
(True, 42)
|
||||
>>> NspawnMachine._parse_sd_notify(b"STATUS=Starting up\\n")
|
||||
(False, None)
|
||||
"""
|
||||
ready = False
|
||||
leader_pid = None
|
||||
for line in data.decode(errors="replace").splitlines():
|
||||
if line == "READY=1":
|
||||
ready = True
|
||||
if line.startswith("X_NSPAWN_LEADER_PID="):
|
||||
leader_pid = int(line.split("=")[1])
|
||||
return ready, leader_pid
|
||||
|
||||
def _drain_notify_socket(self) -> None:
|
||||
"""Continuously drain the container's `sd_notify` socket (NOTIFY_SOCKET)
|
||||
for the whole lifetime of the container, recording readiness and the
|
||||
@@ -1866,13 +1985,7 @@ class NspawnMachine(BaseMachine):
|
||||
continue
|
||||
except OSError:
|
||||
break
|
||||
ready = False
|
||||
leader_pid = None
|
||||
for line in data.decode(errors="replace").splitlines():
|
||||
if line == "READY=1":
|
||||
ready = True
|
||||
if line.startswith("X_NSPAWN_LEADER_PID="):
|
||||
leader_pid = int(line.split("=")[1])
|
||||
ready, leader_pid = self._parse_sd_notify(data)
|
||||
if ready or leader_pid is not None:
|
||||
with self._notify_lock:
|
||||
if ready:
|
||||
@@ -1898,7 +2011,9 @@ class NspawnMachine(BaseMachine):
|
||||
# Poll the socket until we have the container leader PID
|
||||
while True:
|
||||
if self.process.poll() is not None:
|
||||
raise MachineError("systemd-nspawn process exited unexpectedly")
|
||||
raise MachineError(
|
||||
f"{self.name}: systemd-nspawn process exited unexpectedly"
|
||||
)
|
||||
|
||||
with self._notify_lock:
|
||||
is_ready = self._notify_ready
|
||||
|
||||
@@ -12,6 +12,23 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class QMPAPIError(RuntimeError):
|
||||
"""An error response from the QMP API.
|
||||
|
||||
>>> error = {"class": "GenericError", "desc": "boom"}
|
||||
>>> print(QMPAPIError({"error": error, "id": 3}))
|
||||
<QMP API error related to transaction 3 [GenericError]: boom>
|
||||
|
||||
The transaction id is absent from errors that the server hits before it
|
||||
could read the id:
|
||||
|
||||
>>> print(QMPAPIError({"error": error}))
|
||||
<QMP API error related to transaction None [GenericError]: boom>
|
||||
|
||||
>>> QMPAPIError({"error": {"class": "GenericError"}})
|
||||
Traceback (most recent call last):
|
||||
RuntimeError: Malformed QMP API error response
|
||||
"""
|
||||
|
||||
def __init__(self, message: dict[str, Any]):
|
||||
assert "error" in message, "Not an error message!"
|
||||
error = message["error"]
|
||||
|
||||
@@ -13,6 +13,35 @@ class PollingConditionError(Exception):
|
||||
|
||||
|
||||
class PollingCondition:
|
||||
"""A condition that gets checked periodically while a test runs.
|
||||
|
||||
The description comes from the `description` argument. Without one, it
|
||||
falls back to the docstring of the condition, and then to its name:
|
||||
|
||||
>>> from test_driver.logger import CompositeLogger
|
||||
>>> logger = CompositeLogger([])
|
||||
>>> def service_runs():
|
||||
... "The service is running"
|
||||
>>> def no_docstring():
|
||||
... pass
|
||||
>>> PollingCondition(service_runs, logger, description="custom").description
|
||||
'custom'
|
||||
>>> PollingCondition(service_runs, logger).description
|
||||
'The service is running'
|
||||
>>> PollingCondition(no_docstring, logger).description
|
||||
'no_docstring'
|
||||
|
||||
Log messages include the description:
|
||||
|
||||
>>> condition = PollingCondition(service_runs, logger)
|
||||
>>> condition.nested_message
|
||||
"Checking polling condition 'The service is running'"
|
||||
>>> condition.status_message(True)
|
||||
'Polling condition succeeded: The service is running'
|
||||
>>> condition.status_message(False)
|
||||
'Polling condition failed: The service is running'
|
||||
"""
|
||||
|
||||
condition: Callable[[], bool]
|
||||
interval: dt.timedelta
|
||||
description: str | None
|
||||
|
||||
@@ -461,38 +461,35 @@ in
|
||||
pkgs.gtk3.out # for gtk-launch program
|
||||
pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
|
||||
pkgs.xdg-user-dirs-gtk # Used to create the default bookmarks
|
||||
pkgs.gnome-extensions-app
|
||||
pkgs.gnome-tecla
|
||||
];
|
||||
in
|
||||
mandatoryPackages ++ removeExcluded optionalPackages;
|
||||
})
|
||||
|
||||
# Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/gnome-51/elements/core/meta-gnome-core-apps.bst
|
||||
# Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/gnome-48/elements/core/meta-gnome-core-apps.bst
|
||||
(lib.mkIf serviceCfg.core-apps.enable {
|
||||
environment.systemPackages = removeExcluded [
|
||||
pkgs.baobab
|
||||
pkgs.decibels
|
||||
pkgs.epiphany
|
||||
pkgs.gnome-text-editor
|
||||
pkgs.gnome-calculator
|
||||
pkgs.gnome-calendar
|
||||
pkgs.gnome-characters
|
||||
pkgs.gnome-clocks
|
||||
pkgs.gnome-connections
|
||||
pkgs.gnome-console
|
||||
pkgs.gnome-contacts
|
||||
# gnome-disk-utility is controlled below via `programs.gnome-disks`
|
||||
pkgs.gnome-font-viewer
|
||||
pkgs.gnome-logs
|
||||
pkgs.gnome-maps
|
||||
pkgs.gnome-music
|
||||
# gnome-software is controlled below via `services.gnome.gnome-software`
|
||||
pkgs.gnome-system-monitor
|
||||
pkgs.gnome-text-editor
|
||||
pkgs.gnome-tecla
|
||||
pkgs.gnome-weather
|
||||
pkgs.loupe
|
||||
pkgs.nautilus
|
||||
pkgs.papers
|
||||
pkgs.gnome-connections
|
||||
pkgs.showtime
|
||||
pkgs.simple-scan
|
||||
pkgs.snapshot
|
||||
@@ -529,7 +526,6 @@ in
|
||||
];
|
||||
})
|
||||
|
||||
# Note: This is an arbitrary list of packages, there is no "official" list of GNOME games.
|
||||
(lib.mkIf serviceCfg.games.enable {
|
||||
environment.systemPackages = removeExcluded [
|
||||
pkgs.aisleriot
|
||||
@@ -555,13 +551,18 @@ in
|
||||
];
|
||||
})
|
||||
|
||||
# Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/gnome-51/elements/core/meta-gnome-core-developer-tools.bst
|
||||
# Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/gnome-48/elements/core/meta-gnome-core-developer-tools.bst
|
||||
(lib.mkIf serviceCfg.core-developer-tools.enable {
|
||||
environment.systemPackages = removeExcluded [
|
||||
pkgs.dconf-editor
|
||||
pkgs.devhelp
|
||||
pkgs.d-spy
|
||||
pkgs.gnome-builder
|
||||
# boxes would make sense in this option, however
|
||||
# it doesn't function well enough to be included
|
||||
# in default configurations.
|
||||
# https://github.com/NixOS/nixpkgs/issues/60908
|
||||
# pkgs.gnome-boxes
|
||||
pkgs.sysprof
|
||||
];
|
||||
|
||||
|
||||
@@ -353,26 +353,8 @@ in
|
||||
};
|
||||
}
|
||||
]
|
||||
++ lib.optionals (!config.security.pam.p11.enable) [
|
||||
{
|
||||
settings."org/gnome/login-screen" = {
|
||||
enable-smartcard-authentication = false;
|
||||
};
|
||||
}
|
||||
]
|
||||
++ [ "${gdm}/share/gdm/greeter-dconf-defaults" ];
|
||||
|
||||
programs.dconf.profiles.user.databases = [
|
||||
{
|
||||
settings."org/gnome/login-screen" = {
|
||||
enable-smartcard-authentication = config.security.pam.p11.enable;
|
||||
|
||||
# We currently don't provide a `gdm-switchable-auth` PAM service.
|
||||
enable-switchable-authentication = false;
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
# Use AutomaticLogin if delay is zero, because it's immediate.
|
||||
# Otherwise with TimedLogin with zero seconds the prompt is still
|
||||
# presented and there's a little delay.
|
||||
@@ -689,85 +671,6 @@ in
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Do not attempt to authenticate via smartcard when the login option
|
||||
# "Password" is selected (gdm-password).
|
||||
login.p11Auth = lib.mkIf config.security.pam.p11.enable false;
|
||||
|
||||
gdm-smartcard = lib.mkIf config.security.pam.p11.enable {
|
||||
useDefaultRules = false;
|
||||
rules = {
|
||||
auth = utils.pam.autoOrderRules [
|
||||
{
|
||||
name = "nologin";
|
||||
control = "requisite";
|
||||
modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so";
|
||||
}
|
||||
{
|
||||
name = "faillock";
|
||||
control = "requisite";
|
||||
modulePath = "${config.security.pam.package}/lib/security/pam_faillock.so";
|
||||
settings.preauth = true;
|
||||
}
|
||||
{
|
||||
name = "p11";
|
||||
control = "required";
|
||||
modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so";
|
||||
args = [
|
||||
"${pkgs.opensc}/lib/opensc-pkcs11.so"
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "shells";
|
||||
control = "required";
|
||||
modulePath = "${config.security.pam.package}/lib/security/pam_shells.so";
|
||||
}
|
||||
{
|
||||
name = "env";
|
||||
control = "required";
|
||||
modulePath = "${config.security.pam.package}/lib/security/pam_env.so";
|
||||
settings.conffile = "/etc/pam/environment";
|
||||
settings.readenv = 0;
|
||||
}
|
||||
{
|
||||
name = "gdm";
|
||||
enable = pamLogin.enable && pamLogin.enableGnomeKeyring;
|
||||
control = "[success=ok default=1]";
|
||||
modulePath = "${gdm}/lib/security/pam_gdm.so";
|
||||
}
|
||||
{
|
||||
name = "gnome_keyring";
|
||||
enable = pamLogin.enable && pamLogin.enableGnomeKeyring;
|
||||
control = "optional";
|
||||
modulePath = "${pkgs.gnome-keyring}/lib/security/pam_gnome_keyring.so";
|
||||
}
|
||||
];
|
||||
|
||||
account = utils.pam.autoOrderRules [
|
||||
{
|
||||
name = "login";
|
||||
control = "include";
|
||||
modulePath = "login";
|
||||
}
|
||||
];
|
||||
|
||||
password = utils.pam.autoOrderRules [
|
||||
{
|
||||
name = "deny";
|
||||
control = "required";
|
||||
modulePath = "${config.security.pam.package}/lib/security/pam_deny.so";
|
||||
}
|
||||
];
|
||||
|
||||
session = utils.pam.autoOrderRules [
|
||||
{
|
||||
name = "login";
|
||||
control = "include";
|
||||
modulePath = "login";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ in
|
||||
|
||||
- nixpkgs.config.cudaSupport
|
||||
- nixpkgs.config.rocmSupport
|
||||
- if stdenv.hostPlatform.isDarwin
|
||||
- if stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64
|
||||
|
||||
IFF multiple acceleration methods are found to be enabled or if you
|
||||
haven't set either `cudaSupport or rocmSupport` you will have to
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andreas Rammhold <andreas@rammhold.de>
|
||||
Date: Thu, 9 May 2019 11:15:22 +0200
|
||||
Subject: [PATCH] add rootprefix to lookup dir paths
|
||||
|
||||
systemd does not longer use the UDEVLIBEXEC directory as root for
|
||||
discovery default udev rules. By adding `$out/lib` to the lookup paths
|
||||
we should again be able to discover the udev rules amongst other default
|
||||
files that I might have missed.
|
||||
---
|
||||
src/basic/constants.h | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/basic/constants.h b/src/basic/constants.h
|
||||
index 475d8bf..fa11813 100644
|
||||
index 475d8bf79a..fa11813911 100644
|
||||
--- a/src/basic/constants.h
|
||||
+++ b/src/basic/constants.h
|
||||
@@ -40,13 +40,15 @@
|
||||
@@ -260,7 +260,23 @@ in
|
||||
|
||||
options.systemd = {
|
||||
|
||||
package = mkPackageOption pkgs "systemd" { };
|
||||
package = mkPackageOption pkgs "systemd" { } // {
|
||||
# HORRIBLE HACK
|
||||
# Put back the patch that completely broke most networkd setups.
|
||||
# This needs to be reverted and either reinstated in the package
|
||||
# proper, or fixed within the networkd NixOS module, but right now
|
||||
# we just need things to stop being on fire. -K900
|
||||
#
|
||||
# DO NOT remove this without verifying at least
|
||||
# nixosTests.predictable-interface-names.predictableNetworkdSystemdStage1
|
||||
apply =
|
||||
pkg:
|
||||
pkg.overrideAttrs (prevAttrs: {
|
||||
patches = prevAttrs.patches or [ ] ++ [
|
||||
./systemd-search-path.patch
|
||||
];
|
||||
});
|
||||
};
|
||||
|
||||
enableStrictShellChecks = mkEnableOption "" // {
|
||||
description = ''
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
# NixOS.
|
||||
systemd.services."systemd-pcrlogin@".unitConfig.ConditionPathExists =
|
||||
"/run/systemd/nvpcr/login.auth";
|
||||
|
||||
systemd.sockets."systemd-pcrextend" = {
|
||||
wantedBy = [ "sockets.target" ];
|
||||
};
|
||||
}
|
||||
)
|
||||
(
|
||||
@@ -101,6 +105,10 @@
|
||||
"${cfg.package}/lib/systemd/system-generators/systemd-tpm2-generator"
|
||||
"${cfg.package}/lib/systemd/systemd-pcrextend"
|
||||
];
|
||||
|
||||
boot.initrd.systemd.sockets."systemd-pcrextend" = {
|
||||
wantedBy = [ "sockets.target" ];
|
||||
};
|
||||
}
|
||||
)
|
||||
(
|
||||
|
||||
@@ -28,6 +28,8 @@ let
|
||||
|
||||
consoles = lib.concatMapStringsSep " " (c: "console=${c}") cfg.qemu.consoles;
|
||||
|
||||
runScript = hostPkgs.callPackage ./run-virtiofsd-qemu { };
|
||||
|
||||
driveOptions =
|
||||
{ ... }:
|
||||
{
|
||||
@@ -326,33 +328,28 @@ let
|
||||
''
|
||||
)}
|
||||
|
||||
${lib.optionalString useVirtiofs ''
|
||||
echo "Starting virtiofs daemons..."
|
||||
NIX_VIRTIOFS_DIR=$(mktemp -d)
|
||||
${lib.concatLines (
|
||||
lib.mapAttrsToList (tag: share: ''
|
||||
${lib.getExe hostPkgs.virtiofsd} \
|
||||
--socket-path="$NIX_VIRTIOFS_DIR"/"${tag}" \
|
||||
--shared-dir="$(readlink -f "${share.source}")" \
|
||||
${if share.writable then "--writeback" else "--readonly"} \
|
||||
--sandbox=none \
|
||||
--seccomp=none \
|
||||
--cache=${share.cache} \
|
||||
--no-announce-submounts \
|
||||
--translate-uid=host:65534:0:1 \
|
||||
--translate-gid=host:65534:0:1 \
|
||||
&
|
||||
'') cfg.sharedDirectories
|
||||
)}
|
||||
''}
|
||||
export NIX_VIRTIOFS_DIR=$(mktemp -d)
|
||||
|
||||
# Start QEMU.
|
||||
exec ${
|
||||
qemu-common.qemuBinaryWith {
|
||||
qemuPkg = qemu;
|
||||
forceAccel = cfg.qemu.forceAccel;
|
||||
}
|
||||
} \
|
||||
exec ${lib.getExe runScript} \
|
||||
${
|
||||
lib.optionalString (useVirtiofs && cfg.sharedDirectories != { })
|
||||
"--virtiofs-paths ${
|
||||
lib.concatStringsSep " " (
|
||||
lib.mapAttrsToList (
|
||||
tag: share:
|
||||
"${tag}:${share.source}:${share.cache}:${if share.writable then "writeback" else "readonly"}"
|
||||
) cfg.sharedDirectories
|
||||
)
|
||||
}"
|
||||
} \
|
||||
-- \
|
||||
${
|
||||
qemu-common.qemuBinaryWith {
|
||||
qemuPkg = qemu;
|
||||
forceAccel = cfg.qemu.forceAccel;
|
||||
}
|
||||
} \
|
||||
-name ${config.system.name} \
|
||||
-m ${toString config.virtualisation.memorySize} \
|
||||
-smp ${toString config.virtualisation.cores} \
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{ python3Packages }:
|
||||
|
||||
python3Packages.callPackage ./package.nix { }
|
||||
49
nixos/modules/virtualisation/run-virtiofsd-qemu/package.nix
Normal file
49
nixos/modules/virtualisation/run-virtiofsd-qemu/package.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
lib,
|
||||
buildPythonApplication,
|
||||
virtiofsd,
|
||||
ruff,
|
||||
setuptools,
|
||||
ty,
|
||||
}:
|
||||
|
||||
buildPythonApplication {
|
||||
pname = "run-virtiofsd-qemu";
|
||||
version = "1.0";
|
||||
pyproject = true;
|
||||
|
||||
src = ./.;
|
||||
|
||||
postPatch = ''
|
||||
substituteInPlace ./run_virtiofsd_qemu/__init__.py \
|
||||
--replace-fail "@virtiofsd@" "${lib.getExe virtiofsd}"
|
||||
'';
|
||||
|
||||
build-system = [
|
||||
setuptools
|
||||
];
|
||||
|
||||
propagatedBuildInputs = [
|
||||
virtiofsd
|
||||
];
|
||||
|
||||
doCheck = true;
|
||||
|
||||
nativeCheckInputs = [
|
||||
ruff
|
||||
ty
|
||||
];
|
||||
|
||||
checkPhase = ''
|
||||
echo -e "\x1b[32m## run ty\x1b[0m"
|
||||
ty check --error-on-warning run_virtiofsd_qemu
|
||||
echo -e "\x1b[32m## run ruff check\x1b[0m"
|
||||
ruff check .
|
||||
echo -e "\x1b[32m## run ruff format\x1b[0m"
|
||||
ruff format --check --diff .
|
||||
'';
|
||||
|
||||
meta = {
|
||||
mainProgram = "run-virtiofsd-qemu";
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "run-virtiofsd-qemu"
|
||||
version = "1.0"
|
||||
|
||||
[project.scripts]
|
||||
run-virtiofsd-qemu = "run_virtiofsd_qemu:main"
|
||||
|
||||
[tool.setuptools.packages]
|
||||
find = {}
|
||||
@@ -0,0 +1,120 @@
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import signal
|
||||
import subprocess
|
||||
from contextlib import AsyncExitStack, asynccontextmanager
|
||||
from os import environ
|
||||
from pathlib import Path
|
||||
from sys import exit
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def fatal_error(msg: str):
|
||||
logger.error(msg)
|
||||
exit(1)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def virtiofsd(virtiofs_dir: Path, tag: str, source: Path, cache: str, flag: str):
|
||||
socket_path = virtiofs_dir / tag
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
"@virtiofsd@",
|
||||
f"--socket-path={socket_path}",
|
||||
f"--shared-dir={source.resolve()}",
|
||||
f"--{flag}",
|
||||
"--sandbox=none",
|
||||
"--seccomp=none",
|
||||
f"--cache={cache}",
|
||||
"--no-announce-submounts",
|
||||
"--translate-uid=host:65534:0:1",
|
||||
"--translate-gid=host:65534:0:1",
|
||||
)
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
while not await loop.run_in_executor(None, lambda: socket_path.exists()):
|
||||
if proc.returncode is not None:
|
||||
fatal_error(f"virtiofsd process for '{tag}' failed to start. Aborting.")
|
||||
await asyncio.sleep(1)
|
||||
|
||||
yield
|
||||
|
||||
try:
|
||||
proc.terminate()
|
||||
async with asyncio.timeout(2):
|
||||
await proc.communicate()
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.warning(
|
||||
f"virtiofsd process for '{tag}' still running after SIGTERM. Killing."
|
||||
)
|
||||
proc.kill()
|
||||
await proc.communicate()
|
||||
|
||||
|
||||
def extract_arguments() -> tuple[list[tuple[str, Path, str, str]], list[str]]:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--virtiofs-paths",
|
||||
nargs="+",
|
||||
help="Paths to be exposed with virtiofsd in the format 'tag:source:mode:cache'",
|
||||
)
|
||||
|
||||
args, qemu_args = parser.parse_known_args()
|
||||
if not qemu_args:
|
||||
logger.warning("No command to run specified, exiting")
|
||||
exit(0)
|
||||
|
||||
if qemu_args[0] != "--":
|
||||
fatal_error(
|
||||
"Usage error: expected command to run separated with '--' from the args pased to this program!"
|
||||
)
|
||||
qemu_args.pop(0)
|
||||
if not qemu_args:
|
||||
logger.warning("No command to run specified, exiting")
|
||||
exit(0)
|
||||
|
||||
defs = []
|
||||
for defin in args.virtiofs_paths:
|
||||
args = defin.split(":")
|
||||
if len(args) != 4:
|
||||
fatal_error(
|
||||
f"--virtio-paths definition '{defin}' doesn't have four params separated by ':'!"
|
||||
)
|
||||
defs.append((args[0], Path(args[1]), args[2], args[3]))
|
||||
|
||||
return defs, qemu_args
|
||||
|
||||
|
||||
async def amain():
|
||||
logging.basicConfig(format="%(levelname)s: %(funcName)s: %(message)s")
|
||||
args, qemu_args = extract_arguments()
|
||||
|
||||
try:
|
||||
virtiofs_dir = Path(environ["NIX_VIRTIOFS_DIR"])
|
||||
except KeyError:
|
||||
fatal_error("NIX_VIRTIOFS_DIR is unset!")
|
||||
|
||||
async with AsyncExitStack() as virtiofsds:
|
||||
await asyncio.gather(
|
||||
*(
|
||||
virtiofsds.enter_async_context(virtiofsd(virtiofs_dir, *defin))
|
||||
for defin in args
|
||||
)
|
||||
)
|
||||
|
||||
proc = await asyncio.create_subprocess_exec(*qemu_args)
|
||||
loop = asyncio.get_running_loop()
|
||||
loop.add_signal_handler(signal.SIGTERM, lambda: proc.terminate())
|
||||
loop.add_signal_handler(signal.SIGINT, lambda: proc.terminate())
|
||||
await proc.communicate()
|
||||
|
||||
|
||||
def main():
|
||||
asyncio.run(amain())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
pkgs ? import ../../../.. { },
|
||||
}:
|
||||
pkgs.callPackage ./default.nix { }
|
||||
@@ -31,6 +31,12 @@ in
|
||||
displayManager.lightdm.extraConfig = ''
|
||||
logind-check-graphical = false
|
||||
'';
|
||||
|
||||
# `wait_for_x()` establishing a connection that is being teared down
|
||||
# before having any other connection to X11 causes the X server to reset
|
||||
# itself. This flag prevents that behavior.
|
||||
# Context: https://github.com/NixOS/nixpkgs/pull/578540#issuecomment-6593586095
|
||||
displayManager.xserverArgs = lib.mkAfter [ "-noreset" ];
|
||||
})
|
||||
];
|
||||
|
||||
|
||||
@@ -19,15 +19,25 @@
|
||||
|
||||
boot.initrd.availableKernelModules = [ "tpm_tis" ];
|
||||
|
||||
environment.systemPackages = with pkgs; [ cryptsetup ];
|
||||
environment.systemPackages = with pkgs; [
|
||||
cryptsetup
|
||||
tpm2-tools
|
||||
];
|
||||
|
||||
specialisation.boot-luks.configuration = {
|
||||
boot.initrd.luks.devices = lib.mkVMOverride {
|
||||
cryptroot = {
|
||||
device = "/dev/vdb";
|
||||
crypttabExtraOpts = [ "tpm2-device=auto" ];
|
||||
crypttabExtraOpts = [
|
||||
"tpm2-device=auto"
|
||||
"tpm2-measure-pcr=yes"
|
||||
];
|
||||
};
|
||||
};
|
||||
# The volume key measurement is only performed when the OS is explicitly
|
||||
# marked as measured (or booted through a measuring kernel stub).
|
||||
boot.kernelParams = [ "systemd.tpm2_measured_os=1" ];
|
||||
|
||||
virtualisation.rootDevice = "/dev/mapper/cryptroot";
|
||||
};
|
||||
};
|
||||
@@ -54,5 +64,11 @@
|
||||
# Boot and decrypt the disk
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount")
|
||||
|
||||
# The volume key has to be measured into PCR 15 through the
|
||||
# io.systemd.PCRExtend socket during initrd.
|
||||
machine.succeed("grep -q volume-key /run/log/systemd/tpm2-measure.log")
|
||||
pcr = machine.succeed("tpm2_pcrread sha256:15")
|
||||
assert "15: 0x0000000000000000000000000000000000000000000000000000000000000000" not in pcr, pcr
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -41,11 +41,6 @@ let
|
||||
ghostty.pkg = p: p.ghostty;
|
||||
ghostty.cmd = "ghostty -e $command";
|
||||
|
||||
gnome-console.pkg = p: p.gnome-console;
|
||||
gnome-console.executable = "kgx";
|
||||
gnome-console.cmd = "kgx -e $command";
|
||||
gnome-console.kill = true;
|
||||
|
||||
gnome-terminal.pkg = p: p.gnome-terminal;
|
||||
|
||||
guake.pkg = p: p.guake;
|
||||
@@ -56,6 +51,10 @@ let
|
||||
|
||||
kermit.pkg = p: p.kermit-terminal;
|
||||
|
||||
kgx.pkg = p: p.kgx;
|
||||
kgx.cmd = "kgx -e $command";
|
||||
kgx.kill = true;
|
||||
|
||||
kitty.pkg = p: p.kitty;
|
||||
kitty.cmd = "kitty $command";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
stdenv,
|
||||
}:
|
||||
rec {
|
||||
version = "9.2.1252";
|
||||
version = "9.2.1164";
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
@@ -15,7 +15,7 @@ rec {
|
||||
owner = "vim";
|
||||
repo = "vim";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-k5Na69KYXb7kxajpJFv9+vBymApaio7TwHrETudAGrk=";
|
||||
hash = "sha256-Ymtq7+egq8OydTdzHP/q14MK6p+crKlQwduJ27oDbNU=";
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
@@ -24,9 +24,9 @@ let
|
||||
|
||||
coqPath = lib.makeSearchPath "/lib/coq/${rocq-version}/user-contrib" allPackages;
|
||||
|
||||
ocamlPath =
|
||||
lib.makeSearchPathOutput "dev" "/lib/ocaml/${coq.ocamlPackages.ocaml.version}/site-lib"
|
||||
([ coq.ocamlPackages.findlib ] ++ allPackages);
|
||||
ocamlPath = lib.makeSearchPath "/lib/ocaml/${coq.ocamlPackages.ocaml.version}/site-lib" (
|
||||
[ coq.ocamlPackages.findlib ] ++ allPackages
|
||||
);
|
||||
|
||||
pathEnvVar = if isRocq then "ROCQPATH" else "COQPATH";
|
||||
in
|
||||
|
||||
@@ -64,6 +64,8 @@ let
|
||||
versionCheckHook,
|
||||
}:
|
||||
let
|
||||
systemdLibs' = systemdLibs.override { withCompression = true; };
|
||||
|
||||
docker-meta = {
|
||||
license = lib.licenses.asl20;
|
||||
maintainers = with lib.maintainers; [
|
||||
@@ -190,7 +192,7 @@ let
|
||||
++ lib.optionals (lib.versionAtLeast version "29.0.0") [ nftables ]
|
||||
++ lib.optionals withLvm [ lvm2 ]
|
||||
++ lib.optionals withBtrfs [ btrfs-progs ]
|
||||
++ lib.optionals withSystemd [ systemdLibs ]
|
||||
++ lib.optionals withSystemd [ systemdLibs' ]
|
||||
++ lib.optionals withSeccomp [ libseccomp ];
|
||||
|
||||
postPatch = ''
|
||||
|
||||
@@ -200,30 +200,37 @@ if [[ "$NIX_DONT_SET_RPATH_@suffixSalt@" != 1 && "$linkType" != static-pie ]]; t
|
||||
# so, add the directory to the rpath.
|
||||
# It's important to add the rpath in the order of -L..., so
|
||||
# the link time chosen objects will be those of runtime linking.
|
||||
declare -A rpaths seenLibDirs
|
||||
declare -A rpaths
|
||||
for dir in ${libDirs+"${libDirs[@]}"}; do
|
||||
# The same directory is often passed many times, such as from
|
||||
# NIX_LDFLAGS; it would give the same result each time.
|
||||
if [ -n "${seenLibDirs[$dir]:-}" ]; then
|
||||
# If the path is in the store, do not resolve any symlinks and add it to the rpath.
|
||||
# Resolving symlinks in the store breaks bootstrapping, see issue #454199.
|
||||
# If it is outside the store, resolve symlinks step by step until it falls
|
||||
# into the store or it becomes not a symlink.
|
||||
# Always canonicalize the path before checking it is in the store or not.
|
||||
if dir2=$(realpath -s "$dir"); then
|
||||
dir="$dir2"
|
||||
else
|
||||
continue
|
||||
fi
|
||||
seenLibDirs["$dir"]=1
|
||||
# Find where the directory is, following symlinks outside the store,
|
||||
# and in it only where needed; see resolveLibDir. Skip directories
|
||||
# that do not exist, in which the linker cannot find libraries either.
|
||||
if ! [ -d "$dir" ] || ! resolveLibDir "$dir"; then
|
||||
continue
|
||||
fi
|
||||
dir="$resolvedPath"
|
||||
while [ -z "${rpaths[$dir]:-}" ] && [[ "$dir" != "${NIX_STORE:-}"/* ]] && [ -L "$dir" ]; do
|
||||
if dir2=$(readlink "$dir"); then
|
||||
dir="dir2"
|
||||
else
|
||||
break
|
||||
fi
|
||||
if dir2=$(realpath -s "$dir"); then
|
||||
dir="dir2"
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
# If the path turns out to be outside the store, we do not add it to rpath.
|
||||
# This typically happens for libraries in /tmp that are later
|
||||
# copied to $out/lib. If not, we're screwed.
|
||||
if [ -n "${rpaths[$dir]:-}" ] || [[ "$dir" != "${NIX_STORE:-}"/* ]]; then
|
||||
continue
|
||||
fi
|
||||
# Every name in libs is that of a shared library, ending in .so or
|
||||
# containing .so., so the rest of the directory can be skipped.
|
||||
for path in "$dir"/*.so*; do
|
||||
for path in "$dir"/*; do
|
||||
file="${path##*/}"
|
||||
if [ "${libs[$file]:-}" ]; then
|
||||
# This library may have been provided by a previous directory,
|
||||
|
||||
@@ -129,8 +129,6 @@ lib.makeOverridable (
|
||||
"pki"
|
||||
# Custom dconf profiles
|
||||
"dconf"
|
||||
# EGL platform definitions (required by nvidia-x11)
|
||||
"egl"
|
||||
];
|
||||
in
|
||||
map (path: "/etc/${path}") files;
|
||||
|
||||
@@ -302,7 +302,7 @@ lib.extendMkDerivation {
|
||||
|
||||
if [ "$cmd" = "test" ]; then
|
||||
flags+=(-vet=off)
|
||||
concatTo flags checkFlags
|
||||
flags+=($checkFlags)
|
||||
fi
|
||||
|
||||
local OUT
|
||||
|
||||
@@ -109,7 +109,7 @@ fn add_dependencies<P: AsRef<Path> + AsRef<OsStr> + std::fmt::Debug>(
|
||||
.position(|x| *x == 0)
|
||||
.unwrap_or(note.desc.len())];
|
||||
let parsed = serde_json::from_slice::<Vec<DLOpenNote>>(payload)?;
|
||||
for mut parsed_note in parsed {
|
||||
for parsed_note in parsed {
|
||||
if dlopen.use_priority
|
||||
>= parsed_note.priority.unwrap_or(DLOpenPriority::Recommended)
|
||||
|| parsed_note
|
||||
@@ -117,7 +117,9 @@ fn add_dependencies<P: AsRef<Path> + AsRef<OsStr> + std::fmt::Debug>(
|
||||
.map(|f| dlopen.features.contains(&f))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
dlopen_libraries.append(&mut parsed_note.soname);
|
||||
// SONAMEs in one note are ordered alternatives, not
|
||||
// independent dependencies.
|
||||
dlopen_libraries.push(parsed_note.soname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,39 +139,38 @@ fn add_dependencies<P: AsRef<Path> + AsRef<OsStr> + std::fmt::Debug>(
|
||||
.map(|p| Box::<Path>::from(Path::new(p)))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for line in elf
|
||||
for sonames in elf
|
||||
.libraries
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.map(|s| vec![s.to_string()])
|
||||
.chain(dlopen_libraries)
|
||||
{
|
||||
let mut found = false;
|
||||
for path in &rpaths_as_path {
|
||||
let lib = path.join(&line);
|
||||
if lib.exists() {
|
||||
// No need to recurse. The queue will bring it back round.
|
||||
queue.push_back(StorePath {
|
||||
path: Box::from(lib.as_path()),
|
||||
dlopen: dlopen.clone(),
|
||||
});
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
let library = sonames
|
||||
.iter()
|
||||
.flat_map(|soname| rpaths_as_path.iter().map(move |path| path.join(soname)))
|
||||
.find(|lib| lib.exists());
|
||||
if let Some(lib) = library {
|
||||
// No need to recurse. The queue will bring it back round.
|
||||
queue.push_back(StorePath {
|
||||
path: lib.into_boxed_path(),
|
||||
dlopen: dlopen.clone(),
|
||||
});
|
||||
} else {
|
||||
// In Nix, glibc's own libraries lack rpath entries pointing to
|
||||
// themselves, so the dynamic linker (ld-linux-*.so.*) and libc.so.*
|
||||
// can never be resolved through rpath alone. They are always present
|
||||
// in the initrd: the linker via elf.interpreter above, and libc via
|
||||
// at least one binary's rpath. Suppress these known-benign cases.
|
||||
// See also: the ld*.so.? skip in stage-1.nix findLibs.
|
||||
let is_glibc_runtime = (line.starts_with("ld-") && line.contains(".so"))
|
||||
|| line.starts_with("libc.so");
|
||||
let is_glibc_runtime = matches!(
|
||||
sonames.as_slice(),
|
||||
[s] if (s.starts_with("ld-") && s.contains(".so")) || s.starts_with("libc.so")
|
||||
);
|
||||
|
||||
if !is_glibc_runtime {
|
||||
eprintln!(
|
||||
"Warning: Couldn't satisfy dependency {} for {:?}",
|
||||
line,
|
||||
sonames.join(" or "),
|
||||
OsStr::new(&source)
|
||||
);
|
||||
}
|
||||
@@ -314,13 +315,10 @@ fn main() -> eyre::Result<()> {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let contents =
|
||||
fs::read(&args[1]).wrap_err_with(|| format!("failed to open file {:?}", &args[1]))?;
|
||||
let input = serde_json::from_slice::<Vec<StoreInput>>(&contents)
|
||||
.wrap_err_with(|| {
|
||||
let text = String::from_utf8_lossy(&contents);
|
||||
format!("failed to parse JSON '{}' in {:?}",
|
||||
text,
|
||||
&args[1])
|
||||
})?;
|
||||
let input = serde_json::from_slice::<Vec<StoreInput>>(&contents).wrap_err_with(|| {
|
||||
let text = String::from_utf8_lossy(&contents);
|
||||
format!("failed to parse JSON '{}' in {:?}", text, &args[1])
|
||||
})?;
|
||||
let output = &args[2];
|
||||
let out_path = Path::new(output);
|
||||
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
pname = "prefetch-npm-deps";
|
||||
version = (lib.importTOML ./Cargo.toml).package.version;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = lib.cleanSourceWith {
|
||||
src = ./.;
|
||||
filter =
|
||||
|
||||
@@ -45,26 +45,6 @@ lib.extendMkDerivation {
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
# OCaml libraries, and the dependencies they propagate, are only needed
|
||||
# to build other packages. Unless the package chooses its outputs,
|
||||
# those are installed into "dev", rather than "out", to minimize the
|
||||
# "out" runtime closure. Man pages and documentation go to "man" and
|
||||
# "doc".
|
||||
outputs =
|
||||
args.outputs or [
|
||||
"out"
|
||||
"dev"
|
||||
"man"
|
||||
"doc"
|
||||
];
|
||||
|
||||
# The findlib setup hook always points OCAMLFIND_DESTDIR at $out, so
|
||||
# override it after all setup hooks have run.
|
||||
postHook = ''
|
||||
export OCAMLFIND_DESTDIR="''${!outputDev}/lib/ocaml/${ocaml.version}/site-lib/"
|
||||
''
|
||||
+ args.postHook or "";
|
||||
|
||||
inherit enableParallelBuilding;
|
||||
dontAddStaticConfigureFlags = true;
|
||||
configurePlatforms = [ ];
|
||||
@@ -87,15 +67,12 @@ lib.extendMkDerivation {
|
||||
args.installPhase or ''
|
||||
runHook preInstall
|
||||
dune install --prefix $out --libdir $OCAMLFIND_DESTDIR ${lib.concatStringsSep " " dunePackages} \
|
||||
${lib.optionalString (lib.versionAtLeast Dune.version "2.9") ''
|
||||
--docdir "''${!outputDoc}/share/doc" --mandir "''${!outputMan}/share/man" --etcdir "$out/etc" \
|
||||
''} ${lib.optionalString (lib.versionAtLeast Dune.version "3.0") ''
|
||||
--bindir "''${!outputBin}/bin" --datadir "$out/share"
|
||||
''}
|
||||
# Not every package installs something into each output.
|
||||
for output in $(getAllOutputNames); do
|
||||
mkdir -p "''${!output}"
|
||||
done
|
||||
${
|
||||
if lib.versionAtLeast Dune.version "2.9" then
|
||||
"--docdir $out/share/doc --mandir $out/share/man"
|
||||
else
|
||||
""
|
||||
}
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
@@ -106,22 +83,8 @@ lib.extendMkDerivation {
|
||||
runHook postCheck
|
||||
'';
|
||||
|
||||
# With several outputs, multiple-outputs.sh passes autoconf-style
|
||||
# --bindir/--libdir/--mandir/... flags to ./configure. The configure
|
||||
# scripts shipped by dune packages are hand-written and reject them.
|
||||
setOutputFlags = args.setOutputFlags or false;
|
||||
|
||||
meta =
|
||||
let
|
||||
meta = args.meta or { };
|
||||
# meta is often copied from another package, which may have other
|
||||
# outputs. Keep the default if none of them are left.
|
||||
outputsToInstall = lib.intersectLists finalAttrs.outputs (meta.outputsToInstall or [ ]);
|
||||
in
|
||||
removeAttrs meta [ "outputsToInstall" ]
|
||||
// {
|
||||
platforms = meta.platforms or ocaml.meta.platforms;
|
||||
}
|
||||
// lib.optionalAttrs (outputsToInstall != [ ]) { inherit outputsToInstall; };
|
||||
meta = (args.meta or { }) // {
|
||||
platforms = args.meta.platforms or ocaml.meta.platforms;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,223 +1,57 @@
|
||||
import functools
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import multiprocessing as mp
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import tomllib
|
||||
from concurrent.futures import FIRST_EXCEPTION, Future, ThreadPoolExecutor, wait
|
||||
from dataclasses import dataclass, field
|
||||
from os.path import islink, realpath
|
||||
from pathlib import Path
|
||||
from typing import Any, cast
|
||||
from typing import Any, TypedDict, cast
|
||||
from urllib.parse import unquote
|
||||
|
||||
import requests
|
||||
import tomli_w
|
||||
from requests import Session
|
||||
from requests.adapters import HTTPAdapter, Retry
|
||||
|
||||
# Constants for controlling how the crates are downloaded from the registries via `requests`
|
||||
# These do not affect the fetching of git dependencies
|
||||
MAX_WORKERS = min(5, os.cpu_count() or 1) # number of workers in the ThreadPoolExecutor
|
||||
CONNECT_TIMEOUT = 2 # max seconds for establishing initial connection
|
||||
READ_TIMEOUT = 10 # max seconds between receiving data packets
|
||||
TIMEOUT = (CONNECT_TIMEOUT, READ_TIMEOUT)
|
||||
RETRY_COUNT = 3 # number of retries for fetching an url
|
||||
BACKOFF_FACTOR = 0.5 # seconds to wait between retries (gets multiplied by 2 after every retry)
|
||||
|
||||
# If for some reason our custom User-Agent value starts getting rejected, we could
|
||||
# set the User-Agent to the value that cargo uses, e.g.: "cargo/1.95.0 (f2d3ce0bd 2026-03-21)"
|
||||
USER_AGENT = "nixpkgs-fetchCargoVendor/2 (https://github.com/NixOS/nixpkgs)"
|
||||
|
||||
eprint = functools.partial(print, file=sys.stderr)
|
||||
|
||||
|
||||
@dataclass
|
||||
class RegistrySource:
|
||||
raw: str
|
||||
url: str
|
||||
is_sparse: bool
|
||||
ind: int = field(init=False)
|
||||
def load_toml(path: Path) -> dict[str, Any]:
|
||||
with open(path, "rb") as f:
|
||||
return tomllib.load(f)
|
||||
|
||||
|
||||
@dataclass
|
||||
class RegistryPackage:
|
||||
name: str
|
||||
version: str
|
||||
source: RegistrySource
|
||||
checksum: str
|
||||
def get_lockfile_version(cargo_lock_toml: dict[str, Any]) -> int:
|
||||
# lockfile v1 and v2 don't have the `version` key, so assume v2
|
||||
version = cargo_lock_toml.get("version", 2)
|
||||
|
||||
# TODO: add logic for differentiating between v1 and v2
|
||||
|
||||
return version
|
||||
|
||||
|
||||
GIT_SOURCE_REGEX = re.compile(r"git\+(?P<url>[^?]+)(\?(?P<type>rev|tag|branch)=(?P<value>.*))?#(?P<git_sha_rev>.*)")
|
||||
|
||||
|
||||
@dataclass
|
||||
class GitSource:
|
||||
raw: str
|
||||
url: str
|
||||
type: str | None
|
||||
value: str | None
|
||||
git_sha_rev: str
|
||||
ind: int = field(init=False)
|
||||
|
||||
|
||||
@dataclass
|
||||
class GitPackage:
|
||||
name: str
|
||||
version: str
|
||||
source: GitSource
|
||||
|
||||
|
||||
Source = RegistrySource | GitSource
|
||||
Package = RegistryPackage | GitPackage
|
||||
|
||||
|
||||
@dataclass
|
||||
class Lockfile:
|
||||
version: int
|
||||
sources: list[Source]
|
||||
packages: list[Package]
|
||||
|
||||
|
||||
def parse_git_source(raw_source: str, lockfile_version: int) -> GitSource:
|
||||
match = GIT_SOURCE_REGEX.match(raw_source)
|
||||
if match is None:
|
||||
raise Exception(f"Unable to process git source: {raw_source}.")
|
||||
|
||||
parsed_dict = match.groupdict(default=None)
|
||||
url = cast(str, parsed_dict["url"])
|
||||
git_sha_rev = cast(str, parsed_dict["git_sha_rev"])
|
||||
|
||||
source = GitSource(raw_source, url, parsed_dict["type"], parsed_dict["value"], git_sha_rev)
|
||||
|
||||
# the source URL is URL-encoded in lockfile_version >=4
|
||||
# since we just used regex to parse it we have to manually decode the escaped branch/tag name
|
||||
if lockfile_version >= 4 and source.value is not None:
|
||||
source.value = unquote(source.value)
|
||||
|
||||
return source
|
||||
|
||||
|
||||
def parse_source(raw_source: str, lockfile_version: int) -> Source:
|
||||
if raw_source.startswith("git+"):
|
||||
return parse_git_source(raw_source, lockfile_version)
|
||||
elif raw_source.startswith("registry+"):
|
||||
return RegistrySource(raw=raw_source, url=raw_source[9:], is_sparse=False)
|
||||
elif raw_source.startswith("sparse+"):
|
||||
return RegistrySource(raw=raw_source, url=raw_source[7:].rstrip("/"), is_sparse=True)
|
||||
raise Exception(f"Cannot process source: {raw_source}")
|
||||
|
||||
|
||||
def load_lockfile(path: Path) -> Lockfile:
|
||||
with path.open("rb") as f:
|
||||
cargo_lock_toml = tomllib.load(f)
|
||||
|
||||
# The `version` key missing means either lockfile v1 or v2. We assume v2 for now.
|
||||
lockfile_version = cargo_lock_toml.get("version", 2)
|
||||
|
||||
raw_packages: list[dict[str, str]] = cargo_lock_toml["package"]
|
||||
|
||||
sources: list[Source] = []
|
||||
raw_source_to_source: dict[str, Source] = {}
|
||||
|
||||
# we'll mark every source with an index in order of appearance
|
||||
# both git and registry sources have a different incrementing index
|
||||
# we reserve registry index 0 for both of the default crates-io registries
|
||||
|
||||
for raw_source in ["registry+https://github.com/rust-lang/crates.io-index", "sparse+https://index.crates.io/"]:
|
||||
source = parse_source(raw_source, lockfile_version)
|
||||
source.ind = 0
|
||||
sources.append(source)
|
||||
raw_source_to_source[source.raw] = source
|
||||
|
||||
next_registry_ind = 1
|
||||
next_git_ind = 0
|
||||
|
||||
git_selector_tuple_to_git_ind: dict[tuple[str, str | None, str | None], int] = {}
|
||||
|
||||
for raw_pkg in raw_packages:
|
||||
raw_source = raw_pkg.get("source", None)
|
||||
if raw_source is None: # Skip local dependencies
|
||||
continue
|
||||
if raw_source in raw_source_to_source:
|
||||
continue
|
||||
|
||||
source = parse_source(raw_source, lockfile_version)
|
||||
match source:
|
||||
case RegistrySource():
|
||||
source.ind = next_registry_ind
|
||||
next_registry_ind += 1
|
||||
case GitSource():
|
||||
# git sources may get the same `ind` value if their selectors match
|
||||
tup = (source.url, source.type, source.value)
|
||||
if tup not in git_selector_tuple_to_git_ind:
|
||||
git_selector_tuple_to_git_ind[tup] = next_git_ind
|
||||
next_git_ind += 1
|
||||
source.ind = git_selector_tuple_to_git_ind[tup]
|
||||
|
||||
sources.append(source)
|
||||
raw_source_to_source[source.raw] = source
|
||||
|
||||
packages: list[Package] = []
|
||||
|
||||
for raw_pkg in raw_packages:
|
||||
name = raw_pkg["name"]
|
||||
version = raw_pkg["version"]
|
||||
raw_source = raw_pkg.get("source", None)
|
||||
if raw_source is None: # Skip local dependencies
|
||||
continue
|
||||
source = raw_source_to_source[raw_source]
|
||||
|
||||
match source:
|
||||
case RegistrySource():
|
||||
checksum = raw_pkg.get("checksum", None)
|
||||
|
||||
# lockfile v1 has the checksum values in a separate metadata table
|
||||
if checksum is None:
|
||||
lockfile_version = 1
|
||||
checksum_key = f"checksum {name} {version} ({source.raw})"
|
||||
checksum = cargo_lock_toml["metadata"][checksum_key]
|
||||
|
||||
pkg = RegistryPackage(name, version, source, checksum)
|
||||
case GitSource():
|
||||
pkg = GitPackage(name, version, source)
|
||||
|
||||
packages.append(pkg)
|
||||
|
||||
return Lockfile(lockfile_version, sources, packages)
|
||||
|
||||
|
||||
_local = threading.local()
|
||||
|
||||
|
||||
def get_session() -> Session:
|
||||
if hasattr(_local, "session"):
|
||||
return _local.session
|
||||
|
||||
def create_http_session() -> requests.Session:
|
||||
retries = Retry(
|
||||
total=RETRY_COUNT,
|
||||
backoff_factor=BACKOFF_FACTOR,
|
||||
total=5,
|
||||
backoff_factor=0.5,
|
||||
status_forcelist=[500, 502, 503, 504]
|
||||
)
|
||||
session = Session()
|
||||
session.headers["User-Agent"] = USER_AGENT
|
||||
session = requests.Session()
|
||||
session.headers["User-Agent"] = "nixpkgs-fetchCargoVendor/2 (https://github.com/NixOS/nixpkgs)"
|
||||
session.mount('http://', HTTPAdapter(max_retries=retries))
|
||||
session.mount('https://', HTTPAdapter(max_retries=retries))
|
||||
|
||||
_local.session = session
|
||||
return session
|
||||
|
||||
|
||||
def download_file_with_checksum(url: str, destination_path: Path) -> str:
|
||||
session = get_session()
|
||||
def download_file_with_checksum(session: requests.Session, url: str, destination_path: Path) -> str:
|
||||
sha256_hash = hashlib.sha256()
|
||||
with session.get(url, stream=True, timeout=TIMEOUT) as response:
|
||||
response.raise_for_status()
|
||||
with destination_path.open("wb") as file:
|
||||
with session.get(url, stream=True) as response:
|
||||
if not response.ok:
|
||||
raise Exception(f"Failed to fetch file from {url}. Status code: {response.status_code}")
|
||||
with open(destination_path, "wb") as file:
|
||||
for chunk in response.iter_content(1024): # Download in chunks
|
||||
if chunk: # Filter out keep-alive chunks
|
||||
file.write(chunk)
|
||||
@@ -228,157 +62,117 @@ def download_file_with_checksum(url: str, destination_path: Path) -> str:
|
||||
return checksum
|
||||
|
||||
|
||||
# Fetch the config.json file and get the .dl key from it
|
||||
# See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration
|
||||
def fetch_dl_for_registry_source(source: RegistrySource) -> str:
|
||||
# We hardcode the .dl value for crates-io registries to avoid having to clone the git repo, saving a few seconds
|
||||
if source.ind == 0:
|
||||
return "https://static.crates.io/crates"
|
||||
def get_download_url_for_tarball(pkg: dict[str, Any]) -> str:
|
||||
# TODO: support other registries
|
||||
# maybe fetch config.json from the registry root and get the dl key
|
||||
# See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration
|
||||
if pkg["source"] != "registry+https://github.com/rust-lang/crates.io-index":
|
||||
raise Exception("Only the default crates.io registry is supported.")
|
||||
|
||||
eprint(f'Fetching .dl value for registry "{source.url}"')
|
||||
if source.is_sparse:
|
||||
url = source.url + "/config.json"
|
||||
|
||||
# https://doc.rust-lang.org/cargo/reference/registry-web-api.html#web-api
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
|
||||
session = get_session()
|
||||
with session.get(url, headers=headers, timeout=TIMEOUT) as response:
|
||||
response.raise_for_status()
|
||||
registry_config: dict[str, str] = response.json()
|
||||
else:
|
||||
tmp_dir = Path(tempfile.mkdtemp())
|
||||
# use spare-checkout to only get the config.json file from the registry's git repo
|
||||
# --quiet is deliberately not used to be able to debug if something goes wrong
|
||||
cmd = ["nix-prefetch-git", "--builder", "--url", source.url, "--rev", "HEAD", "--sparse-checkout", "config.json", "--out", str(tmp_dir)]
|
||||
subprocess.check_output(cmd)
|
||||
with (tmp_dir / "config.json").open("rb") as f:
|
||||
registry_config: dict[str, str] = json.load(f)
|
||||
|
||||
dl = registry_config["dl"]
|
||||
|
||||
auth_required = registry_config.get("auth-required", False)
|
||||
if auth_required:
|
||||
raise Exception(f'Registry "{source.url}" requires authentication, but it is not yet implemented!')
|
||||
|
||||
return dl
|
||||
# Use static.crates.io (CDN) instead of crates.io/api to avoid the 1 req/sec
|
||||
# rate limit on the API servers.
|
||||
return f"https://static.crates.io/crates/{pkg["name"]}/{pkg["version"]}/download"
|
||||
|
||||
|
||||
# See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-files
|
||||
def name_to_prefix(name: str) -> str:
|
||||
nl = len(name)
|
||||
if nl <= 2:
|
||||
return str(nl)
|
||||
if nl == 3:
|
||||
return "3/" + name[0]
|
||||
return name[0:2] + "/" + name[2:4]
|
||||
def download_tarball(session: requests.Session, pkg: dict[str, Any], out_dir: Path) -> None:
|
||||
|
||||
url = get_download_url_for_tarball(pkg)
|
||||
filename = f"{pkg["name"]}-{pkg["version"]}.tar.gz"
|
||||
|
||||
# See: https://doc.rust-lang.org/cargo/reference/registry-index.html#index-configuration
|
||||
def make_download_url_for_tarball(pkg: RegistryPackage, dl: str) -> str:
|
||||
# Assume default substitutions if no substitutions are specified
|
||||
url = dl if "}" in dl else dl + "/{crate}/{version}/download"
|
||||
# TODO: allow legacy checksum specification, see importCargoLock for example
|
||||
# also, don't forget about the other usage of the checksum
|
||||
expected_checksum = pkg["checksum"]
|
||||
|
||||
prefix = name_to_prefix(pkg.name)
|
||||
url = url.replace("{crate}", pkg.name)
|
||||
url = url.replace("{version}", pkg.version)
|
||||
url = url.replace("{prefix}", prefix)
|
||||
url = url.replace("{lowerprefix}", prefix.lower())
|
||||
url = url.replace("{sha256-checksum}", pkg.checksum)
|
||||
return url
|
||||
tarball_out_dir = out_dir / "tarballs" / filename
|
||||
eprint(f"Fetching {url} -> tarballs/{filename}")
|
||||
|
||||
|
||||
def download_crate_tarball(url: str, out_path: Path, expected_checksum: str) -> None:
|
||||
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
eprint(f"Fetching {url} -> {out_path}")
|
||||
calculated_checksum = download_file_with_checksum(url, out_path)
|
||||
calculated_checksum = download_file_with_checksum(session, url, tarball_out_dir)
|
||||
|
||||
if calculated_checksum != expected_checksum:
|
||||
raise Exception(f"Hash mismatch! File fetched from {url} had checksum {calculated_checksum}, expected {expected_checksum}.")
|
||||
|
||||
|
||||
def download_git_tree(url: str, git_sha_rev: str, out_dir: Path) -> None:
|
||||
|
||||
tree_out_dir = out_dir / "git" / git_sha_rev
|
||||
|
||||
# This could happen if different selectors point to the same git_sha_rev
|
||||
if tree_out_dir.exists():
|
||||
eprint(f"Skipping fetching {url}#{git_sha_rev} as it has already been downloaded")
|
||||
return
|
||||
|
||||
tree_out_dir.mkdir(parents=True)
|
||||
|
||||
eprint(f"Fetching {url}#{git_sha_rev} -> git/{git_sha_rev}")
|
||||
|
||||
cmd = ["nix-prefetch-git", "--builder", "--quiet", "--fetch-submodules", "--url", url, "--rev", git_sha_rev, "--out", str(tree_out_dir)]
|
||||
subprocess.check_output(cmd)
|
||||
|
||||
|
||||
def make_tarball_relpath(pkg: RegistryPackage) -> Path:
|
||||
# Instead of .tar.gz we could have used the .crate extension
|
||||
# But we keep using .tar.gz for backwards compat
|
||||
filename = f'{pkg.name}-{pkg.version}.tar.gz'
|
||||
GIT_SOURCE_REGEX = re.compile("git\\+(?P<url>[^?]+)(\\?(?P<type>rev|tag|branch)=(?P<value>.*))?#(?P<git_sha_rev>.*)")
|
||||
|
||||
# For backwards compat, all crates.io crates (where source.ind == 0)
|
||||
# are stored directly in tarballs/
|
||||
# Crates from other registries are stored in tarballs/registry-{ind}/
|
||||
if pkg.source.ind == 0:
|
||||
reldir = Path("tarballs")
|
||||
else:
|
||||
reldir = Path("tarballs") / f"registry-{pkg.source.ind}"
|
||||
|
||||
return reldir / filename
|
||||
class GitSourceInfo(TypedDict):
|
||||
url: str
|
||||
type: str | None
|
||||
value: str | None
|
||||
git_sha_rev: str
|
||||
|
||||
|
||||
def parse_git_source(source: str, lockfile_version: int) -> GitSourceInfo:
|
||||
match = GIT_SOURCE_REGEX.match(source)
|
||||
if match is None:
|
||||
raise Exception(f"Unable to process git source: {source}.")
|
||||
|
||||
source_info = cast(GitSourceInfo, match.groupdict(default=None))
|
||||
|
||||
# the source URL is URL-encoded in lockfile_version >=4
|
||||
# since we just used regex to parse it we have to manually decode the escaped branch/tag name
|
||||
if lockfile_version >= 4 and source_info["value"] is not None:
|
||||
source_info["value"] = unquote(source_info["value"])
|
||||
|
||||
return source_info
|
||||
|
||||
|
||||
def create_vendor_staging(lockfile_path: Path, out_dir: Path) -> None:
|
||||
lockfile = load_lockfile(lockfile_path)
|
||||
cargo_lock_toml = load_toml(lockfile_path)
|
||||
lockfile_version = get_lockfile_version(cargo_lock_toml)
|
||||
|
||||
git_packages: list[dict[str, Any]] = []
|
||||
registry_packages: list[dict[str, Any]] = []
|
||||
|
||||
for pkg in cargo_lock_toml["package"]:
|
||||
# ignore local dependenices
|
||||
if "source" not in pkg.keys():
|
||||
eprint(f"Skipping local dependency: {pkg["name"]}")
|
||||
continue
|
||||
source = pkg["source"]
|
||||
|
||||
if source.startswith("git+"):
|
||||
git_packages.append(pkg)
|
||||
elif source.startswith("registry+"):
|
||||
registry_packages.append(pkg)
|
||||
else:
|
||||
raise Exception(f"Can't process source: {source}.")
|
||||
|
||||
git_sha_rev_to_url: dict[str, str] = {}
|
||||
for pkg in git_packages:
|
||||
source_info = parse_git_source(pkg["source"], lockfile_version)
|
||||
git_sha_rev_to_url[source_info["git_sha_rev"]] = source_info["url"]
|
||||
|
||||
out_dir.mkdir(exist_ok=True)
|
||||
shutil.copy(lockfile_path, out_dir / "Cargo.lock")
|
||||
|
||||
git_sources = [source for source in lockfile.sources if isinstance(source, GitSource)]
|
||||
registry_sources = [source for source in lockfile.sources if isinstance(source, RegistrySource)]
|
||||
registry_packages = [pkg for pkg in lockfile.packages if isinstance(pkg, RegistryPackage)]
|
||||
# fetch git trees sequentially, since fetching concurrently leads to flaky behaviour
|
||||
if len(git_packages) != 0:
|
||||
(out_dir / "git").mkdir()
|
||||
for git_sha_rev, url in git_sha_rev_to_url.items():
|
||||
download_git_tree(url, git_sha_rev, out_dir)
|
||||
|
||||
# We fetch git trees sequentially because fetching concurrently seemed to cause flaky behaviour
|
||||
for source in git_sources:
|
||||
download_git_tree(source.url, source.git_sha_rev, out_dir)
|
||||
|
||||
raw_registry_source_to_dl: dict[str, str] = {}
|
||||
for source in registry_sources:
|
||||
dl = fetch_dl_for_registry_source(source)
|
||||
eprint(f'Using .dl value of "{dl}" for registry "{source.raw}"')
|
||||
raw_registry_source_to_dl[source.raw] = dl
|
||||
|
||||
eprint(f"Downloading crate tarballs with {MAX_WORKERS} workers...")
|
||||
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
|
||||
futures: list[Future[None]] = []
|
||||
|
||||
for pkg in registry_packages:
|
||||
dl = raw_registry_source_to_dl[pkg.source.raw]
|
||||
url = make_download_url_for_tarball(pkg, dl)
|
||||
|
||||
out_path = out_dir / make_tarball_relpath(pkg)
|
||||
|
||||
future = executor.submit(download_crate_tarball, url, out_path, pkg.checksum)
|
||||
futures.append(future)
|
||||
|
||||
# fail early if a worker raises an exception
|
||||
done, _ = wait(futures, return_when=FIRST_EXCEPTION)
|
||||
for f in done:
|
||||
e = f.exception()
|
||||
if e is None:
|
||||
continue
|
||||
executor.shutdown(cancel_futures=True)
|
||||
raise Exception(f"Failed to download tarball: {e}")
|
||||
# run tarball download jobs in parallel, with at most 5 concurrent download jobs
|
||||
with mp.Pool(min(5, mp.cpu_count())) as pool:
|
||||
if len(registry_packages) != 0:
|
||||
(out_dir / "tarballs").mkdir()
|
||||
session = create_http_session()
|
||||
tarball_args_gen = ((session, pkg, out_dir) for pkg in registry_packages)
|
||||
pool.starmap(download_tarball, tarball_args_gen)
|
||||
|
||||
|
||||
def get_manifest_metadata(manifest_path: Path) -> dict[str, Any]:
|
||||
cmd = ["cargo", "metadata", "--format-version", "1", "--no-deps", "--manifest-path", str(manifest_path)]
|
||||
output = subprocess.check_output(cmd, cwd=manifest_path.parent)
|
||||
output = subprocess.check_output(cmd)
|
||||
return json.loads(output)
|
||||
|
||||
|
||||
@@ -450,7 +244,8 @@ def copy_and_patch_git_crate_subtree(git_tree: Path, crate_name: str, crate_out_
|
||||
shutil.copytree(crate_tree, crate_out_dir, ignore=ignore_func)
|
||||
crate_out_dir.chmod(0o755)
|
||||
|
||||
manifest_data = crate_manifest_path.read_text()
|
||||
with open(crate_manifest_path, "r") as f:
|
||||
manifest_data = f.read()
|
||||
|
||||
if "workspace" in manifest_data:
|
||||
crate_manifest_metadata = get_manifest_metadata(crate_manifest_path)
|
||||
@@ -473,16 +268,16 @@ def extract_crate_tarball_contents(tarball_path: Path, crate_out_dir: Path) -> N
|
||||
subprocess.check_output(cmd)
|
||||
|
||||
|
||||
def make_git_source_selector(source: GitSource) -> dict[str, str]:
|
||||
def make_git_source_selector(source_info: GitSourceInfo) -> dict[str, str]:
|
||||
selector = {}
|
||||
selector["git"] = source.url
|
||||
if source.type is not None:
|
||||
selector[source.type] = source.value
|
||||
selector["git"] = source_info["url"]
|
||||
if source_info["type"] is not None:
|
||||
selector[source_info["type"]] = source_info["value"]
|
||||
return selector
|
||||
|
||||
|
||||
def make_registry_source_selector(source: RegistrySource) -> dict[str, str]:
|
||||
registry = source.raw if source.is_sparse else source.url
|
||||
def make_registry_source_selector(source: str) -> dict[str, str]:
|
||||
registry = source[9:] if source.startswith("registry+") else source
|
||||
selector = {}
|
||||
selector["registry"] = registry
|
||||
return selector
|
||||
@@ -493,9 +288,14 @@ def create_vendor(vendor_staging_dir: Path, out_dir: Path) -> None:
|
||||
out_dir.mkdir(exist_ok=True)
|
||||
shutil.copy(lockfile_path, out_dir / "Cargo.lock")
|
||||
|
||||
lockfile = load_lockfile(lockfile_path)
|
||||
cargo_lock_toml = load_toml(lockfile_path)
|
||||
lockfile_version = get_lockfile_version(cargo_lock_toml)
|
||||
|
||||
source_to_ind: dict[str, str] = {}
|
||||
selector_to_ind: dict[tuple, str] = {}
|
||||
source_config = {}
|
||||
next_registry_ind = 0
|
||||
next_git_ind = 0
|
||||
|
||||
def add_source_replacement(
|
||||
orig_key: str,
|
||||
@@ -508,96 +308,112 @@ def create_vendor(vendor_staging_dir: Path, out_dir: Path) -> None:
|
||||
source_config[orig_key] = orig_selector
|
||||
source_config[orig_key]["replace-with"] = vendored_key
|
||||
|
||||
# we reserve registry index 0 for crates-io
|
||||
source_to_ind["registry+https://github.com/rust-lang/crates.io-index"] = "registry-0"
|
||||
source_to_ind["sparse+https://index.crates.io/"] = "registry-0"
|
||||
add_source_replacement(
|
||||
orig_key="crates-io",
|
||||
orig_selector={}, # there is an internal selector defined for the `crates-io` source
|
||||
vendored_key="vendored-source-registry-0",
|
||||
vendored_dir="@vendor@/source-registry-0"
|
||||
)
|
||||
next_registry_ind += 1
|
||||
|
||||
processed_git_inds = set()
|
||||
for pkg in cargo_lock_toml["package"]:
|
||||
# ignore local dependencies
|
||||
if "source" not in pkg.keys():
|
||||
continue
|
||||
source: str = pkg["source"]
|
||||
if source in source_to_ind:
|
||||
continue
|
||||
|
||||
for source in lockfile.sources:
|
||||
match source:
|
||||
case RegistrySource():
|
||||
if source.ind == 0: # crates-io already handled separately above
|
||||
continue
|
||||
if source.startswith("git+"):
|
||||
source_info = parse_git_source(source, lockfile_version)
|
||||
selector = make_git_source_selector(source_info)
|
||||
selector_key = (source_info["url"], source_info["type"], source_info["value"])
|
||||
if selector_key in selector_to_ind:
|
||||
ind = selector_to_ind[selector_key]
|
||||
else:
|
||||
ind = f"git-{next_git_ind}"
|
||||
next_git_ind += 1
|
||||
selector_to_ind[selector_key] = ind
|
||||
add_source_replacement(
|
||||
orig_key=f"original-source-registry-{source.ind}",
|
||||
orig_selector=make_registry_source_selector(source),
|
||||
vendored_key=f"vendored-source-registry-{source.ind}",
|
||||
vendored_dir=f"@vendor@/source-registry-{source.ind}"
|
||||
orig_key=f"original-source-{ind}",
|
||||
orig_selector=selector,
|
||||
vendored_key=f"vendored-source-{ind}",
|
||||
vendored_dir=f"@vendor@/source-{ind}"
|
||||
)
|
||||
case GitSource():
|
||||
# In some cases multiple git sources can have the same selector, thus the same git ind
|
||||
# but source replacements can't be made for the same selector multiple times
|
||||
if source.ind in processed_git_inds:
|
||||
continue
|
||||
processed_git_inds.add(source.ind)
|
||||
elif source.startswith("registry+") or source.startswith("sparse+"):
|
||||
ind = f"registry-{next_registry_ind}"
|
||||
next_registry_ind += 1
|
||||
selector = make_registry_source_selector(source)
|
||||
add_source_replacement(
|
||||
orig_key=f"original-source-{ind}",
|
||||
orig_selector=selector,
|
||||
vendored_key=f"vendored-source-{ind}",
|
||||
vendored_dir=f"@vendor@/source-{ind}"
|
||||
)
|
||||
else:
|
||||
raise Exception(f"Can't process source: {source}.")
|
||||
|
||||
add_source_replacement(
|
||||
orig_key=f"original-source-git-{source.ind}",
|
||||
orig_selector=make_git_source_selector(source),
|
||||
vendored_key=f"vendored-source-git-{source.ind}",
|
||||
vendored_dir=f"@vendor@/source-git-{source.ind}"
|
||||
)
|
||||
source_to_ind[source] = ind
|
||||
|
||||
config_path = out_dir / ".cargo" / "config.toml"
|
||||
config_path.parent.mkdir()
|
||||
|
||||
with config_path.open("wb") as config_file:
|
||||
with open(config_path, "wb") as config_file:
|
||||
tomli_w.dump({"source": source_config}, config_file)
|
||||
|
||||
for pkg in lockfile.packages:
|
||||
match pkg:
|
||||
case RegistryPackage():
|
||||
crate_out_dir = out_dir / f"source-registry-{pkg.source.ind}" / f"{pkg.name}-{pkg.version}"
|
||||
crate_out_dir.parent.mkdir(exist_ok=True)
|
||||
for pkg in cargo_lock_toml["package"]:
|
||||
|
||||
tarball_path = vendor_staging_dir / make_tarball_relpath(pkg)
|
||||
# ignore local dependenices
|
||||
if "source" not in pkg.keys():
|
||||
continue
|
||||
|
||||
extract_crate_tarball_contents(tarball_path, crate_out_dir)
|
||||
source: str = pkg["source"]
|
||||
source_ind = source_to_ind[source]
|
||||
crate_dir_name = f"{pkg["name"]}-{pkg["version"]}"
|
||||
source_dir_name = f"source-{source_ind}"
|
||||
crate_out_dir = out_dir / source_dir_name / crate_dir_name
|
||||
crate_out_dir.parent.mkdir(exist_ok=True)
|
||||
|
||||
# non-git based crates need the package checksum at minimum
|
||||
with (crate_out_dir / ".cargo-checksum.json").open("w") as f:
|
||||
json.dump({"files": {}, "package": pkg.checksum}, f)
|
||||
if source.startswith("git+"):
|
||||
|
||||
case GitPackage():
|
||||
crate_out_dir = out_dir / f"source-git-{pkg.source.ind}" / f"{pkg.name}-{pkg.version}"
|
||||
crate_out_dir.parent.mkdir(exist_ok=True)
|
||||
source_info = parse_git_source(source, lockfile_version)
|
||||
|
||||
if crate_out_dir.exists():
|
||||
raise Exception(
|
||||
f"{crate_out_dir} already exists!\n"
|
||||
"This likely due to multiple packages having the same name, version and git selector, but not the same locked git revision\n"
|
||||
"As a workaround, change all conflicting packages to have different git selectors\n"
|
||||
"e.g. specifying an exact rev=<hash> selector for each affected package in both Cargo.toml and Cargo.lock\n"
|
||||
"If it is not possible or difficult to do so (e.g. it's a transient dependency), as a hack, you could also consider keeping\n"
|
||||
"the package with the most up-to-date revision and removing all other duplicated entries from Cargo.lock"
|
||||
)
|
||||
git_sha_rev = source_info["git_sha_rev"]
|
||||
git_tree = vendor_staging_dir / "git" / git_sha_rev
|
||||
|
||||
git_sha_rev = pkg.source.git_sha_rev
|
||||
git_tree = vendor_staging_dir / "git" / git_sha_rev
|
||||
copy_and_patch_git_crate_subtree(git_tree, pkg["name"], crate_out_dir)
|
||||
|
||||
copy_and_patch_git_crate_subtree(git_tree, pkg.name, crate_out_dir)
|
||||
# git based crates allow having no checksum information
|
||||
with open(crate_out_dir / ".cargo-checksum.json", "w") as f:
|
||||
json.dump({"files": {}}, f)
|
||||
|
||||
# git based crates allow having no checksum information
|
||||
with (crate_out_dir / ".cargo-checksum.json").open("w") as f:
|
||||
json.dump({"files": {}}, f)
|
||||
elif source.startswith("registry+") or source.startswith("sparse+"):
|
||||
filename = f"{pkg["name"]}-{pkg["version"]}.tar.gz"
|
||||
|
||||
# TODO: change this when non-crates-io registries are supported
|
||||
dir_name = "tarballs"
|
||||
|
||||
tarball_path = vendor_staging_dir / dir_name / filename
|
||||
|
||||
extract_crate_tarball_contents(tarball_path, crate_out_dir)
|
||||
|
||||
# non-git based crates need the package checksum at minimum
|
||||
with open(crate_out_dir / ".cargo-checksum.json", "w") as f:
|
||||
json.dump({"files": {}, "package": pkg["checksum"]}, f)
|
||||
|
||||
else:
|
||||
raise Exception(f"Can't process source: {source}.")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
subcommand = sys.argv[1]
|
||||
|
||||
subcommand_func_dict = {
|
||||
"create-vendor-staging": lambda: create_vendor_staging(
|
||||
lockfile_path=Path(sys.argv[2]),
|
||||
out_dir=Path(sys.argv[3])
|
||||
),
|
||||
"create-vendor": lambda: create_vendor(
|
||||
vendor_staging_dir=Path(sys.argv[2]),
|
||||
out_dir=Path(sys.argv[3])
|
||||
)
|
||||
"create-vendor-staging": lambda: create_vendor_staging(lockfile_path=Path(sys.argv[2]), out_dir=Path(sys.argv[3])),
|
||||
"create-vendor": lambda: create_vendor(vendor_staging_dir=Path(sys.argv[2]), out_dir=Path(sys.argv[3]))
|
||||
}
|
||||
|
||||
subcommand_func = subcommand_func_dict.get(subcommand)
|
||||
|
||||
@@ -8,11 +8,6 @@ cargoSetupPostUnpackHook() {
|
||||
# it writable. If we're using a tarball, the unpackFile hook already handles
|
||||
# this for us automatically.
|
||||
if [ -z $cargoVendorDir ]; then
|
||||
if [ -z "$cargoDeps" ]; then
|
||||
echo "ERROR: Missing cargoDeps"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d "$cargoDeps" ]; then
|
||||
local dest=$(stripHash "$cargoDeps")
|
||||
cp -Lr --reflink=auto -- "$cargoDeps" "$dest"
|
||||
@@ -91,77 +86,6 @@ cargoSetupPostPatchHook() {
|
||||
echo "Finished cargoSetupPostPatchHook"
|
||||
}
|
||||
|
||||
cargoUseSystemLibs() {
|
||||
# Sentinel directory that doesn't exist. For packages
|
||||
# Where you tell it directories, but can't force it to only
|
||||
# use system libraries
|
||||
#
|
||||
# Note that this isn't perfect, as some have fallbacks if their probing fails.
|
||||
local -r sentinel_dir="$(mktemp -du nixpkgs.XXXX)/use/system/library"
|
||||
|
||||
# https://docs.rs/system-deps/8.0.0/system_deps/#internally-build-system-libraries
|
||||
export SYSTEM_DEPS_BUILD_INTERNAL="never"
|
||||
|
||||
# https://github.com/aws/aws-lc-rs/blob/741dbf573a64b6a1e1e6b7c1131a0f8153a28441/aws-lc-sys/README.md#automatic-detection
|
||||
export AWS_LC_SYS_USE_SYSTEM="1"
|
||||
|
||||
# https://github.com/rust-openssl/rust-openssl/blob/b46d5ec06144795e8f9e118c44bebd392956917a/openssl-sys/build/main.rs#L53
|
||||
export OPENSSL_NO_VENDOR="1"
|
||||
|
||||
# 1 = Links statically to the vendored one
|
||||
# 0 = Use pkg-config
|
||||
# https://github.com/rust-lang/libz-sys/blob/2ce3271849d85329b668e0bac9f21427ecf8aef9/build.rs#L256
|
||||
export LIBZ_SYS_STATIC="0"
|
||||
|
||||
# https://github.com/rusqlite/rusqlite/blob/db83b9b08d9cab73f912501eefb8df7b100acd7d/libsqlite3-sys/build.rs#L53
|
||||
export LIBSQLITE3_SYS_USE_PKG_CONFIG="1"
|
||||
|
||||
# https://github.com/gyscos/zstd-rs/blob/ad18ca4e275aed9acc3087d7c1c65d03ab67ad6e/zstd-safe/zstd-sys/build.rs#L279
|
||||
export ZSTD_SYS_USE_PKG_CONFIG="1"
|
||||
|
||||
# https://github.com/rust-lang/git2-rs/blob/a00922bcdf0f78419aa5dd0d3643e73ce01672a8/libgit2-sys/build.rs#L95
|
||||
export LIBGIT2_NO_VENDOR="1"
|
||||
|
||||
# https://github.com/sodiumoxide/sodiumoxide/blob/3057acb1a030ad86ed8892a223d64036ab5e8523/libsodium-sys/build.rs#L34
|
||||
export SODIUM_USE_PKG_CONFIG="1"
|
||||
|
||||
# https://github.com/rust-onig/rust-onig/blob/73e63eb3eea6d93d24a4aadf7fea580287750c7d/onig_sys/build.rs#L250
|
||||
export RUSTONIG_SYSTEM_LIBONIG="1"
|
||||
|
||||
# https://github.com/rust-lang/ssh2-rs/blob/0a11bdd4eecf4525e540c30f14b15ab1c07194b7/libssh2-sys/build.rs#L23
|
||||
export LIBSSH2_SYS_USE_PKG_CONFIG="1"
|
||||
|
||||
# We can only supply the src dir.
|
||||
# https://github.com/nginx/ngx-rust/tree/main/nginx-sys#input-variables
|
||||
# Since we don't want to pull it in for every build, we set it to a dummy value
|
||||
# in all builds, but lets the user set it via `env.NGINX_SOURCE_DIR = nginx.src`
|
||||
export NGINX_SOURCE_DIR="${NGINX_SOURCE_DIR:-"$sentinel_dir/nginx/src"}"
|
||||
|
||||
# We can only supply the lib and include dirs
|
||||
# https://github.com/duckdb/duckdb-rs/blob/ea700a79534c8e8c22a9ac685135f15c31de91d3/crates/libduckdb-sys/build.rs#L203
|
||||
# Set to sentinel by default again
|
||||
# There is also a DUCKDB_LIB_DIR var, but I think only one needs to be set.
|
||||
export DUCKDB_DOWNLOAD_LIB="0"
|
||||
export DUCKDB_INCLUDE_DIR="${DUCKDB_INCLUDE_DIR:-"$sentinel_dir/duckdb/include"}"
|
||||
|
||||
# https://github.com/tikv/jemallocator/blob/a181911517adff5331e43dfd9804086f7c392a25/jemalloc-sys/build.rs#L132
|
||||
export JEMALLOC_OVERRIDE="${JEMALLOC_OVERRIDE:-"$sentinel_dir/lib/libjemalloc"}"
|
||||
}
|
||||
|
||||
# Cargo defaults to one job per host CPU. Limit builds that invoke Cargo
|
||||
# directly (e.g. through Meson or Make) to NIX_BUILD_CORES, like cargoBuildHook.
|
||||
# This runs in a phase because stdenv normalizes NIX_BUILD_CORES after
|
||||
# sourcing setup hooks.
|
||||
cargoSetupBuildJobs() {
|
||||
export CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-$NIX_BUILD_CORES}"
|
||||
}
|
||||
|
||||
postUnpackHooks+=(cargoSetupBuildJobs)
|
||||
|
||||
if [[ -z "${dontCargoUseSystemLibs-}" ]]; then
|
||||
preConfigureHooks+=(cargoUseSystemLibs)
|
||||
fi
|
||||
|
||||
if [ -z "${dontCargoSetupPostUnpack-}" ]; then
|
||||
postUnpackHooks+=(cargoSetupPostUnpackHook)
|
||||
fi
|
||||
|
||||
@@ -187,18 +187,13 @@ let
|
||||
let
|
||||
crateTarball = fetchCrate pkg registries.${registryIndexUrl};
|
||||
in
|
||||
runCommand "${pkg.name}-${pkg.version}"
|
||||
{
|
||||
strictDeps = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
''
|
||||
mkdir $out
|
||||
tar xf "${crateTarball}" -C $out --strip-components=1
|
||||
runCommand "${pkg.name}-${pkg.version}" { } ''
|
||||
mkdir $out
|
||||
tar xf "${crateTarball}" -C $out --strip-components=1
|
||||
|
||||
# Cargo is happy with largely empty metadata.
|
||||
printf '{"files":{},"package":"${crateTarball.outputHash}"}' > "$out/.cargo-checksum.json"
|
||||
''
|
||||
# Cargo is happy with largely empty metadata.
|
||||
printf '{"files":{},"package":"${crateTarball.outputHash}"}' > "$out/.cargo-checksum.json"
|
||||
''
|
||||
else if gitParts != null then
|
||||
let
|
||||
missingHash = throw ''
|
||||
@@ -229,71 +224,66 @@ let
|
||||
else
|
||||
missingHash;
|
||||
in
|
||||
runCommand "${pkg.name}-${pkg.version}"
|
||||
{
|
||||
strictDeps = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
''
|
||||
tree=${tree}
|
||||
runCommand "${pkg.name}-${pkg.version}" { } ''
|
||||
tree=${tree}
|
||||
|
||||
# If the target package is in a workspace, or if it's the top-level
|
||||
# crate, we should find the crate path using `cargo metadata`.
|
||||
# Some packages do not have a Cargo.toml at the top-level,
|
||||
# but only in nested directories.
|
||||
# Only check the top-level Cargo.toml, if it actually exists
|
||||
if [[ -f $tree/Cargo.toml ]]; then
|
||||
crateCargoTOML=$(cd "$tree" && ${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path $tree/Cargo.toml | \
|
||||
${jq}/bin/jq -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path')
|
||||
fi
|
||||
# If the target package is in a workspace, or if it's the top-level
|
||||
# crate, we should find the crate path using `cargo metadata`.
|
||||
# Some packages do not have a Cargo.toml at the top-level,
|
||||
# but only in nested directories.
|
||||
# Only check the top-level Cargo.toml, if it actually exists
|
||||
if [[ -f $tree/Cargo.toml ]]; then
|
||||
crateCargoTOML=$(${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path $tree/Cargo.toml | \
|
||||
${jq}/bin/jq -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path')
|
||||
fi
|
||||
|
||||
# If the repository is not a workspace the package might be in a subdirectory.
|
||||
if [[ -z $crateCargoTOML ]]; then
|
||||
for manifest in $(find $tree -name "Cargo.toml"); do
|
||||
echo Looking at $manifest
|
||||
crateCargoTOML=$(cd "$(dirname "$manifest")" && ${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path "$manifest" | ${jq}/bin/jq -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path' || :)
|
||||
if [[ ! -z $crateCargoTOML ]]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z $crateCargoTOML ]]; then
|
||||
>&2 echo "Cannot find path for crate '${pkg.name}-${pkg.version}' in the tree in: $tree"
|
||||
exit 1
|
||||
# If the repository is not a workspace the package might be in a subdirectory.
|
||||
if [[ -z $crateCargoTOML ]]; then
|
||||
for manifest in $(find $tree -name "Cargo.toml"); do
|
||||
echo Looking at $manifest
|
||||
crateCargoTOML=$(${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path "$manifest" | ${jq}/bin/jq -r '.packages[] | select(.name == "${pkg.name}") | .manifest_path' || :)
|
||||
if [[ ! -z $crateCargoTOML ]]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z $crateCargoTOML ]]; then
|
||||
>&2 echo "Cannot find path for crate '${pkg.name}-${pkg.version}' in the tree in: $tree"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo Found crate ${pkg.name} at $crateCargoTOML
|
||||
tree=$(dirname $crateCargoTOML)
|
||||
echo Found crate ${pkg.name} at $crateCargoTOML
|
||||
tree=$(dirname $crateCargoTOML)
|
||||
|
||||
cp -prvL "$tree" "$out" || echo "Warning: certain files couldn't be copied!" >&2
|
||||
chmod u+w $out
|
||||
cp -prvL "$tree" "$out" || echo "Warning: certain files couldn't be copied!" >&2
|
||||
chmod u+w $out
|
||||
|
||||
if grep -q workspace "$out/Cargo.toml"; then
|
||||
chmod u+w "$out/Cargo.toml"
|
||||
${replaceWorkspaceValues} "$out/Cargo.toml" "$(cd "$tree" && ${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path $crateCargoTOML | ${jq}/bin/jq -r .workspace_root)/Cargo.toml"
|
||||
fi
|
||||
if grep -q workspace "$out/Cargo.toml"; then
|
||||
chmod u+w "$out/Cargo.toml"
|
||||
${replaceWorkspaceValues} "$out/Cargo.toml" "$(${cargo}/bin/cargo metadata --format-version 1 --no-deps --manifest-path $crateCargoTOML | ${jq}/bin/jq -r .workspace_root)/Cargo.toml"
|
||||
fi
|
||||
|
||||
# Cargo is happy with empty metadata.
|
||||
printf '{"files":{},"package":null}' > "$out/.cargo-checksum.json"
|
||||
# Cargo is happy with empty metadata.
|
||||
printf '{"files":{},"package":null}' > "$out/.cargo-checksum.json"
|
||||
|
||||
${optionalString (gitParts ? type) ''
|
||||
gitPartsValue=${escapeShellArg gitParts.value}
|
||||
# starting with lockfile version v4 the git source url contains encoded query parameters
|
||||
# our regex parser does not know how to unescape them to get the actual value, so we do it here
|
||||
${optionalString (lockFileVersion >= 4) ''
|
||||
gitPartsValue=$(${getExe python3Packages.python} -c "import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1]))" "$gitPartsValue")
|
||||
''}
|
||||
${optionalString (gitParts ? type) ''
|
||||
gitPartsValue=${escapeShellArg gitParts.value}
|
||||
# starting with lockfile version v4 the git source url contains encoded query parameters
|
||||
# our regex parser does not know how to unescape them to get the actual value, so we do it here
|
||||
${optionalString (lockFileVersion >= 4) ''
|
||||
gitPartsValue=$(${getExe python3Packages.python} -c "import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1]))" "$gitPartsValue")
|
||||
''}
|
||||
''}
|
||||
|
||||
# Set up configuration for the vendor directory.
|
||||
cat > $out/.cargo-config <<EOF
|
||||
[source."${pkg.source}"]
|
||||
git = "${gitParts.url}"
|
||||
${optionalString (gitParts ? type) "${gitParts.type} = \"$gitPartsValue\""}
|
||||
replace-with = "vendored-sources"
|
||||
EOF
|
||||
''
|
||||
# Set up configuration for the vendor directory.
|
||||
cat > $out/.cargo-config <<EOF
|
||||
[source."${pkg.source}"]
|
||||
git = "${gitParts.url}"
|
||||
${optionalString (gitParts ? type) "${gitParts.type} = \"$gitPartsValue\""}
|
||||
replace-with = "vendored-sources"
|
||||
EOF
|
||||
''
|
||||
else
|
||||
throw "Cannot handle crate source: ${pkg.source}";
|
||||
|
||||
@@ -301,7 +291,6 @@ let
|
||||
runCommand "cargo-vendor-dir"
|
||||
(
|
||||
{
|
||||
strictDeps = true;
|
||||
__structuredAttrs = true;
|
||||
}
|
||||
// (
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{ callPackage }:
|
||||
{
|
||||
gitDependencyCargoConfig = callPackage ./git-dependency-cargo-config { };
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{ rustPlatform }:
|
||||
rustPlatform.fetchCargoVendor {
|
||||
name = "git-dependency-cargo-config";
|
||||
src = ../../import-cargo-lock/git-dependency-cargo-config;
|
||||
hash = "sha256-rUQQ4Xrk+rW5Vgm7GK8xrK9zcwazsmBO6Q6qTCUniWc=";
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
{ };
|
||||
gitDependencyTag = callPackage ./git-dependency-tag { };
|
||||
gitDependencyBranch = callPackage ./git-dependency-branch { };
|
||||
gitDependencyCargoConfig = callPackage ./git-dependency-cargo-config { };
|
||||
maturin = maturin.tests.pyo3;
|
||||
v1 = callPackage ./v1 { };
|
||||
gitDependencyWorkspaceInheritance = callPackage ./git-dependency-workspace-inheritance {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "fixture"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bootloader",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bootloader"
|
||||
version = "0.11.17"
|
||||
source = "git+https://github.com/rust-osdev/bootloader.git?rev=3d7f72e36d4101ecf78b70cef2475d700bb01721#3d7f72e36d4101ecf78b70cef2475d700bb01721"
|
||||
@@ -1,8 +0,0 @@
|
||||
{ rustPlatform }:
|
||||
rustPlatform.importCargoLock {
|
||||
lockFile = ./Cargo.lock;
|
||||
outputHashes = {
|
||||
# Bootloader's .cargo/config.toml enables bindeps, which are required to parse its manifest.
|
||||
"bootloader-0.11.17" = "sha256-mLm5M1HLipN1EzS1zbDgMxMOqNySivGsK8+i0uOmoFM=";
|
||||
};
|
||||
}
|
||||
@@ -33,8 +33,6 @@ assertExecutable() {
|
||||
|
||||
# --prefix ENV SEP VAL : suffix/prefix ENV with VAL, separated by SEP
|
||||
# --suffix
|
||||
# --prefix-unchecked ENV SEP VAL : same as --prefix/--suffix, accepted for compatibility
|
||||
# --suffix-unchecked with makeBinaryWrapper
|
||||
# --prefix-each ENV SEP VALS : like --prefix, but VALS is a list
|
||||
# --suffix-each ENV SEP VALS : like --suffix, but VALS is a list
|
||||
# --prefix-contents ENV SEP FILES : like --suffix-each, but contents of FILES
|
||||
@@ -147,7 +145,7 @@ makeShellWrapper() {
|
||||
command="${params[$((n + 1))]}"
|
||||
n=$((n + 1))
|
||||
echo "$command" >> "$wrapper"
|
||||
elif [[ ("$p" == "--suffix") || ("$p" == "--prefix") || ("$p" == "--suffix-unchecked") || ("$p" == "--prefix-unchecked") ]]; then
|
||||
elif [[ ("$p" == "--suffix") || ("$p" == "--prefix") ]]; then
|
||||
varName="${params[$((n + 1))]}"
|
||||
separator="${params[$((n + 2))]}"
|
||||
value="${params[$((n + 3))]}"
|
||||
|
||||
@@ -150,67 +150,6 @@ expandResponseParams() {
|
||||
done
|
||||
}
|
||||
|
||||
# Resolve the path $1 of a library directory, which like the linker
|
||||
# takes a relative path from the working directory, to the directory the
|
||||
# linker searches, as far as needed to tell whether it is in the store,
|
||||
# and where. Like the kernel, follow each symlink before going on to the
|
||||
# next component, so that symlinks in ancestor directories count, and `..`
|
||||
# applies to the target of a symlink rather than removing it. But in the
|
||||
# store, keep symlinks that are not followed by `..` as they are, since
|
||||
# resolving symlinks between store paths would refer to their targets
|
||||
# instead (see issue #454199). The result is stored in resolvedPath.
|
||||
# Fails if there are too many symlinks.
|
||||
resolveLibDir() {
|
||||
local rest="$1/" component link target links=0
|
||||
# The common case: a path in the store with no `.`, `..` or empty
|
||||
# components is already resolved, since it has no symlink to follow.
|
||||
if [[ "$1" == "${NIX_STORE:-}"/* && "$1/" != */./* && "$1/" != */../* && "$1/" != *//* ]]; then
|
||||
resolvedPath="$1"
|
||||
return
|
||||
fi
|
||||
if [[ "$rest" != /* ]]; then
|
||||
rest="$PWD/$rest"
|
||||
fi
|
||||
resolvedPath=
|
||||
while [[ -n "$rest" ]]; do
|
||||
component="${rest%%/*}"
|
||||
rest="${rest#*/}"
|
||||
case "$component" in
|
||||
"" | .) continue ;;
|
||||
..)
|
||||
if [[ -L "$resolvedPath" ]]; then
|
||||
# Follow it, then apply this `..` to its target.
|
||||
link="$resolvedPath"
|
||||
resolvedPath="${resolvedPath%/*}"
|
||||
rest="../$rest"
|
||||
else
|
||||
resolvedPath="${resolvedPath%/*}"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
link="$resolvedPath/$component"
|
||||
# Keep a symlink in the store unless `..` follows it, and
|
||||
# never resolve the store or its ancestors, which may be
|
||||
# symlinks (NIX_IGNORE_SYMLINK_STORE).
|
||||
if [[ "$link" == "${NIX_STORE:-}"/* || "${NIX_STORE:-}/" == "$link"/* || ! -L "$link" ]]; then
|
||||
resolvedPath="$link"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
(( ++links <= 40 )) || return 1
|
||||
target=$(readlink "$link") || return 1
|
||||
# A relative target is relative to the directory containing the
|
||||
# link, which is now resolvedPath.
|
||||
if [[ "$target" == /* ]]; then
|
||||
resolvedPath=
|
||||
fi
|
||||
rest="$target/$rest"
|
||||
done
|
||||
resolvedPath="${resolvedPath:-/}"
|
||||
}
|
||||
|
||||
checkLinkType() {
|
||||
local arg
|
||||
type="dynamic"
|
||||
|
||||
@@ -66,7 +66,7 @@ gccStdenv.mkDerivation (finalAttrs: {
|
||||
autoupdate
|
||||
'';
|
||||
|
||||
hardeningDisable = lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
hardeningDisable = lib.optionals (stdenv.hostPlatform.isAarch64 && stdenv.hostPlatform.isDarwin) [
|
||||
"stackprotector"
|
||||
];
|
||||
|
||||
|
||||
@@ -92,6 +92,6 @@ stdenv.mkDerivation {
|
||||
platforms = lib.platforms.unix;
|
||||
# needs additional work to support aarch64-darwin
|
||||
# due to usage of _DARWIN_NO_64_BIT_INODE
|
||||
broken = stdenv.hostPlatform.isDarwin;
|
||||
broken = stdenv.hostPlatform.isAarch64 && stdenv.hostPlatform.isDarwin;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
cmake,
|
||||
fixDarwinDylibNames,
|
||||
gtest,
|
||||
static ? stdenv.hostPlatform.isStatic,
|
||||
cxxStandard ? null,
|
||||
@@ -23,8 +22,6 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
outputs = [
|
||||
"out"
|
||||
"dev"
|
||||
# Test helper libraries linking against GoogleTest
|
||||
"testing"
|
||||
];
|
||||
|
||||
cmakeFlags = [
|
||||
@@ -38,22 +35,10 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
nativeBuildInputs = [ cmake ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ fixDarwinDylibNames ];
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
||||
buildInputs = [ gtest ];
|
||||
|
||||
postInstall = ''
|
||||
for lib in scoped_mock_log status_matchers; do
|
||||
moveToOutput "lib/libabsl_$lib.*" "$testing"
|
||||
substituteInPlace $out/lib/cmake/absl/abslTargets-*.cmake \
|
||||
--replace-fail "$out/lib/libabsl_$lib." "$testing/lib/libabsl_$lib."
|
||||
substituteInPlace "$out/lib/pkgconfig/absl_$lib.pc" \
|
||||
--replace-fail "libdir=$out/lib" "libdir=$testing/lib"
|
||||
done
|
||||
'';
|
||||
|
||||
outputChecks.out.disallowedRequisites = [ gtest ];
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
meta = {
|
||||
|
||||
@@ -17,6 +17,8 @@ python3Packages.buildPythonApplication {
|
||||
hash = "sha256-s9kegTZOZEgGx0Yj8jOfzAyjyy1EuabOybMDBoodRvo=";
|
||||
};
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
build-system = with python3Packages; [
|
||||
setuptools
|
||||
];
|
||||
|
||||
@@ -45,7 +45,9 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
# ACPICA emits packed structs that produce unaligned pointers. Apple's
|
||||
# arm64 linker rejects these under chained fixups; opt back into the
|
||||
# legacy fixup format so the link succeeds.
|
||||
NIX_LDFLAGS = lib.optionalString stdenv.hostPlatform.isDarwin "-no_fixup_chains";
|
||||
NIX_LDFLAGS = lib.optionalString (
|
||||
stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64
|
||||
) "-no_fixup_chains";
|
||||
|
||||
# i686 builds fail with hardening enabled (due to -Wformat-overflow). Disable
|
||||
# -Werror altogether to make this derivation less fragile to toolchain
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
lib,
|
||||
rustPlatform,
|
||||
fetchFromGitHub,
|
||||
pkg-config,
|
||||
aws-lc,
|
||||
}:
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
@@ -20,14 +18,6 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
|
||||
cargoHash = "sha256-uch2JKnskO5W8EPK877qL0aQQ+iInHJoCrrhZbmoVRs=";
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkg-config
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
aws-lc
|
||||
];
|
||||
|
||||
meta = {
|
||||
description = "Terminal-based, real-time traffic monitoring and statistics for your AdGuard Home instance";
|
||||
mainProgram = "adguardian";
|
||||
|
||||
@@ -10,6 +10,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "1.2.0";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "NetSPI";
|
||||
repo = "AD-PathFinder";
|
||||
|
||||
@@ -10,6 +10,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "13.2.0";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "ADScanPro";
|
||||
repo = "adscan";
|
||||
|
||||
@@ -16,9 +16,9 @@ let
|
||||
case "$1 $2" in
|
||||
"config var")
|
||||
case "$3" in
|
||||
man) echo "''${man:-$out}/share/man";;
|
||||
man) echo "$out/share/man";;
|
||||
etc) echo "$out/etc";;
|
||||
doc) echo "''${doc:-$out}/share/doc";;
|
||||
doc) echo "$out/share/doc";;
|
||||
share) echo "$out/share";;
|
||||
prefix) echo "$out";;
|
||||
*) echo "fake-opam does not understand arguments: $@" ; exit 1 ;;
|
||||
@@ -46,7 +46,7 @@ ocamlPackages.buildDunePackage rec {
|
||||
postPatch = ''
|
||||
substituteInPlace ./Makefile \
|
||||
--replace "\$(DUNE) install \$(DUNEROOT) --display=short" \
|
||||
"\$(DUNE) install \$(DUNEROOT) --prefix $out --docdir ''${!outputDoc}/share/doc --mandir ''${!outputMan}/share/man"
|
||||
"\$(DUNE) install \$(DUNEROOT) --prefix $out --docdir $out/share/doc --mandir $out/share/man"
|
||||
substituteInPlace ./src/discover.sh \
|
||||
--replace 'gs_path=$(which gs)' 'gs_path=${ghostscriptX}/bin/gs'
|
||||
'';
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
stdenvNoCC.mkDerivation (finalAttrs: {
|
||||
pname = "adwaita-fonts";
|
||||
version = "51.0";
|
||||
version = "50.0";
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://gnome/sources/adwaita-fonts/${lib.versions.major finalAttrs.version}/adwaita-fonts-${finalAttrs.version}.tar.xz";
|
||||
hash = "sha256-+hBK4sG5ZYDTIvVj/+iy38pSlrDspJce/S2AEUBRI9I=";
|
||||
hash = "sha256-TJJ/v+7BxQOAG6UQwslOAFTILFIs97oNO+XU1B/PXIY=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "adwaita-icon-theme";
|
||||
version = "51.0";
|
||||
version = "50.0";
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://gnome/sources/adwaita-icon-theme/${lib.versions.major finalAttrs.version}/adwaita-icon-theme-${finalAttrs.version}.tar.xz";
|
||||
hash = "sha256-ulYc88ljBaRxefpWBYVq1pXJI46gf3CTrr2bqAxOMjs=";
|
||||
hash = "sha256-+sbgQB/KcUeAVhoIG49+J8O8HbNOvaTaF1CB8msk1GA=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
||||
@@ -25,6 +25,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
python3Packages.sphinxHook
|
||||
];
|
||||
|
||||
sphinxRoot = "docs";
|
||||
sphinxBuilders = [
|
||||
"html"
|
||||
"man"
|
||||
@@ -58,6 +59,12 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
"man"
|
||||
];
|
||||
|
||||
# Workaround for upstream packaging paths, can be removed once #573479 is resolved
|
||||
postInstall = ''
|
||||
sphinx-build -b man docs docs/build/man
|
||||
install -Dm644 docs/build/man/*.1 -t $man/share/man/man1/
|
||||
'';
|
||||
|
||||
meta = {
|
||||
homepage = "https://github.com/afewmail/afew";
|
||||
description = "Initial tagging script for notmuch mail";
|
||||
|
||||
@@ -11,6 +11,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "1.7.0";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "agentsploit";
|
||||
repo = "agentsploit";
|
||||
@@ -50,7 +52,6 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
|
||||
disabledTestPaths = [
|
||||
# Tests need network access
|
||||
"tests/unit/test_openai_adapter.py"
|
||||
"tests/integration/"
|
||||
];
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
fetchFromGitHub,
|
||||
cmake,
|
||||
llvmPackages,
|
||||
sqlite,
|
||||
}:
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
@@ -31,8 +30,6 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
rustPlatform.bindgenHook
|
||||
];
|
||||
|
||||
buildInputs = [ sqlite ];
|
||||
|
||||
# Add CFLAGS to suppress the stringop-overflow error during aws-lc-sys compilation.
|
||||
NIX_CFLAGS_COMPILE = "-Wno-error=stringop-overflow";
|
||||
|
||||
|
||||
@@ -397,6 +397,8 @@ buildPythonPackage (
|
||||
pname = "apache-airflow";
|
||||
version = "3.3.2";
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "apache";
|
||||
repo = "airflow";
|
||||
|
||||
@@ -10,6 +10,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "0.35.0";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "microsoft";
|
||||
repo = "apm";
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
lib,
|
||||
fetchFromGitHub,
|
||||
rustPlatform,
|
||||
pkg-config,
|
||||
aws-lc,
|
||||
}:
|
||||
|
||||
rustPlatform.buildRustPackage (finalAttrs: {
|
||||
pname = "apt-swarm";
|
||||
version = "0.6.1";
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "kpcyrd";
|
||||
repo = "apt-swarm";
|
||||
@@ -21,10 +17,6 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
|
||||
cargoHash = "sha256-Fo/+UbdfDhbAsoWjoko4tAmyDZK6tPn/0d2CjPKyaaQ=";
|
||||
|
||||
nativeBuildInputs = [ pkg-config ];
|
||||
|
||||
buildInputs = [ aws-lc ];
|
||||
|
||||
meta = {
|
||||
description = "Experimental p2p gossip network for OpenPGP signature transparency";
|
||||
homepage = "https://github.com/kpcyrd/apt-swarm";
|
||||
|
||||
@@ -9,6 +9,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
pname = "aqtinstall";
|
||||
version = "3.3.0";
|
||||
pyproject = true;
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "miurahr";
|
||||
|
||||
@@ -172,6 +172,10 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
"TestS3FS.*"
|
||||
"TestS3FSGeneric.*"
|
||||
"TestS3FSHTTPS.*" # Needs Minio
|
||||
]
|
||||
++ lib.optionals (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isx86_64) [
|
||||
# https://github.com/apache/arrow/issues/41505
|
||||
"TestAzuriteGeneric.Empty"
|
||||
];
|
||||
in
|
||||
"-${lib.concatStringsSep ":" filteredTests}";
|
||||
@@ -348,6 +352,8 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
__structuredAttrs = true;
|
||||
|
||||
meta = {
|
||||
# https://hydra.nixos.org/job/nixpkgs/unstable/arrow-cpp.x86_64-darwin/all
|
||||
broken = stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isx86_64;
|
||||
description = "Cross-language development platform for in-memory data";
|
||||
homepage = "https://arrow.apache.org/docs/cpp/";
|
||||
changelog = "https://arrow.apache.org/release/${finalAttrs.version}.html";
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
pkg-config,
|
||||
sqlite,
|
||||
openssl,
|
||||
zstd,
|
||||
versionCheckHook,
|
||||
nix-update-script,
|
||||
nixosTests,
|
||||
@@ -37,13 +36,9 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
buildAndTestSubdir = "crates/arti";
|
||||
cargoHash = "sha256-g+t5X1t0koUzqoHpY8+lncqRobdDuZggXtD3HRk9ryE=";
|
||||
|
||||
nativeBuildInputs = [ pkg-config ];
|
||||
nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ pkg-config ];
|
||||
|
||||
buildInputs = [
|
||||
sqlite
|
||||
zstd
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [ openssl ];
|
||||
buildInputs = [ sqlite ] ++ lib.optionals stdenv.hostPlatform.isLinux [ openssl ];
|
||||
|
||||
# `full` includes all stable and non-conflicting feature flags. the primary
|
||||
# downsides are increased binary size and memory usage for building, but
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
autoreconfHook,
|
||||
installShellFiles,
|
||||
enableStandardFeatures ? false,
|
||||
source-highlight,
|
||||
sourceHighlight,
|
||||
highlight,
|
||||
graphviz,
|
||||
texliveMinimal,
|
||||
@@ -246,7 +246,7 @@ python3.pkgs.buildPythonApplication (finalAttrs: {
|
||||
-e "s|run('convert|run('${lib.getExe' imagemagick "convert"}|g" \
|
||||
-i "asciidoc/resources/filters/music/music2png.py"
|
||||
|
||||
sed -e 's|filter="source-highlight|filter="${source-highlight}/bin/source-highlight|' \
|
||||
sed -e 's|filter="source-highlight|filter="${sourceHighlight}/bin/source-highlight|' \
|
||||
-e 's|filter="highlight|filter="${highlight}/bin/highlight|' \
|
||||
-e 's|filter="pygmentize|filter="${pygments}/bin/pygmentize|' \
|
||||
-i "asciidoc/resources/filters/source/source-highlight-filter.conf"
|
||||
@@ -283,10 +283,10 @@ python3.pkgs.buildPythonApplication (finalAttrs: {
|
||||
)
|
||||
+ ''
|
||||
# Fix tests
|
||||
substituteInPlace $(grep -R --files-with-matches "2002-11-25" tests/data) \
|
||||
--replace-fail "2002-11-25" "1980-01-02"
|
||||
substituteInPlace $(grep -R --files-with-matches "00:37:42" tests/data) \
|
||||
--replace-fail "00:37:42" "00:00:00"
|
||||
for f in $(grep -R --files-with-matches "2002-11-25") ; do
|
||||
substituteInPlace $f --replace "2002-11-25" "1980-01-02"
|
||||
substituteInPlace $f --replace "00:37:42" "00:00:00"
|
||||
done
|
||||
''
|
||||
+ lib.optionalString (stdenv.buildPlatform != stdenv.hostPlatform) ''
|
||||
# We want to use asciidoc from the build platform to build the documentation.
|
||||
@@ -317,6 +317,8 @@ python3.pkgs.buildPythonApplication (finalAttrs: {
|
||||
runHook postCheck
|
||||
'';
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
meta = {
|
||||
description = "Text-based document generation system";
|
||||
longDescription = ''
|
||||
|
||||
@@ -10,6 +10,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "1.2.7";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchPypi {
|
||||
inherit (finalAttrs) pname version;
|
||||
hash = "sha256-SqwViOnVx1TcpY8Kd5VQCg1A8KQnBhL8aq9Gsrwer3k=";
|
||||
|
||||
@@ -32,7 +32,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
lib.optionalString (!buildDocs) ''
|
||||
substituteInPlace Makefile --replace "all: binaries docs" "all: binaries"
|
||||
''
|
||||
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
|
||||
+ lib.optionalString (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) ''
|
||||
substituteInPlace sysdefs.h --replace "x86_64" "aarch64"
|
||||
'';
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "at-spi2-core";
|
||||
version = "2.62.0";
|
||||
version = "2.60.6";
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
@@ -39,7 +39,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
|
||||
src = fetchurl {
|
||||
url = "mirror://gnome/sources/at-spi2-core/${lib.versions.majorMinor finalAttrs.version}/at-spi2-core-${finalAttrs.version}.tar.xz";
|
||||
hash = "sha256-A6lPe/NfMA2vKEOjfN82R5qRvFP1mo6kN8eeJdldHeM=";
|
||||
hash = "sha256-qJtkqLIXqAQr3w41y/q2Kc7uNWQNunXfV4r96ap4nVc=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
nixVersions,
|
||||
nixosTests,
|
||||
boost,
|
||||
sqlite,
|
||||
zstd,
|
||||
pkg-config,
|
||||
stdenv,
|
||||
installShellFiles,
|
||||
@@ -39,14 +37,7 @@ rustPlatform.buildRustPackage {
|
||||
installShellFiles
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
boost
|
||||
]
|
||||
++ lib.optionals needNixInclude [ nix ]
|
||||
++ lib.optionals (lib.elem "attic-server" crates) [
|
||||
sqlite
|
||||
zstd
|
||||
];
|
||||
buildInputs = lib.optional needNixInclude nix ++ [ boost ];
|
||||
|
||||
cargoBuildFlags = map (c: "--package=${c}") crates;
|
||||
cargoHash = "sha256-UGgM78QEWJ2QgbQhxEI+yLYXH6T4ey+1oenPTMlJ3GU=";
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
which,
|
||||
pkg-config,
|
||||
perl,
|
||||
guile,
|
||||
guile_2_2,
|
||||
libxml2,
|
||||
}:
|
||||
|
||||
@@ -101,7 +101,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
buildPackages.texinfo
|
||||
];
|
||||
buildInputs = [
|
||||
guile
|
||||
guile_2_2
|
||||
libxml2
|
||||
];
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ let
|
||||
pname = "fernet_key";
|
||||
inherit version src;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
format = "other";
|
||||
|
||||
# this would run the upstream docker makefile
|
||||
|
||||
@@ -51,7 +51,7 @@ buildDotnetModule rec {
|
||||
bintools
|
||||
fixDarwinDylibNames
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
++ lib.optionals (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) [
|
||||
autoSignDarwinBinariesHook
|
||||
];
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
pname = "aw-watcher-steam";
|
||||
version = "0-unstable-2025-06-16";
|
||||
pyproject = true;
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "Edwardsoen";
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
diff --git i/crypto/CMakeLists.txt w/crypto/CMakeLists.txt
|
||||
index 7bac21b..da56759 100644
|
||||
--- i/crypto/CMakeLists.txt
|
||||
+++ w/crypto/CMakeLists.txt
|
||||
@@ -895,20 +895,23 @@ if(BUILD_TESTING)
|
||||
add_dependencies(${DYNAMIC_LOADING_TEST_EXEC} crypto)
|
||||
set_test_location(${DYNAMIC_LOADING_TEST_EXEC})
|
||||
|
||||
set(DYNAMIC_LINKER_LIB "")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR APPLE OR ANDROID)
|
||||
set(DYNAMIC_LINKER_LIB "dl")
|
||||
endif()
|
||||
|
||||
if (BUILD_SHARED_LIBS AND NOT WIN32)
|
||||
target_compile_options(${DYNAMIC_LOADING_TEST_EXEC} PUBLIC "-DLIBCRYPTO_PATH=\"$<TARGET_FILE:crypto>\"")
|
||||
+ if(BORINGSSL_PREFIX)
|
||||
+ target_compile_options(${DYNAMIC_LOADING_TEST_EXEC} PUBLIC "-DSYMBOL_PREFIX=\"${BORINGSSL_PREFIX}_\"")
|
||||
+ endif()
|
||||
# Do not link to boringssl_gtest_main or any library that might be linked to libcrypto.so.
|
||||
if(ANDROID)
|
||||
target_link_libraries(${DYNAMIC_LOADING_TEST_EXEC} PUBLIC boringssl_gtest ${DYNAMIC_LINKER_LIB})
|
||||
else()
|
||||
target_link_libraries(${DYNAMIC_LOADING_TEST_EXEC} PUBLIC boringssl_gtest pthread ${DYNAMIC_LINKER_LIB})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_dependencies(all_tests ${DYNAMIC_LOADING_TEST_EXEC})
|
||||
|
||||
diff --git i/crypto/dynamic_loading_test.c w/crypto/dynamic_loading_test.c
|
||||
index 4c37c28..88002dc 100644
|
||||
--- i/crypto/dynamic_loading_test.c
|
||||
+++ w/crypto/dynamic_loading_test.c
|
||||
@@ -20,53 +20,57 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef LIBCRYPTO_PATH
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
+#ifndef SYMBOL_PREFIX
|
||||
+#define SYMBOL_PREFIX ""
|
||||
+#endif
|
||||
+
|
||||
typedef void (*fp_lc_clear_error_t)(void);
|
||||
typedef int (*fp_lc_tl_func_t)(void);
|
||||
typedef int (*fp_rand_bytes_t)(uint8_t *buf, size_t len);
|
||||
|
||||
#define BUFFER_SIZE 16
|
||||
#define TEST_ITERS 10
|
||||
#define THREAD_COUNT 10
|
||||
|
||||
static void *cycle_thread_local_setup(void *lc_so) {
|
||||
uint8_t buffer[BUFFER_SIZE];
|
||||
- fp_lc_clear_error_t lc_clear_error = dlsym(lc_so, "ERR_clear_error");
|
||||
- fp_rand_bytes_t lc_rand_bytes = dlsym(lc_so, "RAND_bytes");
|
||||
- fp_lc_tl_func_t lc_tl_clear = dlsym(lc_so, "AWSLC_thread_local_clear");
|
||||
+ fp_lc_clear_error_t lc_clear_error = dlsym(lc_so, SYMBOL_PREFIX "ERR_clear_error");
|
||||
+ fp_rand_bytes_t lc_rand_bytes = dlsym(lc_so, SYMBOL_PREFIX "RAND_bytes");
|
||||
+ fp_lc_tl_func_t lc_tl_clear = dlsym(lc_so, SYMBOL_PREFIX "AWSLC_thread_local_clear");
|
||||
|
||||
for (int i = 0; i < TEST_ITERS; i++) {
|
||||
(*lc_clear_error)();
|
||||
if (1 != (*lc_rand_bytes)(buffer, BUFFER_SIZE)) {
|
||||
fprintf(stderr, "Call to RAND_bytes failed.");
|
||||
exit(1);
|
||||
}
|
||||
if (1 != (*lc_tl_clear)()) {
|
||||
fprintf(stderr, "Call to AWSLC_thread_local_clear failed.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *load_unload(void *ctx) {
|
||||
const char* path = ctx;
|
||||
void *lc_so = dlopen(path, RTLD_NOW);
|
||||
- fp_lc_tl_func_t lc_tl_shutdown = dlsym(lc_so, "AWSLC_thread_local_shutdown");
|
||||
+ fp_lc_tl_func_t lc_tl_shutdown = dlsym(lc_so, SYMBOL_PREFIX "AWSLC_thread_local_shutdown");
|
||||
|
||||
pthread_t thread_id[THREAD_COUNT];
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
if (pthread_create(&thread_id[i], NULL, cycle_thread_local_setup, lc_so)) {
|
||||
fprintf(stderr, "Call to pthread_create in load_unload failed.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Also cycle on the current thread
|
||||
@@ -1,50 +0,0 @@
|
||||
Commit ID: eaef466931b704cbded48be8c51f7a8fa75ca6e0
|
||||
Change ID: yxsyyzwrzkrtqvksxqsurozmktvqsssw
|
||||
Author : Marie Ramlow <marie@marie.cologne> (2026-11-01 13:28:50)
|
||||
Committer: Marie Ramlow <marie@marie.cologne> (2026-11-01 13:29:10)
|
||||
|
||||
Fix OpenSSL-compat shim symlinks
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index aa64e1aa22..005dc11c58 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -1844,12 +1844,12 @@
|
||||
endif()
|
||||
install(CODE "
|
||||
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
|
||||
- lib${CRYPTO_LIB_NAME}.${SHIM_LIB_EXT} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libcrypto.${SHIM_LIB_EXT}\")
|
||||
+ lib${CRYPTO_LIB_NAME}.${SHIM_LIB_EXT} \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_LIBDIR}/libcrypto.${SHIM_LIB_EXT}\")
|
||||
" ${SHIM_LINK_COMPONENT})
|
||||
if(BUILD_LIBSSL)
|
||||
install(CODE "
|
||||
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
|
||||
- lib${SSL_LIB_NAME}.${SHIM_LIB_EXT} \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/libssl.${SHIM_LIB_EXT}\")
|
||||
+ lib${SSL_LIB_NAME}.${SHIM_LIB_EXT} \"\$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_LIBDIR}/libssl.${SHIM_LIB_EXT}\")
|
||||
" ${SHIM_LINK_COMPONENT})
|
||||
endif()
|
||||
endif()
|
||||
@@ -1858,7 +1858,7 @@
|
||||
# Always create the include directory symlink for OpenSSL compatibility
|
||||
install(CODE "
|
||||
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
|
||||
- aws-lc/openssl \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/openssl\")
|
||||
+ aws-lc/openssl \"\$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_INCLUDEDIR}/openssl\")
|
||||
" COMPONENT Development)
|
||||
endif()
|
||||
endif()
|
||||
diff --git a/tool-openssl/CMakeLists.txt b/tool-openssl/CMakeLists.txt
|
||||
index 262b42aa00..6f16cfa198 100644
|
||||
--- a/tool-openssl/CMakeLists.txt
|
||||
+++ b/tool-openssl/CMakeLists.txt
|
||||
@@ -191,8 +191,8 @@
|
||||
if(INSTALL_OPENSSL_SHIM AND COHABITANT_BINARIES)
|
||||
install(CODE "
|
||||
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
|
||||
- \"${AWSLC_BIN_PREFIX}openssl\" \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/openssl\")
|
||||
+ \"${AWSLC_BIN_PREFIX}openssl\" \"\$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_BINDIR}/openssl\")
|
||||
execute_process(COMMAND \${CMAKE_COMMAND} -E create_symlink
|
||||
- \"${AWSLC_BIN_PREFIX}c_rehash\" \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/c_rehash\")
|
||||
+ \"${AWSLC_BIN_PREFIX}c_rehash\" \"\$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_BINDIR}/c_rehash\")
|
||||
")
|
||||
endif()
|
||||
@@ -2,58 +2,18 @@
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
buildGoModule,
|
||||
cmake,
|
||||
ninja,
|
||||
go,
|
||||
perl,
|
||||
rust-bindgen,
|
||||
testers,
|
||||
nix-update-script,
|
||||
aws-lc,
|
||||
writableTmpDirAsHomeHook,
|
||||
runCommand,
|
||||
useSharedLibraries ? !stdenv.hostPlatform.isStatic,
|
||||
withRustBindings ? true,
|
||||
symbolPrefix ? "AWS_LC",
|
||||
# This option might lead to OpenSSL being silently swapped to AWS-LC. Only use it if you know what you are doing.
|
||||
withOpenSSLShim ? false,
|
||||
}:
|
||||
|
||||
let
|
||||
aws-lc' = aws-lc.override {
|
||||
useSharedLibraries = false;
|
||||
symbolPrefix = null;
|
||||
};
|
||||
symbols =
|
||||
runCommand "aws-lc-symbols"
|
||||
{
|
||||
inherit (aws-lc) src;
|
||||
nativeBuildInputs = [
|
||||
writableTmpDirAsHomeHook
|
||||
go
|
||||
];
|
||||
}
|
||||
''
|
||||
cd "$src"
|
||||
go run ./util/read_symbols.go -out "$TMPDIR/symbols_crypto.txt" ${aws-lc'}/lib/libcrypto-awslc.a
|
||||
go run ./util/read_symbols.go -out "$TMPDIR/symbols_ssl.txt" ${aws-lc'}/lib/libssl-awslc.a
|
||||
cat "$TMPDIR"/symbols_{crypto,ssl}.txt > $out
|
||||
'';
|
||||
in
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "aws-lc";
|
||||
version = "5.12.0";
|
||||
|
||||
patches = [
|
||||
./fix-dynamic-loading-test.patch
|
||||
./fix-openssl-shim-symlinks.patch
|
||||
];
|
||||
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "aws";
|
||||
repo = "aws-lc";
|
||||
@@ -68,51 +28,26 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
writableTmpDirAsHomeHook
|
||||
cmake
|
||||
ninja
|
||||
go
|
||||
perl
|
||||
]
|
||||
++ lib.optionals withRustBindings [
|
||||
rust-bindgen
|
||||
];
|
||||
|
||||
goDeps =
|
||||
(buildGoModule {
|
||||
inherit (finalAttrs) pname version src;
|
||||
vendorHash = "sha256-495bUr3Cuo7kuhuNLMVhrVg9NXTAXyFmnXRmBrCHovA=";
|
||||
}).goModules;
|
||||
|
||||
# it seems that ENABLE_DIST_PKG rejects apple because of symbol versioning,
|
||||
# but we disable symbol versioning ourselves.
|
||||
postPatch = ''
|
||||
substituteInPlace CMakeLists.txt \
|
||||
--replace-fail "if(NOT UNIX OR APPLE)" "if(NOT UNIX)"
|
||||
'';
|
||||
|
||||
preConfigure = ''
|
||||
ln -s ${finalAttrs.goDeps} vendor
|
||||
'';
|
||||
|
||||
cmakeFlags = [
|
||||
(lib.cmakeBool "BUILD_SHARED_LIBS" useSharedLibraries)
|
||||
(lib.cmakeBool "DISABLE_GO" true)
|
||||
(lib.cmakeBool "DISABLE_PERL" true)
|
||||
(lib.cmakeBool "GENERATE_RUST_BINDINGS" withRustBindings)
|
||||
(lib.cmakeBool "ENABLE_DIST_PKG" true)
|
||||
(lib.cmakeBool "ENABLE_DIST_PKG_OPENSSL_SHIM" withOpenSSLShim)
|
||||
(lib.cmakeBool "ENABLE_SYMBOL_VERSIONING" false)
|
||||
]
|
||||
++ lib.optionals stdenv.cc.isGNU [
|
||||
# Needed with gcc but breaks with clang
|
||||
(lib.cmakeFeature "CMAKE_C_FLAGS" "-Wno-error=stringop-overflow")
|
||||
]
|
||||
++ lib.optionals (symbolPrefix != null) [
|
||||
(lib.cmakeFeature "BORINGSSL_PREFIX" symbolPrefix)
|
||||
(lib.cmakeFeature "BORINGSSL_PREFIX_SYMBOLS" (toString symbols))
|
||||
];
|
||||
|
||||
doCheck = true;
|
||||
checkTarget = "run_tests";
|
||||
checkTarget = "run_minimal_tests";
|
||||
|
||||
postInstall = ''
|
||||
moveToOutput lib/crypto/cmake "$dev"
|
||||
@@ -142,7 +77,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
tests = {
|
||||
version = testers.testVersion {
|
||||
package = finalAttrs.finalPackage;
|
||||
command = "aws-lc-bssl version";
|
||||
command = "bssl version";
|
||||
};
|
||||
pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
|
||||
};
|
||||
@@ -162,14 +97,15 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
asl20
|
||||
isc
|
||||
];
|
||||
mainProgram = "aws-lc-bssl";
|
||||
mainProgram = "bssl";
|
||||
maintainers = with lib.maintainers; [
|
||||
whispersofthedawn
|
||||
];
|
||||
pkgConfigModules = [
|
||||
"aws-lc"
|
||||
"libcrypto-awslc"
|
||||
"libssl-awslc"
|
||||
"libcrypto"
|
||||
"libssl"
|
||||
"openssl"
|
||||
];
|
||||
platforms = lib.platforms.unix;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
pname = "awscurl";
|
||||
version = "0.44";
|
||||
pyproject = true;
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "okigan";
|
||||
|
||||
@@ -10,6 +10,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "1.5.0";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "TacoRocket";
|
||||
repo = "AzureFox";
|
||||
|
||||
@@ -32,10 +32,6 @@ buildNpmPackage (finalAttrs: {
|
||||
libsecret
|
||||
];
|
||||
|
||||
# @vscode/vsce-sign's postinstall script fails on exotic architectures.
|
||||
# We ignore the scripts, and this does not change the output.
|
||||
npmFlags = [ "--ignore-scripts" ];
|
||||
|
||||
meta = {
|
||||
description = "Lightweight server clone of Azure Storage that simulates most of the commands supported by it with minimal dependencies";
|
||||
homepage = "https://github.com/Azure/Azurite";
|
||||
|
||||
@@ -12,6 +12,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
pname = "babeldoc";
|
||||
version = "0.6.4";
|
||||
pyproject = true;
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "funstory-ai";
|
||||
|
||||
@@ -9,6 +9,8 @@ python3.pkgs.buildPythonApplication (finalAttrs: {
|
||||
version = "0.8.0";
|
||||
pyproject = true;
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "meeb";
|
||||
repo = "bandcampsync";
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
less,
|
||||
installShellFiles,
|
||||
makeWrapper,
|
||||
oniguruma,
|
||||
libgit2,
|
||||
zlib,
|
||||
versionCheckHook,
|
||||
@@ -36,7 +35,6 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
oniguruma
|
||||
libgit2
|
||||
zlib
|
||||
];
|
||||
|
||||
@@ -28,7 +28,7 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
license = lib.licenses.asl20;
|
||||
mainProgram = "batmon";
|
||||
platforms = with lib.platforms; unix ++ windows;
|
||||
broken = stdenv.hostPlatform.isDarwin;
|
||||
broken = stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64;
|
||||
maintainers = with lib.maintainers; [ _6543 ];
|
||||
};
|
||||
})
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitLab,
|
||||
fetchFromGitHub,
|
||||
blueprint-compiler,
|
||||
desktop-file-utils,
|
||||
dbus,
|
||||
meson,
|
||||
python3,
|
||||
ninja,
|
||||
pkg-config,
|
||||
vala,
|
||||
wrapGAppsHook4,
|
||||
appstream,
|
||||
flatpak,
|
||||
@@ -31,13 +29,12 @@
|
||||
md4c,
|
||||
webkitgtk_6_0,
|
||||
libsecret,
|
||||
systemdLibs,
|
||||
nix-update-script,
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "bazaar";
|
||||
version = "0.9.9";
|
||||
version = "0.9.1";
|
||||
|
||||
__structuredAttrs = true;
|
||||
strictDeps = true;
|
||||
@@ -49,12 +46,11 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
"dev"
|
||||
];
|
||||
|
||||
src = fetchFromGitLab {
|
||||
domain = "gitlab.gnome.org";
|
||||
owner = "World";
|
||||
src = fetchFromGitHub {
|
||||
owner = "bazaar-org";
|
||||
repo = "bazaar";
|
||||
tag = "v${finalAttrs.version}";
|
||||
hash = "sha256-qmMwlvB8DXNP0SHip1mQoktYFeH/DwfvVtVIny16Ryo=";
|
||||
hash = "sha256-9J+XI5JnV8Yfk3xRI/VM5RSG4eMafbw2rBRpPMIu5yA=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
@@ -64,7 +60,6 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
vala
|
||||
wrapGAppsHook4
|
||||
(python3.withPackages (p: [
|
||||
p.babel
|
||||
@@ -74,7 +69,6 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
|
||||
buildInputs = [
|
||||
appstream
|
||||
dbus
|
||||
flatpak
|
||||
glib-networking
|
||||
gtk4
|
||||
@@ -93,7 +87,6 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
md4c
|
||||
webkitgtk_6_0
|
||||
libsecret
|
||||
systemdLibs
|
||||
];
|
||||
|
||||
postInstall = ''
|
||||
@@ -119,7 +112,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
|
||||
meta = {
|
||||
description = "FlatHub-first app store for GNOME";
|
||||
homepage = "https://gitlab.gnome.org/World/bazaar";
|
||||
homepage = "https://github.com/kolunmi/bazaar";
|
||||
license = lib.licenses.gpl3Plus;
|
||||
maintainers = with lib.maintainers; [
|
||||
dtomvan
|
||||
|
||||
@@ -31,6 +31,7 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
webrtcvad
|
||||
];
|
||||
|
||||
__structuredAttrs = true;
|
||||
dontBuild = true;
|
||||
dontWrapPythonPrograms = true;
|
||||
pyproject = false;
|
||||
|
||||
@@ -118,6 +118,11 @@ let
|
||||
url = "https://github.com/bazelbuild/bazel/releases/download/${version}/bazel_nojdk-${version}-linux-arm64";
|
||||
hash = "sha256-wfuZLSHa77wr0A4ZLF5DqH7qyOljYNXM2a5imoS+nGQ";
|
||||
}
|
||||
else if stdenv.hostPlatform.system == "x86_64-darwin" then
|
||||
fetchurl {
|
||||
url = "https://github.com/bazelbuild/bazel/releases/download/${version}/bazel-${version}-darwin-x86_64";
|
||||
hash = "sha256-qAb9s6R5+EbqVfWHUT7sk1sOrbDEPv4EhgXH7nC46Zw=";
|
||||
}
|
||||
else
|
||||
fetchurl {
|
||||
# stdenv.hostPlatform.system == "aarch64-darwin"
|
||||
@@ -279,12 +284,12 @@ let
|
||||
|
||||
platforms = lib.platforms.linux ++ lib.platforms.darwin;
|
||||
|
||||
inherit (stdenv.hostPlatform) isDarwin;
|
||||
inherit (stdenv.hostPlatform) isDarwin isAarch64;
|
||||
|
||||
system = if isDarwin then "darwin" else "linux";
|
||||
|
||||
# on aarch64 Darwin, `uname -m` returns "arm64"
|
||||
arch = if isDarwin then stdenv.hostPlatform.darwinArch else stdenv.hostPlatform.parsed.cpu.name;
|
||||
arch = with stdenv.hostPlatform; if isDarwin && isAarch64 then "arm64" else parsed.cpu.name;
|
||||
|
||||
bazelRC = writeTextFile {
|
||||
name = "bazel-rc";
|
||||
|
||||
@@ -36,13 +36,12 @@
|
||||
|
||||
let
|
||||
inherit (callPackage ./build-support/patching.nix { }) addFilePatch;
|
||||
inherit (stdenv.hostPlatform) isDarwin;
|
||||
inherit (stdenv.hostPlatform) isDarwin isAarch64;
|
||||
|
||||
bazelSystem = if isDarwin then "darwin" else "linux";
|
||||
|
||||
# on aarch64 Darwin, `uname -m` returns "arm64"
|
||||
bazelArch =
|
||||
if isDarwin then stdenv.hostPlatform.darwinArch else stdenv.hostPlatform.parsed.cpu.name;
|
||||
bazelArch = if isDarwin && isAarch64 then "arm64" else stdenv.hostPlatform.parsed.cpu.name;
|
||||
|
||||
src = fetchzip {
|
||||
url = "https://github.com/bazelbuild/bazel/releases/download/${version}/bazel-${version}-dist.zip";
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
|
||||
let
|
||||
inherit (callPackage ./build-support/patching.nix { }) addFilePatch;
|
||||
inherit (stdenv.hostPlatform) isDarwin;
|
||||
inherit (stdenv.hostPlatform) isDarwin isAarch64;
|
||||
|
||||
defaultShellUtils =
|
||||
# Keep this list conservative. For more exotic tools, prefer to use
|
||||
@@ -85,8 +85,7 @@ let
|
||||
bazelSystem = if isDarwin then "darwin" else "linux";
|
||||
|
||||
# on aarch64 Darwin, `uname -m` returns "arm64"
|
||||
bazelArch =
|
||||
if isDarwin then stdenv.hostPlatform.darwinArch else stdenv.hostPlatform.parsed.cpu.name;
|
||||
bazelArch = if isDarwin && isAarch64 then "arm64" else stdenv.hostPlatform.parsed.cpu.name;
|
||||
|
||||
src = fetchzip {
|
||||
url = "https://github.com/bazelbuild/bazel/releases/download/${version}/bazel-${version}-dist.zip";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
lib,
|
||||
stdenv,
|
||||
fetchFromGitHub,
|
||||
fetchpatch,
|
||||
pkg-config,
|
||||
libuuid,
|
||||
libsodium,
|
||||
@@ -42,14 +41,6 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
hash = "sha256-H8uzTohV30NU1wYhr/WXN76g1zDqGEzRE5QZcmcM7Jc=";
|
||||
};
|
||||
|
||||
# Fix build with linux-headers 7.3
|
||||
patches = [
|
||||
(fetchpatch {
|
||||
url = "https://github.com/koverstreet/bcachefs-tools/commit/adef3bf68249ac674ddc2cbdfe8c7d0d153e15a8.diff";
|
||||
hash = "sha256-nQsL+1fTQ4ltVyTIwIpO9z9nS66Dtr6WTepBZQ0phL8=";
|
||||
})
|
||||
];
|
||||
|
||||
cargoDeps = rustPlatform.fetchCargoVendor {
|
||||
inherit (finalAttrs) src;
|
||||
hash = "sha256-4ZStyYaT+6Suup1ue2wFFCTAlnsnEO9WaUJHe47BKXY=";
|
||||
|
||||
@@ -58,7 +58,5 @@ stdenv.mkDerivation {
|
||||
homepage = "https://github.com/hexagonal-sun/bic";
|
||||
platforms = lib.platforms.unix;
|
||||
maintainers = with lib.maintainers; [ hexagonal-sun ];
|
||||
# never built on aarch64-darwin since first introduction in nixpkgs
|
||||
broken = stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ buildDotnetModule rec {
|
||||
stdenv.cc.cc.lib
|
||||
];
|
||||
|
||||
doCheck = !stdenv.hostPlatform.isDarwin; # mono is not available on aarch64-darwin
|
||||
doCheck = !(stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64); # mono is not available on aarch64-darwin
|
||||
|
||||
meta = {
|
||||
description = "Domain Specific Language (DSL) for deploying Azure resources declaratively";
|
||||
|
||||
@@ -13,6 +13,8 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
version = "2.19.0";
|
||||
format = "wheel";
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
src = fetchPypi {
|
||||
pname = "bitbake_setup";
|
||||
inherit (finalAttrs) version;
|
||||
|
||||
@@ -49,7 +49,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
installShellFiles
|
||||
gnupg
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
++ lib.optionals (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) [
|
||||
darwin.autoSignDarwinBinariesHook
|
||||
]
|
||||
++ lib.optionals withGui [
|
||||
|
||||
@@ -62,7 +62,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
installShellFiles
|
||||
gnupg
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isDarwin [
|
||||
++ lib.optionals (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) [
|
||||
autoSignDarwinBinariesHook
|
||||
]
|
||||
++ lib.optionals withGui [ qt6.wrapQtAppsHook ];
|
||||
|
||||
@@ -6,26 +6,24 @@
|
||||
libadwaita,
|
||||
meson,
|
||||
ninja,
|
||||
python3,
|
||||
runCommand,
|
||||
stdenv,
|
||||
testers,
|
||||
wrapGAppsNoGuiHook,
|
||||
xvfb-run,
|
||||
gnome,
|
||||
python3Packages,
|
||||
}:
|
||||
|
||||
python3Packages.buildPythonApplication (finalAttrs: {
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "blueprint-compiler";
|
||||
version = "0.22.2";
|
||||
pyproject = false;
|
||||
version = "0.20.4";
|
||||
|
||||
src = fetchFromGitLab {
|
||||
domain = "gitlab.gnome.org";
|
||||
owner = "GNOME";
|
||||
repo = "blueprint-compiler";
|
||||
rev = "v${finalAttrs.version}";
|
||||
hash = "sha256-DRpPUfiufwK2c2RW01IYIX6tgVyxfFl5hnv5F8+9aD4=";
|
||||
hash = "sha256-dA+FQTRmTz6rl5ToZJ8CXY1Zd7Em7VwvF3U3Qoyvu80=";
|
||||
};
|
||||
|
||||
postPatch = ''
|
||||
@@ -36,11 +34,17 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
gobject-introspection
|
||||
meson
|
||||
ninja
|
||||
python3
|
||||
wrapGAppsNoGuiHook
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
libadwaita
|
||||
(python3.withPackages (
|
||||
ps: with ps; [
|
||||
pygobject3
|
||||
]
|
||||
))
|
||||
];
|
||||
|
||||
propagatedBuildInputs = [
|
||||
@@ -48,8 +52,6 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
gobject-introspection
|
||||
];
|
||||
|
||||
dependencies = [ python3Packages.pygobject3 ];
|
||||
|
||||
nativeCheckInputs = [
|
||||
dbus
|
||||
xvfb-run
|
||||
@@ -68,13 +70,6 @@ python3Packages.buildPythonApplication (finalAttrs: {
|
||||
runHook postCheck
|
||||
'';
|
||||
|
||||
# Prevent double wrapping, let the Python wrapper use the args in preFixup.
|
||||
dontWrapGApps = true;
|
||||
|
||||
preFixup = ''
|
||||
makeWrapperArgs+=("''${gappsWrapperArgs[@]}")
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
tests = {
|
||||
version = testers.testVersion {
|
||||
|
||||
@@ -74,8 +74,13 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
export NIX_LDFLAGS="$NIX_LDFLAGS -T $TMP/openbsd.ldscript"
|
||||
'';
|
||||
|
||||
# `gctest` fails on aarch64-linux under qemu-user.
|
||||
doCheck = !(stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isAarch64);
|
||||
# `gctest` fails under x86_64 emulation on aarch64-darwin
|
||||
# and also on aarch64-linux (qemu-user)
|
||||
doCheck =
|
||||
!(
|
||||
(stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isx86_64)
|
||||
|| (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isAarch64)
|
||||
);
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user