summary refs log tree commit diff
path: root/pkgs/development/compilers/crystal/build-package.nix
blob: 215c3d37d88712d5fb4081c3c4c8a72a886a77e7 (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
{ stdenv
, lib
, crystal
, shards
, git
, pkg-config
, which
, linkFarm
, fetchgit
, fetchFromGitHub
, installShellFiles
, removeReferencesTo
}:

{
  # Some projects do not include a lock file, so you can pass one
  lockFile ? null
  # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root
, shardsFile ? null
  # We support different builders. To make things more straight forward, make it
  # user selectable instead of trying to autodetect
, format ? "make"
, installManPages ? true
  # Specify binaries to build in the form { foo.src = "src/foo.cr"; }
  # The default `crystal build` options can be overridden with { foo.options = [ "--optionname" ]; }
, crystalBinaries ? { }
, ...
}@args:

assert (builtins.elem format [ "make" "crystal" "shards" ]);
let
  mkDerivationArgs = builtins.removeAttrs args [
    "format"
    "installManPages"
    "lockFile"
    "shardsFile"
    "crystalBinaries"
  ];

  crystalLib = linkFarm "crystal-lib" (lib.mapAttrsToList
    (name: value: {
      inherit name;
      path =
        if (builtins.hasAttr "url" value)
        then fetchgit value
        else fetchFromGitHub value;
    })
    (import shardsFile));

  defaultOptions = [ "--release" "--progress" "--verbose" "--no-debug" ];

  buildDirectly = shardsFile == null || crystalBinaries != { };

in
stdenv.mkDerivation (mkDerivationArgs // {

  configurePhase = args.configurePhase or lib.concatStringsSep "\n"
    (
      [
        "runHook preConfigure"
      ]
      ++ lib.optional (lockFile != null) "cp ${lockFile} ./shard.lock"
      ++ lib.optionals (shardsFile != null) [
        "test -e lib || mkdir lib"
        "for d in ${crystalLib}/*; do ln -s $d lib/; done"
        "cp shard.lock lib/.shards.info"
      ]
      ++ [ "runHook postConfigure" ]
    );

  CRFLAGS = lib.concatStringsSep " " defaultOptions;

  PREFIX = placeholder "out";

  strictDeps = true;
  buildInputs = args.buildInputs or [ ] ++ [ crystal ];

  nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
    crystal
    git
    installShellFiles
    removeReferencesTo
    pkg-config
    which
  ] ++ lib.optional (format != "crystal") shards;

  buildPhase = args.buildPhase or (lib.concatStringsSep "\n" ([
    "runHook preBuild"
  ] ++ lib.optional (format == "make")
    "make \${buildTargets:-build} $makeFlags"
  ++ lib.optionals (format == "crystal") (lib.mapAttrsToList
    (bin: attrs: ''
      crystal ${lib.escapeShellArgs ([
        "build"
        "-o"
        bin
        (attrs.src or (throw "No source file for crystal binary ${bin} provided"))
      ] ++ (attrs.options or defaultOptions))}
    '')
    crystalBinaries)
  ++ lib.optional (format == "shards")
    "shards build --local --production ${lib.concatStringsSep " " (args.options or defaultOptions)}"
  ++ [ "runHook postBuild" ]));

  installPhase = args.installPhase or (lib.concatStringsSep "\n" ([
    "runHook preInstall"
  ] ++ lib.optional (format == "make")
    "make \${installTargets:-install} $installFlags"
  ++ lib.optionals (format == "crystal") (map
    (bin: ''
      install -Dm555 ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]}
    '')
    (lib.attrNames crystalBinaries))
  ++ lib.optional (format == "shards")
    "install -Dm555 bin/* -t $out/bin"
  ++ [
    ''
      for f in README* *.md LICENSE; do
        test -f $f && install -Dm444 $f -t $out/share/doc/${args.pname}
      done
    ''
  ] ++ (lib.optional installManPages ''
    if [ -d man ]; then
      installManPage man/*.?
    fi
  '') ++ [
    "remove-references-to -t ${lib.getLib crystal} $out/bin/*"
    "runHook postInstall"
  ]));

  doCheck = args.doCheck or true;

  checkPhase = args.checkPhase or (lib.concatStringsSep "\n" ([
    "runHook preCheck"
  ] ++ lib.optional (format == "make")
    "make \${checkTarget:-test} $checkFlags"
  ++ lib.optional (format != "make")
    "crystal \${checkTarget:-spec} $checkFlags"
  ++ [ "runHook postCheck" ]));

  doInstallCheck = args.doInstallCheck or true;

  installCheckPhase = args.installCheckPhase or ''
    for f in $out/bin/*; do
      $f --help > /dev/null
    done
  '';

  meta = args.meta or { } // {
    platforms = args.meta.platforms or crystal.meta.platforms;
  };
})