Skip to content

Commit

Permalink
"Components" sidebar section take a while to load redhat-developer#3850
Browse files Browse the repository at this point in the history
Fixes: redhat-developer#3850

Signed-off-by: Victor Rubezhny <[email protected]>
  • Loading branch information
vrubezhny committed Sep 16, 2024
1 parent 7296a84 commit 19071d5
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 42 deletions.
4 changes: 2 additions & 2 deletions src/devfile-registry/devfileRegistryWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as https from 'https';
import * as YAML from 'js-yaml';
import { ExecutionContext } from '../cli';
import { Registry } from '../odo/componentType';
import { Odo } from '../odo/odoWrapper';
import { OdoPreference } from '../odo/odoPreference';
import { DevfileData, DevfileInfo } from './devfileInfo';

export const DEVFILE_VERSION_LATEST: string = 'latest';
Expand Down Expand Up @@ -86,7 +86,7 @@ export class DevfileRegistry {
let registries: Registry[] = [];
const key = ExecutionContext.key('getRegistries');
if (this.executionContext && !this.executionContext.has(key)) {
registries = await Odo.Instance.getRegistries();
registries = await OdoPreference.Instance.getRegistries();
this.executionContext.set(key, registries);
} else {
registries = this.executionContext.get(key);
Expand Down
144 changes: 144 additions & 0 deletions src/odo/odoPreference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*-----------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for license information.
*-----------------------------------------------------------------------------------------------*/

import * as fs from 'fs/promises';
import * as YAML from 'js-yaml';
import * as path from 'path';
import * as vscode from 'vscode';
import { Platform } from '../util/platform';
import { Registry } from './componentType';


type OdoRegistryObject = {
Name: string;
URL: string;
secure: boolean;
};

type OdoSettingsObject = {
RegistryList: OdoRegistryObject[];
ConsentTelemetry;
};

type OdoPreferenceObject = {
kind: string,
apiversion: string,
OdoSettings: OdoSettingsObject;
};

const DefaultOdoPreference: OdoPreferenceObject = {
kind: 'Preference',
apiversion: 'odo.dev/v1alpha1',
OdoSettings: {
RegistryList: [
{
Name: 'DefaultDevfileRegistry',
URL: 'https://registry.devfile.io',
secure: false
} as OdoRegistryObject
],
ConsentTelemetry: false
} as OdoSettingsObject
};

export class OdoPreference {
private static instance: OdoPreference;

public static get Instance(): OdoPreference {
if (!OdoPreference.instance) {
OdoPreference.instance = new OdoPreference();
}
return OdoPreference.instance;
}

private getOdoPreferenceFile(): string {
// This value can be provided to set a seperate directory for users 'homedir' resolution
// note for mocking purpose ONLY
const customHomeDir = Platform.ENV.CUSTOM_HOMEDIR;
const configFileName = 'preference.yaml';

if (customHomeDir && customHomeDir.length > 0) {
return path.join(customHomeDir, '.odo', configFileName);
}

return path.join(Platform.getUserHomePath(), '.odo', configFileName);
}

public async getRegistries(): Promise<Registry[]> {
const odoPreference = await this.readOdoPreference();
return odoPreference.OdoSettings.RegistryList.map((r) => {
return {
name: r.Name,
url: r.URL,
secure: r.secure } as Registry;
});
}

public async addRegistry(name: string, url: string, token: string): Promise<Registry> {
const odoPreference = await this.readOdoPreference();
odoPreference.OdoSettings.RegistryList.push({
Name: name,
URL: url,
secure: !!token
} as never);
await this.writeOdoPreference(odoPreference);
return {
name,
secure: !!token,
url,
};
}

public async removeRegistry(name: string): Promise<void> {
const odoPreference = await this.readOdoPreference();
odoPreference.OdoSettings.RegistryList.splice(
odoPreference.OdoSettings.RegistryList.findIndex((registry) => registry.Name === name), 1
);
await this.writeOdoPreference(odoPreference);
}

private async readOdoPreference(): Promise<OdoPreferenceObject> {
let mergedPreference = DefaultOdoPreference;
const odoPreferenceFilePath = this.getOdoPreferenceFile();
try {
const odoPreferenceFile = await fs.readFile(odoPreferenceFilePath, 'utf8');
const odoPreferences = YAML.load(odoPreferenceFile) as OdoPreferenceObject;
mergedPreference = { ...mergedPreference, ...odoPreferences };
} catch {
// The ODO preferences may not be initialized yet, so we'll try writing down the defaults
try {
await this.writeOdoPreference(mergedPreference);
} catch {
// ignore
}
}
return mergedPreference;
}

private async dirExists(path: string): Promise<boolean> {
try {
if ((await fs.stat(path)).isDirectory()) {
return true;
}
} catch {
// Ignore
}
return false;
}

private async writeOdoPreference(preference: any): Promise<any> {
const odoPreferenceFilePath = this.getOdoPreferenceFile();
try {
const preferenceYaml = YAML.dump(preference);
const odoPreferenceDir = path.parse(odoPreferenceFilePath).dir;
if (!await this.dirExists(odoPreferenceDir)) {
await fs.mkdir(odoPreferenceDir, { recursive: true, mode: 0o750} );
}
await fs.writeFile(this.getOdoPreferenceFile(), preferenceYaml, 'utf8');
} catch {
void vscode.window.showErrorMessage(`An error occured while creating the ODO Preference file at ${odoPreferenceFilePath}!`);
}
}
}
56 changes: 28 additions & 28 deletions src/odo/odoWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ToolsConfig } from '../tools';
import { ChildProcessUtil, CliExitData } from '../util/childProcessUtil';
import { VsCommandError } from '../vscommand';
import { Command } from './command';
import { Registry } from './componentType';
import { ComponentDescription } from './componentTypeDescription';
import { BindableService } from './odoTypes';

Expand Down Expand Up @@ -259,36 +258,37 @@ export class Odo {
// return data;
// }

private async loadRegistryFromPreferences() {
const cliData = await this.execute(new CommandText('odo', 'preference view -o json'));
const prefs = JSON.parse(cliData.stdout) as { registries: Registry[] };
return prefs.registries;
}
// private async loadRegistryFromPreferences() {
// const cliData = await this.execute(new CommandText('odo', 'preference view -o json'));
// const prefs = JSON.parse(cliData.stdout) as { registries: Registry[] };
// return prefs.registries;
// }

public getRegistries(): Promise<Registry[]> {
return this.loadRegistryFromPreferences();
}
// public getRegistries(): Promise<Registry[]> {
// // return this.loadRegistryFromPreferences();
// return OdoPreference.Instance.getOdoRegistries();
// }

public async addRegistry(name: string, url: string, token: string): Promise<Registry> {
const command = new CommandText('odo', `preference add registry ${name} ${url}`);
if (token) {
command.addOption(new CommandOption('--token', token));
}
await this.execute(command);
return {
name,
secure: !!token,
url,
};
}
// public async addRegistry(name: string, url: string, token: string): Promise<Registry> {
// const command = new CommandText('odo', `preference add registry ${name} ${url}`);
// if (token) {
// command.addOption(new CommandOption('--token', token));
// }
// await this.execute(command);
// return {
// name,
// secure: !!token,
// url,
// };
// }

public async removeRegistry(name: string): Promise<void> {
await this.execute(
new CommandText('odo', `preference remove registry ${name}`, [
new CommandOption('--force'),
]),
);
}
// public async removeRegistry(name: string): Promise<void> {
// await this.execute(
// new CommandText('odo', `preference remove registry ${name}`, [
// new CommandOption('--force'),
// ]),
// );
// }

/**
* Deletes all the odo configuration files associated with the component (`.odo`, `devfile.yaml`) located at the given path.
Expand Down
16 changes: 12 additions & 4 deletions src/registriesView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
Registry
} from './odo/componentType';
import { StarterProject } from './odo/componentTypeDescription';
import { OdoPreference } from './odo/odoPreference';
import { Odo } from './odo/odoWrapper';
import { inputValue, quickBtn } from './util/inputValue';
import { Progress } from './util/progress';
Expand Down Expand Up @@ -130,14 +131,21 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {


private async getRegistries(): Promise<Registry[]> {
/* eslint-disable no-console */
console.log('getRegistries: enter');
try {
if (!this.registries) {
console.log('getRegistries: "registries" is not set, reading from prefs...');
this.registries = await DevfileRegistry.Instance.getRegistries();
}
} catch {
} catch(_err) {
console.log(`getRegistries: reading from prefs failed: ${_err}`);

this.registries = [];
}
console.log(`getRegistries: return ${this.registries.length} registries`);
return this.registries;
/* eslint-enable no-console */
}

// public async getCompDescriptions(): Promise<Set<ComponentTypeDescription>> {
Expand Down Expand Up @@ -364,9 +372,9 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {

const devfileInfos = await DevfileRegistry.Instance.getDevfileInfoList(regURL);
if (devfileInfos.length > 0) {
const newRegistry = await Odo.Instance.addRegistry(regName, regURL, token);
const newRegistry = await OdoPreference.Instance.addRegistry(regName, regURL, token);
if (registryContext) {
await Odo.Instance.removeRegistry(registryContext.name);
await OdoPreference.Instance.removeRegistry(registryContext.name);
ComponentTypesView.instance.replaceRegistry(registryContext, newRegistry);
} else {
ComponentTypesView.instance.addRegistry(newRegistry);
Expand All @@ -393,7 +401,7 @@ export class ComponentTypesView implements TreeDataProvider<ComponentType> {
'No',
);
if (yesNo === 'Yes') {
await Odo.Instance.removeRegistry(registry.name);
await OdoPreference.Instance.removeRegistry(registry.name);
ComponentTypesView.instance.removeRegistry(registry);
// ComponentTypesView.instance.refresh();
// if (!isEdit) {
Expand Down
19 changes: 11 additions & 8 deletions test/integration/odoWrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as tmp from 'tmp';
import { promisify } from 'util';
import { Uri, workspace } from 'vscode';
import { Oc } from '../../src/oc/ocWrapper';
import { OdoPreference } from '../../src/odo/odoPreference';
import { Odo } from '../../src/odo/odoWrapper';
import { LoginUtil } from '../../src/util/loginUtil';

Expand Down Expand Up @@ -102,42 +103,43 @@ suite('./odo/odoWrapper.ts', function () {
});
});

// TODO: Move this out of odoWrapper
suite('registries', function () {
const TEST_REGISTRY = 'TestRegistry';

suiteSetup(async function () {
const registries = await Odo.Instance.getRegistries();
const registries = await OdoPreference.Instance.getRegistries();
if (registries.find((registry) => registry.name === TEST_REGISTRY)) {
await Odo.Instance.removeRegistry(TEST_REGISTRY);
await OdoPreference.Instance.removeRegistry(TEST_REGISTRY);
}
});

suiteTeardown(async function () {
try {
await Odo.Instance.removeRegistry(TEST_REGISTRY);
await OdoPreference.Instance.removeRegistry(TEST_REGISTRY);
} catch {
// do nothing, it's probably already deleted
}
});

test('getRegistries()', async function () {
const registries = await Odo.Instance.getRegistries();
const registries = await OdoPreference.Instance.getRegistries();
expect(registries).to.be.of.length(1);
const registryNames = registries.map((registry) => registry.name);
expect(registryNames).to.contain('DefaultDevfileRegistry');
});

test('addRegistry()', async function () {
await Odo.Instance.addRegistry(TEST_REGISTRY, 'https://example.org', undefined);
const registries = await Odo.Instance.getRegistries();
await OdoPreference.Instance.addRegistry(TEST_REGISTRY, 'https://example.org', undefined);
const registries = await OdoPreference.Instance.getRegistries();
expect(registries).to.be.of.length(2);
const registryNames = registries.map((registry) => registry.name);
expect(registryNames).to.contain(TEST_REGISTRY);
});

test('removeRegistry()', async function () {
await Odo.Instance.removeRegistry(TEST_REGISTRY);
const registries = await Odo.Instance.getRegistries();
await OdoPreference.Instance.removeRegistry(TEST_REGISTRY);
const registries = await OdoPreference.Instance.getRegistries();
expect(registries).to.be.of.length(1);
const registryNames = registries.map((registry) => registry.name);
expect(registryNames).to.not.contain(TEST_REGISTRY);
Expand Down Expand Up @@ -189,6 +191,7 @@ suite('./odo/odoWrapper.ts', function () {

suiteSetup(async function() {
tmpFolder = await promisify(tmp.dir)();
await OdoPreference.Instance.getRegistries(); // This creates the ODO preferences, if needed
});

suiteTeardown(async function() {
Expand Down

0 comments on commit 19071d5

Please sign in to comment.