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

9209 package manager flexibility #9286

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions packages/agoric-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"@endo/patterns": "^1.3.1",
"@endo/promise-kit": "^1.1.1",
"@iarna/toml": "^2.2.3",
"@npmcli/arborist": "^7.4.2",
"anylogger": "^0.21.0",
"chalk": "^5.2.0",
"commander": "^11.1.0",
Expand Down
39 changes: 14 additions & 25 deletions packages/agoric-cli/scripts/get-sdk-package-names.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
#! /usr/bin/env node
/* global process, Buffer */
import { spawn } from 'child_process';
import { basename } from 'path';
import process from 'process';
import Arborist from '@npmcli/arborist';

const ps = spawn('yarn', ['workspaces', '--silent', 'info'], {
stdio: ['ignore', 'pipe', 'inherit'],
shell: true,
});
const arb = new Arborist({ path: '../..' });
// root-level
const tree = await arb.loadActual();

// Get Buffers of output.
const chunks = [];
ps.stdout.on('data', data => chunks.push(data));
// query all production dependencies
const results = await tree.querySelectorAll('.workspace');
const packageNames = new Set(results.map(node => node.packageName));

// Wait for the process to exit.
ps.on('close', code => {
if (code !== 0) {
throw Error(`yarn info exited with code ${code}`);
}
const nameList = Array.from(packageNames).sort();

// Get the output.
const json = Buffer.concat(chunks).toString('utf8');
// process.stderr.write(json);

// Write the module.
const workspaces = Object.keys(JSON.parse(json)).sort();
process.stdout.write(`\
// Write the module.
process.stdout.write(`\
// DO NOT EDIT - automatically generated by ${basename(
new URL(import.meta.url).pathname,
)}
new URL(import.meta.url).pathname,
)}
// prettier-ignore
export default ${JSON.stringify(workspaces, null, 2)};
export default ${JSON.stringify(nameList, null, 2)};
`);
});
2 changes: 1 addition & 1 deletion packages/agoric-cli/src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const getSDKBinaries = ({
const xsnap = new URL(`${jsPfx}/xsnap`, myUrl).pathname;
return {
agSolo: new URL(`${jsPfx}/solo/src/entrypoint.js`, myUrl).pathname,
agSoloBuild: ['yarn', '--cwd', xsnap, `build:from-env`],
agSoloBuild: ['npm', 'run', 'build:from-env', '--workspace', xsnap],
cosmosChain: new URL(`${goPfx}/cosmos/build/agd`, myUrl).pathname,
cosmosChainBuild: cosmosBuild,
cosmosClientBuild: cosmosBuild,
Expand Down
55 changes: 15 additions & 40 deletions packages/agoric-cli/src/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async function installMain(progname, rawArgs, powers, opts) {
const { anylogger, fs, spawn } = powers;
const log = anylogger('agoric:install');

const forceSdkVersion = rawArgs[1];
const forceSdkVersion = !!rawArgs[1];

// Notify the preinstall guard that we are running.
process.env.AGORIC_INSTALL = 'true';
Expand All @@ -28,9 +28,8 @@ export default async function installMain(progname, rawArgs, powers, opts) {

const pspawn = makePspawn({ log, spawn, chalk });

const rimraf = file => pspawn('rm', ['-rf', file]);

async function getWorktreePackagePaths(cwd = '.', map = new Map()) {
// TODO use Arborist like get-sdk-package-names.js does
// run `yarn workspaces info` to get the list of directories to
// use, instead of a hard-coded list
const p = pspawn('yarn', ['workspaces', '--silent', 'info'], {
Expand All @@ -52,29 +51,23 @@ export default async function installMain(progname, rawArgs, powers, opts) {
let sdkWorktree;
/** @type {Map<string, string>} */
const sdkPackageToPath = new Map();
const linkFolder = path.resolve(`_agstate/yarn-links`);
const linkFlags = [];
if (opts.sdk) {
linkFlags.push(`--link-folder=${linkFolder}`);
}

const yarnInstallEachWorktree = async (phase, ...flags) => {
for await (const workTree of workTrees) {
log.info(`yarn install ${phase} in ${workTree}`);
const yarnInstall = await pspawn(
'yarn',
[...linkFlags, 'install', ...flags],
{
stdio: 'inherit',
cwd: workTree,
},
);
const yarnInstall = await pspawn('yarn', ['install', ...flags], {
stdio: 'inherit',
cwd: workTree,
});
if (yarnInstall) {
throw Error(`yarn install ${phase} failed in ${workTree}`);
}
}
};

/**
* @param {boolean} forceVersion
*/
const updateSdkVersion = async forceVersion => {
// Prune the old version (removing potentially stale on-disk and yarn.lock
// packages), and update on-disk and yarn.lock packages to the new version.
Expand Down Expand Up @@ -238,11 +231,6 @@ export default async function installMain(progname, rawArgs, powers, opts) {
const sdkRoot = path.resolve(dirname, `../../..`);
await getWorktreePackagePaths(sdkRoot, sdkPackageToPath);

// We remove all the links to prevent `yarn install` below from corrupting
// them.
log('removing', linkFolder);
await rimraf(linkFolder);

// Link the SDK.
if (sdkWorktree) {
await fs.unlink(sdkWorktree).catch(_ => {});
Expand Down Expand Up @@ -285,32 +273,19 @@ export default async function installMain(progname, rawArgs, powers, opts) {
// Create symlinks to the SDK packages.
await Promise.all(
[...sdkPackageToPath.entries()].map(async ([pjName, dir]) => {
const SUBOPTIMAL = false;
await null;
if (SUBOPTIMAL) {
// This use of yarn is noisy and slow.
await pspawn('yarn', [...linkFlags, 'unlink', pjName]);
return pspawn('yarn', [...linkFlags, 'link'], {
stdio: 'inherit',
cwd: dir,
});
}

// This open-coding of the above yarn command is quiet and fast.
const linkName = `${linkFolder}/${pjName}`;
const linkDir = path.dirname(linkName);
log('linking', linkName);
return fs
.mkdir(linkDir, { recursive: true })
.then(_ => fs.symlink(path.relative(linkDir, dir), linkName));
await pspawn('yarn', ['unlink', pjName]);
return pspawn('yarn', ['link'], {
stdio: 'inherit',
cwd: dir,
});
}),
);

const sdkPackages = [...sdkPackageToPath.keys()].sort();
for await (const subdir of subdirs) {
const exists = await fs.stat(`${subdir}/package.json`).catch(_ => false);
const exitStatus = await (exists &&
pspawn('yarn', [...linkFlags, 'link', ...sdkPackages], {
pspawn('yarn', ['link', ...sdkPackages], {
stdio: 'inherit',
cwd: subdir,
}));
Expand Down
16 changes: 13 additions & 3 deletions packages/agoric-cli/tools/getting-started.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
});
}

/** @param {string[]} args */
function yarn(args) {
return pspawnStdout('yarn', args, {
stdio: ['ignore', 'pipe', 'inherit'],
Expand All @@ -66,6 +67,15 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {
});
}

/** @param {string[]} args */
function npmRun(args) {
return pspawnStdout('npm', ['run', ...args], {
stdio: ['ignore', 'pipe', 'inherit'],
env: { ...process.env },
detached: true,
});
}

const olddir = process.cwd();
const { name } = tmp.dirSync({
unsafeCleanup: true,
Expand Down Expand Up @@ -113,19 +123,19 @@ export const gettingStartedWorkflowTest = async (t, options = {}) => {

// ==============
// yarn start:docker
t.is(await yarn(['start:docker']), 0, 'yarn start:docker works');
t.is(await npmRun(['start:docker']), 0, 'yarn start:docker works');

// XXX: use abci_info endpoint to get block height
// sleep to let contract start
await new Promise(resolve => setTimeout(resolve, TIMEOUT_SECONDS));

// ==============
// yarn start:contract
t.is(await yarn(['start:contract']), 0, 'yarn start:contract works');
t.is(await npmRun(['start:contract']), 0, 'yarn start:contract works');

// ==============
// yarn start:ui
const startUiP = yarn(['start:ui']);
const startUiP = npmRun(['start:ui']);
finalizers.push(() => pkill(startUiP.childProcess, 'SIGINT'));
const uiListening = makePromiseKit();
let retries = 0;
Expand Down
Loading
Loading