Repository: oxalica/nocargo
Branch: main
Commit: 089f487c2c12
Files: 91
Total size: 247.4 KB
Directory structure:
gitextract_9z4bbede/
├── .github/
│ └── workflows/
│ ├── binary-cache.yaml
│ ├── ci.yaml
│ └── update.yaml
├── .gitignore
├── LICENSE-MIT
├── README.md
├── build-rust-crate/
│ ├── builder-bin.sh
│ ├── builder-build-script.sh
│ ├── builder-common.sh
│ ├── builder-lib.sh
│ └── default.nix
├── cache/
│ ├── Cargo.toml
│ ├── default.nix
│ └── src/
│ └── lib.rs
├── crates-io-override/
│ ├── default.nix
│ └── proc-macro.nix
├── flake.nix
├── lib/
│ ├── default.nix
│ ├── glob.nix
│ ├── pkg-info.nix
│ ├── resolve.nix
│ ├── semver.nix
│ ├── support.nix
│ └── target-cfg.nix
├── noc/
│ ├── Cargo.toml
│ ├── src/
│ │ ├── init.rs
│ │ └── main.rs
│ └── templates/
│ └── init-flake.nix
├── scripts/
│ └── cratesio-utils.py
├── tests/
│ ├── build-deps/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/
│ │ └── main.rs
│ ├── build-feature-env-vars/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/
│ │ └── main.rs
│ ├── cap-lints/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── crate-names/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── custom-lib-name/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs
│ │ └── main.rs
│ ├── default.nix
│ ├── dependency-v1/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── main.rs
│ ├── dependency-v2/
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ └── src/
│ │ └── main.rs
│ ├── dependency-v3/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── fake-semver/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── features/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── libz-dynamic/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/
│ │ └── main.rs
│ ├── libz-static/
│ │ ├── Cargo.toml
│ │ ├── build.rs
│ │ └── src/
│ │ ├── lib.rs
│ │ └── main.rs
│ ├── lto-fat/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── lto-proc-macro/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── lto-thin/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── tokio-app/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ ├── workspace-inline/
│ │ ├── Cargo.toml
│ │ ├── bar/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ ├── baz/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ └── src/
│ │ └── main.rs
│ ├── workspace-proc-macro-lto/
│ │ ├── Cargo.toml
│ │ ├── procm/
│ │ │ ├── Cargo.toml
│ │ │ └── src/
│ │ │ └── lib.rs
│ │ └── src/
│ │ └── lib.rs
│ └── workspace-virtual/
│ ├── Cargo.toml
│ └── crates/
│ ├── bar/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── exc/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── main.rs
│ └── foo/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── toml2json/
├── Cargo.toml
├── README.md
├── default.nix
└── src/
└── main.rs
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/binary-cache.yaml
================================================
name: Binary cache
on:
push:
branches:
- main
workflow_run:
workflows:
- update
types:
- completed
branches:
- main
permissions:
contents: read
jobs:
populate:
name: Build and push binary cache
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v24
- name: Setup Cachix
uses: cachix/cachix-action@v13
with:
name: nocargo
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
pushFilter: '(-source$|\.tar\.gz)'
- name: Build cached crates
run: nix build .#cache --show-trace --no-update-lock-file
================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI
on:
pull_request:
push:
workflow_run:
workflows:
- update
types:
- completed
branches:
- main
permissions:
contents: read
jobs:
flake-check:
name: Flake check (locked)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v24
- run: nix flake check --show-trace --no-update-lock-file
================================================
FILE: .github/workflows/update.yaml
================================================
name: Update registry
on:
schedule:
- cron: '0 3 * * *' # *-*-* 03:00:00 UTC
workflow_dispatch:
env:
BRANCH: main
permissions:
contents: write
jobs:
update:
name: Update registry
runs-on: ubuntu-latest
env:
CRATES_TOML_DIR: ./crates-toml
steps:
- name: Checkout
uses: actions/checkout@v4
with:
rev: ${{ env.BRANCH }}
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Nix
uses: cachix/install-nix-action@v24
with:
nix_path: nixpkgs=channel:nixpkgs-unstable
- name: Cache fetched Cargo.toml files
uses: actions/cache@v3
with:
path: ${{ env.CRATES_TOML_DIR }}
key: crates-toml
- name: Sync crates.io database
run: ./scripts/cratesio-utils.py sync
- name: Update proc-macro crates
run: ./scripts/cratesio-utils.py update-proc-macro-crates
- name: Update lockfile of popular crates
run: ./scripts/cratesio-utils.py update-popular-crates
# This should be the last. So the registry locked is not earlier than references.
- name: Update flake
run: nix flake update
- name: Flake check
run: nix flake check --show-trace --no-update-lock-file
- name: Push changes
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add flake.lock crates-io-override/proc-macro.nix cache/Cargo.{lock,toml}
git commit -m "registry: update"
git push HEAD:${{ env.BRANCH }}
================================================
FILE: .gitignore
================================================
result
result-*
================================================
FILE: LICENSE-MIT
================================================
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# nocargo: Cargo in Nix
🚧 *This project is under development and is not ready for production yet. APIs are subjects to change.*
Build Rust crates with *Nix Build System*.
- **No IFDs** (import-from-derivation). See [meme](https://gist.github.com/oxalica/d3b1251eb29d10e6f3cb2005167ddcd9).
- No `cargo` dependency during building. Only `rustc`.
- No need for hash prefetching or code generation[^no-code-gen].
- Crate level caching, globally shared.
- [nixpkgs] integration for non-Rust dependencies.
[^no-code-gen]: Initial template generation and `Cargo.lock` updatin don't count for "code generation". The former is optional, and the latter is indeed not "code".
Feature checklist
- Binary cache
- [x] Top 256 popular crate versions with default features
- Nix library
- [ ] Non-flake support.
- [x] `[workspace]`
- [x] `members`
- [ ] Auto-`members`
- [x] `excludes`
FIXME: Buggy.
- [ ] `resolver`
Currently has custom resolution algorithm, more like v2.
- [x] `links`
- [x] `[profile]`
- [x] `[{,dev-,build-}dependencies]`
- [x] `[features]`
- [x] Overriding API
- [x] `[target..dependencies]`
- [x] `[patch]`
Automatically supported. Since the dependency graph `Cargo.lock` currently relies on `cargo`'s generation.
- [ ] Cross-compilation.
FIXME: Buggy with proc-macros.
- `noc` helper
- [x] `noc init`: Initial template `flake.nix` generation
- Dependency kinds
- [ ] `registry`
- [x] `registry-index`
- [x] `git`
- [x] `path` inside workspace
- [ ] `path` outside workspace
- Target detection
- [ ] Library
FIXME: Assume to always exist.
- [x] Binary
- [ ] Test
- [ ] Bench
- [ ] Example
- [ ] `Cargo.lock` generation and updating
## Start with Nix flake
1. (Optional) Add binary substituters for pre-built popular crates, by either
- Install `cachix` and run `cachix use nocargo` ([see more detail about `cachix`](https://app.cachix.org/cache/nocargo)), or
- Manually add substituter `https://nocargo.cachix.org` with public key `nocargo.cachix.org-1:W6jkp5htZBA1tUdU8XHLaD7zBrIFnor0MsLhHgrJeHk=`
1. Enter the root directory of your rust workspace or package. Currently, you should have `Cargo.lock` already created by `cargo`.
1. Run `nix run github:oxalica/nocargo init` to generate `flake.nix`. Or write it by hand by following [the next section](#example-flake.nix-structure).
1. Check flake outputs with `nix flake show`. Typically, the layout would be like,
```
└───packages
└───x86_64-linux
├───default: package 'rust_mypkg1-0.1.0' # The "default" package. For workspace, it's the top-level one if exists.
├───mypkg1: package 'rust_mypkg1-0.1.0' # Crate `mypkg1` with `release` profile.
├───mypkg1-dev: package 'rust_mypkg1-debug-0.1.0' # Crate `mypkg1` with `dev` profile.
├───mypkg2: package 'rust_mypkg2-0.1.0' # etc.
└───mypkg2-dev: package 'rust_mypkg2-debug-0.1.0'
```
1. Run `nix build .#` to build your package. Built binaries (if any) will be placed in `./result/bin`, and the library will be in `./result/lib`.
1. Have fun!
## Example `flake.nix` structure for reference
A template `flake.nix` with common setup are below. It's mostly the same as the generated one, except that the helper `noc` will scan the workspace and discover all external registries and git dependencies for you.
```nix
{
description = "My Rust packages";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
nocargo = {
url = "github:oxalica/nocargo";
inputs.nixpkgs.follows = "nixpkgs";
# See below.
# inputs.registry-crates-io.follows = "registry-crates-io";
};
# Optionally, you can explicitly import crates.io-index here.
# So you can `nix flake update` at any time to get cutting edge version of crates,
# instead of waiting `nocargo` to dump its dependency.
# Otherwise, you can simply omit this to use the locked registry from `nocargo`,
# which is updated periodically.
# registry-crates-io = { url = "github:rust-lang/crates.io-index"; flake = false; };
};
outputs = { nixpkgs, flake-utils, nocargo, ... }@inputs:
flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
let
# The entry API to make Nix derivations from your Rust workspace or package.
# The output of it consists of profile names, like `release` or `dev`, each of which is
# a attrset of all member package derivations keyed by their package names.
ws = nocargo.lib.${system}.mkRustPackageOrWorkspace {
# The root directory, which contains `Cargo.lock` and top-level `Cargo.toml`
# (the one containing `[workspace]` for workspace).
src = ./.;
# If you use registries other than crates.io, they should be imported in flake inputs,
# and specified here. Note that registry should be initialized via `mkIndex`,
# with an optional override.
extraRegistries = {
# "https://example-registry.org" = nocargo.lib.${system}.mkIndex inputs.example-registry {};
};
# If you use crates from git URLs, they should be imported in flake inputs,
# and specified here.
gitSrcs = {
# "https://github.com/some/repo" = inputs.example-git-source;
};
# If some crates in your dependency closure require packages from nixpkgs.
# You can override the argument for `stdenv.mkDerivation` to add them.
#
# Popular `-sys` crates overrides are maintained in `./crates-io-override/default.nix`
# to make them work out-of-box. PRs are welcome.
buildCrateOverrides = with nixpkgs.legacyPackages.${system}; {
# Use package id format `pkgname version (registry)` to reference a direct or transitive dependency.
"zstd-sys 2.0.1+zstd.1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = old: {
nativeBuildInputs = [ pkg-config ];
propagatedBuildInputs = [ zstd ];
};
# Use package name to reference local crates.
"mypkg1" = old: {
nativeBuildInputs = [ git ];
};
};
# We use the rustc from nixpkgs by default.
# But you can override it, for example, with a nightly version from https://github.com/oxalica/rust-overlay
# rustc = rust-overlay.packages.${system}.rust-nightly_2022-07-01;
};
in rec {
# For convenience, we hoist derivations of `release` and `dev` profile for easy access,
# with `dev` packages postfixed by `-dev`.
# You can export different packages of your choice.
packages = ws.release
// nixpkgs.lib.mapAttrs' (name: value: { name = "${name}-dev"; inherit value; }) ws.dev
// {
# The "default" features are turned on by default.
# You can `override` the library derivation to enable a different set of features.
# Explicit overriding will disable "default", unless you manually include it.
mypkg1-with-custom-features = (ws.release.mypkg1.override {
# Enables two features (and transitive ones), and disables "default".
features = [ "feature1" "feature2" ];
}).bin;
};
});
}
```
## FAQ
### Comparison with [cargo2nix] and [naersk]?
Main differences are already clarified [on the top](#nocargo%3A-cargo-in-nix).
`nocargo` is inspired by `cargo2nix` and `buildRustCrate` in `nixpkgs`. We are more like `cargo2nix` while the generation part is implemented by pure Nix, but less like `naersk` which is a wrapper to call `cargo` to build the package inside derivations.
In other words, we and `cargo2nix` use Nix as a *Build System*, while `nearsk` use Nix as a *Package Manager* or *Packager*.
Detail comparison of nocargo, cargo2nix/buildRustCrate, naersk and buildRustPackage
| | nocargo | [cargo2nix]/`buildRustCrate` | [naersk] | `buildRustPackage` |
|-|-|-|-|-|
| Depend on `cargo` | Updating `Cargo.lock` | Updating & generating & building | Updating & vendoring & building | Building |
| Derivation granularity | Per crate | Per crate | Per package + one dependency closure | All in one |
| Crate level sharing | ✔️ | ✔️ | ✖ | ✖ |
| Binary substitution per crate | ✔️ | Not implemented | ✖ | ✖ |
| Code generation | ✖ | ✔️ | ✖ | ✖ |
| Edit workspace & rebuild | Rebuild leaf crates | Rebuild leaf crates | Rebuild leaf crates | Refetch and rebuild all crates |
| Edit dependencies & rebuild | Rebuild changed crates (refetch if needed) | Refetch, regenerate and rebuild changed crates | Refetch and rebuild all crates | Refetch and rebuild all crates |
| Offline rebuild as long as | Not adding unfetched crate dependency | Not adding unfetched crate dependency | Not changing any dependencies | ✖ |
### But why pure Nix build system?
- Sharing through fine-grained derivations between all projects, not just in one workspace.
- Binary substitution per crate.
No need for global `target_dir`/`CARGO_TARGET_DIR` or [sccache].
- Easy `nixpkgs` integration for non-Rust package dependencies, cross-compilation (planned) and package overriding.
- More customizability: per-crate `rustc` flags tweaking, arbitrary crate patching, force dynamic linking and more.
### Can I really throw away `cargo`?
Sorry, currently no. :crying_cat_face: Updating of `Cargo.lock` still relies on `cargo`.
This can happen when creating a new project or changing dependencies.
We are mainly using `cargo`'s SAT solver to pin down the dependency graph.
It's *possible* to implement it ourselves, but not yet, due to the complexity.
## License
MIT Licensed.
[nixpkgs]: https://github.com/NixOS/nixpkgs
[naersk]: https://github.com/nix-community/naersk
[cargo2nix]: https://github.com/cargo2nix/cargo2nix
[sccache]: https://github.com/mozilla/sccache
================================================
FILE: build-rust-crate/builder-bin.sh
================================================
source $stdenv/setup
source $builderCommon
declare -A buildFlagsMap
declare -A binPathMap
dontInstall=1
addBin() {
local name="$1" path="$2" binEdition="$3"
local -a pathCandidates
if [[ -z "$name" ]]; then
echo "Name of the binary target is not specified"
exit 1
fi
if [[ -n "$path" ]]; then
pathCandidates=("$path")
else
pathCandidates=()
if [[ -f "src/bin/$name.rs" ]]; then
pathCandidates+=("src/bin/$name.rs")
fi
if [[ -f "src/bin/$name/main.rs" ]]; then
pathCandidates+=("src/bin/$name/main.rs")
fi
if [[ "$name" == "$pkgName" && -f "src/main.rs" ]]; then
pathCandidates+=("src/main.rs")
fi
fi
case ${#pathCandidates[@]} in
0)
echo "Cannot guess path of binary target"
exit 1
;;
1)
path="${pathCandidates[0]}"
;;
*)
echo "Ambiguous binary target, candidate paths: ${pathCandidates[*]}"
exit 1
;;
esac
printf "Found binary %q at %q\n" "$name" "$path"
binPathMap["$path"]=1
# TODO: Other flags.
buildFlagsMap["$name"]="$path --crate-name ${name//-/_} -C metadata=$rustcMeta-$name"
if [[ -n "${binEdition:=$globalEdition}" ]]; then
buildFlagsMap["$name"]+=" --edition $binEdition"
fi
}
configurePhase() {
runHook preConfigure
convertCargoToml
globalEdition="$(jq --raw-output '.package.edition // ""' "$cargoTomlJson")"
pkgName="$(jq --raw-output '.package.name // ""' "$cargoTomlJson")"
# For packages with the 2015 edition, the default for auto-discovery is false if at least one target is
# manually defined in Cargo.toml. Beginning with the 2018 edition, the default is always true.
# See: https://doc.rust-lang.org/cargo/reference/cargo-targets.html#target-auto-discovery
autoDiscovery=
if [[
"$(jq --raw-output '.package.autobins' "$cargoTomlJson")" != false &&
( "${globalEdition:-2015}" != 2015 || ${#buildFlagsMap[@]} = 0 )
]]; then
autoDiscovery=1
fi
local binsStr
while read -r name; do
read -r path
read -r binEdition
addBin "$name" "$path" "$binEdition"
# Don't strip whitespace.
done < <(jq --raw-output '.bin // [] | .[] | .name // "", .path // "", .edition // ""' "$cargoTomlJson")
if [[ -n "$autoDiscovery" ]]; then
if [[ -f src/main.rs && -z ${binPathMap[src/main.rs]} ]]; then
addBin "$pkgName" src/main.rs ""
fi
local f name
for f in src/bin/*; do
name="${f##*/}"
if [[ "$f" = *.rs && -f "$f" ]]; then
[[ -n "${binPathMap["$f"]}" ]] || addBin "${name%.rs}" "$f" ""
elif [[ -f "$f/main.rs" ]]; then
[[ -n "${binPathMap["$f/main.rs"]}" ]] || addBin "$name" "$f/main.rs" ""
fi
done
fi
if [[ ${#buildFlagsMap[@]} = 0 ]]; then
echo "No binaries to be built"
mkdir $out
exit 0
fi
# Implicitly link library of current crate, if exists.
if [[ -e "$libDevDrv"/lib ]]; then
addExternFlags buildFlagsArray link "::$libOutDrv:$libDevDrv"
fi
# Actually unused.
declare -a cdylibBuildFlagsArray
addExternFlags buildFlagsArray link $dependencies
addFeatures buildFlagsArray $features
importBuildOut buildFlagsArray cdylibBuildFlagsArray "$buildDrv"
setCargoCommonBuildEnv
depsClosure="$(mktemp -d)"
collectTransDeps "$depsClosure" $dependencies
buildFlagsArray+=(-Ldependency="$depsClosure")
runHook postConfigure
}
buildPhase() {
runHook preBuild
mkdir -p $out/bin
local binName
for binName in "${!buildFlagsMap[@]}"; do
export CARGO_CRATE_NAME="$binName"
export CARGO_BIN_NAME="$binName"
runRustc "Building binary $binName" \
${buildFlagsMap["$binName"]} \
--crate-type bin \
--out-dir $out/bin \
$buildFlags \
"${buildFlagsArray[@]}"
done
runHook postBuild
}
genericBuild
================================================
FILE: build-rust-crate/builder-build-script.sh
================================================
source $stdenv/setup
source $builderCommon
shopt -s nullglob
preInstallPhases+="runBuildScriptPhase "
buildFlagsArray+=( -Cmetadata="$rustcMeta" )
configurePhase() {
runHook preConfigure
convertCargoToml
buildScriptSrc="$(jq --raw-output '.package.build // ""' "$cargoTomlJson")"
if [[ -z "$buildScriptSrc" && -e build.rs ]]; then
buildScriptSrc=build.rs
elif [[ -z "$buildScriptSrc" ]]; then
echo "No build script, doing nothing"
mkdir -p $out
exit 0
fi
edition="$(jq --raw-output '.package.edition // ""' "$cargoTomlJson")"
if [[ -n "$edition" ]]; then
buildFlagsArray+=(--edition="$edition")
fi
addFeatures buildFlagsArray $features
addExternFlags buildFlagsArray link $dependencies
setCargoCommonBuildEnv
depsClosure="$(mktemp -d)"
collectTransDeps "$depsClosure" $dependencies
buildFlagsArray+=(-Ldependency="$depsClosure")
runHook postConfigure
}
buildPhase() {
runHook preBuild
mkdir -p $out/bin
runRustc "Building build script" \
"$buildScriptSrc" \
--out-dir="$out/bin" \
--crate-name="build_script_build" \
--crate-type=bin \
--emit=link \
-Cembed-bitcode=no \
$buildScriptBuildFlags \
"${buildFlagsArray[@]}"
runHook postBuild
}
runBuildScriptPhase() {
runHook preRunBuildScript
export CARGO_MANIFEST_DIR="$(pwd)"
if [[ -n "$links" ]]; then
export CARGO_MANIFEST_LINKS="$links"
fi
for feat in $features; do
feat_uppercase="${feat^^}"
export "CARGO_FEATURE_${feat_uppercase//-/_}"=1
done
export OUT_DIR="$out/rust-support/out-dir"
export NUM_JOBS=$NIX_BUILD_CORES
export RUSTC_BACKTRACE=1 # Make debugging easier.
local buildOut
for buildOut in $linksDependencies; do
if [[ -e "$buildOut/rust-support/links-metadata" ]]; then
source "$buildOut/rust-support/links-metadata"
fi
done
# Other flags are set outside.
# - CARGO_CFG_
# - HOST
# - TARGET
# - RUSTC
# - CARGO
# - RUSTDOC
mkdir -p "$out/rust-support" "$OUT_DIR"
echo "Running build script"
stdoutFile="$out/rust-support/build-stdout"
"$out/bin/build_script_build" | tee "$stdoutFile"
runHook postRunBuildScript
}
installPhase() {
runHook preInstall
# https://doc.rust-lang.org/1.61.0/cargo/reference/build-scripts.html#outputs-of-the-build-script
local line rhs
while read -r line; do
rhs="${line#*=}"
case "$line" in
cargo:rerun-if-changed=*|cargo:rerun-if-env-changed=*)
# Ignored due to the sandbox.
;;
cargo:rustc-link-arg=*)
echo "-Clink-arg=$rhs" >>"$out/rust-support/rustc-link-args"
;;
cargo:rustc-link-arg-bin=*)
if [[ "$rhs" != *=* ]]; then
echo "Missing binary name: $line"
exit 1
fi
echo "-Clink-arg=${rhs%%=*}" >>"$out/rust-support/rustc-link-args-bin-${rhs#*=}"
;;
cargo:rustc-link-arg-bins=*)
echo "-Clink-arg=$rhs" >>"$out/rust-support/rustc-link-args-bins"
;;
cargo:rustc-link-arg-tests=*)
echo "-Clink-arg=$rhs" >>"$out/rust-support/rustc-link-args-tests"
;;
cargo:rustc-link-arg-examples=*)
echo "-Clink-arg=$rhs" >>"$out/rust-support/rustc-link-args-examples"
;;
cargo:rustc-link-arg-benches=*)
echo "-Clink-arg=$rhs" >>"$out/rust-support/rustc-link-args-benches"
;;
cargo:rustc-link-lib=*)
if [[ -z "$rhs" ]]; then
echo "Empty link path: $line"
exit 1
fi
echo "-l$rhs" >>"$out/rust-support/rustc-flags"
;;
cargo:rustc-link-search=*)
if [[ -z "$rhs" ]]; then
echo "Empty link path: $line"
exit 1
fi
echo "-L$rhs" >>"$out/rust-support/rustc-flags"
;;
cargo:rustc-flags=*)
local flags i flag
read -r -a flags <<<"$rhs"
for (( i = 0; i < ${#flags[@]}; i++ )); do
flag="${flags[i]}"
if [[ "$flag" = -[lL] ]]; then
(( i++ ))
flag+="${flags[i]}"
elif [[ "$flag" != -[lL]* ]]; then
echo "Only -l and -L are allowed from build script: $line"
exit 1
fi
if [[ ${#flag} == 2 ]]; then
echo "Empty link path: $line"
exit 1
fi
echo "$flag" >>"$out/rust-support/rustc-flags"
done
;;
cargo:rustc-cfg=*)
echo "--cfg=$rhs" >>"$out/rust-support/rustc-flags"
;;
cargo:rustc-env=*=*)
printf 'export %q=%q\n' "${rhs%%=*}" "${rhs#*=}" >>"$out/rust-support/rustc-env"
;;
cargo:rustc-cdylib-link-arg=*)
echo "-Clink-arg=$rhs" >>"$out/rust-support/rustc-cdylib-flags"
;;
cargo:warning=*)
printf "\033[0;1;33mWarning\033[0m: %s\n" "$rhs"
;;
cargo:*=*)
if [[ -n "${links:-}" ]]; then
rhs="${line#*:}"
local k="DEP_${links}_${rhs%%=*}" v="${rhs#*=}"
k="${k^^}"
k="${k//-/_}"
printf 'export %q=%q\n' "$k" "$v" >>"$out/rust-support/links-metadata"
else
printf "\033[0;1;33mWarning\033[0m: no 'links' defined in Cargo.toml, ignoring %s" "$line"
fi
;;
cargo:*)
echo "Unknown or wrong output line: $line"
exit 1
;;
*)
;;
esac
done <"$stdoutFile"
local file
for file in "$out"/rust-support/{rustc-*,links-metadata*}; do
sort "$file" -o "$file"
done
runHook postInstall
}
genericBuild
================================================
FILE: build-rust-crate/builder-common.sh
================================================
declare -a buildFlagsArray
buildFlagsArray+=( --color=always )
# Collect all transitive dependencies (symlinks).
collectTransDeps() {
local collectDir="$1" line rename procMacro depOut depDev
mkdir -p "$collectDir"
shift
for line in "$@"; do
IFS=: read -r rename procMacro depOut depDev <<<"$line"
# May be empty.
cp --no-dereference --no-clobber -t $collectDir $depDev/rust-support/deps-closure/* 2>/dev/null || true
done
}
addExternFlags() {
local var="$1" kind="$2" line rename procMacro depOut depDev paths
shift 2
for line in "$@"; do
IFS=: read -r rename procMacro depOut depDev <<<"$line"
if [[ -n "$procMacro" ]]; then
paths=("$depOut"/lib/*"$sharedLibraryExt")
elif [[ "$kind" == meta ]]; then
paths=("$depDev"/lib/*.rmeta)
else
# FIXME: Currently we only link rlib.
paths=("$depOut"/lib/*.rlib)
fi
if (( ${#paths[@]} == 0 )); then
echo "No dependent library found for $line"
exit 1
elif (( ${#paths[@]} > 1 )); then
echo "Multiple candidate found for dependent library $line, found: ${paths[*]}"
exit 1
fi
if [[ -z "$rename" ]]; then
if [[ "${paths[0]##*/}" =~ ^lib(.*)(-.*)(\.rmeta|\.rlib|"$sharedLibraryExt")$ ]]; then
rename="${BASH_REMATCH[1]}"
else
echo "Invalid library name: ${paths[0]}"
exit 1
fi
fi
eval "$var"'+=(--extern="$rename=${paths[0]}")'
done
}
addFeatures() {
local var="$1" feat
shift
for feat in "$@"; do
eval "$var"'+=(--cfg="feature=\"$feat\"")'
done
}
importBuildOut() {
local var="$1" cvar="$2" drv="$3" flags
[[ ! -e "$drv/rust-support/build-stdout" ]] && return
echo export OUT_DIR="$drv/rust-support/out-dir"
export OUT_DIR="$drv/rust-support/out-dir"
if [[ -e "$drv/rust-support/rustc-env" ]]; then
cat "$drv/rust-support/rustc-env"
source "$drv/rust-support/rustc-env"
fi
if [[ -e "$drv/rust-support/rustc-flags" ]]; then
mapfile -t flags <"$drv/rust-support/rustc-flags"
eval "$var"'+=("${flags[@]}")'
fi
if [[ -e "$drv/rust-support/rustc-cdylib-flags" ]]; then
mapfile -t flags <"$drv/rust-support/rustc-cdylib-flags"
eval "$cvar"'+=("${flags[@]}")'
fi
}
runRustc() {
local msg="$1"
shift
echo "$msg: RUSTC ${*@Q}"
$RUSTC "$@"
}
convertCargoToml() {
local cargoToml="${1:-"$(pwd)/Cargo.toml"}"
cargoTomlJson="$(mktemp "$(dirname "$cargoToml")/Cargo.json.XXX")"
toml2json <"$cargoToml" >"$cargoTomlJson"
}
# https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
setCargoCommonBuildEnv() {
# CARGO_CRATE_NAME is set outside since targets have individual crate names.
# export CARGO=
CARGO_MANIFEST_DIR="$(dirname "$cargoTomlJson")"
export CARGO_MANIFEST_DIR
CARGO_PKG_NAME="$(jq --raw-output '.package.name // ""' "$cargoTomlJson")"
CARGO_PKG_VERSION="$(jq --raw-output '.package.version // ""' "$cargoTomlJson")"
if [[ -z "CARGO_PKG_NAME" ]]; then
echo "Package name must be set"
exit 1
fi
if [[ -z "CARGO_PKG_VERSION" ]]; then
echo "Package version must be set"
exit 1
fi
CARGO_PKG_AUTHORS="$(jq --raw-output '.package.authors // [] | join(":")' "$cargoTomlJson")"
CARGO_PKG_DESCRIPTION="$(jq --raw-output '.package.description // ""' "$cargoTomlJson")"
CARGO_PKG_HOMEPAGE="$(jq --raw-output '.package.homepage // ""' "$cargoTomlJson")"
CARGO_PKG_LICENSE="$(jq --raw-output '.package.license // ""' "$cargoTomlJson")"
CARGO_PKG_LICENSE_FILE="$(jq --raw-output '.package."license-file" // ""' "$cargoTomlJson")"
export CARGO_PKG_NAME CARGO_PKG_VERSION CARGO_PKG_AUTHORS CARGO_PKG_DESCRIPTION \
CARGO_PKG_HOMEPAGE CARGO_PKG_LICENSE CARGO_PKG_LICENSE_FILE
if [[ "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([A-Za-z0-9.-]+))?(\+.*)?$ ]]; then
export CARGO_PKG_VERSION_MAJOR="${BASH_REMATCH[1]}"
export CARGO_PKG_VERSION_MINOR="${BASH_REMATCH[2]}"
export CARGO_PKG_VERSION_PATCH="${BASH_REMATCH[3]}"
export CARGO_PKG_VERSION_PRE="${BASH_REMATCH[4]}"
else
echo "Invalid version: $version"
fi
}
================================================
FILE: build-rust-crate/builder-lib.sh
================================================
source $stdenv/setup
source $builderCommon
shopt -s nullglob
buildFlagsArray+=( -Cmetadata="$rustcMeta" )
configurePhase() {
runHook preConfigure
convertCargoToml
libSrc="$(jq --raw-output '.lib.path // ""' "$cargoTomlJson")"
if [[ -z "$libSrc" && -e src/lib.rs ]]; then
libSrc=src/lib.rs
fi
if [[ ! -e "$libSrc" ]]; then
echo "No library to be built"
mkdir $out $dev
exit 0
fi
crateName="$(jq --raw-output '.lib.name // (.package.name // "" | gsub("-"; "_"))' "$cargoTomlJson")"
if [[ -z "$crateName" ]]; then
echo "Package name must be set"
exit 1
fi
edition="$(jq --raw-output '.package.edition // .lib.edition // ""' "$cargoTomlJson")"
if [[ -n "$edition" ]]; then
buildFlagsArray+=(--edition="$edition")
fi
mapfile -t crateTypes < <(jq --raw-output '.lib."crate-type" // ["lib"] | .[]' "$cargoTomlJson")
cargoTomlIsProcMacro="$(jq --raw-output 'if .lib."proc-macro" then "1" else "" end' "$cargoTomlJson")"
if [[ "$cargoTomlIsProcMacro" != "$procMacro" ]]; then
echo "Cargo.toml says proc-macro = ${cargoTomlIsProcMacro:-0} but it is built with procMacro = ${procMacro:-0}"
exit 1
fi
if [[ -n "$procMacro" ]]; then
# Override crate type.
crateTypes=("proc-macro")
buildFlagsArray+=(--extern=proc_macro)
fi
needLinkDeps=
buildCdylib=
for crateType in "${crateTypes[@]}"; do
case "$crateType" in
lib|rlib)
;;
dylib|staticlib|proc-macro|bin)
needLinkDeps=1
;;
cdylib)
buildCdylib=1
;;
*)
echo "Unsupported crate-type: $crateType"
exit 1
;;
esac
done
if [[ -n "$needLinkDeps" ]]; then
addExternFlags buildFlagsArray link $dependencies
else
addExternFlags buildFlagsArray meta $dependencies
fi
declare -a cdylibBuildFlagsArray
importBuildOut buildFlagsArray cdylibBuildFlagsArray "$buildDrv"
# FIXME: cargo include cdylib flags for all crate-types once cdylib is included.
buildFlagsArray+=( "${cdylibBuildFlagsArray[@]}" )
addFeatures buildFlagsArray $features
setCargoCommonBuildEnv
export CARGO_CRATE_NAME="$crateName"
collectTransDeps $dev/rust-support/deps-closure $dependencies
buildFlagsArray+=(-Ldependency="$dev/rust-support/deps-closure")
runHook postConfigure
}
buildPhase() {
runHook preBuild
local crateTypesCommaSep
printf -v crateTypesCommaSep '%s,' "${crateTypes[@]}"
crateTypesCommaSep="${crateTypesCommaSep%,}"
mkdir -p $out/lib
runRustc "Building lib" \
"$libSrc" \
--out-dir="$out/lib" \
--crate-name="$crateName" \
--crate-type="$crateTypesCommaSep" \
--emit=metadata,link \
-Cextra-filename="-$rustcMeta" \
$buildFlags \
"${buildFlagsArray[@]}"
runHook postBuild
}
installPhase() {
runHook preInstall
mkdir -p $out $bin $dev/lib $dev/rust-support/deps-closure
# May be empty.
mv -t $dev/lib $out/lib/*.rmeta 2>/dev/null || true
ln -sft $dev/rust-support/deps-closure $out/lib/* $dev/lib/* 2>/dev/null || true
runHook postInstall
}
genericBuild
================================================
FILE: build-rust-crate/default.nix
================================================
{ lib, nocargo-lib, stdenv, buildPackages, rust, toml2json, jq }:
{ pname
, version
, src
, rustc ? buildPackages.rustc
, links ? null
# [ { rename = "foo" /* or null */; drv = ; } ]
, dependencies ? []
# Normal dependencies with non empty `links`, which will propagate `DEP__` environments to build script.
, linksDependencies ? dependencies
, buildDependencies ? []
, features ? []
, profile ? {}
, capLints ? null
, buildFlags ? []
, buildScriptBuildFlags ? []
, procMacro ? false
, nativeBuildInputs ? []
, propagatedBuildInputs ? []
, ...
}@args:
let
inherit (nocargo-lib.target-cfg) platformToCfgAttrs;
mkRustcMeta = dependencies: features: let
deps = lib.concatMapStrings (dep: dep.drv.rustcMeta) dependencies;
feats = lib.concatStringsSep ";" features;
final = "${pname} ${version} ${feats} ${deps}";
in
lib.substring 0 16 (builtins.hashString "sha256" final);
buildRustcMeta = mkRustcMeta buildDependencies [];
rustcMeta = mkRustcMeta dependencies [];
# TODO: Pass target binary paths instead of drv here?
mkDeps = map ({ rename, drv, ... }: lib.concatStringsSep ":" [
(toString rename)
(toString drv.procMacro)
drv.out
drv.dev
]);
toDevDrvs = map ({ drv, ... }: drv.dev);
buildDeps = mkDeps buildDependencies;
libDeps = mkDeps dependencies;
builderCommon = ./builder-common.sh;
convertBool = f: t: x:
if x == true then t
else if x == false then f
else x;
# https://doc.rust-lang.org/cargo/reference/profiles.html
profileToRustcFlags = p:
[]
++ lib.optional (p.opt-level or 0 != 0) "-Copt-level=${toString p.opt-level}"
++ lib.optional (p.debug or false != false) "-Cdebuginfo=${if p.debug == true then "2" else toString p.debug}"
# TODO: `-Cstrip` is not handled since stdenv will always strip them.
++ lib.optional (p ? debug-assertions) "-Cdebug-assertions=${convertBool "no" "yes" p.debug-assertions}"
++ lib.optional (p ? overflow-checks) "-Coverflow-checks=${convertBool "no" "yes" p.debug-assertions}"
++ lib.optional (!procMacro && p.lto or false != false) "-Clto=${if p.lto == true then "fat" else p.lto}"
++ lib.optional (p.panic or "unwind" != "unwind") "-Cpanic=${p.panic}"
# `incremental` is not useful since Nix builds in a sandbox.
++ lib.optional (p ? codegen-units) "-Ccodegen-units=${toString p.codegen-units}"
++ lib.optional (p.rpath or false) "-Crpath"
++ lib.optional (p.lto or false == false) "-Cembed-bitcode=no"
;
convertProfile = p: {
buildFlags =
profileToRustcFlags p
++ lib.optional (capLints != null) "--cap-lints=${capLints}"
++ buildFlags;
buildScriptBuildFlags =
profileToRustcFlags (p.build-override or {})
++ buildScriptBuildFlags;
# Build script environments.
PROFILE = p.name or null;
OPT_LEVEL = p.opt-level or 0;
DEBUG = p.debug or 0 != 0;
};
profile' = convertProfile profile;
buildProfile' = convertProfile (profile.build-override or {});
commonArgs = {
inherit pname version src;
nativeBuildInputs = [ toml2json jq ] ++ nativeBuildInputs;
sharedLibraryExt = stdenv.hostPlatform.extensions.sharedLibrary;
inherit capLints;
RUSTC = "${rustc}/bin/rustc";
} // removeAttrs args [
"pname"
"version"
"src"
"rustc"
"links"
"dependencies"
"linksDependencies"
"buildDependencies"
"features"
"profile"
"capLints"
"buildFlags"
"buildScriptBuildFlags"
"procMacro"
"nativeBuildInputs"
"propagatedBuildInputs"
];
cargoCfgs = lib.mapAttrs' (key: value: {
name = "CARGO_CFG_${lib.toUpper key}";
value = if lib.isList value then lib.concatStringsSep "," value
else if value == true then ""
else value;
}) (platformToCfgAttrs stdenv.hostPlatform);
buildDrv = stdenv.mkDerivation ({
name = "rust_${pname}-${version}-build";
builder = ./builder-build-script.sh;
inherit propagatedBuildInputs builderCommon features links;
rustcMeta = buildRustcMeta;
dependencies = buildDeps;
linksDependencies = map (dep: dep.drv.buildDrv) linksDependencies;
HOST = rust.toRustTarget stdenv.buildPlatform;
TARGET = rust.toRustTarget stdenv.hostPlatform;
# This drv links for `build_script_build`.
# So include transitively propagated upstream `-sys` crates' ld dependencies.
buildInputs = toDevDrvs dependencies;
# Build script may produce object files and static libraries which should not be modified.
dontFixup = true;
} // commonArgs // cargoCfgs // buildProfile');
libDrv = stdenv.mkDerivation ({
name = "rust_${pname}-${version}";
builder = ./builder-lib.sh;
outputs = [ "out" "dev" ];
inherit builderCommon buildDrv features rustcMeta procMacro;
# Transitively propagate upstream `-sys` crates' ld dependencies.
# Since `rlib` doesn't link.
propagatedBuildInputs = toDevDrvs dependencies ++ propagatedBuildInputs;
dependencies = libDeps;
} // commonArgs // profile');
binDrv = stdenv.mkDerivation ({
name = "rust_${pname}-${version}-bin";
builder = ./builder-bin.sh;
inherit propagatedBuildInputs builderCommon buildDrv features rustcMeta;
libOutDrv = libDrv.out;
libDevDrv = libDrv.dev;
# This requires linking.
# Include transitively propagated upstream `-sys` crates' ld dependencies.
buildInputs = toDevDrvs dependencies;
dependencies = libDeps;
} // commonArgs // profile');
in
libDrv // {
build = buildDrv;
bin = binDrv;
}
================================================
FILE: cache/Cargo.toml
================================================
[package]
name = "cache"
version = "0.0.0"
description = "Virtual package to reference all popular crates to be cached"
# N.B. We cannot use `={version}` since cargo doesn't allow two compatible versions of
# the same crate appears in the dependency tree, eg. getrandom 0.2.6 and getrandom@0.2.7.
# So we use carpet specifiers to allow merging compatible versions to the highest one currently.
[dependencies]
addr2line = "0.17"
adler = "1"
ahash = "0.7"
aho-corasick = "0.7"
ansi_term = "0.12"
anyhow = "1"
arrayref = "0.3"
arrayvec = "0.7"
arrayvec-2 = { package = "arrayvec", version = "0.5" }
async-stream = "0.3"
async-stream-impl = "0.3"
async-trait = "0.1"
atty = "0.2"
autocfg = "1"
base64 = "0.13"
bincode = "1"
bitflags = "1"
block-buffer = "0.10"
block-buffer-2 = { package = "block-buffer", version = "0.9" }
bstr = "0.2"
byteorder = "1"
bytes = "1"
cc = "1"
cfg-if = "1"
cfg-if-2 = { package = "cfg-if", version = "0.1" }
chrono = "0.4"
clap = "2"
clap_lex = "0.2"
constant_time_eq = "0.1"
convert_case = "0.4"
core-foundation-sys = "0.8"
cpufeatures = "0.2"
crc32fast = "1"
crossbeam-channel = "0.5"
crossbeam-deque = "0.8"
crossbeam-utils = "0.8"
crunchy = "0.2"
crypto-common = "0.1"
csv = "1"
csv-core = "0.1"
darling_macro = "0.13"
data-encoding = "2"
derivative = "2"
derive_more = "0.99"
digest = "0.10"
digest-2 = { package = "digest", version = "0.9" }
dirs-next = "2"
dirs-sys = "0.3"
dirs-sys-next = "0.1"
either = "1"
encoding_rs = "0.8"
env_logger = "0.9"
fallible-iterator = "0.2"
fastrand = "1"
flate2 = "1"
fnv = "1"
foreign-types = "0.3"
foreign-types-shared = "0.1"
form_urlencoded = "1"
futures = "0.3"
futures-channel = "0.3"
futures-core = "0.3"
futures-executor = "0.3"
futures-io = "0.3"
futures-macro = "0.3"
futures-sink = "0.3"
futures-task = "0.3"
futures-util = "0.3"
generic-array = "0.14"
getrandom = "0.2"
getrandom-2 = { package = "getrandom", version = "0.1" }
gimli = "0.26"
glob = "0.3"
h2 = "0.3"
half = "1"
hashbrown = "0.12"
hashbrown-2 = { package = "hashbrown", version = "0.11" }
heck = "0.4"
heck-2 = { package = "heck", version = "0.3" }
hermit-abi = "0.1"
hex = "0.4"
hmac = "0.12"
hostname = "0.3"
http = "0.2"
http-body = "0.4"
httparse = "1"
httpdate = "1"
humantime = "2"
hyper = "0.14"
hyper-tls = "0.5"
ident_case = "1"
idna = "0.2"
indexmap = "1"
instant = "0.1"
ipnet = "2"
itertools = "0.10"
itoa = "1"
itoa-2 = { package = "itoa", version = "0.4" }
jobserver = "0.1"
lazy_static = "1"
lazycell = "1"
libc = "0.2"
libloading = "0.7"
linked-hash-map = "0.5"
lock_api = "0.4"
log = "0.4"
maplit = "1"
match_cfg = "0.1"
matchers = "0.1"
matches = "0.1"
memchr = "2"
memoffset = "0.6"
mime = "0.3"
minimal-lexical = "0.2"
miniz_oxide = "0.5"
miniz_oxide-2 = { package = "miniz_oxide", version = "0.4" }
mio = "0.8"
multimap = "0.8"
native-tls = "0.2"
nom = "7"
num-bigint = "0.4"
num-integer = "0.1"
num-iter = "0.1"
num-traits = "0.2"
num_cpus = "1"
num_threads = "0.1"
object = "0.29"
once_cell = "1"
oorandom = "11"
opaque-debug = "0.3"
openssl-macros = "0.1"
openssl-probe = "0.1"
openssl-sys = "0.9"
parking_lot = "0.12"
parking_lot-2 = { package = "parking_lot", version = "0.11" }
parking_lot_core = "0.9"
parking_lot_core-2 = { package = "parking_lot_core", version = "0.8" }
peeking_take_while = "0.1"
percent-encoding = "2"
phf_shared = "0.10"
pin-project-lite = "0.2"
pin-utils = "0.1"
pkg-config = "0.3"
ppv-lite86 = "0.2"
proc-macro-error = "1"
proc-macro-error-attr = "1"
proc-macro-hack = "0.5"
proc-macro2 = "1"
quick-error = "1"
quote = "1"
rand = "0.8"
rand-2 = { package = "rand", version = "0.7" }
rand_chacha = "0.3"
rand_chacha-2 = { package = "rand_chacha", version = "0.2" }
rand_core = "0.6"
rand_core-2 = { package = "rand_core", version = "0.5" }
rayon = "1"
rayon-core = "1"
regex = "1"
regex-automata = "0.1"
regex-syntax = "0.6"
remove_dir_all = "0.5"
reqwest = "0.11"
ring = "0.16"
rustc-demangle = "0.1"
rustc-hash = "1"
rustc_version = "0.4"
rustc_version-2 = { package = "rustc_version", version = "0.2" }
rustls = "0.20"
ryu = "1"
same-file = "1"
scopeguard = "1"
sct = "0.7"
semver = "0.9"
semver-parser = "0.7"
serde = "1"
serde_cbor = "0.11"
serde_derive = "1"
serde_json = "1"
serde_urlencoded = "0.7"
sha-1 = "0.10"
sha2 = "0.10"
sha2-2 = { package = "sha2", version = "0.9" }
sharded-slab = "0.1"
shlex = "1"
signal-hook-registry = "1"
siphasher = "0.3"
slab = "0.4"
smallvec = "1"
socket2 = "0.4"
spin = "0.5"
stable_deref_trait = "1"
static_assertions = "1"
strsim = "0.10"
strsim-2 = { package = "strsim", version = "0.8" }
subtle = "2"
syn = "1"
synstructure = "0.12"
tempfile = "3"
termcolor = "1"
terminal_size = "0.1"
textwrap = "0.15"
textwrap-2 = { package = "textwrap", version = "0.11" }
thiserror = "1"
thiserror-impl = "1"
thread_local = "1"
time = "0.1"
time-macros = "0.2"
tinyvec = "1"
tinyvec_macros = "0.1"
tokio-macros = "1"
tokio-native-tls = "0.3"
tokio-rustls = "0.23"
tokio-stream = "0.1"
tokio-util = "0.7"
toml = "0.5"
tower-layer = "0.3"
tower-service = "0.3"
tracing = "0.1"
tracing-attributes = "0.1"
tracing-core = "0.1"
tracing-futures = "0.2"
tracing-log = "0.1"
try-lock = "0.2"
typenum = "1"
unicase = "2"
unicode-bidi = "0.3"
unicode-ident = "1"
unicode-normalization = "0.1"
unicode-segmentation = "1"
unicode-width = "0.1"
unicode-xid = "0.2"
untrusted = "0.7"
url = "2"
uuid = "1"
uuid-2 = { package = "uuid", version = "0.8" }
vcpkg = "0.2"
vec_map = "0.8"
version_check = "0.9"
void = "1"
walkdir = "2"
want = "0.3"
wasi = "0.11"
webpki = "0.22"
which = "4"
winapi = "0.3"
winapi-i686-pc-windows-gnu = "0.4"
winapi-util = "0.1"
winapi-x86_64-pc-windows-gnu = "0.4"
windows-sys = "0.36"
windows_aarch64_msvc = "0.36"
windows_i686_gnu = "0.36"
windows_i686_msvc = "0.36"
windows_x86_64_gnu = "0.36"
windows_x86_64_msvc = "0.36"
yaml-rust = "0.4"
================================================
FILE: cache/default.nix
================================================
{ writeText, mkRustPackageOrWorkspace }:
let
ws = mkRustPackageOrWorkspace {
src = ./.;
};
in
writeText "cache-paths"
(toString (ws.dev.cache.dependencies ++ ws.release.cache.dependencies))
================================================
FILE: cache/src/lib.rs
================================================
================================================
FILE: crates-io-override/default.nix
================================================
{ lib, pkgs }:
let
inherit (lib) optionalAttrs listToAttrs;
inherit (builtins) compareVersions;
procMacroOverrides =
listToAttrs
(map (name: {
inherit name;
value = _: { procMacro = true; };
}) (import ./proc-macro.nix));
in
with pkgs;
procMacroOverrides //
{
libz-sys = { features, ... }: optionalAttrs (!(features ? static)) {
nativeBuildInputs = [ pkg-config ];
propagatedBuildInputs = [ zlib ];
};
openssl-sys = { features, ... }: optionalAttrs (!(features ? vendored)) {
nativeBuildInputs = [ pkg-config ];
propagatedBuildInputs = [ openssl ];
};
proc-macro-hack = { version, ... }: {
procMacro = compareVersions version "0.5.0" >= 0;
};
}
================================================
FILE: crates-io-override/proc-macro.nix
================================================
[
"a2kit_macro_derive"
"a2lmacros"
"aa-regex"
"abi_stable_derive"
"ability"
"abistr-macros"
"abomonation_derive"
"abscissa_derive"
"accel-derive"
"accessors"
"accessors-rs"
"accio"
"accursed-unutterable-type-id-derive"
"acme-derive"
"acme-macros"
"act-zero-macro"
"actionable-macros"
"activitypub_federation_derive"
"activitystreams-derive"
"actix-admin-macros"
"actix-auth"
"actix-default-responder"
"actix-easy-multipart-derive"
"actix-grants-proc-macro"
"actix-handler-macro"
"actix-json-responder"
"actix-jwt-auth-middleware-derive"
"actix-macros"
"actix-multipart-derive-impl"
"actix-multipart-extract-derive"
"actix-proc-macros"
"actix-signal-derive"
"actix-telegram-derive"
"actix-web-codegen"
"actix-web-cute-codegen"
"actix-web-error-derive"
"actix-web-lab-derive"
"actix-web-macros"
"actix_derive"
"actix_header"
"actix_responder_macro"
"actix_telepathy_derive"
"actix_validated_forms_derive"
"actori-macros"
"actori-web-codegen"
"actori_derive"
"actors-macros"
"actyx_sdk_macros"
"actyxos_sdk_macros"
"add_getters_setters"
"address-cmp"
"address-literal"
"adhoc_derive"
"adminix_macro"
"admiral-derive"
"adom"
"adorn"
"adsabs-macro"
"aegir_compile"
"aegir_derive"
"aeiou-macros"
"aeon_derive"
"af-core-proc-macros"
"af-proc-macros"
"af_path"
"affix"
"afmt"
"ag-grid-derive"
"agb_image_converter"
"agb_macros"
"agb_sound_converter"
"agnostik-attributes"
"agpu-macro"
"agui_macros"
"ahecha_macro"
"aide-macros"
"aingle_middleware_bytes_derive"
"ak-codegen"
"akin"
"akita_derive"
"aktrs-macros"
"alacritty_config_derive"
"alass-ffi-macros"
"alchemy-macros"
"alder-derive"
"aleo-std-time"
"aleo-std-timed"
"alga_derive"
"algorithmia-entrypoint"
"alipay_derive"
"alipay_macros"
"aliri_braid_impl"
"alkahest-proc"
"alloc_counter_macro"
"allochronic-util-macros"
"alpaca-lexer-derive"
"alphabet-macro"
"alt_serde_derive"
"amadeus-derive"
"amadeus-parquet-derive"
"ambassador"
"amethyst-inspector-derive"
"amethyst_derive"
"amitu_macros"
"amper_mac"
"amplify_derive"
"anansi-macros"
"anchor-attribute-access-control"
"anchor-attribute-account"
"anchor-attribute-constant"
"anchor-attribute-error"
"anchor-attribute-event"
"anchor-attribute-interface"
"anchor-attribute-program"
"anchor-attribute-state"
"anchor-cereal-derive"
"anchor-derive-accounts"
"anchor-gen"
"anchor-generate-cpi-crate"
"anchor-generate-cpi-interface"
"anchored-macros"
"anim-derive"
"annotation-rs-codegen"
"ansi-colors-macro"
"ansiform"
"anthill-di-derive"
"anu-macros"
"any_ref_macro"
"anyint_macros"
"anykind"
"anystring_macro"
"aoc-runner-derive"
"aoc-toolbox-derive"
"aoc_codegen"
"aoc_macros"
"aopt-macro"
"aorist_concept"
"aorist_derive"
"aorist_paste"
"apache-avro-derive"
"apdu-derive"
"apecs-derive"
"aper_derive"
"app_route_derive"
"appkit-derive"
"aptos-crypto-derive"
"aptos-log-derive"
"aquamarine"
"aquatic_toml_config_derive"
"ar_pe_ce_macro"
"aragog-macros"
"arangoq_derive"
"arbitrary-model-tests"
"arcdps_codegen"
"arcon_macros"
"arctk-attr"
"arctk-proc"
"arel_macro"
"arg-derive"
"arg_enum_proc_macro"
"argh_derive"
"argio-macro"
"argmin_codegen"
"argopt-impl"
"argser-macros"
"ark-api-macros"
"ark-ff-asm"
"ark-ff-macros"
"ark-serialize-derive"
"arm7tdmi_aeabi"
"arma-rs-proc"
"armature-macro"
"armour-derive"
"arr_macro_impl"
"array-const-fn-init"
"array_map_derive"
"arraygen"
"arraygen-docfix"
"arrow2_convert_derive"
"artemis-codegen-proc-macro"
"as-dyn-trait"
"as_tuple_derive"
"ascent_macro"
"ascii-literal-impl"
"askama-enum"
"askama_derive"
"asn1-rs-derive"
"asn1-rs-impl"
"asn1_codecs_derive"
"asn1_der_derive"
"asn1_derive"
"asn1rs-macros"
"asn_codecs_derive"
"assay-proc-macro"
"assemble-macros"
"assemblylift-core-guest-macros"
"assert-parse-register-assert-macro"
"assert2-macros"
"assert2ify-macros"
"assert_fn"
"asserter-macros"
"assertify_proc_macros"
"assets_manager_macros"
"associated-derive"
"ast2str-derive"
"ast_node"
"asteracea_proc-macro-definitions"
"asterix-derive"
"async-attributes"
"async-coap-uri-macros"
"async-debug-derive"
"async-ecs-derive"
"async-entry"
"async-graphql-derive"
"async-graphql-relay-derive"
"async-injector-derive"
"async-log-attributes"
"async-metronome-attributes"
"async-proto-derive"
"async-recursion"
"async-reply-derive"
"async-std-test"
"async-stream-impl"
"async-test-derive"
"async-trait"
"async-trait-ext"
"async-trait-fn"
"async-trait-static"
"async-trait-with-sync"
"async-xml-derive"
"async-zmq-derive"
"async_auto_traits"
"async_event_streams_derive"
"async_fn-proc_macros"
"async_for"
"async_init"
"async_object_derive"
"async_static"
"async_t_internal"
"async_trait_proto"
"ataraxy-macros"
"atat_derive"
"atomecs-derive"
"atomic_enum"
"atomic_hooks_macros"
"atomic_macro"
"atomig-macro"
"atomize-macro"
"attempted"
"attribute-derive-macro"
"attributes"
"attribution-macros"
"attrsets"
"aurum_actors_macros"
"autd3-traits"
"authorized_derive"
"auto-add-lifetimes-to-impl"
"auto-args-derive"
"auto-diff-macros"
"auto-enum"
"auto-impl-ops"
"auto-trait"
"auto-version"
"auto_enums_core"
"auto_enums_derive"
"auto_from"
"auto_impl"
"auto_ref"
"autocorrect-derive"
"autocxx-macro"
"autodefault"
"autodiff_injector_core_derive"
"autodo_helper"
"autoerror"
"autograph_derive"
"autoimpl-derive"
"autoincrement_derive"
"autoload"
"autolog"
"automate-derive"
"automato"
"automato_sync"
"automato_sync_non_mut"
"automod"
"autorand-derive"
"autowired-derive"
"auxtools-impl"
"avalanche-macro"
"avantis-utils-derive"
"aversion-macros"
"avocado_derive"
"avr-device-macros"
"awesome-glib"
"awf-codegen"
"awint_macros"
"awmpde_derive"
"awred"
"aws-smt-ir-derive"
"awto-macros"
"axum-debug"
"axum-debug-macros"
"axum-derive-error"
"axum-macros"
"axum-route"
"axum_client_derive"
"ay"
"azalea-block-macros"
"azalea-buf-macros"
"azalea-protocol-macros"
"azalea-registry-macros"
"azul-peek-poke-derive"
"azure-functions-codegen"
"azure-functions-shared-codegen"
"baburu-macros"
"bachue-auto_impl"
"bae"
"baker"
"bakery-derive"
"bakkesmod-macros"
"banjin"
"baroque"
"bart_derive"
"bash_builtins_macro"
"basic-text-literals"
"batbox-derive"
"batch-codegen"
"bdk-macros"
"bdk-testutils-macros"
"be-generust"
"beamcode_derive"
"bean-macro"
"bearings-proc"
"bee-common-derive"
"below_derive"
"bencher-macro"
"benvolio"
"bern-kernel-macros"
"bern-test-macros"
"beserial_derive"
"best_macros"
"better-bae-macros"
"better-macro"
"better_typeid_derive"
"bevy-contrib-inspector-derive"
"bevy-crevice-derive"
"bevy-inspector-egui-derive"
"bevy_aseprite_derive"
"bevy_asset_loader_derive"
"bevy_console_derive"
"bevy_derive"
"bevy_dioxus_macro"
"bevy_discovery"
"bevy_ecs_ldtk_macros"
"bevy_ecs_macros"
"bevy_editor_iris_derive"
"bevy_encase_derive"
"bevy_fallible_derive"
"bevy_hecs_macros"
"bevy_mod_check_filter_macros"
"bevy_mod_scripting_derive"
"bevy_mod_sysfail_macros"
"bevy_property_derive"
"bevy_proto_derive"
"bevy_reflect_derive"
"bevy_render_macros"
"bevy_state_macros"
"bevycheck"
"bf-impl"
"bian-proc"
"big_enum_set_derive"
"bigbang_derive"
"bigml_derive"
"bin-layout-derive"
"bin_codec_derive"
"binary_enclave_macro"
"binary_macros_impl"
"bincode-grpc-macro"
"bincode_derive"
"bind_it"
"bindata-derive"
"bindata-impl"
"bingen"
"binhoc_macros"
"binprot_derive"
"binread_derive"
"binreader-macros"
"binrw_derive"
"binser-derive"
"binserde_derive"
"binver_derive"
"binverse_derive"
"binwrite_derive"
"bio-seq-derive"
"bird-machine-macros"
"bird-protocol-derive"
"biscuit-quote"
"bit-by-bit"
"bit_collection_derive"
"bit_manager_derive"
"bitaccess_macros"
"bitbag_derive"
"bitbar-derive"
"bitbash-macros"
"bitbuffer_derive"
"bitbybit"
"bitcoin-cash-code"
"bitcoin-cash-script-macro"
"bitcoin-script"
"bitf"
"bitfield-derive"
"bitfield-register-macro"
"bitfield-struct"
"bitmask-enum"
"bitmatch"
"bitmath_macros"
"bitpattern"
"bitpatterns-proc-macro"
"bitrange_plugin"
"bitregions-impl"
"bitset-const-macros"
"bitsparrow-derive"
"bitstream_reader_derive"
"bitstruct_derive"
"bittwiddler"
"bitwrap_derive"
"bitwrap_derive_extra"
"bk2d-macro"
"bl602-macros"
"black_marlin-macros"
"blackbox_derive"
"blanket"
"blaze-proc"
"block_effects"
"block_on_proc"
"blocked"
"blockz_derive"
"bloom42_diesel_as_jsonb"
"blpapi-derive"
"bm-le-derive"
"bma-benchmark-proc"
"bmart-derive"
"bmw-derive"
"bointer-derive"
"bolero-generator-derive"
"bolt-client-macros"
"bolt-proto-derive"
"bondrewd-derive"
"bonfida-macros"
"bonsaidb-macros"
"boolenum"
"boomerang_derive"
"border-derive"
"borsh-derive"
"bot-rs-core-derive"
"botanist_codegen"
"boulder_derive"
"bounce-macros"
"bounded-integer-macro"
"bounded-static-derive"
"box_shorthand"
"boxext_derive"
"bpaf_derive"
"bpf-rs-macros"
"bpxe-internal-macros"
"brain_fuck"
"bronze_derive"
"brush_contracts_derive"
"brush_lang_macro"
"bruteforce-macros"
"bstring_macros_hack"
"bstringify"
"btmgmt-packet-macros"
"buffalo_macro"
"buffering_nocopy_macro"
"build-features"
"build-info-proc"
"build-time"
"build-trie"
"build_cfg_macros"
"build_timestamp"
"builder-pattern-macro"
"buildstructor"
"bullet_macros"
"bunt-macros"
"burn-derive"
"butane_codegen"
"butcher_proc_macro"
"buttplug_derive"
"bve-derive"
"byewlma-macros"
"bystr-impl"
"byte-enum-derive"
"byte-slab-derive"
"byte-strings-proc-macro"
"byte-strings-proc_macros"
"byte_eater"
"byte_struct_derive"
"bytecheck_derive"
"byteme"
"bytemuck_derive"
"bytepack_derive"
"bytes-cast-derive"
"bytes-lit"
"bytestream_derive"
"bytey_derive"
"bytify-impl"
"c-like-concat"
"c2rs"
"c2rust-bitfields-derive"
"c2rust-macros"
"c3-lang-macro"
"c3p0_diesel_macro"
"c_api_prefix"
"c_import"
"c_macros"
"cache-macro"
"cached_proc_macro"
"cached_property"
"cagra-parser"
"cain"
"cairo-svgpath"
"calcite_proc_macros"
"calculagraph"
"call-trace-macro"
"caller_modpath_macros"
"calmio_filters"
"cameleon-impl-macros"
"camelpaste"
"camo-derive"
"can-bit-timings-proc-macro"
"canadensis_derive_register_block"
"canadensis_macro"
"canary-macro"
"candid_derive"
"canonical_derive"
"canrun_codegen"
"cantor_macros"
"capsule-macros"
"captures"
"carapax-codegen"
"carbide_derive"
"cardparse_derive"
"cargho_derive"
"cargo-kconfig"
"cargo-snippet"
"cargo-up-derive"
"cargo_equip_marker"
"cargo_meta_proc"
"carrier-pigeon-netmsg-derive"
"cascading-wasm-language"
"casey"
"casper-node-macros"
"casper_types_derive"
"cassandra_macro_derive"
"casserole-derive"
"cast_trait_object_macros"
"castflip_derive"
"castle_macro"
"catalytic_macro"
"catch_panic_macros"
"catchr"
"catinator_macros"
"cbor_enhanced_derive_protocol"
"cbordata-derive"
"cbored-derive"
"cdbc-macro"
"cdds_derive"
"cde_codegen"
"cdefines"
"cdr-encoding-size-derive"
"cdrs-tokio-helpers-derive"
"cdrs_helpers_derive"
"cdrs_helpers_derive_temp"
"celery-codegen"
"celeste_derive"
"cell-map-macro"
"cenum"
"cenum-derive"
"ceres-derive"
"cex_derive"
"cffi-impl"
"cfg-derive"
"cglue-macro"
"chain-cmp"
"chalk-derive"
"channel-server-derive"
"char-lex-macro"
"charify"
"chassis"
"chazi_macros"
"checked_decimal_macro_core"
"checked_expr"
"checkers-macros"
"checkout_server_derive"
"chekov_macros"
"cherry-derive"
"chia_streamable_macro"
"chikatetsu-macros"
"choices-derive"
"chrome-native-macros"
"chronobreak_derive"
"chrony-candm-derive"
"circus_test"
"citerne-derive"
"ckb-fixed-hash-macros"
"ckb-migration-template"
"ckb-occupied-capacity-macros"
"cl-traits-derive"
"clams-derive"
"clap-handler-derive"
"clap-vergen-macro"
"clap_derive"
"clap_derive-v3"
"clapi_internal"
"clapi_macros"
"clapme_derive"
"clean-macro-docs"
"cleu-orm-derive"
"cli-editor"
"cli-errors-macros"
"cli-table-derive"
"cli-toolbox"
"clickhouse-derive"
"clickrs_proc_macro"
"clightningrpc-plugin-macros"
"climer_derive"
"clingo-derive"
"clippy-mini-macro-test"
"clone-fields-derive"
"clone_cell_derive"
"clone_dyn_meta"
"closure-pass"
"clouseau_macros"
"cmd-derive"
"cmd_lib_cf_macros"
"cmd_lib_macros"
"cmd_wrk_macros"
"cmdargs-macros"
"cmdparse-derive"
"cmdr_macro"
"cntrlr-macros"
"code-hasher"
"code-sandwich-crates-io-release-test-macros"
"code-tour"
"code_snippet_generator"
"codesnip_attr"
"codespan-derive-proc"
"coerce-macros"
"coffer-macros"
"coi-actix-web-derive"
"coi-derive"
"coi-rocket-derive"
"coil_proc_macro"
"col_proc_macros_impl"
"collections-fromstr"
"color-hex"
"color-macro"
"color-print-proc-macro"
"column_derive"
"column_store_proc_macros"
"com_macros"
"combination-err"
"comet-rs-impl"
"command-macros-plugin"
"command_attr"
"commander-macros"
"commandy_macros"
"comn-pms"
"compact_macros"
"compact_sql"
"comparable_derive"
"comparable_helper"
"compare_by_address_derive"
"compile-ints"
"compile-time-crc32-impl"
"compile-time-create-file"
"compile-time-lisp"
"compile-time-lua-bind-hash"
"compile-time-run"
"compile-time-run-macro"
"compile_ops"
"compiled-uuid"
"compiler-tools-derive"
"compiletime"
"completion-macro"
"component_group_derive"
"compose-derive"
"compound-error"
"comprehension"
"comprez_macro"
"comptime"
"concat-arrays"
"concat-idents"
"concat_strs_impl"
"concision-derive"
"concision-macros"
"concordium-contracts-common-derive"
"concordium-std-derive"
"concourse-resource-derive"
"condition-derive"
"conditional_impl"
"config-derive"
"config_parser_derive"
"configr_derive"
"configure_derive"
"configurs_derive"
"confique-macro"
"conflagrate-macros"
"conform-derive"
"conformance"
"confql-proc-macro"
"confu_derive"
"conniecs-derive"
"conrod_derive"
"consecuit_macros"
"const-array-attrs"
"const-c-str-impl"
"const-default-derive"
"const-enum"
"const-enum-tools-derive"
"const-field-offset-macro"
"const-gen-derive"
"const-random-macro"
"const-regex"
"const-source-position"
"const-table"
"const-tweaker-attribute"
"const_cge_macro"
"const_fn"
"const_format_proc_macros"
"const_guards_attribute"
"const_internals"
"const_num_bigint_derive"
"const_panic_proc_macros"
"const_strum"
"const_trait_impl"
"constant-cstr"
"constany_blank"
"constany_stage_one"
"constany_stage_two"
"constduck-procmacro"
"constexpr-macros"
"constlua"
"constrainer"
"constructor-macro"
"consulrs_derive"
"context-attribute"
"continuation-router-syn"
"contraband_codegen"
"contracts"
"contrail-derive"
"controlled-option-macros"
"contructor-derive"
"converge_derive"
"converge_test"
"convert-enum"
"convert-js-macros"
"convert_by_name"
"convey_derive"
"cooked-waker-derive"
"core_extensions_proc_macros"
"corewars-parser-macro"
"cornetto"
"corresponding-macros"
"cortex-m-funnel-macros"
"cortex-m-rt-macros"
"cortex-m-rtfm-macros"
"cortex-m-rtic-macros"
"cosmian-wit-bindgen-rust-impl"
"cosmic-macros"
"cosmic-macros-primitive"
"cosmwasm-derive"
"cosmwasm-schema-derive"
"couch_rs_derive"
"count-macro"
"count-tys"
"count_tts"
"counting-macros"
"courier"
"coverage-helper"
"covers"
"cow_struct"
"cpclib-macros"
"cpp-inherit"
"cpp_macros"
"cppvtbl-macros"
"cpreprocess"
"cps"
"cqrs_macro"
"crabler_derive"
"crate-_-name"
"craydate-macro"
"crayfish-macros"
"crayfish-trace-macros"
"crcany-macro"
"creator-derive"
"crepe"
"crevice-derive"
"crevice_notan-derive"
"criterion-macro"
"crndm_derive"
"crochet_macro"
"crokey-proc_macros"
"crossbundle-derive"
"cruiser_derive"
"cryiorust_derive"
"crypto-literal-macro"
"cryptraits-macros"
"css-loader-macros"
"css-modules-macros"
"css-rs-macro"
"cssparser-macros"
"cstr"
"cstr-enum-derive"
"cstr-macros"
"ct-for"
"ctc"
"ctchi_codegen"
"ctflag_derive"
"ctor"
"cuach-derive"
"cubic-protocol-derive"
"cucumber-codegen"
"cucumber_rust_codegen"
"cuda_std_macros"
"cuneiform"
"cur_macro"
"cust_derive"
"custom-format-macros"
"custom-slice-macros"
"custom_debug_derive"
"cute_custom_default"
"cutlass"
"cvars"
"cw-storage-macro"
"cxx-async-macro"
"cxx-qt"
"cxxbridge-macro"
"cyfs-base-derive"
"cynic-proc-macros"
"cynthia-macros"
"cypher_derive"
"d3-derive"
"dacquiri_derive"
"dade_derive"
"dade_macro"
"dag-cbor-derive"
"daml-derive"
"dapr-derive"
"darkly-macros"
"darksteel-codegen"
"darling_macro"
"darpi-code-gen"
"dashu-macros"
"data-encoding-macro-internal"
"data-query-proc"
"data-url-encode-macro-impl"
"data_doc_derive"
"datasize_derive"
"datastore_derive"
"datatest-derive"
"db-derive-impl"
"db-helpers-derive"
"db_ip_macros"
"dbfile_derive"
"dbg-pls-derive"
"dbi-macros"
"dbstruct-derive"
"dbus-async-derive"
"dcc-lsystem-derive"
"dd_maths_traits_macros"
"ddd_dapr_derive"
"dddk_macro"
"de-ref"
"deasync"
"debcontrol_struct_derive"
"debil-derive"
"debug-derive"
"debug-try"
"debug2-derive"
"debug3-derive"
"debug_stub_derive"
"debugger_test"
"declio_derive"
"decorators"
"decurse_macro"
"dede"
"deen-proc"
"deepsize_derive"
"def-mod"
"default-args"
"default-boxed-derive"
"default-conversion"
"default-env"
"default_kwargs"
"defaults"
"defile-proc_macros"
"defmt-macros"
"defmt-test-macros"
"defs"
"defunctionalize-proc-macro"
"degeneric-macros"
"deku_derive"
"delegate"
"delegate-attr"
"deltastruct_proc"
"deltoid-derive"
"deluge-rpc-macro"
"demo-hack-impl"
"dendrite_macros"
"dengine_derive"
"deno_bindgen_macro"
"deno_json_op"
"deno_ops"
"depcon_codegen"
"deprive"
"deq_macros"
"deque-loader-derive"
"der-oid-macro"
"der_derive"
"deranged-macros"
"derefable"
"derivate"
"derivation"
"derivative"
"derive-adhoc-macros"
"derive-aktor"
"derive-collect-docs"
"derive-com-impl"
"derive-com-wrapper"
"derive-debug-extras"
"derive-deref-rs"
"derive-diesel-connection"
"derive-diff"
"derive-dynamic-node"
"derive-enum-error"
"derive-enum-from-into"
"derive-env-url"
"derive-error"
"derive-error-chain"
"derive-ex"
"derive-finite-automaton-derive"
"derive-from-ext"
"derive-getters"
"derive-hex"
"derive-into-owned"
"derive-knet"
"derive-new"
"derive-newtype"
"derive-object-merge"
"derive-ocaml"
"derive-parse"
"derive-partial-eq-extras"
"derive-patch"
"derive-redis-json"
"derive-redis-swapplex"
"derive-serialize-into"
"derive-syn-parse"
"derive-system"
"derive-try-from-primitive"
"derive-where"
"derive_asref"
"derive_bounded"
"derive_builder_macro"
"derive_builder_macro_fork_arti"
"derive_codec_sv2"
"derive_constructor"
"derive_custom_enum_traits"
"derive_deref"
"derive_derive"
"derive_destructure"
"derive_destructure2"
"derive_di_macro"
"derive_display_from_debug"
"derive_dumb"
"derive_enum_macros"
"derive_from_as"
"derive_jface"
"derive_less"
"derive_merge"
"derive_miniconf"
"derive_more"
"derive_pod"
"derive_rich"
"derive_setters"
"derive_type_level"
"derive_weak"
"derive_wrapper"
"derived"
"derivenum"
"descent_macro"
"descriptor_derive"
"deser-derive"
"deserialize_xml_derive"
"despatma"
"desse-derive"
"dessert-derive"
"destruct-derive"
"destruct-drop-derive"
"desugar"
"desugar-impl"
"devault"
"devbox-test-args"
"device-register-macro"
"devise_codegen"
"df_rocket_okapi_codegen"
"df_st_derive"
"dhall_proc_macros"
"dialectic-macro"
"dialoguer_macro"
"dialtone_sqlx_macros"
"dict_derive"
"diem-crypto-derive"
"diem-framework-crypto-derive"
"diesel-crud-codegen"
"diesel-derive-enum"
"diesel-derive-more"
"diesel-derive-newtype"
"diesel-ease"
"diesel-enum"
"diesel-factories-code-gen"
"diesel-selectable-macro"
"diesel-sort-struct-fields"
"diesel_as_jsonb"
"diesel_codegen"
"diesel_derive_model"
"diesel_derives"
"diesel_derives_extra"
"diesel_enum_derive"
"diesel_filter_query"
"diesel_findable"
"diesel_mate_derive"
"diff-enum"
"diff_derive"
"diffus-derive"
"dill-impl"
"dims_derive"
"diny_derive"
"dionysos-derives"
"dioptre-derive"
"dioxus-core-macro"
"dioxus-html-macro"
"dioxus-native-core-macro"
"dioxus-table-macro"
"dioxus-use-request-macro"
"dipa-derive"
"diplomat"
"direct-asm"
"director_macros"
"directree_macros"
"dirmod-codegen"
"dis_rs_macros"
"disabled_contracts"
"disarray-derive"
"disarray-macros"
"disc-derive"
"discord_typed_interactions_proc_macro"
"discrab_codegen"
"discretionary"
"discrim-codegen"
"discrimenum"
"discriminant_hash_derive"
"disp"
"display-as-proc-macro"
"display_adapter_attr"
"display_attr"
"display_derive"
"display_json"
"display_json_derive"
"displaydoc"
"displaydoc-lite-proc_macros"
"displaydoc-watt"
"displaythis-impl"
"dispose-derive"
"distill-serde-importable-derive"
"dizpacho"
"django-query_derive"
"djin-protocol-derive"
"dlhn_derive"
"dlopen2_derive"
"dlopen_derive"
"dmutils_derive"
"dmv_derive"
"doc-cfg"
"doc-since"
"doc_item"
"doc_link"
"docbot-derive"
"dock-derive"
"document-features"
"docx-codegen"
"dodo-derive"
"dogehouse-macros"
"doku-derive"
"domain_derive"
"dont-expand"
"doodle_derive"
"dos-uid-derive"
"dose-derive"
"dosio-macros"
"dotenv_codegen_impl"
"dotenv_codegen_implementation"
"dotenv_config"
"dotenvy_codegen_impl"
"dotinstall-macro"
"double-dyn"
"doubter-macros"
"dough"
"draw_bridge_derive"
"drm-macros"
"drone-core-macros"
"drone-cortex-m-macros"
"drone-cortexm-macros"
"drone-macros"
"drone-riscv-macros"
"drone-stm32-macros"
"drone-sx1276-macros"
"drop-derive"
"drop_struct_macro_derive"
"dropshot_endpoint"
"druid-derive"
"druid-lens-compose"
"dry"
"dtd-macro"
"dtn7-codegen"
"dto_derive"
"dtypei-derive"
"duang"
"dukt-macros"
"duktape-macros"
"dummy"
"duplicate"
"dusk-proc-macros"
"dxr_derive"
"dylink_macro"
"dyn-any-derive"
"dyn-clonable-impl"
"dyn-context-macro"
"dyn-dyn-macros"
"dyn_partial_eq_derive"
"dyn_safe-proc_macros"
"dyn_struct_derive"
"dyn_struct_derive2"
"dynamic-object-derive"
"dynamize"
"dynamo_mapper_macro"
"dynasm"
"dync-derive"
"dynomite-derive"
"dynpath"
"e_num_derive"
"ea"
"easy-csv-derive"
"easy-ext"
"easy-jsonrpc-proc-macro"
"easy-jsonrpc-proc-macro-mw"
"easy-pin-proc-macro"
"easy_pool_proc_macro"
"easy_proc_derive"
"easy_proc_macro"
"ebay_derive"
"ebml-iterable-specification-derive"
"ebpf-kern-macros"
"ebpf-user-macros"
"ecal-derive"
"econf-derive"
"ector-macros"
"ed-derive"
"ed2-derive"
"edgedb-derive"
"edgedb-query-derive"
"edgedb-sdk-macros"
"edited"
"edn-derive"
"educe"
"eff-attr"
"efg"
"efmt_derive"
"eg_derive"
"egui_inspect_derive"
"eiga_builder_derive"
"einops-macros"
"either_trait_macro"
"eko-gc-derive"
"elapsed-printer"
"elapsed-time"
"elastic_derive"
"elastic_types_derive"
"elephantry-derive"
"elfo-macros"
"elise-derive"
"elm_rs_derive"
"elm_rusty"
"elrond-codec-derive"
"elrond-wasm-derive"
"elucify"
"elvis-core-support"
"elvis-derive"
"emacs-macros"
"embed-doc-image"
"embed_js_derive"
"embedded-error-chain-macros"
"embedded-layout-macros"
"embedded-profiling-proc-macros"
"embeddir"
"empty_type_derive"
"emu_glsl"
"emu_macro"
"emv-qrcps-derive"
"encase_derive"
"encdec-macros"
"encoding-asn1-derive"
"encrypted_id_derive"
"encryption-macros-encryption"
"encryption-macros-key-generation"
"endian_codec_derive"
"endian_trait_derive"
"endiannezz_derive"
"eng-wasm-derive"
"enpow"
"ensicoin_serializer_derive"
"enso-shapely-macros"
"entity-async-graphql-macros"
"entity-gym-derive"
"entity_macros"
"entity_noop_macros"
"entrait_macros"
"entrance_derive"
"enum-as-derive"
"enum-as-inner"
"enum-assoc"
"enum-display-derive"
"enum-each-variant-derive"
"enum-error-derive"
"enum-flags"
"enum-group"
"enum-iterator-derive"
"enum-kinds"
"enum-kinds-macros"
"enum-lexer-macro"
"enum-map-derive"
"enum-methods"
"enum-ordinalize"
"enum-other"
"enum-primitive-derive"
"enum-primitive-derive-nostd"
"enum-repr"
"enum-repr-derive"
"enum-tags-macros"
"enum-tryfrom-derive"
"enum-utils"
"enum-variants-strings-derive"
"enum_access"
"enum_coder"
"enum_const_derive"
"enum_const_value"
"enum_cycling_derive"
"enum_default"
"enum_derive_list"
"enum_dispatch"
"enum_for_matches"
"enum_from_str_derive"
"enum_index_derive"
"enum_kind"
"enum_like_derive"
"enum_pipeline_derive"
"enum_to_enum_derive"
"enum_to_str_derive"
"enum_to_u8_slice_derive"
"enum_traits_macros"
"enum_variant_macros_macros"
"enum_variant_type"
"enumber"
"enumer_derive"
"enumerare-macros"
"enumerate"
"enumflags2_derive"
"enumflags_derive"
"enumn"
"enumoid_derive"
"enumscribe_derive"
"enumset_derive"
"enumx_derive"
"env-cast"
"env-config"
"env_ast"
"env_derive"
"env_proc"
"envconf_derive"
"envconfig_derive"
"envcrypt-macro"
"envdot"
"envir_derive"
"envload_derive"
"envopt-derive"
"eosio-macro"
"eosio-scale-info-derive"
"eosio_bytes_derive"
"eosio_macros_internal"
"eosio_numstr_macros_impl"
"ephem_derive"
"epics-sys"
"epoxy_macros"
"epp-client-macros"
"equalia"
"eraserhead-derive"
"ergo-pin"
"ergo_headless_dapp_framework_derive"
"ergol_proc_macro"
"erl_nif_macro"
"err-derive"
"err-gen"
"err-per-field-derive"
"errer_derive"
"erroneous-derive"
"error-chain-mini-derive"
"error-chain-utils"
"error-gen"
"error-rules"
"error-stack-derive"
"error-stack-macros"
"error-utils-derive"
"error_generator"
"error_spanned_derive"
"errorderive"
"erst-derive"
"escher-derive"
"esize"
"esp-hal-procmacros"
"esp32-hal-proc-macros"
"esp8266-hal-proc-macros"
"espr-derive"
"essrpc_macros"
"etanol_macros"
"eternal-macro"
"eth2_ssz_derive"
"eth_event_macro"
"eth_pairings_repr_derive"
"ethabi-derive"
"ethaddr-macros"
"ethanol-derive"
"ethcontract-derive"
"ethdigest-macros"
"ethercat-derive"
"ethers-contract-derive"
"ethers-derive-eip712"
"ethnum-macros"
"eu"
"euclid_macros"
"euphony-core-macros"
"euphony-macros"
"ev3dev-lang-rust-derive"
"ev3robot_macros"
"eva-sdk-derive"
"evegfx-macros"
"eventmill_derive"
"eventsourcing-derive"
"ever-macro"
"every_variant_macro"
"everyday_macros"
"evitable-derive"
"evm-precompiles-derive"
"evmap-derive"
"evmc-declare"
"exclusive"
"exec_time"
"executor-macros"
"exhaust-macros"
"exit_status"
"exocore-apps-macros"
"exonum-derive"
"exotic_macro"
"expand"
"expectation_plugin"
"expose"
"expression_format_impl"
"expry_macros"
"ext-php-rs-derive"
"ext-trait-proc_macros"
"extargsparse_codegen"
"extdot-impl"
"extend"
"extends-rs"
"extension-trait"
"extprim_literals_macros"
"extra_args"
"ez-proc-macro"
"ezinput_macros"
"ezjsonrpc-macros"
"ezmenu-derive"
"ezmenu-macros"
"f128_input"
"f64ad_core_derive"
"fabric-support-procedural"
"fabric-support-procedural-tools-derive"
"fabric_contract_macros"
"factori-impl"
"factory_steel_derive"
"fail_on_ci"
"failure_derive"
"failure_derive_without_backtrace"
"fake_serialize"
"fallacy-clone-derive"
"fallback-derive"
"fancy"
"fantasy-cpu-emulator-macros"
"far_macros"
"fast-map-derive"
"fast-rustc-ap-rustc_macros"
"fast_new_type"
"fast_tuple"
"fastcrypto-derive"
"fasters_derive"
"fastly-macros"
"fastobo-derive-internal"
"fastrlp-derive"
"fatality-proc-macro"
"fates_macro"
"faux_macros"
"fawkes-crypto_derive"
"fax_derive"
"fbinit_macros"
"fbthrift_codegen_includer_proc_macro"
"fce-timestamp-macro"
"fefix_derive"
"fehler-macros"
"feign-macros"
"feignhttp-codegen"
"fem-macros"
"feo-oop-engine-proc-macros"
"feos-derive"
"ferric-macros"
"ferris-extensions"
"ferris-gc-proc-macro"
"festive-macros"
"ff-derive-num"
"ff-uint_derive"
"ff_derive"
"ff_derive-zeroize"
"ff_derive_ce"
"fff_derive"
"ffi-convert-derive"
"ffi-export-proc-macro"
"ffi-gen-macro"
"ffishim_derive"
"ffizz-macros"
"fi-night"
"field-derive"
"field_accessor"
"field_count_derive"
"field_names"
"field_types"
"fieldfilter-derive"
"fieldmask_derive"
"fields-converter-derive"
"fieldwise"
"fievar"
"file-metadata-mditem-macros"
"finchers-derive"
"finite_repr_derive"
"finiteelement_macros"
"finny_derive"
"finte-derive"
"fire-rs-core"
"fitsio-derive"
"fix-hidden-lifetime-bug-proc_macros"
"fix-rs-macros"
"fixed-codec-derive"
"fixed-macro-impl"
"fixed-map-derive"
"fixed-point-macros"
"fixed_len_str"
"fixed_typemap_macros"
"fixed_width_derive"
"fj-proc"
"flag-mast-derive"
"flaggy-codegen"
"flaky_test"
"flarie_macros"
"flat-bytes-derive"
"flatk-derive"
"flatty-macros"
"flax-derive"
"flexiber_derive"
"flexible-locks_derive"
"flexpiler_derive"
"flickr_derive"
"float_eq_derive"
"floccus-proc"
"flow_impl_derive"
"flow_macro"
"flowmacro"
"flowutils"
"fltk-derive"
"fltk-form-derive"
"fluence-fork-libp2p-core-derive"
"fluence-fork-libp2p-swarm-derive"
"fluence-sdk-macro"
"fluence-sdk-test-macro"
"fluent-impl"
"fluent-template-macros"
"fluid_attributes"
"fluidity-derive"
"fluidity-macros"
"flutter_rust_bridge_macros"
"fluvio-protocol-derive"
"fluvio-smartmodule-derive"
"fluvio-smartstream-derive"
"fluvio-test-derive"
"fmt-derive-proc"
"fn-error-context"
"fn-fixture"
"fn_abi"
"fn_has_this"
"fn_mut"
"fn_once"
"fn_type_alias"
"fncmd-impl"
"fnsql-macro"
"fnum-derive"
"fold_impls"
"fondant_derive"
"for_any"
"for_ch"
"foreign-types-macros"
"foreignc_derive"
"forever-rs"
"formal_spec"
"format-bytes-macros"
"format-macro"
"format_env"
"former_derive"
"former_meta"
"formy_derive"
"fort"
"fortify_derive"
"forward_goto"
"foundationdb-macros"
"four-char-code-macros-impl"
"fp-bindgen-macros"
"fpdec-macros"
"fraco_point_derive"
"fractk_macro"
"frame-support-procedural"
"frame-support-procedural-tools-derive"
"frc42_macros"
"freeze-macros"
"frender-macros"
"frenezulo-macros-beta"
"frodobuf-derive"
"from-enum-derive"
"from-mapper-derive"
"from-regex-macros"
"from-repr-enum-derive"
"from-to-repr"
"from_bytes_derive"
"from_file_derive"
"from_hashmap"
"from_int_derive"
"from_remote_derive"
"from_tuple"
"from_value_derive"
"from_variant"
"from_variants_impl"
"fruit-salad_proc-macro-definitions"
"frunk-enum-derive"
"frunk_derives"
"frunk_proc_macros_impl"
"fs_pro_macros"
"fstrings-proc-macro"
"fstrings-rust-proc-macro"
"fuel-pest_derive"
"fuel_codegen"
"fuel_line_derive"
"fuels-abigen-macro"
"fui_macros"
"full_moon_derive"
"func_core"
"func_trace"
"funcmap_derive"
"function-frame"
"function_docs"
"function_from_equation"
"function_group"
"function_name-proc-macro"
"functionate"
"funtime"
"futility-try-catch"
"future-union-impl"
"futures-async-stream-macro"
"futures-await-async-macro"
"futures-await-test-macro"
"futures-await-test-macro-preview"
"futures-cputask-derive"
"futures-derive"
"futures-enum"
"futures-join-macro-preview"
"futures-macro"
"futures-macro-async"
"futures-macro-async-preview"
"futures-macros-lite"
"futures-net-macro"
"futures-select-macro-preview"
"futures-signals-structs-derive"
"futurize-derive"
"fuzzcheck_mutators_derive"
"fuzzy-pickles-derive"
"fxsm-derive"
"fyrox-core-derive"
"g1-macros"
"g2gen"
"gaclen_shader"
"gallium_ecs_derive"
"galvanic-mock"
"game-metrics-macro"
"game_kernel_ecs_derive"
"gantz-derive"
"gauge-mac-derive"
"gazebo_derive"
"gba-proc-macro"
"gc-arena-derive"
"gc_derive"
"gcad"
"gcad_proc_macros"
"gcmodule_derive"
"gdnative-derive"
"gdnative-impl-proc-macros"
"gdnative-macros"
"gdrust_macros"
"gekko-generator"
"gem-macros"
"gemachain-frozen-abi-macro"
"gemachain-sdk-macro"
"gen-nested-iter-yield"
"gen_attributes_interface_generator"
"genawaiter-proc-macro"
"genco-derive"
"genco-macros"
"generate-derive"
"generate-random-macro"
"generate_sql"
"generates"
"generic-bytes-derive"
"generic-derive"
"generic-new"
"generic-predicates-macro"
"generic-simd-macros"
"generic-tests"
"generic_parameterize"
"generoust"
"genesis-impl"
"geng-derive"
"geng-ecs-derive"
"geng-ui-derive"
"genserver_codegen"
"gensym"
"gentian"
"gents_derives"
"geobacter-runtime-amd-macros"
"geoip2-codegen"
"germ-macros-impl"
"get-random-const"
"get-size-derive"
"get_len_base_10_as_usize_macros"
"get_params_derive"
"getset"
"getset-scoped"
"getter-derive-rs"
"getters-by-type"
"gettext-macros"
"gf256-macros"
"gfaas-macro"
"gff-derive"
"gflags-derive"
"gflags-impl"
"gfx_macros"
"ggplot-derive"
"ghost"
"ghosts-proc_macros"
"giftwrap"
"git-testament-derive"
"git-version-macro"
"git_rev"
"gitarena-macros"
"gitver"
"glade_derive"
"gladis4_proc_macro"
"gladis_proc_macro"
"glib-macros"
"glicol_macros"
"glitchup_derive"
"glium_derive"
"gll-macros"
"gll-pg-macros"
"glsl-lang-quote"
"glsl-layout-derive"
"glsl-quasiquote"
"glsl-to-spirv-macros-impl"
"glsp-proc-macros"
"glsp-proc-macros2"
"gltf-derive"
"gluon-salsa-macros"
"gluon_codegen"
"gmod-macros"
"go-away-derive"
"goglob-proc-macro"
"golang-type-decl-macro"
"golang-type-macro"
"golang-type-name-macro"
"goldberg"
"golem-rpc-macros"
"goods-proc"
"google-cloud-derive"
"gorm_macros"
"gostd_derive"
"gotham_derive"
"gotham_formdata_derive"
"gotham_restful_derive"
"gpkg-derive"
"gpt3_macro"
"graal-bindgen-macros"
"gradients-derive"
"grafana-plugin-sdk-macros"
"gramatika-macro"
"grammar-tech-macro"
"graphannis-malloc_size_of_derive"
"graphblas_sparse_linear_algebra_proc_macros"
"graphite_binary_macros"
"graphite_command_macros"
"graphql_query_derive"
"graphrpc-derive"
"grass-macro"
"grb-macro"
"greenie-proc"
"gremlin-derive"
"group_derive"
"grpc-build-derive"
"gs11n_derive"
"gsettings-macro"
"gtk-blueprint"
"gtk-properties-macro"
"gtk-rust-app-derive"
"gtk3-macros"
"gtk4-macros"
"gtk_liststore_item_derive"
"gtmpl_derive"
"guard_let"
"gui-derive"
"guid-macro-impl"
"gull_derive"
"gumdrop_derive"
"gusket-codegen"
"gut-derive"
"gut-plugin"
"guzzle-derive"
"gvariant-macro"
"gvdb-macros"
"gxi-derive"
"gxi-macros"
"gxi-transpiler"
"gxi_macro"
"hackfn"
"hacspec-attributes"
"halcyon_macro_impl"
"hanger"
"hannibal-derive"
"happi-derive"
"hard-xml-derive"
"harled_macro"
"harmony_derive"
"haru-decorator"
"has_command"
"hash32-derive"
"hashfn"
"hashmap_derive"
"hazmat-macros"
"hazy_derive"
"hb_macros"
"hcaptcha_derive"
"hdf5-derive"
"hdk_derive"
"hdk_proc_macros"
"he_di_derive"
"headers-derive"
"heapsize_derive"
"heck-but-macros"
"hecs-component-provider-macros"
"hecs-macros"
"hedera_rust_client_derive"
"heim-derive"
"helper"
"helper_fn"
"herald_derive"
"heron_macros"
"hesione_macros"
"hesoyam_macro"
"hex-literal-impl"
"hex-magic"
"hexbytes"
"hexf"
"hexf-impl"
"hippo-macro"
"hippotat-macros"
"hirola-macros"
"hirpdag_derive"
"hitbox-derive"
"hlbc-derive"
"hoax"
"hobo_css_macros"
"hobo_derive"
"hodoku"
"hoist_temporaries"
"holium-macro"
"holochain_json_derive"
"holochain_serialized_bytes_derive"
"holochain_tracing_macros"
"hot-lib-reloader-macro"
"hotg-rune-proc-block-macros"
"hotpatch_macros"
"houseflow-macros"
"hrpc-proc-macro"
"hstrace_derive"
"html-extractor-macros"
"html-macro"
"html-to-string-macro"
"http-api-problem-derive"
"httpmock-macros"
"huber-procmacro"
"hubpack_derive"
"humphrey_json_derive"
"hyperbole_macros"
"hyperderive"
"hypermod"
"hypersearch_codegen"
"i-macros"
"i-slint-core-macros"
"i18n-embed-fl"
"i18n-embed-impl"
"i18n-macro"
"i18n_codegen"
"i2c-reg-derive"
"iai_macro"
"ibuilder_derive"
"ic-cdk-macros"
"ic-event-hub-macros"
"ic-kit-macros"
"ice-derive"
"iced_focus_derive"
"icu_provider_macros"
"id-derive"
"id_collections_derive"
"identifier_derive"
"identify-tts"
"identity-diff-derive"
"iderive"
"idl-macro"
"idmap-derive"
"if_debug"
"if_empty_derive"
"iffy"
"ifmt-impl"
"iftree"
"ignite-rs_derive"
"igri_derive"
"ike-derive"
"illicit-macro"
"imgui-ext-derive"
"imgui-inspect-derive"
"imm_gc_derive"
"imperative-rs-derive"
"impl-enum"
"impl-service"
"impl-template"
"impl-tools"
"impl-trait-for-tuples"
"impl_inheritance_macros"
"impl_table"
"impl_trait"
"implicit-await-macro"
"impls_index_meta"
"import_fn"
"import_generated_code"
"in_space_routes"
"incdir"
"include-base64"
"include-bytes-plus"
"include-cargo-toml"
"include-crypt-bytes-macro"
"include-crypt-codegen"
"include-dir-macro"
"include-flate-codegen"
"include-glsl-impl"
"include-lua-macro"
"include-oracle-sql-args"
"include-repo"
"include-repo-impl"
"include-sql"
"include-transformed"
"include-url"
"include_cstr"
"include_dir_impl"
"include_dir_macros"
"include_display_mode_tex"
"include_js_codegen"
"include_optional"
"include_path"
"include_rgba"
"include_wgsl"
"indigo-proc-macros"
"indigo-structopt-derive"
"indirect-once-derive"
"indiscriminant_impl"
"indiscriminant_impl_bits"
"indiscriminant_impl_byte_str"
"indiscriminant_impl_str"
"indoc"
"indoc-impl"
"indra-proc-macro"
"inert_derive"
"inertia-macros"
"inet2_derive"
"infer_schema_macros"
"infinitree-macros"
"influxdb-derives"
"influxdb2-derive"
"influxdb2-structmap-derive"
"influxdb_derive"
"inherent"
"inherent-pub"
"inheritance-proc-macro"
"init_codegen"
"inject-macro"
"ink_lang_macro"
"ink_macro"
"ink_storage_derive"
"inkpad-derive"
"inkwell_internals"
"inline-c-macro"
"inline-mod"
"inline-proc"
"inline-rust"
"inline-spirv"
"inline-vbs-macros"
"inpm-impl"
"inpt-macros"
"instrumented-codegen"
"int-enum-impl"
"integra8_decorations_impl"
"integra8_impl"
"integration-test"
"inter"
"inter-struct-codegen"
"interact_derive"
"intercom-attributes"
"interfacer-http-attribute"
"intermittent"
"interoptopus_proc"
"interpol"
"interpol-impl"
"interpolate_name"
"intertrait-macros"
"into-attr-derive"
"into_query_derive"
"into_response_derive"
"into_variant_macro"
"intricate-macros"
"introspection-derive"
"intuitive_macros"
"intuple_derive"
"inventory-impl"
"invoke_impl"
"io-enum"
"io_self_derive"
"iocmap"
"ion-c-sys-macros"
"iota-sc-hname-generator"
"ip-macro"
"ipcs-codegen"
"iredismodule-macros"
"iref-enum"
"iroha-codegen"
"iroha-derive"
"irrefutable"
"irzha"
"is-macro"
"is-same-derive"
"is_not"
"is_variant"
"iso-macro"
"issue-macros"
"itconfig-macro"
"iter-enum"
"iterate-proc-macro"
"iterator_item_macros"
"its_ok"
"j-api-derive"
"j4rs_derive"
"jaded-derive"
"jam_derive"
"janetrs_macros"
"jcers_proc"
"jeep-train-macro"
"jenner-macro"
"jens_derive"
"jet-proto-proc-macros"
"jlrs-derive"
"jni-glue-macros"
"jni_fn"
"jnix-macros"
"jo"
"jockey_derive"
"join"
"join_export"
"join_str"
"jomini_derive"
"josephine_derive"
"josh_hates_closures"
"jrpc-macro"
"jrsonnet-gc-derive"
"jrsonnet-gcmodule-derive"
"js-intern-proc-macro"
"js-macros"
"js-sandbox-macros"
"json_api_derive"
"json_derive"
"json_in_type_derive"
"json_schema_test_suite_proc_macro"
"json_typegen"
"jsondata-derive"
"jsonresponder"
"jsonrpc-derive"
"jsonrpc-sdk-macros"
"jsonrpc-utils-macros"
"jsonrpc-v2-macros"
"jsonrpc_client_macro"
"jsonrpsee-proc-macros"
"jss_derive"
"jump-kun-macros"
"juniper-compose-macros"
"juniper-eager-loading-code-gen"
"juniper-from-schema-code-gen"
"juniper_codegen"
"jvm-macro"
"k8s-openapi-derive"
"kaitai-macros"
"kal-derive"
"kamikaze_di_derive"
"kanata-keyberon-macros"
"kanin_derive"
"kas-macros"
"katalyst_macros"
"katexit"
"kayrx-macro"
"kconfig_impl"
"keeshond_derive"
"kefta_macro"
"ketos_derive"
"kexplain"
"keyby"
"keycode_macro"
"keyframe_derive"
"keypath-proc-macros"
"kf-protocol-derive"
"kg-diag-derive"
"kg-display-derive"
"klickhouse_derive"
"kll-macros"
"knative-derive"
"knife-macro"
"kobold_macros"
"kommand"
"kommandozeilen_argumente_derive"
"kompact-actor-derive"
"kompact-component-derive"
"konst_proc_macros"
"korat_derive"
"kotlin-bridge-macro"
"kproc_macros"
"krator-derive"
"kserd_derive"
"kube-derive"
"kuon_request_derive"
"kurisu-derive"
"kv-derive-macro"
"l10n_impl"
"label-macros"
"label_attribute"
"labelled-enum-derive"
"laby_macros"
"lain_derive"
"lalrproc"
"lambda_runtime_errors_derive"
"lamedh_attributes"
"lamellar-impl"
"lamellar-prof"
"lando-attr"
"lang-util-derive"
"langbox_procmacro"
"lark-debug-derive"
"lark-test-generate"
"later-derive"
"lattice_qcd_rs-procedural_macro"
"layeredconf-derive"
"lazing"
"lazy-re"
"lazy-regex-proc_macros"
"lazy-settings-macros"
"lazy_fn"
"lazylink-macro"
"lbs_derive"
"lc3-macros"
"leafwing_input_manager_macros"
"ledb-derive"
"leetcode_test"
"legion_codegen"
"lemmy_apub_lib_derive"
"lemon-tree-derive"
"lending-iterator-proc_macros"
"lens-rs_derive"
"lerp_derive"
"leveldb-orm-derive"
"lexpr-macros"
"lfa_derive"
"lfsr-macro-generate"
"lfsr-macro-lookup"
"lib3d6"
"lib3h_persistence_derive"
"libafl_derive"
"libcnb-proc-macros"
"libfj_parsable_macro_derive"
"libftd2xx-cc1101-derive"
"libipld-cbor-derive"
"libktx-rs-macros"
"libmw-macro"
"libp2p-core-derive"
"libp2p-swarm-derive"
"libpacket-derive"
"libside-procmacro"
"libtor-derive"
"libvmm_macros"
"libwifi_macros"
"lies-impl"
"lifetime_proc_macros"
"ligen-c-macro"
"ligen-cmake-macro"
"ligen-macro"
"lighter-derive"
"lightning-wire-msgs-derive"
"lightning_encoding_derive"
"limelight-derive"
"limine-proc"
"lingon-macro"
"linkme-impl"
"linux-macros"
"linux-rtic-macros"
"linux_details_macros"
"liquid-derive"
"list_files_macro"
"lit-html-macro"
"litcrypt"
"literal_cstr"
"liutongshuo_decoding_macros_impl"
"livemod-derive"
"llml_derive_crate"
"llml_simd_proc"
"llvm-plugin-inkwell-internals"
"llvm-plugin-macros"
"lnpbp_derive"
"load-dotenv"
"local-impl"
"localghost-macros"
"locenv-macros"
"lock_order"
"lockjaw_processor"
"locktree-derive"
"locspan-derive"
"locustdb-derive"
"locutus-macros"
"log-attributes"
"log-derive"
"log-termination"
"logfn"
"logging_timer_proc_macros"
"loggy-macros"
"loginmanager-codegen"
"logisheets_derives"
"logisheets_workbook_derives"
"logos-derive"
"lokaproc"
"lombok"
"looking-glass-derive"
"loosen"
"loupe-derive"
"lovm2_internals"
"lovm2_module"
"lpc55-rtic-macros"
"lpu-macros"
"lrpc-macros"
"lru-cache-macros"
"lsp_msg_derive"
"lspower-macros"
"ltv_derive_impl"
"lua-macro-impl"
"luao3-macros"
"lucene_query_builder_rs_derive"
"lucet-runtime-macros"
"luminance-derive"
"lunatic-macros"
"lunatic-test"
"lunatic_message_derive"
"lurk-ipld-cbor-derive"
"luther-derive"
"lv2-core-derive"
"lv2-urid-derive"
"lvbitfile2rust-macros"
"machine"
"machinery-macros"
"macrame"
"macro-class-render"
"macro-galois-field"
"macro-input-macros"
"macro-ob"
"macro-ruby"
"macro-vis"
"macro_find_and_replace"
"macro_helper"
"macro_io"
"macro_macro"
"macro_pub"
"macro_rules_attribute-proc_macro"
"macro_state_macros"
"macro_tt_utils"
"macroclassrender"
"macrofied-toolbox"
"macromath"
"macropol"
"macroquad_macro"
"macroscope-macro"
"macrotk-derive"
"macrowind"
"madsim-macros"
"mady_macro"
"magic_static_macro"
"magnet_derive"
"magnus-macros"
"make_singleton"
"make_singleton_derive"
"makeit-derive"
"makepad-shader-ast-impl"
"makepad-tinyserde-derive"
"malloc_size_of_derive"
"malvolio_codegen"
"mammoth-macro"
"manifest-dir-macros"
"mantle-macros"
"many-macros"
"maomi-macro"
"maomi-skin"
"maple-core-macro"
"marigold-macros"
"marine-macro"
"marine-test-macro"
"marine-timestamp-macro"
"marker-blanket"
"market_derive"
"markup-proc-macro"
"marshall_derive"
"masala"
"mashup-impl"
"mat-macros"
"match-lookup"
"match-template"
"match_deref"
"math_dsl_macro"
"mathml-macros"
"matrix-sdk-test-macros"
"matterdb-derive"
"maud_macros"
"mauzi_macros"
"maybe-async"
"maybe-async-cfg"
"mazzaroth-rs-derive"
"mbot_proc_macro_helpers"
"mcl_derive"
"mclient_macro"
"mcre"
"md-icons-helper"
"mdbx-proc"
"mdbx-speedy"
"mdsycx-macro"
"medea-macro"
"mediaflow_derive"
"meet-macro"
"megadex_derive"
"megenginelite-derive"
"meilimelo-macros"
"melange_macros"
"membrane_macro"
"memflow-derive"
"memoise"
"memoize-inner"
"memor"
"memtable-macros"
"memuse_derive"
"mendes-derive"
"mendes-macros"
"merfolk_frontend_derive_macros"
"merge_derive"
"merkle_light_derive"
"meshx-derive"
"messagebus_derive"
"messagepack-rs-macros"
"metafor"
"metaldb-derive"
"metamorphose"
"metered-macro"
"methods-enum"
"metrics-catalogue-macros"
"metrics-fn-codegen"
"metrics-macros"
"metriki-macros"
"mg-settings-macros"
"mic_impl"
"michie-macro"
"micro-timer-macros"
"microamp-macros"
"microrm-macros"
"microserde-derive"
"microtemplate_derive"
"microtype-macro"
"miette-derive"
"migrations_macros"
"miku-macros"
"millennium-macros"
"milter-callback"
"mime-macro-4"
"mimeograph_router_codegen"
"mimicry-derive"
"mincache-impl"
"minceraft-derive"
"minecraft-protocol-derive"
"mini-internal"
"mini-internal-miku"
"mini_paste-proc_macro"
"mini_template_macro"
"miniarg_derive"
"minicbor-derive"
"minicdn_macros"
"minihttp-codegen"
"miniserde-derive-enum"
"miniserde-enum"
"minitrace-macro"
"minnow-derive"
"minutus-macros"
"mips-rt-macros"
"mixin"
"mjb_gc_derive"
"mkit-derive"
"mlua_derive"
"mm0_deepsize_derive"
"mmtk-macros"
"mobile-entry-point"
"mock-it_codegen"
"mock_derive"
"mockall_derive"
"mockall_double"
"mockalloc-macros"
"mockers_derive"
"mockiato-codegen"
"mocktopus_macros"
"mod_interface_meta"
"modelfox_macro"
"models-proc-macro"
"modifier_macro"
"modtype_derive"
"modular-bitfield-impl"
"modular-bitfield-msb-impl"
"modus_ponens_derive"
"mogwai-html-macro"
"mol-derive"
"molt-argparse-procmacro"
"mongod-derive"
"mongodb-ext-derive"
"moniker-derive"
"mono-macro"
"monoio-macros"
"monomo_macros"
"monostate-impl"
"moonboot-macros"
"moonramp-lunar-macro"
"moore-derive"
"moose-macros"
"moq_derive"
"moq_lambda"
"moretypes"
"mork-message-derive"
"motoko_proc_macro"
"motore-macros"
"mouscache_derive"
"movie_derive"
"mox"
"mox-impl"
"mp4ameta_proc"
"mpesa_derive"
"mpi-derive"
"mpl-macro"
"mpst-seq-proc"
"mquote-impl"
"mrsbfh-macros"
"mry_macros"
"mscorlib_safe_derive"
"msfs_derive"
"msgpack-schema-impl"
"msgpacker-derive"
"msiz_rustc-ap-rustc_macros"
"msp430-rt-macros"
"muds-derive"
"mula_proc_macro"
"multi-default-trait-impl"
"multi_index_map"
"multiconst_proc_macros"
"multihash-derive"
"multiversion-macros"
"mun_codegen_macros"
"munge_macro"
"murray"
"mushin_derive"
"musli-macros"
"must-implement-trait"
"muta-apm-derive"
"muta-codec-derive"
"mutable_derive"
"mutants"
"mutview"
"mux-stream-macros"
"mwapi_responses_derive"
"mws-derive"
"mwt"
"mxml"
"my-desire-macros"
"mybatis-macro"
"mycroft-macros-impl"
"mysql_enum_derive"
"mysql_helper"
"mysqldump-quick-xml-derive"
"nacos-api_macro"
"nacos-rs-sdk-macro"
"naia-derive"
"naia-serde-derive"
"naked-function-macro"
"nalgebra-macros"
"name-it-macros"
"name-variant"
"named"
"named-tup-derive"
"named_constants"
"named_return"
"named_tuple"
"named_type_derive"
"nameless-clap_derive"
"nametag"
"namewise"
"namewise-derive"
"nanorpc-derive"
"nanoserde-derive"
"naphtha-proc-macro"
"napi-derive"
"napi-rs-derive"
"naro-derive"
"narrow-derive"
"narui_macros"
"nate-derive"
"native-windows-derive"
"nativeshell_derive"
"nb-blocking-util"
"ndjsonlogger"
"ndk-macro"
"ndless-macros"
"near-bindgen-macros"
"near-contract-tools-macros"
"near-env"
"near-paperclip-macros"
"near-performance-metrics-macros"
"near-plugins-derive"
"near-prop-macros"
"near-rpc-error-macro"
"near-sdk-macros"
"near-units-macro"
"nebula-derive"
"negate"
"negative-impl"
"neli-proc-macros"
"neo-mime-macro"
"neo4rs-macros"
"neon-frame-macro"
"neon-macros"
"nereon_derive"
"nestor_codegen"
"net-literals"
"net-literals-impl"
"netlify_lambda_attributes"
"netxbuilder"
"new-home-application-macro"
"new_derivable"
"newport_codegen"
"newt_component_derive"
"newt_proc_macros"
"newtype-enum-macro"
"next-gen-proc_macros"
"next-gen_proc-macro"
"ni-fpga-macros"
"nicolas_macros"
"nifpga-type-macro"
"nimble-derive"
"nitroglycerin_derive"
"nitrokey-test"
"nj-derive"
"nject-macro"
"no-mangle-if-debug"
"no-panic"
"no_error_macro"
"noble-contracts-proc-macro"
"noble-staking-reward-curve"
"node_api_macro"
"nodex-macros"
"nom-both-macros"
"nom-derive-impl"
"nom-packrat-macros"
"nom-peg"
"nom-recursive-macros"
"nom-rule"
"nom-tracable-macros"
"nommy_derive"
"nongoose-derive"
"nonparallel"
"nonzero"
"noop-attr"
"noop_proc_macro"
"nop-json-derive"
"norpc-macros"
"nostalgia-derive"
"notan_macro"
"notation_macro"
"note_frequencies"
"nougat-proc_macros"
"nova-macro"
"npy-derive"
"npyz-derive"
"nt-list_macros"
"nt-packet-derive"
"ntest_test_cases"
"ntest_timeout"
"ntex-macros"
"ntex-rt-macros"
"null_fn"
"num-derive"
"num-variants"
"num_enum_derive"
"numeric-lut"
"numeric_literals"
"numext-constructor"
"numext-fixed-hash-hack"
"numext-fixed-uint-hack"
"nut_self"
"nyar-macro"
"nys"
"oapi_derive"
"oars_proc_macro"
"oasis-amqp-macros"
"oasis-borsh-derive"
"oasis-cbor-derive"
"oasis-game-core-derive"
"oasis-macros"
"oauth1-request-derive"
"obake_macros"
"obfstr-impl"
"obi-derive"
"objc-foundation-derive"
"objc2-proc-macros"
"objekt-clonable-impl"
"objrs_frameworks_foundation_macros"
"objrs_macros"
"observe-macro"
"observer_attribute"
"ocaml-derive"
"ocaml-gen-derive"
"ockam_macro"
"ockam_macros"
"ockam_message_derive"
"ockam_node_attribute"
"ockam_node_test_attribute"
"ockam_vault_test_attribute"
"octane_macros"
"odata_client_derive"
"odbc-futures-derive"
"odra-proc-macros"
"oe"
"off-side"
"ogma-macros"
"okapi-operation-macro"
"olympia_derive"
"one_at_a_time_please_derive"
"one_user"
"onehot-derive"
"ontio-codegen"
"ontio-derive-codec"
"opaque_typedef_macros"
"open-enum-derive"
"open-metrics-client-derive-text-encode"
"openapi_type_derive"
"openbrush_contracts_derive"
"openbrush_lang_macro"
"opensmtpd_derive"
"openssl-macros"
"opentelemetry-auto-span"
"openwhisk_macro"
"opg_derive"
"ophelia-derive"
"opimps"
"ops-derive"
"opt_args"
"optargs-macro"
"optbuilder"
"optee-utee-macros"
"optfield"
"optick-attr"
"option-constructor-derive"
"optional-fields-serde-macro"
"optional_struct"
"oracle_procmacro"
"orbtk-proc-macros"
"orchestra-proc-macro"
"ord_by_key"
"ordes-macros"
"ordinalizer"
"orga-macros"
"organix-derive"
"orientdb-macro"
"origen-core-support"
"ormlite-macro"
"ormx-macros"
"osaka-macros"
"osauth-derive"
"osc_address_derive"
"osmosis-std-derive"
"oso-derive"
"osquery-rust-codegen"
"otopr-derive"
"otspec_macros"
"otto_vec_derive"
"ouroboros_macro"
"overflow"
"overloadable"
"overloadf_derive"
"overrideGetterSetter"
"overrider"
"ovr-vsdb-derive"
"owasm-abi-derive"
"owned-singleton-macros"
"owo-code"
"oxi-module"
"oxi-test"
"oxidate-macros"
"oxide-macros"
"oxidizer-entity-macro"
"oxlex-derive"
"oxygen_quark_derive"
"oxygengine-ignite-derive"
"oy-derive"
"pacaptr-macros"
"packable-derive"
"package_info_derive"
"packattack-derive"
"packed_bools"
"packed_struct_codegen"
"packer_derive"
"packetrs-macro"
"packing_codegen"
"packs-proc"
"packtool-macro"
"pakr-assert-size"
"palette_derive"
"pallet-contracts-proc-macro"
"pallet-macros"
"pallet-staking-reward-curve"
"pam-macros"
"panda-re-macros"
"pandora-api-derive"
"panoramix-derive"
"paperclip-macros"
"papito_codegen"
"parameterized-macro"
"parce_macros"
"parity-codec-derive"
"parity-scale-codec-derive"
"parity-util-mem-derive"
"parker_codegen"
"parkour_derive"
"parquet_derive"
"parsable-macro"
"parse-display-derive"
"parse-variants-derive"
"parsel_derive"
"parser-c-macro"
"parst_derive"
"partfun_derive"
"partial-application-rs"
"partial-borrow-macros"
"partial_derive"
"partial_ref_derive"
"partialdebug-derive"
"parze-declare"
"passive_derive"
"paste"
"paste-impl"
"pasture-derive"
"patchable-macros"
"paw-attributes"
"paw-structopt"
"pax-macro"
"pbdb-macros"
"pcb-rs-macros"
"pcd-rs-derive"
"pchain-sdk-macros"
"pdf_derive"
"peace_data_derive"
"peace_full_spec_id_macro"
"pear_codegen"
"peek-poke-derive"
"peg-macros"
"pegcel-macros"
"peginator_macro"
"pegtastic-macros"
"pelite-macros"
"pen-ffi-macro"
"penguin-config-derive"
"penrose_proc"
"peppi-derive"
"per_test_directory_macros"
"percy-css-macro"
"percy-router-macro"
"perseus-macro"
"persia-rpc-macro"
"persia-speedy-derive"
"persian-rug_derive"
"persistentcache_procmacro"
"pest-ast"
"pest-deconstruct-derive"
"pest-typed-tree"
"pest_consume_macros"
"pest_derive"
"pest_derive_tmp"
"pformat_macro"
"pg-extern-attr"
"pg_mapper"
"pgc-derive"
"pgmacro"
"pgx-macros"
"pgx-named-columns"
"phantom-fields"
"phenotype-macro"
"phf_macros"
"photonix_derive"
"phper-macros"
"physx-macros"
"pi_async_macro"
"pi_ecs_derive_old"
"pi_ecs_macros"
"pi_enum_default_macro"
"picorv32-rt-macros"
"pijul-macros"
"pin-project-internal"
"pinar-derive"
"pinetime-macros"
"pink-extension-macro"
"pink-sidevm-macro"
"pinned-init-macro"
"pinwheel_elements_macro"
"pinwheel_macro"
"pio-proc"
"pipe-op"
"pipederive"
"piston2d_abstraction_proc_macros"
"pixset_derive"
"pkbuffer_derive"
"pkg-macros"
"pkg-version-impl"
"pkg_impl"
"pl-hlist-derive"
"pl-lens-derive"
"pl-lens-macros"
"placeholder_closure"
"placement-new-derive"
"plaster-router-macro"
"plate-macros"
"plctag-derive"
"pleingres-macros"
"plex"
"pliantdb-macros"
"plotly_derive"
"plugin-runtime-codegen"
"plugin-system"
"pluralize_derive"
"plutonium"
"plutus_data_derive"
"pmacro_ruly"
"pmhelp-internal-macros"
"pn-dcp-macro"
"pnet_macros"
"pocket_prover-derive"
"poe-superfilter-support"
"poem-derive"
"poem-extensions-macro"
"poem-grants-proc-macro"
"poem-openapi-api-derive"
"poem-openapi-derive"
"poem-openapi-macro"
"poem_openapi_validator_derive"
"poggers-derive"
"pogo_attr"
"point-derive"
"poise_macros"
"pokeapi-macro"
"politeness-macro-impl"
"poll_token_derive"
"polling-async-trait"
"polyerror"
"polygraph-macro"
"polyhorn-macros"
"polyhorn-ui-macros"
"polymesh-api-codegen-macro"
"polymesh-primitives-derive"
"pomelo-impl"
"pomsky-macro"
"portus_export"
"positional_derive"
"postcard-derive"
"postfix-macros-impl"
"postgres-derive"
"postgres-derives"
"postgres-extension-macro"
"postgres-mapper-derive"
"postgres-syntax"
"postgres_query_derive"
"postgres_query_macro"
"potatonet-codegen"
"power-instruction-analyzer-proc-macro"
"power-of-two-impl"
"powerset-enum-attr"
"ppc750cl-macros"
"pr47-codegen"
"prae_macro"
"praiya-macro"
"pravega-client-macros"
"pre-proc-macro"
"predicate-macros"
"prefixopt_derive"
"preftool-clap-derive"
"preftool-derive"
"pretend-codegen"
"primitive-enum-derive"
"print_each_line"
"prismatic"
"privsep-derive"
"pro_lang_macro"
"pro_storage_derive"
"proc-bitfield-macros"
"proc-caesar"
"proc-concat-bytes-impl"
"proc-lock-macro"
"proc-macro-error-attr"
"proc-macro-hack-impl"
"proc-macro-id"
"proc-macro-kwargs-derive"
"proc-macro-regex"
"proc-macro-rules-macros"
"proc-macro2-test"
"proc-quote-impl"
"proc-spirv"
"proc-test-catalog"
"proc_macro_global_state"
"proc_macro_test"
"proc_qq_codegen"
"proc_static_assertions"
"proc_unroll"
"proc_use_inline"
"proc_vector2d"
"procedurals"
"proclock-macro"
"procmac"
"proconio-derive"
"procopt"
"profiling-procmacros"
"progenitor-macro"
"projection-macros"
"prom-attire"
"prom-attire-bootstrap"
"prom-timer-macro"
"prometheus-client-derive-text-encode"
"prometheus-metric-storage-derive"
"prometheus-static-metric"
"proofsize_derive"
"propane-macros"
"proper"
"property"
"propfuzz-macro"
"proptest-attr-macro"
"proptest-derive"
"prost-reflect-derive"
"protected-id-derive"
"proto-vulcan-macros"
"protobuf-convert"
"protocol-derive"
"prov-cosmwasm-derive"
"prove_derive"
"proxy-enum"
"prune_derive"
"prusto-macros"
"pseudonym"
"ptah_derive"
"ptr_eq-macros"
"ptr_meta_derive"
"pub-sub-client-derive"
"puball"
"pubcfg"
"public"
"pulz-ecs-macros"
"purescript_waterslide_derive"
"purpurea"
"pwasm-abi-derive"
"pwn-helper-macros"
"pydeco"
"pyo3-asyncio-macros"
"pyo3-macros"
"pyo3-prost"
"pyo3cls"
"python_comm_macros"
"pywrapper-macro"
"q1tsim-derive"
"qadapt-macro"
"qbittorrent-web-api-gen"
"qjs-derive"
"qmetaobject_impl"
"qname-macro"
"qoqo-macros"
"qqx-macro"
"qsk-macros"
"qt_macros"
"qtpl-macros"
"qty-macros"
"qu-derive"
"qualia_derive"
"quantifiable-derive"
"quartz_commands_macros"
"quartz_nbt_macros"
"query-params-derive"
"query_params"
"quick_from"
"quickcheck_async"
"quickcheck_macros"
"quickjs_regex_derive"
"quilkin-macros"
"quit_macros"
"quix-derive"
"quork-proc"
"quote-use"
"quote_precise"
"r-gen-macro"
"r-lombok-macros"
"r3bl_rs_utils_macro"
"rabbithole-derive"
"racetrack-proc-macro"
"rad_ext_template"
"radiation-macros"
"raffia_macro"
"rafka_codegen"
"rainbow-macros"
"ral-macro"
"ramhorns-derive"
"rand_derive"
"rand_derive2"
"randerive"
"random_struct_layout"
"random_variant_macro"
"rapira-derive"
"rapt_derive"
"rart-macros"
"rash_derive"
"rasn-derive"
"ratcc"
"rate-macros"
"raui-derive"
"raw_serde_derive"
"rawcode_derive"
"rayon-attr"
"rayon-macro"
"rayon-macro-hack"
"rbatis-macro-driver"
"rbatis_sql_macro"
"rbtag_derive"
"rbxm-proc"
"rclrust-msg-gen"
"rcstruct"
"rd-derive"
"rdi_macros"
"rdxl"
"rdxl_static_macros"
"re-parse-macros"
"reacty_yew"
"readonly"
"reaktor"
"real-async-trait"
"real-proc"
"real_c_string"
"realia"
"realm_macros"
"reaper-macros"
"reborrow-derive"
"rebound-proc"
"rebpf-macro"
"rec"
"rec_derive"
"recap-derive"
"reciter"
"recorder"
"records"
"red_asn1_derive"
"redacted_debug"
"redbpf-macros"
"redis-derive"
"redis-lua-macro"
"redis_serde_json"
"redismodule_cmd_procmacros"
"ref-cast-impl"
"ref-mut-n"
"ref_clone_derive"
"refinery-macros"
"reflect-internal"
"reflection_derive"
"reflective"
"refloctopus-derive"
"reformation_derive"
"refptr-macros"
"refview_derive"
"regex_static_macro"
"reign_derive"
"reinda-macros"
"relational_types_procmacro"
"relearn_derive"
"relexer-derive"
"relm-attributes"
"relm-derive"
"relm-derive-state"
"relm4-macros"
"remain"
"remoc_macro"
"remote-trait-object-macro"
"remove_macro_call"
"renaissance"
"rename"
"rename-item"
"render_macros"
"renderdoc-derive"
"rental-impl"
"rep_derive"
"repeated"
"replman_derive"
"repr-with-fallback"
"repr_offset_derive"
"reql-macros"
"requestty-macro"
"requiem-macros"
"requiem-web-codegen"
"require_unsafe_in_body"
"rerust"
"reset-router-macros"
"reshape_helper"
"resource_list_proc_macro"
"rest-client_codegen"
"restcrab_macros"
"restep"
"restest_macros"
"restruct_derive"
"result-like-derive"
"resx_derives"
"retrieve"
"retrofit_codegen"
"retroqwest-derive"
"retryable-proc_macros"
"reusable_derive"
"reverse_differentiable"
"review-macro"
"rg3d-core-derive"
"rglua-macros"
"rhachis-run-macro"
"rhai_codegen"
"rhizome_proc-macro-definitions"
"rhs_first_assign"
"rhythmc_macros"
"rifgen_attr"
"riker-macros"
"rill-derive"
"riscv-minimal-rt-macros"
"riscv-rt-macros"
"ritz_impl"
"rkyv_derive"
"rkyv_derive_test"
"rkyv_dyn_derive"
"rkyv_typename_derive"
"rlink-derive"
"rlp-derive"
"rlua-builders-derive"
"rlua-table-derive"
"rnet-macros"
"robespierre-fw-macros"
"robin-derives"
"robma_builder"
"robusta-codegen"
"rocket-config-codegen"
"rocket-grants-proc-macro"
"rocket-jwt"
"rocket-jwt-authorization"
"rocket-model-codegen"
"rocket_codegen"
"rocket_contrib_codegen"
"rocket_db_pools_codegen"
"rocket_extra_codegen"
"rocket_modules"
"rocket_okapi_codegen"
"rocket_okapi_codegen_fork"
"rocket_sync_db_pools_codegen"
"rocketjson_macro"
"rokol_derive"
"rollo-macros"
"roopert_macro_root"
"rooty_derive"
"roqoqo-derive"
"rorm-macro"
"roslibrust_codegen_macro"
"rosrust_codegen"
"rotate-enum"
"rotenv_codegen"
"rotonda-macros"
"router-rs-macro"
"router-xiaobei-macro"
"rovv_derive"
"roxido_macro"
"rp1-macros"
"rp2040-hal-macros"
"rpa_derives"
"rpa_enum"
"rpc-toolkit-macro"
"rpcx_derive"
"rplugin_macros"
"rq_derive"
"rquickjs-macro"
"rrw_macro"
"rs-blocks-derive"
"rs-data-formats_derive"
"rs-graph-derive"
"rs-odbc_derive"
"rs-sandbox-derive"
"rs-sandbox-macros"
"rs_unit"
"rsb_derive"
"rschema-derive"
"rsconnect_macros"
"rsexp-derive"
"rsfbclient-derive"
"rsip-derives"
"rslint_macros"
"rspc-macros"
"rspg-macros"
"rsrl_derive"
"rstest_macros"
"rstest_reuse"
"rsys_macro"
"rt-local-macros"
"rtic-trace-macros"
"rtlola-macros"
"rtti-derive"
"rubber_duck_macro"
"rudeboy-derive"
"ruint-macro"
"rulex-macro"
"ruma-api-macros"
"ruma-events-macros"
"ruma-identifiers-macros"
"ruma-macros"
"ruma-serde-macros"
"rumpsteak-macros"
"rundo_attrs"
"rundo_attrsca"
"rune-macros"
"runestick-macros"
"runng_derive"
"runtime-attributes"
"runtime-fmt-derive"
"ruspiro-interrupt-macros"
"rusqlite-model-derive"
"rust-ad-core-macros"
"rust-ad-macros"
"rust-cef-derive"
"rust-embed-impl"
"rust-fixed-point-decimal-macros"
"rust-fsm-dsl"
"rust-gl-proc"
"rust-hdl-macros"
"rust-i18n-macro"
"rust-jni-generator"
"rust-libretro-proc"
"rust-sitter-macro"
"rust-spice-derive"
"rust-xfinal-macro"
"rust_decimal_macro_impls"
"rust_decimal_macros"
"rust_events_derive"
"rust_gui_macros"
"rust_hawktracer_proc_macro"
"rust_transit_derive"
"rustabi-derive"
"rustacuda_derive"
"rustbus_derive"
"rustc-ap-rustc_macros"
"rustc_codegen_nvvm_macros"
"rusteval-derive"
"rustfmt-config_proc_macro"
"rustfsm_procmacro"
"rustico"
"rustier-macros"
"rustiful-derive"
"rustify_derive"
"rustmex-entrypoint"
"rustorm-derive"
"rustorm_codegen"
"rustpub-macro"
"rustpython-derive"
"rustructure-macros"
"ruststep-derive"
"rustversion"
"rusty-gql-macro"
"rusty-html-macros"
"rusty-junctions-client-api-proc-macro"
"rusty-junctions-library-generation-proc-macro"
"rusty_german_entity_macro"
"rusty_jsc_macros"
"rusty_v8_helper_derive"
"rustyle"
"rustyline-derive"
"rutel_derive"
"rutenspitz_macro"
"ruukh-codegen"
"rvs_derive"
"rvv-asm"
"rwasm_macro"
"rweb-macros"
"rweb-testing-macros"
"rxml_proc"
"rye-macros"
"rysk-tools-macro"
"rzhavchina"
"s_test_fixture"
"sabi_derive"
"sad_machine"
"safe"
"safe-builder-derive"
"safe-bytes-derive"
"safe-regex-macro"
"safe-uninit-derive"
"safe_attr"
"safe_ecs_derive"
"safecoin-frozen-abi-macro"
"safecoin-sdk-macro"
"safer_ffi-proc_macro"
"safety-guard"
"safina-async-test-core"
"sai_component_derive"
"sailfish-macros"
"saito-macros"
"salak_derive"
"salsa-macros"
"salvia_macro"
"salvo_macro"
"salvo_macros"
"samotop-async-trait"
"samp-codegen"
"sana_derive"
"sanitizeable_derive"
"sanitizer_macros"
"saphir_macro"
"sapio_macros"
"saturating_arithmetic"
"sauron-component-macro"
"sauron-node-macro"
"savage_macros"
"save_state_derive"
"savefile-derive"
"savory-derive"
"savory-elements-derive"
"savory-router"
"saw_mcr"
"sawp-ffi-derive"
"sawp-flags-derive"
"sbml-macros"
"sc-chain-spec-derive"
"sc-tracing-proc-macro"
"sc2-proc-macro"
"scale-info-derive"
"scale_documentation_parser"
"scale_impl_generator"
"scanfmt_macros"
"schema-derive"
"schema_oxidation"
"schemafy"
"schemars_derive"
"scientific-macro"
"scones_macros"
"scoped-gc-derive"
"scoped_css"
"scoundrel-macro"
"scpi_derive"
"scraper-macros"
"scrappy-derive"
"scrappy-macros"
"scrappy-web-codegen"
"scrappy_do_codegen"
"scripthookv-rs-macros"
"scroll_derive"
"scsys-derive"
"scsys-macros"
"scylla-macros"
"scylla-macros-flex"
"scylla_orm_macro"
"scylladb-macros"
"scylladb-parse-macros"
"sdb_macro"
"sea-orm-field-updater"
"sea-orm-macros"
"sea-orm-rocket-codegen"
"sea-query-attr"
"sea-query-derive"
"sea-query-driver"
"sea-schema-derive"
"sea-strum_macros"
"sealed"
"sealed_test_derive"
"seamless_macros"
"seaography-derive"
"seawater-macro"
"secop-derive"
"section_parser_derive"
"seed_style_macros"
"segsource-derive"
"select-rustc"
"selectme-macros"
"self-rust-tokenize-derive"
"selfstack"
"semantics-derive"
"sensible"
"sentinel-macros"
"separable-derive"
"seq-macro"
"sequential-macro"
"serbia"
"serde-bindgen-core-derive"
"serde-deserialize-over-derive"
"serde-diff-derive"
"serde-enum"
"serde-enum-derive"
"serde-enum-str"
"serde-ext-macros"
"serde-indexed"
"serde-intermediate-derive"
"serde-json-helpers"
"serde-lite-derive"
"serde-query-derive"
"serde-reflect-intermediate-derive"
"serde-semver-derive"
"serde-tc-macro"
"serde-versions-derive"
"serde_alias"
"serde_amqp_derive"
"serde_apply_macros"
"serde_closure_derive"
"serde_compact"
"serde_default"
"serde_derive"
"serde_derive_state"
"serde_dhall_typegen"
"serde_flat_regex"
"serde_int_map_derive"
"serde_mtproto_derive"
"serde_piecewise_default_derive"
"serde_prefix"
"serde_python_derive"
"serde_repr"
"serde_roundtrip_derive"
"serde_schema_derive"
"serde_someip_derive"
"serde_tuple_macros"
"serde_unit_struct_derive"
"serde_valid_derive"
"serde_version_derive"
"serde_with_macros"
"serdebug_derive"
"serdine_derive"
"serenity_group_name"
"serial_test_derive"
"serialize-to-javascript-impl"
"seripack_macros"
"serum-borsh-derive"
"servant-macro"
"settings-schema-derive"
"sewup-derive"
"sexpy_derive"
"sfsm-proc"
"sgr"
"sgr_macros"
"sgx-type-debug"
"sgx_align_struct_attribute"
"sgx_rand_derive"
"sgx_serialize_derive"
"sgxs-tools"
"sh-builtin-bash-proc"
"sha2-derive-proc-macro"
"shader_macro"
"shaderc-macro"
"shades-edsl"
"shaku_derive"
"shank_macro"
"shard_ecs_derive"
"shardize"
"shared_memory_derive"
"shellfn-attribute"
"shine-ecs-macro"
"shine-gltf-macro"
"shine-graph-macro"
"shine_component_derive"
"shinyframework_codegen"
"shippai_derive"
"shipyard_proc"
"shogun-rust-procedural"
"shoogah_macros"
"shorthand"
"shoulda_macro"
"shred-derive"
"shredder_derive"
"shrinkwraprs"
"shumai-config-impl"
"shuttle-codegen"
"sia-macro"
"sidetree"
"sidevm-macro"
"sierra-proc"
"sif_macro"
"signature_derive"
"sim_derive"
"simavr-section-macro"
"simd-json-derive-int"
"simd_helpers"
"simi-macros"
"simple-bind"
"simple-hash-macro"
"simple-tlv_derive"
"simple_calculator_deliver"
"simple_func_timer"
"simple_parse_derive"
"simple_tables-derive"
"simple_test_case"
"simple_xml_serialize_macro"
"simpleord"
"simplicity_derive"
"simulink-binder"
"simx"
"sing_macros"
"singleton-derive"
"singletonum-derive"
"sir-macro"
"sixtyfps-corelib-macros"
"sixtyfps-macros"
"size-of-derive"
"sjis-literals"
"skidscan-macros"
"sky-derive"
"skyline_macro"
"slashies-macros"
"slashook-macros"
"slashy_macros"
"slicert"
"slices"
"slices-hack"
"slint-macros"
"slip-imp"
"slist-derive"
"slog-extlog-derive"
"slog-mock-proc-macros"
"sm-ext-derive"
"sm_macro"
"small_ctor"
"smart-contract-macros"
"smart-default"
"smart-hash-derive"
"smd_macro"
"smelter"
"smlang-macros"
"smoke-macros"
"smol-attributes"
"smol-potat-derive"
"smol-potat-macro"
"smoldb_derive"
"snafu-cli-debug"
"snafu-derive"
"snake_cased_derive"
"snapshot-proc-macro"
"snarkvm-circuit-environment-witness"
"snarkvm-derives"
"snarkvm-utilities-derives"
"snec_macros"
"snowcat_macros"
"snowchains_proc_macros"
"soa_derive_internal"
"soak-derive"
"solana-frozen-abi-macro"
"solana-sdk-macro"
"solana-sdk-macro-frozen-abi"
"solana_libra_proto_conv_derive"
"solarsail-macros"
"solders-macros"
"solid-derive"
"solidity-bindgen-macros"
"soloud-derive"
"solstice-derive"
"some-error"
"someip_derive"
"sonic_serde_macros"
"sonic_spin"
"sonicbot-macros"
"sonicbot-matrix-macros"
"soroban-env-macros"
"soroban-native-sdk-macros"
"soroban-sdk-macros"
"sort_by_derive"
"sorted_locks_derive"
"sourcegen"
"sp-api-proc-macro"
"sp-core-hashing-proc-macro"
"sp-debug-derive"
"sp-multihash-derive"
"sp-npos-elections-compact"
"sp-phragmen-compact"
"sp-runtime-interface-proc-macro"
"sp-version-proc-macro"
"spa-server-derive"
"spaad_internal"
"spacetimedb-bindgen"
"spandoc-attribute"
"sparta-proc-macros"
"spec"
"specit"
"specs-derive"
"specs-visitor-derive"
"specta-macros"
"spectacle-derive"
"spectacle-impl-tuples"
"spectrum-macros"
"speculate"
"speedy-derive"
"spez-macros"
"sphinx-use-state"
"spice21procs"
"spirv-std-macros"
"spirv-struct-layout-derive"
"splitter-derive"
"sppparse_derive"
"sprattus-derive"
"sql_db_mapper_derive"
"sqlb-macros"
"sqlstate-macros"
"sqlx-crud-macros"
"sqlx-database-tester-macros"
"sqlx-derive-with"
"sqlx-macros"
"sqlx-model-macros"
"sqlx-models-derive"
"sqlx-models-proc-macro"
"sqlx-plus-macros"
"sqlx-type-macro"
"sqlxinsert"
"sqlxmq_macros"
"square-ox-derive"
"squark-macros"
"squtils"
"srcpos_get_derive"
"srpc-macro"
"ssbh_write_derive"
"sscanf_macro"
"ssvm-evmc-declare"
"ssz-derive"
"ssz_rs_derive"
"sszb_derive"
"stability"
"stable-step-derive"
"staged-builder-internals"
"standard-dist"
"starchart-derive"
"stargate-grpc-derive"
"starlane-macros"
"starlark_derive"
"starlark_module"
"starship_module_config_derive"
"stateful_macro_rules"
"statemachine-macro"
"stateroom-wasm-macro"
"static-address"
"static-address-macro"
"static-iref"
"static-map-macro"
"static-noise"
"static-pubkey"
"static-reflect-derive"
"static-router-macros"
"static_init_macro"
"static_map_macros"
"static_res"
"static_table_derive"
"static_test"
"staticfilemap"
"std140-macros"
"stdf-record-derive"
"stdin_parser_derive"
"stdweb-derive"
"stdweb-internal-macros"
"stdweb-internal-test-macro"
"steam-language-gen-derive"
"stidgen"
"stivale-proc"
"stix_derive"
"stlog-macros"
"storm_macro"
"stowaway-derive"
"str-match"
"str_to_enum_derive"
"stratisd_proc_macros"
"stratus-macros"
"stream-future-impl"
"streamduck-core-derive"
"strict_encoding_derive"
"string_enum"
"string_literal"
"stringify-attr"
"stringly_typed_derive"
"strong-xml-derive"
"stronghold-derive"
"struct-convert"
"struct-field-names-as-array"
"struct-merge-codegen"
"struct-variant"
"struct2swagger_derive"
"struct2vec_derive"
"struct_deser-derive"
"struct_field"
"struct_field_names"
"struct_fragment"
"struct_gen_derive"
"struct_layout"
"structbuilder_derive"
"structconf_derive"
"structdoc-derive"
"structdump-derive"
"structenv_derive"
"structform-derive"
"structmap-derive"
"structmapper-codegen"
"structmeta-derive"
"structopt-derive"
"structopt-toml-derive"
"structopt-yaml-derive"
"structout"
"structscan_derive"
"structstruck"
"structsy-derive"
"structural-assert"
"structural_derive"
"structure-macro-impl"
"structview_derive"
"structx_derive"
"structype_derive"
"strukt"
"strum_macros"
"strung_derive"
"struple-impl"
"stry-attrouter"
"stub_trait"
"stubr-attributes"
"stuck-macros"
"stylist-macros"
"sub-model"
"submillisecond_macros"
"suborbital-macro"
"subplotlib-derive"
"subrpcer-impl"
"substance-macro"
"substrait-validator-derive"
"substrate-subxt-proc-macro"
"substrate-test-utils-derive"
"substreams-ethereum-derive"
"substreams-macro"
"subtle-derive"
"subtle-ng-derive"
"subxt-macro"
"sudograph-generate"
"sul"
"sully_peg"
"sum_error"
"summer-boot-macro"
"sunbeam-macro"
"sundial-derives"
"sunfish_macro"
"sunscreen_compiler_macros"
"sunset-sshwire-derive"
"super-sabicom-macro"
"superbitty-macros"
"supermod"
"superstruct"
"suricata-derive"
"surjective-enum"
"surrealdb-derive"
"suspend_fn_proc_macro"
"susy-codec-derive"
"susy-jsonrpc-derive"
"susyabi-derive"
"susydev-jsonrpc-derive"
"susyp2p-core-derive"
"sv-parser-macros"
"sval_derive"
"svec_macro"
"svgbobdoc"
"swarm-bot-packets-macro"
"swarm-derive"
"sway-ir-macros"
"swc_config_macro"
"swc_css_codegen_macros"
"swc_ecma_codegen_macros"
"swc_ecma_parser_macros"
"swc_ecma_quote_macros"
"swc_ecma_transforms_macros"
"swc_ecma_visit_macros"
"swc_eq_ignore_macros"
"swc_estree_macros"
"swc_html_codegen_macros"
"swc_plugin_macro"
"swc_trace_macro"
"swc_visit_macros"
"swc_xml_codegen_macros"
"swift-bridge-macro"
"swipl-macros"
"sycamore-macro"
"sycamore-router-macro"
"syllogism-macro"
"sylt-macro"
"sylvia-derive"
"symm_impl"
"symoxide_macros"
"syncwrap"
"syndicate-macros"
"synonym"
"synthez-codegen"
"t4rust-derive"
"tabled_derive"
"tablefy_derive"
"tackt-macros"
"tagged_bytes"
"taikai"
"tailcall-impl"
"talos_procs"
"tamasfe-schemars_derive"
"tamata-macros"
"tangram_macro"
"taos-macros"
"tapa-trait-serde-derive"
"tapioca-codegen"
"tappet-derive"
"tarantool-proc"
"target-cpu-macro"
"target-lexicon-macros"
"tari_comms_rpc_macros"
"tari_infra_derive"
"tarpc-plugins"
"tarrasque-macro"
"tauri-macros"
"tc-chain-spec-derive"
"tc-tracing-proc-macro"
"tch-tensor-like-derive"
"tco"
"tealr_derive"
"teensy-lc-macros"
"teil_derive"
"telebot-derive"
"telegraf_derive"
"telegram_derive"
"telexide_fork_proc_macros"
"telexide_proc_macros"
"teloc_macros"
"teloxide-macros"
"templar_macros"
"templing"
"temply-derive"
"tencent_scf_derive"
"tensorflow-internal-macros"
"tensorflow_proto_derive"
"tent_codegen"
"tent_proc_macros"
"term-data-table-derive"
"termcandy-macros"
"termcolor_output_impl"
"termination_attrib"
"termpixels_derive"
"test-case-derive"
"test-case-macros"
"test-collector-derive"
"test-context-macros"
"test-env-helpers"
"test-env-log"
"test-fuzz-macro"
"test-generator"
"test-ignore-if"
"test-impl"
"test-log"
"test-span-macro"
"test-strategy"
"test-with"
"test_deps_if"
"test_double"
"testaun"
"testcat"
"testdata-macros"
"testgen"
"testing_macros"
"tet-libp2p-core-derive"
"tetcore-subxt-proc-macro"
"tetcore-test-utils-derive"
"tetsy-codec-derive"
"tetsy-jsonrpc-derive"
"tetsy-libp2p-core-derive"
"tetsy-rlp-derive"
"tetsy-scale-codec-derive"
"tetsy-scale-info-derive"
"tetsy-util-mem-derive"
"tex_derive"
"textwrap-macros-impl"
"thalo-macros"
"thcon_macro"
"thespis_derive"
"thin_trait_object"
"third-pact"
"thirtyfour-macros"
"thirtyfour-querier-derive"
"thisctx_impl"
"thiserror-impl"
"thiserror-impl-no-std"
"thiserror_core2-impl"
"thread_spawn"
"three_em_macro"
"throttle_my_fn"
"thruster-proc"
"thruster-socketio-proc"
"thruster-x"
"thunder"
"thunderbird-macros"
"tia"
"tiberius-derive"
"tide-jsx-impl"
"tide-serve-dir-macro"
"tidy-builder"
"tilde"
"time-graph-macros"
"time-macros"
"time-macros-impl"
"time_main"
"timed_function"
"timed_proc_macros"
"timesource-derive"
"tiny-multihash-derive"
"tiny-multihash-proc-macro"
"tiny-rpc-macros"
"tiny_orm_macro_derive"
"tinyhttp-codegen"
"tinyparse_macro"
"tl-proto-proc"
"tlayuda"
"tls_codec_derive"
"tlua-derive"
"tm-derive"
"to-syn-error-derive"
"to-syn-value_derive"
"to_bytes_derive"
"to_hash_map"
"todo-or-die"
"tojson_macros"
"tokay-macros"
"token-parser-derive"
"tokio-actor"
"tokio-async-attributes"
"tokio-async-await-test"
"tokio-macros"
"tokio-pg-mapper-derive"
"tokio-zmq-derive"
"tokio_env_macro"
"toml-cfg"
"toml-query_derive"
"tonic-error-impl"
"tonic-include-proto"
"tonic-rpc-macro"
"tonic_catch_proc"
"tonic_include_protos"
"took-macro"
"topo-macro"
"toql_derive"
"toql_enum_derive"
"toql_fields_macro"
"toql_paths_macro"
"toql_query_macro"
"toql_role_expr_macro"
"toql_sql_expr_macro"
"torn-api-macros"
"tower-lsp-macros"
"tower-web-macros"
"toy-arms_derive"
"toy-rpc-macros"
"tp-api-proc-macro"
"tp-npos-elections-compact"
"tp-runtime-interface-proc-macro"
"tql_macros"
"trace"
"trace-tools-attributes"
"trace2_macro"
"trace_caller_macro"
"tracelogging_macros"
"tracers-macros-hack"
"tracing-attributes"
"tracing-attributes-http"
"tracing-attributes-hyper"
"tracing-forest-macros"
"tracing-rc-derive"
"tracing-test-macro"
"track-macro"
"trackable_derive"
"tracked-impl"
"tracker-macros"
"tractor-macros"
"trade_aggregation_derive"
"trait-async"
"trait-enumizer-derive"
"trait-match-proc-macro"
"trait-set"
"trait-union-proc"
"trait_adapters_macros"
"trait_cast_impl_rs"
"trait_derive"
"trait_tests"
"traitlit"
"traitor-derive"
"trans-derive"
"trans-schema-derive"
"transit_model_procmacro"
"translation_provider"
"translator"
"transmute-tools"
"trapper_macro"
"trdelnik-test"
"treasure-map-derive"
"tree-buf-macros"
"tree_hash_derive"
"treeflection_derive"
"trigraph"
"trillium-include-dir-impl"
"trillium-static-compiled-macros"
"trimmer_derive"
"trpc-rs-macros"
"trustfall_filetests_macros"
"try-catch"
"try-let"
"try_clone_derive"
"try_match_inner"
"tryfromfail"
"ts-bindgen-build-support"
"ts-rs-macros"
"ts2rs"
"ts3_derive"
"tsify-macros"
"tskit-derive"
"tstr_proc_macros"
"tsukuyomi-macros"
"tsync"
"tt-equal"
"tt-identifier"
"tttr-toolbox-proc-macros"
"tui-markup-ansi-macro"
"tuirealm_derive"
"tuix_derive"
"tulip-derivative"
"tumbleweed_derive"
"tuna-macros"
"tupiter-proc-macro"
"tuple-iter"
"tupleops-macros"
"turbocharger-impl"
"turbolift_macros"
"turbomod"
"turbonone"
"turbosloth-macros"
"turbosql-impl"
"tvm-macros"
"tw-storage-macros"
"twilight-interactions-derive"
"two-rusty-forks-macro"
"tyenum_attribute"
"tylift"
"typ"
"type-census-derive"
"type-change"
"type-cli-derive"
"type-info-derive"
"type-layout-derive"
"type-name-derive"
"type-rules-derive"
"type-uuid-derive"
"type_at_derive"
"type_description_derive"
"type_hash_macros"
"type_utils"
"typed-builder"
"typed-html-macros"
"typed-qb-procmacro"
"typed-sql-derive"
"typed-store-derive"
"typed-urls-derive"
"typed_index_derive"
"typemap-meta-derive"
"typename_derive"
"typenaming-derive"
"typenum-promote"
"typesafe-derive-builder"
"typescript-definitions-derive"
"typescript-definitions-derive-ufo-patch"
"typescript-type-def-derive"
"typescript-wasm-bindgen-macros"
"typescriptify-derive"
"typesense_derive"
"typesets-macro"
"typeshare_marker"
"typestate-proc-macro"
"typetag-impl"
"typetrait"
"typic-derive"
"typify-macro"
"typsy-macros"
"u256-literal"
"u64_array_bigints_macros"
"uapi-proc"
"uavcan-derive"
"ublox_derive"
"uclicious_derive"
"uefi-macros"
"ufmt-macros"
"ugli-derive"
"uhppote-derive"
"ui4-macros"
"uindex_derive"
"uncon_derive"
"unconst_trait_impl"
"unhtml_derive"
"unhygienic-impl"
"unhygienic2"
"uni_components_macro"
"uni_localservice_macro"
"unicode_names2_macros"
"uniffi_macros"
"unimock_macros"
"union_export"
"union_type"
"unique-type-id-derive"
"unit-derive"
"unit-proc"
"unit_system_derive"
"unite"
"unitval-derive"
"uniui_gui_macro"
"unix-ts-macros"
"unpat"
"unprolix"
"unquote"
"unrest_codegen"
"unroll"
"unsafe_fn"
"unstringify"
"unwind_aborts"
"unwrap_all"
"unwrap_helpers_proc_macros"
"unzip-n"
"uom-macros"
"update-sync_derive"
"uptown_funk_macro"
"uri_path_router"
"urid-derive"
"usbd-hid-macros"
"usdt-attr-macro"
"usdt-macro"
"user_doc-doc_proc_macro"
"usual-proc"
"ut"
"utf16_literal"
"utf32-lit"
"utility-types"
"utils-plugs-proc"
"utoipa-gen"
"utools"
"uucore_procs"
"uuid-macro-internal"
"ux-macro"
"v11_macros"
"v9-attr"
"v_escape_derive"
"vale-derive"
"validated_struct_macros"
"validator_derive"
"validators-derive"
"valor_plugin"
"valora_derive"
"valuable-derive"
"value_from_type_macros"
"valuetypes"
"vapabi-derive"
"vararg"
"variant_access"
"variant_access_derive"
"variant_count"
"variant_counter_derived"
"variant_name_derive"
"varianteq"
"variantly"
"variants-struct"
"variation"
"varies"
"varisat-internal-macros"
"varlen_macro"
"vary"
"vec-reg-macro"
"vecmerge-impl"
"vecn"
"velcro_macros"
"veneer-macros"
"veriform_derive"
"verify-macros"
"verify_macro"
"verilated-module"
"version-consts-git-impl"
"versionize_derive"
"versuch"
"vertigo-html-macro"
"vertigo-macro"
"vgtk-macros"
"viable-impl"
"view"
"view_macro"
"vimwiki_macros"
"visa-rs-proc"
"visibility"
"visible"
"visit"
"visit_diff_derive"
"visita_macros"
"viz-macros"
"vizz_derive"
"vk-shader-macros"
"vk-shader-macros-impl"
"vmnet-derive"
"vmprotect-macros"
"volkswagen"
"volo-macros"
"vptr-macros"
"vride-macros"
"vru-noise-macros"
"vsdb_derive"
"vtable-macro"
"vtables_derive"
"vte_generate_state_changes"
"vujio"
"vulkano-shaders"
"wa-serde-derive"
"wa_proto_macro"
"waiter_codegen"
"walle-macro"
"warp_dsl_impl"
"wasi-common-cbindgen"
"wasm-bindgen-derive"
"wasm-bindgen-macro"
"wasm-bindgen-test-macro"
"wasm-bus-macros"
"wasm-interfacegen-macro"
"wasm-rpc-macros"
"wasm-run-proc-macro"
"wasm-typescript-definition"
"wasm-wrapper-gen-impl"
"wasm4-impl"
"wasm_plugin_guest_derive"
"wasmbin-derive"
"wasmbox-macro"
"wasmbus-macros"
"wasmcloud-actor-core-derive"
"wasmedge-bindgen-macro"
"wasmer-bus-macros"
"wasmer-derive"
"wasmer-derive-asml-fork"
"wasmer-derive-near"
"wasmer-inline-c-macro"
"wasmer-wit-bindgen-rust-impl"
"wasmer_enumset_derive"
"wasmesh-macros"
"wasmir"
"wasmtime-component-macro"
"wasmtime-rust-macro"
"wasmtime-wiggle-macro"
"wasmtime_plugin_guest_derive"
"wasmy-macros"
"wasmyon-macro-support"
"waterbear-instruction-derive"
"wayk_proto_derive"
"wayland-scanner"
"waytogo-macro"
"wchar-impl"
"wd-40"
"wd_macro"
"we-derive"
"wearte_derive"
"web-component-derive"
"web-glitz-macros"
"web-sys-query-derive"
"webassembly-test"
"webforms_derive"
"webframework-derive"
"webgl-rc-macro"
"weblab-macros"
"weblog-proc-macro"
"webview2-com-callback-macros"
"webview2-com-macros"
"weechat-macro"
"weft_derive"
"wezterm-dynamic-derive"
"wgpu-traits"
"wgpu_macros"
"whasm-grammar-derive"
"whaterror_macros"
"wide-literals"
"wide-str-impl"
"wig"
"wiggle-macro"
"wikiproc"
"willow-codegen"
"win_etw_macros"
"windows-define"
"windows-dll-codegen"
"windows-implement"
"windows-interface"
"windows_gen_macros"
"windows_winmd_macros"
"windy-macros"
"winit-main-proc"
"winmd-macros"
"winrt_gen_macros"
"winrt_macros"
"winspawn-macro"
"winstr-macros"
"winwrap-derive"
"witchcraft-server-macros"
"witgen_macro"
"with_builtin_macros-proc_macros"
"with_locals-proc_macros"
"with_tempdir"
"wither_derive"
"withers_derive"
"wll-macros"
"wlroots-dehandle"
"woab-macros"
"wolfram-library-link-macros"
"wonderbox-codegen"
"wood_derive"
"woptions_meta"
"worker-macros"
"workflow_macro"
"wotw_seedgen_derive"
"wrapcenum-derive"
"wrapped-vec"
"wrapping_arithmetic"
"wrapping_proc_macro"
"wraptest"
"ws2812-spi-write-constants"
"wstr_impl"
"wundergraph_derive"
"x86test-macro"
"xactor-derive"
"xaynet-macros"
"xdr-rs-serialize-derive"
"xecs_derive"
"xflags-macros"
"xladd-derive"
"xls_table_derive"
"xml-attributes-derive"
"xml-data-derive"
"xml-schema-derive"
"xmlparser-derive-core"
"xmpp-derive"
"xops_macros"
"xorstring-procmacro"
"xous-macros"
"xql-derive"
"xshell-macros"
"xtask-wasm-run-example"
"xtensa-lx-rt-proc-macros"
"xtensa-lx106-rt-proc-macros"
"xtensa-lx6-rt-proc-macros"
"xtor_derive"
"xtra_proc"
"xui-macros"
"xxlib_builder"
"xylem-codegen"
"ya-runtime-sdk-derive"
"yaaf-macros"
"yade"
"yaga-derive"
"yare-macro"
"yarte_derive"
"yarte_lexer_gencode"
"yasec_derive"
"yaserde_derive"
"yatima-rustyline-derive"
"yatt_orm_derive"
"yerpc_derive"
"yew-component"
"yew-fs-router-macro"
"yew-interop-macro"
"yew-macro"
"yew-route-breadcrumbs-derive"
"yew-router-macro"
"yew-router-min-macro"
"yew-router-nested-macro"
"yew-style-in-rs-macro"
"yew_form_derive"
"yewdux-macros"
"yewtil-macro"
"yield-closures-impl"
"yolo_keyword"
"yooper_derive"
"you-can-build-macros"
"youxi-codegen"
"yoyo-macros"
"yui_derive"
"z3d"
"zapper_derive"
"zbus_macros"
"zc-derive"
"zephyrus-macros"
"zero_v_gen"
"zeroable_derive"
"zeroconf-macros"
"zerocopy-derive"
"zerogc-derive"
"zeroize_derive"
"zeronet_sign_derive"
"zestors-codegen"
"zfs-rs-macros"
"zhi_enum_derive"
"zipkin-macros"
"zisvalidator_derive"
"zkp-macros-impl"
"zoet-macro"
"zone_cfg_derive"
"zookeeper_derive"
"zstr"
"zvariant_derive"
]
================================================
FILE: flake.nix
================================================
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
registry-crates-io = {
url = "github:rust-lang/crates.io-index";
flake = false;
};
};
outputs = { self, flake-utils, nixpkgs, registry-crates-io }@inputs:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
inherit (builtins) toJSON typeOf;
inherit (nixpkgs.lib) isDerivation isFunction isAttrs mapAttrsToList listToAttrs flatten;
nocargo-lib = import ./lib { inherit (nixpkgs) lib; };
in flake-utils.lib.eachSystem supportedSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
defaultRegistries = {
"https://github.com/rust-lang/crates.io-index" =
nocargo-lib.pkg-info.mkIndex pkgs.fetchurl registry-crates-io
(import ./crates-io-override {
inherit (nixpkgs) lib;
inherit pkgs;
});
};
in rec {
apps.default = {
type = "app";
program = "${packages.noc}/bin/noc";
};
# Is there a better place? `naersk` places builders under `lib.${system}`.
lib = rec {
mkIndex = nocargo-lib.pkg-info.mkIndex pkgs.fetchurl;
buildRustCrate = pkgs.callPackage ./build-rust-crate {
inherit (packages) toml2json;
inherit nocargo-lib;
};
mkRustPackageOrWorkspace = pkgs.callPackage nocargo-lib.support.mkRustPackageOrWorkspace {
inherit defaultRegistries buildRustCrate;
};
};
packages = rec {
default = noc;
toml2json = pkgs.callPackage ./toml2json { };
noc = (lib.mkRustPackageOrWorkspace {
src = ./noc;
}).release.nocargo.bin;
cache = pkgs.callPackage ./cache {
inherit (lib) mkRustPackageOrWorkspace;
};
};
checks = let
okDrv = derivation {
name = "success";
inherit system;
builder = "/bin/sh";
args = [ "-c" ": >$out" ];
};
checkArgs = {
inherit pkgs defaultRegistries;
assertEq = got: expect: {
__assertion = true;
fn = name:
if toJSON got == toJSON expect then
okDrv
else
pkgs.runCommand name {
nativeBuildInputs = [ pkgs.jq ];
got = toJSON got;
expect = toJSON expect;
} ''
if [[ ''${#got} < 32 && ''${#expect} < 32 ]]; then
echo "got: $got"
echo "expect: $expect"
else
echo "got:"
jq . <<<"$got"
echo
echo "expect:"
jq . <<<"$expect"
echo
echo "diff:"
diff -y <(jq . <<<"$got") <(jq . <<<"$expect")
exit 1
fi
'';
};
};
tests = with nocargo-lib; {
_0000-semver-compare = semver.semver-compare-tests;
_0001-semver-req = semver.semver-req-tests;
_0002-cfg-parser = target-cfg.cfg-parser-tests;
_0003-cfg-eval = target-cfg.cfg-eval-tests;
_0004-platform-cfg = target-cfg.platform-cfg-tests;
_0005-glob = glob.glob-tests;
_0006-sanitize-relative-path = support.sanitize-relative-path-tests;
_0100-pkg-info-from-toml = pkg-info.pkg-info-from-toml-tests;
_0101-preprocess-feature = resolve.preprocess-feature-tests;
_0102-update-feature = resolve.update-feature-tests;
_0103-resolve-feature = resolve.resolve-feature-tests;
_0200-resolve-deps = resolve.resolve-deps-tests;
_0201-build-from-src-dry = support.build-from-src-dry-tests;
} // import ./tests {
inherit pkgs self inputs defaultRegistries;
};
flattenTests = prefix: v:
if isDerivation v then {
name = prefix;
value = v;
} else if v ? __assertion then {
name = prefix;
value = v.fn prefix;
} else if isFunction v then
flattenTests prefix (v checkArgs)
else if isAttrs v then
mapAttrsToList (name: flattenTests "${prefix}-${name}") v
else
throw "Unexpect test type: ${typeOf v}";
tests' = listToAttrs (flatten (mapAttrsToList flattenTests tests));
in tests';
});
}
================================================
FILE: lib/default.nix
================================================
{ lib }:
let
callLib = file: import file { inherit lib self; };
self = {
glob = callLib ./glob.nix;
semver = callLib ./semver.nix;
target-cfg = callLib ./target-cfg.nix;
pkg-info = callLib ./pkg-info.nix;
resolve = callLib ./resolve.nix;
support = callLib ./support.nix;
};
in self
================================================
FILE: lib/glob.nix
================================================
{ lib, ... }:
let
inherit (builtins) match readDir split foldl';
inherit (lib)
replaceStrings isString concatStrings stringLength hasPrefix substring concatStringsSep
head tail init filter
isAttrs attrNames mapAttrs getAttrFromPath;
in
rec {
# We don't allow root-based glob and separator `/` or `\` inside brackets.
globBracketPat = ''\[!?[^\/][^]\/]*]'';
globAtomPat = ''[^[\/]|${globBracketPat}'';
globPat = ''((${globAtomPat})+[\/])*(${globAtomPat})+'';
# Parse a glob pattern into a list of segments.
#
# String -> List ({ lit: String } | { re: String } | { deep: true })
#
# `lit` for simple string literal.
# `re` for segment matching.
# `deep` for `**`
#
# https://docs.rs/glob/0.3.0/glob/struct.Pattern.html
# https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_04
parseGlob = glob:
let
translateAtom = m:
let m' = head m; in
if isString m then
replaceStrings
[ "\\" "{" "(" ")" "^" "$" "|" "." "?" "*" "+" ]
[ "/" "\\{" "\\(" "\\)" "\\^" "\\$" "\\|" "\\." "." ".*" "\\+" ]
m
else if hasPrefix "[!" m' then
"[^" + substring 2 (stringLength m') m'
else
m';
translateSegment = seg:
if seg == "**" then
{ deep = true; }
else if match "[^[?*]+" seg != null then
{ lit = seg; }
else
{ re = concatStrings (map translateAtom (split "(${globBracketPat})" seg)); };
segments = filter (s: isString s && s != "") (split ''/|\\'' glob);
in
if match globPat glob == null then
throw ''
Invalid glob pattern: ${glob}
Note that we don't support root-based pattern and separator `/` or `\` inside brackets.
''
else
map translateSegment segments;
# Find all paths in a tree matching a given glob pattern.
# A path is represented as a list of segments.
#
# String -> Set -> List (List String)
globMatchTree = glob: tree:
let
flatMap = f: foldl' (ret: x: ret ++ f x) [];
go = path: pats:
let
pat = head pats;
pats' = tail pats;
curTree = getAttrFromPath path tree;
keys = if isAttrs curTree then attrNames curTree else [];
in
if pats == [] then
[ path ]
else if pat ? lit then
if pat.lit == "." then
go path pats'
else if pat.lit == ".." then
if path == [] then
[]
else
go (init path) pats'
else if curTree ? ${pat.lit} then
go (path ++ [ pat.lit ]) pats'
else
[]
else if pat ? deep then # `**`
go path pats' ++
flatMap (k: go (path ++ [ k ]) pats) keys # Pass `pats` to recurse into deep directories.
else if pat ? re then
flatMap (k: go (path ++ [ k ]) pats')
(filter (k: match pat.re k != null) keys)
else
throw "Unreachable";
in
go [] (parseGlob glob);
# Find all paths inside a filesystem directory matching a given glob pattern.
# A path is represented as a relative string with `/` as segment separator, eg. "" (root), "foo", "foo/bar"
#
# String -> Path -> List String
globMatchDir = glob: dir:
let
pathToTree = dir:
mapAttrs
(k: ty: if ty == "directory" then pathToTree (dir + "/${k}") else ty)
(readDir dir);
ret = globMatchTree glob (pathToTree dir);
in
map (concatStringsSep "/") ret;
glob-tests = { assertEq, ... }: {
"0parse" = let
assertInvalid = glob: assertEq (builtins.tryEval (parseGlob glob)) { success = false; value = false; };
assertParsed = glob: expect: assertEq (parseGlob glob) expect;
in {
invalid1 = assertInvalid "";
invalid2 = assertInvalid "/";
invalid3 = assertInvalid "/foo";
invalid4 = assertInvalid "foo//bar";
lit1 = assertParsed "foo" [ { lit = "foo"; } ];
lit2 = assertParsed "!.(^$){}" [ { lit = "!.(^$){}"; } ];
lit3 = assertParsed "." [ { lit = "."; } ];
lit4 = assertParsed ".." [ { lit = ".."; } ];
re1 = assertParsed "*" [ { re = ''.*''; } ];
re2 = assertParsed ".*" [ { re = ''\..*''; } ];
re3 = assertParsed "*.*" [ { re = ''.*\..*''; } ];
re4 = assertParsed "[[][]][![][!]][a-z0-]" [ { re = ''[[][]][^[][^]][a-z0-]''; } ];
re5 = assertParsed "?.*[[][?.*]?.*" [ { re = ''.\..*[[][?.*].\..*''; } ];
re6 = assertParsed ".[.]" [ { re = ''\.[.]''; } ];
deep1 = assertParsed "**" [ { deep = true; } ];
compound1 = assertParsed
"./foo/**/*.nix"
[ { lit = "."; } { lit = "foo"; } { deep = true; } { re = ''.*\.nix''; } ];
compound2 = assertParsed
".*/../log/[!abc]*-[0-9T:-]+0000.log"
[ { re = ''\..*''; } { lit = ".."; } { lit = "log"; } { re = ''[^abc].*-[0-9T:-]\+0000\.log''; } ];
};
"1match-tree" = let
tree = {
a = null;
b = null;
b1 = null;
b2 = null;
bcd = null;
bed = null;
c = {
d.e = {
af = null;
f = null;
};
g.h = null;
wtf = null;
};
f = null;
z = {
a = null;
b = {
c = null;
d.e = null;
};
};
};
assertMatch = glob: expect:
let
ret = globMatchTree glob tree;
ret' = map (concatStringsSep "/") ret;
in
assertEq ret' expect;
in {
exact1 = assertMatch "a" [ "a" ];
exact2 = assertMatch "c/g/h" [ "c/g/h" ];
exact3 = assertMatch "c/g" [ "c/g" ];
dot1 = assertMatch "./a" [ "a" ];
dot2 = assertMatch "./a/../c/g/./h" [ "c/g/h" ];
re1 = assertMatch "b*" [ "b" "b1" "b2" "bcd" "bed" ];
re2 = assertMatch "b?" [ "b1" "b2" ];
re3 = assertMatch "c/*" [ "c/d" "c/g" "c/wtf" ];
re4 = assertMatch "b?d" [ "bcd" "bed" ];
deep1 = assertMatch "**/b?d" [ "bcd" "bed" ];
deep2 = assertMatch "c/**/*f" [ "c/wtf" "c/d/e/af" "c/d/e/f" ];
deep3 = assertMatch "**/f/.." [ "" "c/d/e" ];
deep4 = assertMatch "[wz]/**" [ "z" "z/a" "z/b" "z/b/c" "z/b/d" "z/b/d/e" ];
};
"2match-dir" = {
compound1 = assertEq (globMatchDir "*-*.nix" ./.) [ "pkg-info.nix" "target-cfg.nix" ];
compound2 = assertEq (globMatchDir "./features/../**/tokio-[!wtf][opq]?" ../tests) [ "tokio-app" ];
};
};
}
================================================
FILE: lib/pkg-info.nix
================================================
{ lib, ... }:
let
inherit (builtins) readFile readDir fromJSON fromTOML toString attrNames match;
inherit (lib)
stringLength splitString replaceStrings substring isString toLower
filter listToAttrs mapAttrs mapAttrsToList optionalAttrs warnIf;
in
rec {
toPkgId = { name, version, source ? null, ... }:
if source != null then
"${name} ${version} (${source})"
else
# Local crates must be collide names. Simply use the name to make overriding easier.
name;
mkIndex = fetchurl: path: overrides: let
# TODO: We currently only support legacy format used by crates.io-index.
# https://github.com/rust-lang/cargo/blob/2f3df16921deb34a92700f4d5a7ecfb424739558/src/cargo/sources/registry/mod.rs#L230-L244
downloadEndpoint = (fromJSON (readFile (path + "/config.json"))).dl;
mkDownloadUrl =
assert match ".*\\{.*" downloadEndpoint == null;
{ name, version, ... }: "${downloadEndpoint}/${name}/${version}/download";
mkSrc = { name, version, sha256 }@args: fetchurl {
# Use the same name as nixpkgs to benifit from cache.
# https://github.com/NixOS/nixpkgs/pull/122158/files#diff-eb8b8729bfd36f8878c2d8a99f67a2bebb912e9f78c5d2a72457b1f572e26986R67
name = "crate-${name}-${version}.tar.gz";
url = mkDownloadUrl args;
inherit sha256;
};
go = path:
mapAttrs (k: v:
if v == "directory"
then go (path + "/${k}")
else mkPkgInfoSet mkSrc k (readFile (path + "/${k}")) (overrides.${k} or null)
) (removeAttrs (readDir path) [ "config.json" ]);
in
go path // { __registry_index = true; };
# Get pkg info of the given package, with overrides applied if exists.
getPkgInfoFromIndex = index: { name, version, checksum ? null, ... }: let
name' = toLower name;
len = stringLength name';
crate =
if len == 1 then
index."1".${name'} or null
else if len == 2 then
index."2".${name'} or null
else if len == 3 then
index."3".${substring 0 1 name'}.${name'} or null
else
index.${substring 0 2 name'}.${substring 2 2 name'}.${name'} or null;
info = crate.${version} or null;
in
if !(index ? __registry_index) then
throw "Invalid registry. Do you forget `mkIndex` on registry paths?"
else if crate == null then
throw "Package ${name} is not found in index"
else if info == null then
throw "Package ${name} doesn't have version ${version} in index. Available versions: ${toString (attrNames crate)}"
else if info.sha256 != null && checksum != null && info.sha256 != checksum then
throw "Package ${name} ${version} hash mismatched, expect ${info.sha256}, got ${checksum}"
else
info;
# Make a set of pkg infos keyed by version.
mkPkgInfoSet = mkSrc: name: content: override: let
lines = filter (line: line != "") (splitString "\n" content);
parseLine = line: let parsed = fromJSON line; in {
name = parsed.vers;
value = mkPkgInfoFromRegistry mkSrc parsed
// optionalAttrs (override != null) {
# Proc macro crates behave differently in dependency resolution.
procMacro = (override { inherit (parsed) version; features = { }; }).procMacro or false;
__override = override;
};
};
in
listToAttrs (map parseLine lines);
# Package info:
# {
# name = "libz-sys"; # The name in registry.
# version = "0.1.0"; # Semver.
# src = ; # Source path.
# sha256 = "123456...."; # Hash of the `src` tarball. (null or string)
# yanked = false; # Whether it's yanked.
# links = "z"; # The native library to link. (null or string)
# procMacro = false; # Whether this is a proc-macro library. See comments below.
# features = { # Features provided.
# default = [ "std" ];
# std = [];
# };
# dependencies = [
# {
# name = "libc"; # Reference name.
# package = "libc"; # Dependency's name in registry. (default to be `name`)
# req = "^0.1.0"; # Semver requirement.
# features = [ "foo" ]; # Enabled features.
# optional = false; # Whether this dependency is optional.
# default_features = true; # Whether to enable default features.
# target = "cfg(...)"; # Only required on some targets. (null or string, default to be null)
# kind = "normal"; # Dependencies (one of "normal", "dev", "build", default to be "normal")
# # `registry` and `public` are not supported.
# }
# ];
# }
mkPkgInfoFromRegistry =
mkSrc:
# https://github.com/rust-lang/cargo/blob/2f3df16921deb34a92700f4d5a7ecfb424739558/src/cargo/sources/registry/mod.rs#L259
{ name, vers, deps, features, cksum, yanked ? false, links ? null, v ? 1, ... }:
if v != 1 then
throw "${name} ${vers}: Registry layout version ${toString v} is too new to understand"
else
{
inherit name features yanked links;
version = vers;
sha256 = cksum;
dependencies = map sanitizeDep deps;
# N.B. Proc macro indicator is not in the registry: https://github.com/rust-lang/cargo/issues/9605
# This would be overrided in `mkPkgInfoSet`.
procMacro = false;
src = mkSrc {
inherit name;
version = vers;
sha256 = cksum;
};
};
# Sanitize a dependency reference.
# Handling `package` and fill missing fields.
sanitizeDep =
{ name
, package ? name
, version ? null # Cargo.toml use `version`
, req ? version
, features ? []
, optional ? false
, default_features ? true
, target ? null
, kind
, ...
}@args: args // {
inherit name package req features optional default_features target kind;
# Note that `package` == `name` is not the same as omitting `package`.
# See: https://github.com/rust-lang/cargo/issues/6827
# Here we let `package` fallback to name, but set a special `rename` to the renamed `name`
# if `package` != `name`. `rename` will affect the `--extern` flags.
#
# For remind:
# - `name` is used for coresponding feature name for optional dependencies.
# - `package` is used for the original package name of dependency crate.
# - If `package` isn't set, the code name (for `use` or `extern crate`) of the dependency is its lib name.
# `--extern` also use its own lib name.
# - If `package` is set, the code name and `--extern` both use the renamed `name`.
} // optionalAttrs (args.package or null != null) {
rename = replaceStrings ["-"] ["_"] name;
};
# Build a simplified crate into from a parsed Cargo.toml.
mkPkgInfoFromCargoToml = { lockVersion ? 3, package, features ? {}, target ? {}, ... }@args: src: let
transDeps = target: kind:
mapAttrsToList (name: v:
{
inherit name target kind;
package = v.package or name;
# For path or git dependencies, `version` can be omitted.
req = if isString v then v else v.version or null;
features = v.features or [];
optional = v.optional or false;
# It's `default-features` in Cargo.toml, but `default_features` in index and in pkg info.
default_features =
warnIf (v ? default_features) "Ignoring `default_features`. Do you mean `default-features`?"
(v.default-features or true);
# This is used for dependency resoving inside Cargo.lock.
source =
if v ? registry then
throw "Dependency with `registry` is not supported. Use `registry-index` with explicit URL instead."
else if v ? registry-index then
"registry+${v.registry-index}"
else if v ? git then
# For v1 and v2, git-branch URLs are encoded as "git+url" with no query parameters.
if v ? branch && lockVersion >= 3 then
"git+${v.git}?branch=${v.branch}"
else if v ? tag then
"git+${v.git}?tag=${v.tag}"
else if v ? rev then
"git+${v.git}?rev=${v.rev}"
else
"git+${v.git}"
else if v ? path then
# Local crates are mark with `null` source.
null
else
# Default to use crates.io registry.
# N.B. This is necessary and must not be `null`, or it will be indinstinguishable
# with local crates or crates from other registries.
"registry+https://github.com/rust-lang/crates.io-index";
# See `sanitizeDep`
} // optionalAttrs (v.package or null != null) {
rename = replaceStrings ["-"] ["_"] name;
});
collectTargetDeps = target: { dependencies ? {}, dev-dependencies ? {}, build-dependencies ? {}, ... }:
transDeps target "normal" dependencies ++
transDeps target "dev" dev-dependencies ++
transDeps target "build" build-dependencies;
in
{
inherit (package) name version;
inherit src features;
links = package.links or null;
procMacro = args.lib.proc-macro or false;
dependencies =
collectTargetDeps null args ++
mapAttrsToList collectTargetDeps target;
};
pkg-info-from-toml-tests = { assertEq, ... }: {
simple = let
cargoToml = fromTOML (readFile ../tests/tokio-app/Cargo.toml);
info = mkPkgInfoFromCargoToml cargoToml "";
expected = {
name = "tokio-app";
version = "0.0.0";
features = { };
src = "";
links = null;
procMacro = false;
dependencies = [
{
name = "tokio";
package = "tokio";
default_features = false;
features = [ "rt-multi-thread" "macros" "time" ];
kind = "normal";
optional = false;
req = "1";
target = null;
source = "registry+https://github.com/rust-lang/crates.io-index";
}
];
};
in
assertEq info expected;
build-deps =
let
cargoToml = fromTOML (readFile ../tests/build-deps/Cargo.toml);
info = mkPkgInfoFromCargoToml cargoToml "";
expected = {
name = "build-deps";
version = "0.0.0";
features = { };
src = "";
links = null;
procMacro = false;
dependencies = [
{
name = "semver";
package = "semver";
default_features = true;
features = [ ];
kind = "build";
optional = false;
req = "1";
target = null;
source = "registry+https://github.com/rust-lang/crates.io-index";
}
];
};
in
assertEq info expected;
};
}
================================================
FILE: lib/resolve.nix
================================================
{ lib, self }:
let
inherit (builtins) readFile match fromTOML toJSON;
inherit (lib)
foldl' concatStringsSep listToAttrs filter elemAt length optional sort elem flatten
hasPrefix substring
attrValues mapAttrs attrNames filterAttrs composeManyExtensions assertMsg;
inherit (self.semver) parseSemverReq;
inherit (self.pkg-info) mkPkgInfoFromCargoToml toPkgId sanitizeDep;
in rec {
# Resolve the dependencies graph based on the lock file.
# Output:
# {
# "libz-sys 0.1.0 (https://...)" = {
# # name, sha256, ... All fields from pkg info.
# dependencies = [
# {
# # name, kind, ... All fields from dependency in the pkg info.
# resolved = "libc 0.1.0 (https://...)";
# };
# };
# };
# }
#
# Currently (rust 1.63.0), there are 3 versions of the lock file.
# We supports V1, V2 and V3.
# See:
# https://github.com/rust-lang/cargo/blob/rust-1.63.0/src/cargo/core/resolver/resolve.rs#L56
# https://github.com/rust-lang/cargo/blob/rust-1.63.0/src/cargo/core/resolver/encode.rs
resolveDepsFromLock = getPkgInfo: lock: let
# For git sources, they are referenced without the locked hash part after `#`.
# Define: "git+https://github.com/dtolnay/semver?tag=1.0.4#ea9ea80c023ba3913b9ab0af1d983f137b4110a5"
# Reference: "semver 1.0.4 (git+https://github.com/dtolnay/semver?tag=1.0.4)"
removeUrlHash = s:
let m = match "([^#]*)#.*" s; in
if m == null then s else elemAt m 0;
pkgs = map
(pkg: if pkg ? source then pkg // { source = removeUrlHash pkg.source; } else pkg)
lock.package;
pkgsByName = foldl' (set: { name, ... }@pkg:
set // { ${name} = (set.${name} or []) ++ [ pkg ]; }
) {} pkgs;
resolved = listToAttrs (map resolvePkg pkgs);
resolvePkg = { name, version, source ? "", dependencies ? [], ... }@args: let
info = getPkgInfo args;
candidates = map findPkgId dependencies;
id = toPkgId args;
resolvedDependencies =
map (dep: dep // {
resolved = selectDep candidates dep;
}) info.dependencies;
# Find the exact package id of a dependency key, which may omit version or source.
findPkgId = key: let
m = match "([^ ]+)( ([^ ]+))?( \\(([^\\)]*)\\))?" key;
lockName = elemAt m 0;
lockVersion = elemAt m 2;
lockSource = elemAt m 4;
candidates =
filter (pkg:
(lockVersion != null -> pkg.version == lockVersion) &&
(lockSource != null -> pkg.source or null == lockSource))
(pkgsByName.${lockName} or []);
candidateCnt = length candidates;
in
if candidateCnt == 0 then
throw "When resolving ${id}, locked dependency `${key}` not found"
else if candidateCnt > 1 then
throw ''
When resolving ${id}, locked dependency `${key}` is ambiguous.
Found: ${toJSON candidates}
''
else
elemAt candidates 0;
selectDep = candidates: { name, package, req, source ? null, ... }:
let
# Local path or git dependencies don't have version req.
checkReq = if req != null then parseSemverReq req else (ver: true);
checkSource = if source != null then s: s == source else s: true;
selected = filter
({ name, version, source ? null, ... }: name == package && checkReq version && checkSource source)
candidates;
selectedCnt = length selected;
in
if selectedCnt == 0 then
# Cargo will omit disabled optional dependencies in lock file.
# throw "When resolving ${pkgName} ${crateVersion}, dependency ${package} ${req} isn't satisfied in lock file"
null
else if selectedCnt > 1 then
throw ''
When resolving ${id}, dependency ${package} ${if req == null then "*" else req} has multiple candidates in lock file.
Found: ${toJSON selected}
''
else
toPkgId (elemAt selected 0);
in
{
name = toPkgId args;
value = info // { dependencies = resolvedDependencies; };
};
in
assert assertMsg (lock.version or 3 == 3) "Unsupported version of Cargo.lock: ${toString lock.version}";
resolved;
# Calculate the closure of each feature, with `dep:pkg` and `pkg?/feat` syntax desugared.
# [String] -> { [String] } -> { [String | { dep: String, feat?: String }] }
preprocessFeatures = optionalDeps: defs: let
allRefs = flatten (attrValues defs);
defs' =
listToAttrs
(map (dep: { name = dep; value = [ "dep:${dep}" ]; })
(filter (dep: !elem "dep:${dep}" allRefs)
optionalDeps))
// defs;
go = prev: feat:
let
m = match "([a-zA-Z0-9]+)(\\?)?/([a-zA-Z0-9]+)" feat;
depName = elemAt m 0;
isWeak = elemAt m 1 != null;
depFeat = elemAt m 2;
in if elem feat prev then
prev
else if defs' ? ${feat} then
foldl' go ([ feat ] ++ prev) defs'.${feat}
else if hasPrefix "dep:" feat then
[ { dep = substring 4 (-1) feat; } ] ++ prev
else if m == null then
[ feat ] ++ prev
else if isWeak then
[ { dep = depName; feat = depFeat; } ] ++ prev
else
[ { dep = depName; } { dep = depName; feat = depFeat; } ] ++ prev;
fixed = mapAttrs (feat: _: go [ ] feat) defs';
in
fixed;
# Enable `features` in `prev` and do recursive update according to `defs`.
# Optional dependencies must be included in `defs`.
enableFeatures = pkgId: defs: prev: features:
foldl' (prev: feat: let
m = match "(.*)/.*" feat;
mDep = elemAt m 0;
nexts =
if m == null then
# Must be defined.
defs.${feat} or (throw ''
Feature '${feat}' is invalid for ${pkgId}.
Possible features: ${concatStringsSep "," (attrNames defs)}
'')
else
# Dependent features implies optional dependency to be enabled.
# But non-optional dependency doesn't have coresponding feature flag.
optional (defs ? ${mDep}) mDep;
in
if prev.${feat} or false then
prev
else
enableFeatures pkgId defs (prev // { ${feat} = true; }) nexts
) prev features;
# Resolve all features.
# Note that dependent features like `foo/bar` are only available during resolution,
# and will be removed in result set.
#
# Returns:
# {
# "libc 0.1.0 (https://...)" = [ "default" "foo" "bar" ];
# }
resolveFeatures = {
# Follows the layout of the output of `resolveDepsFromLock`.
pkgSet
# Dependency edges (`{ name, kind, resolved, ... }`) will be checked by this filter.
# Only edges returning `true` are considered and propagated.
, depFilter ? dep: true
# Eg. "libc 0.1.0 (https://...)"
, rootId
# Eg. [ "foo" "bar/baz" ]
, rootFeatures
}: let
featureDefs = mapAttrs (id: { features, dependencies, ... }:
features //
listToAttrs
(map (dep: { name = dep.name; value = []; })
# We should collect all optional dependencies for feature def, even though they are not selected.
# This happens on `rand@0.8.3`, whose `default` feature enables `rand_hc`, which is only available
# for `cfg(target_os = "emscripten")`. This feature should be still enable, though optional dependency
# is not.
(filter (dep: dep.optional) dependencies))
) pkgSet;
# initialFeatures = mapAttrs (id: defs: mapAttrs (k: v: false) defs) featureDefs;
initialFeatures = mapAttrs (id: info: {}) pkgSet;
# Overlay of spreading 's nested features into dependencies and enable optional dependencies.
updateDepsOverlay = id: final: prev: let
info = pkgSet.${id};
finalFeatures = final.${id} or {};
updateDep = { name, optional, resolved, default_features, features, ... }: final: prev: let
depFeatures =
lib.optional (default_features && featureDefs.${resolved} ? default) "default" ++
features ++
filter (feat: feat != null)
(map (feat: let m = match "(.*)/(.*)" feat; in
if m != null && elemAt m 0 == name then
elemAt m 1
else
null
) (attrNames finalFeatures));
in
{
${resolved} =
# This condition must be evaluated under `${resolved} =`,
# or we'll enter an infinite recursion.
if optional -> finalFeatures.${name} or false then
enableFeatures
resolved
featureDefs.${resolved}
prev.${resolved}
depFeatures
else
prev.${resolved};
};
in
composeManyExtensions
(map updateDep
(filter depFilter info.dependencies))
final
prev;
rootOverlay = final: prev: {
${rootId} = enableFeatures
rootId
featureDefs.${rootId}
initialFeatures.${rootId}
rootFeatures;
};
final =
composeManyExtensions
(map updateDepsOverlay (attrNames pkgSet) ++ [ rootOverlay ])
final
initialFeatures;
final' =
mapAttrs (id: feats: filter (feat: match ".*/.*" feat == null) (attrNames feats)) final;
in
final';
preprocess-feature-tests = { assertEq, ... }: let
test = optionalDeps: featureDefs: expect:
assertEq (preprocessFeatures optionalDeps featureDefs) expect;
in {
recursive = test [ ] { a = [ "b" ]; b = [ "a" "c" ]; c = [ ]; } {
a = [ "c" "b" "a" ];
b = [ "c" "a" "b" ];
c = [ "c" ];
};
auto-dep = test [ "a" ] { b = [ "a" ]; } {
a = [ { dep = "a"; } "a" ];
b = [ { dep = "a"; } "a" "b" ];
};
manual-dep = test [ "a" ] { b = [ "dep:a" ]; } {
b = [ { dep = "a"; } "b" ];
};
strong-dep = test [ "a" ] { b = [ "a/c" ]; } {
a = [ { dep = "a"; } "a" ];
b = [ { dep = "a"; } { dep = "a"; feat = "c"; } "b" ];
};
weak-dep = test [ "a" ] { b = [ "a?/c" ]; } {
a = [ { dep = "a"; } "a" ];
b = [ { dep = "a"; feat = "c"; } "b" ];
};
};
update-feature-tests = { assertEq, ... }: let
testUpdate = defs: features: expect: let
init = mapAttrs (k: v: false) defs;
out = enableFeatures "pkgId" defs init features;
enabled = attrNames (filterAttrs (k: v: v) out);
in
assertEq enabled expect;
in {
simple1 = testUpdate { a = []; } [] [];
simple2 = testUpdate { a = []; } [ "a" ] [ "a" ];
simple3 = testUpdate { a = []; } [ "a" "a" ] [ "a" ];
simple4 = testUpdate { a = []; b = []; } [ "a" ] [ "a" ];
simple5 = testUpdate { a = []; b = []; } [ "a" "b" ] [ "a" "b" ];
simple6 = testUpdate { a = []; b = []; } [ "a" "b" "a" ] [ "a" "b" ];
} // (let defs = { a = []; b = [ "a" ]; }; in {
link1 = testUpdate defs [ "a" ] [ "a" ];
link2 = testUpdate defs [ "b" "a" ] [ "a" "b" ];
link3 = testUpdate defs [ "b" ] [ "a" "b" ];
link4 = testUpdate defs [ "b" "a" ] [ "a" "b" ];
link5 = testUpdate defs [ "b" "b" ] [ "a" "b" ];
}) // (let defs = { a = []; b = [ "a" ]; c = [ "a" ]; }; in {
common1 = testUpdate defs [ "a" ] [ "a" ];
common2 = testUpdate defs [ "b" ] [ "a" "b" ];
common3 = testUpdate defs [ "a" "b" ] [ "a" "b" ];
common4 = testUpdate defs [ "b" "a" ] [ "a" "b" ];
common5 = testUpdate defs [ "b" "c" ] [ "a" "b" "c" ];
common6 = testUpdate defs [ "a" "b" "c" ] [ "a" "b" "c" ];
common7 = testUpdate defs [ "b" "c" "b" ] [ "a" "b" "c" ];
}) // (let defs = { a = [ "b" "c" ]; b = [ "d" "e" ]; c = [ "f" "g"]; d = []; e = []; f = []; g = []; }; in {
tree1 = testUpdate defs [ "a" ] [ "a" "b" "c" "d" "e" "f" "g" ];
tree2 = testUpdate defs [ "b" ] [ "b" "d" "e" ];
tree3 = testUpdate defs [ "d" ] [ "d" ];
tree4 = testUpdate defs [ "d" "b" "g" ] [ "b" "d" "e" "g" ];
tree5 = testUpdate defs [ "c" "e" "f" ] [ "c" "e" "f" "g" ];
}) // (let defs = { a = [ "b" ]; b = [ "c" ]; c = [ "b" ]; }; in {
cycle1 = testUpdate defs [ "b" ] [ "b" "c" ];
cycle2 = testUpdate defs [ "c" ] [ "b" "c" ];
cycle3 = testUpdate defs [ "a" ] [ "a" "b" "c" ];
});
resolve-feature-tests = { assertEq, ... }: let
test = pkgSet: rootId: rootFeatures: expect: let
resolved = resolveFeatures { inherit pkgSet rootId rootFeatures; };
expect' = mapAttrs (id: feats: sort (a: b: a < b) feats) expect;
in
assertEq resolved expect';
pkgSet1 = {
a = {
features = { foo = [ "bar" ]; bar = []; baz = [ "b" ]; };
dependencies = [
{ name = "b"; resolved = "b-id"; optional = true; default_features = true; features = [ "a" ]; }
{ name = "unused"; resolved = null; optional = true; default_features = true; features = []; }
];
};
b-id = {
features = { default = []; foo = []; bar = [ "foo" ]; a = []; };
dependencies = [];
};
};
pkgSet2 = {
my-id = {
features = { default = [ "tokio/macros" ]; };
dependencies = [
{ name = "tokio"; resolved = "tokio-id"; optional = false; default_features = false; features = [ "fs" ]; }
{ name = "dep"; resolved = "dep-id"; optional = false; default_features = true; features = []; }
];
};
dep-id = {
features = { default = [ "tokio/sync" ]; };
dependencies = [
{ name = "tokio"; resolved = "tokio-id"; optional = false; default_features = false; features = [ "sync" ]; }
];
};
tokio-id = {
features = { default = []; fs = []; sync = []; macros = []; io = []; };
dependencies = [];
};
};
in {
simple = test pkgSet1 "a" [ "foo" ] {
a = [ "foo" "bar" ];
b-id = [ ];
};
depend = test pkgSet1 "a" [ "foo" "baz" ] {
a = [ "foo" "bar" "baz" "b" ];
b-id = [ "default" "a" ];
};
override = test pkgSet1 "a" [ "b/bar" ] {
a = [ "b" ];
b-id = [ "default" "a" "bar" "foo" ];
};
merge = test pkgSet2 "my-id" [ "default" ] {
my-id = [ "default" ];
dep-id = [ "default" ];
tokio-id = [ "fs" "sync" "macros" ];
};
};
resolve-deps-tests = { assertEq, defaultRegistries, ... }: {
simple = let
index = {
libc."0.1.12" = { name = "libc"; version = "0.1.12"; dependencies = []; };
libc."0.2.95" = { name = "libc"; version = "0.2.95"; dependencies = []; };
testt."0.1.0" = {
name = "testt";
version = "0.1.0";
dependencies = map sanitizeDep [
{ name = "libc"; req = "^0.1.0"; kind = "normal"; }
{ name = "liba"; package = "libc"; req = "^0.2.0"; kind = "normal"; }
];
};
};
lock = {
package = [
{
name = "libc";
version = "0.1.12";
source = "registry+https://github.com/rust-lang/crates.io-index";
}
{
name = "libc";
version = "0.2.95";
source = "registry+https://github.com/rust-lang/crates.io-index";
}
{
name = "testt";
version = "0.1.0";
dependencies = [
"libc 0.1.12"
"libc 0.2.95 (registry+https://github.com/rust-lang/crates.io-index)"
];
}
];
};
expected = {
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = {
name = "libc";
version = "0.1.12";
dependencies = [ ];
};
"libc 0.2.95 (registry+https://github.com/rust-lang/crates.io-index)" = {
name = "libc";
version = "0.2.95";
dependencies = [ ];
};
"testt" = {
name = "testt";
version = "0.1.0";
dependencies = [
{
name = "libc";
package = "libc";
req = "^0.1.0";
resolved = "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)";
kind = "normal";
optional = false;
features = [];
default_features = true;
target = null;
}
{
name = "liba";
rename = "liba";
package = "libc";
req = "^0.2.0";
resolved = "libc 0.2.95 (registry+https://github.com/rust-lang/crates.io-index)";
kind = "normal";
optional = false;
features = [];
default_features = true;
target = null;
}
];
};
};
getPkgInfo = { name, version, ... }: index.${name}.${version};
resolved = resolveDepsFromLock getPkgInfo lock;
in
assertEq resolved expected;
workspace-virtual = let
lock = fromTOML (readFile ../tests/workspace-virtual/Cargo.lock);
cargoTomlFoo = fromTOML (readFile ../tests/workspace-virtual/crates/foo/Cargo.toml);
cargoTomlBar = fromTOML (readFile ../tests/workspace-virtual/crates/bar/Cargo.toml);
infoFoo = mkPkgInfoFromCargoToml cargoTomlFoo "";
infoBar = mkPkgInfoFromCargoToml cargoTomlBar "";
getCrateInfo = args:
if args ? source then
throw "No crates.io dependency"
else if args.name == "foo" then
infoFoo
else if args.name == "bar" then
infoBar
else
throw "Unknow crate: ${toJSON args}";
resolved = resolveDepsFromLock getCrateInfo lock;
in
assertEq resolved {
bar = {
dependencies = [];
features = {};
links = null;
name = "bar";
procMacro = false;
src = "";
version = "0.1.0";
};
foo = {
dependencies = [ {
default_features = true;
features = [];
kind = "normal";
name = "bar";
optional = false;
package = "bar";
req = null;
resolved = "bar";
source = null;
target = null;
} ];
features = {};
links = null;
name = "foo";
procMacro = false;
src = "";
version = "0.1.0";
};
};
};
}
================================================
FILE: lib/semver.nix
================================================
{ lib, ... }:
let
inherit (builtins) match elemAt fromJSON;
inherit (lib) compare compareLists splitString all any;
in rec {
parseSemver = ver: let
m = match "([0-9]+)\\.([0-9]+)\\.([0-9]+)(-([A-Za-z0-9.-]+))?(\\+[A-Za-z0-9.-]+)?" ver;
in
if m == null then
throw "Invalid semver: `${ver}`"
else {
maj = fromJSON (elemAt m 0);
min = fromJSON (elemAt m 1);
pat = fromJSON (elemAt m 2);
pre = elemAt m 4;
};
compareSemver = a: b: let
m1 = parseSemver a;
m2 = parseSemver b;
in
if m1.maj != m2.maj then
if m1.maj < m2.maj then -1 else 1
else if m1.min != m2.min then
if m1.min < m2.min then -1 else 1
else if m1.pat != m2.pat then
if m1.pat < m2.pat then -1 else 1
else
comparePre m1.pre m2.pre;
comparePre = a: b:
if a == null then
if b == null then
0
else
1
else if b == null then
-1
else
comparePreList (splitString "." a) (splitString "." b);
isNumber = s: match "[0-9]+" s != null;
comparePreList = compareLists (a: b:
let
num1 = if isNumber a then fromJSON a else null;
num2 = if isNumber b then fromJSON b else null;
in
if num1 != null then
if num2 != null then
compare num1 num2
else
-1
else if num2 != null then
1
else
compare a b
);
parseSemverReq = req: let
reqs = splitString "," req;
comparators = map parseComparators reqs;
in
ver: all (f: f ver) comparators && (isPreVersion ver -> any (containsExactPreVersion ver) reqs);
isPreVersion = ver: match "[0-9.]+-.*" ver != null;
containsExactPreVersion = ver: req: let
m = parseSemver ver;
in
match " *(=|<|<=|>|>=|~|\\^)? *${toString m.maj}\\.${toString m.min}\\.${toString m.pat}-.*" req != null;
opEq = { compMaj, compMin, compPat, compPre }: { maj, min, pat, pre }:
maj == compMaj &&
(compMin == null || min == compMin) &&
(compPat == null || pat == compPat) &&
(compPre == null || comparePre pre compPre == 0);
opLtGt = op: { compMaj, compMin, compPat, compPre }: { maj, min, pat, pre }:
if maj != compMaj then
op maj compMaj
else if compMin == null then
false
else if min != compMin then
op min compMin
else if compPat == null then
false
else if pat != compPat then
op pat compPat
else
op (comparePre pre compPre) 0;
opTilde = { compMaj, compMin, compPat, compPre }: { maj, min, pat, pre }:
maj == compMaj &&
(compMin == null || min == compMin) &&
(compPat == null || pat > compPat || (pat == compPat &&
comparePre pre compPre >= 0));
opCaret = { compMaj, compMin, compPat, compPre }: { maj, min, pat, pre }:
if maj != compMaj then
false
else if compMin == null then
true
else if compPat == null then
if maj > 0 then
min >= compMin
else
min == compMin
else if maj > 0 then
if min != compMin then
min > compMin
else if pat != compPat then
pat > compPat
else
comparePre pre compPre >= 0
else if min > 0 then
if min != compMin then
false
else if pat != compPat then
pat > compPat
else
comparePre pre compPre >= 0
else if min != compMin || pat != compPat then
false
else
comparePre pre compPre >= 0;
parseComparators = req: let
toInt = s: if s == null then null else fromJSON s;
star = match " *(([0-9]+)\\.(([0-9]+)\\.)?)?\\*(\\.\\*)? *" req;
star0 = elemAt star 1;
star1 = elemAt star 3;
comp = match " *(=|>|>=|<|<=|~|\\^)? *(([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(-([A-Za-z0-9.-]+))?(\\+[A-Za-z0-9.-]*)?)?)?) *" req;
compOp = elemAt comp 0;
compVer = elemAt comp 1;
compArgs = {
compMaj = toInt (elemAt comp 2);
compMin = toInt (elemAt comp 4);
compPat = toInt (elemAt comp 6);
compPre = elemAt comp 8;
};
less = a: b: a < b;
greater = a: b: a > b;
op = {
"=" = opEq compArgs;
"<" = opLtGt less compArgs;
"<=" = args: opLtGt less compArgs args || opEq compArgs args;
">" = opLtGt greater compArgs;
">=" = args: opLtGt greater compArgs args || opEq compArgs args;
"~" = opTilde compArgs;
"^" = opCaret compArgs;
}.${if compOp != null then compOp else "^"};
in
if star != null then
if star0 == null then
(ver: true)
else if star1 == null then
(ver: match "${toString star0}\\..*" ver != null)
else
(ver: match "${toString star0}\\.${toString star1}\\..*" ver != null)
else if comp != null then
(ver: op (parseSemver ver))
else
throw "Invalid version comparator: `${req}`";
semver-compare-tests = { assertEq, ... }: {
compare-simple1 = assertEq (compareSemver "1.2.3" "1.2.2") 1;
compare-simple2 = assertEq (compareSemver "1.2.3" "1.2.3") 0;
compare-simple3 = assertEq (compareSemver "1.2.3" "1.2.4") (-1);
compare-simple4 = assertEq (compareSemver "1.2.3" "1.1.3") 1;
compare-simple5 = assertEq (compareSemver "1.2.3" "1.3.3") (-1);
compare-simple6 = assertEq (compareSemver "1.2.3" "0.2.3") 1;
compare-simple7 = assertEq (compareSemver "1.2.3" "2.2.3") (-1);
};
# From https://github.com/dtolnay/semver/blob/a03d376560e0c4d16518bc271867b1981c85acf0/tests/test_version_req.rs
semver-req-tests = { assertEq, ... }: let
testMatchReq = req: { yes ? [], no ? [] }: let
inherit (lib) const;
checker = parseSemverReq req;
got = map checker (yes ++ no);
expect = map (const true) yes ++ map (const false) no;
in
assertEq got expect;
in {
eq1 = testMatchReq "=1.0.0" {
yes = [ "1.0.0" ];
no = [ "1.0.1" "0.9.9" "0.10.0" "0.1.0" "1.0.0-pre" ];
};
default = testMatchReq "^1.0.0" {
yes = [ "1.0.0" "1.1.0" "1.0.1" ];
no = [ "0.9.9" "0.10.0" "0.1.0" "1.0.0-pre" "1.0.1-pre" ];
};
exact1 = testMatchReq "=1.0.0" {
yes = [ "1.0.0" ];
no = [ "1.0.1" "0.9.9" "0.10.0" "0.1.0" "1.0.0-pre" ];
};
exact2 = testMatchReq "=0.9.0" {
yes = [ "0.9.0" ];
no = [ "0.9.1" "1.9.0" "0.0.9" "0.9.0-pre" ];
};
exact3 = testMatchReq "=0.0.2" {
yes = [ "0.0.2" ];
no = [ "0.0.1" "0.0.3" "0.0.2-pre" ];
};
exact4 = testMatchReq "=0.1.0-beta2.a" {
yes = [ "0.1.0-beta2.a" ];
no = [ "0.9.1" "0.1.0" "0.1.1-beta2.a" "0.1.0-beta2" ];
};
exact5 = testMatchReq "=0.1.0" {
yes = [ "0.1.0" "0.1.0+meta" "0.1.0+any" ];
};
gt1 = testMatchReq ">= 1.0.0" {
yes = [ "1.0.0" "2.0.0" ];
no = [ "0.1.0" "0.0.1" "1.0.0-pre" "2.0.0-pre" ];
};
gt2 = testMatchReq ">=2.1.0-alpha2" {
yes = [ "2.1.0-alpha2" "2.1.0-alpha3" "2.1.0" "3.0.0" ];
no = [ "2.0.0" "2.1.0-alpha1" "2.0.0-alpha2" "3.0.0-alpha2" ];
};
lt1 = testMatchReq "<1.0.0" {
yes = [ "0.1.0" "0.0.1" ];
no = [ "1.0.0" "1.0.0-beta" "1.0.1" "0.9.9-alpha" ];
};
le1 = testMatchReq "<= 2.1.0-alpha2" {
yes = [ "2.1.0-alpha2" "2.1.0-alpha1" "2.0.0" "1.0.0" ];
no = [ "2.1.0" "2.2.0-alpha1" "2.0.0-alpha2" "1.0.0-alpha2" ];
};
multi1 = testMatchReq ">1.0.0-alpha, <1.0.0" {
yes = [ "1.0.0-beta" ];
};
multi2 = testMatchReq ">1.0.0-alpha, <1.0" {
no = [ "1.0.0-beta" ];
};
multi3 = testMatchReq ">1.0.0-alpha, <1" {
no = [ "1.0.0-beta" ];
};
multi4 = testMatchReq "> 0.0.9, <= 2.5.3" {
yes = [ "0.0.10" "1.0.0" "2.5.3" ];
no = [ "0.0.8" "2.5.4" ];
};
multi5 = testMatchReq "0.3.0, 0.4.0" {
no = [ "0.0.8" "0.3.0" "0.4.0" ];
};
multi6 = testMatchReq "<= 0.2.0, >= 0.5.0" {
no = [ "0.0.8" "0.3.0" "0.5.1" ];
};
multi7 = testMatchReq "^0.1.0, ^0.1.4, ^0.1.6" {
yes = [ "0.1.6" "0.1.9" ];
no = [ "0.1.0" "0.1.4" "0.2.0" ];
};
multi8 = testMatchReq ">=0.5.1-alpha3, <0.6" {
yes = [ "0.5.1-alpha3" "0.5.1-alpha4" "0.5.1-beta" "0.5.1" "0.5.5" ];
no = [ "0.5.1-alpha1" "0.5.2-alpha3" "0.5.5-pre" "0.5.0-pre" "0.6.0" "0.6.0-pre" ];
};
tilde1 = testMatchReq "~1" {
yes = [ "1.0.0" "1.0.1" "1.1.1" ];
no = [ "0.9.1" "2.9.0" "0.0.9" ];
};
tilde2 = testMatchReq "~1.2" {
yes = [ "1.2.0" "1.2.1" ];
no = [ "1.1.1" "1.3.0" "0.0.9" ];
};
tilde3 = testMatchReq "~1.2.2" {
yes = [ "1.2.2" "1.2.4" ];
no = [ "1.2.1" "1.9.0" "1.0.9" "2.0.1" "0.1.3" ];
};
tilde4 = testMatchReq "~1.2.3-beta.2" {
yes = [ "1.2.3" "1.2.4" "1.2.3-beta.2" "1.2.3-beta.4" ];
no = [ "1.3.3" "1.1.4" "1.2.3-beta.1" "1.2.4-beta.2" ];
};
caret1 = testMatchReq "^1" {
yes = [ "1.1.2" "1.1.0" "1.2.1" "1.0.1" ];
no = [ "0.9.1" "2.9.0" "0.1.4" "1.0.0-beta1" "0.1.0-alpha" "1.0.1-pre" ];
};
caret2 = testMatchReq "^1.1" {
yes = [ "1.1.2" "1.1.0" "1.2.1" ];
no = [ "0.9.1" "2.9.0" "1.0.1" "0.1.4" ];
};
caret3 = testMatchReq "^1.1.2" {
yes = [ "1.1.2" "1.1.4" "1.2.1" ];
no = [ "0.9.1" "2.9.0" "1.1.1" "0.0.1" "1.1.2-alpha1" "1.1.3-alpha1" "2.9.0-alpha1" ];
};
caret4 = testMatchReq "^0.1.2" {
yes = [ "0.1.2" "0.1.4" ];
no = [ "0.9.1" "2.9.0" "1.1.1" "0.0.1" "0.1.2-beta" "0.1.3-alpha" "0.2.0-pre" ];
};
caret5 = testMatchReq "^0.5.1-alpha3" {
yes = [ "0.5.1-alpha3" "0.5.1-alpha4" "0.5.1-beta" "0.5.1" "0.5.5" ];
no = [ "0.5.1-alpha1" "0.5.2-alpha3" "0.5.5-pre" "0.5.0-pre" "0.6.0" ];
};
caret6 = testMatchReq "^0.0.2" {
yes = [ "0.0.2" ];
no = [ "0.9.1" "2.9.0" "1.1.1" "0.0.1" "0.1.4" ];
};
caret7 = testMatchReq "^0.0" {
yes = [ "0.0.2" "0.0.0" ];
no = [ "0.9.1" "2.9.0" "1.1.1" "0.1.4" ];
};
caret8 = testMatchReq "^0" {
yes = [ "0.9.1" "0.0.2" "0.0.0" ];
no = [ "2.9.0" "1.1.1" ];
};
caret9 = testMatchReq "^1.4.2-beta.5" {
yes = [ "1.4.2" "1.4.3" "1.4.2-beta.5" "1.4.2-beta.6" "1.4.2-c" ];
no = [ "0.9.9" "2.0.0" "1.4.2-alpha" "1.4.2-beta.4" "1.4.3-beta.5" ];
};
star1 = testMatchReq "*" {
yes = [ "0.9.1" "2.9.0" "0.0.9" "1.0.1" "1.1.1" ];
};
star2 = testMatchReq "1.*" {
yes = [ "1.2.0" "1.2.1" "1.1.1" "1.3.0" ];
no = [ "0.0.9" ];
};
star3 = testMatchReq "1.2.*" {
yes = [ "1.2.0" "1.2.2" "1.2.4" ];
no = [ "1.9.0" "1.0.9" "2.0.1" "0.1.3" ];
};
pre = testMatchReq "=2.1.1-really.0" {
yes = [ "2.1.1-really.0" ];
};
};
}
================================================
FILE: lib/support.nix
================================================
{ lib, self }:
let
inherit (builtins) fromTOML toJSON match tryEval split;
inherit (lib)
readFile mapAttrs mapAttrs' makeOverridable warnIf
isString hasPrefix
filter flatten elem elemAt listToAttrs subtractLists concatStringsSep
attrNames attrValues recursiveUpdate optionalAttrs;
inherit (self.pkg-info) mkPkgInfoFromCargoToml getPkgInfoFromIndex toPkgId;
inherit (self.resolve) resolveDepsFromLock resolveFeatures;
inherit (self.target-cfg) platformToCfgs evalTargetCfgStr;
inherit (self.glob) globMatchDir;
in
rec {
# https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles
defaultProfiles = rec {
dev = {
name = "dev";
build-override = defaultBuildProfile;
opt-level = 0;
debug = true;
debug-assertions = true;
overflow-checks = true;
lto = false;
panic = "unwind";
codegen-units = 256;
rpath = false;
};
release = {
name = "release";
build-override = defaultBuildProfile;
opt-level = 3;
debug = false;
debug-assertions = false;
overflow-checks = false;
lto = false;
panic = "unwind";
codegen-units = 16;
rpath = false;
};
test = dev // { name = "test"; };
bench = release // { name = "bench"; };
};
defaultBuildProfile = {
opt-level = 0;
codegen-units = 256;
};
profilesFromManifest = manifest:
let
knownFields = [
"name"
"inherits"
# "package" # Unsupported yet.
"build-override"
"opt-level"
"debug"
# split-debug-info # Unsupported.
"strip"
"debug-assertions"
"overflow-checks"
"lto"
"panic"
# incremental # Unsupported.
"codegen-units"
"rpath"
];
profiles = mapAttrs (name: p:
let unknown = removeAttrs p knownFields; in
warnIf (unknown != {}) "Unsupported fields of profile ${name}: ${toString (attrNames unknown)}"
(optionalAttrs (p ? inherits) profiles.${p.inherits} // p)
) (recursiveUpdate defaultProfiles (manifest.profile or {}));
in profiles;
mkRustPackageOrWorkspace =
{ defaultRegistries, pkgsBuildHost, buildRustCrate, stdenv }@default:
{ src # : Path
, gitSrcs ? {} # : Attrset Path
, buildCrateOverrides ? {} # : Attrset (Attrset _)
, extraRegistries ? {} # : Attrset Registry
, registries ? defaultRegistries // extraRegistries
, rustc ? pkgsBuildHost.rustc
, stdenv ? default.stdenv
}:
let
manifest = fromTOML (readFile (src + "/Cargo.toml"));
profiles = profilesFromManifest manifest;
selected = flatten (map (glob: globMatchDir glob src) manifest.workspace.members);
excluded = map sanitizeRelativePath (manifest.workspace.exclude or []);
members = subtractLists excluded selected;
lock = fromTOML (readFile (src + "/Cargo.lock"));
# We don't distinguish between v1 and v2. But v3 is different from both.
lockVersionSet = { lockVersion = lock.version or 2; };
localSrcInfos =
listToAttrs
(map (relativePath:
let
memberRoot = src + ("/" + relativePath);
memberManifest = fromTOML (readFile (memberRoot + "/Cargo.toml")) // lockVersionSet;
in {
name = toPkgId memberManifest.package;
value = mkPkgInfoFromCargoToml memberManifest memberRoot;
}
) (if manifest ? workspace then members else [ "" ]));
in mkRustPackageSet {
gitSrcInfos = mapAttrs (url: src:
mkPkgInfoFromCargoToml (fromTOML (readFile (src + "/Cargo.toml")) // lockVersionSet) src
) gitSrcs;
inherit lock profiles localSrcInfos buildRustCrate buildCrateOverrides registries rustc stdenv;
};
# -> { = { = ; }; }
mkRustPackageSet =
{ lock # :
, localSrcInfos # : Attrset PkgInfo
, gitSrcInfos # : Attrset PkgInfo
, profiles # : Attrset Profile
, buildCrateOverrides # : Attrset (Attrset _)
, buildRustCrate # : Attrset -> Derivation
, registries # : Attrset Registry
# FIXME: Cross compilation.
, rustc
, stdenv
}:
let
getPkgInfo = { source ? null, name, version, ... }@args: let
m = match "(registry|git)\\+([^#]*).*" source;
kind = elemAt m 0;
url = elemAt m 1;
in
# Local crates have no `source`.
if source == null then
localSrcInfos.${toPkgId args}
or (throw "Local crate is outside the workspace: ${toPkgId args}")
// { isLocalPkg = true; }
else if m == null then
throw "Invalid source: ${source}"
else if kind == "registry" then
getPkgInfoFromIndex
(registries.${url} or
(throw "Registry `${url}` not found. Please define it in `extraRegistries`."))
args
// { inherit source; } # `source` is for crate id, which is used for overrides.
else if kind == "git" then
gitSrcInfos.${url}
or (throw "Git source `${url}` not found. Please define it in `gitSrcs`.")
else
throw "Invalid source: ${source}";
hostCfgs = platformToCfgs stdenv.hostPlatform;
pkgSetRaw = resolveDepsFromLock getPkgInfo lock;
pkgSet = mapAttrs (id: info: info // {
dependencies = map (dep: dep // {
targetEnabled = dep.target != null -> evalTargetCfgStr hostCfgs dep.target;
}) info.dependencies;
}) pkgSetRaw;
selectDeps = pkgs: deps: features: selectKind: onlyLinks:
map
(dep: { rename = dep.rename or null; drv = pkgs.${dep.resolved}; })
(filter
({ kind, name, optional, targetEnabled, resolved, ... }@dep:
targetEnabled && kind == selectKind
&& (optional -> elem name features)
&& (if resolved == null then throw "Unresolved dependency: ${toJSON dep}" else true)
&& (onlyLinks -> pkgSet.${resolved}.links != null))
deps);
buildRustCrate' = info: args:
let
# TODO: Proc macro crates should behave differently in dependency resolution.
# But this override is applied just before the `buildRustCrate` call.
args' = args // (info.__override or lib.id) args;
args'' = args' // (buildCrateOverrides.${toPkgId info} or lib.id) args';
in
buildRustCrate args'';
mkPkg = profile: rootId: makeOverridable (
{ features }:
let
rootFeatures = if features != null then features
else if pkgSet.${rootId}.features ? default then [ "default" ]
else [];
resolvedBuildFeatures = resolveFeatures {
inherit pkgSet rootId rootFeatures;
depFilter = dep: dep.targetEnabled && dep.kind == "normal" || dep.kind == "build";
};
resolvedNormalFeatures = resolveFeatures {
inherit pkgSet rootId rootFeatures;
depFilter = dep: dep.targetEnabled && dep.kind == "normal";
};
pkgsBuild = mapAttrs (id: features: let info = pkgSet.${id}; in
if features != null then
buildRustCrate' info {
inherit (info) version src procMacro;
inherit features profile rustc;
pname = info.name;
capLints = if localSrcInfos ? id then null else "allow";
buildDependencies = selectDeps pkgsBuild info.dependencies features "build" false;
# Build dependency's normal dependency is still build dependency.
dependencies = selectDeps pkgsBuild info.dependencies features "normal" false;
linksDependencies = selectDeps pkgsBuild info.dependencies features "normal" true;
}
else
null
) resolvedBuildFeatures;
pkgs = mapAttrs (id: features: let info = pkgSet.${id}; in
if features != null then
buildRustCrate' info {
inherit (info) version src links procMacro;
inherit features profile rustc;
pname = info.name;
capLints = if localSrcInfos ? id then null else "allow";
buildDependencies = selectDeps pkgsBuild info.dependencies features "build" false;
dependencies = selectDeps pkgs info.dependencies features "normal" false;
linksDependencies = selectDeps pkgs info.dependencies features "normal" true;
}
else
null
) resolvedNormalFeatures;
in
pkgs.${rootId}
) {
features = null;
};
in
mapAttrs (_: profile:
mapAttrs' (pkgId: pkgInfo: {
name = pkgInfo.name;
value = mkPkg profile pkgId;
}) localSrcInfos
) profiles;
sanitizeRelativePath = path:
if hasPrefix "/" path then
throw "Absolute path is not allowed: ${path}"
else
concatStringsSep "/"
(filter
(s:
isString s && s != "" && s != "." &&
(if match ''.*[[?*].*|\.\.'' s != null then throw ''
Globing and `..` are not allowed: ${path}
'' else true))
(split ''[\/]'' path));
build-from-src-dry-tests = { assertEq, pkgs, defaultRegistries, ... }: let
inherit (builtins) head listToAttrs;
mkPackage = pkgs.callPackage mkRustPackageOrWorkspace {
inherit defaultRegistries;
buildRustCrate = args: args;
};
build = src: args:
head (attrValues (mkPackage ({ inherit src; } // args)).dev);
in
{
features = let ret = build ../tests/features {}; in
assertEq ret.features [ "a" "default" "semver" ]; # FIXME
dependency-features = let
ret = build ../tests/features { };
semver = (head ret.dependencies).drv;
serde = (head semver.dependencies).drv;
in assertEq
[ semver.features serde.features ]
[ [ "default" "serde" "std" ] [ /* Don't trigger default features */ ] ];
dependency-overrided = let
ret = build ../tests/features {
buildCrateOverrides."" = old: { a = "b"; };
buildCrateOverrides."serde 1.0.139 (registry+https://github.com/rust-lang/crates.io-index)" = old: {
buildInputs = [ "some-inputs" ];
};
};
semver = (head ret.dependencies).drv;
serde = (head semver.dependencies).drv;
in
assertEq serde.buildInputs [ "some-inputs" ];
dependency-kinds = let
mkSrc = from: { __toString = _: ../tests/fake-semver; inherit from; };
gitSrcs = {
"https://github.com/dtolnay/semver?tag=1.0.0" = mkSrc "tag";
"http://github.com/dtolnay/semver" = mkSrc "branch"; # v1, v2
"http://github.com/dtolnay/semver?branch=master" = mkSrc "branch"; # v3
"ssh://git@github.com/dtolnay/semver?rev=a2ce5777dcd455246e4650e36dde8e2e96fcb3fd" = mkSrc "rev";
"ssh://git@github.com/dtolnay/semver" = mkSrc "nothing";
};
extraRegistries = {
"https://www.github.com/rust-lang/crates.io-index" =
head (attrValues defaultRegistries);
};
ret = build ../tests/dependency-v3 {
inherit gitSrcs extraRegistries;
};
ret' = listToAttrs
(map (dep: {
name = if dep.rename != null then dep.rename else dep.drv.pname;
value = dep.drv.src.from or dep.drv.src.name;
}) ret.dependencies);
in
assertEq ret' {
cratesio = "crate-semver-1.0.12.tar.gz";
git_branch = "branch";
git_head = "nothing";
git_rev = "rev";
git_tag = "tag";
registry_index = "crate-semver-1.0.12.tar.gz";
};
libz-propagated = let
ret = build ../tests/libz-dynamic {};
libz = (head ret.dependencies).drv;
in
assertEq (head libz.propagatedBuildInputs).pname "zlib";
libz-link = let
ret = build ../tests/libz-dynamic {};
libz = (head ret.dependencies).drv;
libz' = (head ret.linksDependencies).drv;
in
assertEq [ libz.links libz'.links ] [ "z" "z" ];
};
sanitize-relative-path-tests = { assertEq, ... }: let
assertOk = raw: expect: assertEq (tryEval (sanitizeRelativePath raw)) { success = true; value = expect; };
assertInvalid = raw: assertEq (tryEval (sanitizeRelativePath raw)) { success = false; value = false; };
in
{
empty = assertOk "" "";
simple1 = assertOk "foo" "foo";
simple2 = assertOk "foo/bar" "foo/bar";
dot1 = assertOk "." "";
dot2 = assertOk "./././" "";
dot3 = assertOk "./foo/./bar/" "foo/bar";
dotdot1 = assertInvalid "..";
dotdot2 = assertInvalid "./foo/..";
dotdot3 = assertInvalid "../bar";
root1 = assertInvalid "/";
root2 = assertInvalid "/foo";
};
}
================================================
FILE: lib/target-cfg.nix
================================================
{ lib, ... }:
let
inherit (builtins) match tryEval;
inherit (lib)
concatStrings
length elem elemAt any all sort flatten isList
optionalAttrs mapAttrsToList;
in
rec {
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch
platformToTargetArch = platform:
if platform.isAarch32 then "arm"
else platform.parsed.cpu.name;
# https://doc.rust-lang.org/reference/conditional-compilation.html#target_os
platformToTargetOs = platform:
if platform.isDarwin then "macos"
else platform.parsed.kernel.name;
# https://github.com/rust-lang/rust/blob/9bc8c42bb2f19e745a63f3445f1ac248fb015e53/compiler/rustc_session/src/config.rs#L835
# https://doc.rust-lang.org/reference/conditional-compilation.html
platformToCfgAttrs = platform: {
# Arch info.
# https://github.com/NixOS/nixpkgs/blob/c63d4270feed5eb6c578fe2d9398d3f6f2f96811/pkgs/build-support/rust/build-rust-crate/configure-crate.nix#L126
target_arch = platformToTargetArch platform;
target_endian = if platform.isLittleEndian then "little"
else if platform.isBigEndian then "big"
else throw "Unknow target_endian for ${platform.config}";
target_env = if platform.isNone then ""
else if platform.libc == "glibc" then "gnu"
else if platform.isMusl then "musl"
else if platform.isDarwin then "" # Empty
else lib.trace platform (throw "Unknow target_env for ${platform.config}");
target_family = if platform.isUnix then "unix"
else if platform.isWindows then "windows"
else null;
target_os = platformToTargetOs platform;
target_pointer_width = toString platform.parsed.cpu.bits;
target_vendor = platform.parsed.vendor.name;
} // optionalAttrs platform.isx86 {
# These features are assume to be available.
target_feature = [ "fxsr" "sse" "sse2" ];
} // optionalAttrs platform.isUnix {
unix = true;
} // optionalAttrs platform.isWindows {
windows = true;
};
platformToCfgs = platform:
flatten (
mapAttrsToList (key: value:
if value == true then { inherit key; }
else if isList value then map (value: { inherit key value; }) value
else { inherit key value; }
) (platformToCfgAttrs platform));
# cfgs: [
# { key = "atom1"; }
# { key = "atom2"; }
# { key = "feature"; value = "foo"; }
# { key = "feature"; value = "bar"; }
# ]
evalTargetCfgStr = cfgs: s:
evalCfgExpr cfgs (parseTargetCfgExpr s);
# Cargo's parse is stricter than rustc's.
# - Must starts with `cfg(` and ends with `)`. No spaces are allowed before and after.
# - Identifiers must follows /[A-Za-z_][A-Za-z_0-9]*/.
# - Raw identifiers, raw strings, escapes in strings are not allowed.
#
# The target can also be a simple target name like `aarch64-unknown-linux-gnu`, which will be parsed
# as if it's `cfg(target = "...")`.
#
# https://github.com/rust-lang/cargo/blob/dcc95871605785c2c1f2279a25c6d3740301c468/crates/cargo-platform/src/cfg.rs
parseTargetCfgExpr = cfg: let
fail = reason: throw "${reason}, when parsing `${cfg}";
go = { fn, values, afterComma, prev }@stack: s: let
m = match ''((all|any|not) *\( *|(\)) *|(,) *|([A-Za-z_][A-Za-z_0-9]*) *(= *"([^"]*)" *)?)(.*)'' s;
mFn = elemAt m 1;
mClose = elemAt m 2;
mComma = elemAt m 3;
mIdent = elemAt m 4;
mString = elemAt m 6;
mRest = elemAt m 7;
in
if s == "" then
stack
else if m == null then
fail "No parse `${s}`"
# else if builtins.trace ([ stack m ]) (mFn != null) then
else if mFn != null then
if !afterComma then
fail "Missing comma before `${mFn}` at `${s}"
else
go { fn = mFn; values = []; afterComma = true; prev = stack; } mRest
else if mClose != null then
if prev == null then
fail "Unexpected `)` at `${s}`"
else if fn == "not" && length values == 0 then
fail "`not` must have exact one argument, got 0"
else if prev.fn == "not" && length prev.values != 0 then
fail "`not` must have exact one argument, got at least 2"
else
go (prev // { values = prev.values ++ [ { inherit (stack) fn values; } ]; afterComma = false; }) mRest
else if mComma != null then
if afterComma then
fail "Unexpected `,` at `${s}`"
else
go (stack // { afterComma = true; }) mRest
else
if !afterComma then
fail "Missing comma before identifier `${mIdent}` at `${s}"
else if fn == "not" && length values != 0 then
fail "`not` must have exact one argument, got at least 2"
else
let kv =
if mString != null then { key = mIdent; value = mString; }
else { key = mIdent; };
in
go (stack // { afterComma = false; values = values ++ [ kv ]; }) mRest;
mSimpleTarget = match "[A-Za-z_0-9_.-]+" cfg;
mCfg = match ''cfg\( *(.*)\)'' cfg;
mCfgInner = elemAt mCfg 0;
ret = go { fn = "cfg"; values = []; afterComma = true; prev = null; } mCfgInner;
in
if mSimpleTarget != null then
{ key = "target"; value = cfg; }
else if mCfg == null then
fail "Cfg expr must be a simple target string, or start with `cfg(` and end with `)`"
else if ret.prev != null then
fail "Missing `)`"
else if length ret.values != 1 then
fail "`cfg` must have exact one argument, got ${toString (length ret.values)}"
else
elemAt ret.values 0;
evalCfgExpr = cfgs: tree:
if !(tree ? fn) then
elem tree cfgs
else if tree.fn == "all" then
all (evalCfgExpr cfgs) tree.values
else if tree.fn == "any" then
any (evalCfgExpr cfgs) tree.values
else
!evalCfgExpr cfgs (elemAt tree.values 0);
cfg-parser-tests = { assertEq, ... }: let
shouldParse = cfg: expect:
assertEq (tryEval (parseTargetCfgExpr cfg)) { success = true; value = expect; };
shouldNotParse = cfg:
assertEq (tryEval (parseTargetCfgExpr cfg)) { success = false; value = false; };
in {
simple-target1 = shouldParse "thumbv8m.base-none-eabi"
{ key = "target"; value = "thumbv8m.base-none-eabi"; };
simple-target2 = shouldParse "aarch64-unknown-linux-gnu"
{ key = "target"; value = "aarch64-unknown-linux-gnu"; };
simple1 = shouldParse "cfg(atom)" { key = "atom"; };
simple2 = shouldParse ''cfg(k = "v")'' { key = "k"; value = "v"; };
complex = shouldParse ''cfg( all ( not ( a , ) , b , all ( ) , any ( c , d = "e" ) , ) )''
{
fn = "all";
values = [
{
fn = "not";
values = [ { key = "a"; } ];
}
{ key = "b"; }
{
fn = "all";
values = [];
}
{
fn = "any";
values = [
{ key = "c"; }
{ key = "d"; value = "e"; }
];
}
];
};
invalid-cfg1 = shouldNotParse "cfg (a)";
invalid-cfg2 = shouldNotParse "cfg()";
invalid-cfg3 = shouldNotParse "cfg(a,b)";
invalid-not1 = shouldNotParse "cfg(not(a,b))";
invalid-not2 = shouldNotParse "cfg(not())";
invalid-comma1 = shouldNotParse "cfg(all(,))";
invalid-comma2 = shouldNotParse "cfg(all(a,,b))";
invalid-comma3 = shouldNotParse "cfg(all(a,b,,))";
invalid-comma4 = shouldNotParse "cfg(all(a b))";
invalid-comma5 = shouldNotParse "cfg(all(any() any()))";
invalid-paren1 = shouldNotParse "cfg(all(a)))";
invalid-paren2 = shouldNotParse "cfg(all(a)";
};
cfg-eval-tests = { assertEq, ... }: let
cfgs = [
{ key = "foo"; }
{ key = "bar"; }
{ key = "feature"; value = "foo"; }
{ key = "feature"; value = "bar"; }
];
test = cfg: expect: assertEq (evalTargetCfgStr cfgs cfg) expect;
in {
simple1 = test ''cfg(foo)'' true;
simple2 = test ''cfg(baz)'' false;
simple3 = test ''cfg(feature = "foo")'' true;
simple4 = test ''cfg(foo = "")'' false;
simple5 = test ''cfg(wtf = "foo")'' false;
all1 = test ''cfg(all())'' true;
all2 = test ''cfg(all(foo))'' true;
all3 = test ''cfg(all(baz))'' false;
all4 = test ''cfg(all(foo,bar))'' true;
all5 = test ''cfg(all(foo,bar,baz))'' false;
all6 = test ''cfg(all(foo,baz,bar))'' false;
all7 = test ''cfg(all(baz,foo))'' false;
all8 = test ''cfg(all(baz,feature="foo"))'' false;
all9 = test ''cfg(all(baz,feature="wtf"))'' false;
all10 = test ''cfg(all(foo,feature="foo"))'' true;
any1 = test ''cfg(any())'' false;
any2 = test ''cfg(any(foo))'' true;
any3 = test ''cfg(any(baz))'' false;
any4 = test ''cfg(any(foo,bar))'' true;
any5 = test ''cfg(any(foo,bar,baz))'' true;
any6 = test ''cfg(any(foo,baz,bar))'' true;
any7 = test ''cfg(any(baz,foo))'' true;
any8 = test ''cfg(any(baz,feature="foo"))'' true;
any9 = test ''cfg(any(baz,feature="wtf"))'' false;
any10 = test ''cfg(any(foo,feature="wtf"))'' true;
not1 = test ''cfg(not(foo))'' false;
not2 = test ''cfg(not(wtf))'' true;
};
platform-cfg-tests = { assertEq, ... }: let
inherit (lib.systems) elaborate;
test = config: expect: let
cfgs = platformToCfgs (elaborate config);
strs = map ({ key, value ? null }:
if value != null then "${key}=\"${value}\"\n" else "${key}\n"
) cfgs;
got = concatStrings (sort (a: b: a < b) strs);
in
assertEq got expect;
in {
attrs-x86_64-linux = assertEq (platformToCfgAttrs (elaborate "x86_64-unknown-linux-gnu")) {
target_arch = "x86_64";
target_endian = "little";
target_env = "gnu";
target_family = "unix";
target_feature = ["fxsr" "sse" "sse2"];
target_os = "linux";
target_pointer_width = "64";
target_vendor = "unknown";
unix = true;
};
cfg-x86_64-linux = test "x86_64-unknown-linux-gnu" ''
target_arch="x86_64"
target_endian="little"
target_env="gnu"
target_family="unix"
target_feature="fxsr"
target_feature="sse"
target_feature="sse2"
target_os="linux"
target_pointer_width="64"
target_vendor="unknown"
unix
'';
cfg-aarch64-linux = test "aarch64-unknown-linux-gnu" ''
target_arch="aarch64"
target_endian="little"
target_env="gnu"
target_family="unix"
target_os="linux"
target_pointer_width="64"
target_vendor="unknown"
unix
'';
};
}
================================================
FILE: noc/Cargo.toml
================================================
[package]
name = "nocargo"
version = "0.0.0"
edition = "2021"
license = "MIT"
description = "Helper program for github.com/oxalica/nocargo"
repository = "https://github.com/oxalica/nocargo"
[[bin]]
name = "noc"
path = "src/main.rs"
[dependencies]
anyhow = "1.0.40"
askama = { version = "0.11.1", default-features = false }
cargo_toml = "0.11.5"
clap = { version = "3.2.8", features = ["derive"] }
glob = "0.3.0"
once_cell = "1.12.0"
regex = "1.5.4"
toml = "0.5.9"
[dev-dependencies]
expect-test = "1.3.0"
================================================
FILE: noc/src/init.rs
================================================
use std::collections::{BTreeMap, HashSet};
use std::fs::{read_dir, read_to_string, File};
use std::io::Write;
use std::path::{Path, PathBuf};
use anyhow::{bail, ensure, Context, Result};
use askama::Template;
use cargo_toml::{Dependency, Manifest, Product};
use glob::glob;
use once_cell::sync::Lazy;
use regex::Regex;
/// Create or print template `flake.nix` for your rust crate.
#[derive(clap::Args)]
pub struct Args {
/// Print the content of initial `flake.nix` to stdout rather than to `flake.nix` in
/// the current directory.
#[clap(long, short)]
print: bool,
/// Force overwrite `flake.nix` even if it exists.
#[clap(long, short, conflicts_with = "print")]
force: bool,
/// The Rust project root directory, where the root `Cargo.toml` lies in,
/// either a project or a workspace.
/// Default to be the current directory.
#[clap(long)]
root: Option,
}
impl super::App for Args {
fn run(self) -> Result<()> {
let root = self
.root
.as_deref()
.unwrap_or_else(|| Path::new("."))
.canonicalize()
.context("Failed locate the current directory")?;
// Always at CWD.
let out_path = Path::new("flake.nix");
// Fail fast.
ensure!(
self.print || self.force || !out_path.exists(),
"flake.nix already exists. Use `--force` to overwrite or `--print` to print to stdout only",
);
let manifest =
Manifest::from_path(root.join("Cargo.toml")).context("Failed to load Cargo.toml")?;
// Check ancestor manifest files for (maybe) workspace definition.
if manifest.workspace.is_none() && self.root.is_none() {
if let Some(parent_manifest) = root
.ancestors()
.skip(1)
.map(|p| p.join("Cargo.toml"))
.find(|p| p.exists())
{
bail!(
"Are we in a workspace? Found ancestor manifest at {}\n\
Please run `init` in the *workspace root* directory. \n\
If you are sure the current directory is the root, use `--root=.`",
parent_manifest.display(),
);
}
}
let lock_path = root.join("Cargo.lock");
ensure!(
lock_path.exists(),
"Cargo.lock does not exist at {}\n\
We doesn't support lock generation currently. Please run `cargo update` first.
",
lock_path.display(),
);
let lock_version = (|| -> Result<_> {
let content = read_to_string(&lock_path)?;
let lock = toml::from_str::(&content)?;
Ok(lock
.get("version")
.and_then(|v| v.as_integer())
.unwrap_or(2))
})()
.context("Parse Cargo.lock")?;
match lock_version {
// v1 or v2.
2 => {
eprintln!(
"warning: Cargo.lock is generated by cargo < 1.53.0.\n\
The old lock format is supported but encodes git URLs in a different way,\n\
which results in different `gitSrcs` arguments when calling `mkRustPackageOrWorkspace`.\n\
We recommand to regenerate the lock via `cargo update` with cargo >= 1.53.0 and retry.",
)
}
3 => {}
_ => eprintln!("warning: Unsupported version of Cargo.lock, building may fail"),
}
let out = generate_flake(&root, &manifest, lock_version)?;
if self.print {
println!("{}", out);
} else {
(|| {
let mut f = File::options()
.write(true)
.create(true)
.truncate(self.force)
.open(out_path)?;
f.write_all(out.as_bytes())?;
f.flush()
})()
.with_context(|| format!("Failed write to {:?}", out_path))?;
}
Ok(())
}
}
fn generate_flake(root: &Path, manifest: &Manifest, lock_version: i64) -> Result {
ensure!(manifest.patch.is_empty(), "[patch] is not supported yet");
let is_workspace = manifest.workspace.is_some();
let mut templ = FlakeTemplate {
is_workspace,
main_pkg: None,
registries: Default::default(),
git_srcs: Default::default(),
};
if let Some(pkg) = &manifest.package {
templ.main_pkg = Some((
pkg.name.clone(),
Products::from_path_manifest(root, manifest)?,
));
}
match &manifest.workspace {
Some(ws) => {
ensure!(
!ws.members.is_empty(),
"[workspace] without explicit `members` declarations are not supported yet",
);
let member_roots = get_workspace_members(root, &ws.members)?;
let absolute_member_roots = member_roots
.iter()
.map(|p| p.canonicalize())
.collect::, _>>()?;
ensure!(
member_roots.len() == absolute_member_roots.len(),
"Duplicated workspace members"
);
let member_manifests = member_roots
.iter()
.map(|root| {
let manifest_path = root.join("Cargo.toml");
let manifest = Manifest::from_path(&manifest_path).with_context(|| {
format!(
"Failed to load member Cargo.toml at {}",
manifest_path.display()
)
})?;
Ok(manifest)
})
.collect::>>()?;
let root_pkg = manifest
.package
.is_some()
.then(|| (Path::new("."), manifest));
for (member_root, member_manifest) in member_roots
.iter()
.map(|p| &**p)
.zip(&member_manifests)
.chain(root_pkg)
{
for (dep_name, dep) in get_all_dependencies(member_manifest) {
templ
.check_dependency(dep, lock_version, |local_path| {
let local_dep_root = member_root.join(local_path).canonicalize()?;
ensure!(
absolute_member_roots.contains(&local_dep_root),
"Local dependency not in workspace: {}",
local_path.display(),
);
Ok(())
})
.with_context(|| {
format!(
"In dependency {:?} of workspace member {:?}",
dep_name,
member_root.display(),
)
})?;
}
}
}
None => {
for (dep_name, dep) in get_all_dependencies(manifest) {
templ
.check_dependency(dep, lock_version, |local_path| {
bail!(
"Local dependency is not supported for non-workspace: {}",
local_path.display(),
)
})
.with_context(|| format!("In dependency {:?}", dep_name))?;
}
}
}
// The trailing newline is suppressed by default. Add it back.
Ok(templ.render().unwrap() + "\n")
}
#[derive(Template)]
#[template(path = "../templates/init-flake.nix", escape = "none")]
struct FlakeTemplate {
is_workspace: bool,
main_pkg: Option<(String, Products)>,
// source_id -> flake_ref
registries: BTreeMap,
// source_id -> flake_ref
git_srcs: BTreeMap,
}
mod filters {
pub fn nix_escape(s: &str) -> askama::Result {
Ok(s.replace('\\', "\\\\").replace('"', "\\\""))
}
pub fn ident_or_str(s: &str) -> askama::Result {
const KEYWORDS: &[&str] = &[
"if", "then", "else", "assert", "with", "let", "in", "rec", "inherit", "or",
];
let is_ident_start = |c: char| c.is_ascii_alphabetic() || c == '_';
let is_ident_char =
|c: char| c.is_ascii_alphanumeric() || c == '_' || c == '-' || c == '\'';
if s.starts_with(is_ident_start) && s.chars().all(is_ident_char) && !KEYWORDS.contains(&s) {
Ok(s.into())
} else {
Ok(s.replace('\\', "\\\\").replace('"', "\\\""))
}
}
}
impl FlakeTemplate {
fn check_dependency(
&mut self,
dep: &Dependency,
lock_version: i64,
mut on_local_dep: impl FnMut(&Path) -> Result<()>,
) -> Result<()> {
match DepSource::try_from(dep)? {
// Automatically handled by nocargo.
DepSource::CratesIo => {}
DepSource::RegistryName { name } => {
bail!("External registry with name {:?} is not supported", name)
}
DepSource::Path { path } => {
on_local_dep(path)?;
}
DepSource::RegistryUrl { url } => {
let flake_ref = git_url_to_flake_ref(url, None, None)?;
self.registries.insert(url.into(), flake_ref);
}
DepSource::Git { url, ref_ } => {
let source_url = match ref_ {
GitRef::Tag(tag) => format!("{}?tag={}", url, tag),
GitRef::Branch(branch) if lock_version >= 3 => {
format!("{}?branch={}", url, branch)
}
GitRef::Rev(rev) => format!("{}?rev={}", url, rev),
GitRef::NotSpecified | GitRef::Branch(_) => url.to_owned(),
};
let (ref_name, rev) = match ref_ {
GitRef::Tag(ref_name) | GitRef::Branch(ref_name) => (Some(ref_name), None),
GitRef::NotSpecified => (None, None),
GitRef::Rev(rev) => (None, Some(rev)),
};
let flake_ref = git_url_to_flake_ref(url, ref_name, rev)?;
self.git_srcs.insert(source_url, flake_ref);
}
}
Ok(())
}
}
fn get_workspace_members(root: &Path, members: &[impl AsRef]) -> Result> {
let mut ret = Vec::new();
for member in members {
let pat = root.join(member.as_ref());
let pat = pat
.to_str()
.with_context(|| format!("Non UTF-8 path is not supported: {}", pat.display()))?;
for path in glob(pat)? {
ret.push(path?);
}
}
Ok(ret)
}
fn get_all_dependencies(manifest: &Manifest) -> impl Iterator- {
manifest
.dependencies
.iter()
.chain(&manifest.dev_dependencies)
.chain(&manifest.build_dependencies)
.chain(manifest.target.values().flat_map(|tgt| {
tgt.dependencies
.iter()
.chain(&tgt.dev_dependencies)
.chain(&tgt.build_dependencies)
}))
.map(|(name, dep)| (&**name, dep))
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
struct Products {
library: bool,
binary: bool,
bench: bool,
test: bool,
example: bool,
}
impl Products {
// https://github.com/rust-lang/cargo/blob/rust-1.63.0/src/cargo/util/toml/targets.rs#L3-L8
fn from_path_manifest(path: &Path, manifest: &Manifest) -> Result {
let pkg = manifest.package.as_ref().context("Missing [product]")?;
let has_product = |decls: &[Product],
allow_discover: bool,
extra_path: Option<&str>,
convention_dir: &str|
-> Result {
if !decls.is_empty() {
return Ok(true);
}
if allow_discover {
return Ok(false);
}
if matches!(extra_path, Some(p) if Path::new(p).is_file()) {
return Ok(true);
}
for ent in read_dir(path.join(convention_dir))? {
let ent = ent?;
let file_type = ent.file_type()?;
// `/*.rs`
if file_type.is_file()
&& Path::new(&ent.file_name())
.extension()
.map_or(false, |ext| ext == "rs")
{
return Ok(true);
}
// `/*/main.rs`
if file_type.is_dir() && ent.path().join("main.rs").is_file() {
return Ok(true);
}
}
Ok(false)
};
Ok(Self {
library: manifest.lib.is_some() || path.join("src/lib.rs").exists(),
binary: has_product(&manifest.bin, pkg.autobins, Some("src/main.rs"), "src/bin")?,
bench: has_product(&manifest.bin, pkg.autobenches, None, "benches")?,
test: has_product(&manifest.test, pkg.autotests, None, "tests")?,
example: has_product(&manifest.example, pkg.autoexamples, None, "examples")?,
})
}
}
// https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
#[derive(Debug, Clone, Copy)]
enum DepSource<'a> {
CratesIo,
RegistryName { name: &'a str },
RegistryUrl { url: &'a str },
Path { path: &'a Path },
Git { url: &'a str, ref_: GitRef<'a> },
}
#[derive(Debug, Clone, Copy)]
enum GitRef<'a> {
NotSpecified,
Tag(&'a str),
Branch(&'a str),
Rev(&'a str),
}
impl<'a> TryFrom<&'a Dependency> for DepSource<'a> {
type Error = anyhow::Error;
fn try_from(dep: &'a Dependency) -> Result {
match dep {
Dependency::Simple(_) => Ok(Self::CratesIo),
Dependency::Detailed(detail) => {
match (&detail.registry, &detail.registry_index, &detail.path, &detail.git) {
(None, None, None, None) => Ok(Self::CratesIo),
(Some(name), None, None, None) => Ok(Self::RegistryName { name }),
(None, Some(url), None, None) => Ok(Self::RegistryUrl { url }),
(None, None, Some(path), None) => Ok(Self::Path {
path: Path::new(path),
}),
(None, None, None, Some(url)) => {
let ref_ = match (&detail.branch, &detail.tag, &detail.rev) {
(None, None, None) => GitRef::NotSpecified,
(Some(b), None, None) => GitRef::Branch(b),
(None, Some(t), None) => GitRef::Tag(t),
(None, None, Some(r)) => GitRef::Rev(r),
_ => bail!("For git dependency, at most one of `branch`, `rev` and `tag` is allowed"),
};
Ok(Self::Git { url, ref_ })
}
_ => bail!(
"Only one of `registry`, `registry-index`, `path`, `git` can be specified: {:?}",
dep,
),
}
}
}
}
}
// https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-flake.html?#flake-inputs
pub fn git_url_to_flake_ref(
url_orig: &str,
ref_name: Option<&str>,
rev: Option<&str>,
) -> Result {
let url = url_orig.strip_prefix("git+").unwrap_or(url_orig);
ensure!(
url.starts_with("http://")
|| url.starts_with("https://")
|| url.starts_with("ssh://")
|| url.starts_with("git://"),
"Only http/https/ssh/git schemas are supported for git url, got: {}",
url_orig,
);
static RE_GITHUB_URL: Lazy =
Lazy::new(|| Regex::new(r"^https?://github.com/([^/?#]+)/([^/?#]+?)(.git)?/?$").unwrap());
if let Some(cap) = RE_GITHUB_URL.captures(url) {
let owner = cap.get(1).unwrap().as_str();
let repo = cap.get(2).unwrap().as_str();
return Ok(match rev.or(ref_name) {
Some(rev) => format!("github:{}/{}/{}", owner, repo, rev),
None => format!("github:{}/{}", owner, repo),
});
}
ensure!(
!url.contains(|c| c == '?' || c == '#'),
"Url containing `?` or `#` is not supported yet: {}",
url_orig,
);
let prefix = if url.starts_with("git://") {
""
} else {
"git+"
};
let ret = match (ref_name, rev) {
(_, Some(rev)) => format!("{}{}?rev={}", prefix, url, rev),
(Some(ref_name), None) => format!("{}{}?ref={}", prefix, url, ref_name),
(None, None) => format!("{}{}", prefix, url),
};
Ok(ret)
}
#[cfg(test)]
mod tests {
use super::git_url_to_flake_ref as f;
#[test]
fn test_flake_url_schemas() {
assert_eq!(
f("https://example.com", Some("dev"), Some("123")).unwrap(),
"git+https://example.com?rev=123"
);
assert_eq!(
f("https://example.com", None, Some("123")).unwrap(),
"git+https://example.com?rev=123"
);
assert_eq!(
f("https://example.com", Some("dev"), None).unwrap(),
"git+https://example.com?ref=dev"
);
assert_eq!(
f("https://example.com", None, None).unwrap(),
"git+https://example.com"
);
assert_eq!(
f("http://example.com", None, None).unwrap(),
"git+http://example.com"
);
assert_eq!(
f("git+https://example.com", None, None).unwrap(),
"git+https://example.com"
);
assert_eq!(
f("git://example.com", None, None).unwrap(),
"git://example.com"
);
assert_eq!(
f("git+git://example.com", None, None).unwrap(),
"git://example.com"
);
assert_eq!(
f("git+ssh://git@github.com/foo/bar", None, None).unwrap(),
"git+ssh://git@github.com/foo/bar"
);
f("ws://example.com", None, None).unwrap_err();
}
#[test]
fn test_flake_url_github() {
assert_eq!(
f("https://github.com/foo/bar", Some("dev"), Some("123")).unwrap(),
"github:foo/bar/123"
);
assert_eq!(
f("https://github.com/foo/bar", None, Some("123")).unwrap(),
"github:foo/bar/123"
);
assert_eq!(
f("https://github.com/foo/bar", Some("dev"), None).unwrap(),
"github:foo/bar/dev"
);
assert_eq!(
f("https://github.com/foo/bar", None, None).unwrap(),
"github:foo/bar"
);
assert_eq!(
f("https://github.com/foo/bar.git", None, None).unwrap(),
"github:foo/bar"
);
assert_eq!(
f("https://github.com/foo/bar/", None, None).unwrap(),
"github:foo/bar"
);
assert_eq!(
f("http://github.com/foo/bar.git", None, None).unwrap(),
"github:foo/bar"
);
assert_eq!(
f("git+https://github.com/foo/bar.git", None, None).unwrap(),
"github:foo/bar"
);
}
}
================================================
FILE: noc/src/main.rs
================================================
use anyhow::Result;
use clap::Parser;
mod init;
trait App {
fn run(self) -> Result<()>;
}
#[derive(Parser)]
#[clap(version, about, long_about = None)]
enum Args {
Init(init::Args),
}
impl App for Args {
fn run(self) -> Result<()> {
match self {
Self::Init(args) => args.run(),
}
}
}
fn main() -> Result<()> {
Args::from_args().run()
}
================================================
FILE: noc/templates/init-flake.nix
================================================
# See more usages of nocargo at https://github.com/oxalica/nocargo#readme
{
{%- if let Some((pkg_name, _)) = main_pkg %}
description = "Rust package {{ pkg_name|nix_escape }}";
{%- else %}
description = "My Rust packages";
{%- endif %}
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
nocargo = {
url = "github:oxalica/nocargo";
inputs.nixpkgs.follows = "nixpkgs";
# inputs.registry-crates-io.follows = "registry-crates-io";
};
# Optionally, you can override crates.io index to get cutting-edge packages.
# registry-crates-io = { url = "github:rust-lang/crates.io-index"; flake = false; };
{%- for (_, flake_ref) in registries %}
registry-{{ loop.index }} = { url = "{{ flake_ref|nix_escape }}"; flake = false; };
{%- endfor %}
{%- for (_, flake_ref) in git_srcs %}
git-{{ loop.index }} = { url = "{{ flake_ref|nix_escape }}"; flake = false; };
{%- endfor %}
};
outputs = { nixpkgs, flake-utils, nocargo, ... }@inputs:
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
let
ws = nocargo.lib.${system}.mkRustPackageOrWorkspace {
src = ./.;
{%- if !registries.is_empty() %}
# Referenced external registries other than crates.io.
extraRegistries = {
{%- for (source_id, _) in registries %}
"{{ source_id|nix_escape }}" = nocargo.lib.${system}.mkIndex inputs.registry-{{ loop.index }} {};
{%- endfor %}
};
{%- endif %}
{%- if !git_srcs.is_empty() %}
# Referenced external rust packages from git.
gitSrcs = {
{%- for (source_id, _) in git_srcs %}
"{{ source_id|nix_escape }}" = inputs.git-{{ loop.index }};
{%- endfor %}
};
{%- endif %}
};
in rec {
{%- if is_workspace %}
packages = {% if let Some((pkg_name, prod)) = main_pkg %}{
default = packages.{{ pkg_name|ident_or_str }}{% if prod.binary %}.bin{% endif %};
} // {% endif %}ws.release
// nixpkgs.lib.mapAttrs' (name: value: { name = "${name}-dev"; inherit value; }) ws.dev;
{%- else if let Some((pkg_name, prod)) = main_pkg %}
packages = {
default = packages.{{ pkg_name|ident_or_str }};
{{ pkg_name|ident_or_str }} = ws.release.{{ pkg_name|ident_or_str }}{% if prod.binary %}.bin{% endif %};
{{ pkg_name|ident_or_str }}-dev = ws.dev.{{ pkg_name|ident_or_str }}{% if prod.binary %}.bin{% endif %};
};
{%- endif %}
});
}
================================================
FILE: scripts/cratesio-utils.py
================================================
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p cargo "python3.withPackages (ps: with ps; [ aiohttp toml ])"
from io import BytesIO
from pathlib import Path
from typing import Callable, Optional
from typing_extensions import Self
from urllib import request
import aiohttp
import argparse
import asyncio
import csv
import os
import re
import sqlite3
import subprocess
import sys
import tarfile
import toml
# Check dependencies.
subprocess.check_call(['cargo', '--version'], stdout=subprocess.DEVNULL)
# CRATE_TARBALL_URL = 'https://crates.io/api/v1/crates/{name}/{version}/download' # -> 302
CRATE_TARBALL_URL = 'https://static.crates.io/crates/{name}/{name}-{version}.crate' # -> 200 application/gzip
POPULAR_CRATES_MANIFEST_PATH = Path(__file__).parent.parent / 'cache' / 'Cargo.toml'
PROC_MACRO_LIST_PATH = Path(__file__).parent.parent / 'crates-io-override' / 'proc-macro.nix'
CACHE_DIR = Path(os.environ.get('XDG_CACHE_HOME') or (Path.home() / '.cache')) / 'cratesio'
CRATES_TOML_DIR = Path(os.environ.get('CRATES_TOML_DIR') or (CACHE_DIR / 'toml'))
def noisily(*args) -> None:
print(*args, file=sys.stderr)
class CratesioDB(sqlite3.Connection):
DB_URL = 'https://static.crates.io/db-dump.tar.gz'
DB_DIR = CACHE_DIR
DB_PATH = DB_DIR / 'db.sqlite'
MTIME_PATH = DB_DIR / 'mtime.txt'
INIT_SQL = r'''
PRAGMA journal_mode = off;
PRAGMA cache_size = -{cache_kb};
CREATE TABLE IF NOT EXISTS crates (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
downloads INTEGER NOT NULL
) STRICT;
CREATE TABLE IF NOT EXISTS versions (
id INTEGER NOT NULL PRIMARY KEY,
crate_id INTEGER NOT NULL,
num TEXT NOT NULL,
updated_at TEXT NOT NULL,
created_at TEXT NOT NULL,
downloads INTEGER NOT NULL,
features TEXT NOT NULL,
yanked INTEGER NOT NULL,
license TEXT
) STRICT;
CREATE TABLE IF NOT EXISTS version_downloads (
version_id INTEGER NOT NULL,
downloads INTEGER NOT NULL,
date TEXT NOT NULL,
PRIMARY KEY (version_id, date)
) STRICT, WITHOUT ROWID;
'''
INIT_INDEX_SQL = r'''
CREATE INDEX IF NOT EXISTS versions_ix_crate_to_version ON versions
(crate_id, id);
ANALYZE;
'''
INSERTERS: dict[str, tuple[str, Callable[[dict[str, str]], tuple]]] = {
'crates.csv': (
'INSERT INTO crates VALUES (?,?,?,?,?)',
lambda row: (
int(row['id']),
row['name'],
row['created_at'],
row['updated_at'],
int(row['downloads']),
),
),
'versions.csv': (
'INSERT INTO versions VALUES (?,?,?,?,?,?,?,?,?)',
lambda row: (
int(row['id']),
int(row['crate_id']),
row['num'],
row['updated_at'],
row['created_at'],
int(row['downloads']),
row['features'],
row['yanked'] == 't',
row['license'],
),
),
'version_downloads.csv': (
'INSERT INTO version_downloads VALUES (?,?,?)',
lambda row: (
int(row['version_id']),
int(row['downloads']),
row['date'],
)
),
}
def __init__(self, *, check: bool=True, cache_mb: int=1024) -> None:
assert not check or self.MTIME_PATH.exists(), 'Database not initialized, please run `sync` subcommand'
super().__init__(str(self.DB_PATH))
self.executescript(self.INIT_SQL.format(cache_kb=cache_mb * 1024))
@classmethod
def sync(cls, *, cache_mb: int=1024) -> None:
cls.DB_DIR.mkdir(exist_ok=True)
last_mtime = cls.MTIME_PATH.read_text() if cls.MTIME_PATH.exists() else None
noisily('Synchronizing database')
with request.urlopen(cls.DB_URL) as resp:
assert resp.status == 200, f'HTTP failure {resp.status}'
mtime: str = resp.headers['last-modified']
if mtime == last_mtime:
noisily(f'Database is up-to-date at {mtime}')
return
noisily(f'Fetching and importing database dump at {mtime}, previous at {last_mtime}')
cls.DB_PATH.unlink(missing_ok=True)
db = CratesioDB(check=False, cache_mb=cache_mb)
csv.field_size_limit(2 ** 30) # There are large fields.
with tarfile.open(fileobj=resp, mode='r|gz') as tar:
for member in tar:
name = member.path.split('/')[-1]
if name in cls.INSERTERS:
sql, preprocessor = cls.INSERTERS[name]
fileobj = tar.extractfile(member)
assert fileobj is not None
rdr = csv.DictReader(map(bytes.decode, fileobj))
db.executemany(sql, map(preprocessor, rdr))
noisily(f'Creating indices')
db.executescript(cls.INIT_INDEX_SQL)
db.commit()
db.close()
cls.MTIME_PATH.write_text(mtime)
noisily('Database initialized')
def update_popular_crates(db: CratesioDB, *, time: str, limit: int) -> None:
class VersMajor(tuple):
RE_SEMVER = re.compile(r'^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$')
def __new__(cls: type[Self], s: str) -> Self:
m = cls.RE_SEMVER.match(s)
assert m is not None, f'Invalid semver: {s}'
maj, min, pat = map(int, (m[1], m[2], m[3]))
vers = (maj,) if maj else (maj, min) if min else (maj, min, pat)
return super().__new__(cls, vers)
def __str__(self) -> str:
return '.'.join(map(str, self))
# Reversed.
def __lt__(self, rhs: Self) -> bool:
return super().__gt__(rhs)
noisily('Querying database')
cursor = db.cursor()
cursor.execute('''
SELECT crates.name, versions.num
FROM version_downloads
JOIN versions ON versions.id == version_id
JOIN crates ON crates.id == versions.crate_id
WHERE version_downloads.date > DATE('now', ?)
GROUP BY version_id
ORDER BY SUM(version_downloads.downloads) DESC
''', (time,))
crates_set: set[tuple[str, VersMajor]] = set()
for row in cursor:
crates_set.add((str(row[0]), VersMajor(row[1])))
if len(crates_set) == limit:
break
crates = sorted(crates_set)
noisily('======== Start of top crates')
for name, vers in crates:
noisily(name, vers)
noisily('======== End of top crates')
out_path = POPULAR_CRATES_MANIFEST_PATH
tmp_path = out_path.with_suffix('.tmp')
with out_path.open('r') as fin, tmp_path.open('w') as fout:
for line in fin:
fout.write(line)
if line.startswith('[dependencies]'):
break
last_name: Optional[str] = None
crate_idx = 1
for name, vers in crates:
if last_name != name:
crate_idx = 1
fout.write(f'{name} = "{vers}"\n')
else:
crate_idx += 1
fout.write(f'{name}-{crate_idx} = {{ package = "{name}", version = "{vers}" }}\n')
last_name = name
tmp_path.replace(out_path)
noisily('Updating lock file')
subprocess.check_call(['cargo', 'update', f'--manifest-path={out_path}'])
noisily('Verifying crates metadata')
subprocess.check_call(
['cargo', 'metadata', f'--manifest-path={out_path}', '--format-version=1'],
stdout=subprocess.DEVNULL,
)
def list_popular_crates(db: CratesioDB, *, time: str, pat: Optional[str]) -> None:
noisily('Querying database')
cursor = db.cursor()
cursor.execute('''
SELECT crates.name, SUM(version_downloads.downloads) AS crate_downloads
FROM crates
JOIN versions ON versions.crate_id == crates.id
JOIN version_downloads ON version_downloads.version_id == versions.id
WHERE crates.name LIKE ? AND version_downloads.date > DATE('now', ?)
GROUP BY versions.crate_id
ORDER BY crate_downloads DESC
''', (pat if pat is not None else '%', time))
try:
for row in cursor:
print(row[0], row[1])
except BrokenPipeError as _:
# Suppress backtrace.
exit(1)
def update_proc_macro_crates(db: CratesioDB, *, concurrency: int) -> None:
CRATES_TOML_DIR.mkdir(exist_ok=True)
noisily('Querying database')
cursor = db.cursor()
cursor.execute('''
SELECT crates.name, versions.num AS max_vers, MAX(versions.created_at)
FROM versions
JOIN crates ON crates.id == crate_id
WHERE NOT yanked
GROUP BY crate_id
ORDER BY crates.name ASC
''')
RE_ITEMS = re.compile(r'"([^"]*)"', re.S)
proc_macro_crates: set[str] = set(m[1] for m in RE_ITEMS.finditer(PROC_MACRO_LIST_PATH.read_text()))
async def load_or_fetch(sema: asyncio.Semaphore, name: str, version: str) -> None:
try:
out_path = CRATES_TOML_DIR / f'{name}.toml'
if not out_path.exists():
noisily(f'GET {name} {version}')
url = CRATE_TARBALL_URL.format(name=name, version=version)
async with aiohttp.request(method='GET', url=url) as resp:
resp.raise_for_status()
data = await resp.read()
with tarfile.open(mode='r|gz', fileobj=BytesIO(data)) as tar:
for member in tar:
segments = member.path.split('/')
if len(segments) == 2 and segments[-1] == 'Cargo.toml':
f = tar.extractfile(member)
assert f is not None
tmp_path = out_path.with_suffix('.tmp')
tmp_path.write_bytes(f.read())
tmp_path.replace(out_path)
break
else:
assert False, 'No Cargo.toml found'
except (aiohttp.ClientError, tarfile.TarError, UnicodeDecodeError, AssertionError) as exc:
print(f'For {name} {version}: {exc}', file=sys.stderr)
return
finally:
sema.release()
try:
# Must exist if we are here.
with open(out_path, 'r') as fin:
manifest = toml.load(fin)
lib = manifest.get('lib', {})
if isinstance(lib, dict) and lib.get('proc-macro', False) is True:
proc_macro_crates.add(name)
except (UnicodeDecodeError, toml.TomlDecodeError) as exc:
print(f'For cached {name}: {exc}', file=sys.stderr)
return
async def proc() -> None:
sema = asyncio.Semaphore(concurrency)
for row in cursor:
name: str = row[0]
vers: str = row[1]
await sema.acquire()
asyncio.create_task(load_or_fetch(sema, name, vers))
# Wait until all done.
for _ in range(concurrency):
await sema.acquire()
noisily('Retrieving metadata')
asyncio.run(proc())
noisily(f'Writing to {PROC_MACRO_LIST_PATH}')
with PROC_MACRO_LIST_PATH.open('w') as fout:
fout.write('[\n')
for name in sorted(proc_macro_crates):
assert '"' not in name
fout.write(f'"{name}"\n')
fout.write(']\n')
def main() -> None:
parser = argparse.ArgumentParser(description='Metadata updater and utilities using crates.io database dump')
parser.add_argument('--cache-mb', type=int, required=False, default=1024, help='Sqlite cache size in MiB')
subparser = parser.add_subparsers(required=True)
p = subparser.add_parser('sync', help='Synchronize or initialize the database')
p.set_defaults(sync=True)
p = subparser.add_parser('update-popular-crates', help='Update popular crates cache')
p.add_argument('--limit', type=int, required=False, default=256, help='Number of top crates to cache')
p.add_argument('--time', type=str, default='-90 days', help='Time period to count recent downloads')
p.set_defaults(fn=update_popular_crates)
p = subparser.add_parser('list-popular-crates', help='Print popular crates with download counts in a given period')
p.add_argument('--time', type=str, default='-90 days', help='Time period to count recent downloads')
p.add_argument('--pat', type=str, default=None, help='Crate name pattern to filter for SQL "LIKE"')
p.set_defaults(fn=list_popular_crates)
p = subparser.add_parser('update-proc-macro-crates', help='Update the list of proc-macro crates')
p.add_argument('--concurrency', type=int, default=16, help='Connection concurrency')
p.set_defaults(fn=update_proc_macro_crates)
args = parser.parse_args()
if 'sync' in args:
CratesioDB.sync(cache_mb=args.cache_mb)
else:
subargs = vars(args)
with CratesioDB(cache_mb=subargs.pop('cache_mb')) as db:
subargs.pop('fn')(db, **subargs)
main()
================================================
FILE: tests/build-deps/Cargo.toml
================================================
[package]
name = "build-deps"
version = "0.0.0"
edition = "2015"
[build-dependencies]
semver = "1"
================================================
FILE: tests/build-deps/build.rs
================================================
fn main() {
let s = semver::Version::new(1, 2, 3).to_string();
println!("cargo:rustc-cfg=result={:?}", s);
}
================================================
FILE: tests/build-deps/src/main.rs
================================================
#[cfg(result = "1.2.3")]
fn main() {
println!("Hello, world!");
}
================================================
FILE: tests/build-feature-env-vars/Cargo.toml
================================================
[package]
name = "build-feature-env-vars"
version = "0.0.0"
edition = "2015"
[features]
default = ["foo-bar"]
foo-bar = []
quux = []
================================================
FILE: tests/build-feature-env-vars/build.rs
================================================
use std::env::var;
fn main() {
if var("CARGO_FEATURE_QUUX").is_err() {
if let Ok(s) = var("CARGO_FEATURE_FOO_BAR") {
println!("cargo:rustc-cfg=result={:?}", s);
}
}
}
================================================
FILE: tests/build-feature-env-vars/src/main.rs
================================================
#[cfg(result = "1")]
fn main() {
println!("Hello, world!");
}
================================================
FILE: tests/cap-lints/Cargo.toml
================================================
[package]
name = "cap-lints"
version = "0.0.0"
edition = "2021"
[dependencies]
# error: use of deprecated associated function `try_lock::TryLock::::try_lock_order`: This method is actually unsafe because it unsafely allows the use of weaker memory ordering. Please use try_lock_explicit instead
# --> src/lib.rs:209:63
# |
# 209 | if let Some(mut locked) = self.inner.task.try_lock_order(SeqCst, SeqCst) {
# | ^^^^^^^^^^^^^^
# |
# note: the lint level is defined here
# --> src/lib.rs:2:9
# |
# 2 | #![deny(warnings)]
# | ^^^^^^^^
# = note: `#[deny(deprecated)]` implied by `#[deny(warnings)]`
#
# https://github.com/seanmonstar/want/blob/v0.3.0/src/lib.rs#L352
want = "=0.3.0"
================================================
FILE: tests/cap-lints/src/main.rs
================================================
fn main() {
let _ = want::new();
println!("Hello, world!");
}
================================================
FILE: tests/crate-names/Cargo.toml
================================================
[package]
name = "crate-names"
version = "0.0.0"
edition = "2018"
[dependencies]
b = "=0.2.0"
cc = "=1.0.73"
fnv = "=1.0.7"
RustyXML = "=0.3.0" # Should be lowered.
================================================
FILE: tests/crate-names/src/main.rs
================================================
use std::hash::Hasher;
fn main() {
assert_eq!(b::B, "🅱️");
let _ = cc::Build::new();
assert_eq!(fnv::FnvHasher::with_key(42).finish(), 42);
assert_eq!(xml::escape("<"), "<");
println!("Hello, world!");
}
================================================
FILE: tests/custom-lib-name/Cargo.toml
================================================
[package]
name = "custom-lib-name"
version = "0.0.0"
edition = "2018"
[lib]
name = "custom"
[dependencies]
color-rs = "=0.6.1"
renamed = { package = "color-rs", version = "=0.5.0" }
================================================
FILE: tests/custom-lib-name/src/lib.rs
================================================
pub fn custom() -> i32 {
42
}
================================================
FILE: tests/custom-lib-name/src/main.rs
================================================
fn main() {
assert_eq!(color::consts::PURPLE, color::Rgb::new(0x80, 0x00, 0x80));
assert_eq!(renamed::consts::PURPLE, renamed::Rgb::new(0x80, 0x00, 0x80));
assert_eq!(custom::custom(), 42);
println!("Hello, world!");
}
================================================
FILE: tests/default.nix
================================================
{ pkgs, self, inputs, defaultRegistries }:
let
inherit (pkgs.lib) mapAttrs attrNames attrValues assertMsg head mapAttrsToList;
inherit (self.lib.${pkgs.system}) mkRustPackageOrWorkspace;
inherit (self.packages.${pkgs.system}) noc;
git-semver-1-0-0 = builtins.fetchTarball {
url = "https://github.com/dtolnay/semver/archive/1.0.0/master.tar.gz";
sha256 = "0s7gwj5l0h98spgm7vyxak9z3hgrachwxbnf1fpry5diz939x8n4";
};
git-semver-1-0-12 = builtins.fetchTarball {
url = "https://github.com/dtolnay/semver/archive/1.0.4/master.tar.gz";
sha256 = "1l2nkfmjgz2zkqw03hmy66q0v1rxvs7fc4kh63ph4lf1924wrmix";
};
gitSrcs = {
"https://github.com/dtolnay/semver?tag=1.0.0" = git-semver-1-0-0;
"http://github.com/dtolnay/semver" = git-semver-1-0-12; # v1, v2
"http://github.com/dtolnay/semver?branch=master" = git-semver-1-0-12; # v3
"ssh://git@github.com/dtolnay/semver?rev=a2ce5777dcd455246e4650e36dde8e2e96fcb3fd" = git-semver-1-0-0;
"ssh://git@github.com/dtolnay/semver" = git-semver-1-0-12;
};
extraRegistries = {
"https://www.github.com/rust-lang/crates.io-index" =
head (attrValues defaultRegistries);
};
shouldBeHelloWorld = drv: pkgs.runCommand "${drv.name}" {} ''
binaries=(${drv.bin}/bin/*)
[[ ''${#binaries[@]} == 1 ]]
got="$(''${binaries[0]})"
expect="Hello, world!"
echo "Got : $got"
echo "Expect: $expect"
[[ "$got" == "$expect" ]]
touch $out
'';
mkHelloWorldTest = src:
let
ws = mkRustPackageOrWorkspace {
inherit src gitSrcs extraRegistries;
};
profiles = mapAttrs (_: pkgs: shouldBeHelloWorld (head (attrValues pkgs))) ws;
in {
inherit (profiles) dev release;
};
mkWorkspaceTest = src: expectMembers: let
ws = mkRustPackageOrWorkspace { inherit src; };
gotMembers = attrNames ws.dev;
in
assert assertMsg (gotMembers == expectMembers) ''
Member assertion failed.
expect: ${toString expectMembers}
got: ${toString gotMembers}
'';
ws;
# Recursive Nix setup.
# https://github.com/NixOS/nixpkgs/blob/e966ab3965a656efdd40b6ae0d8cec6183972edc/pkgs/top-level/make-tarball.nix#L45-L48
mkGenInit = name: path:
pkgs.runCommand "gen-${name}" {
nativeBuildInputs = [ noc pkgs.nix ];
checkFlags =
mapAttrsToList (from: to: "--override-input ${from} ${to}") {
inherit (inputs) nixpkgs flake-utils;
nocargo = self;
"nocargo/registry-crates-io" = inputs.registry-crates-io;
registry-1 = inputs.registry-crates-io;
git-1 = git-semver-1-0-0;
git-2 = git-semver-1-0-0;
git-3 = git-semver-1-0-0;
git-4 = git-semver-1-0-0;
};
} ''
cp -r ${path} src
chmod -R u+w src
cd src
echo "generating flake.nix"
noc init
cat flake.nix
install -D flake.nix $out/flake.nix
echo "checking with 'nix flake check'"
export NIX_STATE_DIR=$TMPDIR/nix/var
export NIX_PATH=
export HOME=$TMPDIR
nix-store --init
nixFlags=(
--offline
--option build-users-group ""
--option experimental-features "ca-derivations nix-command flakes"
--store $TMPDIR/nix/store
)
nix flake check \
--no-build \
--show-trace \
$checkFlags \
"''${nixFlags[@]}"
'';
in
{
_1000-hello-worlds = mapAttrs (name: path: mkHelloWorldTest path) {
build-deps = ./build-deps;
build-feature-env-vars = ./build-feature-env-vars;
cap-lints = ./cap-lints;
crate-names = ./crate-names;
custom-lib-name = ./custom-lib-name;
dependency-v1 = ./dependency-v1;
dependency-v2 = ./dependency-v2;
dependency-v3 = ./dependency-v3;
features = ./features;
libz-dynamic = ./libz-dynamic;
libz-static = ./libz-static;
lto-fat = ./lto-fat;
lto-proc-macro = ./lto-proc-macro;
lto-thin = ./lto-thin;
tokio-app = ./tokio-app;
} // {
workspace-inline = mkWorkspaceTest ./workspace-inline [ "bar" "baz" "foo" ];
workspace-proc-macro-lto = mkWorkspaceTest ./workspace-proc-macro-lto [ "acro" "procm" ];
workspace-virtual = mkWorkspaceTest ./workspace-virtual [ "bar" "foo" ];
};
_1100-gen-init = mapAttrs mkGenInit {
dependency-v1 = ./dependency-v1;
dependency-v2 = ./dependency-v2;
dependency-v3 = ./dependency-v3;
features = ./features;
workspace-virtual = ./workspace-virtual;
workspace-inline = ./workspace-inline;
};
}
================================================
FILE: tests/dependency-v1/Cargo.toml
================================================
[package]
name = "dependencies"
version = "0.0.0"
edition = "2018"
[dependencies]
cratesio = { package = "semver", version = "1" }
registry-index = { package = "semver", version = "1", registry-index = "https://www.github.com/rust-lang/crates.io-index" }
git-tag = { package = "semver", git = "https://github.com/dtolnay/semver", tag = "1.0.0" }
git-branch = { package = "semver", git = "http://github.com/dtolnay/semver", branch = "master" }
git-rev = { package = "semver", git = "ssh://git@github.com/dtolnay/semver", rev = "a2ce5777dcd455246e4650e36dde8e2e96fcb3fd" }
git-head = { package = "semver", git = "ssh://git@github.com/dtolnay/semver" }
================================================
FILE: tests/dependency-v1/README.md
================================================
This `Cargo.lock` is generated by rust 1.37.0.
================================================
FILE: tests/dependency-v1/src/main.rs
================================================
fn main() {
cratesio::Version::parse("1.2.3").unwrap();
registry_index::Version::parse("1.2.3").unwrap();
git_tag::Version::parse("1.2.3").unwrap();
git_branch::Version::parse("1.2.3").unwrap();
git_rev::Version::parse("1.2.3").unwrap();
git_head::Version::parse("1.2.3").unwrap();
println!("Hello, world!");
}
================================================
FILE: tests/dependency-v2/Cargo.toml
================================================
[package]
name = "dependencies"
version = "0.0.0"
edition = "2018"
[dependencies]
cratesio = { package = "semver", version = "1" }
registry-index = { package = "semver", version = "1", registry-index = "https://www.github.com/rust-lang/crates.io-index" }
git-tag = { package = "semver", git = "https://github.com/dtolnay/semver", tag = "1.0.0" }
git-branch = { package = "semver", git = "http://github.com/dtolnay/semver", branch = "master" }
git-rev = { package = "semver", git = "ssh://git@github.com/dtolnay/semver", rev = "a2ce5777dcd455246e4650e36dde8e2e96fcb3fd" }
git-head = { package = "semver", git = "ssh://git@github.com/dtolnay/semver" }
================================================
FILE: tests/dependency-v2/README.md
================================================
This `Cargo.lock` is generated by rust 1.41.0.
================================================
FILE: tests/dependency-v2/src/main.rs
================================================
fn main() {
cratesio::Version::parse("1.2.3").unwrap();
registry_index::Version::parse("1.2.3").unwrap();
git_tag::Version::parse("1.2.3").unwrap();
git_branch::Version::parse("1.2.3").unwrap();
git_rev::Version::parse("1.2.3").unwrap();
git_head::Version::parse("1.2.3").unwrap();
println!("Hello, world!");
}
================================================
FILE: tests/dependency-v3/Cargo.toml
================================================
[package]
name = "dependencies"
version = "0.0.0"
edition = "2018"
[dependencies]
cratesio = { package = "semver", version = "1" }
registry-index = { package = "semver", version = "1", registry-index = "https://www.github.com/rust-lang/crates.io-index" }
git-tag = { package = "semver", git = "https://github.com/dtolnay/semver", tag = "1.0.0" }
git-branch = { package = "semver", git = "http://github.com/dtolnay/semver", branch = "master" }
git-rev = { package = "semver", git = "ssh://git@github.com/dtolnay/semver", rev = "a2ce5777dcd455246e4650e36dde8e2e96fcb3fd" }
git-head = { package = "semver", git = "ssh://git@github.com/dtolnay/semver" }
================================================
FILE: tests/dependency-v3/src/main.rs
================================================
fn main() {
cratesio::Version::parse("1.2.3").unwrap();
registry_index::Version::parse("1.2.3").unwrap();
git_tag::Version::parse("1.2.3").unwrap();
git_branch::Version::parse("1.2.3").unwrap();
git_rev::Version::parse("1.2.3").unwrap();
git_head::Version::parse("1.2.3").unwrap();
println!("Hello, world!");
}
================================================
FILE: tests/fake-semver/Cargo.toml
================================================
# This crate is for tests in `support.nix` and will not be really built.
[package]
name = "semver"
version = "1.0.0"
edition = "2018"
[dependencies]
================================================
FILE: tests/fake-semver/src/lib.rs
================================================
================================================
FILE: tests/features/Cargo.toml
================================================
[package]
name = "simple-features"
version = "0.0.0"
edition = "2018"
[dependencies]
semver = { version = "1.0.12", optional = true }
[features]
default = [ "a" ]
a = ["default", "semver/serde"]
b = []
================================================
FILE: tests/features/src/main.rs
================================================
#[cfg(all(feature = "a", not(feature = "b")))]
fn main() {
println!("Hello, world!");
}
================================================
FILE: tests/libz-dynamic/Cargo.toml
================================================
[package]
name = "libz-dynamic"
version = "0.0.0"
edition = "2018"
[dependencies]
libz-sys = { version = "=1.1.6", default-features = false }
================================================
FILE: tests/libz-dynamic/build.rs
================================================
fn main() {
std::env::var("DEP_Z_INCLUDE").expect_err("Dynamic linking should not set DEP_Z_INCLUDE");
println!("cargo:rustc-env=OKAY=");
}
================================================
FILE: tests/libz-dynamic/src/main.rs
================================================
fn main() {
let crc_init = unsafe { libz_sys::crc32(0, "foo".as_ptr() as _, 3) };
assert_eq!(crc_init, 2356372769);
assert_eq!(env!("OKAY"), "");
println!("Hello, world!");
}
================================================
FILE: tests/libz-static/Cargo.toml
================================================
[package]
name = "libz-static"
version = "0.0.0"
edition = "2018"
[dependencies]
libz-sys = { version = "=1.1.3", default-features = false, features = ["static"] }
================================================
FILE: tests/libz-static/build.rs
================================================
fn main() {
let z_include = std::env::var("DEP_Z_INCLUDE").unwrap();
let header = std::fs::read_to_string(z_include + "/zlib.h").unwrap();
let mut lines = header.lines();
assert_eq!(
lines.next().unwrap(),
"/* zlib.h -- interface of the 'zlib' general purpose compression library"
);
assert_eq!(
lines.next().unwrap(),
" version 1.2.11, January 15th, 2017",
"bundled libz MUST be 1.2.11",
);
println!("cargo:rustc-env=OKAY=");
}
================================================
FILE: tests/libz-static/src/lib.rs
================================================
// Only available in the build script.
const _: [(); 1] = [(); option_env!("DEP_Z_INCLUDE").is_none() as usize];
================================================
FILE: tests/libz-static/src/main.rs
================================================
fn main() {
// Only available in the build script.
assert!(option_env!("DEP_Z_INCLUDE").is_none());
let crc_init = unsafe { libz_sys::crc32(0, "foo".as_ptr() as _, 3) };
assert_eq!(crc_init, 2356372769);
assert_eq!(env!("OKAY"), "");
println!("Hello, world!");
}
================================================
FILE: tests/lto-fat/Cargo.toml
================================================
[package]
name = "lto-fat"
version = "0.0.0"
edition = "2021"
[dependencies]
semver = "1"
[profile.release]
lto = "fat"
================================================
FILE: tests/lto-fat/src/main.rs
================================================
fn main() {
assert_eq!(
semver::Version::parse("1.2.3").unwrap().to_string(),
"1.2.3"
);
println!("Hello, world!");
}
================================================
FILE: tests/lto-proc-macro/Cargo.toml
================================================
[package]
name = "lto-proc-macro"
version = "0.0.0"
edition = "2021"
[dependencies]
thiserror = "1"
[profile.release]
lto = "thin"
================================================
FILE: tests/lto-proc-macro/src/main.rs
================================================
#[derive(Debug, thiserror::Error)]
enum Error {
#[error("Hello, {0}!")]
Hello(&'static str),
}
fn main() {
println!("{}", Error::Hello("world"));
}
================================================
FILE: tests/lto-thin/Cargo.toml
================================================
[package]
name = "lto-thin"
version = "0.0.0"
edition = "2021"
[dependencies]
semver = "1"
[profile.release]
lto = "thin"
================================================
FILE: tests/lto-thin/src/main.rs
================================================
fn main() {
assert_eq!(
semver::Version::parse("1.2.3").unwrap().to_string(),
"1.2.3"
);
println!("Hello, world!");
}
================================================
FILE: tests/tokio-app/Cargo.toml
================================================
[package]
name = "tokio-app"
version = "0.0.0"
edition = "2018"
[dependencies]
tokio = { version = "1", features = [ "rt-multi-thread", "macros", "time" ], default-features = false }
================================================
FILE: tests/tokio-app/src/main.rs
================================================
#[tokio::main]
async fn main() {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
println!("Hello, world!");
}
================================================
FILE: tests/workspace-inline/Cargo.toml
================================================
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = { path = "bar" }
[workspace]
members = [".", "b*"]
================================================
FILE: tests/workspace-inline/bar/Cargo.toml
================================================
[package]
name = "bar"
version = "0.1.0"
edition = "2018"
[dependencies]
================================================
FILE: tests/workspace-inline/bar/src/lib.rs
================================================
pub fn hello() -> &'static str {
"Hello"
}
================================================
FILE: tests/workspace-inline/baz/Cargo.toml
================================================
[package]
name = "baz"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = { path = "../bar" }
================================================
FILE: tests/workspace-inline/baz/src/lib.rs
================================================
pub fn show(s: String) {
assert!(s.starts_with(bar::hello()));
println!("{}", s);
}
================================================
FILE: tests/workspace-inline/src/main.rs
================================================
fn main() {
println!("{}, world!", bar::hello());
}
================================================
FILE: tests/workspace-proc-macro-lto/Cargo.toml
================================================
[package]
name = "acro"
version = "0.1.0"
edition = "2018"
[dependencies]
procm = { path = "./procm" }
[workspace]
# FIXME: "." is required.
members = ["procm", "."]
[profile.release]
lto = "thin"
================================================
FILE: tests/workspace-proc-macro-lto/procm/Cargo.toml
================================================
[package]
name = "procm"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
================================================
FILE: tests/workspace-proc-macro-lto/procm/src/lib.rs
================================================
use proc_macro::TokenStream;
#[proc_macro]
pub fn acro(input: TokenStream) -> TokenStream {
format!(r#"fn main() {{ println!({}) }}"#, input).parse().unwrap()
}
================================================
FILE: tests/workspace-proc-macro-lto/src/lib.rs
================================================
procm::acro!("Hello, world!");
================================================
FILE: tests/workspace-virtual/Cargo.toml
================================================
[workspace]
members = [ "./crates/*" ]
exclude = [ "./crates/./exc" ]
================================================
FILE: tests/workspace-virtual/crates/bar/Cargo.toml
================================================
[package]
name = "bar"
version = "0.1.0"
edition = "2018"
[dependencies]
================================================
FILE: tests/workspace-virtual/crates/bar/src/lib.rs
================================================
pub fn world() -> &'static str {
"world"
}
================================================
FILE: tests/workspace-virtual/crates/exc/Cargo.toml
================================================
[package]
name = "exc"
version = "0.1.0"
edition = "2018"
[dependencies]
================================================
FILE: tests/workspace-virtual/crates/exc/src/main.rs
================================================
fn main() {
println!("Hello, world!");
}
================================================
FILE: tests/workspace-virtual/crates/foo/Cargo.toml
================================================
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[dependencies]
bar = { path = "../bar" }
================================================
FILE: tests/workspace-virtual/crates/foo/src/main.rs
================================================
fn main() {
println!("Hello, {}!", bar::world());
}
================================================
FILE: toml2json/Cargo.toml
================================================
[package]
name = "toml2json"
version = "1.0.0"
rust-version = "1.36"
[dependencies]
serde_json = "1.0.0"
toml = "0.5"
================================================
FILE: toml2json/README.md
================================================
## toml2json: minimal impl for toml -> json
This utility program is a dependency of every rust crate derivation.
Thus it's is designed to be simple and have minimal dependencies, instead of using `remarshal` which
pulls in tons of python packages.
================================================
FILE: toml2json/default.nix
================================================
{ stdenv, fetchurl, rustc }:
let
fetch = name: version: sha256:
fetchurl {
name = "crate-${name}-${version}.tar.gz";
url = "https://crates.io/api/v1/crates/${name}/${version}/download";
inherit sha256;
};
manifest = builtins.fromTOML (builtins.readFile ./Cargo.toml);
lock = builtins.fromTOML (builtins.readFile ./Cargo.lock);
in stdenv.mkDerivation {
pname = manifest.package.name;
version = manifest.package.version;
srcs = map ({ name, version, checksum ? null, ... }: if checksum != null then fetch name version checksum else null) lock.package;
sourceRoot = ".";
nativeBuildInputs = [ rustc ];
buildPhase = ''
buildFlagsArray+=(
--color=always
--out-dir .
-L .
-C codegen-units=1
-C opt-level=3
--cap-lints allow
)
run() {
echo "rustc $* ''${buildFlagsArray[*]}"
rustc "$@" "''${buildFlagsArray[@]}"
}
run itoa-*/src/lib.rs --crate-name itoa --crate-type lib \
--cfg 'feature="default"' --cfg 'feature="std"'
run ryu-*/src/lib.rs --crate-name ryu --crate-type lib
run serde-*/src/lib.rs --crate-name serde --crate-type lib \
--cfg 'feature="default"' --cfg 'feature="std"'
run serde_json-*/src/lib.rs --crate-name serde_json --crate-type lib \
--edition=2018 \
--cfg 'feature="default"' --cfg 'feature="std"' \
--extern itoa=libitoa.rlib \
--extern ryu=libryu.rlib \
--extern serde=libserde.rlib
run toml-*/src/lib.rs --crate-name toml --crate-type lib \
--edition=2018 \
--extern serde=libserde.rlib
run ${./src/main.rs} --crate-name toml2json --crate-type bin \
--extern serde_json=./libserde_json.rlib \
--extern toml=libtoml.rlib
'';
testToml = ''
[hello]
world = "good"
[target."cfg(target = \"good\")"]
foo = "bar"
'';
testJson = ''{"hello":{"world":"good"},"target":{"cfg(target = \"good\")":{"foo":"bar"}}}'';
doCheck = true;
checkPhase = ''
./toml2json <<<"$testToml" >out.json
echo "Got : $(cat out.json)"
echo "Expect: $testJson"
[[ "$(cat out.json)" == "$testJson" ]]
'';
installPhase = ''
mkdir -p $out/bin
cp -t $out/bin ./toml2json
'';
}
================================================
FILE: toml2json/src/main.rs
================================================
use std::io::{stdin, stdout, Read, Write};
fn main() -> Result<(), Box> {
let mut input = Vec::new();
stdin().lock().read_to_end(&mut input)?;
let data: serde_json::Value = toml::from_slice(&input)?;
let mut output = serde_json::to_vec(&data)?;
output.push(b'\n');
stdout().lock().write_all(&output)?;
Ok(())
}