Skip to content

Commit 528cbc8

Browse files
committed
Move more config into local typescript gulpfile
1 parent 2c5b672 commit 528cbc8

15 files changed

Lines changed: 10883 additions & 36 deletions

File tree

extensions/ql-vscode/.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module.exports = {
33
parserOptions: {
44
ecmaVersion: 2018,
55
sourceType: "module",
6-
project: ["tsconfig.json", "./src/**/tsconfig.json"],
6+
project: ["tsconfig.json", "./src/**/tsconfig.json", "./_gulpfile.ts/tsconfig.json"],
77
},
88
plugins: ["@typescript-eslint"],
99
env: {
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import * as fs from 'fs-extra';
2+
import * as jsonc from 'jsonc-parser';
3+
import { IPackageJson } from '@microsoft/node-core-library';
4+
import * as path from 'path';
5+
import { getRushContext, RushContext } from './rush';
6+
import * as packlist from 'npm-packlist';
7+
import * as glob from 'glob-promise';
8+
import * as cpp from 'child-process-promise';
9+
10+
interface PackageInfo {
11+
name: string;
12+
version: string;
13+
sourcePath: string;
14+
files: string[];
15+
dependencies: PackageInfo[];
16+
isRoot?: boolean;
17+
copied?: boolean;
18+
}
19+
20+
async function copyPackage(packageFiles: PackageInfo, destPath: string): Promise<void> {
21+
for (const file of packageFiles.files) {
22+
const sourceFilePath = path.resolve(packageFiles.sourcePath, file);
23+
const destFilePath = path.resolve(destPath, file);
24+
if (packageFiles.isRoot && (file === 'package.json')) {
25+
// For non-release builds, we tweak the version number of the extension to add a prerelease
26+
// suffix. Rather than just copying `package.json`, we'll parse the original copy, update the
27+
// `version` property, and write it out to the new location.
28+
const packageJson = jsonc.parse((await fs.readFile(sourceFilePath)).toString());
29+
packageJson.version = packageFiles.version;
30+
await fs.writeFile(destFilePath, JSON.stringify(packageJson));
31+
}
32+
else {
33+
await fs.copy(sourceFilePath, destFilePath);
34+
}
35+
}
36+
}
37+
38+
export interface DeployedPackage {
39+
distPath: string;
40+
name: string;
41+
version: string;
42+
}
43+
44+
class PackageMap {
45+
private map = new Map<string, Map<string, PackageInfo>>();
46+
47+
public getPackageInfo(name: string, version: string): PackageInfo | undefined {
48+
const versionMap = this.map.get(name);
49+
if (versionMap === undefined) {
50+
return undefined;
51+
}
52+
53+
return versionMap.get(version);
54+
}
55+
56+
public addPackageInfo(pkg: PackageInfo): void {
57+
if (this.getPackageInfo(pkg.name, pkg.version)) {
58+
throw new Error(`Attempt to add duplicate package '${pkg.name}@${pkg.version}'.`);
59+
}
60+
61+
let versionMap = this.map.get(pkg.name);
62+
if (versionMap === undefined) {
63+
versionMap = new Map<string, PackageInfo>();
64+
this.map.set(pkg.name, versionMap);
65+
}
66+
67+
versionMap.set(pkg.version, pkg);
68+
}
69+
70+
public hasMultipleVersions(name: string): boolean {
71+
return this.map.get(name)!.size > 1;
72+
}
73+
}
74+
75+
async function collectPackages(context: RushContext, name: string, version: string,
76+
pkgs: PackageMap): Promise<PackageInfo> {
77+
78+
let pkg = pkgs.getPackageInfo(name, version);
79+
if (!pkg) {
80+
const info = await context.getPackageInfo(name, version);
81+
82+
let files: string[];
83+
if (info.isLocal) {
84+
// For local packages, use `packlist` to get the list of files that npm would have packed
85+
// into the tarball.
86+
files = packlist.sync({ path: info.path });
87+
}
88+
else {
89+
// For non-local packages, just copy everything.
90+
files = await glob('**/*', {
91+
nodir: true,
92+
cwd: info.path
93+
});
94+
}
95+
96+
pkg = {
97+
name: name,
98+
version: version,
99+
sourcePath: info.path,
100+
files: files,
101+
dependencies: []
102+
};
103+
104+
pkgs.addPackageInfo(pkg);
105+
106+
for (const dependencyName of info.dependencies.keys()) {
107+
const dependencyVersion = info.dependencies.get(dependencyName)!;
108+
109+
const dependencyPackage = await collectPackages(context, dependencyName, dependencyVersion, pkgs);
110+
pkg.dependencies.push(dependencyPackage);
111+
}
112+
}
113+
114+
return pkg;
115+
}
116+
117+
async function copyPackageAndModules(pkg: PackageInfo, pkgs: PackageMap, destPath: string,
118+
rootNodeModulesPath: string): Promise<void> {
119+
120+
let destPackagePath: string;
121+
if (pkgs.hasMultipleVersions(pkg.name) || pkg.isRoot) {
122+
// Copy as a nested package, and let `npm dedupe` fix it up later if possible.
123+
destPackagePath = path.join(destPath, pkg.name);
124+
}
125+
else {
126+
// Copy to the root `node_modules` directory.
127+
if (pkg.copied) {
128+
return;
129+
}
130+
pkg.copied = true;
131+
destPackagePath = path.join(rootNodeModulesPath, pkg.name);
132+
}
133+
134+
await copyPackage(pkg, destPackagePath);
135+
const nodeModulesPath = path.join(destPackagePath, 'node_modules');
136+
for (const dependencyPkg of pkg.dependencies) {
137+
await copyPackageAndModules(dependencyPkg, pkgs, nodeModulesPath, rootNodeModulesPath);
138+
}
139+
}
140+
141+
export async function deployPackage(packageJsonPath: string): Promise<DeployedPackage> {
142+
try {
143+
const context = await getRushContext(path.dirname(packageJsonPath));
144+
145+
const rootPackage: IPackageJson = jsonc.parse(await fs.readFile(packageJsonPath, 'utf8'));
146+
147+
// Default to development build; use flag --release to indicate release build.
148+
const isDevBuild = !process.argv.includes('--release');
149+
const distDir = path.join(context.rushConfig.rushJsonFolder, 'dist');
150+
await fs.mkdirs(distDir);
151+
152+
if (isDevBuild) {
153+
// NOTE: rootPackage.name had better not have any regex metacharacters
154+
const oldDevBuildPattern = new RegExp('^' + rootPackage.name + '[^/]+-dev[0-9.]+\\.vsix$');
155+
// Dev package filenames are of the form
156+
// vscode-codeql-0.0.1-dev.2019.9.27.19.55.20.vsix
157+
(await fs.readdir(distDir)).filter(name => name.match(oldDevBuildPattern)).map(build => {
158+
console.log(`Deleting old dev build ${build}...`);
159+
fs.unlinkSync(path.join(distDir, build));
160+
});
161+
const now = new Date();
162+
rootPackage.version = rootPackage.version +
163+
`-dev.${now.getUTCFullYear()}.${now.getUTCMonth() + 1}.${now.getUTCDate()}` +
164+
`.${now.getUTCHours()}.${now.getUTCMinutes()}.${now.getUTCSeconds()}`;
165+
}
166+
167+
const distPath = path.join(distDir, rootPackage.name);
168+
await fs.remove(distPath);
169+
await fs.mkdirs(distPath);
170+
171+
console.log(`Gathering transitive dependencies of package '${rootPackage.name}'...`);
172+
const pkgs = new PackageMap();
173+
const rootPkg = await collectPackages(context, rootPackage.name, rootPackage.version, pkgs);
174+
rootPkg.isRoot = true;
175+
176+
console.log(`Copying package '${rootPackage.name}' and its dependencies to '${distPath}'...`);
177+
await copyPackageAndModules(rootPkg, pkgs, path.dirname(distPath), path.join(distPath, 'node_modules'));
178+
await fs.copy(path.resolve(rootPkg.sourcePath, '.vscodeignore'), path.resolve(distPath, '.vscodeignore'));
179+
180+
console.log(`Deduplicating dependencies of package '${rootPackage.name}'...`);
181+
// We create a temporary `package-lock.json` file just to prevent `npm ls` from printing out the
182+
// message that it created a package-lock.json.
183+
const packageLockPath = path.join(distPath, 'package-lock.json');
184+
await fs.writeFile(packageLockPath, '{}');
185+
await cpp.spawn('npm', ['dedupe'], {
186+
cwd: distPath,
187+
stdio: 'inherit'
188+
});
189+
await fs.unlink(packageLockPath);
190+
191+
return {
192+
distPath: distPath,
193+
name: rootPackage.name,
194+
version: rootPackage.version
195+
};
196+
}
197+
catch (e) {
198+
console.error(e);
199+
throw e;
200+
}
201+
}
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
const task = (done: any) => {
2-
console.log('Hello world!');
3-
done();
4-
};
1+
import * as gulp from 'gulp';
2+
import { compileTypeScript, watchTypeScript, copyViewCss } from './typescript';
3+
import { compileTextMateGrammar } from './textmate';
4+
import { copyTestData } from './tests';
5+
import { compileView } from './webpack';
56

6-
7-
export default task;
7+
export const buildWithoutPackage = gulp.parallel(compileTypeScript, compileTextMateGrammar, compileView, copyTestData, copyViewCss);
8+
export { compileTextMateGrammar, watchTypeScript, compileTypeScript };
9+
// exports.default = gulp.series(exports.buildWithoutPackage, packageExtension);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as path from 'path';
2+
import { deployPackage } from './deploy';
3+
import * as childProcess from 'child-process-promise';
4+
5+
export async function packageExtension(): Promise<void> {
6+
const deployedPackage = await deployPackage(path.resolve('package.json'));
7+
console.log(`Packaging extension '${deployedPackage.name}@${deployedPackage.version}'...`);
8+
const args = [
9+
'package',
10+
'--out', path.resolve(deployedPackage.distPath, '..', `${deployedPackage.name}-${deployedPackage.version}.vsix`)
11+
];
12+
const proc = childProcess.spawn('vsce', args, {
13+
cwd: deployedPackage.distPath
14+
});
15+
proc.childProcess.stdout!.on('data', (data) => {
16+
console.log(data.toString());
17+
});
18+
proc.childProcess.stderr!.on('data', (data) => {
19+
console.error(data.toString());
20+
});
21+
22+
await proc;
23+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export interface PackageDependencies {
2+
[key: string]: string;
3+
}
4+
5+
export interface ShrinkwrapPackage {
6+
dependencies?: PackageDependencies;
7+
dev?: boolean;
8+
name?: string;
9+
version?: string;
10+
}
11+
12+
export interface Shrinkwrap {
13+
dependencies: PackageDependencies;
14+
packages: {
15+
[key: string]: ShrinkwrapPackage;
16+
};
17+
}

0 commit comments

Comments
 (0)