Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

linkless build #955

Merged
merged 12 commits into from
Jun 8, 2021
Merged
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ yarn-error.log
*.theia
asset-*
.eslintcache
plugins/vscode-*

# MacOS
.DS_Store
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as path from 'path';

import { ExtPluginApi, ExtPluginApiProvider } from '@theia/plugin-ext/lib/common/plugin-ext-api-contribution';

import { injectable } from 'inversify';
Expand All @@ -23,7 +21,7 @@ export class ChePluginApiProvider implements ExtPluginApiProvider {
initFunction: 'initializeApi',
initVariable: 'che_api_provider',
},
backendInitPath: path.join('@eclipse-che/theia-plugin-ext/lib/plugin/node/che-api-node-provider.js'),
backendInitPath: require.resolve('@eclipse-che/theia-plugin-ext/lib/plugin/node/che-api-node-provider'),
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { overrideUri } from '../../src/node/che-content-aware-utils';

describe('Test overrideUri', () => {
test('Should return the same uri if machine name is not defined', () => {
process.env.CHE_MACHINE_NAME = '';

const uri = URI.from({
scheme: 'file',
path: '/path',
Expand Down
3 changes: 3 additions & 0 deletions generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
"@types/yargs": "12.0.1",
"json2yaml": "^1.1.0"
},
"resolutions": {
"temp": "0.8.4"
},
"files": [
"dist",
"src"
Expand Down
111 changes: 111 additions & 0 deletions generator/src/generate-assembly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**********************************************************************
* Copyright (c) 2018-2021 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

import * as fs from 'fs-extra';
import * as mustache from 'mustache';
import * as path from 'path';

import { CommandBuilder } from 'yargs';
import { Init } from './init';
import { Logger } from './logger';
import { getFullPackageName } from './yarn';
import { rewriteJson } from './json-utils';

export const builder: CommandBuilder = {
'che-theia': {
describe: 'Path of the che-theia project source',
requiresArg: true,
type: 'string',
demandOption: false,
},
'theia-version': {
describe: 'Theia version to set',
requiresArg: true,
type: 'string',
demandOption: false,
default: 'next',
},
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function handleCommand(args: any) {
const cheTheiaDir = args['che-theia '] || process.cwd();
const theiaVersion = args['theia-version']!;
const monacoVersion = await getFullPackageName(cheTheiaDir, Init.MONACO_CORE_PKG);

if (!monacoVersion) {
throw new Error(`Package not found: ${Init.MONACO_CORE_PKG}`);
}

const assemblyDir = path.resolve(cheTheiaDir, 'assembly');
await generateAssembly(assemblyDir, {
theiaVersion,
monacoVersion,
configDirPrefix: '../../',
packageRefPrefix: '../extensions/',
});

const extensionsDir = path.resolve(__dirname, '../../extensions');
const folderNames = await fs.readdir(extensionsDir);
const extensions = new Map<string, string>();
for (const folderName of folderNames) {
const pkgJson = require(path.resolve(extensionsDir, folderName, 'package.json'));
extensions.set(pkgJson.name, pkgJson.version);
}

const theiaPlugins = await fs.readJson(path.resolve(__dirname, '../src/templates/theiaPlugins.json'));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rewriteJson(path.resolve(assemblyDir, 'package.json'), (json: any) => {
const deps = json.dependencies || {};
extensions.forEach((version: string, name: string) => {
deps[name] = version;
});
json.dependencies = deps;
json.scripts['download:plugins'] = 'theia download:plugins';
json.scripts.prepare = json.scripts.prepare + ' && yarn download:plugins';
json.theiaPluginsDir = '../plugins';
json.theiaPlugins = theiaPlugins;
});
}

export interface AssemblyConfiguration {
theiaVersion: string;
monacoVersion: string;
configDirPrefix: string;
packageRefPrefix: string;
}

export async function generateAssembly(examplesAssemblyFolder: string, config: AssemblyConfiguration): Promise<void> {
const srcDir = path.resolve(__dirname, '../src');
const distDir = path.resolve(__dirname, '../dist');
const templateDir = path.join(srcDir, 'templates');
const compileTsConfig = path.join(templateDir, 'assembly-compile.tsconfig.mst.json');

// generate assembly if does not exists
await fs.ensureDir(examplesAssemblyFolder);

const template = path.join(templateDir, 'assembly-package.mst.json');
const target = path.join(examplesAssemblyFolder, 'package.json');

await renderTemplate(template, target, config);
await renderTemplate(compileTsConfig, path.join(examplesAssemblyFolder, 'compile.tsconfig.mst.json'), config);

Logger.info(`copying ${path.join(templateDir, 'cdn')} to ${path.join(examplesAssemblyFolder, 'cdn')}`);
await fs.copy(path.join(templateDir, 'cdn'), path.join(examplesAssemblyFolder, 'cdn'));
Logger.info('distdir=' + distDir);
await fs.copy(path.join(distDir, 'cdn'), path.join(examplesAssemblyFolder, 'cdn'));
await fs.copy(path.join(srcDir, 'scripts'), path.join(examplesAssemblyFolder, 'scripts'));
}

async function renderTemplate(template: string, target: string, config: Object): Promise<void> {
const content = await fs.readFile(template);
const rendered = mustache.render(content.toString(), config).replace(/&#x2F;/g, '/');
await fs.writeFile(target, rendered);
}
57 changes: 19 additions & 38 deletions generator/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
***********************************************************************/

import * as fs from 'fs-extra';
import * as mustache from 'mustache';
import * as path from 'path';
import * as readPkg from 'read-pkg';

import { Command } from './command';
import { ISource } from './init-sources';
import { Logger } from './logger';
import { generateAssembly } from './generate-assembly';

/**
* Generates the examples/assembly
Expand All @@ -36,44 +35,19 @@ export class Init {
return (await readPkg(path.join(this.rootFolder, 'packages/core/package.json'))).version;
}

async getPackageWithVersion(name: string): Promise<string> {
const pkg = JSON.parse(
await new Command(path.resolve(this.rootFolder)).exec(Init.GET_PACKAGE_WITH_VERSION_CMD + name)
).data.trees[0];
return pkg ? pkg.name : '';
}

async generate(): Promise<void> {
const srcDir = path.resolve(__dirname, '../src');
const distDir = path.resolve(__dirname, '../dist');
const templateDir = path.join(srcDir, 'templates');
const compileTsConfig = path.join(templateDir, 'assembly-compile.tsconfig.json');
const packageJsonContent = await fs.readFile(path.join(templateDir, 'assembly-package.mst'));

// generate assembly if does not exists
const rendered = await this.generateAssemblyPackage(packageJsonContent.toString());
await fs.ensureDir(this.examplesAssemblyFolder);
await fs.writeFile(path.join(this.examplesAssemblyFolder, 'package.json'), rendered);
await fs.copy(compileTsConfig, path.join(this.examplesAssemblyFolder, 'compile.tsconfig.json'));
await fs.copy(path.join(templateDir, 'cdn'), path.join(this.examplesAssemblyFolder, 'cdn'));
Logger.info(distDir);
await fs.copy(path.join(distDir, 'cdn'), path.join(this.examplesAssemblyFolder, 'cdn'));
await fs.copy(path.join(srcDir, 'scripts'), path.join(this.examplesAssemblyFolder, 'scripts'));

async generate() {
await generateAssembly(this.examplesAssemblyFolder, {
theiaVersion: '^' + (await this.getCurrentVersion()),
monacoVersion: await this.getPackageWithVersion(Init.MONACO_CORE_PKG),
configDirPrefix: '../../packages/@che-',
packageRefPrefix: '../../config/',
});
// Generate checkout folder is does not exist
await fs.ensureDir(this.checkoutFolder);

// copy build all plugins scripts
await fs.ensureDir(this.pluginsFolder);
await fs.copy(path.join(srcDir, 'foreach_yarn'), path.join(this.pluginsFolder, 'foreach_yarn'));
}

async generateAssemblyPackage(template: string): Promise<string> {
const tags = {
version: await this.getCurrentVersion(),
monacopkg: await this.getPackageWithVersion(Init.MONACO_CORE_PKG),
};
return mustache.render(template, tags).replace(/&#x2F;/g, '/');
await fs.copy(path.resolve(__dirname, '../src/foreach_yarn'), path.join(this.pluginsFolder, 'foreach_yarn'));
}

async updadeBuildConfiguration(extensions: ISource[]): Promise<void> {
Expand Down Expand Up @@ -126,21 +100,28 @@ export class Init {
await fs.writeFile(theiaPackagePath, json);
}

async updatePluginsConfigurtion(): Promise<void> {
async updatePluginsConfiguration(): Promise<void> {
const theiaPackagePath = path.join(this.rootFolder, 'package.json');
const theiaPackage = await readPkg(theiaPackagePath);

theiaPackage['theiaPlugins'] = await this.getPluginsList();
theiaPackage['theiaPlugins'] = await Init.getPluginsList();

const json = JSON.stringify(theiaPackage, undefined, 2);
await fs.writeFile(theiaPackagePath, json);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private async getPluginsList(): Promise<any> {
private static async getPluginsList(): Promise<any> {
const srcDir = path.resolve(__dirname, '../src');
const templateDir = path.join(srcDir, 'templates');
const pluginsJsonContent = await fs.readFile(path.join(templateDir, 'theiaPlugins.json'));
return JSON.parse(pluginsJsonContent.toString());
}

async getPackageWithVersion(name: string): Promise<string> {
const pkg = JSON.parse(
await new Command(path.resolve(this.rootFolder)).exec(Init.GET_PACKAGE_WITH_VERSION_CMD + name)
).data.trees[0];
return pkg ? pkg.name : '';
}
}
38 changes: 38 additions & 0 deletions generator/src/json-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**********************************************************************
* Copyright (c) 2018-2021 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

/**
* Simple code to rewrite parts of JSON files
* @author Thomas Mäder
*/

import * as fs from 'fs-extra';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function rewriteJson(packageJSONPath: string, rewriteFunction: (json: any) => void) {
const json = await fs.readJSON(packageJSONPath);
rewriteFunction(json);

await fs.writeJson(packageJSONPath, json, { encoding: 'utf-8', spaces: 2 });
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function replaceInSection(section: any, replaceVersion: (key: string) => string | undefined) {
if (section) {
for (const dep in section) {
if (section.hasOwnProperty(dep)) {
const replacement = replaceVersion(dep);
if (replacement) {
section[dep] = replacement;
}
}
}
}
}
77 changes: 77 additions & 0 deletions generator/src/link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**********************************************************************
* Copyright (c) 2018-2021 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

/**
* A command to yarn link theia dependencies into che-theia
* @author Thomas Mäder
*/

import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';

import { Command } from './command';
import { CommandBuilder } from 'yargs';

export const builder: CommandBuilder = {
theia: {
describe: 'Path of the theia project source',
requiresArg: true,
type: 'string',
demandOption: false,
},
'che-theia': {
describe: 'Path of the che-theia project source',
requiresArg: true,
type: 'string',
demandOption: false,
},
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function handleCommand(args: any): Promise<void> {
const theiaDir = args.theia || path.resolve(process.cwd(), '../theia');
const cheTheiaDir = args['che-theia'] || process.cwd();

const cfg = await new Command(cheTheiaDir).exec('yarn --silent --json --non-interactive config current');

try {
const yarnConfig = JSON.parse(JSON.parse(cfg).data);
let linkDir = yarnConfig['linkFolder'] || path.resolve(os.homedir(), '.yarn/link');
await fs.ensureDir(linkDir);
linkDir = await fs.realpath(linkDir);
await link(cheTheiaDir, theiaDir, linkDir);
} catch (e) {
console.error(e);
}
}

export async function link(cheTheiaProjectPath: string, theiaProjectPath: string, yarnLinkFolder: string) {
await linkTheia(yarnLinkFolder, theiaProjectPath);
await linkChe(yarnLinkFolder, cheTheiaProjectPath);
}

async function linkTheia(yarnLinkFolder: string, theiaProjectPath: string) {
for (const rootName of ['packages', 'dev-packages', 'examples']) {
const rootPath = path.resolve(theiaProjectPath, rootName);
const folderNames = await fs.readdir(rootPath);
for (const folderName of folderNames) {
await new Command(path.resolve(rootPath, folderName)).exec(`yarn link --link-folder=${yarnLinkFolder}`);
}
}
}

async function linkChe(yarnLinkFolder: string, cheTheiaProjectPath: string) {
const packages = await fs.readdir(path.resolve(yarnLinkFolder, '@theia'));
const cmd = new Command(cheTheiaProjectPath);
for (const pkg of packages) {
await cmd.exec(`yarn link @theia/${pkg}`);
}
}
Loading