Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion XrmToolBox.PluginsStore/StoreForm - Copier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -374,11 +374,31 @@ public PluginUpdates PrepareInstallationPackages(List<XtbNuGetPackage> xtbPackag
}
continue;
}
manager.InstallPackage(xtbPackage.Package, true, false);

var packageFolder = Path.Combine(nugetPluginsFolder,
xtbPackage.Package.Id + "." + xtbPackage.Package.Version);

try
{
manager.InstallPackage(xtbPackage.Package, true, false);
}
catch
{
// Clean up partially extracted package folder on failure
if (Directory.Exists(packageFolder))
{
try
{
Directory.Delete(packageFolder, true);
}
catch
{
// Best effort cleanup - ignore errors during cleanup
}
}
throw;
}

foreach (var fi in xtbPackage.Package.GetFiles())
{
var destinationFile = Path.Combine(applicationDataFolder, fi.EffectivePath);
Expand Down Expand Up @@ -425,6 +445,8 @@ public void PerformInstallation(PluginUpdates updates)
}
else
{
var copiedFiles = new List<string>();

foreach (var pu in updates.Plugins)
{
try
Expand All @@ -436,9 +458,26 @@ public void PerformInstallation(PluginUpdates updates)
Directory.CreateDirectory(destinationDirectory);
}
File.Copy(pu.Source, pu.Destination, true);
copiedFiles.Add(pu.Destination);
}
catch (Exception error)
{
// Clean up files that were copied before the failure
foreach (var copiedFile in copiedFiles)
{
try
{
if (File.Exists(copiedFile))
{
File.Delete(copiedFile);
}
}
catch
{
// Best effort cleanup - ignore errors during cleanup
}
}

MessageBox.Show(this,
"An error occured while copying files: " + error.Message +
"\r\n\r\nCopy has been aborted", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
Expand Down
112 changes: 75 additions & 37 deletions XrmToolBox.PluginsStore/StoreFromPortal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ public bool PerformInstallation(PluginUpdates updates, Form form)
return false;
}

var copiedFiles = new List<string>();

foreach (var pu in updates.Plugins)
{
try
Expand All @@ -340,9 +342,26 @@ public bool PerformInstallation(PluginUpdates updates, Form form)
Directory.CreateDirectory(destinationDirectory);
}
File.Copy(pu.Source, pu.Destination, true);
copiedFiles.Add(pu.Destination);
}
catch (Exception error)
{
// Clean up files that were copied before the failure
foreach (var copiedFile in copiedFiles)
{
try
{
if (File.Exists(copiedFile))
{
File.Delete(copiedFile);
}
}
catch
{
// Best effort cleanup - ignore errors during cleanup
}
}

MessageBox.Show("An error occured while copying files: " + error.Message +
"\r\n\r\nCopy has been aborted", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
Expand Down Expand Up @@ -399,58 +418,77 @@ public async Task<PluginUpdates> PrepareInstallationPackages(List<XtbPlugin> plu

var packageFolder = Path.Combine(nugetPluginsFolder, $"{plugin.NugetId}.{version.Version}");

using (PackageArchiveReader packageReader = new PackageArchiveReader(packageStream))
try
{
foreach (var packageFile in await packageReader.GetFilesAsync(cancellationToken))
using (PackageArchiveReader packageReader = new PackageArchiveReader(packageStream))
{
if (packageFile.ToLower().IndexOf("plugins/") >= 0)
foreach (var packageFile in await packageReader.GetFilesAsync(cancellationToken))
{
if (!Directory.Exists(packageFolder))
if (packageFile.ToLower().IndexOf("plugins/") >= 0)
{
Directory.CreateDirectory(packageFolder);
}
if (!Directory.Exists(packageFolder))
{
Directory.CreateDirectory(packageFolder);
}

var relativeFilePath = packageFile.Remove(0, packageFile.ToLower().IndexOf("plugins/") + 8);
var filePath = Path.Combine(packageFolder, relativeFilePath);
var fi = new FileInfo(filePath);
var relativeFilePath = packageFile.Remove(0, packageFile.ToLower().IndexOf("plugins/") + 8);
var filePath = Path.Combine(packageFolder, relativeFilePath);
var fi = new FileInfo(filePath);

if (!Directory.Exists(fi.Directory.FullName))
{
Directory.CreateDirectory(fi.Directory.FullName);
}
if (!Directory.Exists(fi.Directory.FullName))
{
Directory.CreateDirectory(fi.Directory.FullName);
}

using (var fileStream = File.OpenWrite(filePath))
using (var stream = await packageReader.GetStreamAsync(packageFile, cancellationToken))
{
await stream.CopyToAsync(fileStream);
}
using (var fileStream = File.OpenWrite(filePath))
using (var stream = await packageReader.GetStreamAsync(packageFile, cancellationToken))
{
await stream.CopyToAsync(fileStream);
}

var destinationFile = Path.Combine(Paths.PluginsPath, relativeFilePath);
var destinationFile = Path.Combine(Paths.PluginsPath, relativeFilePath);

// XrmToolBox restart is required when a plugin has to be
// updated or when a new plugin shares files with other
// plugin(s) already installed
if (plugin.RequiresXtbRestart)
{
pus.Plugins.Add(new PluginUpdate
// XrmToolBox restart is required when a plugin has to be
// updated or when a new plugin shares files with other
// plugin(s) already installed
if (plugin.RequiresXtbRestart)
{
Source = filePath,
Destination = destinationFile,
RequireRestart = true
});
}
else if (plugin.Action == PackageInstallAction.Install)
{
pus.Plugins.Add(new PluginUpdate
pus.Plugins.Add(new PluginUpdate
{
Source = filePath,
Destination = destinationFile,
RequireRestart = true
});
}
else if (plugin.Action == PackageInstallAction.Install)
{
Source = filePath,
Destination = destinationFile,
RequireRestart = false
});
pus.Plugins.Add(new PluginUpdate
{
Source = filePath,
Destination = destinationFile,
RequireRestart = false
});
}
}
}
}
}
catch
{
// Clean up partially extracted package folder on failure
if (Directory.Exists(packageFolder))
{
try
{
Directory.Delete(packageFolder, true);
}
catch
{
// Best effort cleanup - ignore errors during cleanup
}
}
throw;
}
}
}

Expand Down
111 changes: 65 additions & 46 deletions XrmToolBox.ToolLibrary/ToolLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -226,69 +226,88 @@ public void DownloadPackage(ToolOperationEventArgs e, PluginUpdates pus)
{
Directory.CreateDirectory(cachePackagePath);

Uri pathUri = new Uri(e.Plugin.DownloadUrl);
byte[] packageBytes;
if (pathUri.Scheme == "http" || pathUri.Scheme == "https")
{
packageBytes = HttpClient.GetByteArrayAsync(e.DownloadUrl).GetAwaiter().GetResult();
}
else if (pathUri.Scheme == "file")
{
packageBytes = File.ReadAllBytes(e.DownloadUrl);
}
else
try
{
throw new Exception($"Unsupported file path scheme {pathUri.Scheme}");
}
Uri pathUri = new Uri(e.Plugin.DownloadUrl);
byte[] packageBytes;
if (pathUri.Scheme == "http" || pathUri.Scheme == "https")
{
packageBytes = HttpClient.GetByteArrayAsync(e.DownloadUrl).GetAwaiter().GetResult();
}
else if (pathUri.Scheme == "file")
{
packageBytes = File.ReadAllBytes(e.DownloadUrl);
}
else
{
throw new Exception($"Unsupported file path scheme {pathUri.Scheme}");
}

using (var ms = new MemoryStream())
{
ms.Write(packageBytes, 0, packageBytes.Length);
var package = Package.Open(ms);
using (var ms = new MemoryStream())
{
ms.Write(packageBytes, 0, packageBytes.Length);
var package = Package.Open(ms);

bool found = false;
bool found = false;

foreach (var part in package.GetParts())
{
if (part.Uri.ToString().ToLower().IndexOf("/plugins/") < 0) continue;
foreach (var part in package.GetParts())
{
if (part.Uri.ToString().ToLower().IndexOf("/plugins/") < 0) continue;

found = true;
found = true;

var fileName = part.Uri.ToString().Split(new string[] { "/Plugins/", "/plugins/" }, StringSplitOptions.RemoveEmptyEntries).Last();
fullPath = Path.Combine(cachePackagePath, fileName);
destinationFile = Path.Combine(Paths.PluginsPath, fileName);
var fileName = part.Uri.ToString().Split(new string[] { "/Plugins/", "/plugins/" }, StringSplitOptions.RemoveEmptyEntries).Last();
fullPath = Path.Combine(cachePackagePath, fileName);
destinationFile = Path.Combine(Paths.PluginsPath, fileName);

var directory = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
var directory = Path.GetDirectoryName(fullPath);
if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);

using (var partStream = part.GetStream())
{
using (var fileStream = File.Create(fullPath))
using (var partStream = part.GetStream())
{
partStream.Seek(0, SeekOrigin.Begin);
partStream.CopyTo(fileStream);
using (var fileStream = File.Create(fullPath))
{
partStream.Seek(0, SeekOrigin.Begin);
partStream.CopyTo(fileStream);
}
}

// XrmToolBox restart is required when a plugin has to be
// updated or when a new plugin shares files with other
// plugin(s) already installed
if (e.Plugin.RequiresXtbRestart || e.Plugin.Action == PackageInstallAction.Install)
{
pus.Plugins.Add(new PluginUpdate
{
Name = e.Plugin.Name,
Source = fullPath,
Destination = destinationFile,
RequireRestart = e.Plugin.RequiresXtbRestart
});
}
}

// XrmToolBox restart is required when a plugin has to be
// updated or when a new plugin shares files with other
// plugin(s) already installed
if (e.Plugin.RequiresXtbRestart || e.Plugin.Action == PackageInstallAction.Install)
if (!found)
{
pus.Plugins.Add(new PluginUpdate
{
Name = e.Plugin.Name,
Source = fullPath,
Destination = destinationFile,
RequireRestart = e.Plugin.RequiresXtbRestart
});
throw new Exception("No plugin files found in package");
}
}

if (!found)
}
catch
{
// Clean up partially extracted package folder on failure
if (Directory.Exists(cachePackagePath))
{
throw new Exception("No plugin files found in package");
try
{
Directory.Delete(cachePackagePath, true);
}
catch
{
// Best effort cleanup - ignore errors during cleanup
}
}
throw;
}
}
else
Expand Down