|
18 | 18 | #include <thread> |
19 | 19 | #include <future> |
20 | 20 | #include <chrono> |
| 21 | +#include <regex> |
21 | 22 |
|
22 | 23 | #include <limits.h> |
23 | 24 | #include <sys/time.h> |
|
55 | 56 | #include <sys/statvfs.h> |
56 | 57 | #endif |
57 | 58 |
|
| 59 | +#include <nlohmann/json.hpp> |
| 60 | + |
58 | 61 |
|
59 | 62 | namespace nix { |
60 | 63 |
|
@@ -2286,12 +2289,99 @@ void DerivationGoal::initEnv() |
2286 | 2289 | } |
2287 | 2290 |
|
2288 | 2291 |
|
| 2292 | +static std::regex shVarName("[A-Za-z_][A-Za-z0-9_]*"); |
| 2293 | + |
| 2294 | + |
2289 | 2295 | void DerivationGoal::writeStructuredAttrs() |
2290 | 2296 | { |
2291 | | - auto json = drv->env.find("__json"); |
2292 | | - if (json == drv->env.end()) return; |
| 2297 | + auto jsonAttr = drv->env.find("__json"); |
| 2298 | + if (jsonAttr == drv->env.end()) return; |
| 2299 | + |
| 2300 | + try { |
| 2301 | + |
| 2302 | + auto jsonStr = rewriteStrings(jsonAttr->second, inputRewrites); |
| 2303 | + |
| 2304 | + auto json = nlohmann::json::parse(jsonStr); |
| 2305 | + |
| 2306 | + /* Add an "outputs" object containing the output paths. */ |
| 2307 | + nlohmann::json outputs; |
| 2308 | + for (auto & i : drv->outputs) |
| 2309 | + outputs[i.first] = rewriteStrings(i.second.path, inputRewrites); |
| 2310 | + json["outputs"] = outputs; |
| 2311 | + |
| 2312 | + writeFile(tmpDir + "/.attrs.json", json.dump()); |
| 2313 | + |
| 2314 | + /* As a convenience to bash scripts, write a shell file that |
| 2315 | + maps all attributes that are representable in bash - |
| 2316 | + namely, strings, integers, nulls, Booleans, and arrays and |
| 2317 | + objects consisting entirely of those values. (So nested |
| 2318 | + arrays or objects are not supported.) */ |
| 2319 | + |
| 2320 | + auto handleSimpleType = [](const nlohmann::json & value) -> std::experimental::optional<std::string> { |
| 2321 | + if (value.is_string()) |
| 2322 | + return shellEscape(value); |
| 2323 | + |
| 2324 | + if (value.is_number()) { |
| 2325 | + auto f = value.get<float>(); |
| 2326 | + if (std::ceil(f) == f) |
| 2327 | + return std::to_string(value.get<int>()); |
| 2328 | + } |
| 2329 | + |
| 2330 | + if (value.is_null()) |
| 2331 | + return "''"; |
| 2332 | + |
| 2333 | + if (value.is_boolean()) |
| 2334 | + return value.get<bool>() ? "1" : ""; |
| 2335 | + |
| 2336 | + return {}; |
| 2337 | + }; |
| 2338 | + |
| 2339 | + std::string jsonSh; |
2293 | 2340 |
|
2294 | | - writeFile(tmpDir + "/.attrs.json", rewriteStrings(json->second, inputRewrites)); |
| 2341 | + for (auto i = json.begin(); i != json.end(); ++i) { |
| 2342 | + |
| 2343 | + if (!std::regex_match(i.key(), shVarName)) continue; |
| 2344 | + |
| 2345 | + auto & value = i.value(); |
| 2346 | + |
| 2347 | + auto s = handleSimpleType(value); |
| 2348 | + if (s) |
| 2349 | + jsonSh += fmt("declare %s=%s\n", i.key(), *s); |
| 2350 | + |
| 2351 | + else if (value.is_array()) { |
| 2352 | + std::string s2; |
| 2353 | + bool good = true; |
| 2354 | + |
| 2355 | + for (auto i = value.begin(); i != value.end(); ++i) { |
| 2356 | + auto s3 = handleSimpleType(i.value()); |
| 2357 | + if (!s3) { good = false; break; } |
| 2358 | + s2 += *s3; s2 += ' '; |
| 2359 | + } |
| 2360 | + |
| 2361 | + if (good) |
| 2362 | + jsonSh += fmt("declare -a %s=(%s)\n", i.key(), s2); |
| 2363 | + } |
| 2364 | + |
| 2365 | + else if (value.is_object()) { |
| 2366 | + std::string s2; |
| 2367 | + bool good = true; |
| 2368 | + |
| 2369 | + for (auto i = value.begin(); i != value.end(); ++i) { |
| 2370 | + auto s3 = handleSimpleType(i.value()); |
| 2371 | + if (!s3) { good = false; break; } |
| 2372 | + s2 += fmt("[%s]=%s ", shellEscape(i.key()), *s3); |
| 2373 | + } |
| 2374 | + |
| 2375 | + if (good) |
| 2376 | + jsonSh += fmt("declare -A %s=(%s)\n", i.key(), s2); |
| 2377 | + } |
| 2378 | + } |
| 2379 | + |
| 2380 | + writeFile(tmpDir + "/.attrs.sh", jsonSh); |
| 2381 | + |
| 2382 | + } catch (std::exception & e) { |
| 2383 | + throw Error("cannot process __json attribute of '%s': %s", drvPath, e.what()); |
| 2384 | + } |
2295 | 2385 | } |
2296 | 2386 |
|
2297 | 2387 |
|
|
0 commit comments