add: simpleTranslate helper function for translators

This commit is contained in:
DavHau 2021-10-17 15:48:32 +07:00
parent 5717104535
commit 9677c12e9e
7 changed files with 335 additions and 29 deletions

View File

@ -0,0 +1,197 @@
{
lib,
externals,
translatorName,
utils,
...
}:
{
translate =
{
inputDirectories,
inputFiles,
# extraArgs
dev,
optional,
peer,
...
}:
let
b = builtins;
yarnLock = utils.readTextFile "${lib.elemAt inputDirectories 0}/yarn.lock";
packageJSON = b.fromJSON (b.readFile "${lib.elemAt inputDirectories 0}/package.json");
parser = import ../yarn-lock/parser.nix { inherit lib; inherit (externals) nix-parsec;};
tryParse = parser.parseLock yarnLock;
parsedLock =
if tryParse.type == "success" then
lib.foldAttrs (n: a: n // a) {} tryParse.value
else
let
failureOffset = tryParse.value.offset;
in
throw "parser failed at: \n${lib.substring failureOffset 50 tryParse.value.str}";
in
utils.simpleTranslate translatorName {
inputData = parsedLock;
mainPackageName = packageJSON.name;
mainPackageVersion = packageJSON.version;
buildSystemName = "nodejs";
buildSystemAttrs = {
nodejsVersion = 14;
};
mainPackageDependencies = inputData:
lib.mapAttrsToList
(depName: depSemVer:
let
depYarnKey = "${depName}@${depSemVer}";
dependencyAttrs =
if ! inputData ? "${depYarnKey}" then
throw "Cannot find entry for top level dependency: '${depYarnKey}'"
else
inputData."${depYarnKey}";
in
"${depName}#${dependencyAttrs.version}"
)
(
packageJSON.dependencies or {}
//
(lib.optionalAttrs dev (packageJSON.devDependencies or {}))
//
(lib.optionalAttrs peer (packageJSON.peerDependencies or {}))
);
serializePackages = inputData:
lib.mapAttrsToList
(yarnName: depAttrs: depAttrs // { inherit yarnName; })
parsedLock;
getOriginalID = dependencyObject:
dependencyObject.yarnName;
getName = dependencyObject:
let
version = lib.last (lib.splitString "@" dependencyObject.yarnName);
in
lib.removeSuffix "@${version}" dependencyObject.yarnName;
getVersion = dependencyObject:
dependencyObject.version;
getDependencies = dependencyObject: getDepByNameVer: getDepByOriginalID:
let
dependencies =
dependencyObject.dependencies or []
++ (lib.optionals optional (dependencyObject.optionalDependencies or []));
in
lib.forEach
dependencies
(dependency:
builtins.head (
lib.mapAttrsToList
(name: value:
let
yarnName = "${name}@${value}";
depObject = getDepByOriginalID yarnName;
version = depObject.version;
in
{ inherit name version; }
)
dependency
)
);
getSourceType = dependencyObject:
if lib.hasInfix "@github:" dependencyObject.yarnName
|| lib.hasInfix "codeload.github.com/" dependencyObject.resolved then
"github"
else if lib.hasInfix "@link:" dependencyObject.yarnName then
"path"
else
"fetchurl";
sourceConstructors = {
github = dependencyObject:
let
gitUrlInfos = lib.splitString "/" dependencyObject.resolved;
in
{
type = "github";
rev = lib.elemAt gitUrlInfos 6;
owner = lib.elemAt gitUrlInfos 3;
repo = lib.elemAt gitUrlInfos 4;
version = dependencyObject.version;
};
path = dependencyObject:
{
version = dependencyObject.version;
path = lib.last (lib.splitString "@link:" dependencyObject.yarnName);
type = "path";
};
fetchurl = dependencyObject:
{
type = "fetchurl";
version = dependencyObject.version;
hash =
if dependencyObject ? integrity then
dependencyObject.integrity
else
throw "Missing integrity for ${dependencyObject.yarnName}";
url = lib.head (lib.splitString "#" dependencyObject.resolved);
};
};
};
# From a given list of paths, this function returns all paths which can be processed by this translator.
# This allows the framework to detect if the translator is compatible with the given inputs
# to automatically select the right translator.
compatiblePaths =
{
inputDirectories,
inputFiles,
}@args:
{
inputDirectories = lib.filter
(utils.containsMatchingFile [ ''.*yarn\.lock'' ''.*package.json'' ])
args.inputDirectories;
inputFiles = [];
};
# If the translator requires additional arguments, specify them here.
# 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.
specialArgs = {
dev = {
description = "Whether to include development dependencies";
type = "flag";
};
optional = {
description = "Whether to include optional dependencies";
type = "flag";
};
peer = {
description = "Whether to include peer dependencies";
type = "flag";
};
};
}

View File

@ -85,7 +85,7 @@
dependencies =
dependencyAttrs.dependencies or []
++ (lib.optionals optional (dependencyAttrs.optionalDependencies or []));
graph = lib.forEach dependencies (dependency:
depList = lib.forEach dependencies (dependency:
builtins.head (
lib.mapAttrsToList
(name: value:
@ -99,7 +99,7 @@
)
);
in
lib.nameValuePair ("${name}#${dependencyAttrs.version}") graph
lib.nameValuePair ("${name}#${dependencyAttrs.version}") depList
)
parsedLock
)

View File

@ -13,15 +13,23 @@ let
b = builtins;
overrideUtils = callPackageDream ./overrideUtils.nix {};
overrideUtils = callPackageDream ./override.nix {};
dreamLockUtils = callPackageDream ./dream-lock.nix {};
translatorUtils = callPackageDream ./translator.nix {};
in
dreamLockUtils
//
overrideUtils
//
translatorUtils
//
rec {
readDreamLock = callPackageDream ./readDreamLock.nix {};
readTextFile = file: lib.replaceStrings [ "\r\n" ] [ "\n" ] (b.readFile file);

28
src/utils/dream-lock.nix Normal file
View File

@ -0,0 +1,28 @@
{
lib,
...
}:
let
b = builtins;
readDreamLock =
{
dreamLock,
}@args:
let
lock =
if b.isPath dreamLock then
b.fromJSON (b.readFile dreamLock)
else
dreamLock;
mainPackage = lock.generic.mainPackage;
dependencyGraph = lock.generic.dependencyGraph;
in
lock;
in
{
inherit readDreamLock;
}

View File

@ -1,25 +0,0 @@
{
lib,
...
}:
let
b = builtins;
in
{
dreamLock,
}@args:
let
lock =
if b.isPath dreamLock then
b.fromJSON (b.readFile dreamLock)
else
dreamLock;
mainPackage = lock.generic.mainPackage;
dependencyGraph = lock.generic.dependencyGraph;
in
lock

98
src/utils/translator.nix Normal file
View File

@ -0,0 +1,98 @@
{
lib,
...
}:
let
b = builtins;
simpleTranslate = translatorName:
{
mainPackageName,
mainPackageVersion,
mainPackageDependencies,
buildSystemName,
buildSystemAttrs,
inputData,
serializePackages,
getOriginalID,
getName,
getVersion,
getDependencies,
getSourceType,
sourceConstructors,
mainPackageSource ? {
type = "unknown";
}
}:
let
serializedPackagesList = serializePackages inputData;
allDependencies = b.foldl'
(result: pkgData: lib.recursiveUpdate result {
"${getName pkgData}" = {
"${getVersion pkgData}" = pkgData;
};
})
{}
serializedPackagesList;
allDependenciesByOriginalID = b.foldl'
(result: pkgData: lib.recursiveUpdate result {
"${getOriginalID pkgData}" = pkgData;
})
{}
serializedPackagesList;
sources = b.foldl'
(result: pkgData: lib.recursiveUpdate result {
"${getName pkgData}#${getVersion pkgData}" =
sourceConstructors."${getSourceType pkgData}" pkgData;
})
{}
serializedPackagesList;
dependencyGraph =
{
"${mainPackageName}#${mainPackageVersion}" =
mainPackageDependencies inputData;
}
//
lib.listToAttrs
(lib.forEach
serializedPackagesList
(pkgData: lib.nameValuePair
"${getName pkgData}#${getVersion pkgData}"
(b.map
(depNameVer: "${depNameVer.name}#${depNameVer.version}")
(getDependencies pkgData getDepByNameVer getDepByOriginalID))));
getDepByOriginalID = id:
allDependenciesByOriginalID."${id}";
getDepByNameVer = name: version:
allDependencies."${name}"."${version}";
in
{
inherit sources;
generic = {
inherit dependencyGraph;
buildSystem = buildSystemName;
mainPackage = "${mainPackageName}#${mainPackageVersion}";
sourcesCombinedHash = null;
translator = translatorName;
};
# build system specific attributes
buildSystem = buildSystemAttrs;
};
in
{
inherit simpleTranslate;
}