|
| 1 | +#include "nix/store/active-builds.hh" |
| 2 | +#include "nix/util/json-utils.hh" |
| 3 | + |
| 4 | +#include <nlohmann/json.hpp> |
| 5 | + |
| 6 | +#ifndef _WIN32 |
| 7 | +# include <pwd.h> |
| 8 | +#endif |
| 9 | + |
| 10 | +namespace nix { |
| 11 | + |
| 12 | +UserInfo UserInfo::fromUid(uid_t uid) |
| 13 | +{ |
| 14 | + UserInfo info; |
| 15 | + info.uid = uid; |
| 16 | + |
| 17 | +#ifndef _WIN32 |
| 18 | + // Look up the user name for the UID (thread-safe) |
| 19 | + struct passwd pwd; |
| 20 | + struct passwd * result; |
| 21 | + std::vector<char> buf(16384); |
| 22 | + if (getpwuid_r(uid, &pwd, buf.data(), buf.size(), &result) == 0 && result) |
| 23 | + info.name = result->pw_name; |
| 24 | +#endif |
| 25 | + |
| 26 | + return info; |
| 27 | +} |
| 28 | + |
| 29 | +} // namespace nix |
| 30 | + |
| 31 | +namespace nlohmann { |
| 32 | + |
| 33 | +using namespace nix; |
| 34 | + |
| 35 | +UserInfo adl_serializer<UserInfo>::from_json(const json & j) |
| 36 | +{ |
| 37 | + return UserInfo{ |
| 38 | + .uid = j.at("uid").get<uid_t>(), |
| 39 | + .name = j.contains("name") && !j.at("name").is_null() |
| 40 | + ? std::optional<std::string>(j.at("name").get<std::string>()) |
| 41 | + : std::nullopt, |
| 42 | + }; |
| 43 | +} |
| 44 | + |
| 45 | +void adl_serializer<UserInfo>::to_json(json & j, const UserInfo & info) |
| 46 | +{ |
| 47 | + j = nlohmann::json{ |
| 48 | + {"uid", info.uid}, |
| 49 | + {"name", info.name}, |
| 50 | + }; |
| 51 | +} |
| 52 | + |
| 53 | +// Durations are serialized as floats representing seconds. |
| 54 | +static std::optional<std::chrono::microseconds> parseDuration(const json & j, const char * key) |
| 55 | +{ |
| 56 | + if (j.contains(key) && !j.at(key).is_null()) |
| 57 | + return std::chrono::duration_cast<std::chrono::microseconds>( |
| 58 | + std::chrono::duration<float, std::chrono::seconds::period>(j.at(key).get<double>())); |
| 59 | + else |
| 60 | + return std::nullopt; |
| 61 | +} |
| 62 | + |
| 63 | +static nlohmann::json printDuration(const std::optional<std::chrono::microseconds> & duration) |
| 64 | +{ |
| 65 | + return duration |
| 66 | + ? nlohmann::json( |
| 67 | + std::chrono::duration_cast<std::chrono::duration<float, std::chrono::seconds::period>>(*duration) |
| 68 | + .count()) |
| 69 | + : nullptr; |
| 70 | +} |
| 71 | + |
| 72 | +ActiveBuildInfo::ProcessInfo adl_serializer<ActiveBuildInfo::ProcessInfo>::from_json(const json & j) |
| 73 | +{ |
| 74 | + return ActiveBuildInfo::ProcessInfo{ |
| 75 | + .pid = j.at("pid").get<pid_t>(), |
| 76 | + .parentPid = j.at("parentPid").get<pid_t>(), |
| 77 | + .user = j.at("user").get<UserInfo>(), |
| 78 | + .argv = j.at("argv").get<std::vector<std::string>>(), |
| 79 | + .utime = parseDuration(j, "utime"), |
| 80 | + .stime = parseDuration(j, "stime"), |
| 81 | + .cutime = parseDuration(j, "cutime"), |
| 82 | + .cstime = parseDuration(j, "cstime"), |
| 83 | + }; |
| 84 | +} |
| 85 | + |
| 86 | +void adl_serializer<ActiveBuildInfo::ProcessInfo>::to_json(json & j, const ActiveBuildInfo::ProcessInfo & process) |
| 87 | +{ |
| 88 | + j = nlohmann::json{ |
| 89 | + {"pid", process.pid}, |
| 90 | + {"parentPid", process.parentPid}, |
| 91 | + {"user", process.user}, |
| 92 | + {"argv", process.argv}, |
| 93 | + {"utime", printDuration(process.utime)}, |
| 94 | + {"stime", printDuration(process.stime)}, |
| 95 | + {"cutime", printDuration(process.cutime)}, |
| 96 | + {"cstime", printDuration(process.cstime)}, |
| 97 | + }; |
| 98 | +} |
| 99 | + |
| 100 | +ActiveBuild adl_serializer<ActiveBuild>::from_json(const json & j) |
| 101 | +{ |
| 102 | + return ActiveBuild{ |
| 103 | + .nixPid = j.at("nixPid").get<pid_t>(), |
| 104 | + .clientPid = j.at("clientPid").get<std::optional<pid_t>>(), |
| 105 | + .clientUid = j.at("clientUid").get<std::optional<uid_t>>(), |
| 106 | + .mainPid = j.at("mainPid").get<pid_t>(), |
| 107 | + .mainUser = j.at("mainUser").get<UserInfo>(), |
| 108 | + .cgroup = j.at("cgroup").get<std::optional<Path>>(), |
| 109 | + .startTime = (time_t) j.at("startTime").get<double>(), |
| 110 | + .derivation = StorePath{getString(j.at("derivation"))}, |
| 111 | + }; |
| 112 | +} |
| 113 | + |
| 114 | +void adl_serializer<ActiveBuild>::to_json(json & j, const ActiveBuild & build) |
| 115 | +{ |
| 116 | + j = nlohmann::json{ |
| 117 | + {"nixPid", build.nixPid}, |
| 118 | + {"clientPid", build.clientPid}, |
| 119 | + {"clientUid", build.clientUid}, |
| 120 | + {"mainPid", build.mainPid}, |
| 121 | + {"mainUser", build.mainUser}, |
| 122 | + {"cgroup", build.cgroup}, |
| 123 | + {"startTime", (double) build.startTime}, |
| 124 | + {"derivation", build.derivation.to_string()}, |
| 125 | + }; |
| 126 | +} |
| 127 | + |
| 128 | +ActiveBuildInfo adl_serializer<ActiveBuildInfo>::from_json(const json & j) |
| 129 | +{ |
| 130 | + ActiveBuildInfo info(adl_serializer<ActiveBuild>::from_json(j)); |
| 131 | + info.processes = j.at("processes").get<std::vector<ActiveBuildInfo::ProcessInfo>>(); |
| 132 | + info.utime = parseDuration(j, "utime"); |
| 133 | + info.stime = parseDuration(j, "stime"); |
| 134 | + return info; |
| 135 | +} |
| 136 | + |
| 137 | +void adl_serializer<ActiveBuildInfo>::to_json(json & j, const ActiveBuildInfo & build) |
| 138 | +{ |
| 139 | + adl_serializer<ActiveBuild>::to_json(j, build); |
| 140 | + j["processes"] = build.processes; |
| 141 | + j["utime"] = printDuration(build.utime); |
| 142 | + j["stime"] = printDuration(build.stime); |
| 143 | +} |
| 144 | + |
| 145 | +} // namespace nlohmann |
0 commit comments