forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Kartik Raj
committed
Sep 17, 2020
1 parent
37db846
commit 4fd7f38
Showing
2 changed files
with
110 additions
and
90 deletions.
There are no files selected for viewing
110 changes: 110 additions & 0 deletions
110
src/client/pythonEnvironments/collection/environmentsReducer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
import { Event, EventEmitter } from 'vscode'; | ||
import { PythonEnvInfo } from '../base/info'; | ||
import { | ||
ILocator, IPythonEnvsIterator, PythonEnvUpdatedEvent, QueryForEvent, | ||
} from '../base/locator'; | ||
import { PythonEnvsChangedEvent } from '../base/watcher'; | ||
import { mergeEnvironments } from '../info'; | ||
|
||
type PythonEnvsIteratorState = { | ||
/** | ||
* Set to true when all information from incoming iterator has been received | ||
*/ | ||
done: boolean; | ||
/** | ||
* Carries the number of pending background calls ongoing at the moment | ||
*/ | ||
pending: number; | ||
}; | ||
|
||
export class PythonEnvsReducer implements ILocator { | ||
public get onChanged(): Event<PythonEnvsChangedEvent> { | ||
return this.pythonEnvsManager.onChanged; | ||
} | ||
|
||
constructor(private readonly pythonEnvsManager: ILocator) {} | ||
|
||
public resolveEnv(env: string | PythonEnvInfo): Promise<PythonEnvInfo | undefined> { | ||
return this.pythonEnvsManager.resolveEnv(env); | ||
} | ||
|
||
public iterEnvs(query?: QueryForEvent<PythonEnvsChangedEvent>): IPythonEnvsIterator { | ||
const didUpdate = new EventEmitter<PythonEnvUpdatedEvent | null>(); | ||
return { ...this.iterEnvsIterator(didUpdate, query), onUpdated: didUpdate.event }; | ||
} | ||
|
||
private async* iterEnvsIterator( | ||
didUpdate: EventEmitter<PythonEnvUpdatedEvent | null>, | ||
query?: QueryForEvent<PythonEnvsChangedEvent>, | ||
): AsyncIterator<PythonEnvInfo, void> { | ||
const state: PythonEnvsIteratorState = { | ||
done: false, | ||
pending: 0, | ||
}; | ||
const seen: PythonEnvInfo[] = []; | ||
const iterator = this.pythonEnvsManager.iterEnvs(query); | ||
|
||
if (iterator.onUpdated !== undefined) { | ||
iterator.onUpdated((event) => { | ||
if (event === null) { | ||
state.done = true; | ||
checkIfFinishedAndNotify(state, didUpdate); | ||
} else { | ||
const old = seen.find((s) => s.location === event.old.location); | ||
if (old !== undefined) { | ||
state.pending += 1; | ||
resolveDifferencesInBackground(old, event.new, state, didUpdate).ignoreErrors(); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
let result = await iterator.next(); | ||
while (!result.done) { | ||
const currEnv = result.value; | ||
const old = seen.find((s) => s.location === currEnv.location); | ||
if (old !== undefined) { | ||
state.pending += 1; | ||
resolveDifferencesInBackground(old, currEnv, state, didUpdate).ignoreErrors(); | ||
} else { | ||
yield currEnv; | ||
seen.push(currEnv); | ||
} | ||
// eslint-disable-next-line no-await-in-loop | ||
result = await iterator.next(); | ||
} | ||
if (iterator.onUpdated === undefined) { | ||
state.done = true; | ||
} | ||
} | ||
} | ||
|
||
async function resolveDifferencesInBackground( | ||
oldEnv: PythonEnvInfo, | ||
newEnv: PythonEnvInfo, | ||
state: PythonEnvsIteratorState, | ||
didUpdate: EventEmitter<PythonEnvUpdatedEvent | null>, | ||
) { | ||
const merged = mergeEnvironments([oldEnv, newEnv])[0]; | ||
didUpdate.fire({ old: oldEnv, new: merged }); | ||
state.pending -= 1; | ||
checkIfFinishedAndNotify(state, didUpdate); | ||
} | ||
|
||
/** | ||
* When all info from incoming iterator has been received and all background calls finishes, notify that we're done | ||
* @param state Carries the current state of progress | ||
* @param didUpdate Used to notify when finished | ||
*/ | ||
function checkIfFinishedAndNotify( | ||
state: PythonEnvsIteratorState, | ||
didUpdate: EventEmitter<PythonEnvUpdatedEvent | null>, | ||
) { | ||
if (state.done && state.pending === 0) { | ||
didUpdate.fire(null); | ||
didUpdate.dispose(); | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.