nix doctor info

Change-Id: Ibe8280da94d0c76bfeb218c9dcb072f0bdbbea4d
This commit is contained in:
Qyriad 2024-04-16 13:37:07 -06:00
parent a0d1d0321e
commit 224157deb6

View file

@ -1,14 +1,27 @@
#include <filesystem>
#include <fstream>
#include <iostream>
#include <sstream>
#include <boost/algorithm/string.hpp>
#include "command.hh"
#include "eval-settings.hh"
#include "eval.hh"
#include "filetransfer.hh"
#include "logging.hh"
#include "serve-protocol.hh"
#include "shared.hh"
#include "store-api.hh"
#include "split.hh"
#include "local-fs-store.hh"
#include "util.hh"
#include "worker-protocol.hh"
namespace fs = std::filesystem;
using namespace std::literals::string_view_literals;
using namespace nix;
namespace {
@ -61,6 +74,36 @@ struct CmdDoctor : StoreCommand
void run(ref<Store> store) override
{
logger->log("Running checks against store uri: " + store->getUri());
std::cout << "- system: " << evalSettings.getCurrentSystem() << "\n";
if (fs::exists("/etc/os-release")) {
std::string hostOs = this->getOsDescription();
std::cout << "- host os: " << hostOs << "\n";
}
// Now check if multi-user.
// FIXME: how actually do we check this?
bool isMultiUser = settings.buildUsersGroup != "" || store->getUri() == "daemon";
std::cout << "- multi-user?: " << (isMultiUser ? "yes" : "no") << "\n";
std::cout << "- sandbox: " << settings.sandboxMode.to_string() << "\n";
std::cout << "- version: ";
// FIXME: nix-env is what nix-info uses. Is there any reason for us to do the same?
try {
// XXX
printVersion("nix-env:");
} catch (Exit const &) {
// Ignore.
}
std::cout << "- <nixpkgs>: ";
evalSettings.pureEval = false;
fileTransferSettings.tries = 0; // FIXME
EvalState evalState(SearchPath{}, store);
auto *nixpkgsSearch = evalState.parseExprFromString("<nixpkgs>", CanonPath::fromCwd());
Value nixpkgsValue;
evalState.eval(nixpkgsSearch, nixpkgsValue);
//evalState.forceValue(nixpkgsValue, noPos);
std::cout << printValue(evalState, nixpkgsValue) << "\n";
if (store.dynamic_pointer_cast<LocalFSStore>()) {
success &= checkNixInPath();
@ -73,6 +116,80 @@ struct CmdDoctor : StoreCommand
throw Exit(2);
}
std::string getOsDescription() const
{
constexpr std::string_view NAME = "NAME=";
constexpr std::string_view VERSION = "VERSION=";
constexpr std::string_view PRETTY_NAME = "PRETTY_NAME=";
constexpr std::string_view BUILD_ID = "BUILD_ID=";
constexpr auto dequoteStrip = [](std::string_view s) -> std::string_view {
return stripChars(s, "\" \n\r");
};
std::vector<std::string> parts;
parts.reserve(4);
if (auto unameCmd = which("uname")) {
assert(fs::path(*unameCmd).is_absolute());
try {
// -sr -> --kernel-name --kernel-release
auto unameOutput = runProgram(*unameCmd, false, {"-sr"});
parts.emplace_back(trim(unameOutput));
} catch (ExecError const & e) {
printError("could not run uname to get OS info: %s", e.what());
}
} else {
printError("could not get OS info: uname not found in PATH");
}
std::optional<std::string> name;
std::optional<std::string> version;
std::optional<std::string> prettyName;
std::optional<std::string> buildId;
try {
std::string const contents = readFile("/etc/os-release");
for (std::string_view const line : splitBy(contents, "\n")) {
if (line.starts_with(NAME)) {
name = dequoteStrip(line.substr(NAME.size()));
}
if (line.starts_with(VERSION)) {
version = dequoteStrip(line.substr(VERSION.size()));
}
if (line.starts_with(PRETTY_NAME)) {
prettyName = dequoteStrip(line.substr(PRETTY_NAME.size()));
}
if (line.starts_with(BUILD_ID)) {
buildId = dequoteStrip(line.substr(BUILD_ID.size()));
}
}
// Use pretty name, falling back to name and version.
if (prettyName.has_value()) {
parts.emplace_back(*prettyName);
} else if (name.has_value()) {
parts.emplace_back(*name);
if (version.has_value()) {
parts.emplace_back(*version);
}
}
if (buildId.has_value()) {
parts.emplace_back(*buildId);
}
} catch (SysError const & e) {
printError("could not determine OS from /etc/os-release: %s", e.what());
}
return boost::algorithm::join(parts, ", ");
}
bool checkNixInPath()
{
PathSet dirs;