mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-09-11 14:35:30 +03:00
Merge pull request #328 from leungbk/cabal-freeze
Add cabal-freeze support
This commit is contained in:
commit
e7c7077f22
23
examples/haskell_cabal-freeze/flake.nix
Normal file
23
examples/haskell_cabal-freeze/flake.nix
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
dream2nix.url = "github:nix-community/dream2nix";
|
||||||
|
src.url = "github:leungbk/unordered-containers/cabal-freeze-test";
|
||||||
|
src.flake = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
dream2nix,
|
||||||
|
src,
|
||||||
|
} @ inp: (dream2nix.lib.makeFlakeOutputs {
|
||||||
|
systems = ["x86_64-linux"];
|
||||||
|
config.projectRoot = ./.;
|
||||||
|
source = src;
|
||||||
|
settings = [
|
||||||
|
{
|
||||||
|
translator = "cabal-freeze";
|
||||||
|
}
|
||||||
|
{subsystemInfo = {defaultPackageName = "unordered-containers";};}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
17
flake.lock
17
flake.lock
@ -124,6 +124,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ghc-utils": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1662774800,
|
||||||
|
"narHash": "sha256-1Rd2eohGUw/s1tfvkepeYpg8kCEXiIot0RijapUjAkE=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "bb3a2d3dc52ff0253fb9c2812bd7aa2da03e0fea",
|
||||||
|
"revCount": 1072,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.haskell.org/bgamari/ghc-utils"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.haskell.org/bgamari/ghc-utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
"gomod2nix": {
|
"gomod2nix": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@ -217,6 +233,7 @@
|
|||||||
"crane": "crane",
|
"crane": "crane",
|
||||||
"devshell": "devshell",
|
"devshell": "devshell",
|
||||||
"flake-utils-pre-commit": "flake-utils-pre-commit",
|
"flake-utils-pre-commit": "flake-utils-pre-commit",
|
||||||
|
"ghc-utils": "ghc-utils",
|
||||||
"gomod2nix": "gomod2nix",
|
"gomod2nix": "gomod2nix",
|
||||||
"mach-nix": "mach-nix",
|
"mach-nix": "mach-nix",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
|
@ -53,6 +53,11 @@
|
|||||||
url = "github:nix-community/all-cabal-json/hackage";
|
url = "github:nix-community/all-cabal-json/hackage";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ghc-utils = {
|
||||||
|
url = "git+https://gitlab.haskell.org/bgamari/ghc-utils";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
@ -66,6 +71,7 @@
|
|||||||
pre-commit-hooks,
|
pre-commit-hooks,
|
||||||
crane,
|
crane,
|
||||||
all-cabal-json,
|
all-cabal-json,
|
||||||
|
ghc-utils,
|
||||||
...
|
...
|
||||||
} @ inp: let
|
} @ inp: let
|
||||||
b = builtins;
|
b = builtins;
|
||||||
|
@ -4,6 +4,12 @@
|
|||||||
"name": "ghc",
|
"name": "ghc",
|
||||||
"version": "8.10.7"
|
"version": "8.10.7"
|
||||||
},
|
},
|
||||||
|
"cabalFlags": {
|
||||||
|
"darcs": [
|
||||||
|
"-fforce-char8-encoding",
|
||||||
|
"-flibrary"
|
||||||
|
]
|
||||||
|
},
|
||||||
"cabal-files": {
|
"cabal-files": {
|
||||||
"aeson": {
|
"aeson": {
|
||||||
"1.2.2.0": {
|
"1.2.2.0": {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
utils,
|
utils,
|
||||||
externals,
|
externals,
|
||||||
|
inputs,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
@ -124,6 +125,9 @@ in {
|
|||||||
doCheck = false;
|
doCheck = false;
|
||||||
doBenchmark = false;
|
doBenchmark = false;
|
||||||
|
|
||||||
|
# FIXME: this skips over the default package if its name isn't set properly
|
||||||
|
configureFlags = subsystemAttrs.cabalFlags."${name}"."${version}" or [];
|
||||||
|
|
||||||
libraryToolDepends = libraryHaskellDepends;
|
libraryToolDepends = libraryHaskellDepends;
|
||||||
executableHaskellDepends = libraryHaskellDepends;
|
executableHaskellDepends = libraryHaskellDepends;
|
||||||
testHaskellDepends = libraryHaskellDepends;
|
testHaskellDepends = libraryHaskellDepends;
|
||||||
@ -139,15 +143,16 @@ in {
|
|||||||
specified in the dream-lock
|
specified in the dream-lock
|
||||||
*/
|
*/
|
||||||
// (
|
// (
|
||||||
l.optionalAttrs
|
l.optionalAttrs (name != defaultPackageName)
|
||||||
(
|
|
||||||
(name != defaultPackageName)
|
|
||||||
&& cabalFiles ? "${name}#${version}"
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
preConfigure = ''
|
preConfigure =
|
||||||
cp ${cabalFiles."${name}#${version}"} ./${name}.cabal
|
if cabalFiles ? "${name}#${version}"
|
||||||
'';
|
then ''
|
||||||
|
cp ${cabalFiles."${name}#${version}"} ./${name}.cabal
|
||||||
|
''
|
||||||
|
else ''
|
||||||
|
cp ${inputs.all-cabal-json}/${name}/${version}/${name}.cabal ./
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
# enable tests only for the top-level package
|
# enable tests only for the top-level package
|
||||||
|
295
src/subsystems/haskell/translators/cabal-freeze/default.nix
Normal file
295
src/subsystems/haskell/translators/cabal-freeze/default.nix
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
{
|
||||||
|
dlib,
|
||||||
|
lib,
|
||||||
|
name,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
l = lib // builtins;
|
||||||
|
in {
|
||||||
|
type = "pure";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Automatically generate unit tests for this translator using project sources
|
||||||
|
from the specified list.
|
||||||
|
|
||||||
|
!!! Your first action should be adding a project here. This will simplify
|
||||||
|
your work because you will be able to use `nix run .#tests-unit` to
|
||||||
|
test your implementation for correctness.
|
||||||
|
*/
|
||||||
|
generateUnitTestsForProjects = [
|
||||||
|
(builtins.fetchTarball {
|
||||||
|
url = "https://github.com/leungbk/ghcid/tarball/1a1aa2f3ee409a0044340f2759d21b64b56b0010";
|
||||||
|
sha256 = "sha256:1mp33xkyyb4jqqriczai80sqwlrjcwd94l7bv709ngwjqy56h2n9";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
/*
|
||||||
|
Allow dream2nix to detect if a given directory contains a project
|
||||||
|
which can be translated with this translator.
|
||||||
|
Usually this can be done by checking for the existence of specific
|
||||||
|
file names or file endings.
|
||||||
|
|
||||||
|
Alternatively a fully featured discoverer can be implemented under
|
||||||
|
`src/subsystems/{subsystem}/discoverers`.
|
||||||
|
This is recommended if more complex project structures need to be
|
||||||
|
discovered like, for example, workspace projects spanning over multiple
|
||||||
|
sub-directories
|
||||||
|
|
||||||
|
If a fully featured discoverer exists, do not define `discoverProject`.
|
||||||
|
*/
|
||||||
|
discoverProject = tree:
|
||||||
|
# Example
|
||||||
|
# Returns true if given directory contains a file ending with .freeze
|
||||||
|
l.any
|
||||||
|
(filename: l.hasSuffix ".freeze" filename)
|
||||||
|
(l.attrNames tree.files);
|
||||||
|
|
||||||
|
# translate from a given source and a project specification to a dream-lock.
|
||||||
|
translate = {
|
||||||
|
/*
|
||||||
|
A project returned by `discoverProjects`
|
||||||
|
Example:
|
||||||
|
|
||||||
|
{
|
||||||
|
"dreamLockPath": "packages/optimism/dream-lock.json",
|
||||||
|
"name": "optimism",
|
||||||
|
"relPath": "",
|
||||||
|
"subsystem": "nodejs",
|
||||||
|
"subsystemInfo": {
|
||||||
|
"workspaces": [
|
||||||
|
"packages/common-ts",
|
||||||
|
"packages/contracts",
|
||||||
|
"packages/core-utils",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"translator": "yarn-lock",
|
||||||
|
"translators": [
|
||||||
|
"yarn-lock",
|
||||||
|
"package-json"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
project,
|
||||||
|
/*
|
||||||
|
Entire source tree represented as deep attribute set.
|
||||||
|
(produced by `prepareSourceTree`)
|
||||||
|
|
||||||
|
This has the advantage that files will only be read once, even when
|
||||||
|
accessed multiple times or by multiple translators.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
{
|
||||||
|
files = {
|
||||||
|
"package.json" = {
|
||||||
|
relPath = "package.json"
|
||||||
|
fullPath = "${source}/package.json"
|
||||||
|
content = ;
|
||||||
|
jsonContent = ;
|
||||||
|
tomlContent = ;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
"packages" = {
|
||||||
|
relPath = "packages";
|
||||||
|
fullPath = "${source}/packages";
|
||||||
|
files = {
|
||||||
|
|
||||||
|
};
|
||||||
|
directories = {
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# returns the tree object of the given sub-path
|
||||||
|
getNodeFromPath = path: ...
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
tree,
|
||||||
|
# arguments defined in `extraArgs` (see below) specified by user
|
||||||
|
ghcVersion,
|
||||||
|
defaultPackageName,
|
||||||
|
defaultPackageVersion,
|
||||||
|
...
|
||||||
|
} @ args: let
|
||||||
|
# get the root source and project source
|
||||||
|
rootSource = tree.fullPath;
|
||||||
|
projectSource = "${tree.fullPath}/${project.relPath}";
|
||||||
|
projectTree = tree.getNodeFromPath project.relPath;
|
||||||
|
|
||||||
|
parsedCabalFreeze = l.pipe projectTree.files [
|
||||||
|
l.attrNames
|
||||||
|
(
|
||||||
|
l.findFirst (l.hasSuffix ".freeze")
|
||||||
|
(throw "No cabal.project.freeze file in the tree")
|
||||||
|
)
|
||||||
|
projectTree.getNodeFromPath
|
||||||
|
(l.attrByPath ["fullPath"] "")
|
||||||
|
(import ./parser.nix {inherit dlib lib;})
|
||||||
|
];
|
||||||
|
|
||||||
|
haskellUtils = import ../utils.nix {inherit inputs lib pkgs;};
|
||||||
|
|
||||||
|
hiddenPackages = haskellUtils.ghcVersionToHiddenPackages."${ghcVersion}";
|
||||||
|
|
||||||
|
serializedRawObjects = l.filter ({name, ...}: (! hiddenPackages ? ${name})) parsedCabalFreeze.packagesAndVersionsList;
|
||||||
|
|
||||||
|
cabalData =
|
||||||
|
haskellUtils.batchFindJsonFromCabalCandidates
|
||||||
|
serializedRawObjects;
|
||||||
|
|
||||||
|
cabalFreezeFlags = l.pipe serializedRawObjects [
|
||||||
|
(l.map ({
|
||||||
|
name,
|
||||||
|
version,
|
||||||
|
}:
|
||||||
|
l.nameValuePair name {"${version}" = parsedCabalFreeze.cabalFlags."${name}" or [];}))
|
||||||
|
(flagsAlist: [(l.nameValuePair defaultPackageName {"${defaultPackageVersion}" = parsedCabalFreeze.cabalFlags."${defaultPackageName}" or [];})] ++ flagsAlist)
|
||||||
|
l.listToAttrs
|
||||||
|
];
|
||||||
|
in
|
||||||
|
dlib.simpleTranslate2.translate
|
||||||
|
({objectsByKey, ...}: rec {
|
||||||
|
translatorName = name;
|
||||||
|
|
||||||
|
# relative path of the project within the source tree.
|
||||||
|
location = project.relPath;
|
||||||
|
|
||||||
|
# the name of the subsystem
|
||||||
|
subsystemName = "haskell";
|
||||||
|
|
||||||
|
# Extract subsystem specific attributes.
|
||||||
|
# The structure of this should be defined in:
|
||||||
|
# ./src/specifications/{subsystem}
|
||||||
|
subsystemAttrs = {
|
||||||
|
cabalFlags = cabalFreezeFlags;
|
||||||
|
|
||||||
|
compiler = {
|
||||||
|
name = "ghc";
|
||||||
|
version = ghcVersion;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# name of the default package
|
||||||
|
defaultPackage = defaultPackageName;
|
||||||
|
|
||||||
|
/*
|
||||||
|
List the package candidates which should be exposed to the user.
|
||||||
|
Only top-level packages should be listed here.
|
||||||
|
Users will not be interested in all individual dependencies.
|
||||||
|
*/
|
||||||
|
exportedPackages = {
|
||||||
|
"${defaultPackage}" = defaultPackageVersion;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
a list of raw package objects
|
||||||
|
If the upstream format is a deep attrset, this list should contain
|
||||||
|
a flattened representation of all entries.
|
||||||
|
*/
|
||||||
|
inherit serializedRawObjects;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Define extractor functions which each extract one property from
|
||||||
|
a given raw object.
|
||||||
|
(Each rawObj comes from serializedRawObjects).
|
||||||
|
|
||||||
|
Extractors can access the fields extracted by other extractors
|
||||||
|
by accessing finalObj.
|
||||||
|
*/
|
||||||
|
extractors = {
|
||||||
|
name = rawObj: finalObj:
|
||||||
|
rawObj.name;
|
||||||
|
|
||||||
|
version = rawObj: finalObj:
|
||||||
|
rawObj.version;
|
||||||
|
|
||||||
|
dependencies = rawObj: finalObj:
|
||||||
|
l.pipe cabalData
|
||||||
|
[
|
||||||
|
(haskellUtils.getDependencyNames finalObj)
|
||||||
|
(l.filter (name:
|
||||||
|
# Keep only .cabal dependencies present in the freeze file
|
||||||
|
(objectsByKey.name ? ${name})))
|
||||||
|
(l.map
|
||||||
|
(depName: {
|
||||||
|
name = depName;
|
||||||
|
version = objectsByKey.name.${depName}.version;
|
||||||
|
}))
|
||||||
|
];
|
||||||
|
|
||||||
|
sourceSpec = rawObj: finalObj:
|
||||||
|
# example
|
||||||
|
{
|
||||||
|
type = "http";
|
||||||
|
url = haskellUtils.getHackageUrl finalObj;
|
||||||
|
hash = "sha256:${haskellUtils.findSha256FromCabalCandidate finalObj.name finalObj.version}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Optionally define extra extractors which will be used to key all
|
||||||
|
final objects, so objects can be accessed via:
|
||||||
|
`objectsByKey.${keyName}.${value}`
|
||||||
|
*/
|
||||||
|
keys = {
|
||||||
|
name = rawObj: finalObj:
|
||||||
|
finalObj.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Optionally add extra objects (list of `finalObj`) to be added to
|
||||||
|
the dream-lock.
|
||||||
|
*/
|
||||||
|
# TODO: support multiple top-level packages; this requires parsing the "packages" heading in cabal.project
|
||||||
|
extraObjects = [
|
||||||
|
{
|
||||||
|
name = defaultPackage;
|
||||||
|
version = exportedPackages."${defaultPackage}";
|
||||||
|
# XXX: some of these are transitive dependencies, but
|
||||||
|
# including only direct deps requires that we either parse
|
||||||
|
# the Cabal file or use a potentially outdated one from
|
||||||
|
# all-cabal-json
|
||||||
|
dependencies = serializedRawObjects;
|
||||||
|
sourceSpec = {
|
||||||
|
type = "path";
|
||||||
|
path = projectTree.fullPath;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
# If the translator requires additional arguments, specify them here.
|
||||||
|
# Users will be able to set these arguments via `settings`.
|
||||||
|
# There are only two types of arguments:
|
||||||
|
# - string argument (type = "argument")
|
||||||
|
# - boolean flag (type = "flag")
|
||||||
|
# String arguments contain a default value and examples. Flags do not.
|
||||||
|
# Flags are false by default.
|
||||||
|
extraArgs = {
|
||||||
|
ghcVersion = {
|
||||||
|
description = "GHC version";
|
||||||
|
default = "9.0.2";
|
||||||
|
examples = ["9.0.2" "9.4.1"];
|
||||||
|
type = "argument";
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultPackageName = {
|
||||||
|
description = "Name of default package";
|
||||||
|
default = "main";
|
||||||
|
examples = ["main" "default"];
|
||||||
|
type = "argument";
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultPackageVersion = {
|
||||||
|
description = "Version of default package";
|
||||||
|
default = "unknown";
|
||||||
|
examples = ["unknown" "1.2.0"];
|
||||||
|
type = "argument";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
96
src/subsystems/haskell/translators/cabal-freeze/parser.nix
Normal file
96
src/subsystems/haskell/translators/cabal-freeze/parser.nix
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
dlib,
|
||||||
|
lib,
|
||||||
|
}: cabalFreezeFile: let
|
||||||
|
l = lib // builtins;
|
||||||
|
|
||||||
|
cabalFreezeFileText = dlib.readTextFile cabalFreezeFile;
|
||||||
|
|
||||||
|
sectionNamesAndContents = l.tail (l.split "\n([^ \t:]+):" (
|
||||||
|
"\n" + (trimSurroundingWhitespace cabalFreezeFileText)
|
||||||
|
));
|
||||||
|
|
||||||
|
sectionNames = l.pipe sectionNamesAndContents [
|
||||||
|
(l.filter l.isList)
|
||||||
|
(l.map l.head)
|
||||||
|
];
|
||||||
|
|
||||||
|
sectionContents = l.pipe sectionNamesAndContents [
|
||||||
|
(l.filter l.isString)
|
||||||
|
(l.map
|
||||||
|
(str:
|
||||||
|
l.pipe str [
|
||||||
|
(l.splitString "\n")
|
||||||
|
l.concatStrings
|
||||||
|
(l.splitString ",")
|
||||||
|
(l.map trimSurroundingWhitespace)
|
||||||
|
]))
|
||||||
|
];
|
||||||
|
|
||||||
|
trimSurroundingWhitespace = str:
|
||||||
|
l.pipe str [
|
||||||
|
(l.split "^[[:space:]]*")
|
||||||
|
l.flatten
|
||||||
|
l.concatStrings
|
||||||
|
(l.split "[[:space:]]*$")
|
||||||
|
l.flatten
|
||||||
|
l.concatStrings
|
||||||
|
];
|
||||||
|
|
||||||
|
sectionNamesWithContents = l.listToAttrs (l.zipListsWith l.nameValuePair sectionNames sectionContents);
|
||||||
|
|
||||||
|
cabalPackageNameVersionRegexp = "any\.([a-zA-Z0-9_-]+) ==([^, \t]+)";
|
||||||
|
|
||||||
|
partitionedConstraints = l.partition (str: l.match cabalPackageNameVersionRegexp str != null) sectionNamesWithContents.constraints;
|
||||||
|
in {
|
||||||
|
packagesAndVersionsList =
|
||||||
|
l.map
|
||||||
|
(str:
|
||||||
|
l.pipe str
|
||||||
|
[
|
||||||
|
(l.match cabalPackageNameVersionRegexp)
|
||||||
|
(packageAndVersion: dlib.nameVersionPair (l.head packageAndVersion) (l.last packageAndVersion))
|
||||||
|
])
|
||||||
|
partitionedConstraints.right;
|
||||||
|
|
||||||
|
packagesAndVersionsAttrSet =
|
||||||
|
l.pipe
|
||||||
|
partitionedConstraints.right
|
||||||
|
[
|
||||||
|
(l.map
|
||||||
|
(str:
|
||||||
|
l.pipe str
|
||||||
|
[
|
||||||
|
(l.match cabalPackageNameVersionRegexp)
|
||||||
|
(packageAndVersion: l.nameValuePair (l.head packageAndVersion) (l.last packageAndVersion))
|
||||||
|
]))
|
||||||
|
l.listToAttrs
|
||||||
|
];
|
||||||
|
|
||||||
|
cabalFlags = l.pipe partitionedConstraints.wrong [
|
||||||
|
(l.map (l.splitString " "))
|
||||||
|
(
|
||||||
|
l.map
|
||||||
|
(words: let
|
||||||
|
packageName = l.head words;
|
||||||
|
configureFlags = l.pipe words [
|
||||||
|
l.tail
|
||||||
|
(l.map (s: let
|
||||||
|
matchList = l.match "([+-])(.+)" s;
|
||||||
|
polarity = l.head matchList;
|
||||||
|
flagName = l.last matchList;
|
||||||
|
in
|
||||||
|
"-f"
|
||||||
|
+ (
|
||||||
|
l.optionalString (polarity == "-") "-"
|
||||||
|
)
|
||||||
|
+ flagName))
|
||||||
|
];
|
||||||
|
in
|
||||||
|
l.nameValuePair packageName configureFlags)
|
||||||
|
)
|
||||||
|
l.listToAttrs
|
||||||
|
];
|
||||||
|
|
||||||
|
# TODO: maybe use the index-state?
|
||||||
|
}
|
@ -8,53 +8,6 @@
|
|||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
l = lib // builtins;
|
l = lib // builtins;
|
||||||
|
|
||||||
hiddenPackagesDefault = {
|
|
||||||
# TODO: unblock these packages and implement actual logic to interpret the
|
|
||||||
# flags found in cabal files
|
|
||||||
Win32 = null;
|
|
||||||
|
|
||||||
# These are the packages which are already contained in the ghc package.
|
|
||||||
# This list actually depends on the ghc version used.
|
|
||||||
# see: https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/libraries/version-history
|
|
||||||
# and: https://gitlab.haskell.org/bgamari/ghc-utils/-/blob/master/library-versions/pkg_versions.txt
|
|
||||||
# TODO: Generate this list dynamically for the given ghc version via pkg_versions.txt
|
|
||||||
array = null;
|
|
||||||
base = null;
|
|
||||||
binary = null;
|
|
||||||
bytestring = null;
|
|
||||||
Cabal = null;
|
|
||||||
containers = null;
|
|
||||||
deepseq = null;
|
|
||||||
directory = null;
|
|
||||||
dns-internal = null;
|
|
||||||
fast-digits-internal = null;
|
|
||||||
filepath = null;
|
|
||||||
ghc = null;
|
|
||||||
ghc-boot = null;
|
|
||||||
ghc-boot-th = null;
|
|
||||||
ghc-compact = null;
|
|
||||||
ghc-heap = null;
|
|
||||||
ghc-prim = null;
|
|
||||||
ghci = null;
|
|
||||||
haskeline = null;
|
|
||||||
hpc = null;
|
|
||||||
integer-gmp = null;
|
|
||||||
libiserv = null;
|
|
||||||
mtl = null;
|
|
||||||
parsec = null;
|
|
||||||
pretty = null;
|
|
||||||
process = null;
|
|
||||||
rts = null;
|
|
||||||
stm = null;
|
|
||||||
template-haskell = null;
|
|
||||||
terminfo = null;
|
|
||||||
text = null;
|
|
||||||
time = null;
|
|
||||||
transformers = null;
|
|
||||||
unix = null;
|
|
||||||
xhtml = null;
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
type = "ifd";
|
type = "ifd";
|
||||||
|
|
||||||
@ -71,7 +24,7 @@ in {
|
|||||||
|
|
||||||
discoverProject = tree:
|
discoverProject = tree:
|
||||||
l.any
|
l.any
|
||||||
(filename: l.hasSuffix ".cabal" filename)
|
(filename: l.hasSuffix "stack.yaml.lock" filename)
|
||||||
(l.attrNames tree.files);
|
(l.attrNames tree.files);
|
||||||
|
|
||||||
# translate from a given source and a project specification to a dream-lock.
|
# translate from a given source and a project specification to a dream-lock.
|
||||||
@ -134,7 +87,7 @@ in {
|
|||||||
compilerVersion = l.last compilerSplit;
|
compilerVersion = l.last compilerSplit;
|
||||||
|
|
||||||
hidden =
|
hidden =
|
||||||
hiddenPackagesDefault;
|
haskellUtils.ghcVersionToHiddenPackages."${compilerVersion}" or haskellUtils.ghcVersionToHiddenPackages."9.0.2";
|
||||||
# TODO: find out what to do with the hidden packages from the snapshot
|
# TODO: find out what to do with the hidden packages from the snapshot
|
||||||
# Currently it looks like those should not be included
|
# Currently it looks like those should not be included
|
||||||
# // (
|
# // (
|
||||||
@ -183,45 +136,6 @@ in {
|
|||||||
in {
|
in {
|
||||||
inherit name version hash;
|
inherit name version hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
getDependencyNames = finalObj: objectsByName: let
|
|
||||||
cabal = cabalData.${finalObj.name}.${finalObj.version};
|
|
||||||
|
|
||||||
targetBuildDepends =
|
|
||||||
cabal.library.condTreeData.build-info.targetBuildDepends or [];
|
|
||||||
|
|
||||||
buildToolDepends =
|
|
||||||
cabal.library.condTreeData.build-info.buildToolDepends or [];
|
|
||||||
|
|
||||||
defaultFlags = l.filter (flag: flag.default) cabal.package-flags;
|
|
||||||
|
|
||||||
defaultFlagNames = l.map (flag: flag.name) defaultFlags;
|
|
||||||
|
|
||||||
collectBuildDepends = condTreeComponent:
|
|
||||||
l.concatMap
|
|
||||||
(attrs: attrs.targetBuildDepends)
|
|
||||||
(l.collect
|
|
||||||
(x: x ? targetBuildDepends)
|
|
||||||
condTreeComponent);
|
|
||||||
|
|
||||||
# TODO: use flags to determine which conditional deps are required
|
|
||||||
condBuildDepends =
|
|
||||||
l.concatMap
|
|
||||||
(component: collectBuildDepends component)
|
|
||||||
cabal.library.condTreeComponents or [];
|
|
||||||
|
|
||||||
depNames =
|
|
||||||
l.map
|
|
||||||
(dep: dep.package-name)
|
|
||||||
(targetBuildDepends ++ buildToolDepends ++ condBuildDepends);
|
|
||||||
in
|
|
||||||
l.filter
|
|
||||||
(name:
|
|
||||||
# ensure package is not a hidden package
|
|
||||||
(! hidden ? ${name})
|
|
||||||
# ignore packages which are not part of the snapshot or lock file
|
|
||||||
&& (objectsByName ? ${name}))
|
|
||||||
depNames;
|
|
||||||
in
|
in
|
||||||
dlib.simpleTranslate2.translate
|
dlib.simpleTranslate2.translate
|
||||||
({objectsByKey, ...}: rec {
|
({objectsByKey, ...}: rec {
|
||||||
@ -287,15 +201,22 @@ in {
|
|||||||
version = rawObj: finalObj:
|
version = rawObj: finalObj:
|
||||||
rawObj.version;
|
rawObj.version;
|
||||||
|
|
||||||
dependencies = rawObj: finalObj: let
|
dependencies = rawObj: finalObj:
|
||||||
depNames = getDependencyNames finalObj objectsByKey.name;
|
l.pipe cabalData
|
||||||
in
|
[
|
||||||
l.map
|
(haskellUtils.getDependencyNames finalObj)
|
||||||
(depName: {
|
(l.filter
|
||||||
name = depName;
|
(name:
|
||||||
version = objectsByKey.name.${depName}.version;
|
# ensure package is not a hidden package
|
||||||
})
|
(! hidden ? ${name})
|
||||||
depNames;
|
# ignore packages which are not part of the snapshot or lock file
|
||||||
|
&& (objectsByKey.name ? ${name})))
|
||||||
|
(l.map
|
||||||
|
(depName: {
|
||||||
|
name = depName;
|
||||||
|
version = objectsByKey.name.${depName}.version;
|
||||||
|
}))
|
||||||
|
];
|
||||||
|
|
||||||
sourceSpec = rawObj: finalObj:
|
sourceSpec = rawObj: finalObj:
|
||||||
# example
|
# example
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
jsonCabalFile = "${all-cabal-json}/${name}/${version}/${name}.json";
|
jsonCabalFile = "${all-cabal-json}/${name}/${version}/${name}.json";
|
||||||
in
|
in
|
||||||
if (! (l.pathExists jsonCabalFile))
|
if (! (l.pathExists jsonCabalFile))
|
||||||
then throw ''"all-cabal-json" seems to be outdated''
|
then throw ''Cannot find JSON for version ${version} of package ${name}. "all-cabal-json" may be outdated.''
|
||||||
else l.fromJSON (l.readFile jsonCabalFile);
|
else l.fromJSON (l.readFile jsonCabalFile);
|
||||||
in {
|
in {
|
||||||
inherit findJsonFromCabalCandidate;
|
inherit findJsonFromCabalCandidate;
|
||||||
@ -20,7 +20,7 @@ in {
|
|||||||
hashFile = "${all-cabal-json}/${name}/${version}/${name}.hashes.json";
|
hashFile = "${all-cabal-json}/${name}/${version}/${name}.hashes.json";
|
||||||
in
|
in
|
||||||
if (! (l.pathExists hashFile))
|
if (! (l.pathExists hashFile))
|
||||||
then throw ''"all-cabal-json" seems to be outdated''
|
then throw ''Cannot find JSON for version ${version} of package ${name}. "all-cabal-json" may be outdated.''
|
||||||
else (l.fromJSON (l.readFile hashFile)).package-hashes.SHA256;
|
else (l.fromJSON (l.readFile hashFile)).package-hashes.SHA256;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -45,4 +45,73 @@ in {
|
|||||||
version,
|
version,
|
||||||
...
|
...
|
||||||
}: "https://hackage.haskell.org/package/${name}-${version}.tar.gz";
|
}: "https://hackage.haskell.org/package/${name}-${version}.tar.gz";
|
||||||
|
|
||||||
|
getDependencyNames = finalObj: cabalDataAsJson: let
|
||||||
|
cabal = with finalObj;
|
||||||
|
cabalDataAsJson.${name}.${version};
|
||||||
|
|
||||||
|
targetBuildDepends =
|
||||||
|
cabal.library.condTreeData.build-info.targetBuildDepends or [];
|
||||||
|
|
||||||
|
buildToolDepends =
|
||||||
|
cabal.library.condTreeData.build-info.buildToolDepends or [];
|
||||||
|
|
||||||
|
buildTools = cabal.library.condTreeData.build-info.buildTools or [];
|
||||||
|
|
||||||
|
defaultFlags = l.filter (flag: flag.default) cabal.package-flags;
|
||||||
|
|
||||||
|
defaultFlagNames = l.map (flag: flag.name) defaultFlags;
|
||||||
|
|
||||||
|
collectBuildDepends = condTreeComponent:
|
||||||
|
l.concatMap
|
||||||
|
(attrs: attrs.targetBuildDepends)
|
||||||
|
(l.collect
|
||||||
|
(x: x ? targetBuildDepends)
|
||||||
|
condTreeComponent);
|
||||||
|
|
||||||
|
# TODO: use flags to determine which conditional deps are required
|
||||||
|
condBuildDepends =
|
||||||
|
l.concatMap
|
||||||
|
(component: collectBuildDepends component)
|
||||||
|
cabal.library.condTreeComponents or [];
|
||||||
|
|
||||||
|
depNames =
|
||||||
|
l.map
|
||||||
|
(dep: dep.package-name)
|
||||||
|
(targetBuildDepends ++ buildToolDepends ++ buildTools ++ condBuildDepends);
|
||||||
|
in
|
||||||
|
depNames;
|
||||||
|
|
||||||
|
# XXX: This might be better as a function. See
|
||||||
|
# https://github.com/nixos/nixpkgs/blob/773c2a7afa4cc94f91d53d8cb35245cbf216082b/pkgs/development/haskell-modules/configuration-ghc-9.4.x.nix#L49-L56
|
||||||
|
# Packages we shouldn't always overwrite with null, but presently do anyway, are
|
||||||
|
# 1) terminfo, when we cross-compile
|
||||||
|
# 2) xhtml, when ghc.hasHaddock is set to false
|
||||||
|
ghcVersionToHiddenPackages = l.pipe "${inputs.ghc-utils}/library-versions/pkg_versions.txt" [
|
||||||
|
l.readFile
|
||||||
|
(l.split "\n#+\n# GHC [^\n]+")
|
||||||
|
l.tail
|
||||||
|
(l.filter l.isString)
|
||||||
|
(l.concatMap (l.splitString "\n"))
|
||||||
|
(l.filter (s: s != "" && !(l.hasPrefix "HEAD" s)))
|
||||||
|
(l.map (
|
||||||
|
s: let
|
||||||
|
ghcVersionAndHiddenPackages = l.match "([^[:space:]]+)[[:space:]]+(.+)" s;
|
||||||
|
ghcVersion = l.head ghcVersionAndHiddenPackages;
|
||||||
|
hiddenPackages = l.pipe (l.last ghcVersionAndHiddenPackages) [
|
||||||
|
(l.splitString " ")
|
||||||
|
(l.map (packageAndVersion:
|
||||||
|
l.pipe packageAndVersion [
|
||||||
|
(l.match "([^/]+)/.+")
|
||||||
|
l.head
|
||||||
|
(packageName: l.nameValuePair packageName null)
|
||||||
|
]))
|
||||||
|
(pkgNames: [(l.nameValuePair "Win32" null)] ++ pkgNames)
|
||||||
|
l.listToAttrs
|
||||||
|
];
|
||||||
|
in
|
||||||
|
l.nameValuePair ghcVersion hiddenPackages
|
||||||
|
))
|
||||||
|
l.listToAttrs
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
lib,
|
lib,
|
||||||
coreutils,
|
coreutils,
|
||||||
nix,
|
nix,
|
||||||
|
git,
|
||||||
python3,
|
python3,
|
||||||
utils,
|
utils,
|
||||||
dream2nixWithExternals,
|
dream2nixWithExternals,
|
||||||
@ -20,8 +21,9 @@ in
|
|||||||
[
|
[
|
||||||
coreutils
|
coreutils
|
||||||
nix
|
nix
|
||||||
|
git
|
||||||
]
|
]
|
||||||
''
|
''
|
||||||
export dream2nixSrc=${dream2nixWithExternals}
|
export dream2nixSrc=${../../.}/src
|
||||||
${pythonEnv}/bin/pytest ${self}/tests/unit -n $(nproc) -v "$@"
|
${pythonEnv}/bin/pytest ${self}/tests/unit -n $(nproc) -v "$@"
|
||||||
''
|
''
|
||||||
|
Loading…
Reference in New Issue
Block a user