summaryrefslogtreecommitdiff
path: root/nix/guix-register/guix-register.cc
blob: 8f9c3c86abd55ee231473fed0a6a4c8b247d23a6 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* 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 }
  };


/* Prefix of the store being populated.  */
static std::string prefix;

/* Parse a single option. */
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
  switch (key)
    {
    case 'p':
      {
	prefix = canonPath (arg);
	settings.nixStore = 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;

      /* Rewrite the input to refer final name, as if we were in a chroot
	 under PREFIX.  */
      std::string final_prefix (NIX_STORE_DIR "/");
      info.path = final_prefix + baseNameOf (info.path);

      /* Keep its real path to canonicalize it and compute its hash.  */
      std::string real_path;
      real_path = prefix + "/" + settings.nixStore + "/" + baseNameOf (info.path);

      if (!store->isValidPath (info.path) || reregister)
	{
	  /* !!! races */
	  if (canonicalise)
	    canonicalisePathMetaData (real_path, -1);

	  if (!hashGiven)
	    {
	      HashResult hash = hashPath (htSHA256, real_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;
}