move global cache location to node typings installer
This commit is contained in:
parent
f603f024ba
commit
672813afb6
|
@ -29,15 +29,12 @@ namespace ts {
|
||||||
|
|
||||||
abstract class TestTypingsInstaller extends server.typingsInstaller.TypingsInstaller implements server.ITypingsInstaller {
|
abstract class TestTypingsInstaller extends server.typingsInstaller.TypingsInstaller implements server.ITypingsInstaller {
|
||||||
protected projectService: server.ProjectService;
|
protected projectService: server.ProjectService;
|
||||||
constructor(private readonly host: server.ServerHost) {
|
constructor(readonly cachePath: string, readonly installTypingHost: server.ServerHost) {
|
||||||
super();
|
super(cachePath, <Path>"");
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract cachePath: string;
|
|
||||||
safeFileList = <Path>"";
|
safeFileList = <Path>"";
|
||||||
packageNameToTypingLocation: Map<string> = createMap<string>();
|
|
||||||
|
|
||||||
postInstallActions: (( map: (t: string[]) => string[]) => void)[] = [];
|
postInstallActions: (( map: (t: string[]) => string[]) => void)[] = [];
|
||||||
|
|
||||||
runPostInstallActions(map: (t: string[]) => string[]) {
|
runPostInstallActions(map: (t: string[]) => string[]) {
|
||||||
|
@ -52,7 +49,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstallTypingHost() {
|
getInstallTypingHost() {
|
||||||
return this.host;
|
return this.installTypingHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
installPackage(packageName: string) {
|
installPackage(packageName: string) {
|
||||||
|
@ -74,7 +71,7 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueueInstallTypingsRequest(project: server.Project, typingOptions: TypingOptions) {
|
enqueueInstallTypingsRequest(project: server.Project, typingOptions: TypingOptions) {
|
||||||
const request = server.createInstallTypingsRequest(project, typingOptions, this.safeFileList, this.packageNameToTypingLocation, this.cachePath);
|
const request = server.createInstallTypingsRequest(project, typingOptions, this.cachePath);
|
||||||
this.install(request);
|
this.install(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1519,9 +1516,8 @@ namespace ts {
|
||||||
|
|
||||||
const host = createServerHost([file1, tsconfig, packageJson]);
|
const host = createServerHost([file1, tsconfig, packageJson]);
|
||||||
class TypingInstaller extends TestTypingsInstaller {
|
class TypingInstaller extends TestTypingsInstaller {
|
||||||
cachePath = "/a/data/";
|
|
||||||
constructor(host: server.ServerHost) {
|
constructor(host: server.ServerHost) {
|
||||||
super(host);
|
super("/a/data/", host);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const installer = new TypingInstaller(host);
|
const installer = new TypingInstaller(host);
|
||||||
|
|
|
@ -18,10 +18,6 @@ namespace ts.server {
|
||||||
fork(modulePath: string): NodeChildProcess;
|
fork(modulePath: string): NodeChildProcess;
|
||||||
} = require("child_process");
|
} = require("child_process");
|
||||||
|
|
||||||
const os: {
|
|
||||||
homedir(): string
|
|
||||||
} = require("os");
|
|
||||||
|
|
||||||
interface ReadLineOptions {
|
interface ReadLineOptions {
|
||||||
input: NodeJS.ReadableStream;
|
input: NodeJS.ReadableStream;
|
||||||
output?: NodeJS.WritableStream;
|
output?: NodeJS.WritableStream;
|
||||||
|
@ -167,24 +163,8 @@ namespace ts.server {
|
||||||
class NodeTypingsInstaller implements ITypingsInstaller {
|
class NodeTypingsInstaller implements ITypingsInstaller {
|
||||||
private installer: NodeChildProcess;
|
private installer: NodeChildProcess;
|
||||||
private projectService: ProjectService;
|
private projectService: ProjectService;
|
||||||
private cachePath: string;
|
|
||||||
|
|
||||||
constructor(private readonly logger: server.Logger) {
|
constructor(private readonly logger: server.Logger) {
|
||||||
let basePath: string;
|
|
||||||
switch (process.platform) {
|
|
||||||
case "win32":
|
|
||||||
basePath = process.env.LOCALAPPDATA || process.env.APPDATA || os.homedir();
|
|
||||||
break;
|
|
||||||
case "linux":
|
|
||||||
basePath = os.homedir();
|
|
||||||
break;
|
|
||||||
case "darwin":
|
|
||||||
basePath = combinePaths(os.homedir(), "Library/Application Support/")
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (basePath) {
|
|
||||||
this.cachePath = combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
attach(projectService: ProjectService) {
|
attach(projectService: ProjectService) {
|
||||||
|
@ -198,13 +178,7 @@ namespace ts.server {
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueueInstallTypingsRequest(project: Project, typingOptions: TypingOptions): void {
|
enqueueInstallTypingsRequest(project: Project, typingOptions: TypingOptions): void {
|
||||||
const request = createInstallTypingsRequest(
|
const request = createInstallTypingsRequest(project, typingOptions);
|
||||||
project,
|
|
||||||
typingOptions,
|
|
||||||
/*safeListPath*/ <Path>(combinePaths(process.cwd(), "typingSafeList.json")), // TODO: fixme
|
|
||||||
/*packageNameToTypingLocation*/ createMap<string>(), // TODO: fixme
|
|
||||||
this.cachePath
|
|
||||||
);
|
|
||||||
if (this.logger.hasLevel(LogLevel.verbose)) {
|
if (this.logger.hasLevel(LogLevel.verbose)) {
|
||||||
this.logger.info(`Sending request: ${JSON.stringify(request)}`);
|
this.logger.info(`Sending request: ${JSON.stringify(request)}`);
|
||||||
}
|
}
|
||||||
|
|
4
src/server/types.d.ts
vendored
4
src/server/types.d.ts
vendored
|
@ -7,11 +7,9 @@ declare namespace ts.server {
|
||||||
readonly projectName: string;
|
readonly projectName: string;
|
||||||
readonly fileNames: string[];
|
readonly fileNames: string[];
|
||||||
readonly projectRootPath: ts.Path;
|
readonly projectRootPath: ts.Path;
|
||||||
readonly safeListPath: ts.Path;
|
|
||||||
readonly packageNameToTypingLocation: ts.Map<string>;
|
|
||||||
readonly typingOptions: ts.TypingOptions;
|
readonly typingOptions: ts.TypingOptions;
|
||||||
readonly compilerOptions: ts.CompilerOptions;
|
readonly compilerOptions: ts.CompilerOptions;
|
||||||
readonly cachePath: string;
|
readonly cachePath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CompressedData {
|
export interface CompressedData {
|
||||||
|
|
|
@ -2,13 +2,39 @@
|
||||||
/// <reference types="node" />
|
/// <reference types="node" />
|
||||||
|
|
||||||
namespace ts.server.typingsInstaller {
|
namespace ts.server.typingsInstaller {
|
||||||
|
|
||||||
|
const os: {
|
||||||
|
homedir(): string
|
||||||
|
} = require("os");
|
||||||
|
|
||||||
|
function getGlobalCacheLocation() {
|
||||||
|
let basePath: string;
|
||||||
|
switch (process.platform) {
|
||||||
|
case "win32":
|
||||||
|
basePath = process.env.LOCALAPPDATA || process.env.APPDATA || os.homedir();
|
||||||
|
break;
|
||||||
|
case "linux":
|
||||||
|
basePath = os.homedir();
|
||||||
|
break;
|
||||||
|
case "darwin":
|
||||||
|
basePath = combinePaths(os.homedir(), "Library/Application Support/")
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.assert(basePath !== undefined);
|
||||||
|
return combinePaths(normalizeSlashes(basePath), "Microsoft/TypeScript");
|
||||||
|
}
|
||||||
|
|
||||||
export class NodeTypingsInstaller extends TypingsInstaller {
|
export class NodeTypingsInstaller extends TypingsInstaller {
|
||||||
private execSync: { (command: string, options: { stdio: "ignore" }): any };
|
private execSync: { (command: string, options: { stdio: "ignore" }): any };
|
||||||
private exec: { (command: string, options: { cwd: string }, callback?: (error: Error, stdout: string, stderr: string) => void): any };
|
private exec: { (command: string, options: { cwd: string }, callback?: (error: Error, stdout: string, stderr: string) => void): any };
|
||||||
|
readonly installTypingHost: InstallTypingHost = sys;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super(getGlobalCacheLocation(), toPath("typingSafeList.json", __dirname, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)));
|
||||||
this.execSync = require("child_process").execSync;
|
const { exec, execSync } = require("child_process");
|
||||||
this.exec = require("child_process").exec;
|
this.execSync = execSync;
|
||||||
|
this.exec = exec;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
@ -38,10 +64,6 @@ namespace ts.server.typingsInstaller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getInstallTypingHost() {
|
|
||||||
return sys;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected sendResponse(response: InstallTypingsResponse) {
|
protected sendResponse(response: InstallTypingsResponse) {
|
||||||
process.send(response);
|
process.send(response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,16 +9,38 @@ namespace ts.server.typingsInstaller {
|
||||||
path: "typings"
|
path: "typings"
|
||||||
}, /*replacer*/undefined, /*space*/4);
|
}, /*replacer*/undefined, /*space*/4);
|
||||||
|
|
||||||
|
interface TsdConfig {
|
||||||
|
installed: MapLike<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tsdTypingToFileName(cachePath: string, tsdTypingFile: string) {
|
||||||
|
return combinePaths(cachePath, `typings/${tsdTypingFile}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPackageName(tsdTypingFile: string) {
|
||||||
|
const idx = tsdTypingFile.indexOf("/");
|
||||||
|
return idx > 0 ? tsdTypingFile.substr(0, idx) : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class TypingsInstaller {
|
export abstract class TypingsInstaller {
|
||||||
|
|
||||||
private isTsdInstalled: boolean;
|
private isTsdInstalled: boolean;
|
||||||
private missingTypings: Map<string> = createMap<string>();
|
|
||||||
|
private packageNameToTypingLocation: Map<string> = createMap<string>();
|
||||||
|
private missingTypingsSet: Map<true> = createMap<true>();
|
||||||
|
private knownCachesSet: Map<true> = createMap<true>();
|
||||||
|
|
||||||
|
abstract readonly installTypingHost: InstallTypingHost;
|
||||||
|
|
||||||
|
constructor(readonly globalCachePath: string, readonly safeListPath: Path) {
|
||||||
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.isTsdInstalled = this.isPackageInstalled("tsd");
|
this.isTsdInstalled = this.isPackageInstalled("tsd");
|
||||||
if (!this.isTsdInstalled) {
|
if (!this.isTsdInstalled) {
|
||||||
this.isTsdInstalled = this.installPackage("tsd");
|
this.isTsdInstalled = this.installPackage("tsd");
|
||||||
}
|
}
|
||||||
|
this.processCacheLocation(this.globalCachePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
install(req: InstallTypingsRequest) {
|
install(req: InstallTypingsRequest) {
|
||||||
|
@ -26,43 +48,91 @@ namespace ts.server.typingsInstaller {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load existing typing information from the cache
|
||||||
|
if (req.cachePath) {
|
||||||
|
this.processCacheLocation(req.cachePath);
|
||||||
|
}
|
||||||
|
|
||||||
const discoverTypingsResult = JsTyping.discoverTypings(
|
const discoverTypingsResult = JsTyping.discoverTypings(
|
||||||
this.getInstallTypingHost(),
|
this.installTypingHost,
|
||||||
req.fileNames,
|
req.fileNames,
|
||||||
req.projectRootPath,
|
req.projectRootPath,
|
||||||
req.safeListPath,
|
this.safeListPath,
|
||||||
req.packageNameToTypingLocation,
|
this.packageNameToTypingLocation,
|
||||||
req.typingOptions,
|
req.typingOptions,
|
||||||
req.compilerOptions);
|
req.compilerOptions);
|
||||||
|
|
||||||
// respond with whatever cached typings we have now
|
// respond with whatever cached typings we have now
|
||||||
this.sendResponse(this.createResponse(req, discoverTypingsResult.cachedTypingPaths));
|
this.sendResponse(this.createResponse(req, discoverTypingsResult.cachedTypingPaths));
|
||||||
|
|
||||||
// start watching files
|
// start watching files
|
||||||
this.watchFiles(discoverTypingsResult.filesToWatch);
|
this.watchFiles(discoverTypingsResult.filesToWatch);
|
||||||
|
|
||||||
// install typings and
|
// install typings and
|
||||||
this.installTypings(req, discoverTypingsResult.cachedTypingPaths, discoverTypingsResult.newTypingNames);
|
this.installTypings(req, discoverTypingsResult.cachedTypingPaths, discoverTypingsResult.newTypingNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private processCacheLocation(cacheLocation: string) {
|
||||||
|
if (this.knownCachesSet[cacheLocation]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tsdJson = combinePaths(cacheLocation, "tsd.json");
|
||||||
|
if (this.installTypingHost.fileExists(tsdJson)) {
|
||||||
|
const tsdConfig = <TsdConfig>JSON.parse(this.installTypingHost.readFile(tsdJson));
|
||||||
|
if (tsdConfig.installed) {
|
||||||
|
for (const key in tsdConfig.installed) {
|
||||||
|
// key is <package name>/<typing file>
|
||||||
|
const packageName = getPackageName(key);
|
||||||
|
if (!packageName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const typingFile = tsdTypingToFileName(cacheLocation, key);
|
||||||
|
const existingTypingFile = this.packageNameToTypingLocation[packageName];
|
||||||
|
if (existingTypingFile === typingFile) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (existingTypingFile) {
|
||||||
|
// TODO: log warning
|
||||||
|
}
|
||||||
|
this.packageNameToTypingLocation[packageName] = typingFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.knownCachesSet[cacheLocation] = true;
|
||||||
|
}
|
||||||
|
|
||||||
private installTypings(req: InstallTypingsRequest, currentlyCachedTypings: string[], typingsToInstall: string[]) {
|
private installTypings(req: InstallTypingsRequest, currentlyCachedTypings: string[], typingsToInstall: string[]) {
|
||||||
typingsToInstall = filter(typingsToInstall, x => !hasProperty(this.missingTypings, x));
|
typingsToInstall = filter(typingsToInstall, x => !this.missingTypingsSet[x]);
|
||||||
if (typingsToInstall.length === 0) {
|
if (typingsToInstall.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: install typings and send response when they are ready
|
// TODO: install typings and send response when they are ready
|
||||||
const host = this.getInstallTypingHost();
|
|
||||||
const tsdPath = combinePaths(req.cachePath, "tsd.json");
|
const tsdPath = combinePaths(req.cachePath, "tsd.json");
|
||||||
if (!host.fileExists(tsdPath)) {
|
if (!this.installTypingHost.fileExists(tsdPath)) {
|
||||||
this.ensureDirectoryExists(req.cachePath, host);
|
this.ensureDirectoryExists(req.cachePath, this.installTypingHost);
|
||||||
host.writeFile(tsdPath, DefaultTsdSettings);
|
this.installTypingHost.writeFile(tsdPath, DefaultTsdSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.runTsd(req.cachePath, typingsToInstall, installedTypings => {
|
this.runTsd(req.cachePath, typingsToInstall, installedTypings => {
|
||||||
// TODO: record new missing package names
|
|
||||||
// TODO: watch project directory
|
// TODO: watch project directory
|
||||||
const typingDirectory = combinePaths(req.cachePath, "typings");
|
const installedPackages: Map<true> = createMap<true>();
|
||||||
installedTypings = installedTypings.map(x => combinePaths(typingDirectory, x));
|
const installedTypingFiles: string[] = [];
|
||||||
this.sendResponse(this.createResponse(req, currentlyCachedTypings.concat(installedTypings)));
|
for (const t of installedTypings) {
|
||||||
|
const packageName = getPackageName(t);
|
||||||
|
if (!packageName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
installedPackages[packageName] = true;
|
||||||
|
installedTypingFiles.push(tsdTypingToFileName(req.cachePath, t));
|
||||||
|
}
|
||||||
|
for (const toInstall of typingsToInstall) {
|
||||||
|
if (!installedPackages[toInstall]) {
|
||||||
|
this.missingTypingsSet[toInstall] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendResponse(this.createResponse(req, currentlyCachedTypings.concat(installedTypingFiles)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +161,6 @@ namespace ts.server.typingsInstaller {
|
||||||
|
|
||||||
protected abstract isPackageInstalled(packageName: string): boolean;
|
protected abstract isPackageInstalled(packageName: string): boolean;
|
||||||
protected abstract installPackage(packageName: string): boolean;
|
protected abstract installPackage(packageName: string): boolean;
|
||||||
protected abstract getInstallTypingHost(): InstallTypingHost;
|
|
||||||
protected abstract sendResponse(response: InstallTypingsResponse): void;
|
protected abstract sendResponse(response: InstallTypingsResponse): void;
|
||||||
protected abstract runTsd(cachePath: string, typingsToInstall: string[], postInstallAction: (installedTypings: string[]) => void): void;
|
protected abstract runTsd(cachePath: string, typingsToInstall: string[], postInstallAction: (installedTypings: string[]) => void): void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
/// <reference path="..\services\services.ts" />
|
|
||||||
/// <reference path="types.d.ts" />
|
/// <reference path="types.d.ts" />
|
||||||
|
|
||||||
namespace ts.server {
|
namespace ts.server {
|
||||||
|
@ -30,15 +29,13 @@ namespace ts.server {
|
||||||
export type Types = Err | Info | Perf;
|
export type Types = Err | Info | Perf;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createInstallTypingsRequest(project: Project, typingOptions: TypingOptions, safeListPath: Path, packageNameToTypingLocation: Map<string>, cachePath: string): InstallTypingsRequest {
|
export function createInstallTypingsRequest(project: Project, typingOptions: TypingOptions, cachePath?: string): InstallTypingsRequest {
|
||||||
return {
|
return {
|
||||||
projectName: project.getProjectName(),
|
projectName: project.getProjectName(),
|
||||||
fileNames: project.getFileNames(),
|
fileNames: project.getFileNames(),
|
||||||
compilerOptions: project.getCompilerOptions(),
|
compilerOptions: project.getCompilerOptions(),
|
||||||
typingOptions,
|
typingOptions,
|
||||||
projectRootPath: <Path>(project.projectKind === ProjectKind.Inferred ? "" : getDirectoryPath(project.getProjectName())), // TODO: fixme
|
projectRootPath: <Path>(project.projectKind === ProjectKind.Inferred ? "" : getDirectoryPath(project.getProjectName())), // TODO: fixme
|
||||||
safeListPath,
|
|
||||||
packageNameToTypingLocation,
|
|
||||||
cachePath
|
cachePath
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue