#include "fetchers.hh" #include "store-api.hh" namespace nix::fetchers { struct PathInput : Input { Path path; /* Allow the user to pass in "fake" tree info attributes. This is useful for making a pinned tree work the same as the repository from which is exported (e.g. path:/nix/store/...-source?lastModified=1585388205&rev=b0c285...). */ std::optional rev; std::optional revCount; std::optional lastModified; std::string type() const override { return "path"; } std::optional getRev() const override { return rev; } bool operator ==(const Input & other) const override { auto other2 = dynamic_cast(&other); return other2 && path == other2->path && rev == other2->rev && revCount == other2->revCount && lastModified == other2->lastModified; } bool isImmutable() const override { return narHash || rev; } ParsedURL toURL() const override { auto query = attrsToQuery(toAttrsInternal()); query.erase("path"); return ParsedURL { .scheme = "path", .path = path, .query = query, }; } Attrs toAttrsInternal() const override { Attrs attrs; attrs.emplace("path", path); if (rev) attrs.emplace("rev", rev->gitRev()); if (revCount) attrs.emplace("revCount", *revCount); if (lastModified) attrs.emplace("lastModified", *lastModified); if (!rev && narHash) attrs.emplace("narHash", narHash->to_string(SRI)); return attrs; } std::optional getSourcePath() const override { return path; } void markChangedFile(std::string_view file, std::optional commitMsg) const override { } std::pair> fetchTreeInternal(nix::ref store) const override { auto input = std::make_shared(*this); // FIXME: check whether access to 'path' is allowed. auto storePath = store->maybeParseStorePath(path); if (storePath) store->addTempRoot(*storePath); if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath)) // FIXME: try to substitute storePath. storePath = store->addToStore("source", path); input->narHash = store->queryPathInfo(*storePath)->narHash; return { Tree { .actualPath = store->toRealPath(*storePath), .storePath = std::move(*storePath), .info = TreeInfo { .revCount = revCount, .lastModified = lastModified } }, input }; } }; struct PathInputScheme : InputScheme { std::unique_ptr inputFromURL(const ParsedURL & url) override { if (url.scheme != "path") return nullptr; auto input = std::make_unique(); input->path = url.path; if (url.authority && *url.authority != "") throw Error("path URL '%s' should not have an authority ('%s')", url.url, *url.authority); for (auto & [name, value] : url.query) if (name == "rev") input->rev = Hash(value, htSHA1); else if (name == "revCount") { uint64_t revCount; if (!string2Int(value, revCount)) throw Error("path URL '%s' has invalid parameter '%s'", url.to_string(), name); input->revCount = revCount; } else if (name == "lastModified") { time_t lastModified; if (!string2Int(value, lastModified)) throw Error("path URL '%s' has invalid parameter '%s'", url.to_string(), name); input->lastModified = lastModified; } else if (name == "narHash") // FIXME: require SRI hash. input->narHash = Hash(value); else throw Error("path URL '%s' has unsupported parameter '%s'", url.to_string(), name); return input; } std::unique_ptr inputFromAttrs(const Attrs & attrs) override { if (maybeGetStrAttr(attrs, "type") != "path") return {}; auto input = std::make_unique(); input->path = getStrAttr(attrs, "path"); for (auto & [name, value] : attrs) if (name == "rev") input->rev = Hash(getStrAttr(attrs, "rev"), htSHA1); else if (name == "revCount") input->revCount = getIntAttr(attrs, "revCount"); else if (name == "lastModified") input->lastModified = getIntAttr(attrs, "lastModified"); else if (name == "narHash") // FIXME: require SRI hash. input->narHash = Hash(getStrAttr(attrs, "narHash")); else if (name == "type" || name == "path") ; else throw Error("unsupported path input attribute '%s'", name); return input; } }; static auto r1 = OnStartup([] { registerInputScheme(std::make_unique()); }); }