feat(core): load native files from tmp location instead of node_modules (#22648)
This commit is contained in:
parent
45d89d21d4
commit
da1808d36c
@ -17,6 +17,10 @@
|
||||
{
|
||||
"group": ["nx/src/plugins/js*"],
|
||||
"message": "Imports from 'nx/src/plugins/js' are not allowed. Use '@nx/js' instead"
|
||||
},
|
||||
{
|
||||
"group": ["**/native-bindings", "**/native-bindings.js", ""],
|
||||
"message": "Direct imports from native-bindings.js are not allowed. Import from index.js instead."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -25,6 +25,10 @@
|
||||
{
|
||||
"group": ["nx/*"],
|
||||
"message": "Circular import in 'nx' found. Use relative path."
|
||||
},
|
||||
{
|
||||
"group": ["**/native-bindings", "**/native-bindings.js"],
|
||||
"message": "Direct imports from native-bindings.js are not allowed. Import from index.js instead."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -26,7 +26,8 @@ function main() {
|
||||
if (
|
||||
process.argv[2] !== 'report' &&
|
||||
process.argv[2] !== '--version' &&
|
||||
process.argv[2] !== '--help'
|
||||
process.argv[2] !== '--help' &&
|
||||
process.argv[2] !== 'reset'
|
||||
) {
|
||||
assertSupportedPlatform();
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
"executor": "@monodon/rust:napi",
|
||||
"options": {
|
||||
"dist": "packages/nx/src/native",
|
||||
"jsFile": "packages/nx/src/native/index.js",
|
||||
"jsFile": "packages/nx/src/native/native-bindings.js",
|
||||
"release": true
|
||||
},
|
||||
"configurations": {
|
||||
|
||||
@ -1,12 +1,17 @@
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
export function checkForUncommittedChanges() {
|
||||
const gitResult = execSync(`git status --porcelain`);
|
||||
if (gitResult.length > 0) {
|
||||
const gitResult = execSync('git status --porcelain').toString();
|
||||
|
||||
const filteredResults = gitResult
|
||||
.split('\n')
|
||||
.filter((line) => !line.includes('.nx') && line.trim().length > 0);
|
||||
|
||||
if (filteredResults.length > 0) {
|
||||
console.log('❗️ Careful!');
|
||||
console.log('You have uncommitted changes in your repository.');
|
||||
console.log('');
|
||||
console.log(gitResult.toString());
|
||||
console.log(filteredResults.join('\n').toString());
|
||||
console.log('Please commit your changes before running the migrator!');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@ -43,6 +43,25 @@ export async function safelyCleanUpExistingProcess(): Promise<void> {
|
||||
if (daemonProcessJson && daemonProcessJson.processId) {
|
||||
try {
|
||||
process.kill(daemonProcessJson.processId);
|
||||
// we wait for the process to actually shut down before returning
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
let count = 0;
|
||||
const interval = setInterval(() => {
|
||||
try {
|
||||
// sending a signal 0 to a process checks if the process is running instead of actually killing it
|
||||
process.kill(daemonProcessJson.processId, 0);
|
||||
} catch (e) {
|
||||
clearInterval(interval);
|
||||
resolve();
|
||||
}
|
||||
if ((count += 1) > 200) {
|
||||
clearInterval(interval);
|
||||
reject(
|
||||
`Daemon process ${daemonProcessJson.processId} didn't exit after 2 seconds.`
|
||||
);
|
||||
}
|
||||
}, 10);
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
deleteDaemonJsonProcessCache();
|
||||
|
||||
@ -25,8 +25,10 @@ import { safelyCleanUpExistingProcess } from '../cache';
|
||||
import { Hash } from '../../hasher/task-hasher';
|
||||
import { Task, TaskGraph } from '../../config/task-graph';
|
||||
import { ConfigurationSourceMaps } from '../../project-graph/utils/project-configuration-utils';
|
||||
import { DaemonProjectGraphError } from '../daemon-project-graph-error';
|
||||
import { ProjectGraphError } from '../../project-graph/project-graph';
|
||||
import {
|
||||
DaemonProjectGraphError,
|
||||
ProjectGraphError,
|
||||
} from '../../project-graph/error-types';
|
||||
|
||||
const DAEMON_ENV_SETTINGS = {
|
||||
NX_PROJECT_GLOB_CACHE: 'false',
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
import { ConfigurationSourceMaps } from '../project-graph/utils/project-configuration-utils';
|
||||
|
||||
export class DaemonProjectGraphError extends Error {
|
||||
constructor(
|
||||
public errors: any[],
|
||||
readonly projectGraph: ProjectGraph,
|
||||
readonly sourceMaps: ConfigurationSourceMaps
|
||||
) {
|
||||
super(
|
||||
`The Daemon Process threw an error while calculating the project graph. Convert this error to a ProjectGraphError to get more information.`
|
||||
);
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@ import { Task, TaskGraph } from '../../config/task-graph';
|
||||
import { getCachedSerializedProjectGraphPromise } from './project-graph-incremental-recomputation';
|
||||
import { InProcessTaskHasher } from '../../hasher/task-hasher';
|
||||
import { readNxJson } from '../../config/configuration';
|
||||
import { DaemonProjectGraphError } from '../daemon-project-graph-error';
|
||||
import { DaemonProjectGraphError } from '../../project-graph/error-types';
|
||||
|
||||
/**
|
||||
* We use this not to recreated hasher for every hash operation
|
||||
|
||||
@ -33,10 +33,12 @@ import { notifyFileWatcherSockets } from './file-watching/file-watcher-sockets';
|
||||
import { serverLogger } from './logger';
|
||||
import { NxWorkspaceFilesExternals } from '../../native';
|
||||
import { ConfigurationResult } from '../../project-graph/utils/project-configuration-utils';
|
||||
import { DaemonProjectGraphError } from '../daemon-project-graph-error';
|
||||
import { LoadedNxPlugin } from '../../project-graph/plugins/internal-api';
|
||||
import { getPlugins } from './plugins';
|
||||
import { ProjectConfigurationsError } from '../../project-graph/error-types';
|
||||
import {
|
||||
DaemonProjectGraphError,
|
||||
ProjectConfigurationsError,
|
||||
} from '../../project-graph/error-types';
|
||||
|
||||
interface SerializedProjectGraph {
|
||||
error: Error | null;
|
||||
|
||||
@ -2,7 +2,7 @@ import { unlinkSync } from 'fs';
|
||||
import { platform } from 'os';
|
||||
import { join, resolve } from 'path';
|
||||
import { DAEMON_SOCKET_PATH, socketDir } from './tmp-dir';
|
||||
import { DaemonProjectGraphError } from './daemon-project-graph-error';
|
||||
import { DaemonProjectGraphError } from '../project-graph/error-types';
|
||||
|
||||
export const isWindows = platform() === 'win32';
|
||||
|
||||
|
||||
@ -1,268 +1,77 @@
|
||||
const { existsSync, readFileSync } = require('fs')
|
||||
const { join } = require('path')
|
||||
const { join, basename } = require('path');
|
||||
const { copyFileSync, existsSync, mkdirSync } = require('fs');
|
||||
const Module = require('module');
|
||||
const { nxVersion} = require("../utils/versions")
|
||||
const { cacheDir} = require("../utils/cache-directory")
|
||||
|
||||
const { platform, arch } = process
|
||||
const nxPackages = new Set([
|
||||
'@nx/nx-android-arm64',
|
||||
'@nx/nx-android-arm-eabi',
|
||||
'@nx/nx-win32-x64-msvc',
|
||||
'@nx/nx-win32-ia32-msvc',
|
||||
'@nx/nx-win32-arm64-msvc',
|
||||
'@nx/nx-darwin-universal',
|
||||
'@nx/nx-darwin-x64',
|
||||
'@nx/nx-darwin-arm64',
|
||||
'@nx/nx-freebsd-x64',
|
||||
'@nx/nx-linux-x64-musl',
|
||||
'@nx/nx-linux-x64-gnu',
|
||||
'@nx/nx-linux-arm64-musl',
|
||||
'@nx/nx-linux-arm64-gnu',
|
||||
'@nx/nx-linux-arm-gnueabihf',
|
||||
]);
|
||||
|
||||
let nativeBinding = null
|
||||
let localFileExisted = false
|
||||
let loadError = null
|
||||
const localNodeFiles = [
|
||||
'nx.android-arm64.node',
|
||||
'nx.android-arm-eabi.node',
|
||||
'nx.win32-x64-msvc.node',
|
||||
'nx.win32-ia32-msvc.node',
|
||||
'nx.win32-arm64-msvc.node',
|
||||
'nx.darwin-universal.node',
|
||||
'nx.darwin-x64.node',
|
||||
'nx.darwin-arm64.node',
|
||||
'nx.freebsd-x64.node',
|
||||
'nx.linux-x64-musl.node',
|
||||
'nx.linux-x64-gnu.node',
|
||||
'nx.linux-arm64-musl.node',
|
||||
'nx.linux-arm64-gnu.node',
|
||||
'nx.linux-arm-gnueabihf.node',
|
||||
];
|
||||
|
||||
function isMusl() {
|
||||
// For Node 10
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
try {
|
||||
const lddPath = require('child_process').execSync('which ldd').toString().trim();
|
||||
return readFileSync(lddPath, 'utf8').includes('musl')
|
||||
} catch (e) {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
return !glibcVersionRuntime
|
||||
}
|
||||
}
|
||||
const originalLoad = Module._load;
|
||||
|
||||
switch (platform) {
|
||||
case 'android':
|
||||
switch (arch) {
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.android-arm64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.android-arm64.node')
|
||||
// We override the _load function so that when a native file is required,
|
||||
// we copy it to a cache directory and require it from there.
|
||||
// This prevents the file being loaded from node_modules and causing file locking issues.
|
||||
// Will only be called once because the require cache takes over afterwards.
|
||||
Module._load = function (request, parent, isMain) {
|
||||
const modulePath = request;
|
||||
if (
|
||||
nxPackages.has(modulePath) ||
|
||||
localNodeFiles.some((f) => modulePath.endsWith(f))
|
||||
) {
|
||||
const nativeLocation = require.resolve(modulePath);
|
||||
const fileName = basename(nativeLocation)
|
||||
// we copy the file to the cache directory (.nx/cache by default) and prefix with nxVersion to avoid stale files being loaded
|
||||
const tmpFile = join(cacheDir, nxVersion + '-' + fileName);
|
||||
if (existsSync(tmpFile)) {
|
||||
return originalLoad.apply(this, [tmpFile, parent, isMain]);
|
||||
}
|
||||
if (!existsSync(cacheDir)) {
|
||||
mkdirSync(cacheDir, { recursive: true });
|
||||
}
|
||||
copyFileSync(nativeLocation, tmpFile);
|
||||
return originalLoad.apply(this, [tmpFile, parent, isMain]);
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-android-arm64')
|
||||
// call the original _load function for everything else
|
||||
return originalLoad.apply(this, arguments);
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.android-arm-eabi.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.android-arm-eabi.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-android-arm-eabi')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Android ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'win32':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.win32-x64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.win32-x64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-win32-x64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'ia32':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.win32-ia32-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.win32-ia32-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-win32-ia32-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.win32-arm64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.win32-arm64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-win32-arm64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'darwin':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.darwin-universal.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.darwin-universal.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-darwin-universal')
|
||||
}
|
||||
break
|
||||
} catch {}
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.darwin-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.darwin-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-darwin-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.darwin-arm64.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.darwin-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-darwin-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'freebsd':
|
||||
if (arch !== 'x64') {
|
||||
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.freebsd-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.freebsd-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-freebsd-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'linux':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-x64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-x64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-x64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-x64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-x64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-x64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-arm64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-arm64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-arm64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-arm64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-arm64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-arm64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-arm-gnueabihf.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-arm-gnueabihf.node')
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-arm-gnueabihf')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
||||
}
|
||||
};
|
||||
|
||||
if (!nativeBinding) {
|
||||
if (loadError) {
|
||||
throw loadError
|
||||
}
|
||||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
const indexModulePath = require.resolve('./native-bindings.js');
|
||||
delete require.cache[indexModulePath];
|
||||
const indexModule = require('./native-bindings.js');
|
||||
|
||||
const { expandOutputs, getFilesForOutputs, remove, copy, hashArray, hashFile, ImportResult, findImports, transferProjectGraph, ChildProcess, RustPseudoTerminal, HashPlanner, TaskHasher, EventType, Watcher, WorkspaceContext, WorkspaceErrors, testOnlyTransferFileMap } = nativeBinding
|
||||
|
||||
module.exports.expandOutputs = expandOutputs
|
||||
module.exports.getFilesForOutputs = getFilesForOutputs
|
||||
module.exports.remove = remove
|
||||
module.exports.copy = copy
|
||||
module.exports.hashArray = hashArray
|
||||
module.exports.hashFile = hashFile
|
||||
module.exports.ImportResult = ImportResult
|
||||
module.exports.findImports = findImports
|
||||
module.exports.transferProjectGraph = transferProjectGraph
|
||||
module.exports.ChildProcess = ChildProcess
|
||||
module.exports.RustPseudoTerminal = RustPseudoTerminal
|
||||
module.exports.HashPlanner = HashPlanner
|
||||
module.exports.TaskHasher = TaskHasher
|
||||
module.exports.EventType = EventType
|
||||
module.exports.Watcher = Watcher
|
||||
module.exports.WorkspaceContext = WorkspaceContext
|
||||
module.exports.WorkspaceErrors = WorkspaceErrors
|
||||
module.exports.testOnlyTransferFileMap = testOnlyTransferFileMap
|
||||
module.exports = indexModule;
|
||||
Module._load = originalLoad;
|
||||
|
||||
290
packages/nx/src/native/native-bindings.js
Normal file
290
packages/nx/src/native/native-bindings.js
Normal file
@ -0,0 +1,290 @@
|
||||
const { existsSync, readFileSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
|
||||
const { platform, arch } = process;
|
||||
|
||||
let nativeBinding = null;
|
||||
let localFileExisted = false;
|
||||
let loadError = null;
|
||||
|
||||
function isMusl() {
|
||||
// For Node 10
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
try {
|
||||
const lddPath = require('child_process')
|
||||
.execSync('which ldd')
|
||||
.toString()
|
||||
.trim();
|
||||
return readFileSync(lddPath, 'utf8').includes('musl');
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
const { glibcVersionRuntime } = process.report.getReport().header;
|
||||
return !glibcVersionRuntime;
|
||||
}
|
||||
}
|
||||
|
||||
switch (platform) {
|
||||
case 'android':
|
||||
switch (arch) {
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.android-arm64.node'));
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.android-arm64.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-android-arm64');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.android-arm-eabi.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.android-arm-eabi.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-android-arm-eabi');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Android ${arch}`);
|
||||
}
|
||||
break;
|
||||
case 'win32':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.win32-x64-msvc.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.win32-x64-msvc.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-win32-x64-msvc');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
case 'ia32':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.win32-ia32-msvc.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.win32-ia32-msvc.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-win32-ia32-msvc');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.win32-arm64-msvc.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.win32-arm64-msvc.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-win32-arm64-msvc');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Windows: ${arch}`);
|
||||
}
|
||||
break;
|
||||
case 'darwin':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.darwin-universal.node'));
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.darwin-universal.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-darwin-universal');
|
||||
}
|
||||
break;
|
||||
} catch {}
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.darwin-x64.node'));
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.darwin-x64.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-darwin-x64');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.darwin-arm64.node'));
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.darwin-arm64.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-darwin-arm64');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on macOS: ${arch}`);
|
||||
}
|
||||
break;
|
||||
case 'freebsd':
|
||||
if (arch !== 'x64') {
|
||||
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`);
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, 'nx.freebsd-x64.node'));
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.freebsd-x64.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-freebsd-x64');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
case 'linux':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-x64-musl.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-x64-musl.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-x64-musl');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-x64-gnu.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-x64-gnu.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-x64-gnu');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'arm64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-arm64-musl.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-arm64-musl.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-arm64-musl');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-arm64-gnu.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-arm64-gnu.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-arm64-gnu');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'nx.linux-arm-gnueabihf.node')
|
||||
);
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./nx.linux-arm-gnueabihf.node');
|
||||
} else {
|
||||
nativeBinding = require('@nx/nx-linux-arm-gnueabihf');
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Linux: ${arch}`);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
|
||||
}
|
||||
|
||||
if (!nativeBinding) {
|
||||
if (loadError) {
|
||||
throw loadError;
|
||||
}
|
||||
throw new Error(`Failed to load native binding`);
|
||||
}
|
||||
|
||||
const {
|
||||
expandOutputs,
|
||||
getFilesForOutputs,
|
||||
remove,
|
||||
copy,
|
||||
hashArray,
|
||||
hashFile,
|
||||
ImportResult,
|
||||
findImports,
|
||||
transferProjectGraph,
|
||||
ChildProcess,
|
||||
RustPseudoTerminal,
|
||||
HashPlanner,
|
||||
TaskHasher,
|
||||
EventType,
|
||||
Watcher,
|
||||
WorkspaceContext,
|
||||
WorkspaceErrors,
|
||||
testOnlyTransferFileMap,
|
||||
} = nativeBinding;
|
||||
|
||||
module.exports.expandOutputs = expandOutputs;
|
||||
module.exports.getFilesForOutputs = getFilesForOutputs;
|
||||
module.exports.remove = remove;
|
||||
module.exports.copy = copy;
|
||||
module.exports.hashArray = hashArray;
|
||||
module.exports.hashFile = hashFile;
|
||||
module.exports.ImportResult = ImportResult;
|
||||
module.exports.findImports = findImports;
|
||||
module.exports.transferProjectGraph = transferProjectGraph;
|
||||
module.exports.ChildProcess = ChildProcess;
|
||||
module.exports.RustPseudoTerminal = RustPseudoTerminal;
|
||||
module.exports.HashPlanner = HashPlanner;
|
||||
module.exports.TaskHasher = TaskHasher;
|
||||
module.exports.EventType = EventType;
|
||||
module.exports.Watcher = Watcher;
|
||||
module.exports.WorkspaceContext = WorkspaceContext;
|
||||
module.exports.WorkspaceErrors = WorkspaceErrors;
|
||||
module.exports.testOnlyTransferFileMap = testOnlyTransferFileMap;
|
||||
@ -1,6 +1,75 @@
|
||||
import { CreateNodesResultWithContext } from './plugins/internal-api';
|
||||
import { ConfigurationResult } from './utils/project-configuration-utils';
|
||||
import {
|
||||
ConfigurationResult,
|
||||
ConfigurationSourceMaps,
|
||||
} from './utils/project-configuration-utils';
|
||||
import { ProjectConfiguration } from '../config/workspace-json-project-json';
|
||||
import {
|
||||
ProcessDependenciesError,
|
||||
ProcessProjectGraphError,
|
||||
} from './build-project-graph';
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
|
||||
export class ProjectGraphError extends Error {
|
||||
readonly #errors: Array<
|
||||
| CreateNodesError
|
||||
| MergeNodesError
|
||||
| ProjectsWithNoNameError
|
||||
| ProjectsWithConflictingNamesError
|
||||
| ProcessDependenciesError
|
||||
| ProcessProjectGraphError
|
||||
>;
|
||||
readonly #partialProjectGraph: ProjectGraph;
|
||||
readonly #partialSourceMaps: ConfigurationSourceMaps;
|
||||
|
||||
constructor(
|
||||
errors: Array<
|
||||
| CreateNodesError
|
||||
| MergeNodesError
|
||||
| ProjectsWithNoNameError
|
||||
| ProjectsWithConflictingNamesError
|
||||
| ProcessDependenciesError
|
||||
| ProcessProjectGraphError
|
||||
>,
|
||||
partialProjectGraph: ProjectGraph,
|
||||
partialSourceMaps: ConfigurationSourceMaps
|
||||
) {
|
||||
super(`Failed to process project graph.`);
|
||||
this.name = this.constructor.name;
|
||||
this.#errors = errors;
|
||||
this.#partialProjectGraph = partialProjectGraph;
|
||||
this.#partialSourceMaps = partialSourceMaps;
|
||||
this.stack = `${this.message}\n ${errors
|
||||
.map((error) => error.stack.split('\n').join('\n '))
|
||||
.join('\n')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The daemon cannot throw errors which contain methods as they are not serializable.
|
||||
*
|
||||
* This method creates a new {@link ProjectGraphError} from a {@link DaemonProjectGraphError} with the methods based on the same serialized data.
|
||||
*/
|
||||
static fromDaemonProjectGraphError(e: DaemonProjectGraphError) {
|
||||
return new ProjectGraphError(e.errors, e.projectGraph, e.sourceMaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets the partial project graph despite the errors which occured.
|
||||
* This partial project graph may be missing nodes, properties of nodes, or dependencies.
|
||||
* This is useful mostly for visualization/debugging. It should not be used for running tasks.
|
||||
*/
|
||||
getPartialProjectGraph() {
|
||||
return this.#partialProjectGraph;
|
||||
}
|
||||
|
||||
getPartialSourcemaps() {
|
||||
return this.#partialSourceMaps;
|
||||
}
|
||||
|
||||
getErrors() {
|
||||
return this.#errors;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProjectsWithConflictingNamesError extends Error {
|
||||
constructor(
|
||||
@ -153,3 +222,16 @@ export function isMergeNodesError(e: unknown): e is MergeNodesError {
|
||||
(typeof e === 'object' && 'name' in e && e?.name === MergeNodesError.name)
|
||||
);
|
||||
}
|
||||
|
||||
export class DaemonProjectGraphError extends Error {
|
||||
constructor(
|
||||
public errors: any[],
|
||||
readonly projectGraph: ProjectGraph,
|
||||
readonly sourceMaps: ConfigurationSourceMaps
|
||||
) {
|
||||
super(
|
||||
`The Daemon Process threw an error while calculating the project graph. Convert this error to a ProjectGraphError to get more information.`
|
||||
);
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,44 +1,33 @@
|
||||
import {
|
||||
readFileMapCache,
|
||||
readProjectGraphCache,
|
||||
writeCache,
|
||||
} from './nx-deps-cache';
|
||||
import {
|
||||
CreateDependenciesError,
|
||||
ProcessDependenciesError,
|
||||
ProcessProjectGraphError,
|
||||
buildProjectGraphUsingProjectFileMap,
|
||||
} from './build-project-graph';
|
||||
import { output } from '../utils/output';
|
||||
import { markDaemonAsDisabled, writeDaemonLogs } from '../daemon/tmp-dir';
|
||||
import { performance } from 'perf_hooks';
|
||||
import { readNxJson } from '../config/nx-json';
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
import { stripIndents } from '../utils/strip-indents';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from '../config/workspace-json-project-json';
|
||||
import { daemonClient } from '../daemon/client/client';
|
||||
import { markDaemonAsDisabled, writeDaemonLogs } from '../daemon/tmp-dir';
|
||||
import { fileExists } from '../utils/fileutils';
|
||||
import { output } from '../utils/output';
|
||||
import { stripIndents } from '../utils/strip-indents';
|
||||
import { workspaceRoot } from '../utils/workspace-root';
|
||||
import { performance } from 'perf_hooks';
|
||||
import {
|
||||
CreateDependenciesError,
|
||||
buildProjectGraphUsingProjectFileMap,
|
||||
} from './build-project-graph';
|
||||
import {
|
||||
readFileMapCache,
|
||||
readProjectGraphCache,
|
||||
writeCache,
|
||||
} from './nx-deps-cache';
|
||||
|
||||
import { ProjectConfigurationsError, ProjectGraphError } from './error-types';
|
||||
import { loadNxPlugins } from './plugins/internal-api';
|
||||
import { ConfigurationResult } from './utils/project-configuration-utils';
|
||||
import {
|
||||
retrieveProjectConfigurations,
|
||||
retrieveWorkspaceFiles,
|
||||
} from './utils/retrieve-workspace-files';
|
||||
import { readNxJson } from '../config/nx-json';
|
||||
import {
|
||||
ConfigurationResult,
|
||||
ConfigurationSourceMaps,
|
||||
} from './utils/project-configuration-utils';
|
||||
import {
|
||||
CreateNodesError,
|
||||
MergeNodesError,
|
||||
ProjectConfigurationsError,
|
||||
ProjectsWithNoNameError,
|
||||
ProjectsWithConflictingNamesError,
|
||||
} from './error-types';
|
||||
import { DaemonProjectGraphError } from '../daemon/daemon-project-graph-error';
|
||||
import { loadNxPlugins, LoadedNxPlugin } from './plugins/internal-api';
|
||||
|
||||
/**
|
||||
* Synchronously reads the latest cached copy of the workspace's ProjectGraph.
|
||||
@ -179,67 +168,6 @@ export async function buildProjectGraphAndSourceMapsWithoutDaemon() {
|
||||
}
|
||||
}
|
||||
|
||||
export class ProjectGraphError extends Error {
|
||||
readonly #errors: Array<
|
||||
| CreateNodesError
|
||||
| MergeNodesError
|
||||
| ProjectsWithNoNameError
|
||||
| ProjectsWithConflictingNamesError
|
||||
| ProcessDependenciesError
|
||||
| ProcessProjectGraphError
|
||||
>;
|
||||
readonly #partialProjectGraph: ProjectGraph;
|
||||
readonly #partialSourceMaps: ConfigurationSourceMaps;
|
||||
|
||||
constructor(
|
||||
errors: Array<
|
||||
| CreateNodesError
|
||||
| MergeNodesError
|
||||
| ProjectsWithNoNameError
|
||||
| ProjectsWithConflictingNamesError
|
||||
| ProcessDependenciesError
|
||||
| ProcessProjectGraphError
|
||||
>,
|
||||
partialProjectGraph: ProjectGraph,
|
||||
partialSourceMaps: ConfigurationSourceMaps
|
||||
) {
|
||||
super(`Failed to process project graph.`);
|
||||
this.name = this.constructor.name;
|
||||
this.#errors = errors;
|
||||
this.#partialProjectGraph = partialProjectGraph;
|
||||
this.#partialSourceMaps = partialSourceMaps;
|
||||
this.stack = `${this.message}\n ${errors
|
||||
.map((error) => error.stack.split('\n').join('\n '))
|
||||
.join('\n')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* The daemon cannot throw errors which contain methods as they are not serializable.
|
||||
*
|
||||
* This method creates a new {@link ProjectGraphError} from a {@link DaemonProjectGraphError} with the methods based on the same serialized data.
|
||||
*/
|
||||
static fromDaemonProjectGraphError(e: DaemonProjectGraphError) {
|
||||
return new ProjectGraphError(e.errors, e.projectGraph, e.sourceMaps);
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets the partial project graph despite the errors which occured.
|
||||
* This partial project graph may be missing nodes, properties of nodes, or dependencies.
|
||||
* This is useful mostly for visualization/debugging. It should not be used for running tasks.
|
||||
*/
|
||||
getPartialProjectGraph() {
|
||||
return this.#partialProjectGraph;
|
||||
}
|
||||
|
||||
getPartialSourcemaps() {
|
||||
return this.#partialSourceMaps;
|
||||
}
|
||||
|
||||
getErrors() {
|
||||
return this.#errors;
|
||||
}
|
||||
}
|
||||
|
||||
function handleProjectGraphError(opts: { exitOnError: boolean }, e) {
|
||||
if (opts.exitOnError) {
|
||||
const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true';
|
||||
|
||||
@ -5,7 +5,7 @@ import type {
|
||||
ProjectsConfigurations,
|
||||
} from '../config/workspace-json-project-json';
|
||||
import { output } from './output';
|
||||
import type { ProjectGraphError } from '../project-graph/project-graph';
|
||||
import type { ProjectGraphError } from '../project-graph/error-types';
|
||||
|
||||
const LIST_CHOICE_DISPLAY_LIMIT = 10;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user