Skip to content

Commit

Permalink
atomic-web: pnpm imported
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Leightcap <[email protected]>
  • Loading branch information
jleightcap committed Sep 30, 2023
1 parent da86490 commit f7b84d6
Show file tree
Hide file tree
Showing 74 changed files with 8,405 additions and 0 deletions.
1 change: 1 addition & 0 deletions all-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
in rec {
atomic-cli = callPackage ./pkgs/atomic-cli {};
atomic-server = callPackage ./pkgs/atomic-server {};
atomic-web = callPackage ./pkgs/atomic-web {};
flarum = callPackage ./pkgs/flarum {};
gnunet-messenger-cli = callPackage ./pkgs/gnunet-messenger-cli {};
kikit = callPackage ./pkgs/kikit {};
Expand Down
16 changes: 16 additions & 0 deletions pkgs/atomic-web/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{ pkgs, fetchFromGitHub, ... }:
with (import ./pnpm2nix-lockfile-6.0 { inherit pkgs; });

mkPnpmPackage rec {
version = "v0.34.5";

src = fetchFromGitHub {
# https://github.com/atomicdata-dev/atomic-server.git
owner = "atomicdata-dev";
repo = "atomic-server";
rev = version;
hash = "sha256-rqucTVvlXe9CXPsZ2cNzyDK9onXw/H96PzWpTR7Fdl4=";
};

sourceRoot = "${src}/browser";
}
2 changes: 2 additions & 0 deletions pkgs/atomic-web/pnpm2nix-lockfile-6.0/.travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
language: nix
script: make test
7 changes: 7 additions & 0 deletions pkgs/atomic-web/pnpm2nix-lockfile-6.0/COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2018 Adam Hose

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6 changes: 6 additions & 0 deletions pkgs/atomic-web/pnpm2nix-lockfile-6.0/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.PHONY: all test

test:
nix-build --no-out-link ./tests/default.nix --show-trace

all: test
53 changes: 53 additions & 0 deletions pkgs/atomic-web/pnpm2nix-lockfile-6.0/README.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
[[https://travis-ci.org/nix-community/pnpm2nix][https://travis-ci.org/nix-community/pnpm2nix.svg?branch=master]]

* pnpm2nix
Loads =pnpm='s shrinkwrap.yaml into nix expressions.

** Example =default.nix=
#+begin_src nix
with (import <nixpkgs> {});
with (import /path/to/pnpm2nix { inherit pkgs; });

mkPnpmPackage {
src = ./.;
# These default to src/package.json & src/shrinkwrap.yaml
# packageJSON = ./package.json;
# shrinkwrapYML = ./shrinkwrap.yaml;
}
#+END_SRC

More comprehensive examples can be found in the [[file://tests/][tests]].

** Managing development environments with pnpm2nix

*** default.nix
#+begin_src nix
with (import <nixpkgs> {});
with (import /path/to/pnpm2nix { inherit pkgs; });

mkPnpmPackage {
src = ./.;
}
#+END_SRC

*** shell.nix
#+begin_src nix
with (import <nixpkgs> {});
with (import /path/to/pnpm2nix { inherit pkgs; });

mkShell {
buildInputs = [
(mkPnpmEnv (import ./default.nix))
];
}
#+END_SRC

** Caveats and known bugs
[[https://github.com/pnpm/pnpm/issues/1035][pnpm does not currently include checksums for tarballs]]

Until this is fixed in =pnpm= github dependencies won't work unless you opt in to impure builds.

This is currently pre-alpha software, it might eat your kittens.

** License
=pnpm2nix= is released under the terms of the MIT license.
223 changes: 223 additions & 0 deletions pkgs/atomic-web/pnpm2nix-lockfile-6.0/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
{ pkgs ? import <nixpkgs> {}
, nodejs ? pkgs.nodejs
, nodePackages ? pkgs.nodePackages
, node-gyp ? nodePackages.node-gyp
} @modArgs:

# Scope mkPnpmDerivation
with (import ./derivation.nix {
inherit pkgs nodejs nodePackages node-gyp;
});
with pkgs;

let

# Replace disallowed characters from package name
# @acme/package -> acme-package
safePkgName = name: builtins.replaceStrings ["@" "/"] ["" "-"] name;

rewritePnpmLock = import ./pnpmlock.nix {
inherit pkgs nodejs nodePackages;
};

importYAML = name: yamlFile: (lib.importJSON ((pkgs.runCommandNoCC name {} ''
mkdir -p $out
${pkgs.yaml2json}/bin/yaml2json < ${yamlFile} | ${pkgs.jq}/bin/jq -a '.' > $out/pnpmlock.json
'').outPath + "/pnpmlock.json"));

overrideDrv = (overrides: drv:
if (lib.hasAttr drv.pname overrides) then
(overrides."${drv.pname}" drv)
else drv);

defaultPnpmOverrides = import ./overrides.nix {
inherit pkgs nodejs nodePackages;
};

in {

inherit defaultPnpmOverrides;

# Create a nix-shell friendly development environment
mkPnpmEnv = drv: let
pkgJSON = writeText "${drv.name}-package-json" (builtins.toJSON drv.passthru.packageJSON);
envDrv = (drv.override {linkDevDependencies = true;}).overrideAttrs(oldAttrs: {
propagatedBuildInputs = [
# Avoid getting npm and its deps in environment
(drv.passthru.nodejs.override { enableNpm = false; })
# Users probably want pnpm
nodePackages.pnpm
];
srcs = [];
src = pkgs.runCommandNoCC "pnpm2nix-dummy-env-src" {} ''
mkdir $out
'';
# Remove original nodejs from inputs, it's now propagated and stripped from npm
buildInputs = builtins.filter (x: x != drv.passthru.nodejs) oldAttrs.buildInputs;
outputs = [ "out" ];
buildPhase = "true";
postUnpack = ''
mkdir -p node_modules/${oldAttrs.pname}
ln -s ${pkgJSON} node_modules/${oldAttrs.pname}/package.json
'';
installPhase = ''
mkdir -p $out
mv node_modules $out
'';
});
in makeSetupHook {
deps = envDrv.buildInputs ++ envDrv.propagatedBuildInputs;
} (writeScript "pnpm-env-hook.sh" ''
export NODE_PATH=${lib.getLib envDrv}/node_modules
'');

mkPnpmPackage = {
src,
packageJSON ? src + "/package.json",
pnpmLock ? src + "/pnpm-lock.yaml",
overrides ? defaultPnpmOverrides,
allowImpure ? false,
linkDevDependencies ? false,
...
} @args:
let
specialAttrs = [ "src" "packageJSON" "pnpmLock" "overrides" "allowImpure" ];

package = lib.importJSON packageJSON;
pname = safePkgName package.name;
version = package.version;
name = pname + "-" + version;

pnpmlock = let
lock = importYAML "${pname}-pnpmlock-${version}" pnpmLock;
in rewritePnpmLock lock;

# Convert pnpm package entries to nix derivations
packages = let

linkPath = src: link: src + ("/" + (lib.removePrefix "link:" link));

# Normal (registry/git) packages
nonLocalPackages = lib.mapAttrs (n: v: (let
drv = mkPnpmModule v;
overriden = overrideDrv overrides drv;
in overriden)) pnpmlock.packages;

# Local (link:) packages
localPackages = let
attrNames = builtins.filter (a: lib.hasPrefix "link:" a) pnpmlock.dependencies;

# Try to resolve relative path and import package.json to read package name
resolvePkgName = (link: (lib.importJSON ((linkPath src link) + "/package.json")).name);
resolve = (link: lib.nameValuePair link (resolvePkgName link));
resolvedSpecifiers = lib.listToAttrs (map (resolve) attrNames);

in lib.mapAttrs (n: v: let
# Note: src can only be local path for link: dependencies
pkgPath = linkPath src n;
pkg = ((import ./default.nix modArgs).mkPnpmPackage {
inherit allowImpure;
src = pkgPath;
packageJSON = pkgPath + "/package.json";
pnpmLock = pkgPath + "/pnpm-lock.yaml";
}).overrideAttrs(oldAttrs: {
src = wrapRawSrc pkgPath oldAttrs.pname;
});
in pkg) resolvedSpecifiers;
in nonLocalPackages // localPackages;

# Wrap sources in a directory named the same as the node_modules/ path
wrapRawSrc = src: pname: (stdenv.mkDerivation (let
name = safePkgName pname;
in {
name = "pnpm2nix-source-${name}";
inherit src;

# Make dirty tars work
TAR_OPTIONS = "--delay-directory-restore";
# We're still making them writable, but we need to run something else first
dontMakeSourcesWritable = true;
# Make directories have +x and everything writable
postUnpack = ''
find "$sourceRoot" -type d -exec chmod u+x {} \;
chmod -R u+w -- "$sourceRoot"
'';

dontBuild = true;
configurePhase = ":";
fixupPhase = ":";
installPhase = ''
mkdir -p $out/${pname}
cp -a * $out/${pname}/
'';
}));
wrapSrc = pkgInfo: let
integrity = lib.splitString "-" pkgInfo.resolution.integrity;
shaType = lib.elemAt integrity 0;
shaSum = lib.elemAt integrity 1;
tarball = (lib.lists.last (lib.splitString "/" pkgInfo.pname)) + "-" + pkgInfo.version + ".tgz";
registry = if builtins.hasAttr "registry" pnpmlock then pnpmlock.registry else "https://registry.npmjs.org/";
src = (if (lib.hasAttr "integrity" pkgInfo.resolution) then
(pkgs.fetchurl {
url = if (lib.hasAttr "tarball" pkgInfo.resolution)
then pkgInfo.resolution.tarball
else "${registry}${pkgInfo.pname}/-/${tarball}";
"${shaType}" = shaSum;
}) else if (lib.hasAttr "commit" pkgInfo.resolution) then builtins.fetchGit {
url = pkgInfo.resolution.repo;
rev = pkgInfo.resolution.commit;
} else if allowImpure then fetchTarball {
# Note: Resolved tarballs(github revs for example)
# does not yet have checksums
# https://github.com/pnpm/pnpm/issues/1035
url = pkgInfo.resolution.tarball;
} else throw "No download method found for package ${pkgInfo.name}, consider adding `allowImpure = true;`");
in wrapRawSrc src pkgInfo.pname;

mkPnpmModule = pkgInfo: let
hasCycle = (builtins.length pkgInfo.constituents) > 1;

# These attrs have already been created in pre-processing
# Cyclic dependencies has deterministic ordering so they will end up with the exact same attributes
name = builtins.substring 0 207 (lib.concatStringsSep "-" (builtins.map (attr: pnpmlock.packages."${attr}".name) pkgInfo.constituents));
version = if !hasCycle then pkgInfo.version else "cyclic";
pname = lib.concatStringsSep "-" (builtins.map (attr: pnpmlock.packages."${attr}".pname) pkgInfo.constituents);

srcs = (builtins.map (attr: wrapSrc pnpmlock.packages."${attr}") pkgInfo.constituents);

deps = builtins.map (attrName: packages."${attrName}")
# Get all dependencies from cycle
(lib.unique (lib.flatten (builtins.map
(attr: pnpmlock.packages."${attr}".dependencies) pkgInfo.constituents)));

in
mkPnpmDerivation {
inherit deps;
attrs = { inherit name srcs pname version; };
linkDevDependencies = false;
};

in
assert pnpmlock.lockfileVersion == "6.0";
(mkPnpmDerivation {
deps = (builtins.map
(attrName: packages."${attrName}")
(pnpmlock.dependencies ++ pnpmlock.optionalDependencies));

devDependencies = builtins.map
(attrName: packages."${attrName}") pnpmlock.devDependencies;

inherit linkDevDependencies;

passthru = {
packageJSON = package;
};

# Filter "special" attrs we know how to interpret, merge rest to drv attrset
attrs = ((lib.filterAttrs (k: v: !(lib.lists.elem k specialAttrs)) args) // {
srcs = [ (wrapRawSrc src pname) ];
inherit name pname version;
});
});

}
Loading

0 comments on commit f7b84d6

Please sign in to comment.