Skip to content

Commit 9fed926

Browse files
committed
Adding support for private registries
Private registries were currently handled by generating code that was referencing the cache in ~/.cargo. This commit adds support to generate correct code for them.
1 parent 236f6ad commit 9fed926

File tree

9 files changed

+277
-8
lines changed

9 files changed

+277
-8
lines changed

crate2nix/default.nix

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
, defaultCrateOverrides ? pkgs.defaultCrateOverrides
1414
, nix ? pkgs.nix
1515
, cargo ? pkgs.cargo
16+
, libsecret ? pkgs.libsecret
1617
, callPackage ? pkgs.callPackage
1718
, nix-prefetch-git ? pkgs.nix-prefetch-git
1819
# Seperate arguements that are NOT filled by callPackage.
@@ -26,7 +27,7 @@ let
2627
baseName = builtins.baseNameOf (builtins.toString name);
2728
in
2829
!(baseName == "templates" && type == "directory");
29-
crate2nix = cargoNix.rootCrate.build.override {
30+
crate2nix = (cargoNix.rootCrate.build.override {
3031
testCrateFlags = [
3132
"--skip nix_integration_tests"
3233
];
@@ -46,7 +47,11 @@ let
4647
buildInputs = lib.optionals stdenv.isDarwin [ darwin.apple_sdk.frameworks.Security ];
4748
};
4849
};
49-
};
50+
}).overrideAttrs (attrs: {
51+
postInstall = lib.optionalString stdenv.isLinux ''
52+
patchelf --add-needed ${libsecret}/lib/libsecret-1.so.0 $out/bin/crate2nix
53+
'';
54+
});
5055
set_templates = if release then "" else "--set TEMPLATES_DIR ${./templates}";
5156
in
5257
symlinkJoin {

crate2nix/src/config.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ pub enum Source {
9494
/// The sha256 hash of the source.
9595
sha256: String,
9696
},
97+
/// Get the source from crates.io.
98+
Registry {
99+
/// The registry's URL
100+
registry: String,
101+
/// The crate name.
102+
name: String,
103+
/// The exact crate version to fetch.
104+
version: semver::Version,
105+
/// The sha256 hash of the source.
106+
sha256: String,
107+
},
97108
/// Get the source from git.
98109
Git {
99110
/// The URL of the git repository.
@@ -179,6 +190,20 @@ impl Display for Source {
179190
version,
180191
sha256,
181192
} => write!(f, "{} {} from crates.io: {}", name, version, sha256),
193+
Source::Registry {
194+
name,
195+
version,
196+
sha256,
197+
registry,
198+
..
199+
} => write!(
200+
f,
201+
"{} {} from {}: {}",
202+
name,
203+
version,
204+
registry.to_string(),
205+
sha256
206+
),
182207
Source::Git { url, rev, sha256 } => write!(f, "{}#{} via git: {}", url, rev, sha256),
183208
Source::Nix { file, attr: None } => write!(f, "{}", file),
184209
Source::Nix {
@@ -198,6 +223,15 @@ impl Source {
198223
version,
199224
..
200225
} => format!("cratesIo --name '{}' '{}' '{}'", name, crate_name, version),
226+
Source::Registry {
227+
name: crate_name,
228+
version,
229+
registry,
230+
..
231+
} => format!(
232+
"registry --registry '{}' --name '{}' '{}' '{}'",
233+
registry, name, crate_name, version
234+
),
201235
Source::Git { url, rev, .. } => {
202236
format!("git --name '{}' '{}' --rev {}", name, url, rev)
203237
}

crate2nix/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ pub struct BuildInfo {
4949
pub root_package_id: Option<PackageId>,
5050
/// Workspaces member package IDs by package names.
5151
pub workspace_members: BTreeMap<String, PackageId>,
52+
/// Registries used by the crates.
53+
pub registries: BTreeMap<String, String>,
5254
/// Build info for all crates needed for this build.
5355
pub crates: Vec<CrateDerivation>,
5456
/// For convenience include the source for tests.
@@ -87,6 +89,8 @@ impl BuildInfo {
8789

8890
prefetch_and_fill_crates_sha256(config, &merged, &mut default_nix)?;
8991

92+
prefetch_and_fill_registries(config, &mut default_nix)?;
93+
9094
Ok(default_nix)
9195
}
9296

@@ -145,6 +149,7 @@ impl BuildInfo {
145149
.map(|pkg| (pkg.name.clone(), pkg_id.clone()))
146150
})
147151
.collect(),
152+
registries: BTreeMap::new(),
148153
crates: metadata
149154
.pkgs_by_id
150155
.values()
@@ -215,6 +220,14 @@ fn prefetch_and_fill_crates_sha256(
215220
Ok(())
216221
}
217222

223+
/// Prefetch hashes when necessary.
224+
fn prefetch_and_fill_registries(config: &GenerateConfig, default_nix: &mut BuildInfo) -> Result<(), Error> {
225+
default_nix.registries = prefetch::prefetch_registries(config, &mut default_nix.crates)
226+
.map_err(|e| format_err!("while prefetching crates for calculating sha256: {}", e))?;
227+
228+
Ok(())
229+
}
230+
218231
fn extract_hashes_from_lockfile(
219232
config: &GenerateConfig,
220233
merged: &MergedMetadata,
@@ -299,6 +312,9 @@ pub struct GenerateConfig {
299312
/// The path of the `crate-hashes.json` file which is used to look up hashes and/or store
300313
/// prefetched hashes at.
301314
pub crate_hashes_json: PathBuf,
315+
/// The path of the `registry-hashes.json` file which is used to look up hashes and/or store
316+
/// prefetched hashes at.
317+
pub registry_hashes_json: PathBuf,
302318
/// The nix expression for the nixpkgs path to use.
303319
pub nixpkgs_path: String,
304320
/// Additional arguments to pass to `cargo metadata`.

crate2nix/src/main.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ pub enum Opt {
9898
)]
9999
crate_hashes: Option<PathBuf>,
100100

101+
#[structopt(
102+
short = "r",
103+
long = "registry-hashes",
104+
parse(from_os_str),
105+
help = "The path to the registry hash cache file. \
106+
Uses 'registry-hashes.json' in the same directory as the Cargo.nix output by default."
107+
)]
108+
registry_hashes: Option<PathBuf>,
109+
101110
// Mostly useful for testing
102111
#[structopt(
103112
long = "no-cargo-lock-checksums",
@@ -364,6 +373,7 @@ fn main() -> anyhow::Result<()> {
364373
output: opt_output,
365374
nixpkgs_path,
366375
crate_hashes,
376+
registry_hashes,
367377
all_features,
368378
default_features,
369379
no_default_features,
@@ -397,6 +407,13 @@ fn main() -> anyhow::Result<()> {
397407
.join("crate-hashes.json")
398408
});
399409

410+
let registry_hashes_json = registry_hashes.unwrap_or_else(|| {
411+
output
412+
.parent()
413+
.expect("Cargo.nix has parent")
414+
.join("registry-hashes.json")
415+
});
416+
400417
let generate_info = crate2nix::GenerateInfo::default();
401418

402419
let feature_metadata_options = || {
@@ -446,6 +463,7 @@ fn main() -> anyhow::Result<()> {
446463
output: output.clone(),
447464
nixpkgs_path,
448465
crate_hashes_json,
466+
registry_hashes_json,
449467
other_metadata_options: feature_metadata_options()?,
450468
use_cargo_lock_checksums: !no_cargo_lock_checksums,
451469
read_crate_hashes: !dont_read_crate_hashes,

crate2nix/src/prefetch.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::io::Write;
44
use std::process::Command;
55

66
use crate::metadata::PackageIdShortener;
7-
use crate::resolve::{CrateDerivation, CratesIoSource, GitSource, ResolvedSource};
7+
use crate::resolve::{CrateDerivation, CratesIoSource, GitSource, RegistrySource, ResolvedSource};
88
use crate::GenerateConfig;
99
use anyhow::bail;
1010
use anyhow::format_err;
@@ -172,6 +172,65 @@ pub fn prefetch(
172172
Ok(hashes)
173173
}
174174

175+
/// Prefetch the config.json file from all the derivation's private registries.
176+
pub fn prefetch_registries(
177+
config: &GenerateConfig,
178+
crate_derivations: &[CrateDerivation],
179+
) -> Result<BTreeMap<String, String>, Error> {
180+
181+
let hashes_string: String = if config.read_crate_hashes {
182+
std::fs::read_to_string(&config.registry_hashes_json).unwrap_or_else(|_| "{}".to_string())
183+
} else {
184+
"{}".to_string()
185+
};
186+
187+
let old_prefetched_hashes: BTreeMap<String, String> = serde_json::from_str(&hashes_string)?;
188+
189+
let mut hashes = old_prefetched_hashes.clone();
190+
191+
for package in crate_derivations {
192+
let registry =
193+
if let ResolvedSource::Registry(RegistrySource { ref registry, .. }) = package.source {
194+
registry
195+
} else {
196+
continue;
197+
};
198+
use std::collections::btree_map::Entry;
199+
if let Entry::Vacant(e) = hashes.entry(registry.to_string()) {
200+
eprintln!("Prefetching {} config", e.key());
201+
let out = get_command_output(
202+
"nix-prefetch-url",
203+
&[&format!(
204+
"{}{}config.json",
205+
e.key(),
206+
if e.key().ends_with("/") { "" } else { "/" }
207+
)],
208+
)?;
209+
e.insert(out);
210+
}
211+
}
212+
213+
if hashes != old_prefetched_hashes {
214+
std::fs::write(
215+
&config.registry_hashes_json,
216+
serde_json::to_vec_pretty(&hashes)?,
217+
)
218+
.map_err(|e| {
219+
format_err!(
220+
"while writing hashes to {}: {}",
221+
config.crate_hashes_json.to_str().unwrap_or("<unknown>"),
222+
e
223+
)
224+
})?;
225+
eprintln!(
226+
"Wrote hashes to {}.",
227+
config.registry_hashes_json.to_string_lossy()
228+
);
229+
}
230+
231+
Ok(hashes)
232+
}
233+
175234
fn get_command_output(cmd: &str, args: &[&str]) -> Result<String, Error> {
176235
let output = Command::new(cmd)
177236
.args(args)
@@ -206,6 +265,7 @@ impl ResolvedSource {
206265
fn inner_prefetchable(&self) -> Option<&dyn PrefetchableSource> {
207266
match self {
208267
ResolvedSource::CratesIo(source) => Some(source),
268+
ResolvedSource::Registry(source) => Some(source),
209269
ResolvedSource::Git(source) => Some(source),
210270
_ => None,
211271
}
@@ -241,6 +301,18 @@ impl PrefetchableSource for CratesIoSource {
241301
}
242302
}
243303

304+
impl PrefetchableSource for RegistrySource {
305+
fn needs_prefetch(&self) -> bool {
306+
self.sha256.is_none()
307+
}
308+
309+
fn prefetch(&self) -> Result<String, Error> {
310+
// This is done in two steps, currently only implemented in
311+
// the generated Nix.
312+
unimplemented!()
313+
}
314+
}
315+
244316
impl PrefetchableSource for GitSource {
245317
fn needs_prefetch(&self) -> bool {
246318
self.sha256.is_none()

0 commit comments

Comments
 (0)