Skip to content

Commit e73eb91

Browse files
Enhance Rapicgen tool management: add version check, update prompt, and installation logic
1 parent bf8eab4 commit e73eb91

File tree

1 file changed

+136
-8
lines changed

1 file changed

+136
-8
lines changed

src/VSCode/src/extension.ts

Lines changed: 136 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,54 @@ function isDotNetSdkInstalled(): boolean {
3737
}
3838
}
3939

40+
/**
41+
* Gets the installed Rapicgen .NET tool version
42+
* @returns The installed version as a string, or null if not installed or version cannot be determined
43+
*/
44+
function getInstalledRapicgenVersion(): string | null {
45+
try {
46+
// Different command for Windows vs. Unix platforms
47+
const command = platform() === 'win32'
48+
? 'dotnet tool list --global | findstr rapicgen'
49+
: 'dotnet tool list --global | grep rapicgen';
50+
51+
const output = execSync(command, { encoding: 'utf-8' });
52+
53+
// Parse the version from the command output
54+
// The output format is usually: package-id version commands
55+
const match = output.match(/rapicgen\s+(\d+\.\d+\.\d+)/i);
56+
return match && match[1] ? match[1] : null;
57+
} catch (error) {
58+
console.error('Error getting Rapicgen version:', error);
59+
return null;
60+
}
61+
}
62+
63+
/**
64+
* Compares two version strings
65+
* @param version1 First version string
66+
* @param version2 Second version string
67+
* @returns 1 if version1 > version2, -1 if version1 < version2, 0 if equal
68+
*/
69+
function compareVersions(version1: string, version2: string): number {
70+
const parts1 = version1.split('.').map(Number);
71+
const parts2 = version2.split('.').map(Number);
72+
73+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
74+
const p1 = i < parts1.length ? parts1[i] : 0;
75+
const p2 = i < parts2.length ? parts2[i] : 0;
76+
77+
if (p1 > p2) {
78+
return 1;
79+
}
80+
if (p1 < p2) {
81+
return -1;
82+
}
83+
}
84+
85+
return 0;
86+
}
87+
4088
/**
4189
* Checks if the Rapicgen .NET tool is installed globally
4290
* @returns true if the tool is installed, false otherwise
@@ -56,23 +104,71 @@ function isRapicgenInstalled(): boolean {
56104
}
57105

58106
/**
59-
* Installs the Rapicgen .NET tool globally
107+
* Checks if the Rapicgen tool needs to be updated based on extension version
60108
* @param context The extension context
61-
* @returns true if installation was successful
109+
* @returns An object indicating if update is needed and current/target versions
110+
*/
111+
function checkRapicgenVersionStatus(context: vscode.ExtensionContext): {
112+
needsUpdate: boolean;
113+
currentVersion: string | null;
114+
targetVersion: string | null;
115+
} {
116+
const extensionVersion = getExtensionVersion(context);
117+
const installedVersion = getInstalledRapicgenVersion();
118+
119+
// Default result
120+
const result = {
121+
needsUpdate: false,
122+
currentVersion: installedVersion,
123+
targetVersion: extensionVersion || null
124+
};
125+
126+
// If extension is dev version (0.1.0) or we can't get versions, no update needed
127+
if (!extensionVersion || extensionVersion === '0.1.0' || !installedVersion) {
128+
return result;
129+
}
130+
131+
// Compare versions and determine if update is needed
132+
const comparison = compareVersions(installedVersion, extensionVersion);
133+
134+
// Only update if the installed version is older (comparison < 0)
135+
result.needsUpdate = comparison < 0;
136+
137+
return result;
138+
}
139+
140+
/**
141+
* Installs or updates the Rapicgen .NET tool globally
142+
* @param context The extension context
143+
* @returns true if installation/update was successful
62144
*/
63145
async function installRapicgen(context: vscode.ExtensionContext): Promise<boolean> {
64146
try {
147+
const version = getExtensionVersion(context);
148+
const isUpdate = isRapicgenInstalled();
149+
const versionStatus = isUpdate ? checkRapicgenVersionStatus(context) : null;
150+
151+
// If tool is already installed and up-to-date (or newer), no need to update
152+
if (isUpdate && versionStatus && !versionStatus.needsUpdate) {
153+
console.log(`Rapicgen is already installed with version ${versionStatus.currentVersion}, which is greater than or equal to extension version ${versionStatus.targetVersion}. No update needed.`);
154+
return true;
155+
}
156+
157+
// Set the appropriate title for the progress notification
158+
const title = isUpdate && versionStatus?.needsUpdate
159+
? `Updating Rapicgen tool from v${versionStatus.currentVersion} to v${versionStatus.targetVersion}...`
160+
: "Installing Rapicgen tool...";
161+
65162
const installResult = await vscode.window.withProgress({
66163
location: vscode.ProgressLocation.Notification,
67-
title: "Installing Rapicgen tool...",
164+
title: title,
68165
cancellable: false
69166
}, async () => {
70167
try {
71-
// Get the extension version to match the tool version
72-
const version = getExtensionVersion(context);
73-
74168
// Build the installation command
75-
let command = 'dotnet tool install --global rapicgen';
169+
let command = isUpdate && versionStatus?.needsUpdate
170+
? 'dotnet tool update --global rapicgen'
171+
: 'dotnet tool install --global rapicgen';
76172

77173
// Only specify version if we're in a release build (detected by version from package.json)
78174
// Local development builds won't specify a version
@@ -83,7 +179,7 @@ async function installRapicgen(context: vscode.ExtensionContext): Promise<boolea
83179
execSync(command, { encoding: 'utf-8' });
84180
return true;
85181
} catch (error) {
86-
console.error('Failed to install rapicgen tool:', error);
182+
console.error('Failed to install/update rapicgen tool:', error);
87183
return false;
88184
}
89185
});
@@ -215,6 +311,22 @@ async function executeRapicgen(generator: string, specificationFilePath: string,
215311
} else {
216312
return;
217313
}
314+
} else {
315+
// Check if update is needed
316+
const versionStatus = checkRapicgenVersionStatus(context);
317+
if (versionStatus.needsUpdate) {
318+
const shouldUpdate = await vscode.window.showInformationMessage(
319+
`A newer version of the Rapicgen tool is available (current: v${versionStatus.currentVersion}, available: v${versionStatus.targetVersion}). Would you like to update?`,
320+
'Yes', 'No'
321+
);
322+
323+
if (shouldUpdate === 'Yes') {
324+
const updateSuccess = await installRapicgen(context);
325+
if (!updateSuccess) {
326+
vscode.window.showWarningMessage(`Failed to update the Rapicgen tool. Continuing with existing version ${versionStatus.currentVersion}.`);
327+
}
328+
}
329+
}
218330
}
219331

220332
const namespace = getNamespace();
@@ -319,6 +431,22 @@ async function executeRapicgenTypeScript(generator: string, specificationFilePat
319431
} else {
320432
return;
321433
}
434+
} else {
435+
// Check if update is needed
436+
const versionStatus = checkRapicgenVersionStatus(context);
437+
if (versionStatus.needsUpdate) {
438+
const shouldUpdate = await vscode.window.showInformationMessage(
439+
`A newer version of the Rapicgen tool is available (current: v${versionStatus.currentVersion}, available: v${versionStatus.targetVersion}). Would you like to update?`,
440+
'Yes', 'No'
441+
);
442+
443+
if (shouldUpdate === 'Yes') {
444+
const updateSuccess = await installRapicgen(context);
445+
if (!updateSuccess) {
446+
vscode.window.showWarningMessage(`Failed to update the Rapicgen tool. Continuing with existing version ${versionStatus.currentVersion}.`);
447+
}
448+
}
449+
}
322450
}
323451

324452
// For TypeScript, we get an output directory rather than a single file

0 commit comments

Comments
 (0)