DYNXZQZVGIOW26Y6VPP4TIBOJEMK6T6Y7HU5ZJYH4GIWFFRIJSIQC FYYWB54CXR3FTAQ4HLDTFS6XWBVLWRGKHVMMNKUXDEJ7UWLHXPBQC H5RKFV7YLV3QFY5HCQHGU7T232FPYMGWSBR3ABNGKMEAN5DS523AC XGCRPWKLJYWGVCMHDIR2K3PVT2R22JALVV5K2IXTHU3JBAEYANGAC 3KEFKH5FYGFUIWMIW6NY3K4FYSLE7LEXR4ZSF6WN52PCC3TVDZBAC U5AKEHEQWHBOVXMTTQFBJA4M4VJ7OWSJJVYYB6FLTJB7NCFPYVRQC SGQQ6LNZCGWM4WP5VOOCGDUZ2FVQEC4FANXJ5SEZPDQHSLF7YL2QC XXCRSVXOJVHO4A6W5R4A32WXXSNJDJLAT2CAQ6DE3JAMUFJF3HPAC 7YS2X7JJVAFT7QFDASQR4ZVUAAFYF4OLK5XLY3JJ2URSXI34ZOTAC std::string clone(const std::string_view &repoUrl,const nix::PathView &repoDir,const std::optional<std::string_view> &channel = {},const std::optional<std::string_view> &state = {});
void clone(const std::string_view &repoUrl,const Path &repoDir,const std::optional<std::string_view> &channel = {},const std::optional<std::string_view> &state = {});
auto program = "pijul"sv;auto res = runProgram(RunOptions{.program = std::string(program),.searchPath = true,.args = std::move(args),.chdir = Path(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;
runProcess("pijul", args, chdir ? chdir->c_str() : nullptr, mode);
std::string clone(const std::string_view &repoUrl,const std::string_view &repoDir,const std::optional<std::string_view> &channel,const std::optional<std::string_view> &state)
void clone(const std::string_view &repoUrl,const Path &repoDir,const std::optional<std::string_view> &channel,const std::optional<std::string_view> &state)
auto output = runPijul({"list"}, repoDir);
std::string output;runPijul({"list"}, repoDir, OutputMode::WithOutput{output});size_t pos = 0;size_t next;std::set<Path> out;while ((next = output.find_first_of("\n\r", pos)) != std::string::npos) {out.emplace(output.substr(pos, next - pos));pos = next + 1;}
#endif
#ifndef NIX_PLUGIN_PIJUL_COMPAT_H#define NIX_PLUGIN_PIJUL_COMPAT_H#ifdef NIX_VERSION#include <error.hh>#include <types.hh>#else#include <filesystem>#include <string>#include <vector>#endif#include <variant>namespace nixpluginpijul{#ifdef NIX_VERSIONusing StringList = nix::Strings;using Path = nix::Path;#elseusing StringList = std::vector<std::string>;using Path = std::filesystem::path;#endifstruct OutputMode final {enum Units {Standard,Interactive,};struct WithOutput {std::string &output;};OutputMode(Units data): m_data(data){}OutputMode(WithOutput data): m_data(data){}bool interactive(){if (auto *t = get_if<Units>(&m_data)) {return *t == Interactive;} else {return false;}}std::string *output(){if (auto *t = get_if<WithOutput>(&m_data)) {return &t->output;} else {return nullptr;}}private:std::variant<Units, WithOutput> m_data;};void runProcess(const char *path, const StringList &args, const char *chdir = nullptr, OutputMode mode = OutputMode::Standard);[[noreturn]] void fatal(const char *text);}#endif // NIX_PLUGIN_PIJUL_COMPAT_H
#include "compat.h"#ifdef NIX_VERSION#if NIX_VERSION >= 0x021900#include <processes.hh>#else#include <util.hh>#endif#else#include <cstdio>#include <fcntl.h>#include <format>#include <spawn.h>#include <sys/wait.h>#include <sysexits.h>#endifusing namespace std::string_literals;using namespace std::string_view_literals;namespace nixpluginpijul{void runProcess(const char *p, const StringList &args, const char *chdir, OutputMode mode){#ifdef NIX_VERSIONauto res = nix::runProgram(nix::RunOptions{.program = std::string(p),.searchPath = true,.args = args,.chdir = Path(chdir),.isInteractive = mode.interactive(),});if (!nix::statusOk(res.first)) {throw nix::ExecError(res.first, "program '%1%' %2%", p, nix::statusToString(res.first));}if (mode.output()) {*mode.output() = std::move(res.second);}#elseint fds[2];posix_spawn_file_actions_t fa;posix_spawn_file_actions_init(&fa);if (mode.output()) {if (pipe(fds) != 0) {perror("failed to create pipe");exit(EX_OSERR);}posix_spawn_file_actions_adddup2(&fa, fds[1], 0);posix_spawn_file_actions_adddup2(&fa, fds[1], 1);}if (!mode.interactive()) {posix_spawn_file_actions_addclose(&fa, 2);}if (chdir) {posix_spawn_file_actions_addchdir_np(&fa, chdir);}std::vector<const char *> argv;argv.push_back(p);for (const auto &el : args) {argv.push_back(el.c_str());}pid_t pid;if (posix_spawnp(&pid, p, &fa, nullptr, const_cast<char *const *const>(argv.data()), nullptr) != 0) {perror("failed to spawn process");exit(EX_OSERR);}close(fds[1]);posix_spawn_file_actions_destroy(&fa);fd_set set;FD_ZERO(&set);int nfds = 0;if (mode.output()) {FD_SET(fds[0], &set);fcntl(fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);nfds = 1;}sigset_t sigs;sigfillset(&sigs);sigdelset(&sigs, SIGCHLD);timespec timeout{.tv_sec = 1};bool running = true;int status;while (running) {// FIXME: this never catches the SIGCHLDint ret = pselect(nfds, &set, nullptr, nullptr, &timeout, &sigs);printf("%d\n", ret);if (ret == -1) {if (errno != EINTR) {perror("pselect");exit(EX_OSERR);}}ret = waitpid(pid, &status, WNOHANG);if (ret == -1) {perror("waitpid");exit(EX_OSERR);} else if (ret == pid) {running = false;ret = 1; // get the last data out of the pipe}if (ret > 0 && mode.output()) {char buf[4096];ssize_t len;do {len = read(fds[0], buf, sizeof(buf));if (len < 0 && errno != EWOULDBLOCK) {perror("read");exit(EX_OSERR);}if (len > 1) {mode.output()->append(buf, len);}} while (len > 0);}}if (mode.output()) {close(fds[0]);}if (status != 0) {fatal(std::format("process `{}' exited with status {}", p, WEXITSTATUS(status)).c_str());}#endif}void fatal(const char *text){#ifdef NIX_VERSIONthrow nix::Error("%1%", text);#elsefprintf(stderr, "fatal: %s\n", text);exit(EX_SOFTWARE);#endif}}
#include "repo.h"using namespace nixpluginpijul;int main(){clone("https://nest.pijul.com/dblsaiko/nix-plugin-pijul", "nix-plugin-pijul");const std::set<Path> &set = getTrackedFiles("nix-plugin-pijul");for (const auto &item : set) {printf("- %s\n", item.c_str());}}
#include "repo.h"#include <format>using namespace nixpluginpijul;template<typename T>void assert_eq(const T &left, const T &right){if (left != right) {const std::string &string = std::format("assertion failed: {} == {}", left, right);fprintf(stderr, "%s\n", string.c_str());exit(1);}}template<typename F>void assert_throws(F op){try {op();} catch (...) {return;}fprintf(stderr, "%s\n", "assertion failed: `op' didn't throw");exit(1);}int main(){auto point = parseRFC3339("1970-01-01T00:00:00.000Z");assert_eq(0L, point.time_since_epoch().count());point = parseRFC3339("1970-01-01T00:00:00Z");assert_eq(0L, point.time_since_epoch().count());point = parseRFC3339("1970-01-01T00:30:00+00:30");assert_eq(0L, point.time_since_epoch().count());point = parseRFC3339("1970-01-01T00:00:00.000-01:00");assert_eq(3600000L, point.time_since_epoch().count());assert_throws([] {parseRFC3339("garbage");});assert_throws([] {parseRFC3339("1");});assert_throws([] {parseRFC3339("1970-01-01T00:00:00");});// FIXME: this should be an invalid timestamp (at least, I think so) because// it has both +00:30 and 'Z' but it parsesassert_throws([] {parseRFC3339("1970-01-01T00:30:00+00:30Z");});}
add_compile_options(-O1 -ggdb)add_executable(DateTest datetest.cpp)target_link_libraries(DateTest PUBLIC PijulTesting)add_test(NAME DateTest COMMAND DateTest)add_executable(RepoTest repotest.cpp)target_link_libraries(RepoTest PUBLIC PijulTesting)add_test(NAME RepoTest COMMAND RepoTest)