about summary refs log tree commit diff
path: root/pkgs/common-updater/generic-updater.nix
blob: 2f8da2f308e60cb1295b2aeedaacf995a2d0ced5 (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
{ lib
, stdenv
, common-updater-scripts
, coreutils
, gnugrep
, gnused
, nix
, writeScript
}:

{ name ? null
, pname ? null
, version ? null
, attrPath ? null
, versionLister
, ignoredVersions ? ""
, rev-prefix ? ""
, odd-unstable ? false
, patchlevel-unstable ? false
}:

let
  # where to print git commands and debugging messages
  fileForGitCommands = "update-git-commits.txt";

  grep = lib.getExe gnugrep;
  sed = lib.getExe gnused;

  # shell script to update package
  updateScript = writeScript "generic-update-script.sh" ''
    #! ${stdenv.shell}
    set -o errexit
    set -x

    name="$1"
    pname="$2"
    version="$3"
    attr_path="$4"
    version_lister="$5"
    ignored_versions="$6"
    rev_prefix="$7"
    odd_unstable="$8"
    patchlevel_unstable="$9"

    [[ -n "$name" ]] || name="$UPDATE_NIX_NAME"
    [[ -n "$pname" ]] || pname="$UPDATE_NIX_PNAME"
    [[ -n "$version" ]] || version="$UPDATE_NIX_OLD_VERSION"
    [[ -n "$attr_path" ]] || attr_path="$UPDATE_NIX_ATTR_PATH"

    # print header
    echo "# $name" >> ${fileForGitCommands}

    function version_is_ignored() {
      local tag="$1"
      [ -n "$ignored_versions" ] && ${grep} -E "$ignored_versions" <<< "$tag"
    }

    function version_is_unstable() {
      local tag="$1"
      local enforce="$2"
      if [ -n "$odd_unstable" -o -n "$enforce" ]; then
        local minor=$(echo "$tag" | ${sed} -rne 's,^[0-9]+\.([0-9]+).*,\1,p')
        if [ $((minor % 2)) -eq 1 ]; then
          return 0
        fi
      fi
      if [ -n "$patchlevel_unstable" -o -n "$enforce" ]; then
        local patchlevel=$(echo "$tag" | ${sed} -rne 's,^[0-9]+\.[0-9]+\.([0-9]+).*$,\1,p')
        if ((patchlevel >= 90)); then
          return 0
        fi
      fi
      return 1
    }

    tags=$(sh -c "$version_lister --pname=$pname --attr-path=$attr_path --file=\"${fileForGitCommands}\"") || exit 1

    # print available tags
    for tag in $tags; do
        echo "#	found $pname version: $tag" >> ${fileForGitCommands}
    done

    # cut any revision prefix not used in the NixOS package version
    if [ -n "$rev_prefix" ]; then
      tags=$(echo "$tags" | ${grep} "^$rev_prefix")
      tags=$(echo "$tags" | ${sed} -e "s,^$rev_prefix,,")
    fi
    tags=$(echo "$tags" | ${grep} "^[0-9]")

    # sort the tags in decreasing order
    tags=$(echo "$tags" | ${coreutils}/bin/sort --reverse --version-sort)

    # find the newest tag
    # do not consider development versions
    for latest_tag in $tags; do
      if version_is_ignored "$latest_tag"; then
        echo "#   skip ignored version: $pname-$latest_tag" >> ${fileForGitCommands}
        latest_tag=
      elif version_is_unstable "$latest_tag"; then
        echo "#   skip development version: $pname-$latest_tag" >> ${fileForGitCommands}
        latest_tag=
      else
        if version_is_unstable "$latest_tag" "enforce"; then
          echo "#   use potential development version: $pname-$latest_tag" >> ${fileForGitCommands}
        fi
        break
      fi
    done

    if [ -n "$latest_tag" ]; then
      # print commands to commit the changes
      if [ "$version" != "$latest_tag" ]; then
        pfile=$(EDITOR=echo ${nix}/bin/nix edit --extra-experimental-features nix-command -f. "$attr_path")
        echo "   git add $pfile " >> ${fileForGitCommands}
        echo "   git commit -m '$attr_path: $version -> $latest_tag'" >> ${fileForGitCommands}
      fi

      # update the nix expression
      ${common-updater-scripts}/bin/update-source-version --print-changes "$attr_path" "$latest_tag"
    else
      # No changes for commit protocol.
      echo "[]"
    fi

    echo "" >> ${fileForGitCommands}
  '';

in {
  name = "generic-update-script";
  command = [ updateScript name pname version attrPath versionLister ignoredVersions rev-prefix odd-unstable patchlevel-unstable ];
  supportedFeatures = [
    # Stdout must contain output according to the updateScript commit protocol when the update script finishes with a non-zero exit code.
    "commit"
  ];
}