Skip to content

Commit 509e8dd

Browse files
authored
Merge pull request #120: cli: Add lockfile mode
2 parents 92ad564 + 7c89111 commit 509e8dd

File tree

3 files changed

+118
-71
lines changed

3 files changed

+118
-71
lines changed

README.md

+26-35
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,11 @@ Commands:
116116
help Print this message or the help of the given subcommand(s)
117117

118118
Options:
119-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
120-
-v, --verbose Print debug messages
121-
-h, --help Print help
122-
-V, --version Print version
119+
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
120+
--lock-file <LOCK_FILE> Specifies the path to the sources.json and activates lockfile mode. In lockfile mode, no default.nix will be generated and --directory will be ignored
121+
-v, --verbose Print debug messages
122+
-h, --help Print help
123+
-V, --version Print version
123124
```
124125

125126
### Initialization
@@ -139,10 +140,9 @@ Intializes the npins directory. Running this multiple times will restore/upgrade
139140
Usage: npins init [OPTIONS]
140141

141142
Options:
142-
--bare Don't add an initial `nixpkgs` entry
143-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
144-
-v, --verbose Print debug messages
145-
-h, --help Print help
143+
--bare Don't add an initial `nixpkgs` entry
144+
-v, --verbose Print debug messages
145+
-h, --help Print help
146146
```
147147

148148
### Migrate from Niv
@@ -168,10 +168,9 @@ Arguments:
168168
[PATH] [default: nix/sources.json]
169169

170170
Options:
171-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
172-
-n, --name <NAME> Only import one entry from Niv
173-
-v, --verbose Print debug messages
174-
-h, --help Print help
171+
-n, --name <NAME> Only import one entry from Niv
172+
-v, --verbose Print debug messages
173+
-h, --help Print help
175174
```
176175

177176
### Adding dependencies
@@ -211,12 +210,11 @@ Commands:
211210
help Print this message or the help of the given subcommand(s)
212211

213212
Options:
214-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
215-
--name <NAME> Add the pin with a custom name. If a pin with that name already exists, it will be overwritten
216-
--frozen Add the pin as frozen, meaning that it will be ignored by `npins update` by default
217-
-v, --verbose Print debug messages
218-
-n, --dry-run Don't actually apply the changes
219-
-h, --help Print help
213+
--name <NAME> Add the pin with a custom name. If a pin with that name already exists, it will be overwritten
214+
--frozen Add the pin as frozen, meaning that it will be ignored by `npins update` by default
215+
-n, --dry-run Don't actually apply the changes
216+
-v, --verbose Print debug messages
217+
-h, --help Print help
220218
```
221219

222220
There are several options for tracking git branches, releases and tags:
@@ -233,18 +231,16 @@ Arguments:
233231
Options:
234232
-b, --branch <BRANCH>
235233
Track a branch instead of a release
236-
-d, --directory <FOLDER>
237-
Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
238234
--name <NAME>
239235
Add the pin with a custom name. If a pin with that name already exists, it will be overwritten
240236
--at <tag or rev>
241237
Use a specific commit/release instead of the latest. This may be a tag name, or a git revision when --branch is set
242238
--frozen
243239
Add the pin as frozen, meaning that it will be ignored by `npins update` by default
244-
-v, --verbose
245-
Print debug messages
246240
--pre-releases
247241
Also track pre-releases. Conflicts with the --branch option
242+
-v, --verbose
243+
Print debug messages
248244
--upper-bound <version>
249245
Bound the version resolution. For example, setting this to "2" will restrict updates to 1.X versions. Conflicts with the --branch option
250246
--release-prefix <RELEASE_PREFIX>
@@ -267,9 +263,8 @@ Arguments:
267263
<NAME>
268264

269265
Options:
270-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
271-
-v, --verbose Print debug messages
272-
-h, --help Print help
266+
-v, --verbose Print debug messages
267+
-h, --help Print help
273268
```
274269

275270
### Show current entries
@@ -283,9 +278,8 @@ Lists the current pin entries
283278
Usage: npins show [OPTIONS]
284279

285280
Options:
286-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
287-
-v, --verbose Print debug messages
288-
-h, --help Print help
281+
-v, --verbose Print debug messages
282+
-h, --help Print help
289283
```
290284

291285
### Updating dependencies
@@ -302,16 +296,14 @@ Arguments:
302296
[NAMES]... Updates only the specified pins
303297

304298
Options:
305-
-d, --directory <FOLDER>
306-
Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
307299
-p, --partial
308300
Don't update versions, only re-fetch hashes
309301
-f, --full
310302
Re-fetch hashes even if the version hasn't changed. Useful to make sure the derivations are in the Nix store
311-
-v, --verbose
312-
Print debug messages
313303
-n, --dry-run
314304
Print the diff, but don't write back the changes
305+
-v, --verbose
306+
Print debug messages
315307
--frozen
316308
Allow updating frozen pins, which would otherwise be ignored
317309
--max-concurrent-downloads <MAX_CONCURRENT_DOWNLOADS>
@@ -331,9 +323,8 @@ Upgrade the sources.json and default.nix to the latest format version. This may
331323
Usage: npins upgrade [OPTIONS]
332324

333325
Options:
334-
-d, --directory <FOLDER> Base folder for sources.json and the boilerplate default.nix [env: NPINS_DIRECTORY=] [default: npins]
335-
-v, --verbose Print debug messages
336-
-h, --help Print help
326+
-v, --verbose Print debug messages
327+
-h, --help Print help
337328
```
338329

339330
### Using private GitLab repositories

src/cli.rs

+60-36
Original file line numberDiff line numberDiff line change
@@ -575,14 +575,18 @@ fn print_diff(name: &str, diff: impl AsRef<[diff::DiffEntry]>) {
575575
pub struct Opts {
576576
/// Base folder for sources.json and the boilerplate default.nix
577577
#[arg(
578-
global = true,
579578
short = 'd',
580579
long = "directory",
581580
default_value = "npins",
582581
env = "NPINS_DIRECTORY"
583582
)]
584583
folder: std::path::PathBuf,
585584

585+
/// Specifies the path to the sources.json and activates lockfile mode.
586+
/// In lockfile mode, no default.nix will be generated and --directory will be ignored.
587+
#[arg(long)]
588+
lock_file: Option<std::path::PathBuf>,
589+
586590
/// Print debug messages.
587591
#[arg(global = true, short = 'v', long = "verbose")]
588592
pub verbose: bool,
@@ -593,7 +597,11 @@ pub struct Opts {
593597

594598
impl Opts {
595599
fn read_pins(&self) -> Result<NixPins> {
596-
let path = self.folder.join("sources.json");
600+
let path = if let Some(lock_file) = self.lock_file.as_ref() {
601+
lock_file.to_owned()
602+
} else {
603+
self.folder.join("sources.json")
604+
};
597605
let fh = std::io::BufReader::new(std::fs::File::open(&path).with_context(move || {
598606
format!(
599607
"Failed to open {}. You must initialize npins before you can show current pins.",
@@ -605,10 +613,14 @@ impl Opts {
605613
}
606614

607615
fn write_pins(&self, pins: &NixPins) -> Result<()> {
608-
if !self.folder.exists() {
609-
std::fs::create_dir(&self.folder)?;
610-
}
611-
let path = self.folder.join("sources.json");
616+
let path = if let Some(lock_file) = &self.lock_file {
617+
lock_file.to_owned()
618+
} else {
619+
if !self.folder.exists() {
620+
std::fs::create_dir(&self.folder)?;
621+
}
622+
self.folder.join("sources.json")
623+
};
612624
let mut fh = std::fs::File::create(&path)
613625
.with_context(move || format!("Failed to open {} for writing.", path.display()))?;
614626
serde_json::to_writer_pretty(&mut fh, &versions::to_value_versioned(pins))?;
@@ -618,23 +630,27 @@ impl Opts {
618630

619631
async fn init(&self, o: &InitOpts) -> Result<()> {
620632
log::info!("Welcome to npins!");
621-
let default_nix = DEFAULT_NIX;
622-
if !self.folder.exists() {
623-
log::info!("Creating `{}` directory", self.folder.display());
624-
std::fs::create_dir(&self.folder).context("Failed to create npins folder")?;
625-
}
626-
log::info!("Writing default.nix");
627-
let p = self.folder.join("default.nix");
628-
let mut fh = std::fs::File::create(&p).context("Failed to create npins default.nix")?;
629-
fh.write_all(default_nix.as_bytes())?;
630633

631-
// Only create the pins if the file isn't there yet
632-
if self.folder.join("sources.json").exists() {
633-
log::info!(
634-
"The file '{}' already exists; nothing to do.",
635-
self.folder.join("pins.json").display()
636-
);
637-
return Ok(());
634+
// Skip the entire default.nix and convenience creating folders bit in lockfile mode
635+
if self.lock_file.is_none() {
636+
let default_nix = DEFAULT_NIX;
637+
if !self.folder.exists() {
638+
log::info!("Creating `{}` directory", self.folder.display());
639+
std::fs::create_dir(&self.folder).context("Failed to create npins folder")?;
640+
}
641+
log::info!("Writing default.nix");
642+
let p = self.folder.join("default.nix");
643+
let mut fh = std::fs::File::create(&p).context("Failed to create npins default.nix")?;
644+
fh.write_all(default_nix.as_bytes())?;
645+
646+
// Only create the pins if the file isn't there yet
647+
if self.folder.join("sources.json").exists() {
648+
log::info!(
649+
"The file '{}' already exists; nothing to do.",
650+
self.folder.join("pins.json").display()
651+
);
652+
return Ok(());
653+
}
638654
}
639655

640656
let initial_pins = if o.bare {
@@ -651,7 +667,7 @@ impl Opts {
651667
self.write_pins(&initial_pins)?;
652668
log::info!(
653669
"Successfully written initial files to '{}'.",
654-
self.folder.display()
670+
self.lock_file.as_ref().unwrap_or(&self.folder).display()
655671
);
656672
Ok(())
657673
}
@@ -812,19 +828,22 @@ impl Opts {
812828
}
813829

814830
fn upgrade(&self) -> Result<()> {
815-
anyhow::ensure!(
816-
self.folder.exists(),
817-
"Could not find npins folder at {}",
818-
self.folder.display(),
819-
);
831+
if self.lock_file.is_none() {
832+
anyhow::ensure!(
833+
self.folder.exists(),
834+
"Could not find npins folder at {}",
835+
self.folder.display(),
836+
);
820837

821-
let nix_path = self.folder.join("default.nix");
822-
let nix_file = DEFAULT_NIX;
823-
if std::fs::read_to_string(&nix_path)? == nix_file {
824-
log::info!("default.nix is already up to date");
825-
} else {
826-
log::info!("Replacing default.nix with an up to date version");
827-
std::fs::write(&nix_path, nix_file).context("Failed to create npins default.nix")?;
838+
let nix_path = self.folder.join("default.nix");
839+
let nix_file = DEFAULT_NIX;
840+
if std::fs::read_to_string(&nix_path)? == nix_file {
841+
log::info!("default.nix is already up to date");
842+
} else {
843+
log::info!("Replacing default.nix with an up to date version");
844+
std::fs::write(&nix_path, nix_file)
845+
.context("Failed to create npins default.nix")?;
846+
}
828847
}
829848

830849
log::info!("Upgrading sources.json to the newest format version");
@@ -842,7 +861,9 @@ impl Opts {
842861
let pins_raw_new = versions::upgrade(pins_raw.clone()).context("Upgrading failed")?;
843862
let pins: NixPins = serde_json::from_value(pins_raw_new.clone())?;
844863
if pins_raw_new != serde_json::Value::Object(pins_raw) {
845-
log::info!("Done. It is recommended to at least run `update --partial` afterwards.");
864+
log::info!(
865+
"Done. It is recommended to at least run `npins update --partial` afterwards."
866+
);
846867
}
847868
self.write_pins(&pins)
848869
}
@@ -1057,6 +1078,9 @@ impl Opts {
10571078
}
10581079

10591080
pub async fn run(&self) -> Result<()> {
1081+
if self.lock_file.is_some() && &*self.folder != std::path::Path::new("npins") {
1082+
anyhow::bail!("If --lock-file is set, --directory will be ignored and thus should not be set to a non-default value (which is \"npins\")");
1083+
}
10601084
match &self.command {
10611085
Command::Init(o) => self.init(o).await?,
10621086
Command::Show => self.show()?,

test.nix

+32
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,38 @@ let
340340
'';
341341
in
342342
{
343+
initNoDefaultNix = mkGitTest {
344+
name = "init-no-default-nix";
345+
repositories."foo" = gitRepo;
346+
commands = ''
347+
npins --lock-file sources.json init --bare
348+
# Setting a custom directory should fail in lockfile mode
349+
! npins --lock-file sources.json -d npins2 show
350+
npins --lock-file sources.json -d npins show
351+
test -e npins/default.nix && exit 1
352+
V=$(jq -r .pins sources.json)
353+
[[ "$V" = "{}" ]]
354+
'';
355+
};
356+
357+
addInLockfileMode = mkGitTest rec {
358+
name = "add-in-lockfile-mode";
359+
repositories."foo" = gitRepo;
360+
commands = ''
361+
npins --lock-file sources2.json init --bare
362+
npins --lock-file sources2.json add git http://localhost:8000/foo -b test-branch
363+
364+
# Check version and url
365+
eq "$(jq -r .pins.foo.version sources2.json)" "null"
366+
eq "$(jq -r .pins.foo.revision sources2.json)" "$(resolveGitCommit ${repositories."foo"} HEAD)"
367+
eq "$(jq -r .pins.foo.url sources2.json)" "null"
368+
369+
# Check setting the directory in normal mode still works
370+
npins -d testing init --bare
371+
NPINS_DIRECTORY=testing npins show
372+
'';
373+
};
374+
343375
addDryRun = mkGitTest {
344376
name = "add-dry-run";
345377
repositories."foo" = gitRepo;

0 commit comments

Comments
 (0)