From a7a4e6a4f719da8d0b26d9a60ff8ed42691d263f Mon Sep 17 00:00:00 2001 From: Ludovic Courtès Date: Sun, 22 Sep 2013 23:23:38 +0200 Subject: Add 'guix-register'. * nix/guix-register/guix-register.cc, tests/guix-register.sh: New files. * Makefile.am (SH_TESTS)[BUILD_DAEMON]: Add tests/guix-register.sh. * daemon.am (sbin_PROGRAMS, guix_register_SOURCES, guix_register_CPPFLAGS, guix_register_LDADD): New variables. * test-env.in: Export 'storedir', 'prefix', 'datarootdir', 'datadir', and 'localstatedir'. --- .gitignore | 1 + Makefile.am | 7 ++ daemon.am | 16 ++++ nix/guix-register/guix-register.cc | 168 +++++++++++++++++++++++++++++++++++++ test-env.in | 7 ++ tests/guix-register.sh | 74 ++++++++++++++++ 6 files changed, 273 insertions(+) create mode 100644 nix/guix-register/guix-register.cc create mode 100644 tests/guix-register.sh diff --git a/.gitignore b/.gitignore index f97a3b5f3d..78b16800bf 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ stamp-h[0-9] /nix/scripts/substitute-binary /doc/images/bootstrap-graph.png /doc/images/bootstrap-graph.eps +/guix-register diff --git a/Makefile.am b/Makefile.am index bf9c1d0e91..7dc79e26e4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -117,6 +117,13 @@ SH_TESTS = \ tests/guix-hash.sh \ tests/guix-package.sh +if BUILD_DAEMON + +SH_TESTS += tests/guix-register.sh + +endif BUILD_DAEMON + + TESTS = $(SCM_TESTS) $(SH_TESTS) TEST_EXTENSIONS = .scm .sh diff --git a/daemon.am b/daemon.am index 8c21dbc328..77bfe71987 100644 --- a/daemon.am +++ b/daemon.am @@ -121,6 +121,7 @@ libstore_a_CXXFLAGS = \ $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) bin_PROGRAMS = guix-daemon +sbin_PROGRAMS = guix-register guix_daemon_SOURCES = \ nix/nix-daemon/nix-daemon.cc \ @@ -137,6 +138,21 @@ guix_daemon_LDADD = \ guix_daemon_headers = \ nix/nix-daemon/shared.hh + +guix_register_SOURCES = \ + nix/guix-register/guix-register.cc + +guix_register_CPPFLAGS = \ + $(libutil_a_CPPFLAGS) \ + $(libstore_a_CPPFLAGS) \ + -I$(top_srcdir)/nix/libstore + +# XXX: Should we start using shared libs? +guix_register_LDADD = \ + libstore.a libutil.a libformat.a -lbz2 \ + $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) + + libexec_PROGRAMS = nix-setuid-helper nix_setuid_helper_SOURCES = \ nix/nix-setuid-helper/nix-setuid-helper.cc diff --git a/nix/guix-register/guix-register.cc b/nix/guix-register/guix-register.cc new file mode 100644 index 0000000000..0a028f0cfe --- /dev/null +++ b/nix/guix-register/guix-register.cc @@ -0,0 +1,168 @@ +/* GNU Guix --- Functional package management for GNU + Copyright (C) 2013 Ludovic Courtès + Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, + 2013 Eelco Dolstra + + This file is part of GNU Guix. + + GNU Guix is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or (at + your option) any later version. + + GNU Guix is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Guix. If not, see . */ + +/* This file derives from the implementation of 'nix-store + --register-validity', by Eelco Dolstra, as found in the Nix package + manager's src/nix-store/nix-store.cc. */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include + +using namespace nix; + +/* Input stream where we read closure descriptions. */ +static std::istream *input = &std::cin; + + + +/* Command-line options. */ + +const char *argp_program_version = + "guix-register (" PACKAGE_NAME ") " PACKAGE_VERSION; +const char *argp_program_bug_address = PACKAGE_BUGREPORT; + +static char doc[] = +"guix-register -- register a closure as valid in a store\ +\v\ +This program is used internally when populating a store with data \ +from an existing store. It updates the new store's database with \ +information about which store files are valid, and what their \ +references are."; + +static const struct argp_option options[] = + { + { "prefix", 'p', "DIRECTORY", 0, + "Open the store that lies under DIRECTORY" }, + { 0, 0, 0, 0, 0 } + }; + +/* Parse a single option. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'p': + { + string prefix = canonPath (arg); + settings.nixStore = prefix + NIX_STORE_DIR; + settings.nixDataDir = prefix + NIX_DATA_DIR; + settings.nixLogDir = prefix + NIX_LOG_DIR; + settings.nixStateDir = prefix + NIX_STATE_DIR; + settings.nixDBPath = settings.nixStateDir + "/db"; + break; + } + + case ARGP_KEY_ARG: + { + std::ifstream *file; + + if (state->arg_num >= 2) + /* Too many arguments. */ + argp_usage (state); + + file = new std::ifstream (); + file->open (arg); + + input = file; + } + break; + + default: + return (error_t) ARGP_ERR_UNKNOWN; + } + + return (error_t) 0; +} + +/* Argument parsing. */ +static struct argp argp = { options, parse_opt, 0, doc }; + + +/* Read from INPUT the description of a closure, and register it as valid in + STORE. The expected format on INPUT is that used by #:references-graphs: + + FILE + DERIVER + NUMBER-OF-REFERENCES + REF1 + ... + REFN + + This is really meant as an internal format. */ +static void +register_validity (LocalStore *store, std::istream &input, + bool reregister = true, bool hashGiven = false, + bool canonicalise = true) +{ + ValidPathInfos infos; + + while (1) + { + ValidPathInfo info = decodeValidPathInfo (input, hashGiven); + if (info.path == "") + break; + if (!store->isValidPath (info.path) || reregister) + { + /* !!! races */ + if (canonicalise) + canonicalisePathMetaData (info.path, -1); + + if (!hashGiven) + { + HashResult hash = hashPath (htSHA256, info.path); + info.hash = hash.first; + info.narSize = hash.second; + } + infos.push_back (info); + } + } + + store->registerValidPaths (infos); +} + + +int +main (int argc, char *argv[]) +{ + try + { + argp_parse (&argp, argc, argv, 0, 0, 0); + + LocalStore store; + register_validity (&store, *input); + } + catch (std::exception &e) + { + fprintf (stderr, "error: %s\n", e.what ()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/test-env.in b/test-env.in index e6b13c271e..ed31f88141 100644 --- a/test-env.in +++ b/test-env.in @@ -69,5 +69,12 @@ then trap "kill $daemon_pid ; rm -rf $NIX_STATE_DIR" EXIT fi +storedir="@storedir@" +prefix="@prefix@" +datarootdir="@datarootdir@" +datadir="@datadir@" +localstatedir="@localstatedir@" +export storedir prefix datarootdir datadir localstatedir + "@abs_top_builddir@/pre-inst-env" "$@" exit $? diff --git a/tests/guix-register.sh b/tests/guix-register.sh new file mode 100644 index 0000000000..b76a1af54f --- /dev/null +++ b/tests/guix-register.sh @@ -0,0 +1,74 @@ +# GNU Guix --- Functional package management for GNU +# Copyright © 2013 Ludovic Courtès +# +# This file is part of GNU Guix. +# +# GNU Guix is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or (at +# your option) any later version. +# +# GNU Guix is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Guix. If not, see . + +# +# Test the 'guix-register' command-line utility. +# + +guix-register --version + +new_store="t-register-$$" +closure="t-register-closure-$$" +rm -rf "$new_store" + +exit_hook=":" +trap "chmod -R +w $new_store ; rm -rf $new_store $closure ; \$exit_hook" EXIT + +mkdir -p "$new_store/$storedir" +new_store_dir="`cd "$new_store/$storedir" ; pwd`" +new_store="`cd "$new_store" ; pwd`" + +to_copy="`guix build guile-bootstrap`" +cp -r "$to_copy" "$new_store_dir" +copied="$new_store_dir/`basename $to_copy`" + +# Create a file representing a closure with zero references, and with an empty +# "deriver" field. +cat >> "$closure" <