@sap/cds-lsp
Advanced tools
Comparing version 5.0.3 to 5.0.5
@@ -9,2 +9,8 @@ # Changelog | ||
## 5.0.5 - 2021-05-11 | ||
### Fixed | ||
- asynchronous scanning of workspace blocked and led to high cpu usage (mostly on Linux/macOS) | ||
## 5.0.3 - 2021-05-06 | ||
@@ -11,0 +17,0 @@ |
@@ -263,3 +263,9 @@ "use strict"; | ||
async fetchCdsEnv() { | ||
return this._cachedCdsEnv || this._envTaskManager.enqueue(`fetching cds.env:${this.workspaceUri}`, this.workspaceSnapshot.workspaceVersion, async () => { | ||
if (this._cachedCdsEnv) { | ||
return this._cachedCdsEnv; | ||
} | ||
if (!this.languageServer.options.getUserSetting(utils_1.UserSetting.FETCH_CDSENV, false)) { | ||
return cdsenv_1.defaultEnv(); | ||
} | ||
return this._envTaskManager.enqueue(`fetching cds.env:${this.workspaceUri}`, this.workspaceSnapshot.workspaceVersion, async () => { | ||
if (!this._cachedCdsEnv) { | ||
@@ -495,3 +501,3 @@ this._cachedCdsEnv = await this._fetchCdsEnv(); | ||
return tracer.tryCatch(async () => { | ||
const cdsenv = path.join(__dirname, '../../../lib/impl/utils/cdsenv/callCdsEnv'); | ||
const cdsenv = path.resolve(__dirname, '../../../lib/impl/utils/cdsenv/callCdsEnv'); | ||
const args = []; | ||
@@ -498,0 +504,0 @@ if (trace_1.currentTrace().tracer(trace_1.LspTraceComponent.ENV).isTracing(trace_1.LspTraceLevel.VERBOSE)) { |
@@ -9,3 +9,3 @@ /// <reference types="@sap__cds-compiler" /> | ||
private updateWorkspaceDocuments; | ||
protected readContent(uri: string): Promise<string>; | ||
protected readContent(uri: string): string; | ||
} |
@@ -24,11 +24,11 @@ "use strict"; | ||
const loopDetector = new utils_1.LoopDetector(); | ||
const thisModule = new utils_1.NodeModule(workspaceRoot, loopDetector, this.context.adapter, () => this.context.fetchCdsEnv()); | ||
const env = await this.context.fetchCdsEnv(); | ||
const thisModule = new utils_1.NodeModule(workspaceRoot, loopDetector, this.context.adapter, env); | ||
const sourceFiles = []; | ||
sourceFiles.push(...await thisModule.scanFiles(workspaceDocuments)); | ||
const dependencies = await thisModule.fetchDependencies(); | ||
sourceFiles.push(...thisModule.scanFiles(workspaceDocuments)); | ||
const dependencies = thisModule.readDependencies(); | ||
for (const dependency of dependencies) { | ||
sourceFiles.push(...await new utils_1.NodeModule(dependency.absoluteLocalPath, loopDetector, this.context.adapter, () => this.context.fetchCdsEnv()).scanFiles(workspaceDocuments)); | ||
sourceFiles.push(...new utils_1.NodeModule(dependency.absoluteLocalPath, loopDetector, this.context.adapter, env).scanFiles(workspaceDocuments)); | ||
} | ||
const env = await this.context.fetchCdsEnv(); | ||
const readFiles = async () => { | ||
const readFiles = () => { | ||
const readingAllFiles = sourceFiles.map((filename) => { | ||
@@ -40,11 +40,11 @@ const uri = this.context.adapter.toUri(filename); | ||
}); | ||
const bytesPerFile = await Promise.all(readingAllFiles); | ||
const bytesPerFile = readingAllFiles; | ||
const totalBytesRead = bytesPerFile.reduce((allBytesRead, singleFileBytesRead) => allBytesRead + singleFileBytesRead, 0); | ||
this.context.tracer.info(() => `A total of ${totalBytesRead} bytes read`); | ||
}; | ||
await this.context.tracer.footprint('Reading source files', readFiles); | ||
this.context.tracer.footprint('Reading source files', readFiles); | ||
return workspaceDocuments; | ||
} | ||
async updateWorkspaceDocuments(uri, workspaceDocuments, env) { | ||
const content = await this.readContent(uri); | ||
updateWorkspaceDocuments(uri, workspaceDocuments, env) { | ||
const content = this.readContent(uri); | ||
workspaceDocuments[uri] = content; | ||
@@ -54,5 +54,5 @@ this.context.onFileRead(env, uri, content); | ||
} | ||
async readContent(uri) { | ||
readContent(uri) { | ||
const filename = this.context.adapter.toLocalPath(uri); | ||
return fs.promises.readFile(filename, { encoding: 'utf8' }); | ||
return fs.readFileSync(filename, { encoding: 'utf8' }); | ||
} | ||
@@ -59,0 +59,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const util = require("util"); | ||
const trace_1 = require("../trace"); | ||
@@ -11,11 +12,22 @@ if (process.argv.includes('--verbose')) { | ||
const con = console; | ||
con.log = (m) => tracer.info(() => String(m)); | ||
con.error = (m) => tracer.error(() => String(m)); | ||
con.log = (m) => tracer.info(() => `stdout: ${util.inspect(m)}`); | ||
con.error = (m) => tracer.info(() => `stderr: ${util.inspect(m)}`); | ||
const CdsEnvConverter_1 = require("./CdsEnvConverter"); | ||
async function sendToLsp(pEnv) { | ||
var _a; | ||
(_a = process.send) === null || _a === void 0 ? void 0 : _a.call(process, JSON.stringify(await pEnv)); | ||
const cdsEnv = await pEnv; | ||
tracer.info(() => 'retrieved cds.env'); | ||
const message = JSON.stringify(cdsEnv); | ||
tracer.info(() => 'stringified cds.env'); | ||
(_a = process.send) === null || _a === void 0 ? void 0 : _a.call(process, message); | ||
tracer.info(() => 'sent cds.env'); | ||
} | ||
sendToLsp(CdsEnvConverter_1.loadEnv()) | ||
.then(() => process.exit(0)); | ||
.then(() => { | ||
tracer.info(() => 'waiting a little until forcing process to exit'); | ||
setTimeout(() => { | ||
tracer.info(() => 'exiting(0)'); | ||
process.exit(0); | ||
}, 500); | ||
}); | ||
//# sourceMappingURL=callCdsEnv.js.map |
@@ -11,8 +11,8 @@ /// <reference types="@sap__cds-compiler" /> | ||
} | ||
export declare function scanForFiles(rootPath: AbsolutePath, isRelevant: (filepath: AbsolutePath) => boolean, loopDetector: LoopDetector): Promise<AbsolutePath[]>; | ||
export declare function scanForFiles(rootPath: AbsolutePath, isRelevant: (filepath: AbsolutePath) => boolean, loopDetector: LoopDetector): AbsolutePath[]; | ||
export declare class IgnoreManager { | ||
readonly tracer: ITracer; | ||
existsFile(filePath: AbsolutePath): Promise<boolean>; | ||
fetchIgnorePatternsFor(folderPath: AbsolutePath): Promise<string[]>; | ||
fetchIgnoreFilePathFor(folderPath: AbsolutePath): Promise<string>; | ||
existsFile(filePath: AbsolutePath): boolean; | ||
fetchIgnorePatternsFor(folderPath: AbsolutePath): string[]; | ||
fetchIgnoreFilePathFor(folderPath: AbsolutePath): string; | ||
ignorerFor(ignorePatterns: string[]): import("ignore").Ignore; | ||
@@ -19,0 +19,0 @@ } |
@@ -42,2 +42,3 @@ "use strict"; | ||
this.canonicalFoldersVisited.add(canonicalFolder); | ||
this.tracer.debug(() => `Ok, new folder ${absoluteFolder}`); | ||
return false; | ||
@@ -47,12 +48,13 @@ } | ||
exports.LoopDetector = LoopDetector; | ||
async function scanForFiles(rootPath, isRelevant, loopDetector) { | ||
function scanForFiles(rootPath, isRelevant, loopDetector) { | ||
const tracer = trace_1.currentTrace().tracer(trace_1.LspTraceComponent.FILES); | ||
const ignoreManager = new IgnoreManager(); | ||
const handleFolder = async function (dir) { | ||
const handleFolder = function (dir) { | ||
dir = canonicalDriveLetter(dir, rootPath); | ||
return tracer.tryCatch(async () => { | ||
return tracer.tryCatch(() => { | ||
if (loopDetector.alreadyVisited(dir)) | ||
return []; | ||
const filenames = await fs.promises.readdir(dir); | ||
const thisIgnorePatterns = await ignoreManager.fetchIgnorePatternsFor(dir); | ||
const filenames = fs.readdirSync(dir); | ||
tracer.debug(() => `Found ${filenames.length} filenames. Filtering ignored...`); | ||
const thisIgnorePatterns = ignoreManager.fetchIgnorePatternsFor(dir); | ||
thisIgnorePatterns.push(...['.git', 'node_modules']); | ||
@@ -63,2 +65,3 @@ const ignorer = ignoreManager.ignorerFor(thisIgnorePatterns); | ||
const absoluteChildpath = path.join(dir, file); | ||
tracer.debug(() => `Processing ${absoluteChildpath}`); | ||
try { | ||
@@ -69,5 +72,6 @@ if (ignorer.ignores(file)) { | ||
} | ||
const isFolder = (await fs.promises.lstat(absoluteChildpath)).isDirectory(); | ||
const isFolder = (fs.lstatSync(absoluteChildpath)).isDirectory(); | ||
if (isFolder) { | ||
const filesFromSubfolder = await handleFolder(absoluteChildpath); | ||
tracer.debug(() => `Processing subfolder ${absoluteChildpath}`); | ||
const filesFromSubfolder = handleFolder(absoluteChildpath); | ||
files.push(...(filesFromSubfolder.filter(fileFromFolder => { | ||
@@ -83,2 +87,3 @@ const relativePath = fileFromFolder.slice(dir.length + 1); | ||
else if (isRelevant(absoluteChildpath)) { | ||
tracer.debug(() => `Processing file ${absoluteChildpath}`); | ||
files.push(absoluteChildpath); | ||
@@ -92,5 +97,5 @@ } | ||
return files; | ||
}, trace_1.LspTraceLevel.ERROR, 'scanForFiles', Promise.resolve([])); | ||
}, trace_1.LspTraceLevel.ERROR, 'scanForFiles', []); | ||
}; | ||
const sourceFiles = await footprintHack(tracer, 'Scanning workspace for files', handleFolder, [rootPath]); | ||
const sourceFiles = footprintHack(tracer, 'Scanning workspace for files', handleFolder, [rootPath]); | ||
tracer.verbose(() => `${sourceFiles.length} files found`); | ||
@@ -112,14 +117,7 @@ return sourceFiles; | ||
} | ||
async existsFile(filePath) { | ||
try { | ||
if (fs.existsSync(filePath)) { | ||
return (await fs.promises.lstat(filePath)).isFile(); | ||
} | ||
} | ||
catch (e) { | ||
} | ||
return false; | ||
existsFile(filePath) { | ||
return this.tracer.tryCatch(() => fs.existsSync(filePath) && fs.lstatSync(filePath).isFile(), trace_1.LspTraceLevel.ERROR, `existsFile(${filePath})`, false); | ||
} | ||
async fetchIgnorePatternsFor(folderPath) { | ||
const ignoreFile = await this.fetchIgnoreFilePathFor(folderPath); | ||
fetchIgnorePatternsFor(folderPath) { | ||
const ignoreFile = this.fetchIgnoreFilePathFor(folderPath); | ||
if (ignoreFile) { | ||
@@ -134,9 +132,9 @@ return this.tracer.tryCatch(() => { | ||
} | ||
async fetchIgnoreFilePathFor(folderPath) { | ||
fetchIgnoreFilePathFor(folderPath) { | ||
let ignorefile = path.join(folderPath, '.cdsignore'); | ||
if (await this.existsFile(ignorefile)) { | ||
if (this.existsFile(ignorefile)) { | ||
return ignorefile; | ||
} | ||
ignorefile = path.join(folderPath, '.gitignore'); | ||
if (await this.existsFile(ignorefile)) { | ||
if (this.existsFile(ignorefile)) { | ||
return ignorefile; | ||
@@ -143,0 +141,0 @@ } |
@@ -62,2 +62,3 @@ import * as LSP from 'vscode-languageserver-protocol'; | ||
SHOW_COMPILER_ERRORS = "cds.compiler.showInternalErrors", | ||
FETCH_CDSENV = "cds.env.fetch", | ||
DOCS_IN_COMPLETION = "cds.completion.showDocumentation", | ||
@@ -64,0 +65,0 @@ DOCFILES_FOR_COMPLETION = "cds.completion.docFiles", |
@@ -36,2 +36,3 @@ "use strict"; | ||
UserSetting["SHOW_COMPILER_ERRORS"] = "cds.compiler.showInternalErrors"; | ||
UserSetting["FETCH_CDSENV"] = "cds.env.fetch"; | ||
UserSetting["DOCS_IN_COMPLETION"] = "cds.completion.showDocumentation"; | ||
@@ -38,0 +39,0 @@ UserSetting["DOCFILES_FOR_COMPLETION"] = "cds.completion.docFiles"; |
@@ -14,8 +14,8 @@ /// <reference types="@sap__cds-compiler" /> | ||
private readonly adapter; | ||
private readonly fetchCdsEnv; | ||
private readonly cdsEnv; | ||
private readonly tracer; | ||
private readonly pathResolver; | ||
constructor(rootPath: AbsolutePath, loopDetector: LoopDetector, adapter: PathAdapter, fetchCdsEnv: () => Promise<ExtractedCdsEnv>); | ||
scanFiles(workspaceDocuments: WorkspaceDocuments): Promise<AbsolutePath[]>; | ||
fetchDependencies(): Promise<IDependency[]>; | ||
constructor(rootPath: AbsolutePath, loopDetector: LoopDetector, adapter: PathAdapter, cdsEnv: ExtractedCdsEnv); | ||
scanFiles(workspaceDocuments: WorkspaceDocuments): AbsolutePath[]; | ||
readDependencies(): IDependency[]; | ||
} |
@@ -16,3 +16,3 @@ "use strict"; | ||
class NodeModule { | ||
constructor(rootPath, loopDetector, adapter, fetchCdsEnv) { | ||
constructor(rootPath, loopDetector, adapter, cdsEnv) { | ||
Object.defineProperty(this, "rootPath", { | ||
@@ -36,7 +36,7 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(this, "fetchCdsEnv", { | ||
Object.defineProperty(this, "cdsEnv", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: fetchCdsEnv | ||
value: cdsEnv | ||
}); | ||
@@ -56,9 +56,8 @@ Object.defineProperty(this, "tracer", { | ||
} | ||
async scanFiles(workspaceDocuments) { | ||
const cdsEnv = await this.fetchCdsEnv(); | ||
scanFiles(workspaceDocuments) { | ||
return FsUtils_1.scanForFiles(this.rootPath, filepath => FileTypesUtil_1.isCdsFile(filepath, workspaceDocuments[this.adapter.toUri(filepath)]) | ||
|| FileTypesUtil_1.isTranslationFile(cdsEnv, filepath) | ||
|| FileTypesUtil_1.isTranslationFile(this.cdsEnv, filepath) | ||
|| FileTypesUtil_1.isPackageJsonFile(filepath), this.loopDetector); | ||
} | ||
async fetchDependencies() { | ||
readDependencies() { | ||
const pkg = FsUtils_1.readPackageJson(this.rootPath); | ||
@@ -83,4 +82,4 @@ const deps = []; | ||
trace_1.Footprint(trace_1.LspTraceComponent.WORKSPACE) | ||
], NodeModule.prototype, "fetchDependencies", null); | ||
], NodeModule.prototype, "readDependencies", null); | ||
exports.NodeModule = NodeModule; | ||
//# sourceMappingURL=NodeModule.js.map |
@@ -140,3 +140,4 @@ "use strict"; | ||
}; | ||
if (tasksForResource.length === 0) { | ||
const isQueueEmpty = tasksForResource.length === 0; | ||
if (isQueueEmpty) { | ||
return createTask(); | ||
@@ -143,0 +144,0 @@ } |
@@ -20,3 +20,3 @@ "use strict"; | ||
windowsHide: true, | ||
timeout: maxMillis !== null && maxMillis !== void 0 ? maxMillis : 0, | ||
timeout: maxMillis, | ||
encoding: 'utf8' | ||
@@ -42,10 +42,14 @@ }, (error, stdout, stderr) => { | ||
exports.shellExec = shellExec; | ||
async function fork(modulePath, cwd, args = [], maxMillis) { | ||
async function fork(modulePath, cwd = process.cwd(), args = [], maxMillis) { | ||
const tracer = LspCls_1.currentTrace().tracer(TracingInterfaces_1.LspTraceComponent.UTIL); | ||
tracer.info(() => `fork: "${modulePath}" in ${cwd}"`); | ||
return new Promise((resolve, reject) => { | ||
var _a, _b; | ||
const child = child_process.fork(modulePath, args, { | ||
cwd, | ||
stdio: 'ignore' | ||
stdio: ['pipe', 'pipe', 'pipe', 'ipc'] | ||
}); | ||
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on('data', data => tracer.verbose(() => `forked.stdout: ${data.toString('utf-8')}`)); | ||
(_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on('data', data => tracer.verbose(() => `forked.stderr: ${data.toString('utf-8')}`)); | ||
tracer.verbose(() => `connected: ${child.connected}, child.spawnargs:\n\t${child.spawnargs.join('\n\t')}`); | ||
let resultReceived = false; | ||
@@ -63,2 +67,3 @@ const handleSecondaryEvent = (getMessage) => { | ||
resultReceived = true; | ||
handleSecondaryEvent(() => `RESULT: ${message}`); | ||
resolve(message); | ||
@@ -74,3 +79,3 @@ }); | ||
if (maxMillis !== undefined) { | ||
setTimeout(() => reject(new Error(`TIMEOUT(${maxMillis}ms): ${modulePath} in ${cwd}`)), maxMillis); | ||
setTimeout(() => handleSecondaryEvent(() => `TIMEOUT(${maxMillis}ms): ${modulePath} in ${cwd}`), maxMillis); | ||
} | ||
@@ -77,0 +82,0 @@ }); |
{ | ||
"name": "@sap/cds-lsp", | ||
"description": "Language server for CDS", | ||
"version": "5.0.3", | ||
"version": "5.0.5", | ||
"homepage": "https://cap.cloud.sap/", | ||
@@ -6,0 +6,0 @@ "author": "SAP SE (https://www.sap.com)", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1962869
26878