Skip to content

Commit 8a033b5

Browse files
committed
Enhance sorting of installable files to prioritize shallower paths in getProjectInstallable function
1 parent a040b37 commit 8a033b5

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

src/managers/builtin/pipUtils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,16 @@ export async function getProjectInstallable(
295295
const p = api.getPythonProject(uri)?.uri.fsPath;
296296
return p && fsPaths.includes(p);
297297
})
298-
.sort();
298+
.sort((a, b) => {
299+
// Sort by path depth (shallowest first) so top-level files like
300+
// requirements.txt appear before deeply nested ones.
301+
const depthA = a.fsPath.split(path.sep).length;
302+
const depthB = b.fsPath.split(path.sep).length;
303+
if (depthA !== depthB) {
304+
return depthA - depthB;
305+
}
306+
return a.fsPath.localeCompare(b.fsPath);
307+
});
299308

300309
await Promise.all(
301310
filtered.map(async (uri) => {

src/test/managers/builtin/pipUtils.unit.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,36 @@ suite('Pip Utils - getProjectInstallable', () => {
199199
assert.ok(firstResult.uri, 'Should have a URI');
200200
assert.ok(firstResult.uri.fsPath.startsWith(workspacePath), 'Should be in workspace directory');
201201
});
202+
203+
test('should sort shallower files before deeper ones', async () => {
204+
// Arrange: Return files at different depths, with deeper ones discovered first
205+
findFilesStub.callsFake((pattern: string) => {
206+
const workspacePath = Uri.file('/test/path/root').fsPath;
207+
if (pattern === '**/*requirements*.txt') {
208+
return Promise.resolve([
209+
Uri.file(path.join(workspacePath, 'deep', 'nested', 'sub', 'requirements.txt')),
210+
Uri.file(path.join(workspacePath, 'subdir', 'dev-requirements.txt')),
211+
]);
212+
} else if (pattern === '*requirements*.txt') {
213+
return Promise.resolve([Uri.file(path.join(workspacePath, 'requirements.txt'))]);
214+
} else if (pattern === '**/requirements/*.txt') {
215+
return Promise.resolve([]);
216+
} else if (pattern === '**/pyproject.toml') {
217+
return Promise.resolve([]);
218+
}
219+
return Promise.resolve([]);
220+
});
221+
222+
// Act
223+
const workspacePath = Uri.file('/test/path/root').fsPath;
224+
const projects = [{ name: 'workspace', uri: Uri.file(workspacePath) }];
225+
const result = (await getProjectInstallable(mockApi as PythonEnvironmentApi, projects)).installables;
226+
227+
// Assert: root-level requirements.txt should come first
228+
assert.strictEqual(result.length, 3);
229+
const names = result.map((r) => r.name);
230+
assert.strictEqual(names[0], 'requirements.txt', 'Root-level requirements.txt should be first');
231+
assert.strictEqual(names[1], 'dev-requirements.txt', 'One-level-deep file should be second');
232+
assert.strictEqual(names[2], 'requirements.txt', 'Deeply nested file should be last');
233+
});
202234
});

0 commit comments

Comments
 (0)