Move repo interaction into separate source file

dblsaiko
Mar 24, 2024, 7:52 PM
XGCRPWKLJYWGVCMHDIR2K3PVT2R22JALVV5K2IXTHU3JBAEYANGAC

Dependencies

  • [2] 7YS2X7JJ Fix compilation against older Nix versions (tested with 2.13.6)
  • [3] SVCRRNQ6 Remove unnecessary version checks
  • [4] 3KEFKH5F Import existing code
  • [5] U5AKEHEQ Fix build for Nix 2.19 to 2.21

Change contents

  • file addition: repo.h (----------)
    [3.15]
    #ifndef NIX_PLUGIN_PIJUL_REPO_H
    #define NIX_PLUGIN_PIJUL_REPO_H
    #include <optional>
    #include <date/date.h>
    #include <types.hh>
    namespace nixpluginpijul
    {
    struct RepoStatus {
    std::string channel;
    std::string state;
    uint64_t lastModified;
    };
    std::string runPijul(nix::Strings args, std::optional<nix::Path> chdir = {}, std::optional<std::string> input = {}, bool isInteractive = false);
    RepoStatus getRepoStatus(const nix::PathView &repoPath);
    std::pair<std::string, uint64_t> getState(const nix::PathView &repoPath);
    std::string getRepoChannel(const nix::PathView &repoPath);
    date::sys_time<std::chrono::milliseconds> parseRFC3339(const std::string &spec);
    }
    #endif // NIX_PLUGIN_PIJUL_REPO_H
  • file addition: repo.cpp (----------)
    [3.15]
    #include "repo.h"
    #include <types.hh>
    #include <util.hh>
    #if NIX_VERSION >= 0x021900
    #include <processes.hh>
    #endif
    #include <nlohmann/json.hpp>
    using nlohmann::json;
    using namespace nix;
    using namespace std::string_literals;
    using namespace std::string_view_literals;
    namespace nixpluginpijul
    {
    std::string runPijul(Strings args, std::optional<Path> chdir, std::optional<std::string> input, bool isInteractive)
    {
    auto program = "pijul"sv;
    auto res = runProgram(RunOptions{
    .program = std::string(program),
    .searchPath = true,
    .args = std::move(args),
    .chdir = std::move(chdir),
    .input = std::move(input),
    .isInteractive = isInteractive,
    });
    if (!statusOk(res.first)) {
    throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first));
    }
    return res.second;
    }
    RepoStatus getRepoStatus(const PathView &repoPath)
    {
    auto [state, lastModified] = getState(repoPath);
    auto channel = getRepoChannel(repoPath);
    return RepoStatus{
    .channel = std::move(channel),
    .state = std::move(state),
    .lastModified = lastModified,
    };
    }
    std::pair<std::string, uint64_t> getState(const PathView &repoPath)
    {
    const auto &output = runPijul({"log", "--output-format", "json", "--state", "--limit", "1"}, Path(repoPath));
    const auto &json = json::parse(output);
    const auto &commitInfo = json.at(0);
    const auto &timestampSpec = commitInfo.at("timestamp").get<std::string>();
    const uint64_t timestamp = std::chrono::duration_cast<std::chrono::seconds>(parseRFC3339(timestampSpec).time_since_epoch()).count();
    const std::string &state = commitInfo.at("state");
    return {state, timestamp};
    }
    std::string getRepoChannel(const PathView &repoPath)
    {
    const auto &output = runPijul({"channel"}, Path(repoPath));
    std::string::size_type pos = 0;
    do {
    const auto nl = output.find('\n', pos);
    const auto line = std::string_view(output).substr(pos, nl - pos);
    if (line.empty()) {
    continue;
    }
    if (line.at(0) == '*') {
    return std::string(line.substr(2));
    }
    pos = nl;
    } while (pos != std::string::npos);
    throw Error("could not parse current channel"s);
    }
    date::sys_time<std::chrono::milliseconds> parseRFC3339(const std::string &spec)
    {
    std::istringstream in{spec};
    date::sys_time<std::chrono::milliseconds> pt;
    in >> date::parse("%FT%TZ", pt);
    if (in.fail()) {
    in.clear();
    in.exceptions(std::ios::failbit);
    in.str(spec);
    in >> date::parse("%FT%T%Ez", pt);
    }
    return pt;
    }
    }
  • edit in src/fetcher.cpp at line 1
    [3.53]
    [3.54]
    #include "repo.h"
  • edit in src/fetcher.cpp at line 25
    [3.223]
    [3.223]
    using nixpluginpijul::getRepoStatus;
    using nixpluginpijul::getState;
    using nixpluginpijul::RepoStatus;
  • edit in src/fetcher.cpp at line 34
    [3.331][3.331:332](),[3.332][3.332:709](),[2.28][3.709:749](),[3.709][3.709:749](),[2.36][3.749:915](),[3.749][3.749:915]()
    std::string runPijul(Strings args, std::optional<Path> chdir = {}, std::optional<std::string> input = {}, bool isInteractive = false)
    {
    auto program = "pijul"sv;
    auto res = runProgram(RunOptions{
    .program = std::string(program),
    .searchPath = true,
    .args = std::move(args),
    .chdir = std::move(chdir),
    .input = std::move(input),
    .isInteractive = isInteractive,
    });
    if (!statusOk(res.first)) {
    throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first));
    }
    return res.second;
    }
  • edit in src/fetcher.cpp at line 211
    [3.4332][3.4332:4451]()
    struct RepoStatus {
    std::string channel;
    std::string state;
    uint64_t lastModified;
    };
  • edit in src/fetcher.cpp at line 436
    [3.10847][3.10847:11185](),[3.11185][3.11185:11191](),[3.11191][3.11191:11827](),[3.11827][3.11827:11894](),[3.11894][3.11894:11900](),[3.11900][3.11900:11961](),[3.11961][3.11961:12099](),[3.12099][3.12099:12814]()
    static RepoStatus getRepoStatus(const PathView &repoPath)
    {
    auto [state, lastModified] = getState(repoPath);
    auto channel = getRepoChannel(repoPath);
    return RepoStatus{
    .channel = std::move(channel),
    .state = std::move(state),
    .lastModified = lastModified,
    };
    }
    static std::pair<std::string, uint64_t> getState(const PathView &repoPath)
    {
    const auto &output = runPijul({"log", "--output-format", "json", "--state", "--limit", "1"}, Path(repoPath));
    const auto &json = nlohmann::json::parse(output);
    const auto &commitInfo = json.at(0);
    const auto &timestampSpec = commitInfo.at("timestamp").get<std::string>();
    const uint64_t timestamp = std::chrono::duration_cast<std::chrono::seconds>(parseRFC3339(timestampSpec).time_since_epoch()).count();
    const std::string &state = commitInfo.at("state");
    return {state, timestamp};
    }
    static date::sys_seconds parseRFC3339(const std::string &spec)
    {
    std::istringstream in;
    date::sys_seconds pt;
    in >> date::parse("%FT%TZ", pt);
    if (in.fail()) {
    in.clear();
    in.exceptions(std::ios::failbit);
    in >> date::parse("%FT%T%Ez", pt);
    }
    return pt;
    }
    static std::string getRepoChannel(const PathView &repoPath)
    {
    const auto &output = runPijul({"channel"}, Path(repoPath));
    std::string::size_type pos = 0;
    do {
    const auto nl = output.find('\n', pos);
    const auto line = std::string_view(output).substr(pos, nl - pos);
    if (line.empty()) {
    continue;
    }
    if (line.at(0) == '*') {
    return std::string(line.substr(2));
    }
    pos = nl;
    } while (pos != std::string::npos);
    throw Error("could not parse current channel"s);
    }
  • replacement in src/CMakeLists.txt at line 4
    [3.13076][3.13076:13097]()
    fetcher.cpp)
    [3.13076]
    [3.13097]
    fetcher.cpp
    repo.cpp
    repo.h)