fix(3p/nix): Use SkipEmpty in all calls to absl::StrSplit

The behavior to return a list containing a single empty string when
provided an empty string is a behavior that absl inherited from legacy
code. However, the behavior expected by legacy code in Nix is the
behavior provided by the SkipEmpty option. Switch all calls to use
SkipEmpty, except for the call already using SkipWhitespace.

See also commit 26a59482d2, with the
partly-prophetic message: "there may be other places we need to
fix this as well."

Change-Id: I6e94856a12cfb1b7e4a3b4e221769ed446648861
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1687
Tested-by: BuildkiteCI
Reviewed-by: glittershark <grfn@gws.fyi>
This commit is contained in:
Kane York 2020-08-06 01:28:00 -07:00 committed by kanepyork
parent 6a97206ceb
commit a5dae62e85
28 changed files with 80 additions and 55 deletions

View file

@ -620,7 +620,8 @@ static void prim_derivationStrict(EvalState& state, const Pos& pos,
} else if (i->name == state.sOutputHashMode) {
handleHashMode(s);
} else if (i->name == state.sOutputs) {
handleOutputs(absl::StrSplit(s, absl::ByAnyChar(" \t\n\r")));
handleOutputs(absl::StrSplit(s, absl::ByAnyChar(" \t\n\r"),
absl::SkipEmpty()));
}
}
}

View file

@ -57,7 +57,7 @@ GitInfo exportGit(ref<Store> store, const std::string& uri,
std::set<std::string> files =
absl::StrSplit(runProgram("git", true, {"-C", uri, "ls-files", "-z"}),
absl::ByChar('\0'));
absl::ByChar('\0'), absl::SkipEmpty());
PathFilter filter = [&](const Path& p) -> bool {
assert(absl::StartsWith(p, uri));

View file

@ -53,7 +53,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string& uri,
runProgram("hg", true,
{"status", "-R", uri, "--clean", "--modified", "--added",
"--no-status", "--print0"}),
absl::ByChar('\0'));
absl::ByChar('\0'), absl::SkipEmpty());
PathFilter filter = [&](const Path& p) -> bool {
assert(absl::StartsWith(p, uri));
@ -129,7 +129,7 @@ HgInfo exportMercurial(ref<Store> store, const std::string& uri,
absl::StrSplit(runProgram("hg", true,
{"log", "-R", cacheDir, "-r", rev, "--template",
"{node} {rev} {branch}"}),
absl::ByAnyChar(" \t\n\r"));
absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
assert(tokens.size() == 3);
HgInfo hgInfo;

View file

@ -42,7 +42,8 @@ void BinaryCacheStore::init() {
upsertFile(cacheInfoFile, "StoreDir: " + storeDir + "\n",
"text/x-nix-cache-info");
} else {
for (auto& line : absl::StrSplit(*cacheInfo, absl::ByChar('\n'))) {
for (auto& line :
absl::StrSplit(*cacheInfo, absl::ByChar('\n'), absl::SkipEmpty())) {
size_t colon = line.find(':');
if (colon == std::string::npos) {
continue;

View file

@ -2485,7 +2485,8 @@ void DerivationGoal::initTmpDir() {
there is no size constraint). */
if (!parsedDrv->getStructuredAttrs()) {
std::set<std::string> passAsFile =
absl::StrSplit(get(drv->env, "passAsFile"), absl::ByAnyChar(" \t\n\r"));
absl::StrSplit(get(drv->env, "passAsFile"), absl::ByAnyChar(" \t\n\r"),
absl::SkipEmpty());
for (auto& i : drv->env) {
if (passAsFile.find(i.first) == passAsFile.end()) {
env[i.first] = i.second;

View file

@ -137,7 +137,7 @@ static void addPkg(const Path& pkgDir, int priority) {
try {
for (auto p : absl::StrSplit(
readFile(pkgDir + "/nix-support/propagated-user-env-packages"),
absl::ByAnyChar(" \n"))) {
absl::ByAnyChar(" \n"), absl::SkipEmpty())) {
auto pkg = std::string(p);
if (!done.count(pkg)) {
postponed.insert(pkg);
@ -175,8 +175,8 @@ void builtinBuildenv(const BasicDerivation& drv) {
/* Convert the stuff we get from the environment back into a
* coherent data type. */
Packages pkgs;
Strings derivations =
absl::StrSplit(getAttr("derivations"), absl::ByAnyChar(" \t\n\r"));
Strings derivations = absl::StrSplit(
getAttr("derivations"), absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
while (!derivations.empty()) {
/* !!! We're trusting the caller to structure derivations env var correctly
*/

View file

@ -421,7 +421,8 @@ DrvPathWithOutputs parseDrvPathWithOutputs(absl::string_view path) {
return DrvPathWithOutputs(
path.substr(0, pos),
absl::StrSplit(path.substr(pos + 1), absl::ByChar(',')));
absl::StrSplit(path.substr(pos + 1), absl::ByChar(','),
absl::SkipEmpty()));
}
Path makeDrvPathWithOutputs(const Path& drvPath,

View file

@ -181,7 +181,8 @@ struct CurlDownloader : public Downloader {
<< "': " << absl::StripAsciiWhitespace(line);
if (line.compare(0, 5, "HTTP/") == 0) { // new response starts
result.etag = "";
std::vector<std::string> ss = absl::StrSplit(line, absl::ByChar(' '));
std::vector<std::string> ss =
absl::StrSplit(line, absl::ByChar(' '), absl::SkipEmpty());
status = ss.size() >= 2 ? ss[1] : "";
result.data = std::make_shared<std::string>();
result.bodySize = 0;
@ -896,8 +897,8 @@ CachedDownloadResult Downloader::downloadCached(
storePath = readLink(fileLink);
store->addTempRoot(storePath);
if (store->isValidPath(storePath)) {
std::vector<std::string> ss =
absl::StrSplit(readFile(dataFile), absl::ByChar('\n'));
std::vector<std::string> ss = absl::StrSplit(
readFile(dataFile), absl::ByChar('\n'), absl::SkipEmpty());
if (ss.size() >= 3 && ss[0] == url) {
time_t lastChecked;
if (absl::SimpleAtoi(ss[2], &lastChecked) &&

View file

@ -423,8 +423,8 @@ void LocalStore::findRuntimeRoots(Roots& roots, bool censor) {
try {
auto mapFile = fmt("/proc/%s/maps", ent->d_name);
std::vector<std::string> mapLines =
absl::StrSplit(readFile(mapFile, true), absl::ByChar('\n'));
std::vector<std::string> mapLines = absl::StrSplit(
readFile(mapFile, true), absl::ByChar('\n'), absl::SkipEmpty());
for (const auto& line : mapLines) {
auto match = std::smatch{};
if (std::regex_match(line, match, mapRegex)) {

View file

@ -59,14 +59,14 @@ Settings::Settings()
auto s = getEnv("NIX_REMOTE_SYSTEMS");
if (!s.empty()) {
Strings ss;
for (auto p : absl::StrSplit(s, absl::ByChar(':'))) {
for (auto p : absl::StrSplit(s, absl::ByChar(':'), absl::SkipEmpty())) {
ss.push_back(absl::StrCat("@", p));
}
builders = concatStringsSep(" ", ss);
}
sandboxPaths =
absl::StrSplit("/bin/sh=" SANDBOX_SHELL, absl::ByAnyChar(" \t\n\r"));
sandboxPaths = absl::StrSplit("/bin/sh=" SANDBOX_SHELL,
absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
}
void loadConfFile() {

View file

@ -468,9 +468,9 @@ static void canonicalisePathMetaData_(const Path& path, uid_t fromUid,
throw SysError("querying extended attributes of '%s'", path);
}
for (auto& eaName :
absl::StrSplit(std::string(eaBuf.data(), eaSize),
absl::ByString(std::string("\000", 1)))) {
for (auto& eaName : absl::StrSplit(std::string(eaBuf.data(), eaSize),
absl::ByString(std::string("\000", 1)),
absl::SkipEmpty())) {
/* Ignore SELinux security labels since these cannot be
removed even by root. */
if (eaName == "security.selinux") {
@ -702,7 +702,7 @@ void LocalStore::queryPathInfoUncached(
s = (const char*)sqlite3_column_text(state->stmtQueryPathInfo, 6);
if (s != nullptr) {
info->sigs = absl::StrSplit(s, absl::ByChar(' '));
info->sigs = absl::StrSplit(s, absl::ByChar(' '), absl::SkipEmpty());
}
s = (const char*)sqlite3_column_text(state->stmtQueryPathInfo, 7);

View file

@ -97,8 +97,8 @@ class LocalStore : public LocalFSStore {
public:
// Hack for build-remote.cc.
// TODO(tazjin): remove this when we've got gRPC
PathSet locksHeld =
absl::StrSplit(getEnv("NIX_HELD_LOCKS"), absl::ByAnyChar(" \t\n\r"));
PathSet locksHeld = absl::StrSplit(
getEnv("NIX_HELD_LOCKS"), absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
/* Initialise the local store, upgrading the schema if
necessary. */

View file

@ -52,7 +52,8 @@ bool Machine::mandatoryMet(const std::set<std::string>& features) const {
}
void parseMachines(const std::string& s, Machines& machines) {
for (auto line : absl::StrSplit(s, absl::ByAnyChar("\n;"))) {
for (auto line :
absl::StrSplit(s, absl::ByAnyChar("\n;"), absl::SkipEmpty())) {
// Skip empty lines & comments
line = absl::StripAsciiWhitespace(line);
if (line.empty() || line[line.find_first_not_of(" \t")] == '#') {
@ -73,7 +74,7 @@ void parseMachines(const std::string& s, Machines& machines) {
}
std::vector<std::string> tokens =
absl::StrSplit(line, absl::ByAnyChar(" \t\n\r"));
absl::StrSplit(line, absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
auto sz = tokens.size();
if (sz < 1) {
throw FormatError("bad machine specification '%s'", line);
@ -86,13 +87,16 @@ void parseMachines(const std::string& s, Machines& machines) {
// TODO(tazjin): what???
machines.emplace_back(
tokens[0],
isSet(1) ? absl::StrSplit(tokens[1], absl::ByChar(','))
isSet(1)
? absl::StrSplit(tokens[1], absl::ByChar(','), absl::SkipEmpty())
: std::vector<std::string>{settings.thisSystem},
isSet(2) ? tokens[2] : "", isSet(3) ? std::stoull(tokens[3]) : 1LL,
isSet(4) ? std::stoull(tokens[4]) : 1LL,
isSet(5) ? absl::StrSplit(tokens[5], absl::ByChar(','))
isSet(5)
? absl::StrSplit(tokens[5], absl::ByChar(','), absl::SkipEmpty())
: std::set<std::string>{},
isSet(6) ? absl::StrSplit(tokens[6], absl::ByChar(','))
isSet(6)
? absl::StrSplit(tokens[6], absl::ByChar(','), absl::SkipEmpty())
: std::set<std::string>{},
isSet(7) ? tokens[7] : "");
}

View file

@ -232,14 +232,15 @@ class NarInfoDiskCacheImpl final : public NarInfoDiskCache {
auto hash_ = Hash::deserialize(queryNAR.getStr(6));
narInfo->narHash = Hash::unwrap_throw(hash_);
narInfo->narSize = queryNAR.getInt(7);
for (auto r : absl::StrSplit(queryNAR.getStr(8), absl::ByChar(' '))) {
for (auto r : absl::StrSplit(queryNAR.getStr(8), absl::ByChar(' '),
absl::SkipEmpty())) {
narInfo->references.insert(absl::StrCat(cache.storeDir, "/", r));
}
if (!queryNAR.isNull(9)) {
narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(9);
}
for (auto& sig :
absl::StrSplit(queryNAR.getStr(10), absl::ByChar(' '))) {
for (auto& sig : absl::StrSplit(
queryNAR.getStr(10), absl::ByChar(' '), absl::SkipEmpty())) {
narInfo->sigs.insert(std::string(sig));
}
narInfo->ca = queryNAR.getStr(11);

View file

@ -62,7 +62,8 @@ NarInfo::NarInfo(const Store& store, const std::string& s,
corrupt();
}
} else if (name == "References") {
std::vector<std::string> refs = absl::StrSplit(value, absl::ByChar(' '));
std::vector<std::string> refs =
absl::StrSplit(value, absl::ByChar(' '), absl::SkipEmpty());
if (!references.empty()) {
corrupt();
}

View file

@ -88,7 +88,8 @@ std::optional<Strings> ParsedDerivation::getStringsAttr(
if (i == drv.env.end()) {
return {};
}
return absl::StrSplit(i->second, absl::ByAnyChar(" \t\n\r"));
return absl::StrSplit(i->second, absl::ByAnyChar(" \t\n\r"),
absl::SkipEmpty());
}
}

View file

@ -22,7 +22,8 @@ SSHMaster::SSHMaster(const std::string& host, std::string keyFile,
void SSHMaster::addCommonSSHOpts(Strings& args) {
for (auto& i :
absl::StrSplit(getEnv("NIX_SSHOPTS"), absl::ByAnyChar(" \t\n\r"))) {
absl::StrSplit(getEnv("NIX_SSHOPTS"), absl::ByAnyChar(" \t\n\r"),
absl::SkipEmpty())) {
args.push_back(std::string(i));
}
if (!keyFile.empty()) {

View file

@ -960,7 +960,8 @@ std::pair<std::string, Store::Params> splitUriAndParams(
Store::Params params;
auto q = uri.find('?');
if (q != std::string::npos) {
Strings parts = absl::StrSplit(uri.substr(q + 1), absl::ByChar('&'));
Strings parts =
absl::StrSplit(uri.substr(q + 1), absl::ByChar('&'), absl::SkipEmpty());
for (const auto& s : parts) {
auto e = s.find('=');
if (e != std::string::npos) {

View file

@ -262,7 +262,7 @@ void BaseSetting<bool>::convertToArg(Args& args, const std::string& category) {
template <>
void BaseSetting<Strings>::set(const std::string& str) {
value = absl::StrSplit(str, absl::ByAnyChar(" \t\n\r"));
value = absl::StrSplit(str, absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
}
template <>
@ -280,7 +280,7 @@ void BaseSetting<Strings>::toJSON(JSONPlaceholder& out) {
template <>
void BaseSetting<StringSet>::set(const std::string& str) {
value = absl::StrSplit(str, absl::ByAnyChar(" \t\n\r"));
value = absl::StrSplit(str, absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
}
template <>

View file

@ -547,7 +547,7 @@ std::vector<Path> getConfigDirs() {
Path configHome = getConfigDir();
std::string configDirs = getEnv("XDG_CONFIG_DIRS");
std::vector<std::string> result =
absl::StrSplit(configDirs, absl::ByChar(':'));
absl::StrSplit(configDirs, absl::ByChar(':'), absl::SkipEmpty());
result.insert(result.begin(), configHome);
return result;
}

View file

@ -114,7 +114,8 @@ static void _main(int argc, char** argv) {
!std::regex_search(argv[1], std::regex("nix-shell"))) {
script = argv[1];
try {
Strings lines = absl::StrSplit(readFile(script), absl::ByChar('\n'));
Strings lines = absl::StrSplit(readFile(script), absl::ByChar('\n'),
absl::SkipEmpty());
if (std::regex_search(lines.front(), std::regex("^#!"))) {
lines.pop_front();
inShebang = true;
@ -443,8 +444,9 @@ static void _main(int argc, char** argv) {
env["NIX_STORE"] = store->storeDir;
env["NIX_BUILD_CORES"] = std::to_string(settings.buildCores);
StringSet passAsFile = absl::StrSplit(get(drv.env, "passAsFile", ""),
absl::ByAnyChar(" \t\n\r"));
StringSet passAsFile =
absl::StrSplit(get(drv.env, "passAsFile", ""),
absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
bool keepTmp = false;
int fileNr = 0;

View file

@ -26,14 +26,15 @@ static void readChannels() {
auto channelsFile = readFile(channelsList);
std::vector<std::string> lines =
absl::StrSplit(channelsFile, absl::ByChar('\n'));
absl::StrSplit(channelsFile, absl::ByChar('\n'), absl::SkipEmpty());
for (auto& line : lines) {
line = absl::StripTrailingAsciiWhitespace(line);
if (std::regex_search(line, std::regex("^\\s*\\#"))) {
continue;
}
std::vector<std::string> split = absl::StrSplit(line, absl::ByChar(' '));
std::vector<std::string> split =
absl::StrSplit(line, absl::ByChar(' '), absl::SkipEmpty());
auto url = std::regex_replace(split[0], std::regex("/*$"), "");
auto name = split.size() > 1 ? split[1] : baseNameOf(url);
channels[name] = url;

View file

@ -533,7 +533,8 @@ static void performOp(TunnelLogger* logger, const ref<Store>& store,
trusted.insert(s);
}
Strings subs;
Strings ss = absl::StrSplit(value, absl::ByAnyChar(" \t\n\r"));
Strings ss = absl::StrSplit(value, absl::ByAnyChar(" \t\n\r"),
absl::SkipEmpty());
for (auto& s : ss) {
if (trusted.count(s) != 0u) {
subs.push_back(s);

View file

@ -48,7 +48,8 @@ struct CmdDoctor final : StoreCommand {
static bool checkNixInPath() {
PathSet dirs;
for (auto& dir : absl::StrSplit(getEnv("PATH"), absl::ByChar(':'))) {
for (auto& dir :
absl::StrSplit(getEnv("PATH"), absl::ByChar(':'), absl::SkipEmpty())) {
if (pathExists(absl::StrCat(dir, "/nix-env"))) {
dirs.insert(dirOf(canonPath(absl::StrCat(dir, "/nix-env"), true)));
}
@ -71,7 +72,8 @@ struct CmdDoctor final : StoreCommand {
static bool checkProfileRoots(const ref<Store>& store) {
PathSet dirs;
for (auto dir : absl::StrSplit(getEnv("PATH"), absl::ByChar(':'))) {
for (auto dir :
absl::StrSplit(getEnv("PATH"), absl::ByChar(':'), absl::SkipEmpty())) {
Path profileDir = dirOf(dir);
try {
Path userEnv = canonPath(profileDir, true);

View file

@ -55,7 +55,8 @@ struct CmdEdit final : InstallableCommand {
auto editor = getEnv("EDITOR", "cat");
Strings args = absl::StrSplit(editor, absl::ByAnyChar(" \t\n\r"));
Strings args =
absl::StrSplit(editor, absl::ByAnyChar(" \t\n\r"), absl::SkipEmpty());
if (editor.find("emacs") != std::string::npos ||
editor.find("nano") != std::string::npos ||

View file

@ -123,7 +123,8 @@ struct CmdRun final : InstallablesCommand {
todo.push(path);
}
Strings unixPath = absl::StrSplit(getEnv("PATH"), absl::ByChar(':'));
Strings unixPath =
absl::StrSplit(getEnv("PATH"), absl::ByChar(':'), absl::SkipEmpty());
while (!todo.empty()) {
Path path = todo.front();
@ -137,7 +138,8 @@ struct CmdRun final : InstallablesCommand {
auto propPath = path + "/nix-support/propagated-user-env-packages";
if (accessor->stat(propPath).type == FSAccessor::tRegular) {
for (auto p :
absl::StrSplit(readFile(propPath), absl::ByAnyChar(" \t\n\r"))) {
absl::StrSplit(readFile(propPath), absl::ByAnyChar(" \t\n\r"),
absl::SkipEmpty())) {
todo.push(std::string(p));
}
}

View file

@ -103,7 +103,8 @@ struct CmdUpgradeNix final : MixDryRun, StoreCommand {
static Path getProfileDir(const ref<Store>& store) {
Path where;
for (auto& dir : absl::StrSplit(getEnv("PATH"), absl::ByChar(':'))) {
for (auto& dir :
absl::StrSplit(getEnv("PATH"), absl::ByChar(':'), absl::SkipEmpty())) {
if (pathExists(absl::StrCat(dir, "/nix-env"))) {
where = dir;
break;

View file

@ -80,7 +80,8 @@ std::string TestNameFor(
const testing::TestParamInfo<std::filesystem::path>& info) {
std::string name;
for (auto part : absl::StrSplit(info.param.stem().string(), '-')) {
for (auto part :
absl::StrSplit(info.param.stem().string(), '-', absl::SkipEmpty())) {
std::string part_owned(part);
part_owned[0] = absl::ascii_toupper(part_owned[0]);
absl::StrAppend(&name, part_owned);