mirror of
https://github.com/danog/code-server.git
synced 2024-11-27 04:45:52 +01:00
c4c480a068
* Implement last opened functionality Fixes https://github.com/cdr/code-server/issues/4619 * Fix test temp dirs not being cleaned up * Mock logger everywhere This suppresses all the error and debug output we generate which makes it hard to actually find which test has failed. It also gives us a standard way to test logging for the few places we do that. * Use separate data directories for unit test instances Exactly as we do for the e2e tests. * Add integration tests for vscode route * Make settings use --user-data-dir Without this test instances step on each other feet and they also clobber your own non-test settings. * Make redirects consistent They will preserve the trailing slash if there is one. * Remove compilation check If you do a regular non-watch build there are no compilation stats so this bricks VS Code in CI when running the unit tests. I am not sure how best to fix this for the case where you have a build that has not been packaged yet so I just removed it for now and added a message to check if VS Code is compiling when in dev mode. * Update code-server update endpoint name
141 lines
4.0 KiB
TypeScript
141 lines
4.0 KiB
TypeScript
import { spawn, fork, ChildProcess } from "child_process"
|
|
import * as path from "path"
|
|
import { onLine, OnLineCallback } from "../../src/node/util"
|
|
|
|
interface DevelopmentCompilers {
|
|
[key: string]: ChildProcess | undefined
|
|
vscode: ChildProcess
|
|
vscodeWebExtensions: ChildProcess
|
|
codeServer: ChildProcess
|
|
plugins: ChildProcess | undefined
|
|
}
|
|
|
|
class Watcher {
|
|
private rootPath = path.resolve(process.cwd())
|
|
private readonly paths = {
|
|
/** Path to uncompiled VS Code source. */
|
|
vscodeDir: path.join(this.rootPath, "vendor", "modules", "code-oss-dev"),
|
|
pluginDir: process.env.PLUGIN_DIR,
|
|
}
|
|
|
|
//#region Web Server
|
|
|
|
/** Development web server. */
|
|
private webServer: ChildProcess | undefined
|
|
|
|
private reloadWebServer = (): void => {
|
|
if (this.webServer) {
|
|
this.webServer.kill()
|
|
}
|
|
|
|
// Pass CLI args, save for `node` and the initial script name.
|
|
const args = process.argv.slice(2)
|
|
this.webServer = fork(path.join(this.rootPath, "out/node/entry.js"), args)
|
|
const { pid } = this.webServer
|
|
|
|
this.webServer.on("exit", () => console.log("[Code Server]", `Web process ${pid} exited`))
|
|
|
|
console.log("\n[Code Server]", `Spawned web server process ${pid}`)
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region Compilers
|
|
|
|
private readonly compilers: DevelopmentCompilers = {
|
|
codeServer: spawn("tsc", ["--watch", "--pretty", "--preserveWatchOutput"], { cwd: this.rootPath }),
|
|
vscode: spawn("yarn", ["watch"], { cwd: this.paths.vscodeDir }),
|
|
vscodeWebExtensions: spawn("yarn", ["watch-web"], { cwd: this.paths.vscodeDir }),
|
|
plugins: this.paths.pluginDir ? spawn("yarn", ["build", "--watch"], { cwd: this.paths.pluginDir }) : undefined,
|
|
}
|
|
|
|
public async initialize(): Promise<void> {
|
|
for (const event of ["SIGINT", "SIGTERM"]) {
|
|
process.on(event, () => this.dispose(0))
|
|
}
|
|
|
|
for (const [processName, devProcess] of Object.entries(this.compilers)) {
|
|
if (!devProcess) continue
|
|
|
|
devProcess.on("exit", (code) => {
|
|
console.log(`[${processName}]`, "Terminated unexpectedly")
|
|
this.dispose(code)
|
|
})
|
|
|
|
if (devProcess.stderr) {
|
|
devProcess.stderr.on("data", (d: string | Uint8Array) => process.stderr.write(d))
|
|
}
|
|
}
|
|
|
|
onLine(this.compilers.vscode, this.parseVSCodeLine)
|
|
onLine(this.compilers.codeServer, this.parseCodeServerLine)
|
|
|
|
if (this.compilers.plugins) {
|
|
onLine(this.compilers.plugins, this.parsePluginLine)
|
|
}
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region Line Parsers
|
|
|
|
private parseVSCodeLine: OnLineCallback = (strippedLine, originalLine) => {
|
|
if (!strippedLine.length) return
|
|
|
|
console.log("[VS Code]", originalLine)
|
|
|
|
if (strippedLine.includes("Finished compilation with")) {
|
|
console.log("[VS Code] ✨ Finished compiling! ✨", "(Refresh your web browser ♻️)")
|
|
this.reloadWebServer()
|
|
}
|
|
}
|
|
|
|
private parseCodeServerLine: OnLineCallback = (strippedLine, originalLine) => {
|
|
if (!strippedLine.length) return
|
|
|
|
console.log("[Compiler][Code Server]", originalLine)
|
|
|
|
if (strippedLine.includes("Watching for file changes")) {
|
|
console.log("[Compiler][Code Server]", "Finished compiling!", "(Refresh your web browser ♻️)")
|
|
this.reloadWebServer()
|
|
}
|
|
}
|
|
|
|
private parsePluginLine: OnLineCallback = (strippedLine, originalLine) => {
|
|
if (!strippedLine.length) return
|
|
|
|
console.log("[Compiler][Plugin]", originalLine)
|
|
|
|
if (strippedLine.includes("Watching for file changes...")) {
|
|
this.reloadWebServer()
|
|
}
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region Utilities
|
|
|
|
private dispose(code: number | null): void {
|
|
for (const [processName, devProcess] of Object.entries(this.compilers)) {
|
|
console.log(`[${processName}]`, "Killing...\n")
|
|
devProcess?.removeAllListeners()
|
|
devProcess?.kill()
|
|
}
|
|
process.exit(typeof code === "number" ? code : 0)
|
|
}
|
|
|
|
//#endregion
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
try {
|
|
const watcher = new Watcher()
|
|
await watcher.initialize()
|
|
} catch (error: any) {
|
|
console.error(error.message)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
|
|
main()
|