Agoric / dapp-orchestration-basics

Agoric Orchestration Sample dApp
2 stars 4 forks source link

Refactor makeDeployBuilder and installBundles to preserve DRY #54

Open Jovonni opened 1 month ago

Jovonni commented 1 month ago
          Will revisit this, but this is for note taking, and ideation:

Here the difference between makeDeployBuilder functions (could paraneterize it with the path used in await tools.installBundles):

export const makeDeployBuilder = (tools, readJSON, execa) =>
  async function deployBuilder(builder) {
    console.log(`building plan: ${builder}`);
    // build the plan
    const { stdout } = await execa`agoric run ${builder}`;
    const match = stdout.match(/ (?<name>[-\w]+)-permit.json/);
    if (!(match && match.groups)) {
      throw new Error('no permit found');
    }
    const plan = await readJSON(`./${match.groups.name}-plan.json`);
    console.log(plan);

    console.log('copying files to container');
    tools.copyFiles([
      nodeRequire.resolve(`../${plan.script}`),
      nodeRequire.resolve(`../${plan.permit}`),
      ...plan.bundles.map(b => b.fileName),
    ]);

    console.log('installing bundles');
    await tools.installBundles(
      // plan.bundles.map(b => `/tmp/contracts/${b.bundleID}.json`),
      plan.bundles.map(b => `/root/${b.bundleID}.json`), // <===== HERE
      console.log,
    );

    console.log('executing proposal');
    await tools.runCoreEval({
      name: plan.name,
      description: `${plan.name} proposal`,
    });
  };

export const makeDeployBuilderE2E = (tools, readJSON, execa) =>
  async function deployBuilder(builder) {
    console.log(`building plan: ${builder}`);
    // build the plan
    const { stdout } = await execa`agoric run ${builder}`;
    const match = stdout.match(/ (?<name>[-\w]+)-permit.json/);
    if (!(match && match.groups)) {
      throw new Error('no permit found');
    }
    const plan = await readJSON(`./${match.groups.name}-plan.json`);
    console.log(plan);

    console.log('copying files to container');
    tools.copyFiles([
      nodeRequire.resolve(`../${plan.script}`),
      nodeRequire.resolve(`../${plan.permit}`),
      ...plan.bundles.map(b => b.fileName),
    ]);

    console.log('installing bundles');
    await tools.installBundles(
      plan.bundles.map(b => `/tmp/contracts/${b.bundleID}.json`),
      // plan.bundles.map(b => `/root/${b.bundleID}.json`),  // <===== HERE
      console.log,
    );

    console.log('executing proposal');
    await tools.runCoreEval({
      name: plan.name,
      description: `${plan.name} proposal`,
    });
  };

and here is the diffference between installBundles, and installBundlesE2E (could parameterize it to follow a different control flow based on if its for orca-multichain.test.js, or the e2e script to preserve DRY (if orca-multichain, take simple path, else do more work etc) :


  const installBundles = async (fullPaths, progress) => {
    await null;
    /** @type {Record<string, import('../test/boot-tools.js').CachedBundle>} */
    const bundles = {};
    // for (const [name, rootModPath] of Object.entries(bundleRoots)) {
    console.log('fullPaths', fullPaths);

    for (const fullPath of fullPaths) {
      const { tx, confirm } = await installBundle(fullPath, {
        id: fullPath,
        agd,
        follow: qt.query.follow,
        progress,
        delay,
        // bundleId: getBundleId(bundle),
        bundleId: undefined,
      });
      console.log('confirm', confirm);
      progress({
        // name,
        id: fullPath,
        installHeight: tx.height,
        installed: confirm,
      });
    }
    // eslint-disable-next-line no-undef
    return harden(bundles);
  };

  const installBundlesE2E = async (fullPaths, progress) => {
    await null;
    /** @type {Record<string, import('../test/boot-tools.js').CachedBundle>} */
    const bundles = {};
    console.log('fullPaths', fullPaths);

    console.log('getBundleId(bundle)');

    for (const _fullPath of fullPaths) {
      console.log('+fullPath');
      console.log(_fullPath);

      const pathSlices = _fullPath.split(',');
      // if (pathSlices.length != 2) throw 'invalid path slices length';
      const contractPath = pathSlices[0];
      const proposalPath = pathSlices[1];

      console.log('contractPath');
      console.log(contractPath);
      console.log('proposalPath');
      console.log(proposalPath);

      const fullPath = contractPath;
      const containerPath = fullPath.includes('contract/src/')
        ? '/root/src/' + fullPath.split('contract/src/').pop()
        : fullPath;

      console.log('containerPath');
      console.log(containerPath);

      // load bundle
      const bundle = await bundleCache.load(fullPath, 'orca');
      const bundle_proposal = await bundleCache.load(proposalPath, 'orca');

      console.log('bundle');
      console.log(bundle);
      console.log(bundle_proposal);

      //copy to
      const homeDir = os.homedir();
      const bundleId = getBundleId(bundle);
      const bundleFileName = path.join(
        homeDir,
        '.agoric/cache',
        `${bundleId}.json`,
      );

      console.log('bundleFileName');
      console.log(bundleFileName);

      if (fs.existsSync(bundleFileName)) {
        console.log(`copying ${bundleFileName} to container...`);
        const copyCommand = `kubectl cp ${bundleFileName} agoriclocal-genesis-0:/root/bundles/${path.basename(bundleFileName)}`;
        exec(copyCommand, (error, stdout, stderr) => {
          if (error) {
            console.error(`Error copying file: ${stderr}`);
            return;
          }
        });
        console.log(
          `bundle copied to container at /root/${path.basename(bundleFileName)}`,
        );
      } else {
        console.error(`bundle file ${bundleFileName} does not exist!`);
      }

      // generate plan, etc
      const tools = await makeAgdTools(console.log, childProcess);
      const contractBuilder = './test/builder/init-orca.js';
      const { stdout } = await execa`agoric run ${contractBuilder}`;
      const match = stdout.match(/ (?<name>[-\w]+)-permit.json/);
      if (!(match && match.groups)) {
        throw new Error('no permit found');
      }
      const plan = await fse.readJSON(`./${match.groups.name}-plan.json`);
      console.log(plan);

      console.log('copying files to containr');

      // copy artifacts to container
      tools.copyFiles([
        nodeRequire.resolve(`../${plan.script}`),
        nodeRequire.resolve(`../${plan.permit}`),
        ...plan.bundles.map(b => b.fileName),
      ]);

      console.log(
        'getBundleId(bundle)',
        getBundleId(bundle),
        plan.bundles[0].bundleID,
        getBundleId(bundle) == plan.bundles[0].bundleID,
      );

      //install proposal
      const proposalResult = await installBundle(
        `/root/${plan.bundles[1].bundleID}.json`,
        {
          id: fullPath,
          agd,
          follow: qt.query.follow,
          progress,
          delay,
          // bundleId: getBundleId(bundle),
          bundleId: plan.bundles[1].bundleID,
          // bundleId: undefined,
        },
      );

      console.log('confirm_contract', proposalResult.confirm);

      progress({
        id: fullPath,
        installHeight: proposalResult.tx.height,
        installed: proposalResult.confirm,
      });

      //install contract

      let { tx, confirm } = await installBundle(
        `/root/${plan.bundles[0].bundleID}.json`,
        {
          id: fullPath,
          agd,
          follow: qt.query.follow,
          progress,
          delay,
          // bundleId: getBundleId(bundle),
          bundleId: plan.bundles[0].bundleID,
          // bundleId: undefined,
        },
      );

      console.log('confirm_contract', confirm);

      progress({
        // name,
        id: fullPath,
        installHeight: tx.height,
        installed: confirm,
      });
    }
    // eslint-disable-next-line no-undef
    return harden(bundles);
  };

Originally posted by @Jovonni in https://github.com/Agoric/dapp-orchestration-basics/issues/37#issuecomment-2373175880