Skip to content

Commit 46fbca6

Browse files
authored
Use a glob pattern to look for conda executables (#1904)
Fixes #256
1 parent fd46c26 commit 46fbca6

File tree

9 files changed

+46
-28
lines changed

9 files changed

+46
-28
lines changed

.appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ init:
7272

7373
install:
7474
- ps: Install-Product node $env:nodejs_version
75-
- npm ci
75+
- npm i
7676
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
7777
- python -m pip install -U pip
7878
- pip install -t ./pythonFiles/experimental/ptvsd git+https://github.com/Microsoft/ptvsd/

news/3 Code Health/256.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use a glob pattern to look for `conda` executables.

package-lock.json

Lines changed: 4 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,7 @@
18911891
"fs-extra": "4.0.3",
18921892
"fuzzy": "0.1.3",
18931893
"get-port": "3.2.0",
1894+
"glob": "^7.1.2",
18941895
"iconv-lite": "0.4.21",
18951896
"inversify": "4.11.1",
18961897
"line-by-line": "0.1.6",

src/client/common/platform/fileSystem.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import { createHash } from 'crypto';
66
import * as fs from 'fs-extra';
7+
import * as glob from 'glob';
78
import { inject, injectable } from 'inversify';
89
import * as path from 'path';
910
import { createDeferred } from '../helpers';
@@ -130,4 +131,14 @@ export class FileSystem implements IFileSystem {
130131
});
131132
});
132133
}
134+
public search(globPattern: string): Promise<string[]> {
135+
return new Promise<string[]>((resolve, reject) => {
136+
glob(globPattern, (ex, files) => {
137+
if (ex) {
138+
return reject(ex);
139+
}
140+
resolve(Array.isArray(files) ? files : []);
141+
});
142+
});
143+
}
133144
}

src/client/common/platform/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,5 @@ export interface IFileSystem {
4747
copyFile(src: string, dest: string): Promise<void>;
4848
deleteFile(filename: string): Promise<void>;
4949
getFileHash(filePath: string): Promise<string | undefined>;
50+
search(globPattern: string): Promise<string[]>;
5051
}

src/client/interpreter/locators/services/condaService.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import { CondaHelper } from './condaHelper';
1111
// tslint:disable-next-line:no-require-imports no-var-requires
1212
const untildify: (value: string) => string = require('untildify');
1313

14-
export const KNOWN_CONDA_LOCATIONS = ['~/anaconda/bin/conda', '~/miniconda/bin/conda',
15-
'~/anaconda2/bin/conda', '~/miniconda2/bin/conda',
16-
'~/anaconda3/bin/conda', '~/miniconda3/bin/conda'];
14+
// This glob pattern will match all of the following:
15+
// ~/anaconda/bin/conda, ~/anaconda3/bin/conda, ~/miniconda/bin/conda, ~/miniconda3/bin/conda
16+
export const CondaLocationsGlob = '~/*conda*/bin/conda';
1717

1818
@injectable()
1919
export class CondaService implements ICondaService {
@@ -181,9 +181,8 @@ export class CondaService implements ICondaService {
181181
return this.getCondaFileFromKnownLocations();
182182
}
183183
private async getCondaFileFromKnownLocations(): Promise<string> {
184-
const condaFiles = await Promise.all(KNOWN_CONDA_LOCATIONS
185-
.map(untildify)
186-
.map(async (condaPath: string) => this.fileSystem.fileExists(condaPath).then(exists => exists ? condaPath : '')));
184+
const condaFiles = await this.fileSystem.search(untildify(CondaLocationsGlob))
185+
.catch<string[]>(() => []);
187186

188187
const validCondaFiles = condaFiles.filter(condaPath => condaPath.length > 0);
189188
return validCondaFiles.length === 0 ? 'conda' : validCondaFiles[0];

src/test/common/platform/filesystem.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,12 @@ suite('FileSystem', () => {
7777
const fileContents = await fileSystem.readFile(fileToAppendTo);
7878
expect(fileContents).to.be.equal(dataToAppend);
7979
});
80+
test('Test searching for files', async () => {
81+
const files = await fileSystem.search(path.join(__dirname, '*.js'));
82+
expect(files).to.be.array();
83+
expect(files.length).to.be.at.least(1);
84+
const expectedFileName = __filename.replace(/\\/g, '/');
85+
const fileName = files[0].replace(/\\/g, '/');
86+
expect(fileName).to.equal(expectedFileName);
87+
});
8088
});

src/test/interpreters/condaService.test.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Architecture, IFileSystem, IPlatformService } from '../../client/common
99
import { IProcessService, IProcessServiceFactory } from '../../client/common/process/types';
1010
import { ILogger, IPersistentStateFactory } from '../../client/common/types';
1111
import { IInterpreterLocatorService, InterpreterType, PythonInterpreter } from '../../client/interpreter/contracts';
12-
import { CondaService, KNOWN_CONDA_LOCATIONS } from '../../client/interpreter/locators/services/condaService';
12+
import { CondaService } from '../../client/interpreter/locators/services/condaService';
1313
import { IServiceContainer } from '../../client/ioc/types';
1414
import { MockState } from './mocks';
1515

@@ -356,21 +356,25 @@ suite('Interpreters Conda Service', () => {
356356
processService.verify(p => p.exec(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
357357
});
358358

359-
KNOWN_CONDA_LOCATIONS.forEach(knownLocation => {
360-
test(`Must return conda path from known location '${knownLocation}' (non windows)`, async () => {
361-
const expectedCondaLocation = untildify(knownLocation);
362-
platformService.setup(p => p.isWindows).returns(() => false);
363-
processService.setup(p => p.exec(TypeMoq.It.isValue('conda'), TypeMoq.It.isValue(['--version']), TypeMoq.It.isAny())).returns(() => Promise.reject(new Error('Not Found')));
364-
fileSystem.setup(fs => fs.fileExists(TypeMoq.It.isAny())).returns((file: string) => Promise.resolve(file === expectedCondaLocation));
359+
['~/anaconda/bin/conda', '~/miniconda/bin/conda', '~/anaconda2/bin/conda',
360+
'~/miniconda2/bin/conda', '~/anaconda3/bin/conda', '~/miniconda3/bin/conda']
361+
.forEach(knownLocation => {
362+
test(`Must return conda path from known location '${knownLocation}' (non windows)`, async () => {
363+
const expectedCondaLocation = untildify(knownLocation);
364+
platformService.setup(p => p.isWindows).returns(() => false);
365+
processService.setup(p => p.exec(TypeMoq.It.isValue('conda'), TypeMoq.It.isValue(['--version']), TypeMoq.It.isAny())).returns(() => Promise.reject(new Error('Not Found')));
366+
fileSystem.setup(fs => fs.search(TypeMoq.It.isAny())).returns(() => Promise.resolve([expectedCondaLocation]));
367+
fileSystem.setup(fs => fs.fileExists(TypeMoq.It.isValue(expectedCondaLocation))).returns(() => Promise.resolve(true));
365368

366-
const condaExe = await condaService.getCondaFile();
367-
assert.equal(condaExe, expectedCondaLocation, 'Failed to identify');
369+
const condaExe = await condaService.getCondaFile();
370+
assert.equal(condaExe, expectedCondaLocation, 'Failed to identify');
371+
});
368372
});
369-
});
370373

371374
test('Must return \'conda\' if conda could not be found in known locations', async () => {
372375
platformService.setup(p => p.isWindows).returns(() => false);
373376
processService.setup(p => p.exec(TypeMoq.It.isValue('conda'), TypeMoq.It.isValue(['--version']), TypeMoq.It.isAny())).returns(() => Promise.reject(new Error('Not Found')));
377+
fileSystem.setup(fs => fs.search(TypeMoq.It.isAny())).returns(() => Promise.resolve([]));
374378
fileSystem.setup(fs => fs.fileExists(TypeMoq.It.isAny())).returns((file: string) => Promise.resolve(false));
375379

376380
const condaExe = await condaService.getCondaFile();

0 commit comments

Comments
 (0)