Added pnpm support. Sloppy and incomplete. Unsure of what to do

with the symlinks without modifying the project.

microsoft/vscode-vsce#421
This commit is contained in:
Empathic Qubit 2020-09-04 22:54:15 -04:00
parent 5ade7bfa42
commit f2c83c1bc3
7 changed files with 1445 additions and 25 deletions

View file

@ -25,11 +25,11 @@
},
"scripts": {
"copy-vsce": "mkdir -p out && cp src/vsce out/vsce",
"compile": "tsc && yarn copy-vsce",
"watch": "yarn copy-vsce && tsc --watch",
"watch-test": "yarn copy-vsce && concurrently \"tsc --watch\" \"mocha --watch\"",
"compile": "tsc && npm run copy-vsce",
"watch": "npm run copy-vsce && tsc --watch",
"watch-test": "npm run copy-vsce && concurrently \"tsc --watch\" \"mocha --watch\"",
"test": "mocha",
"prepublishOnly": "tsc && yarn copy-vsce && mocha",
"prepublishOnly": "tsc && npm run copy-vsce && mocha",
"vsce": "out/vsce"
},
"engines": {

1301
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,11 @@ export interface ICreateVSIXOptions {
* Should use Yarn instead of NPM.
*/
useYarn?: boolean;
/**
* Select the package manager to use
*/
usePackageManager?: "yarn" | "pnpm" | "npm";
}
export interface IPublishOptions {
@ -62,6 +67,11 @@ export interface IPublishOptions {
* Should use Yarn instead of NPM.
*/
useYarn?: boolean;
/**
* Select the package manager to use
*/
usePackageManager?: "yarn" | "pnpm" | "npm";
}
/**
@ -69,7 +79,8 @@ export interface IPublishOptions {
*/
export enum PackageManager {
Npm,
Yarn
Yarn,
Pnpm,
}
export interface IListFilesOptions {
@ -122,6 +133,11 @@ export interface IPublishVSIXOptions {
* Should use Yarn instead of NPM.
*/
useYarn?: boolean;
/**
* Select the package manager to use
*/
usePackageManager?: "yarn" | "pnpm" | "npm";
}
/**
@ -142,7 +158,7 @@ export function publish(options: IPublishOptions = {}): Promise<any> {
* Lists the files included in the extension's package.
*/
export function listFiles(options: IListFilesOptions = {}): Promise<string[]> {
return _listFiles(options.cwd, options.packageManager === PackageManager.Yarn, options.packagedDependencies, options.ignoreFile);
return _listFiles(options.cwd, options.packageManager === PackageManager.Yarn, <any>({ [PackageManager.Yarn]: "yarn", [PackageManager.Npm]: "npm", [PackageManager.Pnpm]: "pnpm" }[options.packageManager]), options.packagedDependencies, options.ignoreFile);
}
/**

View file

@ -62,9 +62,10 @@ module.exports = function (argv: string[]): void {
.command('ls')
.description('Lists all the files that will be published')
.option('--yarn', 'Use yarn instead of npm')
.option('--packageManager [yarn|npm|pnpm]', 'Use yarn, npm, or pnpm package manager')
.option('--packagedDependencies <path>', 'Select packages that should be published only (includes dependencies)', (val, all) => all ? all.concat(val) : [val], undefined)
.option('--ignoreFile [path]', 'Indicate alternative .vscodeignore')
.action(({ yarn, packagedDependencies, ignoreFile }) => main(ls(undefined, yarn, packagedDependencies, ignoreFile)));
.action(({ yarn, packagedDependencies, ignoreFile, packageManager }) => main(ls(undefined, yarn, packagedDependencies, ignoreFile, packageManager)));
program
.command('package')
@ -74,9 +75,10 @@ module.exports = function (argv: string[]): void {
.option('--baseContentUrl [url]', 'Prepend all relative links in README.md with this url.')
.option('--baseImagesUrl [url]', 'Prepend all relative image links in README.md with this url.')
.option('--yarn', 'Use yarn instead of npm')
.option('--packageManager [yarn|npm|pnpm]', 'Use yarn, npm, or pnpm package manager')
.option('--ignoreFile [path]', 'Indicate alternative .vscodeignore')
.option('--noGitHubIssueLinking', 'Prevent automatic expansion of GitHub-style issue syntax into links')
.action(({ out, githubBranch, baseContentUrl, baseImagesUrl, yarn, ignoreFile, noGitHubIssueLinking }) => main(packageCommand({ packagePath: out, githubBranch, baseContentUrl, baseImagesUrl, useYarn: yarn, ignoreFile, expandGitHubIssueLinks: noGitHubIssueLinking })));
.action(({ out, githubBranch, baseContentUrl, baseImagesUrl, yarn, ignoreFile, noGitHubIssueLinking, packageManager }) => main(packageCommand({ packagePath: out, githubBranch, baseContentUrl, baseImagesUrl, useYarn: yarn, ignoreFile, expandGitHubIssueLinks: noGitHubIssueLinking, usePackageManager: packageManager })));
program
.command('publish [<version>]')
@ -88,10 +90,11 @@ module.exports = function (argv: string[]): void {
.option('--baseContentUrl [url]', 'Prepend all relative links in README.md with this url.')
.option('--baseImagesUrl [url]', 'Prepend all relative image links in README.md with this url.')
.option('--yarn', 'Use yarn instead of npm while packing extension files')
.option('--packageManager [yarn|npm|pnpm]', 'Use yarn, npm, or pnpm package manager')
.option('--noVerify')
.option('--ignoreFile [path]', 'Indicate alternative .vscodeignore')
.option('--web', 'Experimental flag to enable publishing web extensions. Note: This is supported only for selected extensions.')
.action((version, { pat, message, packagePath, githubBranch, baseContentUrl, baseImagesUrl, yarn, noVerify, ignoreFile, web }) => main(publish({ pat, commitMessage: message, version, packagePath, githubBranch, baseContentUrl, baseImagesUrl, useYarn: yarn, noVerify, ignoreFile, web })));
.action((version, { pat, message, packagePath, githubBranch, baseContentUrl, baseImagesUrl, yarn, noVerify, ignoreFile, web, packageManager }) => main(publish({ pat, commitMessage: message, version, packagePath, githubBranch, baseContentUrl, baseImagesUrl, useYarn: yarn, noVerify, ignoreFile, web, usePackageManager: packageManager })));
program
.command('unpublish [<extensionid>]')

View file

@ -1,6 +1,7 @@
import * as path from 'path';
import * as fs from 'fs';
import * as cp from 'child_process';
import * as denodeify from 'denodeify';
import * as parseSemver from 'parse-semver';
import * as _ from 'lodash';
import { CancellationToken } from './util';
@ -71,6 +72,13 @@ export interface YarnDependency {
children: YarnDependency[];
}
interface PnpmTreeNode {
name: string;
from: string;
version: string;
dependencies: { [key:string]:PnpmTreeNode };
}
function asYarnDependency(prefix: string, tree: YarnTreeNode, prune: boolean): YarnDependency | null {
if (prune && /@[\^~]/.test(tree.name)) {
return null;
@ -99,6 +107,32 @@ function asYarnDependency(prefix: string, tree: YarnTreeNode, prune: boolean): Y
return { name, path: dependencyPath, children };
}
async function asPnpmDependency(prefix: string, tree: PnpmTreeNode, prune: boolean): Promise<YarnDependency | null> {
if (prune && /^[\^~]/.test(tree.version)) {
return null;
}
let name = tree.name || tree.from;
let s = path.sep;
const dependencyPath = await denodeify(fs.realpath)(`${prefix}${s}${name}`);
const children: YarnDependency[] = [];
console.log(dependencyPath);
const deps = await Promise.all(
_.values(tree.dependencies || {})
.map(child => asPnpmDependency(`${dependencyPath}${s}..`, child, prune))
);
for(const dep of deps) {
if (dep) {
children.push(dep);
}
}
return { name, path: dependencyPath, children };
}
function selectYarnDependencies(deps: YarnDependency[], packagedDependencies: string[]): YarnDependency[] {
const index = new class {
@ -145,6 +179,30 @@ function selectYarnDependencies(deps: YarnDependency[], packagedDependencies: st
return reached.values;
}
async function getPnpmProductionDependencies(cwd: string, packagedDependencies?: string[]): Promise<YarnDependency[]> {
const raw = await new Promise<string>((c, e) => cp.exec('pnpm list --depth 1000000 --prod --json --silent', { cwd, encoding: 'utf8', env: { ...process.env }, maxBuffer: 5000 * 1024 }, (err, stdout) => err ? e(err) : c(stdout)));
const match = /^\s*\[[\s\S]*\]\s*$/m.exec(raw);
if (!match || match.length !== 1) {
throw new Error('Could not parse result of `pnpm list --json`' + raw);
}
const usingPackagedDependencies = Array.isArray(packagedDependencies);
const trees = _.values(JSON.parse(match[0])[0].dependencies) as PnpmTreeNode[];
let result = (
await Promise.all(
trees.map(tree => asPnpmDependency(path.join(cwd, 'node_modules'), tree, !usingPackagedDependencies))
)
).filter(dep => !!dep);
if (usingPackagedDependencies) {
result = selectYarnDependencies(result, packagedDependencies);
}
return result;
}
async function getYarnProductionDependencies(cwd: string, packagedDependencies?: string[]): Promise<YarnDependency[]> {
const raw = await new Promise<string>((c, e) => cp.exec('yarn list --prod --json', { cwd, encoding: 'utf8', env: { ...process.env }, maxBuffer: 5000 * 1024 }, (err, stdout) => err ? e(err) : c(stdout)));
const match = /^{"type":"tree".*$/m.exec(raw);
@ -179,8 +237,34 @@ async function getYarnDependencies(cwd: string, packagedDependencies?: string[])
return _.uniq(result);
}
export function getDependencies(cwd: string, useYarn = false, packagedDependencies?: string[]): Promise<string[]> {
return useYarn ? getYarnDependencies(cwd, packagedDependencies) : getNpmDependencies(cwd);
async function getPnpmDependencies(cwd: string, packagedDependencies?: string[]): Promise<string[]> {
const result: string[] = [cwd];
if (await new Promise(c => fs.exists(path.join(cwd, 'pnpm-lock.yaml'), c))) {
const deps = await getPnpmProductionDependencies(cwd, packagedDependencies);
const flatten = (dep: YarnDependency) => { result.push(dep.path); dep.children.forEach(flatten); };
deps.forEach(flatten);
}
return _.uniq(result);
}
export function getDependencies(cwd: string, useYarn = false, usePackageManager: "yarn" | "npm" | "pnpm", packagedDependencies?: string[]): Promise<string[]> {
if(useYarn) {
return getYarnDependencies(cwd, packagedDependencies);
}
else if(usePackageManager == "npm") {
return getNpmDependencies(cwd);
}
else if(usePackageManager == "pnpm") {
return getPnpmDependencies(cwd, packagedDependencies);
}
else if(usePackageManager == "yarn") {
return getYarnDependencies(cwd, packagedDependencies);
}
else {
return getNpmDependencies(cwd);
}
}
export function getLatestVersion(name: string, cancellationToken?: CancellationToken): Promise<string> {

View file

@ -64,6 +64,7 @@ export interface IPackageOptions {
baseContentUrl?: string;
baseImagesUrl?: string;
useYarn?: boolean;
usePackageManager?: "yarn" | "npm" | "pnpm";
dependencyEntryPoints?: string[];
ignoreFile?: string;
expandGitHubIssueLinks?: boolean;
@ -919,8 +920,8 @@ const defaultIgnore = [
'**/.vscode-test/**'
];
function collectAllFiles(cwd: string, useYarn = false, dependencyEntryPoints?: string[]): Promise<string[]> {
return getDependencies(cwd, useYarn, dependencyEntryPoints).then(deps => {
function collectAllFiles(cwd: string, useYarn = false, usePackageManager: "yarn" | "npm" | "pnpm" = "npm", dependencyEntryPoints?: string[]): Promise<string[]> {
return getDependencies(cwd, useYarn, usePackageManager, dependencyEntryPoints).then(deps => {
const promises: Promise<string[]>[] = deps.map(dep => {
return glob('**', { cwd: dep, nodir: true, dot: true, ignore: 'node_modules/**' })
.then(files => files
@ -932,8 +933,8 @@ function collectAllFiles(cwd: string, useYarn = false, dependencyEntryPoints?: s
});
}
function collectFiles(cwd: string, useYarn = false, dependencyEntryPoints?: string[], ignoreFile?: string): Promise<string[]> {
return collectAllFiles(cwd, useYarn, dependencyEntryPoints).then(files => {
function collectFiles(cwd: string, useYarn = false, usePackageManager: "yarn" | "npm" | "pnpm" = "npm", dependencyEntryPoints?: string[], ignoreFile?: string): Promise<string[]> {
return collectAllFiles(cwd, useYarn, usePackageManager, dependencyEntryPoints).then(files => {
files = files.filter(f => !/\r$/m.test(f));
return readFile(ignoreFile ? ignoreFile : path.join(cwd, '.vscodeignore'), 'utf8')
@ -997,11 +998,12 @@ export function createDefaultProcessors(manifest: Manifest, options: IPackageOpt
export function collect(manifest: Manifest, options: IPackageOptions = {}): Promise<IFile[]> {
const cwd = options.cwd || process.cwd();
const useYarn = options.useYarn || false;
const usePackageManager = options.usePackageManager || "npm";
const packagedDependencies = options.dependencyEntryPoints || undefined;
const ignoreFile = options.ignoreFile || undefined;
const processors = createDefaultProcessors(manifest, options);
return collectFiles(cwd, useYarn, packagedDependencies, ignoreFile).then(fileNames => {
return collectFiles(cwd, useYarn, usePackageManager, packagedDependencies, ignoreFile).then(fileNames => {
const files = fileNames.map(f => ({ path: `extension/${f}`, localPath: path.join(cwd, f) }));
return processFiles(processors, files);
@ -1029,15 +1031,28 @@ function getDefaultPackageName(manifest: Manifest): string {
return `${manifest.name}-${manifest.version}.vsix`;
}
async function prepublish(cwd: string, manifest: Manifest, useYarn: boolean = false): Promise<void> {
async function prepublish(cwd: string, manifest: Manifest, useYarn: boolean = false, usePackageManager: "yarn" | "npm" | "pnpm" = "npm"): Promise<void> {
if (!manifest.scripts || !manifest.scripts['vscode:prepublish']) {
return;
}
console.log(`Executing prepublish script '${useYarn ? 'yarn' : 'npm'} run vscode:prepublish'...`);
let tool = 'npm';
if(useYarn) {
tool = 'yarn'
}
else if(usePackageManager == "npm") {
tool = 'npm';
}
else if(usePackageManager == "pnpm") {
tool = 'pnpm';
}
else if(usePackageManager == "yarn") {
tool = 'yarn'
}
console.log(`Executing prepublish script '${tool} run vscode:prepublish'...`);
await new Promise((c, e) => {
const tool = useYarn ? 'yarn' : 'npm';
const child = cp.spawn(tool, ['run', 'vscode:prepublish'], { cwd, shell: true, stdio: 'inherit' });
child.on('exit', code => code === 0 ? c() : e(`${tool} failed with exit code ${code}`));
child.on('error', e);
@ -1067,7 +1082,7 @@ export async function pack(options: IPackageOptions = {}): Promise<IPackageResul
const manifest = await readManifest(cwd);
await prepublish(cwd, manifest, options.useYarn);
await prepublish(cwd, manifest, options.useYarn, options.usePackageManager);
const files = await collect(manifest, options);
const jsFiles = files.filter(f => /\.js$/i.test(f.path));
@ -1103,17 +1118,17 @@ export async function packageCommand(options: IPackageOptions = {}): Promise<any
/**
* Lists the files included in the extension's package. Does not run prepublish.
*/
export function listFiles(cwd = process.cwd(), useYarn = false, packagedDependencies?: string[], ignoreFile?: string): Promise<string[]> {
export function listFiles(cwd = process.cwd(), useYarn = false, usePackageManager: "yarn" | "npm" | "pnpm" = "npm", packagedDependencies?: string[], ignoreFile?: string): Promise<string[]> {
return readManifest(cwd)
.then(() => collectFiles(cwd, useYarn, packagedDependencies, ignoreFile));
.then(() => collectFiles(cwd, useYarn, usePackageManager, packagedDependencies, ignoreFile));
}
/**
* Lists the files included in the extension's package. Runs prepublish.
*/
export function ls(cwd = process.cwd(), useYarn = false, packagedDependencies?: string[], ignoreFile?: string): Promise<void> {
export function ls(cwd = process.cwd(), useYarn = false, usePackageManager?: "yarn" | "npm" | "pnpm", packagedDependencies?: string[], ignoreFile?: string): Promise<void> {
return readManifest(cwd)
.then(manifest => prepublish(cwd, manifest, useYarn))
.then(() => collectFiles(cwd, useYarn, packagedDependencies, ignoreFile))
.then(manifest => prepublish(cwd, manifest, useYarn, usePackageManager))
.then(() => collectFiles(cwd, useYarn, usePackageManager, packagedDependencies, ignoreFile))
.then(files => files.forEach(f => console.log(`${f}`)));
}

View file

@ -96,6 +96,7 @@ export interface IPublishOptions {
baseContentUrl?: string;
baseImagesUrl?: string;
useYarn?: boolean;
usePackageManager?: "yarn" | "npm" | "pnpm";
noVerify?: boolean;
ignoreFile?: string;
web?: boolean;