diff --git a/Oqtane.Server/Infrastructure/InstallationManager.cs b/Oqtane.Server/Infrastructure/InstallationManager.cs index d6b99661..eba54a2b 100644 --- a/Oqtane.Server/Infrastructure/InstallationManager.cs +++ b/Oqtane.Server/Infrastructure/InstallationManager.cs @@ -116,14 +116,23 @@ namespace Oqtane.Infrastructure string folder = Path.Combine(environment.WebRootPath, "Framework"); if (Directory.Exists(folder)) { - string upgradepackage = ""; - - // iterate through packages - foreach (string packagename in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg")) + // get package with highest version and clean up any others + string packagename = ""; + foreach(string package in Directory.GetFiles(folder, "Oqtane.Framework.*.nupkg")) { + if (packagename != "") + { + File.Delete(packagename); + } + packagename = package; + } + + if (packagename != "") + { + // verify package version + string packageversion = ""; using (ZipArchive archive = ZipFile.OpenRead(packagename)) { - string frameworkversion = ""; // locate nuspec foreach (ZipArchiveEntry entry in archive.Entries) { @@ -138,54 +147,29 @@ namespace Oqtane.Infrastructure XmlNode node = doc.SelectSingleNode("/package/metadata/version"); if (node != null) { - frameworkversion = node.InnerText; + packageversion = node.InnerText; } reader.Close(); } } - - // ensure package version is higher than current framework - if (frameworkversion != "" && Version.Parse(Constants.Version).CompareTo(Version.Parse(frameworkversion)) < 0) - { - upgradepackage = packagename; - } - else - { - File.Delete(packagename); - } } - } - if (upgradepackage != "") - { - FinishUpgrade(upgradepackage); + // ensure package version is higher than current framework version + if (packageversion != "" && Version.Parse(Constants.Version).CompareTo(Version.Parse(packageversion)) < 0) + { + FinishUpgrade(); + } } } } - private void FinishUpgrade(string packagename) + private void FinishUpgrade() { string folder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); // check if upgrade application exists if (File.Exists(Path.Combine(folder, "Oqtane.Upgrade.exe"))) { - // unzip package - using (ZipArchive archive = ZipFile.OpenRead(packagename)) - { - foreach (ZipArchiveEntry entry in archive.Entries) - { - string filename = Path.GetFileName(entry.FullName); - if (Path.GetExtension(filename) == ".dll") - { - entry.ExtractToFile(Path.Combine(Path.Combine(environment.WebRootPath, "Framework"), filename), true); - } - } - } - - // delete package - File.Delete(packagename); - // run upgrade application var process = new Process(); process.StartInfo.FileName = Path.Combine(folder, "Oqtane.Upgrade.exe"); diff --git a/Oqtane.Upgrade/Program.cs b/Oqtane.Upgrade/Program.cs index f9ec133c..70ede475 100644 --- a/Oqtane.Upgrade/Program.cs +++ b/Oqtane.Upgrade/Program.cs @@ -1,4 +1,6 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; using System.Reflection; using System.Threading; @@ -9,89 +11,131 @@ namespace Oqtane.Upgrade static void Main(string[] args) { string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); + // assumes that the application executable must be deployed to the /bin of the Oqtane.Server project if (binfolder.Contains("Oqtane.Server\\bin")) { - // ie. Oqtane.Server\bin\Debug\netcoreapp3.0\Oqtane.Upgrade.exe + // ie. binfolder = Oqtane.Server\bin\Debug\netcoreapp3.0\ string rootfolder = Directory.GetParent(binfolder).Parent.Parent.FullName; string deployfolder = Path.Combine(rootfolder, "wwwroot\\Framework"); - // take the app offline - if (File.Exists(Path.Combine(rootfolder, "app_offline.bak"))) - { - File.Move(Path.Combine(rootfolder, "app_offline.bak"), Path.Combine(rootfolder, "app_offline.htm")); - } - if (Directory.Exists(deployfolder)) { - string filename; - string[] files = Directory.GetFiles(deployfolder); - if (CanAccessFiles(files, binfolder)) + string packagename = ""; + string[] packages = Directory.GetFiles(deployfolder, "Oqtane.Framework.*.nupkg"); + if (packages.Length > 0) { - // backup the files - foreach (string file in files) + packagename = packages[packages.Length - 1]; // use highest version + } + + if (packagename != "") + { + // take the app offline + if (File.Exists(Path.Combine(rootfolder, "app_offline.bak"))) { - filename = Path.Combine(binfolder, Path.GetFileName(file)); - if (File.Exists(filename)) + File.Move(Path.Combine(rootfolder, "app_offline.bak"), Path.Combine(rootfolder, "app_offline.htm")); + } + + // get list of files in package + List files = new List(); + using (ZipArchive archive = ZipFile.OpenRead(packagename)) + { + foreach (ZipArchiveEntry entry in archive.Entries) { + if (Path.GetExtension(entry.FullName) == ".dll") + { + files.Add(Path.GetFileName(entry.FullName)); + } + } + } + + // ensure files are not locked + string filename; + if (CanAccessFiles(files, binfolder)) + { + // create backup + foreach (string file in files) + { + filename = Path.Combine(binfolder, Path.GetFileName(file)); + if (File.Exists(filename.Replace(".dll", ".bak"))) + { + File.Delete(filename.Replace(".dll", ".bak")); + } File.Move(filename, filename.Replace(".dll", ".bak")); } - } - // copy the new files - bool success = true; - try - { - foreach (string file in files) + // extract files + bool success = true; + try { - filename = Path.Combine(binfolder, Path.GetFileName(file)); - // delete the file from the /bin if it exists - if (File.Exists(filename)) + using (ZipArchive archive = ZipFile.OpenRead(packagename)) { - File.Delete(filename); + foreach (ZipArchiveEntry entry in archive.Entries) + { + filename = Path.GetFileName(entry.FullName); + if (files.Contains(filename)) + { + entry.ExtractToFile(Path.Combine(binfolder, filename), true); + } + } } - // copy the new file to the /bin - File.Move(Path.Combine(deployfolder, Path.GetFileName(file)), filename); - } - } - catch - { - // an error occurred deleting or moving a file - success = false; - } - // restore on failure - if (!success) - { - foreach (string file in files) + } + catch { - filename = Path.Combine(binfolder, Path.GetFileName(file)); - if (File.Exists(filename)) + // an error occurred extracting a file + success = false; + } + + if (success) + { + // clean up backup + foreach (string file in files) { - File.Move(filename, filename.Replace(".bak", ".dll")); + filename = Path.Combine(binfolder, Path.GetFileName(file)); + if (File.Exists(filename.Replace(".dll", ".bak"))) + { + File.Delete(filename.Replace(".dll", ".bak")); + } } } + else + { + // restore on failure + foreach (string file in files) + { + filename = Path.Combine(binfolder, Path.GetFileName(file)); + if (File.Exists(filename)) + { + File.Delete(filename); + } + File.Move(filename.Replace(".dll", ".bak"), filename); + } + } + + // delete package + File.Delete(packagename); + } + + // bring the app back online + if (File.Exists(Path.Combine(rootfolder, "app_offline.htm"))) + { + File.Move(Path.Combine(rootfolder, "app_offline.htm"), Path.Combine(rootfolder, "app_offline.bak")); } } } - - // bring the app back online - if (File.Exists(Path.Combine(rootfolder, "app_offline.htm"))) - { - File.Move(Path.Combine(rootfolder, "app_offline.htm"), Path.Combine(rootfolder, "app_offline.bak")); - } } return; } - private static bool CanAccessFiles(string[] files, string folder) + private static bool CanAccessFiles(List files, string folder) { // ensure files are not locked by another process - the shutdownTimeLimit defines the duration for app shutdown bool canaccess = true; FileStream stream = null; int i = 0; - while (i < (files.Length - 1) && canaccess) + while (i < (files.Count - 1) && canaccess) { string filepath = Path.Combine(folder, Path.GetFileName(files[i])); int attempts = 0;