# This module generates the nixos-checkout script, which replaces the
# NixOS and Nixpkgs source trees in /etc/nixos/{nixos,nixpkgs} with
# Subversion checkouts.
{config, pkgs, ...}:
with pkgs.lib;
let
options = {
# !!! These option (and their implementation) seems
# over-engineering. nixos-checkout was never intended to be a
# generic, "check out anything that the user want to have from any
# version management system whatsoever", but merely a trivial
# convenience script to checkout the NixOS and Nixpkgs trees
# during or after a NixOS installation.
installer.repos.nixos = mkOption {
default = [ { type = "svn"; } ];
example =
[ { type = "svn"; url = "https://svn.nixos.org/repos/nix/nixos/branches/stdenv-updates"; target = "/etc/nixos/nixos-stdenv-updates"; }
{ type = "git"; initialize = ''git clone git://mawercer.de/nixos $target''; update = "git pull origin"; target = "/etc/nixos/nixos-git"; }
];
description = ''
The NixOS repository from which the system will be built.
nixos-checkout will update all working
copies of the given repositories,
nixos-rebuild will use the first item
which has the attribute default = true
falling back to the first item. The type defines the
repository tool added to the path. It also defines a "valid"
repository. If the target directory already exists and it's
not valid it will be moved to the backup location
dir-date.
For svn the default target and repositories are
/etc/nixos/nixos and
https://svn.nixos.org/repos/nix/nixos/trunk.
For git repositories update is called after initialization
when the repo is initialized. The initialize code is run
from working directory dirname
target and should create the
directory
dir. For
the executables used see .
'';
};
installer.repos.nixpkgs = mkOption {
default = [ { type = "svn"; } ];
description = "same as ";
};
installer.repoTypes = mkOption {
default = {
svn = { valid = "[ -d .svn ]"; env = [ pkgs.coreutils pkgs.subversion ]; };
git = { valid = "[ -d .git ]"; env = [ pkgs.coreutils pkgs.git pkgs.gnused /* FIXME: use full path to sed in nix-pull */ ]; };
gitsvn = { valid = "[ -d .git/svn ]"; env = [ pkgs.coreutils pkgs.gitFull pkgs.gnused ]; };
};
description = ''
Defines, for each supported version control system
(e.g. git), the dependencies for the
mechanism, as well as a test used to determine whether a
directory is a checkout created by that version control
system.
'';
};
};
### implementation
# prepareRepoAttrs adds svn defaults and preparse the repo attribute sets so that they
# returns in any case:
# { type = git/svn;
# target = path;
# initialize = cmd; # must create target dir, dirname target will exist
# update = cmd; # pwd will be target
# default = true/false;
# }
prepareRepoAttrs = repo : attrs :
assert (isAttrs attrs);
assert (repo + "" == repo); # assert repo is a string
if (! (attrs ? type)) then
throw "repo type is missing of : ${showVal attrs}"
# prepare svn repo
else if attrs.type == "svn" then
let a = { # add svn defaults
url = "https://svn.nixos.org/repos/nix/${repo}/trunk";
target = "/etc/nixos/${repo}";
} // attrs; in
rec {
inherit (a) type target;
default = if a ? default then a.default else false;
initialize = "svn co ${a.url} ${a.target}";
update = initialize; # co is just as fine as svn update
}
# prepare git repo
else if attrs.type == "git" then # sanity check for existing attrs
assert (all id (map ( attr : if hasAttr attr attrs then true
else throw "git repository item is missing attribute ${attr}")
[ "target" "initialize" "update" ]
));
let t = escapeShellArg attrs.target; in
rec {
inherit (attrs) type target;
default = if attrs ? default then attrs.default else false;
update = "cd ${t}; ${attrs.update}";
initialize = ''
cd $(dirname ${t}); ${attrs.initialize}
[ -d ${t} ] || { echo "git initialize failed to create target directory ${t}"; exit 1; }
${update}'';
}
else if attrs.type == "gitsvn" then # sanity check for existing attrs
let
a = {
# add gitsvn defaults
url = "https://svn.nixos.org/repos/nix/${repo}";
# XXX: same default target as svn: good/bad?
target = "/etc/nixos/${repo}";
initialize = "git svn clone -s ${a.url} ${a.target}";
# splitting this in fetch and rebase -l helps to recover partly cloned repo
update = "git svn fetch && git svn rebase -l";
} // attrs;
t = escapeShellArg a.target;
in
rec {
inherit (a) type target;
default = if a ? default then a.default else false;
update = "cd ${t} && ${a.update}";
initialize = ''
cd $(dirname ${t}) && ${a.initialize}
[ -d ${t} ] || { echo "gitsvn initialize failed to create target directory ${t}"; exit 1; }
${update}'';
}
else throw "unkown repo type ${attrs.type}";
# apply prepareRepoAttrs on each repo definition
repos = mapAttrs ( repo : list : map (x : (prepareRepoAttrs repo x) // { inherit repo; } ) list ) config.installer.repos;
# function returning the default repo (first one having attribute default or head of list)
defaultRepo = list : head ( (filter ( attrs : attrs ? default && attrs.default == true ) list)
++ list );
# creates the nixos-checkout script
nixosCheckout = pkgs.substituteAll {
name = "nixos-checkout";
dir = "bin";
isExecutable = true;
src = pkgs.writeScript "nixos-checkout" (''
#! @shell@ -e
# this file is automatically generated from nixos configuration file settings (installer.repos)
backupTimestamp=$(date "+%Y%m%d%H%M%S")
'' + concatMapStrings ( attrs :
let repoType = builtins.getAttr attrs.type config.installer.repoTypes;
target = escapeShellArg attrs.target; in
''
# ${attrs.type} repo ${target}
PATH=
for path in ${toString repoType.env}; do
PATH=$PATH:$path/bin:$path/sbin
done
if [ -d ${target} ] && { cd ${target} && { ${ repoType.valid}; }; }; then
echo; echo '>> ' updating ${attrs.type} repo ${target}
set -x; ${attrs.update}; set +x
else # [ make backup and ] initialize
[ -e ${target} ] && mv ${target} ${target}-$backupTimestamp
target=${target}
[ -d "$(dirname ${target})" ] || mkdir -p "$(dirname ${target})"
echo; echo '>> 'initializing ${attrs.type} repo ${target}
set -x; ${attrs.initialize}; set +x
fi
''
) # flatten all repo definition to one list adding the repository
( concatLists (flattenAttrs repos) )
);
};
in
{
require = options;
environment.systemPackages = [nixosCheckout];
}