|
1 | 1 | import * as fs from 'fs-extra'; |
2 | 2 | import * as jsonc from 'jsonc-parser'; |
3 | | -import { IPackageJson } from '@microsoft/node-core-library'; |
4 | 3 | 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 | 4 |
|
38 | 5 | export interface DeployedPackage { |
39 | 6 | distPath: string; |
40 | 7 | name: string; |
41 | 8 | version: string; |
42 | 9 | } |
43 | 10 |
|
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); |
| 11 | +const packageFiles = [ |
| 12 | + '.vscodeignore', |
| 13 | + 'CHANGELOG.md', |
| 14 | + 'README.md', |
| 15 | + 'language-configuration.json', |
| 16 | + 'media', |
| 17 | + 'node_modules', |
| 18 | + 'out' |
| 19 | +]; |
| 20 | + |
| 21 | +async function copyPackage(sourcePath: string, destPath: string): Promise<void> { |
| 22 | + for (const file of packageFiles) { |
| 23 | + console.log(`copying ${path.resolve(sourcePath, file)} to ${path.resolve(destPath, file)}`); |
| 24 | + await fs.copy(path.resolve(sourcePath, file), path.resolve(destPath, file)); |
138 | 25 | } |
139 | 26 | } |
140 | 27 |
|
141 | 28 | export async function deployPackage(packageJsonPath: string): Promise<DeployedPackage> { |
142 | 29 | try { |
143 | | - const context = await getRushContext(path.dirname(packageJsonPath)); |
144 | | - |
145 | | - const rootPackage: IPackageJson = jsonc.parse(await fs.readFile(packageJsonPath, 'utf8')); |
| 30 | + const packageJson: any = jsonc.parse(await fs.readFile(packageJsonPath, 'utf8')); |
146 | 31 |
|
147 | 32 | // Default to development build; use flag --release to indicate release build. |
148 | 33 | const isDevBuild = !process.argv.includes('--release'); |
149 | | - const distDir = path.join(context.rushConfig.rushJsonFolder, 'dist'); |
| 34 | + const distDir = path.join(__dirname, '../../../dist'); |
150 | 35 | await fs.mkdirs(distDir); |
151 | 36 |
|
152 | 37 | if (isDevBuild) { |
153 | 38 | // NOTE: rootPackage.name had better not have any regex metacharacters |
154 | | - const oldDevBuildPattern = new RegExp('^' + rootPackage.name + '[^/]+-dev[0-9.]+\\.vsix$'); |
| 39 | + const oldDevBuildPattern = new RegExp('^' + packageJson.name + '[^/]+-dev[0-9.]+\\.vsix$'); |
155 | 40 | // Dev package filenames are of the form |
156 | 41 | // vscode-codeql-0.0.1-dev.2019.9.27.19.55.20.vsix |
157 | 42 | (await fs.readdir(distDir)).filter(name => name.match(oldDevBuildPattern)).map(build => { |
158 | 43 | console.log(`Deleting old dev build ${build}...`); |
159 | 44 | fs.unlinkSync(path.join(distDir, build)); |
160 | 45 | }); |
161 | 46 | const now = new Date(); |
162 | | - rootPackage.version = rootPackage.version + |
| 47 | + packageJson.version = packageJson.version + |
163 | 48 | `-dev.${now.getUTCFullYear()}.${now.getUTCMonth() + 1}.${now.getUTCDate()}` + |
164 | 49 | `.${now.getUTCHours()}.${now.getUTCMinutes()}.${now.getUTCSeconds()}`; |
165 | 50 | } |
166 | 51 |
|
167 | | - const distPath = path.join(distDir, rootPackage.name); |
| 52 | + const distPath = path.join(distDir, packageJson.name); |
168 | 53 | await fs.remove(distPath); |
169 | 54 | await fs.mkdirs(distPath); |
170 | 55 |
|
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')); |
| 56 | + await fs.writeFile(path.join(distPath, 'package.json'), JSON.stringify(packageJson, null, 2)); |
179 | 57 |
|
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); |
| 58 | + const sourcePath = path.join(__dirname, '..'); |
| 59 | + console.log(`Copying package '${packageJson.name}' and its dependencies to '${distPath}'...`); |
| 60 | + await copyPackage(sourcePath, distPath); |
190 | 61 |
|
191 | 62 | return { |
192 | 63 | distPath: distPath, |
193 | | - name: rootPackage.name, |
194 | | - version: rootPackage.version |
| 64 | + name: packageJson.name, |
| 65 | + version: packageJson.version |
195 | 66 | }; |
196 | 67 | } |
197 | 68 | catch (e) { |
|
0 commit comments