mirror of
https://github.com/NixOS/nix.git
synced 2025-11-11 04:56:01 +01:00
Shellbang support with flakes
Enables shebang usage of nix shell. All arguments with `#! nix` get
added to the nix invocation. This implementation does NOT set any
additional arguments other than placing the script path itself as the
first argument such that the interpreter can utilize it.
Example below:
```
#!/usr/bin/env nix
#! nix shell --quiet
#! nix nixpkgs#bash
#! nix nixpkgs#shellcheck
#! nix nixpkgs#hello
#! nix --ignore-environment --command bash
# shellcheck shell=bash
set -eu
shellcheck "$0" || exit 1
function main {
hello
echo 0:"$0" 1:"$1" 2:"$2"
}
"$@"
```
fix: include programName usage
EDIT: For posterity I've changed shellwords to shellwords2 in order
not to interfere with other changes during a rebase.
shellwords2 is removed in a later commit. -- roberth
This commit is contained in:
parent
ba4e07782c
commit
74210c12fe
7 changed files with 114 additions and 9 deletions
|
|
@ -6,6 +6,7 @@
|
|||
#include "users.hh"
|
||||
#include "json-utils.hh"
|
||||
|
||||
#include <regex>
|
||||
#include <glob.h>
|
||||
|
||||
namespace nix {
|
||||
|
|
@ -78,6 +79,12 @@ std::optional<std::string> RootArgs::needsCompletion(std::string_view s)
|
|||
}
|
||||
|
||||
void RootArgs::parseCmdline(const Strings & _cmdline)
|
||||
{
|
||||
// Default via 5.1.2.2.1 in C standard
|
||||
Args::parseCmdline("", _cmdline);
|
||||
}
|
||||
|
||||
void Args::parseCmdline(const std::string & programName, const Strings & _cmdline)
|
||||
{
|
||||
Strings pendingArgs;
|
||||
bool dashDash = false;
|
||||
|
|
@ -93,6 +100,36 @@ void RootArgs::parseCmdline(const Strings & _cmdline)
|
|||
}
|
||||
|
||||
bool argsSeen = false;
|
||||
|
||||
// Heuristic to see if we're invoked as a shebang script, namely,
|
||||
// if we have at least one argument, it's the name of an
|
||||
// executable file, and it starts with "#!".
|
||||
Strings savedArgs;
|
||||
auto isNixCommand = std::regex_search(programName, std::regex("nix$"));
|
||||
if (isNixCommand && cmdline.size() > 0) {
|
||||
auto script = *cmdline.begin();
|
||||
try {
|
||||
auto lines = tokenizeString<Strings>(readFile(script), "\n");
|
||||
if (std::regex_search(lines.front(), std::regex("^#!"))) {
|
||||
lines.pop_front();
|
||||
for (auto pos = std::next(cmdline.begin()); pos != cmdline.end();pos++)
|
||||
savedArgs.push_back(*pos);
|
||||
cmdline.clear();
|
||||
|
||||
for (auto line : lines) {
|
||||
line = chomp(line);
|
||||
|
||||
std::smatch match;
|
||||
if (std::regex_match(line, match, std::regex("^#!\\s*nix\\s(.*)$")))
|
||||
for (const auto & word : shellwords(match[1].str()))
|
||||
cmdline.push_back(word);
|
||||
}
|
||||
cmdline.push_back(script);
|
||||
for (auto pos = savedArgs.begin(); pos != savedArgs.end();pos++)
|
||||
cmdline.push_back(*pos);
|
||||
}
|
||||
} catch (SysError &) { }
|
||||
}
|
||||
for (auto pos = cmdline.begin(); pos != cmdline.end(); ) {
|
||||
|
||||
auto arg = *pos;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue