-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcargo-index.nix
115 lines (106 loc) · 3.79 KB
/
cargo-index.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
{ sources ? import ./nix/sources.nix
, nixpkgs ? sources.nixpkgs
, pkgs ? import nixpkgs { config = {}; }
, lib ? pkgs.lib
, cratesIoIndex ? sources."crates.io-index"
, semver ? pkgs.callPackage ./semver.nix {}
, lines ? pkgs.callPackage ./lines.nix {}
}:
rec {
/* Returns all uploaded crateConfigs for the crate with the given name
from the given checked out index.
*/
crateConfigs = { name, index ? cratesIoIndex, ... }@args:
let
lines = crateConfigLines args;
configs = builtins.map builtins.fromJSON lines;
in builtins.sort (a: b: lib.versionOlder b.vers a.vers) configs;
/* Returns a config that matches the given `versionReq` or `null`.
Otherwise similar to `crateConfigs`.
*/
crateConfigForVersion = { name, versionReq ? "*", index ? cratesIoIndex, filterYanked ? true, ... }@args:
let
configs = crateConfigs args;
versionMatcher = semver.versionMatcher versionReq;
matchPackage = pkg:
versionMatcher pkg.vers
&& (filterYanked -> !(pkg.yanked or (builtins.trace "no yanked in ${builtins.toJSON pkg}" false)));
matchingPackages = builtins.filter matchPackage configs;
firstMatch = builtins.head matchingPackages;
in
if matchingPackages != []
then firstMatch
else null;
/* Highly experimental - mostly to test code right now. */
transitiveCrateConfigs =
{ name
, versionReq ? "*"
, index ? cratesIoIndex
, filterYanked ? true
, visited ? {}
}@args:
let
config = crateConfigForVersion args;
myKey = "${config.name}/${config.vers}";
visitedWithMe = visited // { "${myKey}" = config; };
resolveDep = visited: { name, req, kind, ... }@dep:
let
depName = dep.package or name;
in
# builtins.trace
# "visited ${builtins.toJSON (builtins.attrNames visited)}"
# builtins.trace
# "resolving ${depName} ${req} ${kind} (dep of ${config.name} ${config.vers})"
transitiveCrateConfigs {
inherit index filterYanked visited;
name = depName;
versionReq = req;
};
blacklist = [ "core" "std" ];
depFilter =
{ name, kind, ... }@dep:
kind == "normal"
&& ((dep ? target && dep.target != null) -> dep.target == pkgs.targetPlatform.config)
&& !(builtins.elem (dep.package or name) blacklist);
deps = config.deps or [];
filteredDeps = builtins.filter depFilter deps;
in
if visited ? "${myKey}"
then visited
else lib.foldl resolveDep visitedWithMe filteredDeps;
/* Returns the index sub path for the given crate name
The corresponding cargo code looks like this:
```rust
// See module comment in `registry/mod.rs` for why this is structured
// the way it is.
let fs_name = name
.chars()
.flat_map(|c| c.to_lowercase())
.collect::<String>();
let raw_path = match fs_name.len() {
1 => format!("1/{}", fs_name),
2 => format!("2/{}", fs_name),
3 => format!("3/{}/{}", &fs_name[..1], fs_name),
_ => format!("{}/{}/{}", &fs_name[0..2], &fs_name[2..4], fs_name),
};
```
*/
cratePath = name:
let
lower = lib.toLower name;
len = builtins.stringLength lower;
in
assert len > 0;
if len == 1
then "1/${lower}"
else if len == 2
then "2/${lower}"
else if len == 3
then "3/${builtins.substring 0 1 lower}/${lower}"
else "${builtins.substring 0 2 lower}/${builtins.substring 2 2 lower}/${lower}";
crateConfigLines = { name, index ? cratesIoIndex, ... }:
let
config = builtins.readFile "${index}/${cratePath name}";
in lines.lines config;
inherit lib cratesIoIndex semver lines;
}