Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(build): use known working node version for the installer #268

Merged
merged 2 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-*'
workflow_dispatch:


jobs:
run-build:
Expand All @@ -23,7 +25,14 @@ jobs:
run: Copy-Item (Get-Command node.exe | Select-Object -ExpandProperty Definition) .
- run: npm test
- run: npm run build
- name: Archive build artifact
if: github.ref_type == 'branch'
uses: actions/upload-artifact@v3
with:
name: Installer
path: "build/out/NodistSetup-*.exe"
- name: Create release draft
if: github.ref_type == 'tag'
uses: ncipollo/release-action@v1
with:
artifacts: "build/out/NodistSetup-*.exe"
Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
name: run-tests

on:
push:
branches:
- '**'
tags-ignore:
- '**'
pull_request:

jobs:
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,9 @@ MIT License

## Changelog

v0.10.1
v0.10.2
* Fix building shims (for newer go versions) by using go modules
* Fix npm shim to use correct node version
* Add npx shim (works only for npm versions that ship with npx)
* Fix getting latest npm version
* Use last available x86 version for building (first node 18 versions are not available for x86)
Expand Down
46 changes: 13 additions & 33 deletions build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var fs = require('fs');
var mkdirp = require('mkdirp');
var ncp = require('ncp');
var path = require('path');
var semver = require('semver');
var recursiveReaddir = require('recursive-readdir');
var request = require('request');
var rimraf = require('rimraf');
Expand Down Expand Up @@ -83,6 +84,7 @@ var npm = new (require('../lib/npm'))({nodistDir: stagingDir});
//default npm version to the latest at the time of writing
var npmVersion = '6.14.16';
var nodeVersion = '16.15.0';
var maxNodeMainVersion = '^20';

var versionPathx86 = '';
var versionPathx64 = '';
Expand All @@ -102,31 +104,14 @@ console.log('Welcome to the Nodist Builder');
console.log(' before going further we need to prep our staging folder');

//defining helper functions
function getLatestNodeVersionFor(nodeVersions, fileType) {
function getLatestUsableNodeVersionFor(nodeVersions, fileType) {
for (var key in nodeVersions) {
if (nodeVersions[key].files.includes(fileType)) {
return nodeVersions[key].version;
if (nodeVersions[key].files.includes(fileType) && semver.satisfies(nodeVersions[key].version, maxNodeMainVersion)) {
return { nodeVersion: nodeVersions[key].version, npmVersion: nodeVersions[key].npm };
}
}
}

async function resolveLinkedWorkspaces(dirPath) {
let movedLinks = 0;
const files = await fs.readdirAsync(dirPath, { withFileTypes: true });
const dirPromises = [];
for (const file of files) {
const filePath = path.join(dirPath, file.name);
if (file.isSymbolicLink()) {
const linkTarget = await fs.readlinkAsync(filePath);
await fs.renameAsync(path.join(dirPath, linkTarget), filePath);
movedLinks++;
} else if (file.isDirectory()) {
dirPromises.push(resolveLinkedWorkspaces(filePath));
}
}
return (await Promise.all(dirPromises)).reduce((sum, num) => sum + num, movedLinks);
}

//start by clearing the staging and tmp folders
P.all([
rimraf(outDir),
Expand Down Expand Up @@ -193,19 +178,19 @@ P.all([
console.log('Finished copying static files');

console.log('Compiling node shim');
return exec('go build -o "'+stagingBin +'/node.exe" shim-node.go', { cwd: goSrcDir });
return exec('go build -o "'+stagingBin +'/node.exe" ./cmd/node', { cwd: goSrcDir });
})
.then(function(){
console.log('Done compiling node shim');

console.log('Compiling npm shim');
return exec('go build -o "'+stagingBin +'/npm.exe" shim-npm.go', { cwd: goSrcDir });
return exec('go build -o "'+stagingBin +'/npm.exe" ./cmd/npm', { cwd: goSrcDir });
})
.then(function(){
console.log('Done compiling npm shim');

console.log('Compiling npx shim');
return exec('go build -o "'+stagingBin +'/npx.exe" shim-npx.go', { cwd: goSrcDir });
return exec('go build -o "'+stagingBin +'/npx.exe" ./cmd/npx', { cwd: goSrcDir });
})
.then(function() {
console.log('Done compiling npx shim');
Expand All @@ -217,7 +202,7 @@ P.all([
});
})
.then(function(res){
nodeVersion = getLatestNodeVersionFor(res.body, 'win-x86-exe');
({ nodeVersion, npmVersion } = getLatestUsableNodeVersionFor(res.body, 'win-x86-exe'));
nodeLatestUrlx86 = nodeLatestUrlx86.replace('VERSION',nodeVersion);
nodeLatestUrlx64 = nodeLatestUrlx64.replace('VERSION',nodeVersion);
console.log('Latest version of Node ' + nodeVersion);
Expand Down Expand Up @@ -253,14 +238,9 @@ P.all([
);
})
.then(function(){
console.log('Figure out the latest version of NPM');
return npm.latestVersion();
})
.then(function(version){
npmVersion = version;
var downloadLink = npm.downloadUrl(version);
console.log('Determined latest NPM as ' + npmVersion);
console.log('Downloading latest NPM from ' + downloadLink);
var downloadLink = npm.downloadUrl(npmVersion);
console.log('Determined matching NPM as ' + npmVersion);
console.log('Downloading matching NPM from ' + downloadLink);
return Promise.resolve()
.then(() => mkdirp(stagingNpmDir+'/'+npmVersion.replace('v','')))
.then(() => {
Expand Down Expand Up @@ -291,7 +271,7 @@ P.all([
})
.then(function() {
console.log('Installation complete');
return resolveLinkedWorkspaces(path.join(stagingNpmDir, npmVersion.replace('v', ''), 'node_modules'));
return helper.resolveLinkedWorkspaces(path.join(stagingNpmDir, npmVersion.replace('v', '')), false);
})
.then(function(movedLinks) {
if (movedLinks) {
Expand Down
52 changes: 52 additions & 0 deletions lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ var path = require('path');
var promisePipe = require('promisepipe');
var ProgressBar = require('progress');
var request = require('request');
const P = require('bluebird');
var debug = require('debug')('nodist:build')

//make some promising APIs
P.promisifyAll(fs);

/**
* Copy File
* @param {string} source
Expand Down Expand Up @@ -141,3 +145,51 @@ exports.downloadFileStream = function downloadFileStream(url) {
});
return req
}

/**
* Npm version >= 18 using symlinks that do not work in windows and have to be fixed
* this function replace the broken symlinks with NTFS junction or move the directory if junctions are not supported
*
* @param {string} dirPath
* @param {boolean} preferSymlink
* @returns {Promise<number>} number of changed links
*/
exports.resolveLinkedWorkspaces = async function resolveLinkedWorkspaces(dirPath, preferSymlink = true) {
let fixedLinks = 0;
const packageLockJson = JSON.parse(fs.readFileSync(path.join(dirPath, 'package-lock.json')).toString());
await Promise.all(Object.entries(packageLockJson.packages)
.filter(([pkgPath, pkg]) => pkg.link === true)
.map(async ([pkgPath, pkg]) => {

const linkPath = path.join(dirPath, pkgPath);


if (await fs.accessAsync(linkPath, fs.constants.F_OK).then(() => true).catch(() => false)) {
await fs.unlinkAsync(linkPath);
}

let linkCreated = false;
if (preferSymlink) {
const linkTarget = path.join(
...pkgPath.split('/').slice(0, -1).map(() => '..'),
pkg.resolved
);
debug('Create symlink for ', linkPath, 'with target', linkTarget);
try {
await fs.symlinkAsync(linkTarget, linkPath, 'junction');
linkCreated = true;
} catch (e) {
debug('Link ', linkPath, 'could not be created');
}
}
if (!linkCreated) {
const from = path.join(dirPath, pkg.resolved);
debug('Move', from, 'to', linkPath);
await fs.renameAsync(from, linkPath);
}

fixedLinks++;
}));

return fixedLinks;
};
37 changes: 1 addition & 36 deletions lib/npm.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,41 +36,6 @@ module.exports = npmist

var NPMIST = npmist.prototype

/**
* Npm version >= 18 using symlinks that do not work in windows and have to be fixed
* this function replace the broken symlinks with NTFS junction or move the directory if junctions are not supported
*
* @param {string} dirPath
* @returns {Promise<number>} number of changed links
*/
async function resolveLinkedWorkspaces(dirPath) {
let fixedLinks = 0;
const packageLockJson = JSON.parse(fs.readFileSync(path.join(dirPath, 'package-lock.json')).toString());
await Promise.all(Object.entries(packageLockJson.packages)
.filter(([pkgPath, pkg]) => pkg.link === true)
.map(async ([pkgPath, pkg]) => {
const linkTarget = path.join(
...pkgPath.split('/').slice(0, -1).map(() => '..'),
pkg.resolved
);
const linkPath = path.join(dirPath, pkgPath);

debug('Create symlink for ', linkPath, 'with target', linkTarget);
if (await fs.accessAsync(linkPath, fs.constants.F_OK).then(() => true).catch(() => false)) {
await fs.unlinkAsync(linkPath);
}

try {
await fs.symlinkAsync(linkTarget, linkPath, 'junction');
} catch (e) {
await fs.renameAsync(path.join(dirPath, linkTarget), linkPath);
}
fixedLinks++;
}));

return fixedLinks;
}

/**
* List available NPM versions
* @return {string}
Expand Down Expand Up @@ -331,7 +296,7 @@ NPMIST.install = function(v,done){
.then(() => {
if (semver.gte(version, '8.0.0')) {
debug('Fix symlinks for npm version >= 8');
return resolveLinkedWorkspaces(path.join(archivePath))
return buildHelper.resolveLinkedWorkspaces(path.join(archivePath))
.then(fixedLinks => {
debug(`Fixed ${fixedLinks} symlinks for npm node_modules`);
});
Expand Down
16 changes: 16 additions & 0 deletions src/cmd/node/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"os"
"os/exec"

nodist "github.com/nodists/nodist/internal"
)

func main() {
err, nodebin, _, _ := nodist.DetermineNodeExecutable("node")

// Run node!
cmd := exec.Command(nodebin, os.Args[1:]...)
nodist.ExecuteCommand(cmd, err)
}
23 changes: 23 additions & 0 deletions src/cmd/npm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"os"
"os/exec"

nodist "github.com/nodists/nodist/internal"
)

func main() {
err, nodebin, dir, nodeVersion := nodist.DetermineNodeExecutable("node")

path, _ := nodist.DetermineNpmPath(dir, nodeVersion)

npmbin := path + "/bin/npm-cli.js"

args := []string{npmbin}
args = append(args, os.Args[1:]...)

// Run npm!
cmd := exec.Command(nodebin, args...)
nodist.ExecuteCommand(cmd, err)
}
30 changes: 30 additions & 0 deletions src/cmd/npx/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"errors"
"fmt"
"os"
"os/exec"

nodist "github.com/nodists/nodist/internal"
)

func main() {
err, nodebin, dir, nodeVersion := nodist.DetermineNodeExecutable("node")

path, npmVersion := nodist.DetermineNpmPath(dir, nodeVersion)

npxbin := path + "/bin/npx-cli.js"

if _, err := os.Stat(npxbin); errors.Is(err, os.ErrNotExist) {
fmt.Println("Npx not found for selected npm version:", npmVersion)
os.Exit(47)
}

args := []string{npxbin}
args = append(args, os.Args[1:]...)

// Run npx!
cmd := exec.Command(nodebin, args...)
nodist.ExecuteCommand(cmd, err)
}
2 changes: 1 addition & 1 deletion src/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/nodists/nodist

go 1.12
go 1.20

require (
github.com/marcelklehr/semver v0.0.0-20160716173943-4590ea5640ed // indirect
Expand Down
Loading