about summary refs log tree commit diff
path: root/nixpkgs/pkgs/development/compilers/crystal
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/development/compilers/crystal')
-rw-r--r--nixpkgs/pkgs/development/compilers/crystal/build-package.nix109
-rw-r--r--nixpkgs/pkgs/development/compilers/crystal/crystal2nix.cr42
-rw-r--r--nixpkgs/pkgs/development/compilers/crystal/crystal2nix.nix22
-rw-r--r--nixpkgs/pkgs/development/compilers/crystal/default.nix225
4 files changed, 398 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/development/compilers/crystal/build-package.nix b/nixpkgs/pkgs/development/compilers/crystal/build-package.nix
new file mode 100644
index 000000000000..856c6e58bc18
--- /dev/null
+++ b/nixpkgs/pkgs/development/compilers/crystal/build-package.nix
@@ -0,0 +1,109 @@
+{ stdenv, lib, crystal, shards, git, pkgconfig, which, linkFarm, fetchFromGitHub, installShellFiles }:
+
+{ # 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 = [ "--no-debug" ]; }
+, 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 = fetchFromGitHub value;
+  }) (import shardsFile));
+
+  # we previously had --no-debug here but that is not recommended by upstream
+  defaultOptions = [ "--release" "--progress" "--verbose" ];
+
+  buildDirectly = shardsFile == null || crystalBinaries != { };
+in stdenv.mkDerivation (mkDerivationArgs // {
+
+  configurePhase = args.configurePhase or lib.concatStringsSep "\n" ([
+    "runHook preConfigure"
+  ] ++ lib.optional (lockFile != null)   "ln -s ${lockFile} ./shard.lock"
+    ++ lib.optional (shardsFile != null) "ln -s ${crystalLib} lib"
+    ++ [ "runHook postConfigure "]);
+
+  CRFLAGS = lib.concatStringsSep " " defaultOptions;
+
+  PREFIX = placeholder "out";
+
+  buildInputs = args.buildInputs or [ ] ++ [ crystal ]
+    ++ lib.optional (format != "crystal") shards;
+
+  nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [ git installShellFiles pkgconfig which ];
+
+  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 " " 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
+  '') ++ [
+    "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
+    done
+  '';
+
+  meta = args.meta or { } // {
+    platforms = args.meta.platforms or crystal.meta.platforms;
+  };
+})
diff --git a/nixpkgs/pkgs/development/compilers/crystal/crystal2nix.cr b/nixpkgs/pkgs/development/compilers/crystal/crystal2nix.cr
new file mode 100644
index 000000000000..0610de5cfa4d
--- /dev/null
+++ b/nixpkgs/pkgs/development/compilers/crystal/crystal2nix.cr
@@ -0,0 +1,42 @@
+require "yaml"
+require "json"
+
+class PrefetchJSON
+  JSON.mapping(sha256: String)
+end
+
+class ShardLock
+  YAML.mapping(
+    version: Float32,
+    shards: Hash(String, Hash(String, String))
+  )
+end
+
+File.open "shards.nix", "w+" do |file|
+  file.puts %({)
+  yaml = ShardLock.from_yaml(File.read("shard.lock"))
+  yaml.shards.each do |key, value|
+    owner, repo = value["github"].split("/")
+    url = "https://github.com/#{value["github"]}"
+    rev = if value["version"]?
+            "v#{value["version"]}"
+          else
+            value["commit"]
+          end
+
+    sha256 = ""
+    args = ["--url", url, "--rev", rev]
+    Process.run("@nixPrefetchGit@", args: args) do |x|
+      x.error.each_line { |e| puts e }
+      sha256 = PrefetchJSON.from_json(x.output).sha256
+    end
+
+    file.puts %(  #{key} = {)
+    file.puts %(    owner = "#{owner}";)
+    file.puts %(    repo = "#{repo}";)
+    file.puts %(    rev = "#{rev}";)
+    file.puts %(    sha256 = "#{sha256}";)
+    file.puts %(  };)
+  end
+  file.puts %(})
+end
diff --git a/nixpkgs/pkgs/development/compilers/crystal/crystal2nix.nix b/nixpkgs/pkgs/development/compilers/crystal/crystal2nix.nix
new file mode 100644
index 000000000000..5fc40cd23741
--- /dev/null
+++ b/nixpkgs/pkgs/development/compilers/crystal/crystal2nix.nix
@@ -0,0 +1,22 @@
+{ lib, crystal, nix-prefetch-git }:
+
+crystal.buildCrystalPackage {
+  pname = "crystal2nix";
+  version = "unstable-2018-07-31";
+
+  nixPrefetchGit = "${lib.getBin nix-prefetch-git}/bin/nix-prefetch-git";
+  unpackPhase = "substituteAll ${./crystal2nix.cr} crystal2nix.cr";
+
+  format = "crystal";
+
+  crystalBinaries.crystal2nix.src = "crystal2nix.cr";
+
+  # it will blow up without a shard.yml file
+  doInstallCheck = false;
+
+  meta = with lib; {
+    description = "Utility to convert Crystal's shard.lock files to a Nix file";
+    license = licenses.mit;
+    maintainers = with maintainers; [ manveru ];
+  };
+}
diff --git a/nixpkgs/pkgs/development/compilers/crystal/default.nix b/nixpkgs/pkgs/development/compilers/crystal/default.nix
new file mode 100644
index 000000000000..a04d48dd0e5a
--- /dev/null
+++ b/nixpkgs/pkgs/development/compilers/crystal/default.nix
@@ -0,0 +1,225 @@
+{ stdenv, lib, fetchFromGitHub, fetchurl, makeWrapper
+, coreutils, git, gmp, hostname, openssl, readline, tzdata, libxml2, libyaml
+, boehmgc, libatomic_ops, pcre, libevent, libiconv, llvm, clang, which, zlib, pkgconfig
+, callPackage }:
+
+# We need multiple binaries as a given binary isn't always able to build
+# (even slightly) older or newer versions.
+# - 0.26.1 can build 0.25.x and 0.26.x but not 0.27.x
+# - 0.27.2 can build 0.27.x but not 0.25.x, 0.26.x and 0.29.x
+#
+# We need to keep around at least the latest version released with a stable
+# NixOS
+
+let
+  archs = {
+    x86_64-linux  = "linux-x86_64";
+    i686-linux    = "linux-i686";
+    x86_64-darwin = "darwin-x86_64";
+  };
+
+  arch = archs.${stdenv.system} or (throw "system ${stdenv.system} not supported");
+
+  checkInputs = [ git gmp openssl readline libxml2 libyaml ];
+
+  genericBinary = { version, sha256s, rel ? 1 }:
+  stdenv.mkDerivation rec {
+    pname = "crystal-binary";
+    inherit version;
+
+    src = fetchurl {
+      url = "https://github.com/crystal-lang/crystal/releases/download/${version}/crystal-${version}-${toString rel}-${arch}.tar.gz";
+      sha256 = sha256s.${stdenv.system};
+    };
+
+    buildCommand = ''
+      mkdir -p $out
+      tar --strip-components=1 -C $out -xf ${src}
+    '';
+  };
+
+  commonBuildInputs = extraBuildInputs: [
+    boehmgc libatomic_ops pcre libevent libyaml zlib libxml2 openssl
+  ] ++ extraBuildInputs
+    ++ stdenv.lib.optionals stdenv.isDarwin [ libiconv ];
+
+
+  generic = ({ version, sha256, binary, doCheck ? true, extraBuildInputs ? [] }:
+  lib.fix (compiler: stdenv.mkDerivation {
+    pname = "crystal";
+    inherit doCheck version;
+
+    src = fetchFromGitHub {
+      owner  = "crystal-lang";
+      repo   = "crystal";
+      rev    = version;
+      inherit sha256;
+    };
+
+    outputs = [ "out" "lib" "bin" ];
+
+    postPatch = ''
+      substituteInPlace src/crystal/system/unix/time.cr \
+        --replace /usr/share/zoneinfo ${tzdata}/share/zoneinfo
+
+      ln -sf spec/compiler spec/std
+
+      # Dirty fix for when no sandboxing is enabled
+      rm -rf /tmp/crystal
+      mkdir -p /tmp/crystal
+
+      substituteInPlace spec/std/file_spec.cr \
+        --replace '/bin/ls' '${coreutils}/bin/ls' \
+        --replace '/usr/share' '/tmp/crystal' \
+        --replace '/usr' '/tmp'
+
+      substituteInPlace spec/std/process_spec.cr \
+        --replace '/bin/cat' '${coreutils}/bin/cat' \
+        --replace '/bin/ls' '${coreutils}/bin/ls' \
+        --replace '/usr/bin/env' '${coreutils}/bin/env' \
+        --replace '"env"' '"${coreutils}/bin/env"' \
+        --replace '"/usr"' '"/tmp"'
+
+      substituteInPlace spec/std/socket/tcp_server_spec.cr \
+        --replace '{% if flag?(:gnu) %}"listen: "{% else %}"bind: "{% end %}' '"bind: "'
+
+      substituteInPlace spec/std/system_spec.cr \
+        --replace '`hostname`' '`${hostname}/bin/hostname`'
+
+      # See https://github.com/crystal-lang/crystal/pull/8640
+      substituteInPlace spec/std/http/cookie_spec.cr \
+        --replace '01 Jan 2020' '01 Jan #{Time.utc.year + 2}'
+
+      # See https://github.com/crystal-lang/crystal/issues/8629
+      substituteInPlace spec/std/socket/udp_socket_spec.cr \
+        --replace 'it "joins and transmits to multicast groups"' 'pending "joins and transmits to multicast groups"'
+
+      # See https://github.com/crystal-lang/crystal/pull/8699
+      substituteInPlace spec/std/xml/xml_spec.cr \
+        --replace 'it "handles errors"' 'pending "handles errors"'
+    '';
+
+    buildInputs = commonBuildInputs extraBuildInputs;
+
+    nativeBuildInputs = [ binary makeWrapper which pkgconfig llvm ];
+
+    makeFlags = [
+      "CRYSTAL_CONFIG_VERSION=${version}"
+    ];
+
+    buildFlags = [
+      "all" "docs"
+    ];
+
+    LLVM_CONFIG = "${llvm}/bin/llvm-config";
+
+    FLAGS = [
+      "--release"
+      "--single-module" # needed for deterministic builds
+    ];
+
+    # This makes sure we don't keep depending on the previous version of
+    # crystal used to build this one.
+    CRYSTAL_LIBRARY_PATH = "${placeholder "lib"}/crystal";
+
+    # We *have* to add `which` to the PATH or crystal is unable to build stuff
+    # later if which is not available.
+    installPhase = ''
+      runHook preInstall
+
+      install -Dm755 .build/crystal $bin/bin/crystal
+      wrapProgram $bin/bin/crystal \
+          --suffix PATH : ${lib.makeBinPath [ pkgconfig clang which ]} \
+          --suffix CRYSTAL_PATH : lib:$lib/crystal \
+          --suffix CRYSTAL_LIBRARY_PATH : ${
+            lib.makeLibraryPath (commonBuildInputs extraBuildInputs)
+          }
+      install -dm755 $lib/crystal
+      cp -r src/* $lib/crystal/
+
+      install -dm755 $out/share/doc/crystal/api
+      cp -r docs/* $out/share/doc/crystal/api/
+      cp -r samples $out/share/doc/crystal/
+
+      install -Dm644 etc/completion.bash $out/share/bash-completion/completions/crystal
+      install -Dm644 etc/completion.zsh $out/share/zsh/site-functions/_crystal
+
+      install -Dm644 man/crystal.1 $out/share/man/man1/crystal.1
+
+      install -Dm644 -t $out/share/licenses/crystal LICENSE README.md
+
+      mkdir -p $out
+      ln -s $bin/bin $out/bin
+      ln -s $lib $out/lib
+
+      runHook postInstall
+    '';
+
+    enableParallelBuilding = true;
+
+    dontStrip = true;
+
+    checkTarget = "spec";
+
+    preCheck = ''
+      export HOME=/tmp
+      mkdir -p $HOME/test
+
+      export LIBRARY_PATH=${lib.makeLibraryPath checkInputs}:$LIBRARY_PATH
+      export PATH=${lib.makeBinPath checkInputs}:$PATH
+    '';
+
+    passthru.buildCrystalPackage = callPackage ./build-package.nix {
+      crystal = compiler;
+    };
+
+    meta = with lib; {
+      description = "A compiled language with Ruby like syntax and type inference";
+      homepage = "https://crystal-lang.org/";
+      license = licenses.asl20;
+      maintainers = with maintainers; [ manveru david50407 peterhoeg ];
+      platforms = builtins.attrNames archs;
+    };
+  }));
+
+in rec {
+  binaryCrystal_0_31 = genericBinary {
+    version = "0.31.1";
+    sha256s = {
+      x86_64-linux  = "0r8salf572xrnr4m6ll9q5hz6jj8q7ff1rljlhmqb1r26a8mi2ih";
+      i686-linux    = "0hridnis5vvrswflx0q67xfg5hryhz6ivlwrb9n4pryj5d1gwjrr";
+      x86_64-darwin = "1dgxgv0s3swkc5cwawzgpbc6bcd2nx4hjxc7iw2h907y1vgmbipz";
+    };
+  };
+
+  crystal_0_31 = generic {
+    version = "0.31.1";
+    sha256  = "1dswxa32w16gnc6yjym12xj7ibg0g6zk3ngvl76lwdjqb1h6lwz8";
+    doCheck = false; # 5 checks are failing now
+    binary = binaryCrystal_0_31;
+  };
+
+  crystal_0_32 = generic {
+    version = "0.32.1";
+    sha256  = "120ndi3nhh2r52hjvhwfb49cdggr1bzdq6b8xg7irzavhjinfza6";
+    binary = binaryCrystal_0_31;
+  };
+
+  crystal_0_33 = generic {
+    version = "0.33.0";
+    sha256  = "1zg0qixcws81s083wrh54hp83ng2pa8iyyafaha55mzrh8293jbi";
+    binary = binaryCrystal_0_31;
+    doCheck = false; # 4 checks are failing now
+  };
+
+  crystal_0_34 = generic {
+    version = "0.34.0";
+    sha256  = "110lfpxk9jnqyznbfnilys65ixj5sdmy8pvvnlhqhc3ccvrlnmq4";
+    binary = crystal_0_33;
+    doCheck = false; # 4 checks are failing now
+  };
+
+  crystal = crystal_0_34;
+
+  crystal2nix = callPackage ./crystal2nix.nix {};
+}