Developer documentation
This commit is contained in:
Родитель
4a34b4a683
Коммит
2a11ad5166
|
@ -16,7 +16,7 @@
|
|||
"${workspaceRoot}/out/test/*"
|
||||
],
|
||||
"preLaunchTask": "npm",
|
||||
"smartStep": true
|
||||
"smartStep": false
|
||||
},
|
||||
{
|
||||
"name": "Launch Tests",
|
||||
|
|
|
@ -55,6 +55,8 @@ if(SPHINX_EXECUTABLE)
|
|||
-j 10
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/docs"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/docs"
|
||||
COMMAND "${YARN_EXECUTABLE}" --silent docs
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
COMMENT "Generating documentation"
|
||||
)
|
||||
endif()
|
||||
|
|
|
@ -18,6 +18,11 @@ Contents:
|
|||
|
||||
kits
|
||||
|
||||
Developer Reference
|
||||
===================
|
||||
|
||||
`Documentation for the code itself is kept within the code, and is extracted via
|
||||
TypeDoc. See the developer reference documentation here <dev/index.html>`_.
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
|
34
package.json
34
package.json
|
@ -636,30 +636,32 @@
|
|||
"vscode:prepublish": "./node_modules/.bin/tsc -p ./",
|
||||
"compile": "./node_modules/.bin/tsc -watch -p ./",
|
||||
"compile-once": "./node_modules/.bin/tsc -p ./",
|
||||
"postinstall": "node ./node_modules/vscode/bin/install"
|
||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||
"docs": "node ./node_modules/.bin/typedoc --mode modules --excludeExternals --out build/docs/dev --readme none --tsconfig tsconfig-docs.json src/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "~2.3.0",
|
||||
"@types/node": "~8.0.0",
|
||||
"vscode": "~1.1.0",
|
||||
"mocha": "~3.4.2",
|
||||
"@types/mocha": "~2.2.41",
|
||||
"@types/js-yaml": "^3.5.28",
|
||||
"@types/ajv": "^0.0.3",
|
||||
"@types/xml2js": "^0.0.28",
|
||||
"@types/es6-promisify": "~5.0.0",
|
||||
"@types/js-yaml": "^3.5.28",
|
||||
"@types/mocha": "~2.2.41",
|
||||
"@types/node": "~8.0.0",
|
||||
"@types/rimraf": "^0.0.28",
|
||||
"@types/ws": "^0.0.38",
|
||||
"@types/es6-promisify": "~5.0.0"
|
||||
"@types/xml2js": "^0.0.28",
|
||||
"mocha": "~3.4.2",
|
||||
"typedoc": "^0.8.0",
|
||||
"typescript": "~2.3.0",
|
||||
"vscode": "~1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"open": "0.0.5",
|
||||
"js-yaml": "^3.6.1",
|
||||
"ajv": "^4.7.5",
|
||||
"xml2js": "^0.4.17",
|
||||
"rimraf": "^2.5.4",
|
||||
"ws": "^1.1.1",
|
||||
"Polymer": "1.6.1--",
|
||||
"ajv": "^4.7.5",
|
||||
"es6-promisify": "~5.0.0",
|
||||
"js-yaml": "^3.6.1",
|
||||
"open": "0.0.5",
|
||||
"rimraf": "^2.5.4",
|
||||
"rollbar": "~2.2.8",
|
||||
"es6-promisify": "~5.0.0"
|
||||
"ws": "^1.1.1",
|
||||
"xml2js": "^0.4.17"
|
||||
}
|
||||
}
|
||||
|
|
313
src/api.ts
313
src/api.ts
|
@ -1,34 +1,90 @@
|
|||
/**
|
||||
* This module defines the external API for the extension. Other
|
||||
* extensions can access this API via the exports instance for the extension.
|
||||
*
|
||||
* Look at the `CMakeToolsAPI` interface for the actual exported API.
|
||||
*
|
||||
* Copy the `api.ts` source file into your project to use it.
|
||||
*/ /** */
|
||||
|
||||
import {DiagnosticCollection, Disposable, Event, TextEditor} from 'vscode';
|
||||
|
||||
|
||||
/**
|
||||
* The result of executing a program.
|
||||
*/
|
||||
export interface ExecutionResult {
|
||||
/**
|
||||
* The return code of the program.
|
||||
*/
|
||||
retc: number;
|
||||
stdout: string|null;
|
||||
stderr: string|null;
|
||||
/**
|
||||
* The full standard output of the program. May be `null` if standard out
|
||||
* was not captured.
|
||||
*/
|
||||
stdout: string | null;
|
||||
/**
|
||||
* Standard error output of the program. May be `null` if standard error was
|
||||
* not captured
|
||||
*/
|
||||
stderr: string | null;
|
||||
}
|
||||
|
||||
export interface ExecuteOptions {
|
||||
/**
|
||||
* Options for executing a command.
|
||||
*/
|
||||
export interface ExecutionOptions {
|
||||
/**
|
||||
* Whether output from the command should be suppressed from CMake Tools'
|
||||
* output channel.
|
||||
*/
|
||||
silent: boolean;
|
||||
environment: {[key: string]: string};
|
||||
/**
|
||||
* Additional environment variables to define when executing the command.
|
||||
*/
|
||||
environment: {[key: string] : string};
|
||||
/**
|
||||
* Whether we should collect output from the command.
|
||||
*
|
||||
* @note All output from the command is collected into a single string, so
|
||||
* commands which emit a lot of output may consume a lot of memory if
|
||||
* `collectOutput` is set to `true`.
|
||||
*/
|
||||
collectOutput?: boolean;
|
||||
/**
|
||||
* The working directory for the command. The default directory is
|
||||
* unspecified.
|
||||
*/
|
||||
workingDirectory?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw, unprocessed compilation information on a source file. This is what
|
||||
* would be found in a compilation database, `compile_commands.json`.
|
||||
*/
|
||||
export interface RawCompilationInfo {
|
||||
file: string;
|
||||
directory: string;
|
||||
command: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nicer, cleaner compilation information on a source file. This would be
|
||||
* provided by CMake Server.
|
||||
*/
|
||||
export interface CompilationInfo {
|
||||
file: string;
|
||||
compile?: RawCompilationInfo;
|
||||
includeDirectories: {path: string; isSystem: boolean;}[];
|
||||
compileDefinitions: {[define: string]: string | null};
|
||||
includeDirectories: {path : string; isSystem : boolean;}[];
|
||||
compileDefinitions: {[define: string] : string | null};
|
||||
compileFlags: string[];
|
||||
compiler?: string;
|
||||
}
|
||||
|
||||
export enum EntryType {
|
||||
/**
|
||||
* The type of a CMake cache entry
|
||||
*/
|
||||
export enum CacheEntryType {
|
||||
Bool = 0,
|
||||
String = 1,
|
||||
Path = 2,
|
||||
|
@ -38,33 +94,66 @@ export enum EntryType {
|
|||
Static = 6,
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a CTest test
|
||||
*/
|
||||
export interface Test {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* The properties of a CMake cache entry.
|
||||
*/
|
||||
export interface CacheEntryProperties {
|
||||
type: EntryType;
|
||||
type: CacheEntryType;
|
||||
helpString: string;
|
||||
/** The name of the cache entry */
|
||||
key: string;
|
||||
/** The entry's value. Type depends on `type`. */
|
||||
value: any;
|
||||
/** Whether this entry is ADVANCED, meaning it hidden from the user. */
|
||||
advanced: boolean;
|
||||
}
|
||||
|
||||
export interface CacheEntry extends CacheEntryProperties { as<T>(): T; }
|
||||
/**
|
||||
* A cache entry from a CMake cache.
|
||||
*/
|
||||
export interface CacheEntry extends CacheEntryProperties {
|
||||
/**
|
||||
* Return the value as a `T` instance. Does no actual conversion. It's up to
|
||||
* you to check the value of `CacheEntryProperties.type`.
|
||||
*/
|
||||
as<T>(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of an executable CMake target, defined via `add_executable()`.
|
||||
*/
|
||||
export interface ExecutableTarget {
|
||||
/**
|
||||
* The name of the target.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* The absolute path to the build output.
|
||||
*/
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface VariantKeywordSettings { [key: string]: string; }
|
||||
|
||||
/**
|
||||
* A target with a name, but no output. This may be created via `add_custom_command()`.
|
||||
*/
|
||||
export interface NamedTarget {
|
||||
type: 'named';
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A target with a name, path, and type.
|
||||
*/
|
||||
export interface RichTarget {
|
||||
type: 'rich';
|
||||
name: string;
|
||||
|
@ -74,72 +163,214 @@ export interface RichTarget {
|
|||
|
||||
export type Target = NamedTarget | RichTarget;
|
||||
|
||||
/**
|
||||
* The CMake Tools extension API obtained via `getExtension().exports`
|
||||
*/
|
||||
export interface CMakeToolsAPI extends Disposable {
|
||||
// Get the root source directory
|
||||
constructor(): never;
|
||||
/**
|
||||
* The source directory, containing the root of the project
|
||||
*/
|
||||
readonly sourceDir: Promise<string>;
|
||||
// Get the main CMake File
|
||||
/**
|
||||
* The `CMakeLists.txt` at to the root of the project
|
||||
*/
|
||||
readonly mainListFile: Promise<string>;
|
||||
// Get the binary directory for the project
|
||||
/**
|
||||
* The root build directory for the project. May change based on build
|
||||
* configuration.
|
||||
*/
|
||||
readonly binaryDir: Promise<string>;
|
||||
// Get the path to the CMake cache
|
||||
/**
|
||||
* The path to the `CMakeCache.txt for the project.
|
||||
*/
|
||||
readonly cachePath: Promise<string>;
|
||||
// Targets which are executable
|
||||
/**
|
||||
* List of CMake targets created via `add_executable()`.
|
||||
*/
|
||||
readonly executableTargets: Promise<ExecutableTarget[]>;
|
||||
// Diagnostics obtained from configure/build
|
||||
/**
|
||||
* CMake code diagnostics. Includes warnings and errors, etc.
|
||||
*/
|
||||
readonly diagnostics: Promise<DiagnosticCollection>;
|
||||
// Targets available for building
|
||||
/**
|
||||
* All targets available to be built
|
||||
*/
|
||||
readonly targets: Promise<Target[]>;
|
||||
// Event fired when configure completes
|
||||
/**
|
||||
* Event fired when the configure/generate stage completes
|
||||
*/
|
||||
readonly reconfigured: Event<void>;
|
||||
// Event fired when the default build target changes
|
||||
/**
|
||||
* Event fired when the active target changes.
|
||||
*/
|
||||
readonly targetChangedEvent: Event<void>;
|
||||
|
||||
// Execute a command using the CMake executable
|
||||
executeCMakeCommand(args: string[], options?: ExecuteOptions): Promise<ExecutionResult>;
|
||||
/**
|
||||
* Execute a command using the CMake executable.
|
||||
*
|
||||
* @param args Arguments to CMake
|
||||
* @param options Additional execution options
|
||||
* @returns The result of execution.
|
||||
*/
|
||||
executeCMakeCommand(args: string[], options?: ExecutionOptions): Promise<ExecutionResult>;
|
||||
// Execute an arbitrary program in the active environments
|
||||
execute(program: string, args: string[], options?: ExecuteOptions): Promise<ExecutionResult>;
|
||||
/**
|
||||
* Execute an arbitrary program.
|
||||
*
|
||||
* @param program Path to an executable binary
|
||||
* @param args List of command-line arguments to the program
|
||||
* @param options Additional execution options
|
||||
* @returns The result of execution
|
||||
*
|
||||
* ## Why you should use this API:
|
||||
*
|
||||
* You can execute a program on your own, but if it requires access to
|
||||
* environment variables that CMake Tools knows about, such as Visual C++
|
||||
* environment variables, this is the most reliable way to ensure that you
|
||||
* execute in the context that the user is expecting.
|
||||
*/
|
||||
execute(program: string, args: string[], options?: ExecutionOptions): Promise<ExecutionResult>;
|
||||
|
||||
// Get the compilation information for a file
|
||||
/**
|
||||
* Get the compilation information for a file
|
||||
*
|
||||
* @param filepath The source file in question
|
||||
* @returns New compilation info, or `null` if no compilation info was found
|
||||
* for the named file.
|
||||
*/
|
||||
compilationInfoForFile(filepath: string): Promise<CompilationInfo | null>;
|
||||
|
||||
// Configure the project. Returns the return code from CMake.
|
||||
/**
|
||||
* Configure the project.
|
||||
*
|
||||
* @param extraArgs Extra arguments to pass on the CMake command line
|
||||
* @param runPreBuild Run any pre-build/configure tasks
|
||||
* @returns The exit code of CMake
|
||||
*/
|
||||
configure(extraArgs?: string[], runPreBuild?: boolean): Promise<number>;
|
||||
// Build the project. Returns the return code from the build
|
||||
|
||||
/**
|
||||
* Build the project
|
||||
*
|
||||
* @param target The target to build. If not provided, will build the user's
|
||||
* active build target.
|
||||
* @returns the exit code of the build command
|
||||
*/
|
||||
build(target?: string): Promise<number>;
|
||||
// Install the project. Returns the return code from CMake
|
||||
|
||||
/**
|
||||
* Installs the project
|
||||
* @returns The exit code from CMake
|
||||
*/
|
||||
install(): Promise<number>;
|
||||
// Open the CMake Cache file in a text editor
|
||||
|
||||
/**
|
||||
* Open a text editor to the CMake cache file.
|
||||
*
|
||||
* @returns A new text editor, or `null` if the file could not be opened.
|
||||
*/
|
||||
|
||||
jumpToCacheFile(): Promise<TextEditor | null>;
|
||||
// Clean the build output
|
||||
|
||||
/**
|
||||
* Clean the build output. Runs the `clean` target.
|
||||
*
|
||||
* @returns The exit code from the build command
|
||||
*/
|
||||
clean(): Promise<number>;
|
||||
|
||||
/**
|
||||
* Clean up old configuration and reconfigure.
|
||||
*
|
||||
* @returns The exit code from CMake
|
||||
*
|
||||
* @note This is *not* the same as running `clean`, then `configure`.
|
||||
* Cleaning up configure includes removing the CMake cache file and any
|
||||
* intermediate configuration files.
|
||||
*/
|
||||
// Remove cached build settings and rerun the configuration
|
||||
cleanConfigure(): Promise<number>;
|
||||
// Clean the build output and rebuild
|
||||
|
||||
/**
|
||||
* Clean the build output and rebuild
|
||||
*
|
||||
* @returns The exit code from the build command.
|
||||
*/
|
||||
cleanRebuild(): Promise<number>;
|
||||
// Build a target selected by the user
|
||||
|
||||
/**
|
||||
* Asks the user to select a target, then builds that target.
|
||||
*
|
||||
* @returns The exit code from the build command.
|
||||
*/
|
||||
buildWithTarget(): Promise<number>;
|
||||
// Show a selector for the user to set the default build target
|
||||
|
||||
/**
|
||||
* Open up a QuickPick where the user can select a target to build.
|
||||
*/
|
||||
setDefaultTarget(): Promise<void>;
|
||||
// Set the active build variant
|
||||
|
||||
/**
|
||||
* Set the new build type.
|
||||
*
|
||||
* @returns The exit code from running CMake configure
|
||||
*/
|
||||
setBuildType(): Promise<number>;
|
||||
// Execute CTest
|
||||
|
||||
/**
|
||||
* Execute CTest
|
||||
*
|
||||
* @returns The exit code from CTest
|
||||
*/
|
||||
ctest(): Promise<number>;
|
||||
// Stop the currently running build/configure/test/install process
|
||||
|
||||
/**
|
||||
* Stop the currently running command.
|
||||
*
|
||||
* @returns `true` on success. `false` otherwise.
|
||||
*/
|
||||
stop(): Promise<boolean>;
|
||||
// Show a quickstart
|
||||
|
||||
/**
|
||||
* Run the CMake project quickstart.
|
||||
*
|
||||
* @returns The exit code from running CMake configure
|
||||
*/
|
||||
quickStart(): Promise<number>;
|
||||
// Start the executable target without a debugger
|
||||
|
||||
/**
|
||||
* Start the active target without a debugger.
|
||||
*/
|
||||
launchTarget(): Promise<void>;
|
||||
// Start the debugger with the selected build target
|
||||
|
||||
/**
|
||||
* Start the active target with a debugger.
|
||||
*/
|
||||
debugTarget(): Promise<void>;
|
||||
// Get the path to the active debugging target
|
||||
|
||||
/**
|
||||
* Get the path to the active launch target
|
||||
*/
|
||||
launchTargetProgramPath(): Promise<string | null>;
|
||||
// Allow the user to select target to debug
|
||||
|
||||
/**
|
||||
* Show a QuickPick to select a new target to launch.
|
||||
*/
|
||||
selectLaunchTarget(): Promise<string | null>;
|
||||
// Show the environment selection quickpick
|
||||
|
||||
/**
|
||||
* Show a QuickPick to select a build environment
|
||||
*/
|
||||
selectEnvironments(): Promise<void>;
|
||||
// Sets the variant based on keyword settings
|
||||
|
||||
/**
|
||||
* Select the active variant combination
|
||||
*/
|
||||
setActiveVariantCombination(settings: VariantKeywordSettings): Promise<void>;
|
||||
// Toggle code coverage view on/off
|
||||
|
||||
/**
|
||||
* Toggle test coverage decorations
|
||||
*/
|
||||
toggleCoverageDecorations(): void;
|
||||
}
|
130
src/cache.ts
130
src/cache.ts
|
@ -1,32 +1,54 @@
|
|||
/**
|
||||
* Module for reading from the CMake cache
|
||||
*/ /** */
|
||||
|
||||
import * as api from './api';
|
||||
// import * as async from './async';
|
||||
import * as util from './util';
|
||||
// import {log} from "./logging";
|
||||
import {fs} from './pr';
|
||||
|
||||
|
||||
/**
|
||||
* Implements access to CMake cache entries. See `api.CacheEntry` for more
|
||||
* information. This type is immutable.
|
||||
*/
|
||||
export class Entry implements api.CacheEntry {
|
||||
private _type: api.EntryType = api.EntryType.Uninitialized;
|
||||
private _type: api.CacheEntryType = api.CacheEntryType.Uninitialized;
|
||||
private _docs: string = '';
|
||||
private _key: string = '';
|
||||
private _value: any = null;
|
||||
private _advanced: boolean = false;
|
||||
|
||||
public get type() { return this._type; }
|
||||
get type() { return this._type; }
|
||||
|
||||
public get helpString() { return this._docs; }
|
||||
get helpString() { return this._docs; }
|
||||
|
||||
public get key() { return this._key; }
|
||||
get key() { return this._key; }
|
||||
|
||||
public get value() { return this._value; }
|
||||
get value() { return this._value; }
|
||||
|
||||
public as<T>(): T { return this.value as T; }
|
||||
as<T>(): T { return this.value as T; }
|
||||
|
||||
public get advanced() { return this._advanced; }
|
||||
get advanced() { return this._advanced; }
|
||||
|
||||
constructor(key: string, value: string, type: api.EntryType, docs: string, advanced: boolean) {
|
||||
/**
|
||||
* Create a new Cache Entry instance. Doesn't modify any files. You probably
|
||||
* want to get these from the `CMakeCache` object instead.
|
||||
* @param key The name of the entry
|
||||
* @param value The actual value of the entry. Always a string.
|
||||
* @param type The actual type of `value`
|
||||
* @param docs The `DOC` string in the cache
|
||||
* @param advanced Whether the entry is `ADVANCED`
|
||||
*/
|
||||
constructor(key: string,
|
||||
value: string,
|
||||
type: api.CacheEntryType,
|
||||
docs: string,
|
||||
advanced: boolean) {
|
||||
this._key = key;
|
||||
this._type = type;
|
||||
if (type === api.EntryType.Bool) {
|
||||
if (type === api.CacheEntryType.Bool) {
|
||||
this._value = util.isTruthy(value);
|
||||
} else {
|
||||
this._value = value;
|
||||
|
@ -36,10 +58,20 @@ export class Entry implements api.CacheEntry {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads a CMake cache file. This class is immutable.
|
||||
*/
|
||||
export class CMakeCache {
|
||||
private _entries: Map<string, Entry>;
|
||||
|
||||
public static async fromPath(path: string): Promise<CMakeCache> {
|
||||
/**
|
||||
* Read the contents of a CMakeCache.txt file.
|
||||
* @param path Path to a CMakeCache.txt-format file
|
||||
* @returns The CMake cache.
|
||||
*
|
||||
* @note The cache *may* not exist. In that case, the entries is empty and
|
||||
* the `exists` property is `false`. Creating or modifying the file named by
|
||||
* `path` has no effect on existing instance of this class.
|
||||
*/
|
||||
static async fromPath(path: string): Promise<CMakeCache> {
|
||||
const exists = await fs.exists(path);
|
||||
if (exists) {
|
||||
const content = await fs.readFile(path);
|
||||
|
@ -50,23 +82,44 @@ export class CMakeCache {
|
|||
}
|
||||
}
|
||||
|
||||
allEntries(): Entry[] { return Array.from(this._entries.values()); }
|
||||
/** Get a list of all cache entries */
|
||||
get allEntries(): Entry[] { return Array.from(this._entries.values()); }
|
||||
|
||||
constructor(path: string, exists: boolean, entries: Map<string, Entry>) {
|
||||
this._entries = entries;
|
||||
this._path = path;
|
||||
this._exists = exists;
|
||||
}
|
||||
/**
|
||||
* Create a new instance. This is **private**. You may only create an instance
|
||||
* via the `fromPath` static method.
|
||||
* @param _path Path to the cache
|
||||
* @param _exists Whether the file exists
|
||||
* @param _entries Entries in the cache
|
||||
*/
|
||||
private constructor(private readonly _path: string,
|
||||
private readonly _exists: boolean,
|
||||
private readonly _entries: Map<string, Entry>) {}
|
||||
|
||||
private _exists: boolean = false;
|
||||
public get exists() { return this._exists; }
|
||||
/**
|
||||
* `true` if the file exists when this instance was created.
|
||||
* `false` otherwise.
|
||||
*/
|
||||
get exists() { return this._exists; }
|
||||
|
||||
private _path: string = '';
|
||||
public get path() { return this._path; }
|
||||
/**
|
||||
* The path to the cache file, which may not exist
|
||||
*/
|
||||
get path() { return this._path; }
|
||||
|
||||
public getReloaded(): Promise<CMakeCache> { return CMakeCache.fromPath(this.path); }
|
||||
/**
|
||||
* Reload the cache file and return a new instance. This will not modify this
|
||||
* instance.
|
||||
* @returns A **new instance**.
|
||||
*/
|
||||
getReloaded(): Promise<CMakeCache> { return CMakeCache.fromPath(this.path); }
|
||||
|
||||
public static parseCache(content: string): Map<string, Entry> {
|
||||
/**
|
||||
* Parse the contents of a CMake cache file.
|
||||
* @param content The contents of a CMake cache file.
|
||||
* @returns A map from the cache keys to the entries in the cache.
|
||||
*/
|
||||
static parseCache(content: string): Map<string, Entry> {
|
||||
const lines = content.split(/\r\n|\n|\r/)
|
||||
.filter(line => !!line.length)
|
||||
.filter(line => !/^\s*#/.test(line));
|
||||
|
@ -90,15 +143,15 @@ export class CMakeCache {
|
|||
} else {
|
||||
const key = name;
|
||||
const typemap = {
|
||||
BOOL: api.EntryType.Bool,
|
||||
STRING: api.EntryType.String,
|
||||
PATH: api.EntryType.Path,
|
||||
FILEPATH: api.EntryType.FilePath,
|
||||
INTERNAL: api.EntryType.Internal,
|
||||
UNINITIALIZED: api.EntryType.Uninitialized,
|
||||
STATIC: api.EntryType.Static,
|
||||
} as { [type: string]: api.EntryType };
|
||||
const type: api.EntryType = typemap[typename];
|
||||
BOOL : api.CacheEntryType.Bool,
|
||||
STRING : api.CacheEntryType.String,
|
||||
PATH : api.CacheEntryType.Path,
|
||||
FILEPATH : api.CacheEntryType.FilePath,
|
||||
INTERNAL : api.CacheEntryType.Internal,
|
||||
UNINITIALIZED : api.CacheEntryType.Uninitialized,
|
||||
STATIC : api.CacheEntryType.Static,
|
||||
} as{[type: string] : api.CacheEntryType};
|
||||
const type: api.CacheEntryType = typemap[typename];
|
||||
const docs = docs_acc.trim();
|
||||
docs_acc = '';
|
||||
if (type === undefined) {
|
||||
|
@ -113,7 +166,10 @@ export class CMakeCache {
|
|||
return entries;
|
||||
}
|
||||
|
||||
public get(key: string): Entry | null {
|
||||
return this._entries.get(key) || null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get an entry from the cache
|
||||
* @param key The name of a cache entry
|
||||
* @returns The cache entry, or `null` if the cache entry is not present.
|
||||
*/
|
||||
get(key: string): Entry | null { return this._entries.get(key) || null; }
|
||||
}
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
/**
|
||||
* Root of the extension
|
||||
*/
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import {RollbarController} from './rollbar';
|
||||
import rollbar from './rollbar';
|
||||
import {KitManager, Kit} from './kit';
|
||||
import {StateManager} from './state';
|
||||
import {CMakeDriver} from './driver';
|
||||
import {LegacyCMakeDriver} from './legacy-driver';
|
||||
|
||||
export class CMakeProject implements vscode.Disposable {
|
||||
// Let's us submit rollbar messages
|
||||
private _rollbar = new RollbarController(this.extensionContext);
|
||||
|
||||
/**
|
||||
* Class implementing the extension. It's all here!
|
||||
*/
|
||||
export class CMakeTools implements vscode.Disposable {
|
||||
/**
|
||||
* The state manager for the class
|
||||
*/
|
||||
private _stateManager = new StateManager(this.extensionContext);
|
||||
|
||||
/**
|
||||
|
@ -17,7 +23,11 @@ export class CMakeProject implements vscode.Disposable {
|
|||
* to it for kit changes.
|
||||
*/
|
||||
private _kitManager = new KitManager(this._stateManager);
|
||||
// We store the active kit here
|
||||
|
||||
/**
|
||||
* Store the active kit. We keep it around in case we need to restart the
|
||||
* CMake driver.
|
||||
*/
|
||||
private _activeKit: Kit | null = null;
|
||||
|
||||
/**
|
||||
|
@ -25,10 +35,16 @@ export class CMakeProject implements vscode.Disposable {
|
|||
*/
|
||||
private _cmakeDriver: CMakeDriver;
|
||||
|
||||
/**
|
||||
* Construct a new instance. The instance isn't ready, and must be initalized.
|
||||
* @param extensionContext The extension context
|
||||
*
|
||||
* This is private. You must call `create` to get an instance.
|
||||
*/
|
||||
private constructor(readonly extensionContext: vscode.ExtensionContext) {
|
||||
// Handle the active kit changing. We want to do some updates and teardown
|
||||
this._kitManager.onActiveKitChanged(kit => {
|
||||
this._rollbar.invokeAsync('Changing CMake kit', async() => {
|
||||
rollbar.invokeAsync('Changing CMake kit', async() => {
|
||||
this._activeKit = kit;
|
||||
if (kit) {
|
||||
await this._cmakeDriver.setKit(kit);
|
||||
|
@ -37,9 +53,11 @@ export class CMakeProject implements vscode.Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
// Teardown
|
||||
/**
|
||||
* Dispose the extension
|
||||
*/
|
||||
dispose() {
|
||||
this._rollbar.invoke('Root dispose', () => {
|
||||
rollbar.invoke('Root dispose', () => {
|
||||
this._kitManager.dispose();
|
||||
if (this._cmakeDriver) {
|
||||
this._cmakeDriver.dispose();
|
||||
|
@ -54,17 +72,19 @@ export class CMakeProject implements vscode.Disposable {
|
|||
if (this._cmakeDriver) {
|
||||
await this._cmakeDriver.asyncDispose();
|
||||
}
|
||||
this._cmakeDriver = await LegacyCMakeDriver.create(this._rollbar);
|
||||
this._cmakeDriver = await LegacyCMakeDriver.create();
|
||||
if (this._activeKit) {
|
||||
await this._cmakeDriver.setKit(this._activeKit);
|
||||
}
|
||||
}
|
||||
|
||||
// Two-phase initialize
|
||||
/**
|
||||
* Two-phase init. Called by `create`.
|
||||
*/
|
||||
private async _init() {
|
||||
await this._rollbar.invokeAsync('Root init', async() => {
|
||||
await rollbar.invokeAsync('Root init', async() => {
|
||||
// First, start up Rollbar
|
||||
await this._rollbar.requestPermissions();
|
||||
await rollbar.requestPermissions(this.extensionContext);
|
||||
// Now start the CMake driver
|
||||
await this._reloadCMakeDriver();
|
||||
// Start up the kit manager. This will also inject the current kit into
|
||||
|
@ -73,26 +93,47 @@ export class CMakeProject implements vscode.Disposable {
|
|||
});
|
||||
}
|
||||
|
||||
// Static creation, because we never want to hand-out an uninitialized
|
||||
// instance
|
||||
static async create(ctx: vscode.ExtensionContext): Promise<CMakeProject> {
|
||||
const inst = new CMakeProject(ctx);
|
||||
/**
|
||||
* Create an instance asynchronously
|
||||
* @param ctx The extension context
|
||||
*
|
||||
* The purpose of making this the only way to create an instance is to prevent
|
||||
* us from creating uninitialized instances of the CMake Tools extension.
|
||||
*/
|
||||
static async create(ctx: vscode.ExtensionContext): Promise<CMakeTools> {
|
||||
const inst = new CMakeTools(ctx);
|
||||
await inst._init();
|
||||
return inst;
|
||||
}
|
||||
|
||||
// Extension command implementations
|
||||
/**
|
||||
* Implementation of `cmake.editKits`
|
||||
*/
|
||||
editKits() {
|
||||
return this._rollbar.invokeAsync('editKits', () => this._kitManager.openKitsEditor());
|
||||
return this._kitManager.openKitsEditor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of `cmake.scanForKits`
|
||||
*/
|
||||
scanForKits() {
|
||||
return this._rollbar.invokeAsync('scanForKits', () => this._kitManager.rescanForKits());
|
||||
return this._kitManager.rescanForKits();
|
||||
}
|
||||
selectKit() { return this._rollbar.invokeAsync('selectKit', () => this._kitManager.selectKit()); }
|
||||
|
||||
/**
|
||||
* Implementation of `cmake.selectKit`
|
||||
*/
|
||||
selectKit() { return this._kitManager.selectKit(); }
|
||||
|
||||
/**
|
||||
* Implementation of `cmake.configure`
|
||||
*/
|
||||
async configure() {
|
||||
while (!this._activeKit) {
|
||||
await this.selectKit();
|
||||
}
|
||||
return this._rollbar.invokeAsync('configure', () => this._cmakeDriver.configure());
|
||||
return this._cmakeDriver.configure();
|
||||
}
|
||||
}
|
||||
|
||||
export default CMakeTools;
|
162
src/config.ts
162
src/config.ts
|
@ -1,15 +1,65 @@
|
|||
/**
|
||||
* Provides a typed interface to CMake Tools' configuration options. You'll want
|
||||
* to import the `config` default export, which is an instance of the
|
||||
* `ConfigurationReader` class.
|
||||
*/ /** */
|
||||
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
import * as util from './util';
|
||||
import rollbar from './rollbar';
|
||||
|
||||
export class ConfigurationReader {
|
||||
public readConfig<T>(key: string, default_: T | null = null): T | null {
|
||||
const config = vscode.workspace.getConfiguration('cmake');
|
||||
const value = config.get(key);
|
||||
return (value !== undefined) ? value as T : default_;
|
||||
/**
|
||||
* Read a config value from `settings.json`
|
||||
* @param key The configuration setting name
|
||||
* @param default_ The default value to return, if the setting is missing
|
||||
*/
|
||||
function readConfig<T>(key: string): T | null;
|
||||
function readConfig<T>(key: string, default_: T): T;
|
||||
function readConfig<T>(key: string, default_?: T): T | null {
|
||||
const config = vscode.workspace.getConfiguration('cmake');
|
||||
const value = config.get(key) as T | undefined;
|
||||
if (value === undefined) {
|
||||
if (default_ === undefined) {
|
||||
return null;
|
||||
} else {
|
||||
return default_;
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a config value from `settings.json`, which may be prefixed by the
|
||||
* platform name.
|
||||
* @param key The configuration setting name
|
||||
*/
|
||||
function readPrefixedConfig<T>(key: string): T | null;
|
||||
function readPrefixedConfig<T>(key: string, default_: T): T;
|
||||
function readPrefixedConfig<T>(key: string, default_?: T): T | null {
|
||||
const platmap = {
|
||||
win32 : 'windows',
|
||||
darwin : 'osx',
|
||||
linux : 'linux',
|
||||
} as{[k: string] : string};
|
||||
const platform = platmap[process.platform];
|
||||
if (default_ === undefined) {
|
||||
return readConfig(`${platform}.${key}`, readConfig<T>(`${key}`));
|
||||
} else {
|
||||
return readConfig(`${platform}.${key}`, readConfig<T>(`${key}`, default_));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class exposes a number of readonly properties which can be used to
|
||||
* access configuration options. Each property corresponds to a value in
|
||||
* `settings.json`. See `package.json` for CMake Tools to see the information
|
||||
* on each property. An underscore in a property name corresponds to a dot `.`
|
||||
* in the setting name.
|
||||
*/
|
||||
class ConfigurationReader {
|
||||
private _escapePaths(obj: {[k: string] : any}) {
|
||||
return Object.getOwnPropertyNames(obj).reduce(
|
||||
(acc, key: string) => {
|
||||
|
@ -19,68 +69,58 @@ export class ConfigurationReader {
|
|||
{} as typeof obj);
|
||||
}
|
||||
|
||||
private _readPrefixed<T>(key: string): T | null {
|
||||
const platmap = {
|
||||
win32 : 'windows',
|
||||
darwin : 'osx',
|
||||
linux : 'linux',
|
||||
} as{[k: string] : string};
|
||||
const platform = platmap[process.platform];
|
||||
return this.readConfig<T>(`${platform}.${key}`, this.readConfig<T>(`${key}`));
|
||||
}
|
||||
get buildDirectory(): string { return readPrefixedConfig<string>('buildDirectory') !; }
|
||||
|
||||
get buildDirectory(): string { return this._readPrefixed<string>('buildDirectory') !; }
|
||||
get installPrefix(): string | null { return readPrefixedConfig<string>('installPrefix') !; }
|
||||
|
||||
get installPrefix(): string | null { return this._readPrefixed<string>('installPrefix') !; }
|
||||
get sourceDirectory(): string { return readPrefixedConfig<string>('sourceDirectory') as string; }
|
||||
|
||||
get sourceDirectory(): string { return this._readPrefixed<string>('sourceDirectory') as string; }
|
||||
get buildBeforeRun(): boolean { return !!readPrefixedConfig<boolean>('buildBeforeRun'); }
|
||||
|
||||
get buildBeforeRun(): boolean { return !!this._readPrefixed<boolean>('buildBeforeRun'); }
|
||||
|
||||
get saveBeforeBuild(): boolean { return !!this._readPrefixed<boolean>('saveBeforeBuild'); }
|
||||
get saveBeforeBuild(): boolean { return !!readPrefixedConfig<boolean>('saveBeforeBuild'); }
|
||||
|
||||
get clearOutputBeforeBuild(): boolean {
|
||||
return !!this._readPrefixed<boolean>('clearOutputBeforeBuild');
|
||||
return !!readPrefixedConfig<boolean>('clearOutputBeforeBuild');
|
||||
}
|
||||
|
||||
get configureSettings(): any { return this._readPrefixed<Object>('configureSettings'); }
|
||||
get configureSettings(): any { return readPrefixedConfig<Object>('configureSettings'); }
|
||||
|
||||
get initialBuildType(): string | null { return this._readPrefixed<string>('initialBuildType'); }
|
||||
get initialBuildType(): string | null { return readPrefixedConfig<string>('initialBuildType'); }
|
||||
|
||||
get preferredGenerators(): string[] {
|
||||
return this._readPrefixed<string[]>('preferredGenerators') || [];
|
||||
return readPrefixedConfig<string[]>('preferredGenerators', []);
|
||||
}
|
||||
|
||||
get generator(): string | null { return this._readPrefixed<string>('generator'); }
|
||||
get generator(): string | null { return readPrefixedConfig<string>('generator'); }
|
||||
|
||||
get toolset(): string | null { return this._readPrefixed<string>('toolset'); }
|
||||
get toolset(): string | null { return readPrefixedConfig<string>('toolset'); }
|
||||
|
||||
get platform(): string | null { return this._readPrefixed<string>('platform'); }
|
||||
get platform(): string | null { return readPrefixedConfig<string>('platform'); }
|
||||
|
||||
get configureArgs(): string[] { return this._readPrefixed<string[]>('configureArgs') !; }
|
||||
get configureArgs(): string[] { return readPrefixedConfig<string[]>('configureArgs') !; }
|
||||
|
||||
get buildArgs(): string[] { return this._readPrefixed<string[]>('buildArgs') !; }
|
||||
get buildArgs(): string[] { return readPrefixedConfig<string[]>('buildArgs') !; }
|
||||
|
||||
get buildToolArgs(): string[] { return this._readPrefixed<string[]>('buildToolArgs') !; }
|
||||
get buildToolArgs(): string[] { return readPrefixedConfig<string[]>('buildToolArgs') !; }
|
||||
|
||||
get parallelJobs(): number | null { return this._readPrefixed<number>('parallelJobs'); }
|
||||
get parallelJobs(): number | null { return readPrefixedConfig<number>('parallelJobs'); }
|
||||
|
||||
get ctest_parallelJobs(): number | null {
|
||||
return this._readPrefixed<number>('ctest.parallelJobs');
|
||||
return readPrefixedConfig<number>('ctest.parallelJobs');
|
||||
}
|
||||
|
||||
get parseBuildDiagnostics(): boolean {
|
||||
return !!this._readPrefixed<boolean>('parseBuildDiagnostics');
|
||||
return !!readPrefixedConfig<boolean>('parseBuildDiagnostics');
|
||||
}
|
||||
|
||||
get enableOutputParsers(): string[] | null {
|
||||
return this._readPrefixed<string[]>('enableOutputParsers');
|
||||
return readPrefixedConfig<string[]>('enableOutputParsers');
|
||||
}
|
||||
|
||||
get cmakePath(): string { return this._readPrefixed<string>('cmakePath') || 'cmake'; }
|
||||
get cmakePath(): string { return readPrefixedConfig<string>('cmakePath', 'cmake'); }
|
||||
|
||||
get ctestPath(): string {
|
||||
const ctest_path = this._readPrefixed<string>('ctestPath');
|
||||
const ctest_path = readPrefixedConfig<string>('ctestPath');
|
||||
if (!ctest_path) {
|
||||
const cmake = this.cmakePath;
|
||||
if (cmake === 'cmake' || cmake === 'cmake.exe') {
|
||||
|
@ -92,33 +132,32 @@ export class ConfigurationReader {
|
|||
}
|
||||
}
|
||||
|
||||
get debugConfig(): any { return this._readPrefixed<any>('debugConfig'); }
|
||||
get debugConfig(): any { return readPrefixedConfig<any>('debugConfig'); }
|
||||
|
||||
get environment() {
|
||||
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('environment') || {});
|
||||
return this._escapePaths(readPrefixedConfig<{[key: string] : string}>('environment', {}));
|
||||
}
|
||||
|
||||
get configureEnvironment() {
|
||||
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('configureEnvironment')
|
||||
|| {});
|
||||
return this._escapePaths(
|
||||
readPrefixedConfig<{[key: string] : string}>('configureEnvironment', {}));
|
||||
}
|
||||
|
||||
get buildEnvironment() {
|
||||
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('buildEnvironment')
|
||||
|| {});
|
||||
return this._escapePaths(readPrefixedConfig<{[key: string] : string}>('buildEnvironment', {}));
|
||||
}
|
||||
|
||||
get testEnvironment() {
|
||||
return this._escapePaths(this._readPrefixed<{[key: string] : string}>('testEnvironment') || {});
|
||||
return this._escapePaths(readPrefixedConfig<{[key: string] : string}>('testEnvironment', {}));
|
||||
}
|
||||
|
||||
get defaultVariants(): Object { return this._readPrefixed<Object>('defaultVariants') || {}; }
|
||||
get defaultVariants(): Object { return readPrefixedConfig<Object>('defaultVariants', {}); }
|
||||
|
||||
get ctestArgs(): string[] { return this._readPrefixed<string[]>('ctestArgs') || []; }
|
||||
get ctestArgs(): string[] { return readPrefixedConfig<string[]>('ctestArgs', []); }
|
||||
|
||||
get useCMakeServer(): boolean { return this._readPrefixed<boolean>('useCMakeServer') || false; }
|
||||
get useCMakeServer(): boolean { return readPrefixedConfig<boolean>('useCMakeServer', true); }
|
||||
|
||||
public get numJobs(): number {
|
||||
get numJobs(): number {
|
||||
const jobs = this.parallelJobs;
|
||||
if (!!jobs) {
|
||||
return jobs;
|
||||
|
@ -126,7 +165,7 @@ export class ConfigurationReader {
|
|||
return os.cpus().length + 2;
|
||||
}
|
||||
|
||||
public get numCTestJobs(): number {
|
||||
get numCTestJobs(): number {
|
||||
const ctest_jobs = this.ctest_parallelJobs;
|
||||
if (!ctest_jobs) {
|
||||
return this.numJobs;
|
||||
|
@ -134,14 +173,31 @@ export class ConfigurationReader {
|
|||
return ctest_jobs;
|
||||
}
|
||||
|
||||
public get mingwSearchDirs(): string[] {
|
||||
return this._readPrefixed<string[]>('mingwSearchDirs') || [];
|
||||
get mingwSearchDirs(): string[] { return readPrefixedConfig<string[]>('mingwSearchDirs', []); }
|
||||
|
||||
get emscriptenSearchDirs(): string[] {
|
||||
return readPrefixedConfig<string[]>('emscriptenSearchDirs', []);
|
||||
}
|
||||
|
||||
public get emscriptenSearchDirs(): string[] {
|
||||
return this._readPrefixed<string[]>('emscriptenSearchDirs') || [];
|
||||
/**
|
||||
* Watch for changes on a particular setting
|
||||
* @param setting The name of the setting to watch
|
||||
* @param cb A callback when the setting changes
|
||||
*/
|
||||
onChange<K extends keyof ConfigurationReader>(setting: K,
|
||||
cb: (value: ConfigurationReader[K]) => void) {
|
||||
const state = {value : this[setting]};
|
||||
return vscode.workspace.onDidChangeConfiguration(_ => {
|
||||
rollbar.invoke(`Callback changing setting: cmake.${setting}`, () => {
|
||||
const new_value = this[setting];
|
||||
if (new_value !== state.value) {
|
||||
state.value = new_value;
|
||||
cb(new_value);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const config = new ConfigurationReader();
|
||||
const config = new ConfigurationReader();
|
||||
export default config;
|
||||
|
|
45
src/dirs.ts
45
src/dirs.ts
|
@ -1,18 +1,41 @@
|
|||
/**
|
||||
* This module defines important directories and paths to the extension
|
||||
*/ /** */
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
export function userHome(): string { return process.env['HOME'] || process.env['PROFILE'] !; }
|
||||
/**
|
||||
* Directory class.
|
||||
*/
|
||||
class Dirs {
|
||||
/**
|
||||
* The current user's home directory
|
||||
*/
|
||||
get userHome(): string { return process.env['HOME'] || process.env['PROFILE'] !; }
|
||||
|
||||
export function userLocalDir(): string {
|
||||
if (process.platform == 'win32') {
|
||||
return process.env['AppData'] !;
|
||||
} else {
|
||||
const xdg_dir = process.env["XDG_DATA_HOME"];
|
||||
if (xdg_dir) {
|
||||
return xdg_dir;
|
||||
/**
|
||||
* The user-local data directory. This is where user-specific persistent
|
||||
* application data should be stored.
|
||||
*/
|
||||
get userLocalDir(): string {
|
||||
if (process.platform == 'win32') {
|
||||
return process.env['AppData'] !;
|
||||
} else {
|
||||
const xdg_dir = process.env["XDG_DATA_HOME"];
|
||||
if (xdg_dir) {
|
||||
return xdg_dir;
|
||||
}
|
||||
const home = this.userHome;
|
||||
return path.join(home, '.local/share');
|
||||
}
|
||||
const home = userHome();
|
||||
return path.join(home, '.local/share');
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory where CMake Tools should store user-specific persistent
|
||||
* data.
|
||||
*/
|
||||
get dataDir(): string { return path.join(this.userLocalDir, 'CMakeTools'); }
|
||||
}
|
||||
|
||||
export function dataDir(): string { return path.join(userLocalDir(), 'CMakeTools'); }
|
||||
const dirs = new Dirs();
|
||||
export default dirs;
|
||||
|
|
155
src/driver.ts
155
src/driver.ts
|
@ -1,47 +1,117 @@
|
|||
/**
|
||||
* Defines base class for CMake drivers
|
||||
*/ /** */
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import * as api from './api';
|
||||
import {RollbarController} from './rollbar';
|
||||
import rollbar from './rollbar';
|
||||
import {Kit, CompilerKit, ToolchainKit, VSKit} from './kit';
|
||||
import {CMakeCache} from './cache';
|
||||
import * as util from './util';
|
||||
import {config} from './config';
|
||||
import config from './config';
|
||||
import {fs} from './pr';
|
||||
|
||||
/**
|
||||
* Base class for CMake drivers.
|
||||
*
|
||||
* CMake drivers are separated because different CMake version warrant different
|
||||
* communication methods. Older CMake versions need to be driven by the command
|
||||
* line, but newer versions may be controlled via CMake server, which provides
|
||||
* a much richer interface.
|
||||
*
|
||||
* This class defines the basis for what a driver must implement to work.
|
||||
*/
|
||||
export abstract class CMakeDriver implements vscode.Disposable {
|
||||
/**
|
||||
* Do the configuration process for the current project.
|
||||
*
|
||||
* @returns The exit code from CMake
|
||||
*/
|
||||
abstract configure(): Promise<number>;
|
||||
|
||||
/**
|
||||
* Do any necessary disposal for the driver. For the CMake Server driver,
|
||||
* this entails shutting down the server process and closing the open pipes.
|
||||
*
|
||||
* The reason this is separate from the regular `dispose()` is so that the
|
||||
* driver shutdown may be `await`ed on to ensure full shutdown.
|
||||
*/
|
||||
abstract asyncDispose(): Promise<void>;
|
||||
|
||||
constructor(protected readonly _rollbar: RollbarController) {}
|
||||
/**
|
||||
* Construct the driver. Concrete instances should provide their own creation
|
||||
* routines.
|
||||
*/
|
||||
protected constructor() {}
|
||||
|
||||
// We just call the async disposal method
|
||||
/**
|
||||
* Dispose the driver. This disposes some things synchronously, but also
|
||||
* calls the `asyncDispose()` method to start any asynchronous shutdown.
|
||||
*/
|
||||
dispose() {
|
||||
this._rollbar.invokeAsync('Async disposing CMake driver', async () => this.asyncDispose());
|
||||
rollbar.invokeAsync('Async disposing CMake driver', async() => this.asyncDispose());
|
||||
this._cacheWatcher.dispose();
|
||||
}
|
||||
|
||||
/// The current kit
|
||||
protected _kit: Kit | null = null;
|
||||
/// Get the current kit as a compiler kit
|
||||
/**
|
||||
* The current Kit. Starts out `null`, but once set, is never `null` again.
|
||||
* We do some separation here to protect ourselves: The `_baseKit` property
|
||||
* is `private`, so derived classes cannot change it, except via
|
||||
* `_setBaseKit`, which only allows non-null kits. This prevents the derived
|
||||
* classes from resetting the kit back to `null`.
|
||||
*/
|
||||
private _baseKit: Kit | null = null;
|
||||
|
||||
/**
|
||||
* Sets the kit on the base class.
|
||||
* @param k The new kit
|
||||
*/
|
||||
protected _setBaseKit(k: Kit) { this._baseKit = k; }
|
||||
|
||||
/**
|
||||
* Get the current kit. Once non-`null`, the kit is never `null` again.
|
||||
*/
|
||||
protected get _kit() { return this._baseKit; }
|
||||
|
||||
/**
|
||||
* Get the current kit as a `CompilerKit`.
|
||||
*
|
||||
* @precondition `this._kit` is non-`null` and `this._kit.type` is `compilerKit`.
|
||||
* Guarded with an `assert`
|
||||
*/
|
||||
protected get _compilerKit() {
|
||||
console.assert(this._kit && this._kit.type == 'compilerKit', JSON.stringify(this._kit));
|
||||
return this._kit as CompilerKit;
|
||||
}
|
||||
/// Get the current kit as a toolchain kit
|
||||
|
||||
/**
|
||||
* Get the current kit as a `ToolchainKit`.
|
||||
*
|
||||
* @precondition `this._kit` is non-`null` and `this._kit.type` is `toolchainKit`.
|
||||
* Guarded with an `assert`
|
||||
*/
|
||||
protected get _toolchainFileKit() {
|
||||
console.assert(this._kit && this._kit.type == 'toolchainKit', JSON.stringify(this._kit));
|
||||
return this._kit as ToolchainKit;
|
||||
}
|
||||
/// Get the current kit as a VS kit
|
||||
/**
|
||||
* Get the current kit as a `VSKit`.
|
||||
*
|
||||
* @precondition `this._kit` is non-`null` and `this._kit.type` is `vsKit`.
|
||||
* Guarded with an `assert`
|
||||
*/
|
||||
protected get _vsKit() {
|
||||
console.assert(this._kit && this._kit.type == 'vsKit', JSON.stringify(this._kit));
|
||||
return this._kit as VSKit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we need to wipe the build directory if we change to `kit`
|
||||
* Determine if we need to wipe the build directory if we change adopt `kit`
|
||||
* @param kit The new kit
|
||||
* @returns `true` if the new kit requires a clean reconfigure.
|
||||
*/
|
||||
protected _kitChangeNeedsClean(kit: Kit): boolean {
|
||||
if (!this._kit) {
|
||||
|
@ -71,17 +141,24 @@ export abstract class CMakeDriver implements vscode.Disposable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the current kit. This lets the driver reload, if necessary.
|
||||
* @param kit The new kit
|
||||
*/
|
||||
abstract setKit(kit: Kit): Promise<void>;
|
||||
|
||||
/// Are we busy?
|
||||
/**
|
||||
* Is the driver busy? ie. running a configure/build/test
|
||||
*/
|
||||
get isBusy() { return this._isBusy; }
|
||||
protected _isBusy: boolean = false;
|
||||
|
||||
/**
|
||||
* The source directory, where the root CMakeLists.txt lives
|
||||
* The source directory, where the root CMakeLists.txt lives.
|
||||
*
|
||||
* @note This is distinct from the config values, since we do variable
|
||||
* substitution.
|
||||
*/
|
||||
get sourceDir(): string {
|
||||
const dir = util.replaceVars(config.sourceDirectory);
|
||||
|
@ -166,31 +243,58 @@ export abstract class CMakeDriver implements vscode.Disposable {
|
|||
return true;
|
||||
}
|
||||
|
||||
private _cmakeCache: CMakeCache | null;
|
||||
/**
|
||||
* The CMake cache for the driver.
|
||||
*
|
||||
* Will be automatically reloaded when the file on disk changes.
|
||||
*/
|
||||
get cmakeCache() { return this._cmakeCache; }
|
||||
private _cmakeCache: Promise<CMakeCache | null> = Promise.resolve(null);
|
||||
|
||||
/**
|
||||
* Watcher for the CMake cache file on disk.
|
||||
*/
|
||||
private _cacheWatcher = vscode.workspace.createFileSystemWatcher(this.cachePath);
|
||||
|
||||
allCacheEntries(): api.CacheEntryProperties[] {
|
||||
return !this.cmakeCache ? [] : this.cmakeCache.allEntries().map(e => ({
|
||||
type : e.type,
|
||||
key : e.key,
|
||||
value : e.value,
|
||||
advanced : e.advanced,
|
||||
helpString : e.helpString,
|
||||
}));
|
||||
/**
|
||||
* Get all cache entries
|
||||
*/
|
||||
get allCacheEntries() { return this._allCacheEntries(); }
|
||||
private async _allCacheEntries(): Promise<api.CacheEntryProperties[]> {
|
||||
const cache = await this.cmakeCache;
|
||||
if (!cache) {
|
||||
return [];
|
||||
} else {
|
||||
return cache.allEntries.map(e => ({
|
||||
type : e.type,
|
||||
key : e.key,
|
||||
value : e.value,
|
||||
advanced : e.advanced,
|
||||
helpString : e.helpString,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous initialization. Should be called by base classes during
|
||||
* their initialization.
|
||||
*/
|
||||
protected async _init() {
|
||||
if (await fs.exists(this.cachePath)) {
|
||||
this._cmakeCache = await CMakeCache.fromPath(this.cachePath);
|
||||
this._cmakeCache = CMakeCache.fromPath(this.cachePath);
|
||||
}
|
||||
this._cacheWatcher.onDidChange(() => {
|
||||
this._rollbar.invokeAsync('Reloading CMake Cache', async() => {
|
||||
this._cmakeCache = await CMakeCache.fromPath(this.cachePath);
|
||||
rollbar.invokeAsync('Reloading CMake Cache', async() => {
|
||||
this._cmakeCache = CMakeCache.fromPath(this.cachePath);
|
||||
// Force await here so that any errors are thrown into rollbar
|
||||
await this._cmakeCache;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of command line flags that should be passed to CMake
|
||||
*/
|
||||
protected _cmakeFlags(): string[] {
|
||||
const settings = Object.assign({}, config.configureSettings);
|
||||
|
||||
|
@ -217,7 +321,6 @@ export abstract class CMakeDriver implements vscode.Disposable {
|
|||
};
|
||||
const settings_flags
|
||||
= util.objectPairs(settings).map(([ key, value ]) => _makeFlag(key, value));
|
||||
// = Object.getOwnPropertyNames(settings).map(key => _makeFlag(key, settings[key]));
|
||||
const flags = [ '--no-warn-unused-cli' ];
|
||||
return flags.concat(settings_flags);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* Extension startup/teardown
|
||||
*/ /** */
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
|
@ -6,27 +10,39 @@ import * as vscode from 'vscode';
|
|||
// import { log } from './logging';
|
||||
// import { outputChannels } from "./util";
|
||||
|
||||
import {CMakeProject} from './project';
|
||||
import CMakeTools from './cmake-tools';
|
||||
import rollbar from './rollbar';
|
||||
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<CMakeProject> {
|
||||
/**
|
||||
* Starts up the extension.
|
||||
* @param context The extension context
|
||||
* @returns A promise that will resolve when the extension is ready for use
|
||||
*/
|
||||
export async function activate(context: vscode.ExtensionContext): Promise<CMakeTools> {
|
||||
// log.initialize(context);
|
||||
|
||||
const pr = await CMakeProject.create(context);
|
||||
// Create a new instance and initailize.
|
||||
const cmt = await CMakeTools.create(context);
|
||||
|
||||
context.subscriptions.push(pr);
|
||||
// Push it so we get clean teardown.
|
||||
context.subscriptions.push(cmt);
|
||||
|
||||
function register(name: keyof CMakeProject) {
|
||||
const fn = (pr[name] as Function).bind(pr);
|
||||
return vscode.commands.registerCommand('cmake.' + name, _ => fn());
|
||||
// A register function helps us bind the commands to the extension
|
||||
function register<K extends keyof CMakeTools>(name: K) {
|
||||
const fn = (cmt[name] as Function).bind(cmt);
|
||||
return vscode.commands.registerCommand('cmake.' + name, () => {
|
||||
return rollbar.invokeAsync(name, fn);
|
||||
});
|
||||
}
|
||||
|
||||
const funs : (keyof CMakeProject)[] =
|
||||
// List of functions that will be bound commands
|
||||
const funs : (keyof CMakeTools)[] =
|
||||
[
|
||||
'editKits',
|
||||
'scanForKits',
|
||||
'selectKit',
|
||||
'configure',
|
||||
// 'build',
|
||||
// 'build',
|
||||
// 'install',
|
||||
// 'jumpToCacheFile',
|
||||
// 'clean',
|
||||
|
@ -45,9 +61,12 @@ export async function activate(context: vscode.ExtensionContext): Promise<CMakeP
|
|||
// 'selectEnvironments',
|
||||
// 'toggleCoverageDecorations',
|
||||
];
|
||||
|
||||
// Bind them all!
|
||||
for (const key of funs) { context.subscriptions.push(register(key));}
|
||||
|
||||
return pr;
|
||||
// Return that promise
|
||||
return cmt;
|
||||
}
|
||||
|
||||
// this method is called when your extension is deactivated
|
||||
|
|
124
src/kit.ts
124
src/kit.ts
|
@ -1,15 +1,24 @@
|
|||
/**
|
||||
* Module for controlling and working with Kits.
|
||||
*/ /** */
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
import * as proc from './proc';
|
||||
import * as dirs from './dirs';
|
||||
import dirs from './dirs';
|
||||
import {StateManager} from './state';
|
||||
import {fs} from './pr';
|
||||
|
||||
/**
|
||||
* Base of all kits. Just has a name.
|
||||
*/
|
||||
export interface BaseKit { name: string; }
|
||||
export interface BaseKit {
|
||||
/**
|
||||
* The name of the kit
|
||||
*/
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilerKits list compilers for each language. This will be used on platforms
|
||||
|
@ -17,6 +26,13 @@ export interface BaseKit { name: string; }
|
|||
*/
|
||||
export interface CompilerKit extends BaseKit {
|
||||
type: 'compilerKit';
|
||||
|
||||
/**
|
||||
* The language compilers.
|
||||
*
|
||||
* The key `lang` is the language, as in `CMAKE_<lang>_COMPILER`.
|
||||
* The corresponding value is a path to a compiler for that language.
|
||||
*/
|
||||
compilers: {[lang: string] : string}
|
||||
}
|
||||
|
||||
|
@ -26,7 +42,18 @@ export interface CompilerKit extends BaseKit {
|
|||
*/
|
||||
export interface VSKit extends BaseKit {
|
||||
type: 'vsKit';
|
||||
|
||||
/**
|
||||
* The visual studio name. This corresponds to a name returned by `vswhere`,
|
||||
* and is used to look up the path to the VS installation when the user
|
||||
* selects this kit
|
||||
*/
|
||||
visualStudio: string;
|
||||
|
||||
/**
|
||||
* The architecture for the kit. This is used when asking for the architecture
|
||||
* from the dev environment batch file.
|
||||
*/
|
||||
visualStudioArchitecture: string;
|
||||
}
|
||||
|
||||
|
@ -35,24 +62,31 @@ export interface VSKit extends BaseKit {
|
|||
*/
|
||||
export interface ToolchainKit extends BaseKit {
|
||||
type: 'toolchainKit';
|
||||
|
||||
/**
|
||||
* Path to a CMake toolchain file.
|
||||
*/
|
||||
toolchainFile: string;
|
||||
}
|
||||
|
||||
/// Kits are a sum type of the above interface
|
||||
/**
|
||||
* Tagged union of all the kit types
|
||||
*/
|
||||
export type Kit = CompilerKit | VSKit | ToolchainKit;
|
||||
|
||||
/**
|
||||
* Convert a binary (by path) to a CompilerKit. This checks if the named binary
|
||||
* is a GCC or Clang compiler and gets its version. If it is not a compiler,
|
||||
* returns null.
|
||||
* returns `null`.
|
||||
* @param bin Path to a binary
|
||||
* @returns A CompilerKit, or null if `bin` is not a known compiler
|
||||
*/
|
||||
async function kitIfCompiler(bin: string):
|
||||
Promise<CompilerKit | null> {
|
||||
const fname = path.basename(bin);
|
||||
const gcc_regex = /^gcc(-\d+(\.\d+(\.\d+)?)?)?$/;
|
||||
const clang_regex = /^clang(-\d+(\.\d+(\.\d+)?)?)?$/;
|
||||
// Check by filename what the compiler might be. This is just heuristic.
|
||||
const gcc_regex = /^gcc(-\d+(\.\d+(\.\d+)?)?)?(\\.exe)?$/;
|
||||
const clang_regex = /^clang(-\d+(\.\d+(\.\d+)?)?)?(\\.exe)?$/;
|
||||
const gcc_res = gcc_regex.exec(fname);
|
||||
const clang_res = clang_regex.exec(fname);
|
||||
if (gcc_res) {
|
||||
|
@ -166,7 +200,7 @@ async function scanDirForCompilerKits(dir: string) {
|
|||
* @returns A list of Kits.
|
||||
*/
|
||||
async function
|
||||
scanForKits() {
|
||||
scanForKits() {
|
||||
// Search directories on `PATH` for compiler binaries
|
||||
const pathvar = process.env['PATH'] !;
|
||||
const sep = process.platform === 'win32' ? ';' : ':';
|
||||
|
@ -179,7 +213,11 @@ async function
|
|||
return kits;
|
||||
}
|
||||
|
||||
function _descriptionForKit(kit: Kit) {
|
||||
/**
|
||||
* Generates a string description of a kit. This is shown to the user.
|
||||
* @param kit The kit to generate a description for
|
||||
*/
|
||||
function descriptionForKit(kit: Kit) {
|
||||
switch (kit.type) {
|
||||
case 'toolchainKit': {
|
||||
return `Kit for toolchain file ${kit.toolchainFile}`;
|
||||
|
@ -194,12 +232,39 @@ function _descriptionForKit(kit: Kit) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that manages and tracks Kits
|
||||
*/
|
||||
export class KitManager implements vscode.Disposable {
|
||||
/**
|
||||
* The known kits
|
||||
*/
|
||||
private _kits = [] as Kit[];
|
||||
|
||||
/**
|
||||
* The path to the `cmake-kits.json` file
|
||||
*/
|
||||
private get _kitsPath(): string { return path.join(dirs.dataDir, 'cmake-kits.json'); }
|
||||
|
||||
/**
|
||||
* Watches the file at `_kitsPath`.
|
||||
*/
|
||||
private _kitsWatcher = vscode.workspace.createFileSystemWatcher(this._kitsPath);
|
||||
|
||||
/**
|
||||
* Event emitted when the Kit changes. This can be via user action, by the
|
||||
* available kits changing, or on initial load when the prior workspace kit
|
||||
* is reloaded.
|
||||
*/
|
||||
get onActiveKitChanged() { return this._activeKitChangedEmitter.event; }
|
||||
private _activeKitChangedEmitter = new vscode.EventEmitter<Kit | null>();
|
||||
readonly onActiveKitChanged = this._activeKitChangedEmitter.event;
|
||||
|
||||
/**
|
||||
* Change the current kit. Commits the current kit name to workspace-local
|
||||
* persistent state so that the same kit is reloaded when the user opens
|
||||
* the workspace again.
|
||||
* @param kit The new Kit
|
||||
*/
|
||||
private _setActiveKit(kit: Kit | null) {
|
||||
if (kit) {
|
||||
this.stateManager.activeKitName = kit.name;
|
||||
|
@ -209,10 +274,15 @@ export class KitManager implements vscode.Disposable {
|
|||
this._activeKitChangedEmitter.fire(kit);
|
||||
}
|
||||
|
||||
// The status bar shows the currently selected kit, and allows the user
|
||||
// to select a new kit
|
||||
/**
|
||||
* Shows teh currently selected kit and allows the user to select a new one.
|
||||
*/
|
||||
private _statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 3);
|
||||
|
||||
/**
|
||||
* Create a new kit manager.
|
||||
* @param stateManager The workspace state manager
|
||||
*/
|
||||
constructor(readonly stateManager: StateManager) {
|
||||
// Re-read the kits file when it is changed
|
||||
this._kitsWatcher.onDidChange(_e => this._rereadKits());
|
||||
|
@ -229,14 +299,22 @@ export class KitManager implements vscode.Disposable {
|
|||
this._statusItem.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the kit manager
|
||||
*/
|
||||
dispose() {
|
||||
this._kitsWatcher.dispose();
|
||||
this._activeKitChangedEmitter.dispose();
|
||||
this._statusItem.dispose();
|
||||
}
|
||||
|
||||
private get _kitsPath(): string { return path.join(dirs.dataDir(), 'cmake-kits.json'); }
|
||||
|
||||
/**
|
||||
* Shows a QuickPick that lets the user select a new kit.
|
||||
* @returns The selected Kit, or `null` if the user cancelled the selection
|
||||
* @note The user cannot reset the active kit to `null`. If they make no
|
||||
* selection, the current kit is kept. The only way it can reset to `null` is
|
||||
* if the active kit becomes somehow unavailable.
|
||||
*/
|
||||
async selectKit(): Promise<Kit | null> {
|
||||
interface KitItem extends vscode.QuickPickItem {
|
||||
kit: Kit
|
||||
|
@ -244,7 +322,7 @@ export class KitManager implements vscode.Disposable {
|
|||
const items = this._kits.map((kit): KitItem => {
|
||||
return {
|
||||
label : kit.name,
|
||||
description : _descriptionForKit(kit),
|
||||
description : descriptionForKit(kit),
|
||||
kit : kit,
|
||||
};
|
||||
});
|
||||
|
@ -261,6 +339,12 @@ export class KitManager implements vscode.Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescan the system for kits.
|
||||
*
|
||||
* This will update the `cmake-kits.json` file with any newly discovered kits,
|
||||
* and rewrite any previously discovered kits with the new data.
|
||||
*/
|
||||
async rescanForKits() {
|
||||
// clang-format off
|
||||
const old_kits_by_name = this._kits.reduce(
|
||||
|
@ -296,6 +380,10 @@ export class KitManager implements vscode.Disposable {
|
|||
await fs.writeFile(this._kitsPath, JSON.stringify(sorted_kits, null, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reread the `cmake-kits.json` file. This will be called if we write the
|
||||
* file in `rescanForKits`, or if the user otherwise edits the file manually.
|
||||
*/
|
||||
private async _rereadKits() {
|
||||
const content_str = await fs.readFile(this._kitsPath);
|
||||
const content = JSON.parse(content_str.toLocaleString()) as object[];
|
||||
|
@ -344,6 +432,9 @@ export class KitManager implements vscode.Disposable {
|
|||
this._setActiveKit(already_active_kit || null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the kits manager. Must be called before using an instance.
|
||||
*/
|
||||
async initialize() {
|
||||
if (await fs.exists(this._kitsPath)) {
|
||||
// Load up the list of kits that we've saved
|
||||
|
@ -367,8 +458,11 @@ export class KitManager implements vscode.Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a text editor with the user-local `cmake-kits.json` file.
|
||||
*/
|
||||
async openKitsEditor() {
|
||||
const text = await vscode.workspace.openTextDocument(this._kitsPath);
|
||||
return vscode.window.showTextDocument(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
import {CMakeDriver} from './driver';
|
||||
import {RollbarController} from './rollbar';
|
||||
/**
|
||||
* Module for the legacy driver. Talks to pre-CMake Server versions of CMake.
|
||||
* Can also talk to newer versions of CMake via the command line.
|
||||
*/ /** */
|
||||
|
||||
import { CMakeDriver } from './driver';
|
||||
// import rollbar from './rollbar';
|
||||
import {Kit} from './kit';
|
||||
import {fs} from './pr';
|
||||
import {config} from './config';
|
||||
import config from './config';
|
||||
import * as util from './util';
|
||||
import * as proc from './proc';
|
||||
// import * as proc from './proc';
|
||||
|
||||
/**
|
||||
* The legacy driver.
|
||||
*/
|
||||
export class LegacyCMakeDriver extends CMakeDriver {
|
||||
private constructor(rb: RollbarController) { super(rb); }
|
||||
private constructor() { super(); }
|
||||
|
||||
async setKit(kit: Kit): Promise<void> {
|
||||
const need_clean = this._kitChangeNeedsClean(kit);
|
||||
if (need_clean) {
|
||||
await fs.rmdir(this.binaryDir);
|
||||
}
|
||||
this._kit = kit;
|
||||
this._setBaseKit(kit);
|
||||
}
|
||||
|
||||
// Legacy disposal does nothing
|
||||
|
@ -57,8 +65,8 @@ export class LegacyCMakeDriver extends CMakeDriver {
|
|||
return res.retc;
|
||||
}
|
||||
|
||||
static async create(rb: RollbarController): Promise<LegacyCMakeDriver> {
|
||||
const inst = new LegacyCMakeDriver(rb);
|
||||
static async create(): Promise<LegacyCMakeDriver> {
|
||||
const inst = new LegacyCMakeDriver();
|
||||
await inst._init();
|
||||
return inst;
|
||||
}
|
||||
|
|
40
src/pr.ts
40
src/pr.ts
|
@ -1,3 +1,8 @@
|
|||
/**
|
||||
* This module promise-ifies some NodeJS APIs that are frequently used in this
|
||||
* ext.
|
||||
*/ /** */
|
||||
|
||||
import promisify_ = require('es6-promisify');
|
||||
import * as util from 'util';
|
||||
// VSCode doesn't ship with util.promisify yet, but we do have type definitions for it, so we'll
|
||||
|
@ -6,10 +11,14 @@ const promisify = promisify_ as typeof util.promisify;
|
|||
|
||||
import * as fs_ from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
/**
|
||||
* Wrappers for the `fs` module.
|
||||
*
|
||||
* Also has a few utility functions
|
||||
*/
|
||||
export namespace fs {
|
||||
|
||||
export function exists(fspath: string): Promise<boolean> {
|
||||
|
@ -36,6 +45,11 @@ export namespace fs {
|
|||
|
||||
export const unlink = promisify(fs_.unlink);
|
||||
|
||||
/**
|
||||
* Creates a directory and all parent directories recursively. If the file
|
||||
* already exists, and is not a directory, just return.
|
||||
* @param fspath The directory to create
|
||||
*/
|
||||
export async function mkdir_p(fspath: string): Promise<void> {
|
||||
const parent = path.dirname(fspath);
|
||||
if (!await exists(parent)) {
|
||||
|
@ -54,6 +68,11 @@ export namespace fs {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file from one location to another.
|
||||
* @param inpath The input file
|
||||
* @param outpath The output file
|
||||
*/
|
||||
export function copyFile(inpath: string, outpath: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const reader = fs_.createReadStream(inpath);
|
||||
|
@ -69,21 +88,10 @@ export namespace fs {
|
|||
});
|
||||
}
|
||||
|
||||
export function hexHash(filepath: string): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const hash = crypto.createHash('md5');
|
||||
const reader = fs_.createReadStream(filepath);
|
||||
reader.on('error', e => reject(e));
|
||||
reader.on('open', _fd => {
|
||||
reader.pipe(hash);
|
||||
reader.on('close', () => {
|
||||
hash.end();
|
||||
resolve((hash.read() as Buffer).toString('hex'));
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a directory recursively. **DANGER DANGER!**
|
||||
* @param dirpath Directory to remove
|
||||
*/
|
||||
export function rmdir(dirpath: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
rimraf(dirpath, err => {
|
||||
|
|
51
src/proc.ts
51
src/proc.ts
|
@ -1,27 +1,32 @@
|
|||
/**
|
||||
* Wrappers and utilities around the NodeJS `child_process` module.
|
||||
*/ /** */
|
||||
|
||||
import * as proc from 'child_process';
|
||||
|
||||
export interface ExecutionResult {
|
||||
retc: number;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
import {ExecutionResult} from './api';
|
||||
|
||||
export function execute(command: string, args: string[], options?: proc.SpawnOptions): Promise<ExecutionResult> {
|
||||
return new Promise<ExecutionResult>((resolve, reject) => {
|
||||
const child = proc.spawn(command, args, options);
|
||||
child.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
let stdout_acc = '';
|
||||
let stderr_acc = '';
|
||||
child.stdout.on('data', (data: Uint8Array) => {
|
||||
stdout_acc += data.toString();
|
||||
});
|
||||
child.stderr.on('data', (data: Uint8Array) => {
|
||||
stderr_acc += data.toString();
|
||||
});
|
||||
child.on('close', (retc) => {
|
||||
resolve({retc: retc, stdout: stdout_acc, stderr: stderr_acc});
|
||||
});
|
||||
});
|
||||
/**
|
||||
* Execute a command and return the result
|
||||
* @param command The binary to execute
|
||||
* @param args The arguments to pass to the binary
|
||||
* @param options Additional execution options
|
||||
*
|
||||
* @note Output from the command is accumulated into a single buffer: Commands
|
||||
* which produce a lot of output should be careful about memory constraints.
|
||||
*/
|
||||
export function execute(command: string, args: string[], options?: proc.SpawnOptions):
|
||||
Promise<ExecutionResult> {
|
||||
return new Promise<ExecutionResult>((resolve, reject) => {
|
||||
const child = proc.spawn(command, args, options);
|
||||
child.on('error', (err) => { reject(err); });
|
||||
let stdout_acc = '';
|
||||
let stderr_acc = '';
|
||||
child.stdout.on('data', (data: Uint8Array) => { stdout_acc += data.toString(); });
|
||||
child.stderr.on('data', (data: Uint8Array) => { stderr_acc += data.toString(); });
|
||||
// Don't stop until the child stream is closed, otherwise we might not read
|
||||
// the whole output of the command.
|
||||
child.on('close',
|
||||
(retc) => { resolve({retc : retc, stdout : stdout_acc, stderr : stderr_acc}); });
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,41 +1,70 @@
|
|||
/**
|
||||
* Wrapper around Rollbar, for error reporting.
|
||||
*/ /** */
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import Rollbar = require('rollbar');
|
||||
|
||||
/**
|
||||
* The wrapper around Rollbar. Presents a nice functional API.
|
||||
*/
|
||||
class RollbarController {
|
||||
/**
|
||||
* The payload to send with any messages. Can be updated via `updatePayload`.
|
||||
*/
|
||||
private readonly _payload: object = {platform : 'client'};
|
||||
|
||||
export class RollbarController {
|
||||
/**
|
||||
* The Rollbar client instance we use to communicate.
|
||||
*/
|
||||
private _rollbar = new Rollbar({
|
||||
accessToken : '14d411d713be4a5a9f9d57660534cac7',
|
||||
reportLevel : 'error',
|
||||
payload : {
|
||||
platform : 'client',
|
||||
},
|
||||
payload : this._payload,
|
||||
});
|
||||
|
||||
/**
|
||||
* If `true`, we will send messages. We must get the user's permission first!
|
||||
*/
|
||||
private _enabled = false;
|
||||
|
||||
constructor(readonly extensionContext: vscode.ExtensionContext) {}
|
||||
|
||||
async requestPermissions() {
|
||||
/**
|
||||
* Request permission to use Rollbar from the user. This will show a message
|
||||
* box at the top of the window on first permission request.
|
||||
* @param extensionContext Extension context, where we use a memento to
|
||||
* remember our permission
|
||||
*/
|
||||
async requestPermissions(extensionContext: vscode.ExtensionContext): Promise<void> {
|
||||
// The memento key where we store permission. Update this to ask again.
|
||||
const key = 'rollbar-optin3';
|
||||
const optin = this.extensionContext.globalState.get(key);
|
||||
const optin = extensionContext.globalState.get(key);
|
||||
if (optin === true) {
|
||||
this._enabled = true;
|
||||
} else if (optin == false) {
|
||||
this._enabled = false;
|
||||
} else if (optin === undefined) {
|
||||
// We haven't asked yet. Ask them now:
|
||||
const item = await vscode.window.showInformationMessage(
|
||||
"Would you like to opt-in to send anonymous error and exception data to help improve CMake Tools?",
|
||||
{ title: 'Yes!', isCloseAffordance: false, } as vscode.MessageItem,
|
||||
{ title: 'No Thanks', isCloseAffordance: true, } as vscode.MessageItem);
|
||||
|
||||
if (item === undefined) {
|
||||
// We didn't get an answer
|
||||
return;
|
||||
}
|
||||
this.extensionContext.globalState.update(key, !item.isCloseAffordance);
|
||||
extensionContext.globalState.update(key, !item.isCloseAffordance);
|
||||
this._enabled = !item.isCloseAffordance
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an exception with Rollbar.
|
||||
* @param what A message about what we were doing when the exception happened
|
||||
* @param exception The exception object
|
||||
* @param additional Additional items in the payload
|
||||
* @returns The LogResult if we are enabled. `null` otherwise.
|
||||
*/
|
||||
exception(what: string, exception: Error, additional: object = {}): Rollbar.LogResult | null {
|
||||
if (this._enabled) {
|
||||
return this._rollbar.error(what, exception, additional);
|
||||
|
@ -43,25 +72,57 @@ export class RollbarController {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error with Rollbar
|
||||
* @param what A message about what we were doing when the error happened
|
||||
* @param additional Additional items in the payload
|
||||
* @returns The LogResult if we are enabled. `null` otherwise.
|
||||
*/
|
||||
error(what: string, additional: object = {}): Rollbar.LogResult | null {
|
||||
if (this._enabled) {
|
||||
return this._rollbar.error(what, additional);
|
||||
const stack = new Error().stack;
|
||||
return this._rollbar.error(what, additional, {stack: stack});
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
invokeAsync<T>(what: string, func: () => Promise<T>): Promise<T>;
|
||||
/**
|
||||
* Update the content of the Rollbar payload with additional context
|
||||
* information.
|
||||
* @param data Daya to merge into the payload
|
||||
*/
|
||||
updatePayload(data: object) {
|
||||
Object.assign(this._payload, data);
|
||||
this._rollbar.configure({payload : this._payload});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke an asynchronous function, and catch any promise rejects.
|
||||
* @param what Message about what we are doing
|
||||
* @param additional Additional data to log
|
||||
* @param func The block to call
|
||||
*/
|
||||
invokeAsync<T>(what: string, additional: object, func: () => Promise<T>): Promise<T>;
|
||||
invokeAsync<T>(what: string, func: () => Promise<T>): Promise<T>;
|
||||
invokeAsync<T>(what: string, additional: object, func?: () => Promise<T>): Promise<T> {
|
||||
if (!func) {
|
||||
func = additional as() => Promise<T>;
|
||||
additional = {};
|
||||
}
|
||||
return func().catch(e => { this.exception('Unhandled Promise rejection: ' + what, e, additional); });
|
||||
return func().catch(e => {
|
||||
this.exception('Unhandled Promise rejection: ' + what, e, additional);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
invoke<T>(what: string, func: () => T): T;
|
||||
/**
|
||||
* Invoke a synchronous function, and catch and log any unhandled exceptions
|
||||
* @param what Message about what we are doing
|
||||
* @param additional Additional data to log
|
||||
* @param func The block to call
|
||||
*/
|
||||
invoke<T>(what: string, additional: object, func: () => T): T;
|
||||
invoke<T>(what: string, func: () => T): T;
|
||||
invoke<T>(what: string, additional: object, func?: () => T): T {
|
||||
if (!func) {
|
||||
func = additional as() => T;
|
||||
|
@ -75,3 +136,6 @@ export class RollbarController {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rollbar = new RollbarController();
|
||||
export default rollbar;
|
|
@ -13,7 +13,9 @@ import * as vscode from 'vscode';
|
|||
export class StateManager {
|
||||
constructor(readonly extensionContext: vscode.ExtensionContext) {}
|
||||
|
||||
// The kit
|
||||
/**
|
||||
* The name of the workspace-local active kit.
|
||||
*/
|
||||
public get activeKitName(): string | null {
|
||||
const kit = this.extensionContext.workspaceState.get<string>('activeKitName');
|
||||
return kit || null;
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as path from 'path';
|
|||
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
import {config} from './config';
|
||||
import config from './config';
|
||||
|
||||
/**
|
||||
* Escape a string so it can be used as a regular expression
|
||||
|
@ -86,6 +86,11 @@ export function isTruthy(value: (boolean | string | null | undefined | number))
|
|||
return !!value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an array of key-value pairs from an object using
|
||||
* `getOwnPropertyNames`
|
||||
* @param obj The object to iterate
|
||||
*/
|
||||
export function objectPairs<V>(obj: {[key: string] : V}): [ string, V ][] {
|
||||
return Object.getOwnPropertyNames(obj).map(key => ([ key, obj[key] ] as[string, V]));
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"target": "es2017",
|
||||
"outDir": "out",
|
||||
"lib": [
|
||||
"es6"
|
||||
|
@ -13,7 +13,8 @@
|
|||
"strictNullChecks": true,
|
||||
"experimentalDecorators": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitThis": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
256
yarn.lock
256
yarn.lock
|
@ -10,10 +10,47 @@
|
|||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/es6-promisify/-/es6-promisify-5.0.0.tgz#f4ed22257f54c4e4af4d2f498766ef055db7a728"
|
||||
|
||||
"@types/fs-extra@^4.0.0":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-4.0.2.tgz#7b9b1bbf85962cbe029b5a83c9b530d7c75af3ba"
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/glob@*":
|
||||
version "5.0.32"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.32.tgz#aec5cfe987c72f099fdb1184452986aa506d5e8f"
|
||||
dependencies:
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/handlebars@^4.0.31":
|
||||
version "4.0.36"
|
||||
resolved "https://registry.yarnpkg.com/@types/handlebars/-/handlebars-4.0.36.tgz#ff57c77fa1ab6713bb446534ddc4d979707a3a79"
|
||||
|
||||
"@types/highlight.js@^9.1.8":
|
||||
version "9.1.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/highlight.js/-/highlight.js-9.1.10.tgz#b621f809cd9573b80992b90cffc5788208e3069c"
|
||||
|
||||
"@types/js-yaml@^3.5.28":
|
||||
version "3.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-3.9.1.tgz#2f3c142771bb345829ce690c5838760b6b9ba553"
|
||||
|
||||
"@types/lodash@^4.14.37":
|
||||
version "4.14.74"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.74.tgz#ac3bd8db988e7f7038e5d22bd76a7ba13f876168"
|
||||
|
||||
"@types/marked@0.0.28":
|
||||
version "0.0.28"
|
||||
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-0.0.28.tgz#44ba754e9fa51432583e8eb30a7c4dd249b52faa"
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.1.tgz#b683eb60be358304ef146f5775db4c0e3696a550"
|
||||
|
||||
"@types/minimatch@^2.0.29":
|
||||
version "2.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-2.0.29.tgz#5002e14f75e2d71e564281df0431c8c1b4a2a36a"
|
||||
|
||||
"@types/mocha@~2.2.41":
|
||||
version "2.2.43"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.43.tgz#03c54589c43ad048cbcbfd63999b55d0424eec27"
|
||||
|
@ -26,6 +63,13 @@
|
|||
version "0.0.28"
|
||||
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
|
||||
|
||||
"@types/shelljs@^0.7.0":
|
||||
version "0.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.7.4.tgz#137b5f31306eaff4de120ffe5b9d74b297809cfc"
|
||||
dependencies:
|
||||
"@types/glob" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/ws@^0.0.38":
|
||||
version "0.0.38"
|
||||
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-0.0.38.tgz#42106fff4b422ca956734e29f0d73a6d893194d3"
|
||||
|
@ -56,6 +100,18 @@ ajv@^5.1.0:
|
|||
json-schema-traverse "^0.3.0"
|
||||
json-stable-stringify "^1.0.1"
|
||||
|
||||
align-text@^0.1.1, align-text@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
|
||||
dependencies:
|
||||
kind-of "^3.0.2"
|
||||
longest "^1.0.1"
|
||||
repeat-string "^1.5.2"
|
||||
|
||||
amdefine@>=0.0.4:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
|
@ -114,6 +170,10 @@ assert-plus@^0.2.0:
|
|||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234"
|
||||
|
||||
async@^1.4.0:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
|
||||
|
||||
async@~1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.2.1.tgz#a4816a17cd5ff516dfa2c7698a453369b9790de0"
|
||||
|
@ -195,6 +255,10 @@ buffer-crc32@~0.2.3:
|
|||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
|
||||
camelcase@^1.0.2:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
|
||||
|
||||
caseless@~0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
|
||||
|
@ -203,6 +267,13 @@ caseless@~0.12.0:
|
|||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
|
||||
center-align@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
|
||||
dependencies:
|
||||
align-text "^0.1.3"
|
||||
lazy-cache "^1.0.3"
|
||||
|
||||
chalk@^1.0.0, chalk@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
|
||||
|
@ -213,6 +284,14 @@ chalk@^1.0.0, chalk@^1.1.1:
|
|||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
cliui@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
|
||||
dependencies:
|
||||
center-align "^0.1.1"
|
||||
right-align "^0.1.1"
|
||||
wordwrap "0.0.2"
|
||||
|
||||
clone-buffer@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
|
||||
|
@ -317,6 +396,10 @@ decache@^3.0.5:
|
|||
dependencies:
|
||||
find "^0.2.4"
|
||||
|
||||
decamelize@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
|
||||
deep-assign@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b"
|
||||
|
@ -509,6 +592,14 @@ from@~0:
|
|||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe"
|
||||
|
||||
fs-extra@^4.0.0:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
|
@ -592,7 +683,7 @@ glob@^5.0.3:
|
|||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.5, glob@^7.1.1:
|
||||
glob@^7.0.0, glob@^7.0.5, glob@^7.1.1:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
|
||||
dependencies:
|
||||
|
@ -609,7 +700,7 @@ glogg@^1.0.0:
|
|||
dependencies:
|
||||
sparkles "^1.0.0"
|
||||
|
||||
graceful-fs@^4.0.0, graceful-fs@^4.1.2:
|
||||
graceful-fs@^4.0.0, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
|
@ -724,6 +815,16 @@ gulplog@^1.0.0:
|
|||
dependencies:
|
||||
glogg "^1.0.0"
|
||||
|
||||
handlebars@^4.0.6:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f"
|
||||
dependencies:
|
||||
async "^1.4.0"
|
||||
optimist "^0.6.1"
|
||||
source-map "^0.4.4"
|
||||
optionalDependencies:
|
||||
uglify-js "^2.6"
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
|
@ -782,6 +883,10 @@ he@1.1.1:
|
|||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||
|
||||
highlight.js@^9.0.0:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
|
||||
|
||||
hoek@2.x.x:
|
||||
version "2.16.3"
|
||||
resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
|
||||
|
@ -817,6 +922,10 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
|
|||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
interpret@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0"
|
||||
|
||||
is-buffer@^1.1.5:
|
||||
version "1.1.5"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
|
||||
|
@ -967,6 +1076,12 @@ json3@3.3.2:
|
|||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsonify@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||
|
@ -996,6 +1111,10 @@ kind-of@^4.0.0:
|
|||
dependencies:
|
||||
is-buffer "^1.1.5"
|
||||
|
||||
lazy-cache@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
||||
|
||||
lazystream@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
|
||||
|
@ -1108,6 +1227,14 @@ lodash.templatesettings@^3.0.0:
|
|||
lodash._reinterpolate "^3.0.0"
|
||||
lodash.escape "^3.0.0"
|
||||
|
||||
lodash@^4.13.1:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
longest@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
|
||||
|
||||
lru-cache@~2.2.1:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
|
||||
|
@ -1116,6 +1243,10 @@ map-stream@~0.1.0:
|
|||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
|
||||
|
||||
marked@^0.3.5:
|
||||
version "0.3.6"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
|
||||
|
||||
merge-stream@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
|
||||
|
@ -1164,6 +1295,10 @@ minimist@^1.1.0:
|
|||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
minimist@~0.0.1:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
|
||||
|
||||
mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
|
@ -1267,6 +1402,13 @@ open@0.0.5:
|
|||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc"
|
||||
|
||||
optimist@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
|
||||
dependencies:
|
||||
minimist "~0.0.1"
|
||||
wordwrap "~0.0.2"
|
||||
|
||||
options@>=0.0.5:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f"
|
||||
|
@ -1295,6 +1437,10 @@ path-is-absolute@^1.0.0:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
|
||||
path-parse@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
|
||||
|
||||
pause-stream@0.0.11:
|
||||
version "0.0.11"
|
||||
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
|
||||
|
@ -1327,6 +1473,10 @@ process-nextick-args@^1.0.6, process-nextick-args@~1.0.6:
|
|||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
||||
|
||||
progress@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
|
@ -1386,6 +1536,12 @@ readable-stream@~1.1.9:
|
|||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
rechoir@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
||||
dependencies:
|
||||
resolve "^1.1.6"
|
||||
|
||||
regex-cache@^0.4.2:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
|
||||
|
@ -1474,6 +1630,18 @@ requires-port@1.0.x:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||
|
||||
resolve@^1.1.6:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
|
||||
dependencies:
|
||||
path-parse "^1.0.5"
|
||||
|
||||
right-align@^0.1.1:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
|
||||
dependencies:
|
||||
align-text "^0.1.1"
|
||||
|
||||
rimraf@2, rimraf@^2.5.4:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
|
||||
|
@ -1508,6 +1676,14 @@ semver@^5.3.0:
|
|||
version "5.4.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
|
||||
|
||||
shelljs@^0.7.0:
|
||||
version "0.7.8"
|
||||
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3"
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
interpret "^1.0.0"
|
||||
rechoir "^0.6.2"
|
||||
|
||||
sntp@1.x.x:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
|
||||
|
@ -1526,7 +1702,13 @@ source-map-support@^0.4.11:
|
|||
dependencies:
|
||||
source-map "^0.5.6"
|
||||
|
||||
source-map@^0.5.6:
|
||||
source-map@^0.4.4:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
|
||||
dependencies:
|
||||
amdefine ">=0.0.4"
|
||||
|
||||
source-map@^0.5.6, source-map@~0.5.1:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
|
||||
|
@ -1696,10 +1878,53 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
|||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
|
||||
typedoc-default-themes@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.5.0.tgz#6dc2433e78ed8bea8e887a3acde2f31785bd6227"
|
||||
|
||||
typedoc@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.8.0.tgz#d7172bc6a29964f451b7609c005beadadefe2361"
|
||||
dependencies:
|
||||
"@types/fs-extra" "^4.0.0"
|
||||
"@types/handlebars" "^4.0.31"
|
||||
"@types/highlight.js" "^9.1.8"
|
||||
"@types/lodash" "^4.14.37"
|
||||
"@types/marked" "0.0.28"
|
||||
"@types/minimatch" "^2.0.29"
|
||||
"@types/shelljs" "^0.7.0"
|
||||
fs-extra "^4.0.0"
|
||||
handlebars "^4.0.6"
|
||||
highlight.js "^9.0.0"
|
||||
lodash "^4.13.1"
|
||||
marked "^0.3.5"
|
||||
minimatch "^3.0.0"
|
||||
progress "^2.0.0"
|
||||
shelljs "^0.7.0"
|
||||
typedoc-default-themes "^0.5.0"
|
||||
typescript "2.4.1"
|
||||
|
||||
typescript@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.1.tgz#c3ccb16ddaa0b2314de031e7e6fee89e5ba346bc"
|
||||
|
||||
typescript@~2.3.0:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42"
|
||||
|
||||
uglify-js@^2.6:
|
||||
version "2.8.29"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
|
||||
dependencies:
|
||||
source-map "~0.5.1"
|
||||
yargs "~3.10.0"
|
||||
optionalDependencies:
|
||||
uglify-to-browserify "~1.0.0"
|
||||
|
||||
uglify-to-browserify@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
|
||||
|
||||
ultron@1.0.x:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
|
||||
|
@ -1711,6 +1936,10 @@ unique-stream@^2.0.2:
|
|||
json-stable-stringify "^1.0.0"
|
||||
through2-filter "^2.0.0"
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
|
||||
|
||||
url-parse@^1.1.9:
|
||||
version "1.1.9"
|
||||
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19"
|
||||
|
@ -1825,6 +2054,18 @@ vscode@~1.1.0:
|
|||
url-parse "^1.1.9"
|
||||
vinyl-source-stream "^1.1.0"
|
||||
|
||||
window-size@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
|
||||
|
||||
wordwrap@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
|
||||
|
||||
wordwrap@~0.0.2:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
@ -1851,6 +2092,15 @@ xmlbuilder@~9.0.1:
|
|||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
||||
yargs@~3.10.0:
|
||||
version "3.10.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
|
||||
dependencies:
|
||||
camelcase "^1.0.2"
|
||||
cliui "^2.1.0"
|
||||
decamelize "^1.0.0"
|
||||
window-size "0.1.0"
|
||||
|
||||
yauzl@^2.2.1:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.8.0.tgz#79450aff22b2a9c5a41ef54e02db907ccfbf9ee2"
|
||||
|
|
Загрузка…
Ссылка в новой задаче