This commit is contained in:
Anmol Sethi 2020-10-30 03:26:30 -04:00
parent bea185b8b2
commit 82e8a00a0d
No known key found for this signature in database
GPG Key ID: 8CEF1878FF10ADEB
4 changed files with 50 additions and 47 deletions

View File

@ -1,12 +1,12 @@
import * as path from "path"
import * as util from "./util"
import * as pluginapi from "../../typings/plugin"
import * as fs from "fs"
import * as semver from "semver"
import { version } from "./constants"
const fsp = fs.promises
import { Logger, field } from "@coder/logger" import { Logger, field } from "@coder/logger"
import * as express from "express" import * as express from "express"
import * as fs from "fs"
import * as path from "path"
import * as semver from "semver"
import * as pluginapi from "../../typings/plugin"
import { version } from "./constants"
import * as util from "./util"
const fsp = fs.promises
// These fields are populated from the plugin's package.json. // These fields are populated from the plugin's package.json.
interface Plugin extends pluginapi.Plugin { interface Plugin extends pluginapi.Plugin {
@ -34,7 +34,7 @@ export class PluginAPI {
*/ */
private readonly csPlugin = "", private readonly csPlugin = "",
private readonly csPluginPath = `${path.join(util.paths.data, "plugins")}:/usr/share/code-server/plugins`, private readonly csPluginPath = `${path.join(util.paths.data, "plugins")}:/usr/share/code-server/plugins`,
){ ) {
this.logger = logger.named("pluginapi") this.logger = logger.named("pluginapi")
} }
@ -44,7 +44,7 @@ export class PluginAPI {
*/ */
public async applications(): Promise<Application[]> { public async applications(): Promise<Application[]> {
const apps = new Array<Application>() const apps = new Array<Application>()
for (let p of this.plugins) { for (const p of this.plugins) {
const pluginApps = await p.applications() const pluginApps = await p.applications()
// TODO prevent duplicates // TODO prevent duplicates
@ -62,7 +62,7 @@ export class PluginAPI {
* mount mounts all plugin routers onto r. * mount mounts all plugin routers onto r.
*/ */
public mount(r: express.Router): void { public mount(r: express.Router): void {
for (let p of this.plugins) { for (const p of this.plugins) {
r.use(`/${p.name}`, p.router()) r.use(`/${p.name}`, p.router())
} }
} }
@ -75,14 +75,14 @@ export class PluginAPI {
// Built-in plugins. // Built-in plugins.
await this._loadPlugins(path.join(__dirname, "../../plugins")) await this._loadPlugins(path.join(__dirname, "../../plugins"))
for (let dir of this.csPluginPath.split(":")) { for (const dir of this.csPluginPath.split(":")) {
if (!dir) { if (!dir) {
continue continue
} }
await this._loadPlugins(dir) await this._loadPlugins(dir)
} }
for (let dir of this.csPlugin.split(":")) { for (const dir of this.csPlugin.split(":")) {
if (!dir) { if (!dir) {
continue continue
} }
@ -93,7 +93,7 @@ export class PluginAPI {
private async _loadPlugins(dir: string): Promise<void> { private async _loadPlugins(dir: string): Promise<void> {
try { try {
const entries = await fsp.readdir(dir, { withFileTypes: true }) const entries = await fsp.readdir(dir, { withFileTypes: true })
for (let ent of entries) { for (const ent of entries) {
if (!ent.isDirectory()) { if (!ent.isDirectory()) {
continue continue
} }
@ -124,14 +124,12 @@ export class PluginAPI {
private _loadPlugin(dir: string, packageJSON: PackageJSON): Plugin { private _loadPlugin(dir: string, packageJSON: PackageJSON): Plugin {
const logger = this.logger.named(packageJSON.name) const logger = this.logger.named(packageJSON.name)
logger.debug("loading plugin", logger.debug("loading plugin", field("plugin_dir", dir), field("package_json", packageJSON))
field("plugin_dir", dir),
field("package_json", packageJSON),
)
if (!semver.satisfies(version, packageJSON.engines["code-server"])) { if (!semver.satisfies(version, packageJSON.engines["code-server"])) {
throw new Error(`plugin range ${q(packageJSON.engines["code-server"])} incompatible` + throw new Error(
` with code-server version ${version}`) `plugin range ${q(packageJSON.engines["code-server"])} incompatible` + ` with code-server version ${version}`,
)
} }
if (!packageJSON.name) { if (!packageJSON.name) {
throw new Error("plugin missing name") throw new Error("plugin missing name")

View File

@ -1,8 +1,8 @@
import { describe } from "mocha"
import { PluginAPI } from "../src/node/plugin"
import { logger } from "@coder/logger" import { logger } from "@coder/logger"
import * as path from "path"
import * as assert from "assert" import * as assert from "assert"
import { describe } from "mocha"
import * as path from "path"
import { PluginAPI } from "../src/node/plugin"
/** /**
* Use $LOG_LEVEL=debug to see debug logs. * Use $LOG_LEVEL=debug to see debug logs.
@ -15,17 +15,20 @@ describe("plugin", () => {
// We remove the function fields from the application's plugins. // We remove the function fields from the application's plugins.
const apps = JSON.parse(JSON.stringify(await papi.applications())) const apps = JSON.parse(JSON.stringify(await papi.applications()))
assert.deepEqual([ assert.deepEqual(
{ [
name: "goland", {
version: "4.0.0", name: "goland",
iconPath: "icon.svg", version: "4.0.0",
plugin: { iconPath: "icon.svg",
name: "test-plugin", plugin: {
version: "1.0.0", name: "test-plugin",
description: "Fake plugin for testing code-server's plugin API", version: "1.0.0",
description: "Fake plugin for testing code-server's plugin API",
},
}, },
}, ],
], apps) apps,
)
}) })
}) })

View File

@ -1,6 +1,6 @@
import * as pluginapi from "../../../typings/plugin"
import * as express from "express" import * as express from "express"
import * as path from "path"; import * as path from "path"
import * as pluginapi from "../../../typings/plugin"
export function init(config: pluginapi.PluginConfig) { export function init(config: pluginapi.PluginConfig) {
config.logger.debug("test-plugin loaded!") config.logger.debug("test-plugin loaded!")
@ -15,9 +15,11 @@ export function router(): express.Router {
} }
export function applications(): pluginapi.Application[] { export function applications(): pluginapi.Application[] {
return [{ return [
name: "goland", {
version: "4.0.0", name: "goland",
iconPath: "icon.svg", version: "4.0.0",
}] iconPath: "icon.svg",
},
]
} }

View File

@ -4,8 +4,8 @@
/* Basic Options */ /* Basic Options */
// "incremental": true, /* Enable incremental compilation */ // "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */ // "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */ // "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */ // "checkJs": true, /* Report errors in .js files. */
@ -14,7 +14,7 @@
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */ // "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */ // "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./out", /* Redirect output structure to the directory. */ "outDir": "./out" /* Redirect output structure to the directory. */,
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */ // "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
@ -25,7 +25,7 @@
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */ /* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */ "strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */ // "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */
@ -48,7 +48,7 @@
// "typeRoots": [], /* List of folders to include type definitions from. */ // "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */ // "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
@ -63,7 +63,7 @@
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */ /* Advanced Options */
"skipLibCheck": true, /* Skip type checking of declaration files. */ "skipLibCheck": true /* Skip type checking of declaration files. */,
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
} }
} }