Skip to content

Commit

Permalink
Add script to generate a built-in extension pack
Browse files Browse the repository at this point in the history
The new script 'create-extension-pack.js' can be executed directly
after a project build (i.e. yarn) as long as the extensions
associated with the build are already available in the registry.

When the extensions are not yet available in the registry the script
'package-vsix.js' needs to be executed as a previous step.

The result will be an extension package in .vsix format installed
under the 'dist' folder (which is then used as the source for the
existing publishing step).

This extension package will include a reference to all extensions
resolved during the build step.

Fixes: eclipse-theia#40

Signed-off-by: Alvaro Sanchez-Leon <[email protected]>
  • Loading branch information
alvsan09 committed Mar 18, 2021
1 parent d4148d2 commit 2fb1a32
Show file tree
Hide file tree
Showing 4 changed files with 193 additions and 5 deletions.
184 changes: 184 additions & 0 deletions src/create-extension-pack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/********************************************************************************
* Copyright (C) 2021 Ericsson and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

/*
* Creates an extension package referencing all built-in extensions previously
* created during build time i.e. by executing yarn
*
* Extensions will be skipped if a corresponding .vsix file is not found under the 'dist'
* folder and also not found under the extension registry.
*/
// @ts-check
const fs = require('fs-extra');
const path = require('path');
const vsce = require('vsce');
const yargs = require('yargs');

const { computeVersion, vscodeVersion, isPublished } = require('./version');
const { dist, extensions, theiaExtension } = require('./paths.js');

const { tag, force } = yargs.option('tag', {
choices: ['latest', 'next']
}).demandOption('tag')
.option('force', {
description: 'Create extension pack even if it is found to be already available',
boolean: true,
default: false
}).argv;

const PACKAGE_JSON = 'package.json'
const categories = ['Extension Packs'];
const packName = 'builtin-extension-pack';
const publisher = 'open-vsx';
const repository = 'https://github.com/theia-ide/vscode-builtin-extensions';

(async () => {
const vscodeVer = await vscodeVersion();
const packVersion = await computeVersion(tag);
const extPackNameAndVersion = packName + '-' + packVersion;

const extPackVsixPath = dist(packName + '-' + packVersion + '.vsix');
const extensionPackAlreadyAvailable = await isAvailable(extPackVsixPath, packName, packVersion, publisher);
if (extensionPackAlreadyAvailable && !force) {
console.log("Exiting as this extension package is already created or published: " + extPackVsixPath);
return;
}

const extPackSrcFolder = theiaExtension(extPackNameAndVersion);
if (!fs.existsSync(extPackSrcFolder)) {
await fs.mkdir(extPackSrcFolder);
}

const extPack = {};
extPack.name = packName;
extPack.displayName = packName;
extPack.description = 'Builtin extension pack associated to a version of vscode';
extPack.version = packVersion;
extPack.publisher = publisher;
extPack.categories = categories;
extPack.engines = { vscode: '^' + vscodeVer };
extPack.repository = repository;
extPack.extensionPack = await resolveExtensions();

if (extPack.extensionPack.length === 0) {
process.exitCode = 1;
console.error('Aborting: No extension was found available for this version: ' + packVersion);
return;
}

const packFolderPath = path.join(extPackSrcFolder, '..', extPackNameAndVersion)
const packJsonPath = path.join(packFolderPath, PACKAGE_JSON);
const licensePath = path.join(packFolderPath, 'LICENSE.txt');
const readmePath = path.join(packFolderPath, 'README.md');

fs.writeFileSync(packJsonPath, JSON.stringify(extPack, null, 2), 'utf-8');
console.log('Generated ' + PACKAGE_JSON + ' file at: ' + packJsonPath);
fs.writeFileSync(licensePath, genLicense());
fs.writeFileSync(readmePath, genReadme());

await vsce.createVSIX({
'cwd': packFolderPath,
'packagePath': dist(),
'useYarn': true
});

async function resolveExtensions() {
const extensionsArr = [];
for (const extension of fs.readdirSync(extensions())) {
const extDataPath = extensions(extension, PACKAGE_JSON);
if (!fs.existsSync(extDataPath)) {
console.log('No ' + PACKAGE_JSON + ' found for: ' + extension);
continue;
}

const content = fs.readFileSync(extDataPath, 'utf-8');
const extData = JSON.parse(content);

const extVsixPath = dist(extData.name + '-' + packVersion + '.vsix');
const available = await isAvailable(extVsixPath, extData.name, packVersion);
if (!available) {
console.log("Skipping extension, i.e. .vsix is not found and " +
"neither published in the registry : " + extVsixPath);
continue;
}

const extensionId = extData.publisher + '.' + extData.name;
console.log('Adding: ' + extensionId);
extensionsArr.push(extensionId);
}
return Promise.resolve(extensionsArr);
}

async function isAvailable(extVsixPath, extensionName, extensionVersion, namespace = 'vscode') {
if (fs.existsSync(extVsixPath)) {
return Promise.resolve(true);
}

return isPublished(extensionVersion, extensionName, namespace);
}
})();

function genLicense() {
const date = new Date();
const year = date.getFullYear();
return `MIT License
Copyright(c) ${year} - Ericsson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.`;
}

function genReadme(ext) {
return `# Built-in extension package
## What is this extension package? Do I need it?
If you are running \`VS Code\`, \`Code OSS\` or derived product built from the VS Code repository,
such as [VSCodium](https://github.com/VSCodium/vscodium), you do not need to install this extension package as
the included extensions are already present - "built-in".
Built-in extensions are built-along and included in \`VS Code\` and \`Code OSS\`.
In consequence they may be expected to be present and used by other extensions.
They are part of the [vscode GitHub repository](https://github.com/microsoft/vscode/tree/master/) and
generally contribute basic functionality such as textmate grammars, used for syntax-highlighting, for some
of the most popular programming languages. In some cases, more substantial features are contributed through
built-in extensions (e.g. Typescript, Markdown, git, ...). Please see the description above to learn what
this specific extension does.
To learn more about built-in extensions, including how they are built and packaged,
please see [vscode-builtin-extensions](https://github.com/theia-ide/vscode-builtin-extensions).
This extension package may be useful for builders of \'VS Code\' derived products so it can be
included as a dependency or be installed within an extension or plugin directory instead of listing each
individual extension as a dependency.
`;
}
2 changes: 1 addition & 1 deletion src/package-vsix.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* and the wanted commit/tag checkled-out, before the start of packaging.
*/
// @ts-check
const fs = require('fs-extra')
const fs = require('fs-extra');
const os = require('os');
const yargs = require('yargs');
const capitalize = require('capitalize');
Expand Down
10 changes: 7 additions & 3 deletions src/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ const OPEN_VSX_ORG_URL = 'https://open-vsx.org'
* @param releaseType latest or next
*/
async function computeVersion(releaseType) {
const vscodePck = JSON.parse(fs.readFileSync(vscode('package.json'), 'utf-8'));
let ver = vscodePck.version || '0.0.1';
let ver = await vscodeVersion();
const shortRevision = (await run('git', ['rev-parse', '--short', 'HEAD'], vscode())).trim();

return new Promise((resolve) => {
Expand All @@ -46,6 +45,11 @@ async function computeVersion(releaseType) {
});
}

async function vscodeVersion() {
const vscodePck = JSON.parse(fs.readFileSync(vscode('package.json'), 'utf-8'));
return Promise.resolve(vscodePck.version || '0.0.1');
}

/**
* Returns whether an extension is already published on the currently
* set registry (default: https://open-vsx.org)
Expand All @@ -63,4 +67,4 @@ async function isPublished(version, extension, namespace = 'vscode') {
return true;
}

module.exports = { computeVersion, isPublished };
module.exports = { computeVersion, isPublished, vscodeVersion };
2 changes: 1 addition & 1 deletion vscode
Submodule vscode updated 1039 files

0 comments on commit 2fb1a32

Please sign in to comment.