Browse Source

Correct the installation and removal of plugins

Upgrading plugins was broken for various reasons. There are four
fixes and a minor one:

1. Use a directory name based only on the `Name` of the plugin, not
   the source filename, which contains the version. Avoids strange
   duplication of the plugin.
2. Use the new directory name for the deletes if it's present, so
   that installation and removal happen at that directory level
   and we don't leave empty folders laying around. Ensures we
   properly remove additional resources in plugins too, not just
   the main `.dll` file.
3. Ignore the incoming `target` when installing, and always set
   it ourself to the proper directory, which would matter when
   reinstalling.
4. Deletes an existing target directory before installing if it
   exists. Note that not calling any of the plugin removal code
   is intentional; I suspect that would delete configurations
   unexpectedly when upgrading which would be annoying. This way,
   it just replaces the files and then reloads.
5. (Minor) Added some actual debug messages around the plugin
   download section so failures can be more accurately seen.
Joshua Boniface 6 years ago
parent
commit
05a4161fd3

+ 1 - 1
Emby.Server.Implementations/ApplicationHost.cs

@@ -1046,7 +1046,7 @@ namespace Emby.Server.Implementations
 
         private async void PluginInstalled(object sender, GenericEventArgs<PackageVersionInfo> args)
         {
-            string dir = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(args.Argument.targetFilename));
+            string dir = Path.Combine(ApplicationPaths.PluginsPath, args.Argument.name);
             var types = Directory.EnumerateFiles(dir, "*.dll", SearchOption.AllDirectories)
                         .Select(x => Assembly.LoadFrom(x))
                         .SelectMany(x => x.ExportedTypes)

+ 35 - 6
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -85,9 +85,11 @@ namespace Emby.Server.Implementations.Updates
         private void OnPluginInstalled(PackageVersionInfo package)
         {
             _logger.LogInformation("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification);
+            _logger.LogDebug("{String}", package.name);
 
             PluginInstalled?.Invoke(this, new GenericEventArgs<PackageVersionInfo> { Argument = package });
 
+            _logger.LogDebug("{String}", package.name);
             _applicationHost.NotifyPendingRestart();
         }
 
@@ -518,12 +520,12 @@ namespace Emby.Server.Implementations.Updates
                 return;
             }
 
-            if (target == null)
-            {
-                target = Path.Combine(_appPaths.PluginsPath, Path.GetFileNameWithoutExtension(package.targetFilename));
-            }
+            // Always override the passed-in target (which is a file) and figure it out again
+            target = Path.Combine(_appPaths.PluginsPath, package.name);
+            _logger.LogDebug("Installing plugin to {Filename}.", target);
 
             // Download to temporary file so that, if interrupted, it won't destroy the existing installation
+            _logger.LogDebug("Downloading ZIP.");
             var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
             {
                 Url = package.sourceUrl,
@@ -536,9 +538,17 @@ namespace Emby.Server.Implementations.Updates
 
             // TODO: Validate with a checksum, *properly*
 
+            // Check if the target directory already exists, and remove it if so
+            if (Directory.Exists(target))
+            {
+                _logger.LogDebug("Deleting existing plugin at {Filename}.", target);
+                Directory.Delete(target, true);
+            }
+
             // Success - move it to the real target
             try
             {
+                _logger.LogDebug("Extracting ZIP {TempFile} to {Filename}.", tempFile, target);
                 using (var stream = File.OpenRead(tempFile))
                 {
                     _zipClient.ExtractAllFromZip(stream, target, true);
@@ -552,6 +562,7 @@ namespace Emby.Server.Implementations.Updates
 
             try
             {
+                _logger.LogDebug("Deleting temporary file {Filename}.", tempFile);
                 _fileSystem.DeleteFile(tempFile);
             }
             catch (IOException ex)
@@ -574,7 +585,18 @@ namespace Emby.Server.Implementations.Updates
             _applicationHost.RemovePlugin(plugin);
 
             var path = plugin.AssemblyFilePath;
-            _logger.LogInformation("Deleting plugin file {0}", path);
+            bool is_path_directory = false;
+            // Check if we have a plugin directory we should remove too
+            if (Path.GetDirectoryName(plugin.AssemblyFilePath) != _appPaths.PluginsPath)
+            {
+                path = Path.GetDirectoryName(plugin.AssemblyFilePath);
+                is_path_directory = true;
+                _logger.LogInformation("Deleting plugin directory {0}", path);
+            }
+            else
+            {
+                _logger.LogInformation("Deleting plugin file {0}", path);
+            }
 
             // Make this case-insensitive to account for possible incorrect assembly naming
             var file = _fileSystem.GetFilePaths(Path.GetDirectoryName(path))
@@ -585,7 +607,14 @@ namespace Emby.Server.Implementations.Updates
                 path = file;
             }
 
-            _fileSystem.DeleteFile(path);
+            if (is_path_directory)
+            {
+                Directory.Delete(path, true);
+            }
+            else
+            {
+                _fileSystem.DeleteFile(path);
+            }
 
             var list = _config.Configuration.UninstalledPlugins.ToList();
             var filename = Path.GetFileName(path);