Skip to content

Commit 9b29363

Browse files
authored
Fix nom support (#59)
Previously, with `--nom`, `nix-your-shell` would pass all `nix` commands through `nom`, causing unsupported commands (e.g. all but `build`, `develop`, and `shell`) to fail (e.g. it would run `nom flake update`, which errors).
1 parent c4441aa commit 9b29363

File tree

2 files changed

+378
-353
lines changed

2 files changed

+378
-353
lines changed

src/main.rs

+16-353
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ mod shell;
1515
use shell::Shell;
1616
use shell::ShellKind;
1717

18+
mod nix;
19+
1820
/// Environment variable that indicates that the Nix profile has already been sourced.
1921
///
2022
/// This is set when a Nix profile script is sourced:
@@ -143,7 +145,7 @@ fn main() -> eyre::Result<()> {
143145
}
144146

145147
Command::NixShell { args } => {
146-
let new_args = transform_nix_shell(args, shell.path.as_str());
148+
let new_args = nix::transform_nix_shell(args, shell.path.as_str());
147149
let prog = if opts.nom { "nom-shell" } else { "nix-shell" };
148150
tracing::debug!(
149151
command = shell_words::join(
@@ -159,16 +161,25 @@ fn main() -> eyre::Result<()> {
159161
}
160162

161163
Command::Nix { args } => {
162-
let new_args = transform_nix(args, shell.path.as_str());
163-
let prog = if opts.nom { "nom" } else { "nix" };
164+
let new_args = nix::transform_nix(args, shell.path.as_str());
165+
let prog = if opts.nom
166+
&& new_args
167+
.subcommand
168+
.map(|subcommand| ["shell", "build", "develop"].contains(&subcommand.as_str()))
169+
.unwrap_or(false)
170+
{
171+
"nom"
172+
} else {
173+
"nix"
174+
};
164175
tracing::debug!(
165176
command = shell_words::join(
166-
std::iter::once(prog).chain(new_args.iter().map(|s| s.as_str()))
177+
std::iter::once(prog).chain(new_args.args.iter().map(|s| s.as_str()))
167178
),
168179
"Launching nix"
169180
);
170181
Err(process::Command::new(prog)
171-
.args(new_args)
182+
.args(new_args.args)
172183
.env(NIX_SOURCED_VAR, "1")
173184
.exec()
174185
.into())
@@ -211,351 +222,3 @@ fn executable_is_on_path(executable: &Utf8Path) -> eyre::Result<bool> {
211222
.map(Utf8Path::new)
212223
.any(|component| component == directory))
213224
}
214-
215-
/// Transform arguments to a `nix` invocation to run the specified `command`.
216-
///
217-
/// Only modifies `nix develop` and `nix shell` commands.
218-
fn transform_nix(args: Vec<String>, command: &str) -> Vec<String> {
219-
let mut ret = Vec::with_capacity(args.len() + 2);
220-
221-
let mut subcommand = None;
222-
223-
let mut i = 0;
224-
while i < args.len() {
225-
ret.push(args[i].clone());
226-
227-
match args[i].as_str() {
228-
"--help" | "--version"
229-
| "-c" | "--command"
230-
=> {
231-
// We already have a command to run.
232-
return args;
233-
}
234-
235-
// Two arguments
236-
"--option"
237-
| "--redirect"
238-
| "--override-flake"
239-
| "--arg"
240-
| "--argstr"
241-
| "--override-input"
242-
=> {
243-
ret.push(args[i + 1].clone());
244-
ret.push(args[i + 2].clone());
245-
i += 2;
246-
}
247-
248-
// One argument
249-
"--log-format"
250-
| "--access-tokens"
251-
| "--allowed-impure-host-deps"
252-
| "--allowed-uris"
253-
| "--allowed-users"
254-
| "--bash-prompt"
255-
| "--bash-prompt-prefix"
256-
| "--bash-prompt-suffix"
257-
| "--build-hook"
258-
| "--build-poll-interval"
259-
| "--build-users-group"
260-
| "--builders"
261-
| "--commit-lockfile-summary"
262-
| "--connect-timeout"
263-
| "--cores"
264-
| "--diff-hook"
265-
| "--download-attempts"
266-
| "--download-speed"
267-
| "--experimental-features"
268-
| "--extra-access-tokens"
269-
| "--extra-allowed-impure-host-deps"
270-
| "--extra-allowed-uris"
271-
| "--extra-allowed-users"
272-
| "--extra-experimental-features"
273-
| "--extra-extra-platforms"
274-
| "--extra-hashed-mirrors"
275-
| "--extra-nix-path"
276-
| "--extra-platforms"
277-
| "--extra-plugin-files"
278-
| "--extra-sandbox-paths"
279-
| "--extra-secret-key-files"
280-
| "--extra-substituters"
281-
| "--extra-system-features"
282-
| "--extra-trusted-public-keys"
283-
| "--extra-trusted-substituters"
284-
| "--extra-trusted-users"
285-
| "--flake-registry"
286-
| "--gc-reserved-space"
287-
| "--hashed-mirrors"
288-
| "--http-connections"
289-
| "--log-lines"
290-
| "--max-build-log-size"
291-
| "--max-free"
292-
| "--max-jobs"
293-
| "--max-silent-time"
294-
| "--min-free"
295-
| "--min-free-check-interval"
296-
| "--nar-buffer-size"
297-
| "--narinfo-cache-negative-ttl"
298-
| "--narinfo-cache-positive-ttl"
299-
| "--netrc-file"
300-
| "--nix-path"
301-
| "--plugin-files"
302-
| "--post-build-hook"
303-
| "--pre-build-hook"
304-
| "--repeat"
305-
| "--sandbox-paths"
306-
| "--secret-key-files"
307-
| "--stalled-download-timeout"
308-
| "--store"
309-
| "--substituters"
310-
| "--system"
311-
| "--system-features"
312-
| "--tarball-ttl"
313-
| "--timeout"
314-
| "--trusted-public-keys"
315-
| "--trusted-substituters"
316-
| "--trusted-users"
317-
| "--user-agent-suffix"
318-
// `nix develop` options
319-
| "-k" | "--keep"
320-
| "--phase"
321-
|"--profile"
322-
| "--unset"
323-
| "--eval-store"
324-
| "-I" | "--include"
325-
| "--inputs-from"
326-
| "--update-input"
327-
| "--expr"
328-
| "-f" | "--file"
329-
=> {
330-
ret.push(args[i + 1].clone());
331-
i += 1;
332-
}
333-
334-
// Zero arguments
335-
"--offline"
336-
| "--refresh"
337-
| "--debug"
338-
| "-L"
339-
| "--print-build-logs"
340-
| "--quiet"
341-
| "-v"
342-
| "--verbose"
343-
| "--accept-flake-config"
344-
| "--no-accept-flake-config"
345-
| "--allow-dirty"
346-
| "--no-allow-dirty"
347-
| "--allow-import-from-derivation"
348-
| "--no-allow-import-from-derivation"
349-
| "--allow-symlinked-store"
350-
| "--no-allow-symlinked-store"
351-
| "--allow-unsafe-native-code-during-evaluation"
352-
| "--no-allow-unsafe-native-code-during-evaluation"
353-
| "--auto-optimise-store"
354-
| "--no-auto-optimise-store"
355-
| "--builders-use-substitutes"
356-
| "--no-builders-use-substitutes"
357-
| "--compress-build-log"
358-
| "--no-compress-build-log"
359-
| "--darwin-log-sandbox-violations"
360-
| "--no-darwin-log-sandbox-violations"
361-
| "--enforce-determinism"
362-
| "--no-enforce-determinism"
363-
| "--eval-cache"
364-
| "--no-eval-cache"
365-
| "--fallback"
366-
| "--no-fallback"
367-
| "--fsync-metadata"
368-
| "--no-fsync-metadata"
369-
| "--http2"
370-
| "--no-http2"
371-
| "--ignore-try"
372-
| "--no-ignore-try"
373-
| "--impersonate-linux-26"
374-
| "--no-impersonate-linux-26"
375-
| "--keep-build-log"
376-
| "--no-keep-build-log"
377-
| "--keep-derivations"
378-
| "--no-keep-derivations"
379-
| "--keep-env-derivations"
380-
| "--no-keep-env-derivations"
381-
| "--keep-failed"
382-
| "--no-keep-failed"
383-
| "--keep-going"
384-
| "--no-keep-going"
385-
| "--keep-outputs"
386-
| "--no-keep-outputs"
387-
| "--preallocate-contents"
388-
| "--no-preallocate-contents"
389-
| "--print-missing"
390-
| "--no-print-missing"
391-
| "--pure-eval"
392-
| "--no-pure-eval"
393-
| "--require-sigs"
394-
| "--no-require-sigs"
395-
| "--restrict-eval"
396-
| "--no-restrict-eval"
397-
| "--run-diff-hook"
398-
| "--no-run-diff-hook"
399-
| "--sandbox"
400-
| "--no-sandbox"
401-
| "--sandbox-fallback"
402-
| "--no-sandbox-fallback"
403-
| "--show-trace"
404-
| "--no-show-trace"
405-
| "--substitute"
406-
| "--no-substitute"
407-
| "--sync-before-registering"
408-
| "--no-sync-before-registering"
409-
| "--trace-function-calls"
410-
| "--no-trace-function-calls"
411-
| "--trace-verbose"
412-
| "--no-trace-verbose"
413-
| "--use-case-hack"
414-
| "--no-use-case-hack"
415-
| "--use-registries"
416-
| "--no-use-registries"
417-
| "--use-sqlite-wal"
418-
| "--no-use-sqlite-wal"
419-
| "--warn-dirty"
420-
| "--no-warn-dirty"
421-
| "--relaxed-sandbox"
422-
// `nix develop` options
423-
| "--build"
424-
| "--check"
425-
| "--configure"
426-
| "--debugger"
427-
| "-i" | "--ignore-environment"
428-
| "--install"
429-
| "--installcheck"
430-
| "--unpack"
431-
| "--impure"
432-
| "--commit-lock-file"
433-
| "--no-registries"
434-
| "--no-update-lock-file"
435-
| "--no-write-lock-file"
436-
| "--recreate-lock-file"
437-
| "--derivation"
438-
=> {}
439-
440-
"build" | "develop" | "flake" | "help" | "profile" | "repl" | "run" | "search"
441-
| "shell" | "bundle" | "copy" | "edit" | "eval" | "fmt" | "log" | "path-info"
442-
| "registry" | "why-depends" | "daemon" | "describe-stores" | "hash" | "key"
443-
| "nar" | "print-dev-env" | "realisation" | "show-config" | "show-derivation"
444-
| "store" | "doctor" | "upgrade-nix" => {
445-
// Top-level subcommand.
446-
447-
// Replace `subcommand` unless it already has a value.
448-
if subcommand.is_none() {
449-
subcommand = Some(args[i].clone());
450-
}
451-
}
452-
453-
_ => {
454-
// Unknown argument, ignore.
455-
}
456-
}
457-
458-
i += 1;
459-
}
460-
461-
// We want to add our `--command` flag right at the end, because `--command` makes *all the
462-
// rest of the positional arguments* get parsed as arguments to the command.
463-
//
464-
// Note that this behavior is unlike `nix-shell`, where the `--command` flag takes one argument
465-
// that may include spaces...
466-
match subcommand.as_deref() {
467-
Some("develop") | Some("shell") => {
468-
ret.push("--command".into());
469-
ret.push(command.into());
470-
}
471-
472-
_ => {}
473-
}
474-
475-
ret
476-
}
477-
478-
/// Transform arguments to a `nix-shell` invocation to run the specified `command`.
479-
fn transform_nix_shell(args: Vec<String>, command: &str) -> Vec<String> {
480-
let mut ret = Vec::with_capacity(args.len() + 2);
481-
ret.push("--command".into());
482-
ret.push(command.into());
483-
484-
let mut i = 0;
485-
while i < args.len() {
486-
ret.push(args[i].clone());
487-
match args[i].as_str() {
488-
// Two arguments
489-
"--arg" | "--argstr"
490-
// `nix-store`
491-
| "--option"
492-
// From `nix-build` source...
493-
| "--override-flake"
494-
=> {
495-
ret.push(args[i + 1].clone());
496-
ret.push(args[i + 2].clone());
497-
i += 2;
498-
}
499-
500-
// One argument
501-
"--attr" | "-A" | "--exclude" | "--keep"
502-
| "-i" // Interpreter, shebang only
503-
// `nix-store`
504-
| "--add-root"
505-
// From `nix-build` source...
506-
| "--cores"
507-
| "--max-silent-time"
508-
| "--timeout"
509-
| "--store-uri"
510-
| "-I" | "--include"
511-
| "--eval-store"
512-
| "-o" | "--out-link"
513-
=> {
514-
ret.push(args[i + 1].clone());
515-
i += 1;
516-
}
517-
518-
// Zero arguments
519-
"--pure" | "--impure"
520-
// `--packages` changes the meaning of positional arguments, so we effectively
521-
// ignore it.
522-
| "-p" | "--packages"
523-
// Also changes meaning of positional arguments.
524-
| "-E" | "--expr"
525-
// `nix-store`
526-
| "--dry-run" | "--ignore-unknown" | "--check"
527-
// From `nix-build` source...
528-
| "-Q" | "--no-build-output"
529-
| "-K" | "--keep-failed"
530-
| "-k" | "--keep-going"
531-
| "--fallback"
532-
| "--readonly-mode"
533-
| "--no-gc-warning"
534-
| "--add-drv-link" | "--indirect"
535-
| "--no-out-link" | "--no-link"
536-
| "--drv-link"
537-
| "--repair"
538-
| "--run-env"
539-
=> {
540-
// Nothing to skip.
541-
}
542-
543-
"--command" | "--run"
544-
| "--help"
545-
| "--version"
546-
=> {
547-
// We already have a command to run; don't add our own `--command {command}`
548-
// arguments.
549-
return args;
550-
}
551-
552-
_ => {
553-
// Unknown argument, ignore.
554-
}
555-
}
556-
557-
i += 1;
558-
}
559-
560-
ret
561-
}

0 commit comments

Comments
 (0)