uninstallPlugin method
Future<PluginOperationResult>
uninstallPlugin(
- String plugin, [
- PluginScope scope = PluginScope.user,
- bool deleteDataDirFlag = true
Uninstall a plugin.
Removes the plugin from settings and V2 installed data. When the last scope is removed, also cleans up cached versions, options, and the data directory.
Implementation
Future<PluginOperationResult> uninstallPlugin(
String plugin, [
PluginScope scope = PluginScope.user,
bool deleteDataDirFlag = true,
]) async {
assertInstallableScope(scope);
final loadResult = await loadAllPluginsFn();
final allPlugins = [...loadResult.enabled, ...loadResult.disabled];
final foundPlugin = findPluginByIdentifier(plugin, allPlugins);
final settingSource = scopeToSettingSource(scope);
final settings = getSettingsEnabledPlugins(settingSource);
String pluginId;
String pluginName;
if (foundPlugin != null) {
pluginId =
settings?.keys.firstWhere(
(k) =>
k == plugin ||
k == foundPlugin.manifest.name ||
k.startsWith('${foundPlugin.manifest.name}@'),
orElse: () =>
plugin.contains('@') ? plugin : foundPlugin.manifest.name,
) ??
(plugin.contains('@') ? plugin : foundPlugin.manifest.name);
pluginName = foundPlugin.manifest.name;
} else {
return PluginOperationResult(
success: false,
message: 'Plugin "$plugin" not found in installed plugins',
);
}
// Check scope installation.
final projectPath = getProjectPathForScope(scope);
final installedData = loadInstalledPluginsV2();
final installations = installedData[pluginId];
final scopeInstallation = installations?.cast<PluginInstallationRecord?>().firstWhere(
(i) => i!.scope == scope && i.projectPath == projectPath,
orElse: () => null,
);
if (scopeInstallation == null) {
return PluginOperationResult(
success: false,
message:
'Plugin "$plugin" is not installed in ${scope.name} scope. '
'Use --scope to specify the correct scope.',
);
}
// Remove from settings.
final newEnabled = Map<String, bool>.from(settings ?? {});
newEnabled.remove(pluginId);
updateSettings(settingSource, {'enabledPlugins': newEnabled});
clearAllCaches();
// Remove from V2 data.
removePluginInstallation(pluginId, scope, projectPath);
// Cleanup when this was the last scope.
final updatedData = loadInstalledPluginsV2();
final remaining = updatedData[pluginId];
final isLastScope = remaining == null || remaining.isEmpty;
if (isLastScope && scopeInstallation.installPath != null) {
await markVersionOrphaned(scopeInstallation.installPath!);
}
if (isLastScope) {
deletePluginOptions(pluginId);
if (deleteDataDirFlag) {
await deletePluginDataDir(pluginId);
}
}
// Warn about reverse dependents.
final reverseDeps = findReverseDependents(pluginId, allPlugins);
final depWarn =
reverseDeps.isNotEmpty
? '. Warning: the following plugins depend on this: '
'${reverseDeps.join(', ')}'
: '';
return PluginOperationResult(
success: true,
message:
'Successfully uninstalled plugin: $pluginName '
'(scope: ${scope.name})$depWarn',
pluginId: pluginId,
pluginName: pluginName,
scope: scope,
reverseDependents: reverseDeps.isNotEmpty ? reverseDeps : null,
);
}