async _getDBFlagsAndDirForSrc( src: string, compilationDBFile: ?NuclideUri, ): Promise<{ dbFlags: ?Map<string, ClangFlags>, dbDir: ?string, }> { let dbFlags = null; let dbDir = null; if (compilationDBFile != null) { // Look for a compilation database provided by the client. dbFlags = await this._loadFlagsFromCompilationDatabase(compilationDBFile); dbDir = nuclideUri.dirname(compilationDBFile); } else { // Look for a manually provided compilation database. dbDir = await fsPromise.findNearestFile( COMPILATION_DATABASE_FILE, nuclideUri.dirname(src), ); if (dbDir != null) { const dbFile = nuclideUri.join(dbDir, COMPILATION_DATABASE_FILE); dbFlags = await this._loadFlagsFromCompilationDatabase(dbFile); } } return {dbFlags, dbDir}; }
async function handleNodeModule( root: NuclideUri, packageJsonFile: string, exportCache: ExportCache, ): Promise<?ExportUpdateForFile> { const file = nuclideUri.join(root, packageJsonFile); try { const fileContents = await fsPromise.readFile(file, 'utf8'); const packageJson = JSON.parse(fileContents); const entryPoint = require.resolve( nuclideUri.join(nuclideUri.dirname(file), packageJson.main || ''), ); const entryContents = await fsPromise.readFile(entryPoint, 'utf8'); const sha1 = crypto .createHash('sha1') .update(entryContents) .digest('hex'); const cachedUpdate = exportCache.get({filePath: entryPoint, sha1}); if (cachedUpdate != null) { return { updateType: 'setExports', file: entryPoint, sha1, exports: cachedUpdate, }; } // TODO(hansonw): How do we handle haste modules inside Node modules? // For now we'll just treat them as usual. const update = await getExportsForFile( entryPoint, { isHaste: false, useNameReducers: false, nameReducers: [], nameReducerBlacklist: [], nameReducerWhitelist: [], }, entryContents, ); return update ? decorateExportUpdateWithMainDirectory( update, nuclideUri.join(root, nuclideUri.dirname(packageJsonFile)), ) : update; } catch (error) { // Some modules just can't be required; that's perfectly normal. if (error.code !== 'MODULE_NOT_FOUND') { logger.warn(`Couldn't index ${file}`, error); } return null; } }
async function canFindFlow(flowPath: string): Promise<boolean> { if (process.platform === 'win32') { // On Windows, if the flow path is configured as a full path rather than just "flow" or // "flow.exe", format the path correctly to pass to `where <flow>` const dirPath = nuclideUri.dirname(flowPath); if (dirPath != null && dirPath !== '' && dirPath !== '.') { const whichPath = `${nuclideUri.dirname(flowPath)}:${nuclideUri.basename(flowPath)}`; return (await which(whichPath)) != null; } } return (await which(flowPath)) != null; }
async _launchTargetInTerminal(requestMessage: launchRequest): Promise<void> { const launchConfig: HHVMLaunchConfig = requestMessage.arguments; // This is a launch in terminal request. Perform the launch and then // return an attach configuration. const startupArgs = await getLaunchArgs(launchConfig); // Terminal args require everything to be a string, but debug port // is typed as a number. const terminalArgs = [startupArgs.hhvmPath]; for (const arg of startupArgs.hhvmArgs) { terminalArgs.push(String(arg)); } const runInTerminalArgs: DebugProtocol.RunInTerminalRequestArguments = { kind: 'integrated', cwd: nuclideUri.dirname(launchConfig.targetUri), args: terminalArgs, }; this._writeOutputWithHeader({ seq: ++this._sequenceNumber, type: 'request', command: 'runInTerminal', arguments: runInTerminalArgs, }); this._runInTerminalRequest = new Deferred(); await this._runInTerminalRequest.promise; const attachConfig: HHVMAttachConfig = { targetUri: launchConfig.targetUri, action: 'attach', debugPort: startupArgs.debugPort, }; await this._attachTarget({...requestMessage, arguments: attachConfig}); }
async function runLinterCommand(src: NuclideUri): Promise<string> { const dirName = nuclideUri.dirname(src); let result; let runFlake8; try { // $FlowFB runFlake8 = require('./fb/run-flake8').default; } catch (e) { // Ignore. } if (runFlake8 != null) { result = await runFlake8(src); if (result != null) { return result; } } const command = (global.atom && atom.config.get('nuclide.nuclide-python.pathToFlake8')) || 'flake8'; invariant(typeof command === 'string'); return runCommand(command, [src], { cwd: dirName, // 1 indicates unclean lint result (i.e. has errors/warnings). isExitError: exit => exit.exitCode == null || exit.exitCode > 1, }).toPromise(); }
function getTopLevelModulePath(src: string): Promise<?string> { return fsPromise.findFurthestFile( '__init__.py', nuclideUri.dirname(src), true /* stopOnMissing */, ); }
function processGrepResult( result: string, headerFile: string, includeRegex: RegExp, ): ?string { const splitIndex = result.indexOf('\0'); if (splitIndex === -1) { return null; } const filename = result.substr(0, splitIndex); if (!isSourceFile(filename)) { return null; } const match = includeRegex.exec(result.substr(splitIndex + 1)); if (match == null) { return null; } // Source-relative includes have to be verified. // Relative paths will match the (../)* rule (at index 2). if (match[2] != null) { const includePath = nuclideUri.normalize( nuclideUri.join(nuclideUri.dirname(filename), match[1]), ); if (includePath !== headerFile) { return null; } } return filename; }
beforeEach(() => { const PROCESS_PATH = nuclideUri.join( __dirname, 'fixtures/dummy-service/dummyioserver.py', ); const OPTS = { cwd: nuclideUri.dirname(PROCESS_PATH), stdio: 'pipe', detached: false, }; const serviceRegistry = new ServiceRegistry( [], [ { name: 'dummy', definition: nuclideUri.join( __dirname, 'fixtures/dummy-service/DummyService.js', ), implementation: nuclideUri.join( __dirname, 'fixtures/dummy-service/DummyService.js', ), preserveFunctionNames: true, }, ], ); const processStream = spawn('python', [PROCESS_PATH], OPTS) // For the sake of our tests, simulate creating the process asynchronously. .subscribeOn(Scheduler.async); server = new RpcProcess('Dummy IO Server', serviceRegistry, processStream); });
/** * Simultaneously looks at directories between `startDir` and `stopDir` (or root dir), * passing them to the provided `matcher` function and returning the string returned * by the logically first (nearest) matcher, or `null` if no matchers matched. * @param matcher: a function that returns the matched path if a match is found; otherwise null * @param startDir: Where to begin the search * @param stopDir: Where to stop the search (e.g., repository root), or null for filesystem root * @return the nearest matched path to startDir if a match is found; otherwise null */ async function findNearest( matcher: (candidate: string) => Promise<?string>, startDir: string, stopDir: ?string, ): Promise<?string> { const candidates = []; let candidateDir = startDir; while (candidateDir !== stopDir) { candidates.push(candidateDir); const parentDir = nuclideUri.dirname(candidateDir); if (parentDir === candidateDir) { // filesystem root reached break; } else { candidateDir = parentDir; } } const results = await Promise.all(candidates.map(matcher)); for (const result of results) { if (result != null) { return result; } } return null; }
async _getModifiedFlags( src: string, originalFlags: Array<string>, ): Promise<Array<string>> { // Look for the project-wide flags const projectFlagsDir = await fsPromise.findNearestFile( PROJECT_CLANG_FLAGS_FILE, nuclideUri.dirname(src), ); if (projectFlagsDir == null) { return originalFlags; } const projectFlagsFile = nuclideUri.join( projectFlagsDir, PROJECT_CLANG_FLAGS_FILE, ); const projectFlags = await this._loadProjectCompilerFlags(projectFlagsFile); if (projectFlags == null) { return originalFlags; } return originalFlags .filter(flag => projectFlags.ignoredCompilerFlags.indexOf(flag) === -1) .concat(projectFlags.extraCompilerFlags); }
static async _findSourceFileForHeader( header: string, projectRoot: string, ): Promise<?string> { // Basic implementation: look at files in the same directory for paths // with matching file names. const dir = nuclideUri.dirname(header); const files = await fsPromise.readdir(dir); const basename = ClangFlagsManager._getFileBasename(header); for (const file of files) { if ( isSourceFile(file) && ClangFlagsManager._getFileBasename(file) === basename ) { return nuclideUri.join(dir, file); } } // Try searching all subdirectories for source files that include this header. // Give up after INCLUDE_SEARCH_TIMEOUT. return findIncludingSourceFile(header, projectRoot) .timeout(INCLUDE_SEARCH_TIMEOUT) .catch(() => Observable.of(null)) .toPromise(); }
const getPackageJson = memoize(async (dir: NuclideUri) => { // Bail out at the FS root. const parent = nuclideUri.dirname(dir); if (parent === dir) { return null; } const packageJson = nuclideUri.join(dir, 'package.json'); let fileContents; try { fileContents = await fsPromise.readFile(packageJson, 'utf8'); } catch (err) { return getPackageJson(parent); } try { return { dirname: dir, main: nuclideUri.resolve( dir, JSON.parse(fileContents).main || 'index.js', ), }; } catch (err) { return null; } });
/** * Returns the directory of the nearest package.json if `file` matches the "main" field. * This ensures that e.g. package/index.js can be imported as just "package". */ async function checkIfMain(file: NuclideUri): Promise<?NuclideUri> { const pkgJson = await getPackageJson(nuclideUri.dirname(file)); return pkgJson != null && nuclideUri.stripExtension(pkgJson.main) === nuclideUri.stripExtension(file) ? pkgJson.dirname : null; }
/** * This function returns HgRepositoryDescription filled with a repoPath and * originURL iff it finds that the given directory is within an Hg repository. */ export default function findHgRepository( startDirectoryPath: string, ): ?HgRepositoryDescription { if (!nuclideUri.isLocal(startDirectoryPath)) { return null; } let workingDirectoryPath = startDirectoryPath; for (;;) { const repoPath = nuclideUri.join(workingDirectoryPath, '.hg'); if (tryIsDirectorySync(repoPath)) { let originURL = null; // Note that .hg/hgrc will not exist in a local repo created via `hg init`, for example. const hgrc = tryReadFileSync(nuclideUri.join(repoPath, 'hgrc')); if (hgrc != null) { const config = ini.parse(hgrc); if ( typeof config.paths === 'object' && typeof config.paths.default === 'string' ) { originURL = config.paths.default; } } return {repoPath, originURL, workingDirectoryPath}; } const parentDir = nuclideUri.dirname(workingDirectoryPath); if (parentDir === workingDirectoryPath) { return null; } else { workingDirectoryPath = parentDir; } } }
getParent(): RemoteDirectory { const directoryPath = nuclideUri.dirname(this._path); const remoteConnection = this._server.getRemoteConnectionForUri(this._path); const hgRepositoryDescription = remoteConnection != null ? remoteConnection.getHgRepositoryDescription() : null; return this._server.createDirectory(directoryPath, hgRepositoryDescription); }
export async function findNearestCompilationDbDir( source: NuclideUri, ): Promise<?NuclideUri> { return fs.findNearestFile( COMPILATION_DATABASE_FILE, nuclideUri.dirname(source), ); }
].reduce((acc, servicePath) => { if (fs.existsSync(servicePath)) { const basedir = nuclideUri.dirname(servicePath); const src = fs.readFileSync(servicePath, 'utf8'); const jsonConfig: Array<Object> = JSON.parse(src); acc.push(...createServiceConfigObject(basedir, jsonConfig)); } return acc; }, []);
const selectedPaths = nodes.map(node => { const nodePath = FileTreeHelpers.keyToPath(node.uri); const parentOfRoot = nuclideUri.dirname(node.rootUri); // Fix Windows paths to avoid end of filename truncation return isRunningInWindows() ? nuclideUri.relative(parentOfRoot, nodePath).replace(/\//g, '\\') : nuclideUri.relative(parentOfRoot, nodePath); });
findTags( query: string, options?: { caseInsensitive?: boolean, partialMatch?: boolean, limit?: number, }, ): Promise<Array<CtagsResult>> { let ctags; try { ctags = require('nuclide-prebuilt-libs/ctags'); } catch (e) { getLogger('nuclide-ctags-rpc').error( 'Could not load the ctags package:', e, ); return Promise.resolve([]); } const dir = nuclideUri.dirname(this._tagsPath); return new Promise((resolve, reject) => { ctags.findTags( this._tagsPath, query, options, async (error, tags: Array<Object>) => { if (error != null) { reject(error); } else { const processed = await Promise.all( tags.map(async tag => { // Convert relative paths to absolute ones. tag.file = nuclideUri.join(dir, tag.file); // Tag files are often not perfectly in sync - filter out missing files. if (await fsPromise.exists(tag.file)) { if (tag.fields != null) { const map = new Map(); for (const key in tag.fields) { map.set(key, tag.fields[key]); } tag.fields = map; } return tag; } return null; }), ); // $FlowFixMe(>=0.55.0) Flow suppress resolve(arrayCompact(processed)); } }, ); }); }
getParent(): RemoteDirectory { if (this.isRoot()) { return this; } else { const uri = nuclideUri.createRemoteUri( this._host, nuclideUri.dirname(this._localPath), ); return this._server.createDirectory(uri, this._hgRepositoryDescription); } }
function flowConfigToResolveDirnames( flowFile: string, flowFileContents: string, ): Array<string> { const resolveDirs = flowFileContents.match( /module.system.node.resolve_dirname=([^\s]+)/g, ); return resolveDirs ? resolveDirs.map(dirString => nuclideUri.join(nuclideUri.dirname(flowFile), dirString.split('=')[1]), ) : [nuclideUri.join(nuclideUri.dirname(flowFile), 'node_modules')]; }
async _getDependencies( src: string, basePath: string, kind: string, ): Promise<Array<string>> { // Since we're doing string-based comparisons, resolve paths to their // real (symlinks followed) paths. const realBasePath = await fsPromise.realpath(basePath); const realSrcPath = await fsPromise.realpath(src); let currPath = nuclideUri.dirname(realSrcPath); while (nuclideUri.contains(realBasePath, currPath)) { const relativePath = nuclideUri.relative(realBasePath, currPath); if (relativePath === '.' || relativePath === '') { break; } const searchRoot = this._getBuckTargetForDir(relativePath); try { // Not using Promise.all since we want to break as soon as one query returns // a non-empty result, and we don't want concurrent buck queries. // eslint-disable-next-line no-await-in-loop const results = await BuckService.query( basePath, `kind(${kind}, rdeps(${searchRoot}, owner(${src})))`, ); if (results.length > 0) { return results; } } catch (e) { // Ignore - most likely because the currPath doesn't contain a // BUCK/TARGETS file. } currPath = nuclideUri.dirname(currPath); } return []; }
_visitImport(serviceParser: ServiceParser, imp: Import): void { let resolved = resolveFrom(nuclideUri.dirname(this._fileName), imp.file); // Prioritize .flow files. if (fs.existsSync(resolved + '.flow')) { resolved += '.flow'; } const importedFile = getFileParser(resolved); const exportNode = importedFile.getExports().get(imp.imported); invariant( exportNode != null, `Could not find export for ${imp.imported} in ${resolved}`, ); importedFile.parseExport(serviceParser, exportNode); }
export async function findNearestBuildFile( textEditorPath: NuclideUri, ): Promise<?NuclideUri> { const buckRoot = await getBuckProjectRoot(textEditorPath); if (buckRoot != null) { const buildFileName = await getBuildFileName(buckRoot); const fsService = getFileSystemServiceByNuclideUri(textEditorPath); return fsService.findNearestAncestorNamed( buildFileName, nuclideUri.dirname(textEditorPath), ); } return null; }
async _loadFlagsFromCompilationDatabase( dbFile: string, ): Promise<Map<string, ClangFlags>> { const cache = this._compilationDatabases.get(dbFile); if (cache != null) { return cache; } const flags = new Map(); try { const contents = await fsPromise.readFile(dbFile, 'utf8'); const data = JSON.parse(contents); invariant(data instanceof Array); const dbDir = nuclideUri.dirname(dbFile); await Promise.all( data.map(async entry => { const {command, file} = entry; const directory = await fsPromise.realpath( // Relative directories aren't part of the spec, but resolving them // relative to the compile_commands.json location seems reasonable. nuclideUri.resolve(dbDir, entry.directory), this._realpathCache, ); const filename = nuclideUri.resolve(directory, file); if (await fsPromise.exists(filename)) { const realpath = await fsPromise.realpath( filename, this._realpathCache, ); const result = { rawData: { flags: command, file, directory, }, flagsFile: dbFile, }; flags.set(realpath, result); this._pathToFlags.set(realpath, Promise.resolve(result)); } }), ); this._compilationDatabases.set(dbFile, flags); } catch (e) { logger.error(`Error reading compilation flags from ${dbFile}`, e); } return flags; }
beforeEach(() => { jasmine.useRealClock(); // Simulated scribe_cat script which saves data into: // ${process.env['SCRIBE_MOCK_PATH'] + category_name} // It terminates once we cut off the stdin stream. const scribeCatMockCommandPath = nuclideUri.join( nuclideUri.dirname(__filename), 'scripts', 'scribe_cat_mock', ); waitsForPromise(async () => { tempDir = await fsPromise.tempdir(); originalCommand = __test__.setScribeCatCommand(scribeCatMockCommandPath); process.env.SCRIBE_MOCK_PATH = tempDir; }); });
export async function guessBuildFile(file: string): Promise<?string> { const dir = nuclideUri.dirname(file); let bestMatch = null; await Promise.all( [...BUCK_BUILD_FILES, 'compile_commands.json'].map(async name => { const nearestDir = await fsPromise.findNearestFile(name, dir); if (nearestDir != null) { const match = nuclideUri.join(nearestDir, name); // Return the closest (most specific) match. if (bestMatch == null || match.length > bestMatch.length) { bestMatch = match; } } }), ); return bestMatch; }
entries.forEach(entry => { const entryPath = nuclideUri.join(subscription.path, entry.name); const observer = entityObserver.get(entryPath); if (observer != null) { // TODO(most): handle `rename`, if needed. if (!entry.exists) { observer.next('delete'); } else { observer.next('change'); } } // A file watch event can also be considered a directory change // for the parent directory if a file was created or deleted. if (entry.new || !entry.exists) { directoryChanges.add(nuclideUri.dirname(entryPath)); } });
(transientSettings, savedSettings) => { const {config} = props; const { cwdPropertyName, scriptPropertyName, launch, scriptExtension, } = config; const atomInputValues = new Map(savedSettings.atomInputValues || []); const scriptPath = (scriptPropertyName != null && atomInputValues.get(scriptPropertyName)) || (scriptExtension != null && getActiveScriptPath(scriptExtension)) || ''; if (cwdPropertyName != null) { const cwd = atomInputValues.get(cwdPropertyName) || (scriptPath !== '' ? nuclideUri.dirname(scriptPath) : ''); if (cwd !== '') { atomInputValues.set(cwdPropertyName, cwd); } } if (launch) { if (scriptPath !== '' && scriptPropertyName != null) { atomInputValues.set(scriptPropertyName, scriptPath); } } const booleanValues = new Map(savedSettings.booleanValues || []); const enumValues = new Map(savedSettings.enumValues || []); this._populateDefaultValues( config, atomInputValues, booleanValues, enumValues, ); // do not serialize and deserialize processes const processTableValues = new Map(); this.setState({ atomInputValues, booleanValues, enumValues, processTableValues, }); },
.map(workspace => { // Yarn workspaces can be a glob pattern (folder/*) or specific paths. // Either way, getting the dirname should work for most cases. if (typeof workspace === 'string') { try { return nuclideUri.resolve( root, nuclideUri.dirname(workspace), ); } catch (err) { getLogger('js-imports-server').error( `Could not parse Yarn workspace: ${workspace}`, err, ); return null; } } })