diff --git a/packages/cli/lib/index.js b/packages/cli/lib/index.js index 97e6074..b0997df 100644 --- a/packages/cli/lib/index.js +++ b/packages/cli/lib/index.js @@ -29,19 +29,19 @@ exports.install = async options => { const allPkgs = await util.getAllPkgPaths(options.cwd, options.pkg); - await Promise.all(allPkgs.map(async pkgPath => { + for (const pkgPath of allPkgs) { const { baseDir, tarIndex, nodeModulesDir } = await util.getWorkdir(options.cwd, pkgPath); const mountedInfo = currentMountInfo.find(item => item.mountPoint === nodeModulesDir); if (mountedInfo) { console.log(`[rapid] ${nodeModulesDir} already mounted, try to clean`); - await exports.clean(path.join(options.cwd, pkgPath)); + await exports.clean(path.join(options.cwd, pkgPath), true); } await fs.mkdir(baseDir, { recursive: true }); await fs.mkdir(path.dirname(tarIndex), { recursive: true }); - })); + } await fs.mkdir(tarBucketsDir, { recursive: true }); await util.createNydusdConfigFile(nydusdConfigFile); @@ -58,7 +58,10 @@ exports.install = async options => { assert(Object.keys(packageLock).length, '[rapid] depsJSON invalid.'); await nydusd.startNydusFs(nydusMode, options.cwd, options.pkg); - // 执行 lifecycle scripts + console.time('[rapid] wait for access'); + await util.ensureAccess(options.cwd, packageLock); + console.timeEnd('[rapid] wait for access'); + console.time('[rapid] run lifecycle scripts'); await options.scripts.runLifecycleScripts(mirrorConfig); console.timeEnd('[rapid] run lifecycle scripts'); diff --git a/packages/cli/lib/nydusd/fuse_mode.js b/packages/cli/lib/nydusd/fuse_mode.js index d6cf036..72a46ac 100644 --- a/packages/cli/lib/nydusd/fuse_mode.js +++ b/packages/cli/lib/nydusd/fuse_mode.js @@ -42,17 +42,19 @@ async function generateBootstrapFile(cwd, pkg) { async function mountNydus(cwd, pkg) { const allPkgs = await getAllPkgPaths(cwd, pkg); - await Promise.all(allPkgs.map(async pkgPath => { + + // 需要串行 mount,并发创建时 nydusd 会出现问题 + for (const pkgPath of allPkgs) { const { dirname, bootstrap } = await getWorkdir(cwd, pkgPath); console.time(`[rapid] mount '/${dirname}' to nydusd daemon using socket api`); await nydusdApi.mount(`/${dirname}`, cwd, bootstrap); console.timeEnd(`[rapid] mount '/${dirname}' to nydusd daemon using socket api`); - })); + } } async function mountOverlay(cwd, pkg) { const allPkgs = await getAllPkgPaths(cwd, pkg); - await Promise.all(allPkgs.map(async pkgPath => { + for (const pkgPath of allPkgs) { const { upper, @@ -90,15 +92,15 @@ ${upper}=RW:${mnt}=RO \ ${nodeModulesDir}`; } console.info('[rapid] mountOverlay: `%s`', shScript); + console.time('[rapid] overlay mounted.'); await execa.command(shScript); - console.info('[rapid] overlay mounted.'); - })); + console.timeEnd('[rapid] overlay mounted.'); + } } async function endNydusFs(cwd, pkg) { const allPkgs = await getAllPkgPaths(cwd, pkg); - await Promise.all(allPkgs.map(async pkgPath => { - + for (const pkgPath of allPkgs) { const { dirname, overlay, @@ -117,7 +119,7 @@ async function endNydusFs(cwd, pkg) { await nydusdApi.umount(`/${dirname}`); // 清除 nydus 相关目录 await fs.rm(baseDir, { recursive: true, force: true }); - })); + } } module.exports = { diff --git a/packages/cli/lib/util.js b/packages/cli/lib/util.js index dbbc397..5913e62 100644 --- a/packages/cli/lib/util.js +++ b/packages/cli/lib/util.js @@ -396,6 +396,43 @@ function validDep(pkg, productionMode, arch, platform) { } +exports.ensureAccess = async function ensureAccess(cwd, packageLock) { + let access = false; + let targetPath; + + for (const [ pkgPath, pkgItem ] of Object.entries(packageLock)) { + if (pkgPath.startsWith('node_modules') && !pkgItem.optional) { + targetPath = pkgPath; + break; + } + } + + // 如果没有找到合适的检测点,直接返回 + if (!targetPath) { + return; + } + + let retry = 0; + + // 如果找到了检测点,但是检测点不存在,等待检测点创建 + while (!access) { + try { + await fs.access(targetPath); + access = true; + } catch (e) { + retry++; + console.log( + `[rapid] still waiting for access ${targetPath} retry after 50ms, retry count: ${retry}` + ); + if (retry > 40) { + console.error(`[rapid] wait for access ${targetPath} timeout`); + throw e; + } + await this.sleep(50); + } + } +}; + exports.getAllPkgPaths = async function getAllPkgPaths(cwd, pkg) { const workspaces = await exports.getWorkspaces(cwd, pkg); const allPkgs = Object.values(workspaces);