1#include "nix-eval/src/lib.rs"2#include "lib.hh"3#include <nix/fetchers/fetch-settings.hh>4#include <nix/store/build-result.hh>5#include <nix/store/content-address.hh>6#include <nix/store/derived-path.hh>7#include <nix/store/local-fs-store.hh>8#include <nix/store/outputs-spec.hh>9#include <nix/store/path-info.hh>10#include <nix/store/profiles.hh>11#include <nix/store/realisation.hh>12#include <nix/store/store-api.hh>13#include <nix/util/file-system.hh>14#include <nix/util/hash.hh>15#include <nix/util/posix-source-accessor.hh>16#include <nix/util/ref.hh>17#include <nix/util/signature/local-keys.hh>18#include <nix/util/signature/signer.hh>19#include <nix/util/source-path.hh>20#include <nix_api_fetchers.h>21#include <nix_api_store_internal.h>22#include <sstream>2324struct nix_fetchers_settings {25 nix::ref<nix::fetchers::Settings> settings;26};2728extern "C" {29void set_fetcher_setting(nix_fetchers_settings *settings_struct,30 const char *setting, const char *value) {31 auto &settings_ref = settings_struct->settings;32 bool result = settings_ref->set(setting, value);33}34}3536rust::String switch_profile(Store *store, rust::Str profile,37 rust::Str store_path) {38 try {39 auto nixStore = store->ptr;40 auto *lfs = dynamic_cast<nix::LocalFSStore *>(&*nixStore);41 if (!lfs)42 return rust::String("destination is not a local-fs store");43 auto path = nixStore->parseStorePath(std::string(store_path));44 std::filesystem::path prof = std::string(profile);45 auto gen = nix::createGeneration(*lfs, prof, path);46 nix::switchLink(prof, gen);47 return rust::String();48 } catch (const std::exception &e) {49 return rust::String(e.what());50 }51}5253rust::String sign_closure(Store *store, rust::Str store_path,54 rust::Str key_file) {55 try {56 auto nixStore = store->ptr;57 nix::LocalSigner signer(58 nix::SecretKey::parse(nix::readFile(std::string(key_file))));59 auto root = nixStore->parseStorePath(std::string(store_path));60 nix::StorePathSet closure;61 nixStore->computeFSClosure(root, closure);62 for (auto &p : closure) {63 auto info = nixStore->queryPathInfo(p);64 nix::ValidPathInfo info2(*info);65 info2.sign(*nixStore, signer);66 nixStore->addSignatures(p, info2.sigs);67 }68 return rust::String();69 } catch (const std::exception &e) {70 return rust::String(e.what());71 }72}7374CxxListGenerationsResult list_generations(rust::Str profile_path) {75 CxxListGenerationsResult out{rust::String(), {}};76 try {77 auto [gens, current] =78 nix::findGenerations(std::filesystem::path(std::string(profile_path)));79 for (auto &g : gens) {80 CxxProfileGeneration cg{};81 cg.id = g.number;82 cg.store_path = rust::String(g.path.string());83 cg.creation_time_unix = static_cast<int64_t>(g.creationTime);84 cg.current = current.has_value() && *current == g.number;85 out.generations.push_back(cg);86 }87 } catch (const std::exception &e) {88 out.error = rust::String(e.what());89 }90 return out;91}9293static std::vector<std::string> split_lines(rust::Str joined) {94 std::vector<std::string> out;95 std::string buf;96 std::istringstream iss((std::string(joined)));97 while (std::getline(iss, buf)) {98 if (!buf.empty())99 out.push_back(buf);100 }101 return out;102}103104CxxBuildResult build_drv_outputs(Store *store, rust::Str drv_path,105 // TODO: Vec<str>106 rust::Str output_names_joined) {107 CxxBuildResult res{rust::String(), {}};108 try {109 auto nixStore = store->ptr;110 auto sp = nixStore->parseStorePath(std::string(drv_path));111112 nix::DerivedPath::Built built{113 .drvPath = nix::makeConstantStorePathRef(sp),114 .outputs = nix::OutputsSpec{nix::OutputsSpec::All{}},115 };116 auto names = split_lines(output_names_joined);117 if (!names.empty()) {118 std::set<nix::OutputName, std::less<>> nameSet;119 for (auto &n : names)120 nameSet.insert(n);121 built.outputs =122 nix::OutputsSpec{nix::OutputsSpec::Names{std::move(nameSet)}};123 }124125 std::vector<nix::DerivedPath> reqs;126 reqs.push_back(built);127128 auto results = nixStore->buildPathsWithResults(reqs);129 for (auto &r : results) {130 if (auto *failure = r.tryGetFailure()) {131 res.error = rust::String(failure->what());132 return res;133 }134 }135 for (auto &r : results) {136 if (auto *success = r.tryGetSuccess()) {137 for (auto &[name, real] : success->builtOutputs) {138 res.outputs.push_back(139 rust::String(nixStore->printStorePath(real.outPath)));140 }141 }142 }143 } catch (const std::exception &e) {144 res.error = rust::String(e.what());145 }146 return res;147}148149CxxBuildResult substitute_paths(Store *store, rust::Str paths_joined) {150 CxxBuildResult res{rust::String(), {}};151 try {152 auto nixStore = store->ptr;153 auto paths = split_lines(paths_joined);154155 std::vector<nix::DerivedPath> reqs;156 reqs.reserve(paths.size());157 for (auto &p : paths) {158 reqs.push_back(nix::DerivedPath::Opaque{nixStore->parseStorePath(p)});159 }160161 // Substituter miss will cause scheduler to trigger build162 auto results = nixStore->buildPathsWithResults(reqs);163 for (auto &r : results) {164 if (r.tryGetSuccess() == nullptr)165 continue;166 if (auto *opaque = std::get_if<nix::DerivedPath::Opaque>(&r.path.raw())) {167 res.outputs.push_back(168 rust::String(nixStore->printStorePath(opaque->path)));169 }170 }171 } catch (const std::exception &e) {172 res.error = rust::String(e.what());173 }174 return res;175}176177bool is_valid_path(Store *store, rust::Str path) {178 try {179 auto nixStore = store->ptr;180 auto sp = nixStore->parseStorePath(std::string(path));181 return nixStore->isValidPath(sp);182 } catch (const std::exception &) {183 return false;184 }185}186187AddFileToStoreResult add_file_to_store(Store *store, rust::Str name,188 rust::Str path) {189 AddFileToStoreResult out{rust::String(), rust::String(), rust::String()};190 try {191 auto nixStore = store->ptr;192 auto src = nix::PosixSourceAccessor::createAtRoot(193 std::filesystem::path(std::string(path)));194 auto info = nixStore->addToStoreSlow(std::string(name), src,195 nix::ContentAddressMethod::Raw::Flat,196 nix::HashAlgorithm::SHA256);197 out.store_path = rust::String(nixStore->printStorePath(info.path));198 if (info.ca.has_value()) {199 out.hash =200 rust::String(info.ca->hash.to_string(nix::HashFormat::SRI, true));201 }202 } catch (const std::exception &e) {203 out.error = rust::String(e.what());204 }205 return out;206}