mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-09-11 14:35:30 +03:00
Merge pull request #40 from DavHau/dev
Add tests; Improve: overrides, nodejs builder, output schema
This commit is contained in:
commit
f30b6759f4
43
checks.nix
Normal file
43
checks.nix
Normal file
@ -0,0 +1,43 @@
|
||||
{
|
||||
lib ? pkgs.lib,
|
||||
pkgs ? import <nixpkgs> {},
|
||||
dream2nix ? import ./src { inherit pkgs; },
|
||||
}:
|
||||
|
||||
let
|
||||
lib = pkgs.lib // builtins;
|
||||
|
||||
makeTest =
|
||||
{
|
||||
name,
|
||||
source,
|
||||
cmds,
|
||||
}:
|
||||
let
|
||||
outputs = dream2nix.riseAndShine {
|
||||
inherit source;
|
||||
};
|
||||
commandsToRun = cmds outputs;
|
||||
in
|
||||
pkgs.runCommand "test-${name}" {}
|
||||
(lib.concatStringsSep "\n" commandsToRun);
|
||||
|
||||
projects = {
|
||||
prettier = {
|
||||
source = lib.fetchTarball {
|
||||
url = "https://github.com/prettier/prettier/tarball/2.4.1";
|
||||
sha256 = "19b37qakhlsnr2n5bgv83aih5npgzbad1d2p2rs3zbq5syqbxdyi";
|
||||
};
|
||||
cmds = outputs: [
|
||||
"${outputs.defaultPackage}/bin/prettier --version | grep -q 2.4.1 && mkdir $out"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
allTests =
|
||||
lib.mapAttrs
|
||||
(name: args: makeTest (args // { inherit name; }))
|
||||
projects;
|
||||
|
||||
in
|
||||
allTests
|
@ -40,7 +40,7 @@ In case of a `pure` or `IFD` translator:
|
||||
|
||||
# optionally specify additional arguments that the user can provide to the
|
||||
# translator to customize its behavior
|
||||
specialArgs = ...;
|
||||
extraArgs = ...;
|
||||
}
|
||||
```
|
||||
|
||||
@ -53,7 +53,7 @@ In case of an `impure` translator:
|
||||
#
|
||||
# The first arg `$1` will be a json file containing the input parameters
|
||||
# like defined in /specifications/translator-call-example.json and the
|
||||
# additional arguments required according to specialArgs
|
||||
# additional arguments required according to extraArgs
|
||||
#
|
||||
# The program is expected to create a file at the location specified
|
||||
# by the input parameter `outFile`.
|
||||
@ -66,7 +66,7 @@ In case of an `impure` translator:
|
||||
|
||||
# optionally specify additional arguments that the user can provide to the
|
||||
# translator to customize its behavior
|
||||
specialArgs = ...;
|
||||
extraArgs = ...;
|
||||
}
|
||||
```
|
||||
|
||||
|
83
flake.nix
83
flake.nix
@ -14,7 +14,7 @@
|
||||
node2nix = { url = "github:svanderburg/node2nix"; flake = false; };
|
||||
};
|
||||
|
||||
outputs = { self, mach-nix, nix-parsec, nixpkgs, node2nix, }:
|
||||
outputs = { self, mach-nix, nix-parsec, nixpkgs, node2nix, }@inp:
|
||||
let
|
||||
|
||||
b = builtins;
|
||||
@ -28,40 +28,76 @@
|
||||
);
|
||||
|
||||
# To use dream2nix in non-flake + non-IFD enabled repos, the source code of dream2nix
|
||||
# must be installed into that repo (using nix run dream2nix#install).
|
||||
# The problem is, we also need to install all of dream2nix' dependecies as well.
|
||||
# Therefore 'externalSourcesFor' contains all relevant files of external projects we depend on.
|
||||
makeExternalSources = pkgs: pkgs.runCommand "dream2nix-external" {} ''
|
||||
mkdir -p $out/{mach-nix-lib,node2nix,nix-parsec}
|
||||
cp ${mach-nix}/{lib/extractor/{default.nix,distutils.patch,setuptools.patch},LICENSE} $out/mach-nix-lib/
|
||||
cp ${node2nix}/{nix/node-env.nix,LICENSE} $out/node2nix/
|
||||
cp ${nix-parsec}/{parsec,lexer}.nix $out/nix-parsec/
|
||||
'';
|
||||
# must be installed into these repos (using nix run dream2nix#install).
|
||||
# The problem is, all of dream2nix' dependecies need to be installed as well.
|
||||
# Therefore 'externalPaths' contains all relevant files of external projects
|
||||
# which dream2nix depends on. Exactly these files will be installed.
|
||||
externalPaths = {
|
||||
mach-nix = [
|
||||
"lib/extractor/default.nix"
|
||||
"lib/extractor/distutils.patch"
|
||||
"lib/extractor/setuptools.patch"
|
||||
"LICENSE"
|
||||
];
|
||||
node2nix = [
|
||||
"nix/node-env.nix"
|
||||
"LICENSE"
|
||||
];
|
||||
nix-parsec = [
|
||||
"parsec.nix"
|
||||
"lexer.nix"
|
||||
];
|
||||
};
|
||||
|
||||
externalSourcesFor = forAllSystems (system: makeExternalSources);
|
||||
# create a directory containing the files listed in externalPaths
|
||||
makeExternalDir = pkgs: pkgs.runCommand "dream2nix-external" {}
|
||||
(lib.concatStringsSep "\n"
|
||||
(lib.mapAttrsToList
|
||||
(inputName: paths:
|
||||
lib.concatStringsSep "\n"
|
||||
(lib.forEach
|
||||
paths
|
||||
(path: ''
|
||||
mkdir -p $out/${inputName}/$(dirname ${path})
|
||||
cp ${inp."${inputName}"}/${path} $out/${inputName}/${path}
|
||||
'')))
|
||||
externalPaths));
|
||||
|
||||
externalDirFor = forAllSystems (system: makeExternalDir);
|
||||
|
||||
# An interface to access files of external projects.
|
||||
# This implementation aceeses the flake inputs directly,
|
||||
# but if dream2nix is used without flakes, it defaults
|
||||
# to another implementation of that function which
|
||||
# uses the installed external paths instead (see default.nix)
|
||||
externalSources =
|
||||
lib.genAttrs
|
||||
(lib.attrNames externalPaths)
|
||||
(inputName: inp."${inputName}");
|
||||
|
||||
overridesDir = "${./overrides}";
|
||||
|
||||
# system specific dream2nix api
|
||||
dream2nixFor = forAllSystems (system: pkgs: import ./src rec {
|
||||
externalSources = externalSourcesFor."${system}";
|
||||
inherit pkgs;
|
||||
inherit lib;
|
||||
externalDir = externalDirFor."${system}";
|
||||
inherit externalSources lib overridesDir pkgs;
|
||||
});
|
||||
|
||||
in
|
||||
{
|
||||
# overlay with flakes enabled nix
|
||||
# (all of dream2nix cli dependends on nix ^2.4)
|
||||
overlay = new: old: {
|
||||
nix = old.writeScriptBin "nix" ''
|
||||
${new.nixUnstable}/bin/nix --option experimental-features "nix-command flakes" "$@"
|
||||
overlay = final: prev: {
|
||||
nix = prev.writeScriptBin "nix" ''
|
||||
${final.nixUnstable}/bin/nix --option experimental-features "nix-command flakes" "$@"
|
||||
'';
|
||||
};
|
||||
|
||||
# System independent dream2nix api.
|
||||
# Similar to drem2nixFor but will require 'system(s)' or 'pkgs' as an argument.
|
||||
# Produces flake-like output schema.
|
||||
lib.dream2nix = import ./src/lib.nix {
|
||||
inherit makeExternalSources lib;
|
||||
lib = import ./src/lib.nix {
|
||||
inherit externalSources overridesDir lib;
|
||||
nixpkgsSrc = "${nixpkgs}";
|
||||
};
|
||||
|
||||
@ -91,12 +127,17 @@
|
||||
|
||||
shellHook = ''
|
||||
export NIX_PATH=nixpkgs=${nixpkgs}
|
||||
export d2nExternalSources=${externalSourcesFor."${system}"}
|
||||
export d2nExternalDir=${externalDirFor."${system}"}
|
||||
export dream2nixWithExternals=${dream2nixFor."${system}".dream2nixWithExternals}
|
||||
export d2nExternalSources=$dream2nixWithExternals/external
|
||||
export d2nOverridesDir=${./overrides}
|
||||
|
||||
echo "\nManually execute 'export dream2nixWithExternals={path to your dream2nix checkout}'"
|
||||
'';
|
||||
});
|
||||
|
||||
checks = forAllSystems (system: pkgs: import ./checks.nix {
|
||||
inherit lib pkgs;
|
||||
dream2nix = dream2nixFor."${system}";
|
||||
});
|
||||
};
|
||||
}
|
||||
|
75
overrides/nodejs/default.nix
Normal file
75
overrides/nodejs/default.nix
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
}:
|
||||
|
||||
let
|
||||
b = builtins;
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
gifsicle = {
|
||||
add-binary = {
|
||||
installScript = ''
|
||||
ln -s ${pkgs.gifsicle}/bin/gifsicle ./vendor/gifsicle
|
||||
npm run postinstall
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
mozjpeg = {
|
||||
add-binary = {
|
||||
installScript = ''
|
||||
ln -s ${pkgs.mozjpeg}/bin/cjpeg ./vendor/cjpeg
|
||||
npm run postinstall
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
optipng-bin = {
|
||||
add-binary = {
|
||||
installScript = ''
|
||||
ln -s ${pkgs.optipng}/bin/optipng ./vendor/optipng
|
||||
npm run postinstall
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
pngquant-bin = {
|
||||
add-binary = {
|
||||
installScript = ''
|
||||
ln -s ${pkgs.pngquant}/bin/pngquant ./vendor/pngquant
|
||||
npm run postinstall
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
webpack = {
|
||||
remove-webpack-cli-check = {
|
||||
_condition = pkg: pkg.version == "5.41.1";
|
||||
ignoreScripts = false;
|
||||
patches = [
|
||||
./webpack/remove-webpack-cli-check.patch
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
webpack-cli = {
|
||||
remove-webpack-check = {
|
||||
_condition = pkg: pkg.version == "4.7.2";
|
||||
ignoreScripts = false;
|
||||
patches = [
|
||||
./webpack-cli/remove-webpack-check.patch
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
"@mattermost/webapp" = {
|
||||
run-webpack = {
|
||||
installScript = ''
|
||||
NODE_ENV=production node --max-old-space-size=8192 ./node_modules/webpack/bin/webpack.js
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
12
overrides/nodejs/webpack-cli/remove-webpack-check.patch
Normal file
12
overrides/nodejs/webpack-cli/remove-webpack-check.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/packages/webpack-cli/bin/cli.js b/packages/webpack-cli/bin/cli.js
|
||||
--- a/bin/cli.js
|
||||
+++ b/bin/cli.js
|
||||
@@ -21,7 +21,7 @@ if (!process.env.WEBPACK_CLI_SKIP_IMPORT_LOCAL) {
|
||||
|
||||
process.title = "webpack";
|
||||
|
||||
-if (utils.packageExists("webpack")) {
|
||||
+if (true) {
|
||||
runCLI(process.argv, originalModuleCompile);
|
||||
} else {
|
||||
const { promptInstallation, logger, colors } = utils;
|
12
overrides/nodejs/webpack/remove-webpack-cli-check.patch
Normal file
12
overrides/nodejs/webpack/remove-webpack-cli-check.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff --git a/bin/webpack.js b/bin/webpack.js
|
||||
--- a/bin/webpack.js
|
||||
+++ b/bin/webpack.js
|
||||
@@ -87,7 +87,7 @@ const cli = {
|
||||
url: "https://github.com/webpack/webpack-cli"
|
||||
};
|
||||
|
||||
-if (!cli.installed) {
|
||||
+if (false) {
|
||||
const path = require("path");
|
||||
const fs = require("graceful-fs");
|
||||
const readLine = require("readline");
|
@ -9,7 +9,7 @@ import networkx as nx
|
||||
from cleo import Command, option
|
||||
|
||||
from utils import dream2nix_src, checkLockJSON, callNixFunction, buildNixFunction, buildNixAttribute, \
|
||||
list_translators_for_source, order_dict, strip_hashes_from_lock
|
||||
list_translators_for_source, sort_dict, strip_hashes_from_lock
|
||||
|
||||
|
||||
class PackageCommand(Command):
|
||||
@ -164,7 +164,7 @@ class PackageCommand(Command):
|
||||
exit(1)
|
||||
|
||||
# raise error if any specified extra arg is unknown
|
||||
unknown_extra_args = set(specified_extra_args.keys()) - set(translator['specialArgs'].keys())
|
||||
unknown_extra_args = set(specified_extra_args.keys()) - set(translator['extraArgs'].keys())
|
||||
if unknown_extra_args:
|
||||
print(
|
||||
f"Invalid extra args for translator '{translator['name']}': "
|
||||
@ -176,7 +176,7 @@ class PackageCommand(Command):
|
||||
|
||||
# transform flags to bool
|
||||
for argName, argVal in specified_extra_args.copy().items():
|
||||
if translator['specialArgs'][argName]['type'] == 'flag':
|
||||
if translator['extraArgs'][argName]['type'] == 'flag':
|
||||
if argVal.lower() in ('yes', 'y', 'true'):
|
||||
specified_extra_args[argName] = True
|
||||
elif argVal.lower() in ('no', 'n', 'false'):
|
||||
@ -188,18 +188,18 @@ class PackageCommand(Command):
|
||||
)
|
||||
|
||||
specified_extra_args =\
|
||||
{k: (bool(v) if translator['specialArgs'][k]['type'] == 'flag' else v ) \
|
||||
{k: (bool(v) if translator['extraArgs'][k]['type'] == 'flag' else v ) \
|
||||
for k, v in specified_extra_args.items()}
|
||||
|
||||
# on non-interactive session, assume defaults for unspecified extra args
|
||||
if not self.io.is_interactive():
|
||||
specified_extra_args.update(
|
||||
{n: (True if v['type'] == 'flag' else v['default']) \
|
||||
for n, v in translator['specialArgs'].items() \
|
||||
for n, v in translator['extraArgs'].items() \
|
||||
if n not in specified_extra_args and 'default' in v}
|
||||
)
|
||||
unspecified_extra_args = \
|
||||
{n: v for n, v in translator['specialArgs'].items() \
|
||||
{n: v for n, v in translator['extraArgs'].items() \
|
||||
if n not in specified_extra_args}
|
||||
# raise error if any extra arg unspecified in non-interactive session
|
||||
if unspecified_extra_args:
|
||||
@ -310,18 +310,18 @@ class PackageCommand(Command):
|
||||
removed_edges.append((node_from, node_to))
|
||||
except nx.NetworkXNoCycle:
|
||||
continue
|
||||
lock['generic']['dependenciesRemoved'] = {}
|
||||
lock['generic']['cyclicDependencies'] = {}
|
||||
if removed_edges:
|
||||
lock['generic']['dependenciesRemoved'] = {}
|
||||
lock['generic']['cyclicDependencies'] = {}
|
||||
removed_cycles_text = 'Removed Cyclic dependencies:'
|
||||
for node, removed_node in removed_edges:
|
||||
removed_cycles_text += f"\n {node} -> {removed_node}"
|
||||
n_name, n_ver = node.split('#')
|
||||
if n_name not in lock['generic']['dependenciesRemoved']:
|
||||
lock['generic']['dependenciesRemoved'][n_name] = {}
|
||||
if n_ver not in lock['generic']['dependenciesRemoved'][n_name]:
|
||||
lock['generic']['dependenciesRemoved'][n_name][n_ver] = []
|
||||
lock['generic']['dependenciesRemoved'][n_name][n_ver].append(removed_node)
|
||||
if n_name not in lock['generic']['cyclicDependencies']:
|
||||
lock['generic']['cyclicDependencies'][n_name] = {}
|
||||
if n_ver not in lock['generic']['cyclicDependencies'][n_name]:
|
||||
lock['generic']['cyclicDependencies'][n_name][n_ver] = []
|
||||
lock['generic']['cyclicDependencies'][n_name][n_ver].append(removed_node)
|
||||
print(removed_cycles_text)
|
||||
|
||||
# calculate combined hash if --combined was specified
|
||||
@ -357,9 +357,9 @@ class PackageCommand(Command):
|
||||
lock['generic']['sourcesCombinedHash'] = hash
|
||||
|
||||
# re-write dream.lock
|
||||
checkLockJSON(order_dict(lock))
|
||||
checkLockJSON(sort_dict(lock))
|
||||
with open(outputDreamLock, 'w') as f:
|
||||
json.dump(order_dict(lock), f, indent=2)
|
||||
json.dump(sort_dict(lock), f, indent=2)
|
||||
|
||||
# create default.nix
|
||||
template = callNixFunction(
|
||||
|
@ -1,7 +1,6 @@
|
||||
{
|
||||
# from dream2nix
|
||||
dream2nixWithExternals,
|
||||
externalSources,
|
||||
fetchers,
|
||||
translators,
|
||||
|
||||
|
@ -106,8 +106,8 @@ def list_translators_for_source(sourcePath):
|
||||
return list(sorted(translatorsList, key=lambda t: t['compatible']))
|
||||
|
||||
|
||||
def order_dict(d):
|
||||
return {k: order_dict(v) if isinstance(v, dict) else v
|
||||
def sort_dict(d):
|
||||
return {k: sort_dict(v) if isinstance(v, dict) else v
|
||||
for k, v in sorted(d.items())}
|
||||
|
||||
def strip_hashes_from_lock(lock):
|
||||
|
@ -2,8 +2,6 @@
|
||||
pkgs,
|
||||
|
||||
callPackageDream,
|
||||
externalSources,
|
||||
dream2nixWithExternals,
|
||||
translators,
|
||||
...
|
||||
}:
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
# attributes
|
||||
buildSystemAttrs,
|
||||
dependenciesRemoved,
|
||||
cyclicDependencies,
|
||||
mainPackageName,
|
||||
mainPackageVersion,
|
||||
packageVersions,
|
||||
@ -40,11 +40,10 @@ let
|
||||
|
||||
b = builtins;
|
||||
|
||||
# tells if a dependency introduces a cycle
|
||||
# -> needs to be built in a combined derivation
|
||||
isCyclic = name: version:
|
||||
b.elem name standalonePackageNames
|
||||
||
|
||||
(dependenciesRemoved ? "${name}"
|
||||
&& dependenciesRemoved."${name}" ? "${version}");
|
||||
cyclicDependencies ? "${name}"."${version}";
|
||||
|
||||
mainPackageKey =
|
||||
"${mainPackageName}#${mainPackageVersion}";
|
||||
@ -68,7 +67,8 @@ let
|
||||
lib.genAttrs
|
||||
versions
|
||||
(version:
|
||||
if isCyclic name version then
|
||||
if isCyclic name version
|
||||
|| b.elem name standalonePackageNames then
|
||||
makeCombinedPackage name version
|
||||
else
|
||||
makePackage name version))
|
||||
@ -81,14 +81,15 @@ let
|
||||
inherit name version;
|
||||
builder = builders.nodejs.node2nix;
|
||||
inject =
|
||||
lib.optionalAttrs (dependenciesRemoved ? "${name}"."${version}") {
|
||||
lib.optionalAttrs (cyclicDependencies ? "${name}"."${version}") {
|
||||
"${name}"."${version}" =
|
||||
dependenciesRemoved."${name}"."${version}";
|
||||
cyclicDependencies."${name}"."${version}";
|
||||
};
|
||||
};
|
||||
in
|
||||
built.package;
|
||||
built.defaultPackage;
|
||||
|
||||
# Generates a derivation for a specific package name + version
|
||||
makePackage = name: version:
|
||||
let
|
||||
|
||||
@ -118,34 +119,37 @@ let
|
||||
|
||||
buildInputs = [ jq nodejs nodejs.python ];
|
||||
|
||||
# prevents running into ulimits
|
||||
passAsFile = [ "dependenciesJson" "nodeDeps" ];
|
||||
|
||||
ignoreScripts = true;
|
||||
preBuildPhases = [ "d2nPatchPhase" "d2nInstallDependenciesPhase" ];
|
||||
|
||||
dontUnpack = true;
|
||||
preFixupPhases = [ "d2nPostInstallPhase" ];
|
||||
|
||||
# not used by default but can be enabled if needed
|
||||
dontConfigure = true;
|
||||
dontBuild = true;
|
||||
|
||||
dontNpmInstall = false;
|
||||
|
||||
# can be overridden to define alternative install command
|
||||
# (defaults to 'npm run postinstall')
|
||||
installScript = null;
|
||||
|
||||
# python script to modify some metadata to support installation
|
||||
# (see comments below on d2nPatchPhase)
|
||||
fixPackage = "${./fix-package.py}";
|
||||
|
||||
# costs performance and doesn't seem beneficial in most scenarios
|
||||
dontStrip = true;
|
||||
|
||||
|
||||
# not using the default unpackPhase,
|
||||
# as it fails setting the permissions sometimes
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
# The default unpackPhase seemed to fail on setting permissions
|
||||
# for some packages.
|
||||
# TODO: debug nixpkgs unpackPhase and upstream improvement.
|
||||
unpackPhase = ''
|
||||
runHook preUnpack
|
||||
|
||||
nodeModules=$out/lib/node_modules
|
||||
|
||||
mkdir -p $nodeModules
|
||||
|
||||
cd $TMPDIR
|
||||
export sourceRoot="$nodeModules/$packageName"
|
||||
|
||||
unpackFile $src
|
||||
|
||||
@ -156,30 +160,68 @@ let
|
||||
if [ -f "$src" ]
|
||||
then
|
||||
# Figure out what directory has been unpacked
|
||||
packageDir="$(find . -maxdepth 1 -type d | tail -1)"
|
||||
export packageDir="$(find . -maxdepth 1 -type d | tail -1)"
|
||||
|
||||
# Restore write permissions
|
||||
find "$packageDir" -type d -exec chmod u+x {} \;
|
||||
chmod -R u+w "$packageDir"
|
||||
|
||||
# Move the extracted tarball into the output folder
|
||||
mv "$packageDir" "$nodeModules/$packageName"
|
||||
mv "$packageDir" "$sourceRoot"
|
||||
elif [ -d "$src" ]
|
||||
then
|
||||
strippedName="$(stripHash $src)"
|
||||
export strippedName="$(stripHash $src)"
|
||||
|
||||
# Restore write permissions
|
||||
chmod -R u+w "$strippedName"
|
||||
|
||||
# Move the extracted directory into the output folder
|
||||
mv "$strippedName" "$nodeModules/$packageName"
|
||||
mv "$strippedName" "$sourceRoot"
|
||||
fi
|
||||
|
||||
runHook postUnpack
|
||||
'';
|
||||
|
||||
# The python script wich is executed in this phase:
|
||||
# - ensures that the package is compatible to the current system
|
||||
# - ensures the main version in package.json matches the expected
|
||||
# - deletes "devDependencies" and "peerDependencies" from package.json
|
||||
# (might block npm install in case npm install is used)
|
||||
# - pins dependency versions in package.json
|
||||
# - creates symlinks for executables declared in package.json
|
||||
# Apart from that:
|
||||
# - Any usage of 'link:' in package.json is replaced with 'file:'
|
||||
# - If package-lock.json exists, it is deleted, as it might conflict
|
||||
# with the parent package-lock.json.
|
||||
d2nPatchPhase = ''
|
||||
# delete package-lock.json as it can lead to conflicts
|
||||
rm -f package-lock.json
|
||||
|
||||
# repair 'link:' -> 'file:'
|
||||
mv $nodeModules/$packageName/package.json $nodeModules/$packageName/package.json.old
|
||||
cat $nodeModules/$packageName/package.json.old | sed 's!link:!file\:!g' > $nodeModules/$packageName/package.json
|
||||
rm $nodeModules/$packageName/package.json.old
|
||||
|
||||
# run python script (see commend above):
|
||||
cp package.json package.json.bak
|
||||
python $fixPackage \
|
||||
|| \
|
||||
# exit code 3 -> the package is incompatible to the current platform
|
||||
# -> Let the build succeed, but don't create lib/node_packages
|
||||
if [ "$?" == "3" ]; then
|
||||
rm -r $out/*
|
||||
echo "Not compatible with system $system" > $out/error
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
|
||||
# - links all direct node dependencies into the node_modules directory
|
||||
# - adds executables of direct node dependencies to PATH
|
||||
# - adds the current node module to NODE_PATH
|
||||
# - sets HOME=$TMPDIR, as this is required by some npm scripts
|
||||
d2nInstallDependenciesPhase = ''
|
||||
# symlink dependency packages into node_modules
|
||||
for dep in $(cat $nodeDepsPath); do
|
||||
# add bin to PATH
|
||||
@ -192,12 +234,12 @@ let
|
||||
if [[ $module == @* ]]; then
|
||||
for submodule in $(ls $dep/lib/node_modules/$module); do
|
||||
mkdir -p $nodeModules/$packageName/node_modules/$module
|
||||
echo "ln -s $dep/lib/node_modules/$module/$submodule $nodeModules/$packageName/node_modules/$module/$submodule"
|
||||
echo -e "creating link: $dep/lib/node_modules/$module/$submodule\n -> $nodeModules/$packageName/node_modules/$module/$submodule"
|
||||
ln -s $dep/lib/node_modules/$module/$submodule $nodeModules/$packageName/node_modules/$module/$submodule
|
||||
done
|
||||
else
|
||||
mkdir -p $nodeModules/$packageName/node_modules/
|
||||
echo "ln -s $dep/lib/node_modules/$module $nodeModules/$packageName/node_modules/$module"
|
||||
echo -e "creating link: $dep/lib/node_modules/$module\n -> $nodeModules/$packageName/node_modules/$module"
|
||||
ln -s $dep/lib/node_modules/$module $nodeModules/$packageName/node_modules/$module
|
||||
fi
|
||||
done
|
||||
@ -206,39 +248,30 @@ let
|
||||
|
||||
export NODE_PATH="$NODE_PATH:$nodeModules/$packageName/node_modules"
|
||||
|
||||
cd "$nodeModules/$packageName"
|
||||
|
||||
export HOME=$TMPDIR
|
||||
'';
|
||||
|
||||
# delete package-lock.json as it can lead to conflicts
|
||||
rm -f package-lock.json
|
||||
# Run the install command which defaults to 'npm run postinstall'.
|
||||
# Set alternative install command by overriding 'installScript'.
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
|
||||
# pin dependency versions in package.json
|
||||
cp package.json package.json.bak
|
||||
python $fixPackage \
|
||||
|| \
|
||||
# exit code 3 -> the package is incompatible to the current platform
|
||||
if [ "$?" == "3" ]; then
|
||||
rm -r $out/*
|
||||
echo "Not compatible with system $system" > $out/error
|
||||
exit 0
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# execute installation command
|
||||
# execute install command
|
||||
if [ -n "$installScript" ]; then
|
||||
if [ -f "$installScript" ]; then
|
||||
exec $installScript
|
||||
else
|
||||
echo "$installScript" | bash
|
||||
fi
|
||||
elif [ -z "$dontNpmInstall" ]; then
|
||||
if [ "$(jq '.scripts.postinstall' ./package.json)" != "null" ]; then
|
||||
npm --production --offline --nodedir=$nodeSources run postinstall
|
||||
fi
|
||||
elif [ "$(jq '.scripts.postinstall' ./package.json)" != "null" ]; then
|
||||
npm --production --offline --nodedir=$nodeSources run postinstall
|
||||
fi
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
|
||||
# Symlinks executables and manual pages to correct directories
|
||||
d2nPostInstallPhase = ''
|
||||
# Create symlink to the deployed executable folder, if applicable
|
||||
if [ -d "$nodeModules/.bin" ]
|
||||
then
|
||||
@ -249,21 +282,20 @@ let
|
||||
# Create symlinks to the deployed manual page folders, if applicable
|
||||
if [ -d "$nodeModules/$packageName/man" ]
|
||||
then
|
||||
mkdir -p $out/share
|
||||
for dir in "$nodeModules/$packageName/man/"*
|
||||
mkdir -p $out/share
|
||||
for dir in "$nodeModules/$packageName/man/"*
|
||||
do
|
||||
mkdir -p $out/share/man/$(basename "$dir")
|
||||
for page in "$dir"/*
|
||||
do
|
||||
mkdir -p $out/share/man/$(basename "$dir")
|
||||
for page in "$dir"/*
|
||||
do
|
||||
ln -s $page $out/share/man/$(basename "$dir")
|
||||
done
|
||||
ln -s $page $out/share/man/$(basename "$dir")
|
||||
done
|
||||
done
|
||||
fi
|
||||
|
||||
runHook postInstall
|
||||
'';
|
||||
};
|
||||
in
|
||||
# apply packageOverrides to current derivation
|
||||
(utils.applyOverridesToPackage packageOverrides pkg name);
|
||||
|
||||
|
||||
|
@ -29,7 +29,9 @@ if 'os' in package_json:
|
||||
version = os.environ.get("version")
|
||||
if package_json['version'] != version:
|
||||
print(
|
||||
"WARNING: Replacing version in package.json: "
|
||||
"WARNING: The version of this package defined by its package.json "
|
||||
"doesn't match the version expected by dream2nix."
|
||||
"\n -> Replacing version in package.json: "
|
||||
f"{package_json['version']} -> {version}",
|
||||
file=sys.stderr
|
||||
)
|
||||
@ -40,7 +42,7 @@ if package_json['version'] != version:
|
||||
# We rely on dream.lock having the correct dependencies specified
|
||||
if 'devDependencies' in package_json:
|
||||
print(
|
||||
f"Removing devDependencies from package.json",
|
||||
f"package.json: removed all devDependencies",
|
||||
file=sys.stderr
|
||||
)
|
||||
changed = True
|
||||
@ -50,7 +52,7 @@ if 'devDependencies' in package_json:
|
||||
# We rely on dream.lock instead
|
||||
if 'peerDependencies' in package_json:
|
||||
print(
|
||||
f"Removing peerDependencies from package.json",
|
||||
f"package.json: removed all peerDependencies",
|
||||
file=sys.stderr
|
||||
)
|
||||
changed = True
|
||||
@ -65,8 +67,8 @@ if 'dependencies' in package_json:
|
||||
package_json['dependencies'][pname] = actual_deps[pname]
|
||||
changed = True
|
||||
print(
|
||||
f"Replacing loose version '{version}' with '{actual_deps[pname]}'"
|
||||
f" for dependency '{pname}' in package.json",
|
||||
f"package.json: Pinning version '{version}' to '{actual_deps[pname]}'"
|
||||
f" for dependency '{pname}'",
|
||||
file=sys.stderr
|
||||
)
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
{
|
||||
buildSystemAttrs,
|
||||
dependenciesRemoved,
|
||||
cyclicDependencies,
|
||||
mainPackageName,
|
||||
mainPackageVersion,
|
||||
getCyclicDependencies,
|
||||
|
113
src/default.nix
113
src/default.nix
@ -1,29 +1,47 @@
|
||||
# this is the system specific api for dream2nix
|
||||
# it requires passing one specifi pkgs
|
||||
# This is the system specific api for dream2nix.
|
||||
# It requires passing one specific pkgs.
|
||||
# If the intention is to generate output for several systems,
|
||||
# use ./lib.nix instead
|
||||
# use ./lib.nix instead.
|
||||
|
||||
{
|
||||
pkgs ? import <nixpkgs> {},
|
||||
lib ? pkgs.lib,
|
||||
|
||||
# the dream2nix cli depends on some nix 2.4 features
|
||||
nix ? pkgs.writeScriptBin "nix" ''
|
||||
${pkgs.nixUnstable}/bin/nix --option experimental-features "nix-command flakes" "$@"
|
||||
'',
|
||||
|
||||
# dependencies of dream2nix
|
||||
externalSources ?
|
||||
lib.genAttrs
|
||||
(lib.attrNames (builtins.readDir externalDir))
|
||||
(inputName: "${externalDir}/${inputName}"),
|
||||
|
||||
# required for non-flake mode
|
||||
externalDir ?
|
||||
# if called via CLI, load externals via env
|
||||
if builtins ? getEnv && builtins.getEnv "d2nExternalSources" != "" then
|
||||
builtins.getEnv "d2nExternalSources"
|
||||
# load from default dircetory
|
||||
if builtins ? getEnv && builtins.getEnv "d2nExternalDir" != "" then
|
||||
builtins.getEnv "d2nExternalDir"
|
||||
# load from default directory
|
||||
else
|
||||
./external,
|
||||
|
||||
# dream2nix overrides
|
||||
overridesDir ?
|
||||
# if called via CLI, load externals via env
|
||||
if builtins ? getEnv && builtins.getEnv "d2nOverridesDir" != "" then
|
||||
builtins.getEnv "d2nOverridesDir"
|
||||
# load from default directory
|
||||
else
|
||||
./overrides,
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
b = builtins;
|
||||
|
||||
utils = callPackageDream ./utils {};
|
||||
|
||||
# like pkgs.callPackage, but includes all the dream2nix modules
|
||||
callPackageDream = f: args: pkgs.callPackage f (args // {
|
||||
inherit builders;
|
||||
inherit callPackageDream;
|
||||
@ -36,13 +54,8 @@ let
|
||||
inherit nix;
|
||||
});
|
||||
|
||||
externals = {
|
||||
node2nix = nodejs: pkgs.callPackage "${externalSources}/node2nix/node-env.nix" { inherit nodejs; };
|
||||
nix-parsec = rec {
|
||||
lexer = import "${externalSources}/nix-parsec/lexer.nix" { inherit parsec; };
|
||||
parsec = import "${externalSources}/nix-parsec/parsec.nix";
|
||||
};
|
||||
};
|
||||
|
||||
utils = callPackageDream ./utils {};
|
||||
|
||||
config = builtins.fromJSON (builtins.readFile ./config.json);
|
||||
|
||||
@ -61,6 +74,20 @@ let
|
||||
# the translator modules and utils for all subsystems
|
||||
translators = callPackageDream ./translators {};
|
||||
|
||||
externals = {
|
||||
node2nix = nodejs: pkgs.callPackage "${externalSources.node2nix}/nix/node-env.nix" { inherit nodejs; };
|
||||
nix-parsec = rec {
|
||||
lexer = import "${externalSources.nix-parsec}/lexer.nix" { inherit parsec; };
|
||||
parsec = import "${externalSources.nix-parsec}/parsec.nix";
|
||||
};
|
||||
};
|
||||
|
||||
dreamOverrides = lib.genAttrs (utils.dirNames overridesDir) (name:
|
||||
import (overridesDir + "/${name}") {
|
||||
inherit lib pkgs;
|
||||
}
|
||||
);
|
||||
|
||||
# the location of the dream2nix framework for self references (update scripts, etc.)
|
||||
dream2nixWithExternals =
|
||||
if b.pathExists (./. + "/external") then
|
||||
@ -70,16 +97,10 @@ let
|
||||
cp -r ${./.} $out
|
||||
chmod +w $out
|
||||
mkdir $out/external
|
||||
ls -lah ${externalSources}
|
||||
cp -r ${externalSources}/* $out/external/
|
||||
ls -lah ${externalDir}
|
||||
cp -r ${externalDir}/* $out/external/
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
rec {
|
||||
|
||||
inherit apps builders dream2nixWithExternals fetchers translators updaters utils;
|
||||
|
||||
# automatically find a suitable builder for a given generic lock
|
||||
findBuilder = dreamLock:
|
||||
let
|
||||
@ -234,7 +255,7 @@ rec {
|
||||
|
||||
inherit (dreamLockInterface)
|
||||
buildSystemAttrs
|
||||
dependenciesRemoved
|
||||
cyclicDependencies
|
||||
getDependencies
|
||||
getCyclicDependencies
|
||||
mainPackageName
|
||||
@ -306,10 +327,50 @@ rec {
|
||||
;
|
||||
builder = builder';
|
||||
builderArgs = (args.builderArgs or {}) // {
|
||||
inherit packageOverrides;
|
||||
packageOverrides =
|
||||
args.packageOverrides or {}
|
||||
// dreamOverrides."${dreamLock.generic.buildSystem}" or {};
|
||||
};
|
||||
};
|
||||
|
||||
# Makes the packages tree compatible with flakes schema.
|
||||
# For each package the attr `{pname}` will link to the latest release.
|
||||
# Other package versions will be inside: `{pname}.versions`
|
||||
formattedBuilderOutputs = builderOutputs // {
|
||||
packages =
|
||||
let
|
||||
allPackages = builderOutputs.packages or {};
|
||||
|
||||
latestPackages =
|
||||
lib.mapAttrs'
|
||||
(pname: releases:
|
||||
let
|
||||
latest =
|
||||
releases."${utils.latestVersion (b.attrNames releases)}";
|
||||
in
|
||||
(lib.nameValuePair
|
||||
"${pname}"
|
||||
(latest // {
|
||||
versions = releases;
|
||||
})))
|
||||
allPackages;
|
||||
in
|
||||
latestPackages;
|
||||
};
|
||||
in
|
||||
builderOutputs;
|
||||
formattedBuilderOutputs;
|
||||
|
||||
in
|
||||
{
|
||||
inherit
|
||||
apps
|
||||
builders
|
||||
dream2nixWithExternals
|
||||
fetchers
|
||||
fetchSources
|
||||
riseAndShine
|
||||
translators
|
||||
updaters
|
||||
utils
|
||||
;
|
||||
}
|
||||
|
@ -95,11 +95,11 @@ rec {
|
||||
|
||||
translateHttpUrl =
|
||||
let
|
||||
fetcher = fetchers.fetchurl;
|
||||
fetcherOutputs = fetchers.fetchurl.outputs { url = shortcut; };
|
||||
fetcher = fetchers.http;
|
||||
fetcherOutputs = fetchers.http.outputs { url = shortcut; };
|
||||
in
|
||||
constructSource {
|
||||
type = "fetchurl";
|
||||
type = "http";
|
||||
hash = fetcherOutputs.calcHash "sha256";
|
||||
url = shortcut;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
fetchurl,
|
||||
http,
|
||||
python3,
|
||||
|
||||
utils,
|
||||
@ -25,7 +25,7 @@
|
||||
calcHash = algo: utils.hashPath algo (
|
||||
let
|
||||
firstChar = builtins.substring 0 1 pname;
|
||||
result = b.fetchurl {
|
||||
result = b.http {
|
||||
url =
|
||||
"https://files.pythonhosted.org/packages/source/"
|
||||
+ "${firstChar}/${pname}/${pname}-${version}.${extension}";
|
||||
@ -38,7 +38,7 @@
|
||||
fetched = hash:
|
||||
let
|
||||
firstChar = builtins.substring 0 1 pname;
|
||||
result = (fetchurl {
|
||||
result = (http {
|
||||
url =
|
||||
"https://files.pythonhosted.org/packages/source/"
|
||||
+ "${firstChar}/${pname}/${pname}-${version}.${extension}";
|
||||
|
17
src/lib.nix
17
src/lib.nix
@ -6,8 +6,9 @@
|
||||
nixpkgsSrc ? <nixpkgs>,
|
||||
lib ? (import nixpkgsSrc {}).lib,
|
||||
|
||||
# dream2nix
|
||||
makeExternalSources,
|
||||
# (if called impurely ./default.nix will handle externals and overrides)
|
||||
externalSources ? null,
|
||||
overridesDir ? null,
|
||||
}:
|
||||
|
||||
let
|
||||
@ -79,10 +80,14 @@ in
|
||||
dream2nixFor =
|
||||
lib.mapAttrs
|
||||
(system: pkgs:
|
||||
import ./default.nix {
|
||||
inherit pkgs;
|
||||
externalSources = makeExternalSources pkgs;
|
||||
})
|
||||
import ./default.nix
|
||||
({ inherit pkgs; }
|
||||
// (lib.optionalAttrs (externalSources != null) {
|
||||
inherit externalSources;
|
||||
})
|
||||
// (lib.optionalAttrs (overridesDir != null) {
|
||||
inherit overridesDir;
|
||||
})))
|
||||
allPkgs;
|
||||
|
||||
allBuilderOutputs =
|
||||
|
@ -27,7 +27,7 @@
|
||||
"url": "https://download.pypi.org/requests/2.28.0",
|
||||
"hash": "000000000000000000000000000000000000000",
|
||||
"version": "1.2.3",
|
||||
"type": "fetchurl"
|
||||
"type": "http"
|
||||
}
|
||||
},
|
||||
"certifi": {
|
||||
@ -35,7 +35,7 @@
|
||||
"url": "https://download.pypi.org/certifi/2.0",
|
||||
"hash": "000000000000000000000000000000000000000",
|
||||
"version": "2.3.4",
|
||||
"type": "fetchurl"
|
||||
"type": "http"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [
|
||||
"fetchurl",
|
||||
"http",
|
||||
"git",
|
||||
"github",
|
||||
"gitlab",
|
||||
@ -29,7 +29,7 @@
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": { "type": { "const": "fetchurl" } }
|
||||
"properties": { "type": { "const": "http" } }
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
|
@ -13,7 +13,7 @@
|
||||
{
|
||||
|
||||
# the input format is specified in /specifications/translator-call-example.json
|
||||
# this script receives a json file including the input paths and specialArgs
|
||||
# this script receives a json file including the input paths and extraArgs
|
||||
translateBin = writeScriptBin "translate" ''
|
||||
#!${bash}/bin/bash
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
# - string argument (type = "argument")
|
||||
# - boolean flag (type = "flag")
|
||||
# String arguments contain a default value and examples. Flags do not.
|
||||
specialArgs = {
|
||||
extraArgs = {
|
||||
|
||||
# Example: boolean option
|
||||
# Flags always default to 'false' if not specified by the user
|
||||
|
@ -67,7 +67,7 @@
|
||||
# - string argument (type = "argument")
|
||||
# - boolean flag (type = "flag")
|
||||
# String arguments contain a default value and examples. Flags do not.
|
||||
specialArgs = {
|
||||
extraArgs = {
|
||||
|
||||
# Example: boolean option
|
||||
# Flags always default to 'false' if not specified by the user
|
||||
|
@ -6,7 +6,6 @@
|
||||
pkgs,
|
||||
|
||||
callPackageDream,
|
||||
externalSources,
|
||||
externals,
|
||||
dream2nixWithExternals,
|
||||
utils,
|
||||
@ -36,7 +35,7 @@ let
|
||||
inherit subsystem type name;
|
||||
translate = args:
|
||||
translator.translate
|
||||
((getSpecialArgsDefaults translator.specialArgs or {}) // args);
|
||||
((getextraArgsDefaults translator.extraArgs or {}) // args);
|
||||
};
|
||||
|
||||
|
||||
@ -99,7 +98,7 @@ let
|
||||
(t: {
|
||||
inherit (t)
|
||||
name
|
||||
specialArgs
|
||||
extraArgs
|
||||
subsystem
|
||||
type
|
||||
;
|
||||
@ -107,7 +106,7 @@ let
|
||||
});
|
||||
|
||||
# pupulates a translators special args with defaults
|
||||
getSpecialArgsDefaults = specialArgsDef:
|
||||
getextraArgsDefaults = extraArgsDef:
|
||||
lib.mapAttrs
|
||||
(name: def:
|
||||
if def.type == "flag" then
|
||||
@ -115,7 +114,7 @@ let
|
||||
else
|
||||
def.default or null
|
||||
)
|
||||
specialArgsDef;
|
||||
extraArgsDef;
|
||||
|
||||
in
|
||||
{
|
||||
|
@ -106,14 +106,14 @@
|
||||
if identifyGitSource dependencyObject then
|
||||
"git"
|
||||
else
|
||||
"fetchurl";
|
||||
"http";
|
||||
|
||||
sourceConstructors = {
|
||||
|
||||
git = dependencyObject:
|
||||
utils.parseGitUrl dependencyObject.version;
|
||||
|
||||
fetchurl = dependencyObject:
|
||||
http = dependencyObject:
|
||||
rec {
|
||||
version = dependencyObject.version;
|
||||
url = dependencyObject.resolved;
|
||||
@ -139,7 +139,7 @@
|
||||
inputFiles = [];
|
||||
};
|
||||
|
||||
specialArgs = {
|
||||
extraArgs = {
|
||||
|
||||
dev = {
|
||||
description = "include dependencies for development";
|
||||
|
@ -141,7 +141,7 @@
|
||||
else if lib.hasInfix "@link:" dependencyObject.yarnName then
|
||||
"path"
|
||||
else
|
||||
"fetchurl";
|
||||
"http";
|
||||
|
||||
|
||||
sourceConstructors = {
|
||||
@ -164,9 +164,9 @@
|
||||
path = lib.last (lib.splitString "@link:" dependencyObject.yarnName);
|
||||
};
|
||||
|
||||
fetchurl = dependencyObject:
|
||||
http = dependencyObject:
|
||||
{
|
||||
type = "fetchurl";
|
||||
type = "http";
|
||||
version = dependencyObject.version;
|
||||
hash =
|
||||
if dependencyObject ? integrity then
|
||||
@ -214,7 +214,7 @@
|
||||
# - string argument (type = "argument")
|
||||
# - boolean flag (type = "flag")
|
||||
# String arguments contain a default value and examples. Flags do not.
|
||||
specialArgs = {
|
||||
extraArgs = {
|
||||
|
||||
name = {
|
||||
description = "The name of the main package";
|
||||
|
@ -16,7 +16,7 @@
|
||||
let
|
||||
b = builtins;
|
||||
|
||||
machNixExtractor = "${externalSources}/mach-nix-lib/default.nix";
|
||||
machNixExtractor = "${externalSources.mach-nix}/lib/default.nix";
|
||||
|
||||
setuptools_shim = ''
|
||||
import sys, setuptools, tokenize, os; sys.argv[0] = 'setup.py'; __file__='setup.py';
|
||||
@ -31,7 +31,7 @@ in
|
||||
{
|
||||
|
||||
# the input format is specified in /specifications/translator-call-example.json
|
||||
# this script receives a json file including the input paths and specialArgs
|
||||
# this script receives a json file including the input paths and extraArgs
|
||||
translateBin = utils.writePureShellScript
|
||||
[
|
||||
bash
|
||||
@ -115,7 +115,7 @@ in
|
||||
};
|
||||
|
||||
# define special args and provide defaults
|
||||
specialArgs = {
|
||||
extraArgs = {
|
||||
|
||||
# the python attribute
|
||||
pythonAttr = {
|
||||
|
@ -79,7 +79,7 @@ def main():
|
||||
dream_lock['sources'][pname][data['version']] = dict(
|
||||
url=data['url'],
|
||||
hash=data['sha256'],
|
||||
type='fetchurl',
|
||||
type='http',
|
||||
)
|
||||
|
||||
# dump generic lock to stdout (json)
|
||||
|
@ -120,4 +120,42 @@ rec {
|
||||
nameVersionToKey = nameVersion:
|
||||
"${nameVersion.name}#${nameVersion.version}";
|
||||
|
||||
# determines if version v1 is greater than version v2
|
||||
versionGreater = v1: v2:
|
||||
versionGreaterList
|
||||
(lib.splitString "." v1)
|
||||
(lib.splitString "." v2);
|
||||
|
||||
# internal helper for 'versionGreater'
|
||||
versionGreaterList = v1: v2:
|
||||
let
|
||||
head1 = b.head v1;
|
||||
head2 = b.head v2;
|
||||
n1 =
|
||||
if builtins.match ''[[:digit:]]*'' head1 != null then
|
||||
lib.toInt head1
|
||||
else
|
||||
0;
|
||||
n2 = if builtins.match ''[[:digit:]]*'' head2 != null then
|
||||
lib.toInt head2
|
||||
else
|
||||
0;
|
||||
in
|
||||
if n1 > n2 then
|
||||
true
|
||||
else
|
||||
# end recursion condition
|
||||
if b.length v1 == 1 || b.length v1 == 1 then
|
||||
false
|
||||
else
|
||||
# continue recursion
|
||||
versionGreaterList (b.tail v1) (b.tail v2);
|
||||
|
||||
# picks the latest version from a list of version strings
|
||||
latestVersion = versions:
|
||||
b.head
|
||||
(lib.sort
|
||||
(v1: v2: versionGreater v1 v2)
|
||||
versions);
|
||||
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ let
|
||||
{}
|
||||
(b.map (utils.keyToNameVersion) allDependencyKeys);
|
||||
|
||||
dependenciesRemoved =
|
||||
cyclicDependencies =
|
||||
lib.mapAttrs
|
||||
(name: versions:
|
||||
lib.mapAttrs
|
||||
@ -56,7 +56,7 @@ let
|
||||
lib.forEach removedKeys
|
||||
(rKey: utils.keyToNameVersion rKey))
|
||||
versions)
|
||||
lock.generic.dependenciesRemoved or {};
|
||||
lock.generic.cyclicDependencies or {};
|
||||
|
||||
# Format:
|
||||
# {
|
||||
@ -76,14 +76,14 @@ let
|
||||
if dependenciesAttrs ? "${pname}#${version}" then
|
||||
# filter out cyclicDependencies
|
||||
lib.filter
|
||||
(dep: ! b.elem dep (dependenciesRemoved."${pname}"."${version}" or []))
|
||||
(dep: ! b.elem dep (cyclicDependencies."${pname}"."${version}" or []))
|
||||
dependenciesAttrs."${pname}#${version}"
|
||||
# assume no deps if package not found in dependencyGraph
|
||||
else
|
||||
[];
|
||||
|
||||
getCyclicDependencies = pname: version:
|
||||
dependenciesRemoved."${pname}"."${version}" or [];
|
||||
cyclicDependencies."${pname}"."${version}" or [];
|
||||
|
||||
in
|
||||
{
|
||||
@ -97,7 +97,7 @@ let
|
||||
|
||||
inherit
|
||||
buildSystemAttrs
|
||||
dependenciesRemoved
|
||||
cyclicDependencies
|
||||
getCyclicDependencies
|
||||
getDependencies
|
||||
packageVersions
|
||||
|
@ -6,21 +6,34 @@ let
|
||||
|
||||
b = builtins;
|
||||
|
||||
exampleOverrides = {
|
||||
|
||||
hello = [
|
||||
{
|
||||
description = "patch hello";
|
||||
condition = pkg: if pkg.version > 3.0.0 then true else false;
|
||||
overrideAttrs = old: {
|
||||
patches = [];
|
||||
throwErrorUnclearAttributeOverride = pname: overrideName: attrName:
|
||||
throw ''
|
||||
Error while applying override for ${pname}: '${overrideName}'
|
||||
There are multiple override functions accepting an argument named '${attrName}'.
|
||||
Please modify the override to clarify which override function should be used.
|
||||
Instead of:
|
||||
```
|
||||
"${pname}" = {
|
||||
"${overrideName}" = {
|
||||
...
|
||||
${attrName} = ...;
|
||||
...
|
||||
};
|
||||
};
|
||||
override = old: {
|
||||
withPython = false;
|
||||
```
|
||||
Use:
|
||||
```
|
||||
"${pname}" = {
|
||||
"${overrideName}" = {
|
||||
...
|
||||
overrideAttrs = oldAttrs: {
|
||||
${attrName} = ...;
|
||||
};
|
||||
...
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
```
|
||||
'';
|
||||
|
||||
applyOverridesToPackage = conditionalOverrides: pkg: pname:
|
||||
if ! conditionalOverrides ? "${pname}" then
|
||||
@ -31,16 +44,30 @@ let
|
||||
|
||||
# if condition is unset, it will be assumed true
|
||||
evalCondition = condOverride: pkg:
|
||||
if condOverride ? condition then
|
||||
condOverride.condition pkg
|
||||
if condOverride ? _condition then
|
||||
condOverride._condition pkg
|
||||
else
|
||||
true;
|
||||
|
||||
# filter the overrides by the package name and conditions
|
||||
overridesToApply =
|
||||
(lib.filter
|
||||
(condOverride: evalCondition condOverride pkg)
|
||||
conditionalOverrides."${pname}");
|
||||
let
|
||||
overridesForPackage = conditionalOverrides."${pname}";
|
||||
overridesListForPackage =
|
||||
lib.mapAttrsToList
|
||||
(_name: data: data // { inherit _name; })
|
||||
overridesForPackage;
|
||||
in
|
||||
(lib.filter
|
||||
(condOverride: evalCondition condOverride pkg)
|
||||
overridesListForPackage);
|
||||
|
||||
# apply single attribute override
|
||||
applySingleAttributeOverride = oldVal: functionOrValue:
|
||||
if b.isFunction functionOrValue then
|
||||
functionOrValue oldVal
|
||||
else
|
||||
functionOrValue;
|
||||
|
||||
# helper to apply one conditional override
|
||||
# the condition is not evaluated anymore here
|
||||
@ -48,8 +75,46 @@ let
|
||||
let
|
||||
overrideFuncs =
|
||||
lib.mapAttrsToList
|
||||
(funcName: func: { inherit funcName func; })
|
||||
(lib.filterAttrs (n: v: lib.hasPrefix "override" n) condOverride);
|
||||
(funcName: func: { inherit funcName func; })
|
||||
(lib.filterAttrs (n: v: lib.hasPrefix "override" n) condOverride);
|
||||
|
||||
singleArgOverrideFuncs =
|
||||
let
|
||||
availableFunctions =
|
||||
lib.mapAttrs
|
||||
(funcName: func: lib.attrNames (lib.functionArgs func))
|
||||
(lib.filterAttrs
|
||||
(funcName: func: lib.hasPrefix "override" funcName)
|
||||
pkg);
|
||||
|
||||
getOverrideFuncNameForAttrName = attrName:
|
||||
let
|
||||
applicableFuncs =
|
||||
lib.attrNames
|
||||
(lib.filterAttrs
|
||||
(funcName: args: b.elem attrName args)
|
||||
availableFunctions);
|
||||
in
|
||||
if b.length applicableFuncs == 0 then
|
||||
"overrideAttrs"
|
||||
else if b.length applicableFuncs >= 1 then
|
||||
throwErrorUnclearAttributeOverride pname condOverride._name attrName
|
||||
else
|
||||
b.elemAt applicableFuncs 0;
|
||||
|
||||
attributeOverrides =
|
||||
lib.filterAttrs
|
||||
(n: v: ! lib.hasPrefix "override" n && ! lib.hasPrefix "_" n)
|
||||
condOverride;
|
||||
|
||||
in
|
||||
lib.mapAttrsToList
|
||||
(attrName: funcOrValue: {
|
||||
funcName = getOverrideFuncNameForAttrName attrName;
|
||||
func = oldAttrs: { "${attrName}" = funcOrValue; };
|
||||
})
|
||||
attributeOverrides;
|
||||
|
||||
in
|
||||
b.foldl'
|
||||
(pkg: overrideFunc:
|
||||
@ -59,14 +124,11 @@ let
|
||||
updateAttrsFuncs = overrideFunc.func old;
|
||||
in
|
||||
lib.mapAttrs
|
||||
(attrName: maybeFunction:
|
||||
if b.isFunction maybeFunction then
|
||||
maybeFunction old."${attrName}"
|
||||
else
|
||||
maybeFunction)
|
||||
(attrName: functionOrValue:
|
||||
applySingleAttributeOverride old."${attrName}" functionOrValue)
|
||||
updateAttrsFuncs))
|
||||
pkg
|
||||
overrideFuncs;
|
||||
(overrideFuncs ++ singleArgOverrideFuncs);
|
||||
in
|
||||
# apply the overrides to the given pkg
|
||||
(lib.foldl
|
||||
|
Loading…
Reference in New Issue
Block a user