in src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts [266:397]
private shouldRunExperiment(experiment: IRawExperiment, processedExperiment: IExperiment): Promise<ExperimentState> {
if (processedExperiment.state !== ExperimentState.Evaluating) {
return Promise.resolve(processedExperiment.state);
}
if (!experiment.enabled) {
return Promise.resolve(ExperimentState.NoRun);
}
const condition = experiment.condition;
if (!condition) {
return Promise.resolve(ExperimentState.Run);
}
if (!this.checkExperimentDependencies(experiment)) {
return Promise.resolve(ExperimentState.NoRun);
}
if (this.environmentService.appQuality === 'stable' && condition.insidersOnly === true) {
return Promise.resolve(ExperimentState.NoRun);
}
const isNewUser = !this.storageService.get(lastSessionDateStorageKey, StorageScope.GLOBAL);
if ((condition.newUser === true && !isNewUser)
|| (condition.newUser === false && isNewUser)) {
return Promise.resolve(ExperimentState.NoRun);
}
if (typeof condition.displayLanguage === 'string') {
let localeToCheck = condition.displayLanguage.toLowerCase();
let displayLanguage = language!.toLowerCase();
if (localeToCheck !== displayLanguage) {
const a = displayLanguage.indexOf('-');
const b = localeToCheck.indexOf('-');
if (a > -1) {
displayLanguage = displayLanguage.substr(0, a);
}
if (b > -1) {
localeToCheck = localeToCheck.substr(0, b);
}
if (displayLanguage !== localeToCheck) {
return Promise.resolve(ExperimentState.NoRun);
}
}
}
if (!condition.userProbability) {
condition.userProbability = 1;
}
let extensionsCheckPromise = Promise.resolve(true);
const installedExtensions = condition.installedExtensions;
if (installedExtensions) {
extensionsCheckPromise = this.extensionManagementService.getInstalled(ExtensionType.User).then(locals => {
let includesCheck = true;
let excludesCheck = true;
const localExtensions = locals.map(local => `${local.manifest.publisher.toLowerCase()}.${local.manifest.name.toLowerCase()}`);
if (Array.isArray(installedExtensions.includes) && installedExtensions.includes.length) {
const extensionIncludes = installedExtensions.includes.map(e => e.toLowerCase());
includesCheck = localExtensions.some(e => extensionIncludes.indexOf(e) > -1);
}
if (Array.isArray(installedExtensions.excludes) && installedExtensions.excludes.length) {
const extensionExcludes = installedExtensions.excludes.map(e => e.toLowerCase());
excludesCheck = !localExtensions.some(e => extensionExcludes.indexOf(e) > -1);
}
return includesCheck && excludesCheck;
});
}
const storageKey = 'experiments.' + experiment.id;
const experimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
return extensionsCheckPromise.then(success => {
const fileEdits = condition.fileEdits;
if (!success || !fileEdits || typeof fileEdits.minEditCount !== 'number') {
const runExperiment = success && typeof condition.userProbability === 'number' && Math.random() < condition.userProbability;
return runExperiment ? ExperimentState.Run : ExperimentState.NoRun;
}
experimentState.editCount = experimentState.editCount || 0;
if (experimentState.editCount >= fileEdits.minEditCount) {
return ExperimentState.Run;
}
const onSaveHandler = this.textFileService.models.onModelsSaved(e => {
const date = new Date().toDateString();
const latestExperimentState: IExperimentStorageState = safeParse(this.storageService.get(storageKey, StorageScope.GLOBAL), {});
if (latestExperimentState.state !== ExperimentState.Evaluating) {
onSaveHandler.dispose();
return;
}
e.forEach(async event => {
if (event.kind !== StateChange.SAVED
|| latestExperimentState.state !== ExperimentState.Evaluating
|| date === latestExperimentState.lastEditedDate
|| (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount)
) {
return;
}
let filePathCheck = true;
let workspaceCheck = true;
if (typeof fileEdits.filePathPattern === 'string') {
filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath);
}
if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) {
const tags = await this.workspaceStatsService.getTags();
workspaceCheck = !!tags && fileEdits.workspaceIncludes.some(x => !!tags[x]);
}
if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) {
const tags = await this.workspaceStatsService.getTags();
workspaceCheck = !!tags && !fileEdits.workspaceExcludes.some(x => !!tags[x]);
}
if (filePathCheck && workspaceCheck) {
latestExperimentState.editCount = (latestExperimentState.editCount || 0) + 1;
latestExperimentState.lastEditedDate = date;
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
}
});
if (typeof latestExperimentState.editCount === 'number' && latestExperimentState.editCount >= fileEdits.minEditCount) {
processedExperiment.state = latestExperimentState.state = (typeof condition.userProbability === 'number' && Math.random() < condition.userProbability && this.checkExperimentDependencies(experiment)) ? ExperimentState.Run : ExperimentState.NoRun;
this.storageService.store(storageKey, JSON.stringify(latestExperimentState), StorageScope.GLOBAL);
if (latestExperimentState.state === ExperimentState.Run && experiment.action && ExperimentActionType[experiment.action.type] === ExperimentActionType.Prompt) {
this.fireRunExperiment(processedExperiment);
}
}
});
this._register(onSaveHandler);
return ExperimentState.Evaluating;
});
}