summaryrefslogtreecommitdiffstats
path: root/pkgs/build-support/compress-drv/default.nix
blob: 97f72d4fa3965d212beab26e311bb406f8ec5bec (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
{ lib, runCommand }:
/**
  Compresses files of a given derivation, and returns a new derivation with
  compressed files

  # Inputs

  `formats` ([String])

  : List of file extensions to compress. Example: `["txt" "svg" "xml"]`.

  `extraFindOperands` (String)

  : Extra command line parameters to pass to the find command.
    This can be used to exclude certain files.
    For example: `-not -iregex ".*(\/apps\/.*\/l10n\/).*"`

  `compressors` ( { ${fileExtension} :: String })

  : Map a desired extension (e.g. `gz`) to a compress program.

    The compressor program that will be executed to get the `COMPRESSOR` extension.
    The program should have a single " {}", which will be the replaced with the
    target filename.

    Compressor must:

    - read symlinks (thus --force is needed to gzip, zstd, xz).
    - keep the original file in place (--keep).

  # Type

  ```
  compressDrv :: Derivation -> { formats :: [String]; compressors :: { ${fileExtension} :: String; } } -> Derivation
  ```

  # Examples
  :::{.example}
  ## `pkgs.compressDrv` usage example
  ```
  compressDrv pkgs.spdx-license-list-data.json {
    formats = ["json"];
    compressors = {
      gz = "${zopfli}/bin/zopfli --keep {}";
    };
  }
  =>
  «derivation /nix/store/...-spdx-license-list-data-3.24.0-compressed.drv»
  ```

  See also pkgs.compressDrvWeb, which is a wrapper on top of compressDrv, for broader usage
  examples.
  :::
*/
drv:
{
  formats,
  compressors,
  extraFindOperands ? "",
}:
let
  validProg =
    ext: prog:
    let
      matches = (builtins.length (builtins.split "\\{}" prog) - 1) / 2;
    in
    matches == 1 || throw "compressor ${ext} needs to have exactly one '{}', found ${toString matches}";
  mkCmd =
    ext: prog:
    assert validProg ext prog;
    ''
      find -L $out -type f -regextype posix-extended -iregex '.*\.(${formatsPipe})' ${extraFindOperands} -print0 \
        | xargs -0 -P$NIX_BUILD_CORES -I{} ${prog}
    '';
  formatsPipe = lib.concatStringsSep "|" formats;
in
runCommand "${drv.name}-compressed"
  (
    (lib.optionalAttrs (drv ? pname) { inherit (drv) pname; })
    // (lib.optionalAttrs (drv ? version) { inherit (drv) version; })
    // (lib.optionalAttrs (drv ? passthru) { inherit (drv) passthru; })
    // (lib.optionalAttrs (drv ? meta) { inherit (drv) meta; })
  )
  ''
    mkdir $out

    # cannot use lndir here, because it stop recursing at symlinks that point to directories
    (cd ${drv}; find -L -type d -exec mkdir -p $out/{} ';')
    (cd ${drv}; find -L -type f -exec ln -s ${drv}/{} $out/{} ';')

    ${lib.concatStringsSep "\n\n" (lib.mapAttrsToList mkCmd compressors)}
  ''