Skip to content

Commit 6dcbfd3

Browse files
authored
Merge pull request #795 from avh4/new-npm
Automate the new npm packages
2 parents c6c0199 + b409a5e commit 6dcbfd3

16 files changed

+517
-40
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Check nixkpgs packages
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
nixpkgsChannel:
7+
required: true
8+
default: 'nixpkgs-unstable'
9+
package:
10+
required: true
11+
default: 'elmPackages.elm-format'
12+
13+
jobs:
14+
build:
15+
strategy:
16+
matrix:
17+
os:
18+
- ubuntu-latest
19+
- macOS-latest
20+
21+
name: ${{ matrix.os }} ${{ github.event.inputs.nixpkgsChannel }}
22+
runs-on: ${{ matrix.os }}
23+
24+
steps:
25+
- uses: cachix/install-nix-action@v19
26+
with:
27+
nix_path: nixpkgs=channel:${{ github.event.inputs.nixpkgsChannel }}
28+
- name: Environment info
29+
run: |
30+
echo -n 'nixpkgs '; nix-instantiate --eval -E '(import <nixpkgs> {}).lib.version'
31+
nix --version
32+
- name: Fetch packages
33+
run: |
34+
nix-shell -p "${{ github.event.inputs.package }}" --run true
35+
- name: Check elm-format
36+
run: |
37+
nix-shell -p "${{ github.event.inputs.package }}" --run 'elm-format && file $(which elm-format)'
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Check npm packages
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
npmPackage:
7+
required: true
8+
default: 'elm-format@latest'
9+
10+
jobs:
11+
build:
12+
strategy:
13+
matrix:
14+
os:
15+
- ubuntu-latest
16+
- windows-latest
17+
- macOS-latest
18+
19+
name: ${{ matrix.os }} ${{ github.event.inputs.npmPackage }}
20+
runs-on: ${{ matrix.os }}
21+
22+
steps:
23+
- name: Environment info
24+
run: |
25+
echo -n 'node: '; node --version
26+
echo -n 'npm: '; npm --version
27+
- name: Set up workspace
28+
run: |
29+
echo '{}' > package.json
30+
- name: Install ${{ github.event.inputs.npmPackage }}
31+
run: |
32+
npm install --save-dev "${{ github.event.inputs.npmPackage }}"
33+
- name: Check elm-format
34+
shell: bash # workaround for https://github.com/MicrosoftDocs/PowerShell-Docs/issues/2361
35+
run: |
36+
npm list -a
37+
./node_modules/.bin/elm-format
38+
find . -type f -name 'elm-format*' -print0 | xargs -0 file

PUBLISHING.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,24 @@ Then `cd elm-tooling`, push the resulting branch, and make a PR to <https://gith
5959

6060
## NPM
6161

62+
1. `cd package/npm`
63+
1. Create `elm-format-<new-version>.nix`:
64+
- Fill out the release info
65+
- `prerelease` is optional and should have the format `(alpha|beta|rc).[0-9]+` if present
66+
- `scope` is optional and will create a scoped top-level package (don't set it for normal releases)
67+
- `binaryPackageScope` is the scope that the binary packages will be published under
68+
- Fill out the `binaries` info for each supported platform
69+
- To get the sha256, run `nix-prefetch fetchzip --url <release url>`
70+
- `v` is the sub-patch version for this binary and can be incremented as needed (but should be reset to `"1"` on each new elm-format version)
71+
1. `nix-shell --pure`
72+
1. For each folder in `./elm-format-*-*`, go to the folder and `./publish.sh`
73+
74+
Then publish the main npm package:
75+
6276
```sh
63-
cd package/npm
77+
cd elm-format
6478
npm install
65-
# for experimental releases
66-
# npm publish --tag exp
67-
npm publish
68-
npm dist-tag add elm-format@<new version> exp
69-
npm dist-tag add elm-format@<new version> latest-0.18.0
70-
npm dist-tag add elm-format@<new version> latest-0.19.0
71-
npm dist-tag add elm-format@<new version> latest-0.19.1
79+
./publish.sh
7280
```
7381

7482

package/npm/.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
/node_modules/
2-
/bin/
3-
/unpacked_bin/
2+
/result

package/npm/base-package.nix

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
{
2+
stdenvNoCC,
3+
substituteAll,
4+
lib,
5+
writeShellScript,
6+
...
7+
}: {
8+
name,
9+
version,
10+
prerelease ? null,
11+
npmScope,
12+
binaryPackageScope,
13+
binaryPackages,
14+
experimental,
15+
elmVersions,
16+
}: let
17+
concatLines = lib.concatMapStrings (s: s + "\n");
18+
19+
npmPackageName =
20+
if npmScope == null
21+
then name
22+
else "@${npmScope}/${name}";
23+
24+
npmVersion =
25+
if prerelease == null
26+
then version
27+
else "${version}-${prerelease}";
28+
29+
package-json = let
30+
base = builtins.fromJSON (builtins.readFile ./package.json);
31+
in
32+
base
33+
// {
34+
name = npmPackageName;
35+
version = npmVersion;
36+
optionalDependencies = builtins.listToAttrs (lib.mapAttrsToList (key: p: {
37+
name = p.npmPackageName;
38+
value = p.npmPackageVersion;
39+
})
40+
binaryPackages);
41+
};
42+
43+
packageFiles = package-json.files;
44+
45+
copyTemplateFile = file: let
46+
template = ./. + ("/" + file);
47+
rendered = substituteAll {
48+
src = template;
49+
inherit name npmPackageName binaryPackageScope;
50+
};
51+
in ''
52+
cp ${rendered} $out/${file}
53+
'';
54+
55+
publish-sh = let
56+
distTag = tag: ''npm dist-tag add ${npmPackageName}@${npmVersion} ${tag}'';
57+
58+
distTagElmVersion = elmVersion:
59+
distTag "latest-${elmVersion}";
60+
61+
primaryTag =
62+
if prerelease != null
63+
then "rc"
64+
else if experimental
65+
then "exp"
66+
else "latest";
67+
68+
extraPublishArgs =
69+
if npmScope == null
70+
then ""
71+
else "--access=public";
72+
in
73+
writeShellScript "publish.sh"
74+
(concatLines [
75+
''
76+
set -euxo pipefail
77+
npm publish --tag ${primaryTag} ${extraPublishArgs}
78+
''
79+
(
80+
if prerelease == null
81+
then ''
82+
${distTag "exp"}
83+
${concatLines (map distTagElmVersion elmVersions)}
84+
''
85+
else ""
86+
)
87+
]);
88+
in
89+
stdenvNoCC.mkDerivation {
90+
name = "${name}-${npmVersion}";
91+
92+
phases = ["installPhase"];
93+
installPhase = ''
94+
mkdir -p $out
95+
cp ${builtins.toFile "package.json" (builtins.toJSON package-json)} $out/package.json
96+
mkdir -p $out/bin
97+
${copyTemplateFile "README.md"}
98+
${concatLines (map copyTemplateFile packageFiles)}
99+
cp "${publish-sh}" "$out/publish.sh"
100+
'';
101+
}

package/npm/bin/elm-format

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env node
2+
var spawn = require("child_process").spawn;
3+
4+
var binPath = require("../binary.js")();
5+
6+
spawn(binPath, process.argv.slice(2), { stdio: "inherit" }).on(
7+
"exit",
8+
process.exit
9+
);

package/npm/binary-package.nix

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
stdenvNoCC,
3+
writeShellScript,
4+
...
5+
}: {
6+
name,
7+
platform,
8+
baseVersion,
9+
binaryVersion,
10+
npmScope,
11+
projectUrl ? "https://github.com/avh4/elm-format",
12+
binarySrc,
13+
}: let
14+
platformInfo = (import ./platform-info.nix)."${platform}";
15+
inherit (platformInfo) binExt;
16+
npmPlatformString = with platformInfo.npm; "${os}-${cpu}";
17+
18+
packageName = "${name}-${npmPlatformString}";
19+
npmPackageName = "@${npmScope}/${packageName}";
20+
npmPackageVersion = "${baseVersion}-${binaryVersion}";
21+
22+
package-json = builtins.toFile "package.json" (builtins.toJSON {
23+
name = npmPackageName;
24+
version = npmPackageVersion;
25+
description = "The ${platform} binary for ${name}.";
26+
repository = projectUrl;
27+
license = "BSD-3-Clause";
28+
os = [platformInfo.npm.os];
29+
cpu = [platformInfo.npm.cpu];
30+
files = ["elm-format${binExt}"];
31+
});
32+
33+
readme = builtins.toFile "README.md" ''
34+
This is the ${platform} binary for [${name}](${projectUrl}).
35+
'';
36+
37+
publish-sh =
38+
writeShellScript "publish.sh"
39+
''
40+
set -euxo pipefail
41+
npm publish --access=public
42+
'';
43+
in
44+
stdenvNoCC.mkDerivation {
45+
name = "${packageName}-${npmPackageVersion}";
46+
47+
phases = ["unpackPhase" "installPhase"];
48+
src = binarySrc;
49+
installPhase = ''
50+
mkdir -p $out
51+
cp "${package-json}" "$out/package.json"
52+
cp "${readme}" "$out/README.md"
53+
cp -L "elm-format${binExt}" "$out/elm-format${binExt}"
54+
chmod +x "$out/elm-format${binExt}"
55+
cp "${publish-sh}" "$out/publish.sh"
56+
'';
57+
}
58+
// {
59+
inherit npmPackageName npmPackageVersion;
60+
npmUnscopedPackageName = packageName;
61+
}

package/npm/binary.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
var fs = require("fs");
2+
var path = require("path");
3+
var package = require("./package.json");
4+
5+
module.exports = function () {
6+
var os = process.env.BINWRAP_PLATFORM || process.platform;
7+
var arch = process.env.BINWRAP_ARCH || process.arch;
8+
9+
var requested = `${os}-${arch}`;
10+
var current = `${process.platform}-${process.arch}`;
11+
var subPackageName = `@@binaryPackageScope@/@name@-${requested}`;
12+
13+
if (requested !== current) {
14+
console.error(
15+
`WARNING: Using binaries for the requested platform (${requested}) instead of for the actual platform (${current}).`
16+
);
17+
}
18+
19+
if (!(subPackageName in package.optionalDependencies)) {
20+
exitFailure(
21+
`The @npmPackageName@ npm package does not support your platform (${requested}).`
22+
);
23+
}
24+
25+
var fileName = os === "win32" ? "elm-format.exe" : "elm-format";
26+
27+
try {
28+
var subBinaryPath = require.resolve(`${subPackageName}/${fileName}`);
29+
} catch (error) {
30+
if (error && error.code === "MODULE_NOT_FOUND") {
31+
exitFailure(missingSubPackageHelp(subPackageName));
32+
} else {
33+
exitFailure(
34+
`I had trouble requiring the binary package for your platform (${subPackageName}):\n\n${error}`
35+
);
36+
}
37+
}
38+
39+
// Yarn 2 and later ("Berry") always invokes `node` (regardless of configuration)
40+
// so we cannot do any optimizations there.
41+
var isYarnBerry = /\byarn\/(?!1\.)/.test(
42+
process.env.npm_config_user_agent || ""
43+
);
44+
45+
// On Windows, npm always invokes `node` so we cannot do any optimizations there either.
46+
if (os === "win32" || isYarnBerry) {
47+
return subBinaryPath;
48+
}
49+
50+
var binaryPath = path.resolve(__dirname, package.bin["elm-format"]);
51+
var tmpPath = binaryPath + ".tmp";
52+
53+
try {
54+
// Atomically replace the file with a hard link to the binary as an optimization.
55+
fs.linkSync(subBinaryPath, tmpPath);
56+
fs.renameSync(tmpPath, binaryPath);
57+
} catch (error) {
58+
exitFailure(
59+
`I had some trouble writing file to disk. It is saying:\n\n${error}`
60+
);
61+
}
62+
63+
return binaryPath;
64+
};
65+
66+
function exitFailure(message) {
67+
console.error(
68+
`
69+
-- ERROR -----------------------------------------------------------------------
70+
71+
${message}
72+
73+
NOTE: You can avoid npm entirely by downloading directly from:
74+
https://github.com/avh4/elm-format/releases/tag/${package.version}
75+
All this package does is distributing a file from there.
76+
77+
--------------------------------------------------------------------------------
78+
`.trim()
79+
);
80+
process.exit(1);
81+
}
82+
83+
function missingSubPackageHelp(subPackageName) {
84+
return `
85+
I support your platform, but I could not find the binary package (${subPackageName}) for it!
86+
87+
This can happen if you use the "--omit=optional" (or "--no-optional") npm flag.
88+
The "optionalDependencies" package.json feature is used by elm-format to install the correct
89+
binary executable for your current platform. Remove that flag to use elm-format.
90+
91+
This can also happen if the "node_modules" folder was copied between two operating systems
92+
that need different binaries - including "virtual" operating systems like Docker and WSL.
93+
If so, try installing with npm rather than copying "node_modules".
94+
`.trim();
95+
}

package/npm/default.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{pkgs ? import <nixpkgs> {}}:
2+
import ./workspace.nix pkgs (import ./elm-format-0.8.5-test.nix)

0 commit comments

Comments
 (0)