~ruther/guix-local

a7a4e6a4f719da8d0b26d9a60ff8ed42691d263f — Ludovic Courtès 12 years ago 996ed6a
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'.
6 files changed, 273 insertions(+), 0 deletions(-)

M .gitignore
M Makefile.am
M daemon.am
A nix/guix-register/guix-register.cc
M test-env.in
A tests/guix-register.sh
M .gitignore => .gitignore +1 -0
@@ 76,3 76,4 @@ stamp-h[0-9]
/nix/scripts/substitute-binary
/doc/images/bootstrap-graph.png
/doc/images/bootstrap-graph.eps
/guix-register

M Makefile.am => Makefile.am +7 -0
@@ 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

M daemon.am => daemon.am +16 -0
@@ 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

A nix/guix-register/guix-register.cc => nix/guix-register/guix-register.cc +168 -0
@@ 0,0 1,168 @@
/* GNU Guix --- Functional package management for GNU
   Copyright (C) 2013 Ludovic Courtès <ludo@gnu.org>
   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012,
     2013 Eelco Dolstra <eelco.dolstra@logicblox.com>

   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 <http://www.gnu.org/licenses/>.  */

/* 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 <config.h>

#include <globals.hh>
#include <local-store.hh>

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstdio>

#include <argp.h>

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;
}

M test-env.in => test-env.in +7 -0
@@ 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 $?

A tests/guix-register.sh => tests/guix-register.sh +74 -0
@@ 0,0 1,74 @@
# GNU Guix --- Functional package management for GNU
# Copyright © 2013 Ludovic Courtès <ludo@gnu.org>
#
# 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 <http://www.gnu.org/licenses/>.

#
# 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" <<EOF
$copied

0
EOF

# Register it.
guix-register -p "$new_store" < "$closure"

# Doing it a second time shouldn't hurt.
guix-register -p "$new_store" "$closure"

# Now make sure this is recognized as valid.

NIX_IGNORE_SYMLINK_STORE=1
NIX_STORE_DIR="$new_store_dir"
NIX_LOCALSTATE_DIR="$new_store$localstatedir"
NIX_LOG_DIR="$new_store$localstatedir/log/nix"
NIX_DB_DIR="$new_store$localstatedir/nix/db"

export NIX_IGNORE_SYMLINK_STORE NIX_STORE_DIR NIX_LOCALSTATE_DIR	\
  NIX_LOG_DIR NIX_DB_DIR

guix-daemon --disable-chroot &
subdaemon_pid=$!
exit_hook="kill $subdaemon_pid"

# At this point the copy in $new_store must be valid, and unreferenced.
guile -c "
   (use-modules (guix store))
   (define s (open-connection))
   (exit (and (valid-path? s \"$copied\")
              (equal? (list \"$copied\") (dead-paths s))))"