/// <summary> /// Delete the directory /// </summary> /// <param name="path">Path to the directory</param> /// <returns>A task that represents the completion of the operation</returns> protected virtual async Task DeleteDirectoryAsync(string path) { path = GetVirtualPath(path); if (path == GetRootDirectory()) { throw new Exception(GetLanguageResource("E_CannotDeleteRoot")); } path = GetFullPath(path); if (!_fileProvider.DirectoryExists(path)) { throw new Exception(GetLanguageResource("E_DeleteDirInvalidPath")); } if (_fileProvider.GetDirectories(path).Length > 0 || _fileProvider.GetFiles(path).Length > 0) { throw new Exception(GetLanguageResource("E_DeleteNonEmpty")); } try { _fileProvider.DeleteDirectory(path); await HttpContext.Response.WriteAsync(GetSuccessResponse()); } catch { throw new Exception(GetLanguageResource("E_CannotDeleteDir")); } }
/// <summary> /// Initialize /// </summary> /// <param name="applicationPartManager">Application part manager</param> /// <param name="config">Config</param> public static void Initialize(ApplicationPartManager applicationPartManager, GSConfig config) { if (applicationPartManager == null) { throw new ArgumentNullException(nameof(applicationPartManager)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } using (new WriteLockDisposable(Locker)) { // TODO: Add verbose exception handling / raising here since this is happening on app startup and could // prevent app from starting altogether var pluginFolder = _fileProvider.MapPath(GSPluginDefaults.Path); _shadowCopyFolder = _fileProvider.MapPath(GSPluginDefaults.ShadowCopyPath); _reserveShadowCopyFolder = _fileProvider.Combine(_fileProvider.MapPath(GSPluginDefaults.ShadowCopyPath), $"{GSPluginDefaults.ReserveShadowCopyPathName}{DateTime.Now.ToFileTimeUtc()}"); var referencedPlugins = new List <PluginDescriptor>(); var incompatiblePlugins = new List <string>(); try { var installedPluginSystemNames = GetInstalledPluginNames(_fileProvider.MapPath(GSPluginDefaults.InstalledPluginsFilePath)); Debug.WriteLine("Creating shadow copy folder and querying for DLLs"); //ensure folders are created _fileProvider.CreateDirectory(pluginFolder); _fileProvider.CreateDirectory(_shadowCopyFolder); //get list of all files in bin var binFiles = _fileProvider.GetFiles(_shadowCopyFolder, "*", false); if (config.ClearPluginShadowDirectoryOnStartup) { //clear out shadow copied plugins foreach (var f in binFiles) { if (_fileProvider.GetFileName(f).Equals("placeholder.txt", StringComparison.InvariantCultureIgnoreCase)) { continue; } Debug.WriteLine("Deleting " + f); try { //ignore index.htm var fileName = _fileProvider.GetFileName(f); if (fileName.Equals("index.htm", StringComparison.InvariantCultureIgnoreCase)) { continue; } _fileProvider.DeleteFile(f); } catch (Exception exc) { Debug.WriteLine("Error deleting file " + f + ". Exception: " + exc); } } //delete all reserve folders foreach (var directory in _fileProvider.GetDirectories(_shadowCopyFolder, GSPluginDefaults.ReserveShadowCopyPathNamePattern)) { try { _fileProvider.DeleteDirectory(directory); } catch { //do nothing } } } //load description files foreach (var dfd in GetDescriptionFilesAndDescriptors(pluginFolder)) { var descriptionFile = dfd.Key; var pluginDescriptor = dfd.Value; //ensure that version of plugin is valid if (!pluginDescriptor.SupportedVersions.Contains(GSVersion.CurrentVersion, StringComparer.InvariantCultureIgnoreCase)) { incompatiblePlugins.Add(pluginDescriptor.SystemName); continue; } //some validation if (string.IsNullOrWhiteSpace(pluginDescriptor.SystemName)) { throw new Exception($"A plugin '{descriptionFile}' has no system name. Try assigning the plugin a unique name and recompiling."); } if (referencedPlugins.Contains(pluginDescriptor)) { throw new Exception($"A plugin with '{pluginDescriptor.SystemName}' system name is already defined"); } //set 'Installed' property pluginDescriptor.Installed = installedPluginSystemNames .FirstOrDefault(x => x.Equals(pluginDescriptor.SystemName, StringComparison.InvariantCultureIgnoreCase)) != null; try { var directoryName = _fileProvider.GetDirectoryName(descriptionFile); if (string.IsNullOrEmpty(directoryName)) { throw new Exception($"Directory cannot be resolved for '{_fileProvider.GetFileName(descriptionFile)}' description file"); } //get list of all DLLs in plugins (not in bin!) var pluginFiles = _fileProvider.GetFiles(directoryName, "*.dll", false) //just make sure we're not registering shadow copied plugins .Where(x => !binFiles.Select(q => q).Contains(x)) .Where(x => IsPackagePluginFolder(_fileProvider.GetDirectoryName(x))) .ToList(); //other plugin description info var mainPluginFile = pluginFiles .FirstOrDefault(x => _fileProvider.GetFileName(x).Equals(pluginDescriptor.AssemblyFileName, StringComparison.InvariantCultureIgnoreCase)); //plugin have wrong directory if (mainPluginFile == null) { incompatiblePlugins.Add(pluginDescriptor.SystemName); continue; } pluginDescriptor.OriginalAssemblyFile = mainPluginFile; //shadow copy main plugin file pluginDescriptor.ReferencedAssembly = PerformFileDeploy(mainPluginFile, applicationPartManager, config); //load all other referenced assemblies now foreach (var plugin in pluginFiles .Where(x => !_fileProvider.GetFileName(x).Equals(_fileProvider.GetFileName(mainPluginFile), StringComparison.InvariantCultureIgnoreCase)) .Where(x => !IsAlreadyLoaded(x))) { PerformFileDeploy(plugin, applicationPartManager, config); } //init plugin type (only one plugin per assembly is allowed) foreach (var t in pluginDescriptor.ReferencedAssembly.GetTypes()) { if (typeof(IPlugin).IsAssignableFrom(t)) { if (!t.IsInterface) { if (t.IsClass && !t.IsAbstract) { pluginDescriptor.PluginType = t; break; } } } } referencedPlugins.Add(pluginDescriptor); } catch (ReflectionTypeLoadException ex) { //add a plugin name. this way we can easily identify a problematic plugin var msg = $"Plugin '{pluginDescriptor.FriendlyName}'. "; foreach (var e in ex.LoaderExceptions) { msg += e.Message + Environment.NewLine; } var fail = new Exception(msg, ex); throw fail; } catch (Exception ex) { //add a plugin name. this way we can easily identify a problematic plugin var msg = $"Plugin '{pluginDescriptor.FriendlyName}'. {ex.Message}"; var fail = new Exception(msg, ex); throw fail; } } } catch (Exception ex) { var msg = string.Empty; for (var e = ex; e != null; e = e.InnerException) { msg += e.Message + Environment.NewLine; } var fail = new Exception(msg, ex); throw fail; } ReferencedPlugins = referencedPlugins; IncompatiblePlugins = incompatiblePlugins; } }