summary refs log tree commit diff
path: root/maintainers/scripts/update.nix
blob: bbc3004b1c4e8c79c2a4028ed7729afc289031c5 (plain) (blame)
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
{ package ? null
, maintainer ? null
, path ? null
, max-workers ? null
, keep-going ? null
}:

# TODO: add assert statements

let
  /* Remove duplicate elements from the list based on some extracted value. O(n^2) complexity.
   */
  nubOn = f: list:
    if list == [] then
      []
    else
      let
        x = pkgs.lib.head list;
        xs = pkgs.lib.filter (p: f x != f p) (pkgs.lib.drop 1 list);
      in
        [x] ++ nubOn f xs;

  pkgs = import ./../../default.nix {
    overlays = [];
  };

  packagesWith = cond: return: set:
    nubOn (pkg: pkg.updateScript)
      (pkgs.lib.flatten
        (pkgs.lib.mapAttrsToList
          (name: pkg:
            let
              result = builtins.tryEval (
                if pkgs.lib.isDerivation pkg && cond name pkg
                  then [(return name pkg)]
                else if pkg.recurseForDerivations or false || pkg.recurseForRelease or false
                  then packagesWith cond return pkg
                else []
              );
            in
              if result.success then result.value
              else []
          )
          set
        )
      );

  packagesWithUpdateScriptAndMaintainer = maintainer':
    let
      maintainer =
        if ! builtins.hasAttr maintainer' pkgs.lib.maintainers then
          builtins.throw "Maintainer with name `${maintainer'} does not exist in `maintainers/maintainer-list.nix`."
        else
          builtins.getAttr maintainer' pkgs.lib.maintainers;
    in
      packagesWith (name: pkg: builtins.hasAttr "updateScript" pkg &&
                                 (if builtins.hasAttr "maintainers" pkg.meta
                                   then (if builtins.isList pkg.meta.maintainers
                                           then builtins.elem maintainer pkg.meta.maintainers
                                           else maintainer == pkg.meta.maintainers
                                        )
                                   else false
                                 )
                   )
                   (name: pkg: pkg)
                   pkgs;

  packagesWithUpdateScript = path:
    let
      attrSet = pkgs.lib.attrByPath (pkgs.lib.splitString "." path) null pkgs;
    in
      if attrSet == null then
        builtins.throw "Attribute path `${path}` does not exists."
      else
        packagesWith (name: pkg: builtins.hasAttr "updateScript" pkg)
                       (name: pkg: pkg)
                       attrSet;

  packageByName = name:
    let
        package = pkgs.lib.attrByPath (pkgs.lib.splitString "." name) null pkgs;
    in
      if package == null then
        builtins.throw "Package with an attribute name `${name}` does not exists."
      else if ! builtins.hasAttr "updateScript" package then
        builtins.throw "Package with an attribute name `${name}` does not have a `passthru.updateScript` attribute defined."
      else
        package;

  packages =
    if package != null then
      [ (packageByName package) ]
    else if maintainer != null then
      packagesWithUpdateScriptAndMaintainer maintainer
    else if path != null then
      packagesWithUpdateScript path
    else
      builtins.throw "No arguments provided.\n\n${helpText}";

  helpText = ''
    Please run:

        % nix-shell maintainers/scripts/update.nix --argstr maintainer garbas

    to run all update scripts for all packages that lists \`garbas\` as a maintainer
    and have \`updateScript\` defined, or:

        % nix-shell maintainers/scripts/update.nix --argstr package gnome3.nautilus

    to run update script for specific package, or

        % nix-shell maintainers/scripts/update.nix --argstr path gnome3

    to run update script for all package under an attribute path.

    You can also add

        --argstr max-workers 8

    to increase the number of jobs in parallel, or

        --argstr keep-going true

    to continue running when a single update fails.
  '';

  packageData = package: {
    name = package.name;
    pname = pkgs.lib.getName package;
    updateScript = map builtins.toString (pkgs.lib.toList package.updateScript);
  };

  packagesJson = pkgs.writeText "packages.json" (builtins.toJSON (map packageData packages));

  optionalArgs =
    pkgs.lib.optional (max-workers != null) "--max-workers=${max-workers}"
    ++ pkgs.lib.optional (keep-going == "true") "--keep-going";

  args = [ packagesJson ] ++ optionalArgs;

in pkgs.stdenv.mkDerivation {
  name = "nixpkgs-update-script";
  buildCommand = ''
    echo ""
    echo "----------------------------------------------------------------"
    echo ""
    echo "Not possible to update packages using \`nix-build\`"
    echo ""
    echo "${helpText}"
    echo "----------------------------------------------------------------"
    exit 1
  '';
  shellHook = ''
    unset shellHook # do not contaminate nested shells
    exec ${pkgs.python3.interpreter} ${./update.py} ${builtins.concatStringsSep " " args}
  '';
}