#include "fetchers.hh" #include "store-api.hh" #include namespace nix::fetchers { std::unique_ptr>> inputSchemes = nullptr; void registerInputScheme(std::shared_ptr && inputScheme) { if (!inputSchemes) inputSchemes = std::make_unique>>(); inputSchemes->push_back(std::move(inputScheme)); } Input Input::fromURL(const std::string & url) { return fromURL(parseURL(url)); } static void fixupInput(Input & input) { // Check common attributes. input.getType(); input.getRef(); if (input.getRev()) input.immutable = true; input.getRevCount(); input.getLastModified(); if (input.getNarHash()) input.immutable = true; } Input Input::fromURL(const ParsedURL & url) { for (auto & inputScheme : *inputSchemes) { auto res = inputScheme->inputFromURL(url); if (res) { res->scheme = inputScheme; fixupInput(*res); return std::move(*res); } } throw Error("input '%s' is unsupported", url.url); } Input Input::fromAttrs(Attrs && attrs) { for (auto & inputScheme : *inputSchemes) { auto res = inputScheme->inputFromAttrs(attrs); if (res) { res->scheme = inputScheme; fixupInput(*res); return std::move(*res); } } Input input; input.attrs = attrs; fixupInput(input); return input; } ParsedURL Input::toURL() const { if (!scheme) throw Error("cannot show unsupported input '%s'", attrsToJson(attrs)); return scheme->toURL(*this); } std::string Input::to_string() const { return toURL().to_string(); } Attrs Input::toAttrs() const { return attrs; } bool Input::hasAllInfo() const { return getNarHash() && scheme && scheme->hasAllInfo(*this); } bool Input::operator ==(const Input & other) const { return attrs == other.attrs; } bool Input::contains(const Input & other) const { auto other2(other); other2.attrs.erase("ref"); other2.attrs.erase("rev"); if (*this == other2) return true; return false; } std::pair Input::fetch(ref store) const { if (!scheme) throw Error("cannot fetch unsupported input '%s'", attrsToJson(toAttrs())); auto [tree, input] = scheme->fetch(store, *this); if (tree.actualPath == "") tree.actualPath = store->toRealPath(tree.storePath); auto narHash = store->queryPathInfo(tree.storePath)->narHash; input.attrs.insert_or_assign("narHash", narHash.to_string(SRI)); if (auto narHash2 = getNarHash()) { if (narHash != *narHash2) throw Error("NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'", to_string(), tree.actualPath, narHash2->to_string(SRI), narHash.to_string(SRI)); } // FIXME: check lastModified, revCount input.immutable = true; assert(input.hasAllInfo()); return {std::move(tree), input}; } Input Input::applyOverrides( std::optional ref, std::optional rev) const { if (!scheme) return *this; return scheme->applyOverrides(*this, ref, rev); } void Input::clone(const Path & destDir) const { assert(scheme); scheme->clone(*this, destDir); } std::optional Input::getSourcePath() const { assert(scheme); return scheme->getSourcePath(*this); } void Input::markChangedFile( std::string_view file, std::optional commitMsg) const { assert(scheme); return scheme->markChangedFile(*this, file, commitMsg); } StorePath Input::computeStorePath(Store & store) const { auto narHash = getNarHash(); if (!narHash) throw Error("cannot compute store path for mutable input '%s'", to_string()); return store.makeFixedOutputPath(true, *narHash, "source"); } std::string Input::getType() const { return getStrAttr(attrs, "type"); } std::optional Input::getNarHash() const { if (auto s = maybeGetStrAttr(attrs, "narHash")) // FIXME: require SRI hash. return Hash(*s, htSHA256); return {}; } std::optional Input::getRef() const { if (auto s = maybeGetStrAttr(attrs, "ref")) return *s; return {}; } std::optional Input::getRev() const { if (auto s = maybeGetStrAttr(attrs, "rev")) return Hash(*s, htSHA1); return {}; } std::optional Input::getRevCount() const { if (auto n = maybeGetIntAttr(attrs, "revCount")) return *n; return {}; } std::optional Input::getLastModified() const { if (auto n = maybeGetIntAttr(attrs, "lastModified")) return *n; return {}; } ParsedURL InputScheme::toURL(const Input & input) { throw Error("don't know how to convert input '%s' to a URL", attrsToJson(input.attrs)); } Input InputScheme::applyOverrides( const Input & input, std::optional ref, std::optional rev) { if (ref) throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref); if (rev) throw Error("don't know how to set revision of input '%s' to '%s'", input.to_string(), rev->gitRev()); return input; } std::optional InputScheme::getSourcePath(const Input & input) { return {}; } void InputScheme::markChangedFile(const Input & input, std::string_view file, std::optional commitMsg) { assert(false); } void InputScheme::clone(const Input & input, const Path & destDir) { throw Error("do not know how to clone input '%s'", input.to_string()); } }