Skip to content

Commit

Permalink
Add x-generate-msbuild-props command (#705)
Browse files Browse the repository at this point in the history
* Add x-activate-msbuildprops command which is activate except it can only generate msbuild properties, and never downloads the content.

* Fix espidf activation.

* Rename activate-msbuildprops to generate-msbuildprops and the switch to --out only for that command.

* Rename x-generate-msbuildprops to x-generate-msbuild-props

* Avoid redundantly passing in 'session' values to Activation.activate, as requested by #705 (comment)
  • Loading branch information
BillyONeal authored Sep 19, 2022
1 parent 4bc93c8 commit 522aa94
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 87 deletions.
15 changes: 1 addition & 14 deletions ce/ce/archivers/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT License.

import { UnpackEvents } from '../interfaces/events';
import { Session } from '../session';
import { Credentials } from '../util/credentials';
import { execute } from '../util/exec-cmd';
import { isFilePath, Uri } from '../util/uri';
Expand All @@ -14,16 +13,12 @@ export interface CloneOptions {

/** @internal */
export class Git {
#session: Session;
#toolPath: string;
#targetFolder: Uri;
#environment: NodeJS.ProcessEnv;

constructor(session: Session, toolPath: string, environment: NodeJS.ProcessEnv, targetFolder: Uri) {
this.#session = session;
constructor(toolPath: string, targetFolder: Uri) {
this.#toolPath = toolPath;
this.#targetFolder = targetFolder;
this.#environment = environment;
}

/**
Expand All @@ -45,7 +40,6 @@ export class Git {
options.depth ? `--depth=${options.depth}` : '',
'--progress'
], {
env: this.#environment,
onStdErrData: chunkToHeartbeat(events),
onStdOutData: chunkToHeartbeat(events)
});
Expand All @@ -70,7 +64,6 @@ export class Git {
options.commit ? options.commit : '',
options.depth ? `--depth=${options.depth}` : ''
], {
env: this.#environment,
cwd: this.#targetFolder.fsPath
});

Expand All @@ -92,7 +85,6 @@ export class Git {
'checkout',
options.commit ? options.commit : ''
], {
env: this.#environment,
cwd: this.#targetFolder.fsPath,
onStdErrData: chunkToHeartbeat(events),
onStdOutData: chunkToHeartbeat(events)
Expand All @@ -117,7 +109,6 @@ export class Git {
options.recurse ? '--recurse-submodules' : '',
options.hard ? '--hard' : ''
], {
env: this.#environment,
cwd: this.#targetFolder.fsPath,
onStdErrData: chunkToHeartbeat(events),
onStdOutData: chunkToHeartbeat(events)
Expand All @@ -140,7 +131,6 @@ export class Git {
}

const result = await execute(this.#toolPath, ['init'], {
env: this.#environment,
cwd: this.#targetFolder.fsPath
});

Expand All @@ -162,7 +152,6 @@ export class Git {
name,
location.toString()
], {
env: this.#environment,
cwd: this.#targetFolder.fsPath
});

Expand All @@ -186,7 +175,6 @@ export class Git {
options.depth ? `--depth=${options.depth}` : '',
options.recursive ? '--recursive' : '',
], {
env: this.#environment,
cwd: this.#targetFolder.fsPath,
onStdErrData: chunkToHeartbeat(events),
onStdOutData: chunkToHeartbeat(events)
Expand All @@ -210,7 +198,6 @@ export class Git {
key,
value
], {
env: this.#environment,
cwd: this.#targetFolder.fsPath
});
return result.code === 0;
Expand Down
33 changes: 17 additions & 16 deletions ce/ce/artifacts/activation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class Activation {

// the folder is relative to the artifact install
for (const folder of values) {
this.addPath(pathName, resolve(targetFolder.fsPath, folder));
this.addPath(pathName, targetFolder.join(folder).fsPath);
}
}

Expand All @@ -78,7 +78,7 @@ export class Activation {
if (!toolName || !toolPath) {
continue;
}
this.addTool(toolName, resolve(targetFolder.fsPath, toolPath));
this.addTool(toolName, targetFolder.join(toolPath).fsPath);
}

// **** locations ****
Expand All @@ -87,7 +87,7 @@ export class Activation {
continue;
}

this.addLocation(name, resolve(targetFolder.fsPath, location));
this.addLocation(name, targetFolder.join(location).fsPath);
}

// **** variables ****
Expand Down Expand Up @@ -547,9 +547,11 @@ export class Activation {
return [env, undo];
}

async activate(currentEnvironment: Record<string, string | undefined>, shellScriptFile: Uri | undefined, undoEnvironmentFile: Uri | undefined, msbuildFile: Uri | undefined, json: Uri | undefined) {
async activate(undoEnvironmentFile: Uri | undefined, msbuildFile: Uri | undefined, json: Uri | undefined) {
let undoDeactivation = '';
const scriptKind = extname(shellScriptFile?.fsPath || '');
const scriptKind = extname(this.#session.postscriptFile?.fsPath || '');

const currentEnvironment = {...this.#session.environment};

// load previous activation undo data
const previous = currentEnvironment[undoVariableName];
Expand All @@ -558,9 +560,10 @@ export class Activation {
const deactivationData = await deactivationDataFile.tryReadUTF8();
if (deactivationData) {
const deactivationParsed = JSON.parse(deactivationData);
currentEnvironment = undoActivation(currentEnvironment, deactivationParsed.environment || {});
const previousEnvironmentValues = deactivationParsed.environment || {};
undoActivation(currentEnvironment, previousEnvironmentValues);
delete currentEnvironment[undoVariableName];
undoDeactivation = generateScriptContent(scriptKind, deactivationParsed.environment || {}, deactivationParsed.aliases || {});
undoDeactivation = generateScriptContent(scriptKind, previousEnvironmentValues, deactivationParsed.aliases || {});
}
}

Expand Down Expand Up @@ -599,11 +602,11 @@ export class Activation {
}

// generate shell script if requested
if (shellScriptFile) {
if (this.#session.postscriptFile) {
const contents = undoDeactivation + generateScriptContent(scriptKind, variables, aliases);

this.#session.channels.verbose(`--------[START SHELL SCRIPT FILE]--------\n${contents}\n--------[END SHELL SCRIPT FILE]---------`);
await shellScriptFile.writeUTF8(contents);
await this.#session.postscriptFile.writeUTF8(contents);
}

// generate msbuild props file if requested
Expand All @@ -621,7 +624,7 @@ export class Activation {
}


/** produces an environment block that can be passed to child processes to leverage dependent artifacts during installtion/activation. */
/** produces an environment block that can be passed to child processes to leverage dependent artifacts during installation/activation. */
async getEnvironmentBlock(): Promise<NodeJS.ProcessEnv> {
const result = { ... this.#session.environment };

Expand Down Expand Up @@ -709,16 +712,14 @@ export async function deactivate(shellScriptFile: Uri, variables: Record<string,
await shellScriptFile.writeUTF8(generateScriptContent(kind, variables, aliases));
}

function undoActivation(currentEnvironment: Record<string, string | undefined>, variables: Record<string, string>) {
const result = { ...currentEnvironment };
for (const [key, value] of linq.entries(variables)) {
function undoActivation(targetEnvironment: Record<string, string | undefined>, oldVariableValues: Record<string, string>) {
for (const [key, value] of linq.entries(oldVariableValues)) {
if (value) {
result[key] = value;
targetEnvironment[key] = value;
} else {
delete result[key];
delete targetEnvironment[key];
}
}
return result;
}

async function toArrayAsync<T>(iterable: AsyncIterable<T>) {
Expand Down
36 changes: 16 additions & 20 deletions ce/ce/artifacts/artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { resolve } from 'path';
import { MetadataFile } from '../amf/metadata-file';
import { RegistriesDeclaration, RegistryDeclaration } from '../amf/registries';
import { artifactIdentity, prettyRegistryName } from '../cli/format';
import { FileType } from '../fs/filesystem';
import { i } from '../i18n';
import { activateEspIdf, installEspIdf } from '../installers/espidf';
import { InstallEvents } from '../interfaces/events';
import { getArtifact, Registry, RegistryResolver } from '../registries/registries';
import { Session } from '../session';
import { linq } from '../util/linq';
import { Uri } from '../util/uri';
import { Activation } from './activation';
import { SetOfDemands } from './SetOfDemands';

export type Selections = Map<string, string>; // idOrShortName, version
Expand Down Expand Up @@ -82,6 +82,8 @@ export abstract class ArtifactBase {

return Promise.resolve(undefined);
}

abstract loadActivationSettings(activation: Activation): Promise<boolean>;
}

export enum InstallStatus {
Expand All @@ -91,8 +93,6 @@ export enum InstallStatus {
}

export class Artifact extends ArtifactBase {
allPaths: Array<string> = [];

constructor(session: Session, metadata: MetadataFile, public shortName: string, public targetLocation: Uri) {
super(session, metadata);
}
Expand Down Expand Up @@ -129,10 +129,6 @@ export class Artifact extends ArtifactBase {
this.session.channels.message(addDisplayPrefix(thisDisplayName, applicableDemands.messages));

if (await this.isInstalled && !options.force) {
if (!await this.loadActivationSettings(events)) {
throw new Error(i`Failed during artifact activation`);
}

events.alreadyInstalledArtifact?.(thisDisplayName);
return InstallStatus.AlreadyInstalled;
}
Expand Down Expand Up @@ -160,11 +156,12 @@ export class Artifact extends ArtifactBase {
await installer(this.session, this.id, this.version, this.targetLocation, installInfo, events, options);
}

if (this.metadata.espidf) {
await installEspIdf(this.session, events, this.targetLocation);
}

// after we unpack it, write out the installed manifest
await this.writeManifest();
if (!await this.loadActivationSettings(events)) {
throw new Error(i`Failed during artifact activation`);
}
return InstallStatus.Installed;
} catch (err) {
try {
Expand All @@ -186,27 +183,23 @@ export class Artifact extends ArtifactBase {
await this.targetLocation.delete({ recursive: true, useTrash: false });
}

async loadActivationSettings(events: Partial<InstallEvents>) {

async loadActivationSettings(activation: Activation) : Promise<boolean> {
// construct paths (bin, lib, include, etc.)
// construct tools
// compose variables
// defines

// record all the files in the artifact
this.allPaths = (await this.targetLocation.readDirectory(undefined, { recursive: true })).select(([name, stat]) => stat === FileType.Directory ? name.fsPath + '/' : name.fsPath);
for (const exportsBlock of this.applicableDemands.exports) {
this.session.activation.addExports(exportsBlock, this.targetLocation);
activation.addExports(exportsBlock, this.targetLocation);
}

// if espressif install
if (this.metadata.espidf) {
// check for some file that espressif installs to see if it's installed.
if (!await this.targetLocation.exists('.espressif')) {
await installEspIdf(this.session, events, this.targetLocation);
}

// activate
await activateEspIdf(this.session, this.targetLocation);
if (!await activateEspIdf(this.session, activation, this.targetLocation)) {
return false;
}
}

return true;
Expand Down Expand Up @@ -256,6 +249,9 @@ export function sanitizeUri(u: string) {
}

export class ProjectManifest extends ArtifactBase {
loadActivationSettings(activation: Activation) {
return Promise.resolve(true);
}
}

export class InstalledArtifact extends Artifact {
Expand Down
66 changes: 66 additions & 0 deletions ce/ce/cli/commands/generate-msbuild-props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Activation } from '../../artifacts/activation';
import { buildRegistryResolver, resolveDependencies } from '../../artifacts/artifact';
import { i } from '../../i18n';
import { session } from '../../main';
import { showArtifacts } from '../artifacts';
import { Command } from '../command';
import { error } from '../styling';
import { Json } from '../switches/json';
import { MSBuildProps } from '../switches/msbuild-props';
import { Project } from '../switches/project';
import { WhatIf } from '../switches/whatIf';

export class GenerateMSBuildPropsCommand extends Command {
readonly command = 'generate-msbuild-props';
readonly aliases = [];
seeAlso = [];
argumentsHelp = [];
whatIf = new WhatIf(this);
project: Project = new Project(this);
msbuildProps: MSBuildProps = new MSBuildProps(this, 'out');
json : Json = new Json(this);

get summary() {
return i`Generates MSBuild properties for an activation without downloading anything for a project`;
}

get description() { return ['']; }

override async run() {
if (!this.msbuildProps.active) {
error(i`generate-msbuild-props requires --msbuild-props`);
return false;
}

const projectManifest = await this.project.manifest;

if (!projectManifest) {
error(i`Unable to find project in folder (or parent folders) for ${session.currentDirectory.fsPath}`);
return false;
}

const projectResolver = await buildRegistryResolver(session, projectManifest.metadata.registries);
const resolved = await resolveDependencies(session, projectResolver, [projectManifest], 3);

// print the status of what is going to be activated.
if (!await showArtifacts(resolved, projectResolver, {})) {
error(i`Unable to activate project`);
return false;
}

const activation = new Activation(session);
for (const artifact of resolved) {
if (!await artifact.artifact.loadActivationSettings(activation)) {
session.channels.error(i`Unable to activate project.`);
return false;
}
}

const content = activation.generateMSBuild();
await this.msbuildProps.value?.writeUTF8(content);
return true;
}
}
Loading

0 comments on commit 522aa94

Please sign in to comment.