implement racket packaging and environments
This commit is contained in:
parent
fc5b593038
commit
7245fe83e5
|
@ -0,0 +1,64 @@
|
|||
# nix support for racket
|
||||
|
||||
implements nix helpers for building racket packages and environments
|
||||
|
||||
this is a complete new implementation of this functionality. i did not use racket2nix because
|
||||
racket2nix is messy and hasn't been updated for a while. this is a significantly simpler
|
||||
implementation owning to better use of stdenv utilities and racket features
|
||||
|
||||
## how to use
|
||||
|
||||
### make nix packages for racket packages
|
||||
|
||||
```nix
|
||||
pkgs.racketPackages.callPackage (
|
||||
{
|
||||
lib,
|
||||
buildRacketPackage,
|
||||
fetchFromGitHub,
|
||||
}: buildRacketPackage {
|
||||
pname = "ansi-color";
|
||||
version = "0.2";
|
||||
|
||||
src = final.fetchFromGitHub {
|
||||
owner = "renatoathaydes";
|
||||
repo = "ansi-color";
|
||||
rev = "0.2";
|
||||
hash = "sha256-7WDW+4R9K+XLb9nMNGQlU+zAi2Gq7cUqzO3csN+AJvI=";
|
||||
};
|
||||
}
|
||||
) {}
|
||||
|
||||
```
|
||||
|
||||
### build a racket environment
|
||||
|
||||
unfortunately, due to racket limitations, `nix-shell`/`nix develop` will not work at all for racket
|
||||
packages that are created using this nix code. instead, similar to `python.buildEnv` /
|
||||
`python.withPackages`, you can create a racket environment with a given set of packages in it. this
|
||||
functions somewhat like a python "virtualenv" for racket. it is implemented by creating a "tethered
|
||||
installation" -- see <https://docs.racket-lang.org/raco/tethered-install.html>.
|
||||
|
||||
```nix
|
||||
with pkgs.racketPackages; makeRacketEnv {
|
||||
packages = [
|
||||
ansi-color
|
||||
];
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
the resulting environment will have a `bin/racket` executable which has the declared packages
|
||||
available
|
||||
|
||||
## future work
|
||||
|
||||
- automatically convert info.rkt into packaging. this should be doable for most of the catalog that
|
||||
is currently building on the CI, and perhaps some additional steps are needed for native library
|
||||
dependencies declared in info.rkt
|
||||
- allow using either racket or racket-minimal as a base (currently only racket non-minimal is
|
||||
supported)
|
||||
- instead of having 2 separate packages, rework racket to be a layered installation on top of
|
||||
racket-minimal, reducing duplication. this is similar to how guix does it
|
||||
- split outputs or have an option to not build the docs for every package, because it can take a
|
||||
while and results in 20+MB of additional disk space
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
lib,
|
||||
racket,
|
||||
racketInstallHook,
|
||||
stdenv,
|
||||
|
||||
wrapGAppsHook3,
|
||||
}: lib.extendMkDerivation {
|
||||
constructDrv = stdenv.mkDerivation;
|
||||
excludeDrvArgNames = [
|
||||
"dependencies"
|
||||
];
|
||||
extendDrvArgs = finalAttrs:
|
||||
{
|
||||
pname,
|
||||
version,
|
||||
nativeBuildInputs ? [],
|
||||
propagatedBuildInputs ? [],
|
||||
|
||||
dependencies ? [],
|
||||
|
||||
tetheredInstallation ? false,
|
||||
...
|
||||
} @ attrs: {
|
||||
name = "racket${racket.version}-" + pname + "-" + version;
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
racketTetheredInstallation = tetheredInstallation;
|
||||
|
||||
nativeBuildInputs = [
|
||||
racket
|
||||
racketInstallHook
|
||||
|
||||
wrapGAppsHook3
|
||||
] ++ nativeBuildInputs;
|
||||
|
||||
propagatedBuildInputs = [racket] ++ dependencies ++ propagatedBuildInputs;
|
||||
|
||||
dontWrapGApps = true;
|
||||
|
||||
preFixup = ''
|
||||
find $out/bin -type f -executable -print0 |
|
||||
while IFS= read -r -d ''' f; do
|
||||
if test "$(file --brief --mime-type "$f")" = application/x-executable; then
|
||||
wrapGApp "$f"
|
||||
fi
|
||||
done
|
||||
'';
|
||||
};
|
||||
}
|
84
flake.nix
84
flake.nix
|
@ -1,7 +1,85 @@
|
|||
{
|
||||
description = "A very basic flake";
|
||||
description = "Flake for racket packaging test";
|
||||
|
||||
outputs = { self, dragnpkgs } @ inputs: dragnpkgs.lib.mkFlake {
|
||||
packages.racket = ./racket/package.nix;
|
||||
outputs = { self, dragnpkgs } @ inputs: {
|
||||
legacyPackages.x86_64-linux = dragnpkgs.lib.dragnpkgs-custom {
|
||||
system = "x86_64-linux";
|
||||
overlays = [self.overlays.default];
|
||||
};
|
||||
|
||||
overlays.default = final: prev: {
|
||||
racket-minimal = final.callPackage ./racket/minimal.nix {};
|
||||
racket = final.callPackage ./racket/package.nix {};
|
||||
|
||||
racketPackages = final.lib.makeScope final.newScope (self: {
|
||||
racketInstallHook = self.callPackage ./racket-install-hook.nix {};
|
||||
buildRacketPackage = self.callPackage ./build-racket-package.nix {};
|
||||
|
||||
makeRacketEnv = self.callPackage ./make-racket-env.nix {};
|
||||
|
||||
testEnv = self.makeRacketEnv {
|
||||
packages = [self.ansi-color];
|
||||
};
|
||||
|
||||
ansi-color = self.callPackage (
|
||||
{
|
||||
lib,
|
||||
buildRacketPackage,
|
||||
fetchFromGitHub,
|
||||
}: buildRacketPackage {
|
||||
pname = "ansi-color";
|
||||
version = "0.2";
|
||||
|
||||
src = final.fetchFromGitHub {
|
||||
owner = "renatoathaydes";
|
||||
repo = "ansi-color";
|
||||
rev = "0.2";
|
||||
hash = "sha256-7WDW+4R9K+XLb9nMNGQlU+zAi2Gq7cUqzO3csN+AJvI=";
|
||||
};
|
||||
}
|
||||
) {};
|
||||
|
||||
namespaced-transformer-lib = self.callPackage (
|
||||
{
|
||||
lib,
|
||||
buildRacketPackage,
|
||||
fetchFromGitHub,
|
||||
}: buildRacketPackage {
|
||||
pname = "namespaced-transformer-lib";
|
||||
version = "none";
|
||||
|
||||
src = "${final.fetchFromGitHub {
|
||||
owner = "lexi-lambda";
|
||||
repo = "namespaced-transformer";
|
||||
rev = "4cdc1bdae09a07b78f23665267f2c7df4be5a7f6";
|
||||
hash = "sha256-vpDJ7qUNhKreig1LbU33d7TXXHkfd7gPxE1Fc5bvzFE=";
|
||||
}}/namespaced-transformer-lib";
|
||||
}
|
||||
) {};
|
||||
|
||||
curly-fn-lib = self.callPackage (
|
||||
{
|
||||
lib,
|
||||
buildRacketPackage,
|
||||
fetchFromGitHub,
|
||||
|
||||
namespaced-transformer-lib,
|
||||
}: buildRacketPackage {
|
||||
pname = "curly-fn-lib";
|
||||
version = "none";
|
||||
|
||||
dependencies = [ namespaced-transformer-lib ];
|
||||
|
||||
src = "${final.fetchFromGitHub {
|
||||
owner = "lexi-lambda";
|
||||
repo = "racket-curly-fn";
|
||||
rev = "d64cd71d5b386be85f5979edae6f6b6469a4df86";
|
||||
hash = "sha256-ge7o/UAvUXA4DIl03UkqVnLHNaPGq4SqxWvpcKdXndI=";
|
||||
}}/curly-fn-lib";
|
||||
}
|
||||
) {};
|
||||
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
lib,
|
||||
racket,
|
||||
buildRacketPackage,
|
||||
}: {
|
||||
packages,
|
||||
}: buildRacketPackage {
|
||||
pname = "env";
|
||||
version = "0";
|
||||
|
||||
unpackPhase = "touch nix-racket-env-only";
|
||||
|
||||
dependencies = packages;
|
||||
tetheredInstallation = true;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
racket,
|
||||
makeSetupHook,
|
||||
}: makeSetupHook {
|
||||
name = "racket-install-hook";
|
||||
propagatedBuildInputs = [ racket ];
|
||||
} ./racket-install-hook.sh
|
|
@ -0,0 +1,153 @@
|
|||
echo "Sourcing racket-install-hook"
|
||||
|
||||
addRacketPath() {
|
||||
if [ -f "$1/nix-support/racket-pkg" ]; then
|
||||
addToSearchPathWithCustomDelimiter : NIX_RACKET_PKG_PATH $1
|
||||
fi
|
||||
}
|
||||
|
||||
racketInstallPhase() {
|
||||
echo "Executing racketInstallPhase"
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/{include,etc/racket,lib/racket,share/racket/pkgs,share/racket/collects,bin,share/applications,share/doc/racket,share/man}
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
touch $out/nix-support/racket-pkg
|
||||
|
||||
out="$out" tethered="$racketTetheredInstallation" \
|
||||
racket --no-user-path -nl racket/base -f - <<EOF
|
||||
(require racket/function racket/hash racket/list racket/pretty racket/string racket/match)
|
||||
|
||||
(define out (getenv "out"))
|
||||
(define pkgs (path-list-string->path-list (or (getenv "NIX_RACKET_PKG_PATH") "") '()))
|
||||
|
||||
(define tethered? (equal? (getenv "tethered") "1"))
|
||||
|
||||
(define base-config (read-installation-configuration-table))
|
||||
|
||||
(define (add-to-search added-list search-list)
|
||||
(match search-list
|
||||
['() (error "no #f found in search list!")]
|
||||
[(cons #f rst) (cons #f (append added-list rst))]
|
||||
[(cons fst rst) (cons fst (add-to-search added-list rst))]))
|
||||
|
||||
(define (make-search-path* key list-key [pkgs-search '()])
|
||||
(define old-search-list (hash-ref base-config list-key '(#f)))
|
||||
(define old-value
|
||||
(cond
|
||||
[(hash-has-key? base-config key)
|
||||
(list (hash-ref base-config key))]
|
||||
[(eq? key 'links-file)
|
||||
(list
|
||||
(path->string
|
||||
(build-path (hash-ref base-config 'share-dir) "links.rktd")))]
|
||||
[else (error "no key" key)]))
|
||||
(define added-list (append pkgs-search old-value))
|
||||
(add-to-search added-list old-search-list))
|
||||
|
||||
(define (default-location pkg key)
|
||||
(path->string
|
||||
(match key
|
||||
['include-dir (build-path pkg "include")]
|
||||
['lib-dir (build-path pkg "lib/racket")]
|
||||
['share-dir (build-path pkg "share/racket")]
|
||||
['pkgs-dir (build-path pkg "share/racket/pkgs")]
|
||||
['links-file (build-path pkg "share/racket/links.rktd")]
|
||||
['bin-dir (build-path pkg "bin")]
|
||||
['doc-dir (build-path pkg "share/doc/racket")]
|
||||
['man-dir (build-path pkg "share/man")]
|
||||
[_ (error "unexpected key:" key)])))
|
||||
|
||||
(define (make-search-path key list-key)
|
||||
(define pkgs-search
|
||||
(for/list ([pkg (in-list pkgs)])
|
||||
(default-location pkg key)))
|
||||
|
||||
(make-search-path* key list-key pkgs-search))
|
||||
|
||||
(define (add-libs lib-path)
|
||||
(define ldflags (string-split (getenv "NIX_LDFLAGS")))
|
||||
(define libs
|
||||
(for/list ([lib (in-list ldflags)] #:when (string-prefix? "-L" lib))
|
||||
(string-trim "-L" #:right? #f)))
|
||||
(remove-duplicates (append libs lib-path)))
|
||||
|
||||
(define config*
|
||||
(hash
|
||||
'absolute-installation? #t
|
||||
'build-stamp ""
|
||||
'catalogs (hash-ref base-config 'catalogs)
|
||||
'compiled-file-roots (hash-ref base-config 'compiled-file-roots)
|
||||
|
||||
'apps-dir (path->string (build-path out "share/applications"))
|
||||
|
||||
'bin-dir (default-location out 'bin-dir)
|
||||
'bin-search-dirs (make-search-path 'bin-dir 'bin-search-dirs)
|
||||
|
||||
'doc-dir (default-location out 'doc-dir)
|
||||
'doc-search-dirs (make-search-path 'doc-dir 'doc-search-dirs)
|
||||
'doc-search-url (hash-ref base-config 'doc-search-url)
|
||||
|
||||
'include-dir (default-location out 'include-dir)
|
||||
'include-search-dirs (make-search-path 'include-dir 'include-search-dirs)
|
||||
|
||||
'lib-dir (default-location out 'lib-dir)
|
||||
'lib-search-dirs (add-libs (make-search-path 'lib-dir 'lib-search-dirs))
|
||||
|
||||
'links-file (default-location out 'links-file)
|
||||
'links-search-files (make-search-path 'links-file 'links-search-files)
|
||||
|
||||
'man-dir (default-location out 'man-dir)
|
||||
'man-search-dirs (make-search-path 'man-dir 'man-search-dirs)
|
||||
|
||||
'pkgs-dir (default-location out 'pkgs-dir)
|
||||
'pkgs-search-dirs (make-search-path 'pkgs-dir 'pkgs-search-dirs)
|
||||
|
||||
'share-dir (default-location out 'share-dir)
|
||||
'share-search-dirs (make-search-path 'share-dir 'share-search-dirs)))
|
||||
|
||||
(define config
|
||||
(if tethered?
|
||||
(hash-union
|
||||
config*
|
||||
(hash
|
||||
'config-tethered-console-bin-dir (hash-ref config* 'bin-dir)
|
||||
'config-tethered-gui-bin-dir (hash-ref config* 'bin-dir)
|
||||
'config-tethered-apps-dir (hash-ref config* 'apps-dir)))
|
||||
config*))
|
||||
|
||||
(with-output-to-file (build-path out "etc/racket/config.rktd")
|
||||
(curry pretty-write config))
|
||||
EOF
|
||||
|
||||
echo Initializing installation layer
|
||||
if [ "$racketTetheredInstallation" == "true" ]; then
|
||||
racket --config $out/etc/racket/ --no-user-path -l- \
|
||||
raco setup
|
||||
else
|
||||
racket --config $out/etc/racket/ --no-user-path -l- \
|
||||
raco setup --no-launcher
|
||||
|
||||
rm $out/bin/mzscheme # ????
|
||||
fi
|
||||
|
||||
if [ -f "nix-racket-env-only" ]; then
|
||||
echo Skipping raco pkg install
|
||||
else
|
||||
echo Running raco pkg install
|
||||
racket --config $out/etc/racket/ --no-user-path -l- \
|
||||
raco pkg install --installation --deps fail --copy --name "$pname" "$(readlink -e .)"
|
||||
fi
|
||||
|
||||
runHook postInstall
|
||||
echo "Finished executing racketInstallPhase"
|
||||
}
|
||||
|
||||
|
||||
if [ -z "${dontUseRacketInstall-}" ] && [ -z "${installPhase-}" ]; then
|
||||
echo "Adding racket env hook"
|
||||
addEnvHooks "$targetOffset" addRacketPath
|
||||
echo "Using racketInstallPhase"
|
||||
installPhase=racketInstallPhase
|
||||
fi
|
Loading…
Reference in New Issue