From svn_mapguide at osgeo.org Thu Jun 5 07:40:00 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Thu, 5 Jun 2025 07:40:00 -0700 Subject: [mapguide-commits] r10148 - branches/4.0/MgDev Message-ID: <20250605144000.52D7A1413E1@trac.osgeo.org> Author: jng Date: 2025-06-05 07:39:58 -0700 (Thu, 05 Jun 2025) New Revision: 10148 Modified: branches/4.0/MgDev/stampassemblies.bat Log: Fix paths due to MgPortable restructuring Modified: branches/4.0/MgDev/stampassemblies.bat =================================================================== --- branches/4.0/MgDev/stampassemblies.bat 2025-05-27 09:53:31 UTC (rev 10147) +++ branches/4.0/MgDev/stampassemblies.bat 2025-06-05 14:39:58 UTC (rev 10148) @@ -39,9 +39,9 @@ pushd "%CD%\Portable\MgAppLayout\Properties" SetAssemblyVersion.exe -set:%1 AssemblyInfo.cs popd -pushd "%CD%\Portable\MapViewer\Properties" +pushd "%CD%\Portable\OSGeo.MapGuide.Viewer\Properties" SetAssemblyVersion.exe -set:%1 AssemblyInfo.cs popd -pushd "%CD%\Portable\MapViewer.Desktop\Properties" +pushd "%CD%\Portable\OSGeo.MapGuide.Viewer.Portable\Properties" SetAssemblyVersion.exe -set:%1 AssemblyInfo.cs popd \ No newline at end of file From svn_mapguide at osgeo.org Thu Jun 12 05:00:33 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Thu, 12 Jun 2025 05:00:33 -0700 Subject: [mapguide-commits] r10149 - in branches/4.0/MgDev/Server/RepositoryAdmin: . app app/Commands Message-ID: <20250612120034.30B793EB803@trac.osgeo.org> Author: jng Date: 2025-06-12 05:00:32 -0700 (Thu, 12 Jun 2025) New Revision: 10149 Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/ICommonCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx Log: #2879: Implement the beginnings of a replacement repository admin app. The original PHP scripts is merely a glorified wrapper over 3 existing tools: - db_archive - db_checkpoint - db_recover With some file move/copy routines. Our replacement is pretty much the same thing, except it's now a .net console app. .net is not only multi-platform now, but also supports single-file publishing which is great as we can produce self-contained binaries on both Windows and Linux, simplifying the packaging story as a result. This commit implements the cold backup part of the app, which uses db_archive to obtain listing of files to copy to the given backup directory. Index: branches/4.0/MgDev/Server/RepositoryAdmin/app =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app 2025-06-05 14:39:58 UTC (rev 10148) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app 2025-06-12 12:00:32 UTC (rev 10149) Property changes on: branches/4.0/MgDev/Server/RepositoryAdmin/app ___________________________________________________________________ Added: svn:ignore ## -0,0 +1,3 ## +bin +obj +.vs Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,158 @@ +? +using System.Diagnostics; + +namespace MapGuide.RepositoryAdmin.Commands; + +public class App(ICommonCommand cmd, + TextWriter stdout, + TextWriter stderr, + FileInfo dbArchive, + FileInfo dbCheckpoint, + FileInfo dbRecover) +{ + public void Stdout(string msg) => stdout.WriteLine(msg); + + public void Stderr(string msg) => stderr.WriteLine(msg); + + private IEnumerable GetDatabaseFiles(string homeDir) + { + var proc = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = dbArchive.FullName, + Arguments = $"-sv -h \"{homeDir}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true, + WorkingDirectory = dbArchive.DirectoryName + } + }; + proc.Start(); + while (!proc.StandardOutput.EndOfStream) + { + var line = proc.StandardOutput.ReadLine(); + if (line != null) + yield return line; + } + } + + private void TransferDatabaseFiles(DirectoryInfo outDir) + { + var files = GetDatabaseFiles(cmd.InputPath.FullName); + foreach (var f in files) + { + var fi = new FileInfo(Path.Combine(cmd.InputPath.FullName, f)); + TransferFile(outDir, fi); + } + } + + private IEnumerable GetLogFiles(string homeDir, bool unusedFilesOnly = false) + { + var proc = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = dbArchive.FullName, + Arguments = unusedFilesOnly ? $"-v -h \"{homeDir}\"" : $"-lv -h \"{homeDir}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true, + WorkingDirectory = dbArchive.DirectoryName + } + }; + proc.Start(); + while (!proc.StandardOutput.EndOfStream) + { + var line = proc.StandardOutput.ReadLine(); + if (line != null) + yield return line; + } + } + + private void TransferFiles(DirectoryInfo outDir, IList fileName, int index = 0, bool moveFile = false) + { + if (fileName.Count - index <= 0) + throw new CommandException(Strings.IDS_ERR_DATABASE_OR_LOG_FILE_NOT_FOUND); + + for (int i = index; i < fileName.Count; i++) + { + var f = new FileInfo(Path.Combine(cmd.InputPath.FullName, fileName[i])); + this.TransferFile(outDir, f, moveFile); + } + } + + private void TransferLogFiles(DirectoryInfo outDir) + { + List? logFiles = null; + int? numUnusedFiles = null; + switch (cmd) + { + case BackupCommand bk: + { + var unusedFiles = this.GetLogFiles(cmd.InputPath.FullName, true).ToList(); + logFiles = this.GetLogFiles(cmd.InputPath.FullName, false).ToList(); + numUnusedFiles = unusedFiles.Count; + + if (bk.IncrementalLevel != BackupCommand.MIN_INCREMENTAL_LEVEL && numUnusedFiles > 0) + { + this.TransferFiles(outDir, unusedFiles, 0, true); + } + } + break; + case RestoreCommand rs: + { + logFiles = this.GetLogFiles(cmd.InputPath.FullName, false).ToList(); + numUnusedFiles = 0; + } + break; + default: + throw new CommandException(Strings.IDS_ERR_INVALID_OPERATION); + } + + if (logFiles != null && numUnusedFiles.HasValue) + { + this.TransferFiles(outDir, logFiles, numUnusedFiles.Value, false); + } + } + + internal int BackupOfflineRepositories() + { + stdout.WriteLine(Strings.IDS_PROGRESS_BACKING_UP_OFFLINE_REPOSITORY); + + var outDir = cmd.OutputPath.CreateSubdirectory("LastColdBackup"); + TransferDatabaseFiles(outDir); + TransferLogFiles(outDir); + + return 0; + } + + private void TransferFile(DirectoryInfo outDir, FileInfo file, bool move = false, bool overwrite = true) + { + var dest = Path.Combine(outDir.FullName, file.Name); + switch (cmd) + { + case BackupCommand bk: + stdout.WriteLine("\t" + string.Format(Strings.IDS_PROGRESS_ARCHIVING_FILE, file.Name)); + break; + case RestoreCommand rs: + stdout.WriteLine("\t" + string.Format(Strings.IDS_PROGRESS_RECOVERING_FILE, file.Name)); + break; + } + + if (move) + { + file.MoveTo(dest, overwrite); + } + else + { + file.CopyTo(dest, overwrite); + } + + } + + internal int BackupOnlineRepositories() + { + return 0; + } +} Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,50 @@ +using CommandLine; + +namespace MapGuide.RepositoryAdmin.Commands; + +[Verb("backup", HelpText = "VerbHelp_Backup", ResourceType = typeof(Strings))] +public class BackupCommand : BaseCommand +{ + [Option('l', "incremental-level", Required = true)] + public required int IncrementalLevel { get; set; } + + [Option('i', "input-path", Required = true, HelpText = "ArgHelp_Backup_InputPath", ResourceType = typeof(Strings))] + public override required DirectoryInfo InputPath { get; set; } + + [Option('o', "output-path", Required = true, HelpText = "ArgHelp_Backup_OutputPath", ResourceType = typeof(Strings))] + public override required DirectoryInfo OutputPath { get; set; } + + public const int MIN_INCREMENTAL_LEVEL = 0; + public const int MAX_INCREMENTAL_LEVEL = 10; + + protected override int ExecuteCore(App app) + { + if (!InputPath.Exists) + { + app.Stderr(string.Format(Strings.IDS_ERR_DIRECTORY_NOT_FOUND, InputPath)); + return 1; + } + if (!OutputPath.Exists) + { + OutputPath.Create(); + } + if (IncrementalLevel < MIN_INCREMENTAL_LEVEL || IncrementalLevel > MAX_INCREMENTAL_LEVEL) + { + app.Stderr(string.Format(Strings.IDS_ERR_ARGUMENT_OUT_OF_RANGE, IncrementalLevel)); + return 1; + } + + //tools.Stdout($"Incremental level: {IncrementalLevel}"); + //tools.Stdout($"Input path: {InputPath}"); + //tools.Stdout($"Output path: {OutputPath}"); + + if (IncrementalLevel == 0) + { + return app.BackupOfflineRepositories(); + } + else + { + return app.BackupOnlineRepositories(); + } + } +} \ No newline at end of file Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,77 @@ +using CommandLine; + +namespace MapGuide.RepositoryAdmin.Commands; + +public abstract class BaseCommand : ICommonCommand +{ + [Option('b', "bin-path", Required = false, HelpText = "ArgHelp_Common_BinPath", ResourceType = typeof(Strings))] + public DirectoryInfo? BinPath { get; set; } + + public abstract required DirectoryInfo InputPath { get; set; } + + public abstract required DirectoryInfo OutputPath { get; set; } + + public int Execute(TextWriter stdout, TextWriter stderr) + { + var dir = BinPath ?? new DirectoryInfo("../bin"); + if (!dir.Exists) + { + stderr.WriteLine(string.Format(Strings.IDS_ERR_DIRECTORY_NOT_FOUND, dir.FullName)); + return 1; + } + + FileInfo? dbArchive = null; + FileInfo? dbCheckpoint = null; + FileInfo? dbRecover = null; + + foreach (var f in dir.EnumerateFiles()) + { + switch (f.Name.ToLower()) + { + case string s when s.StartsWith("db_archive"): + dbArchive = f; + break; + case string s when s.StartsWith("db_checkpoint"): + dbCheckpoint = f; + break; + case string s when s.StartsWith("db_recover"): + dbRecover = f; + break; + } + } + + stdout.WriteLine(string.Format(Strings.IDS_PROGRESS_CHECKING_TOOLS, dir.FullName)); + + if (dbArchive == null || !dbArchive.Exists) + { + stderr.WriteLine(string.Format(Strings.IDS_ERR_FILE_NOT_FOUND, "db_archive")); + return 1; + } + if (dbCheckpoint == null || !dbCheckpoint.Exists) + { + stderr.WriteLine(string.Format(Strings.IDS_ERR_FILE_NOT_FOUND, "db_checkpoint")); + return 1; + } + if (dbRecover == null || !dbRecover.Exists) + { + stderr.WriteLine(string.Format(Strings.IDS_ERR_FILE_NOT_FOUND, "db_recover")); + return 1; + } + + try + { + var app = new App(this, stdout, stderr, dbArchive, dbCheckpoint, dbRecover); + var res = ExecuteCore(app); + stdout.WriteLine(Strings.IDS_PROGRESS_OPERATION_SUCCEEDED); + return res; + } + catch (CommandException ex) + { + stderr.WriteLine(ex.Message); + stderr.WriteLine(Strings.IDS_PROGRESS_OPERATION_FAILED); + return 1; + } + } + + protected abstract int ExecuteCore(App app); +} \ No newline at end of file Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,13 @@ +?namespace MapGuide.RepositoryAdmin.Commands; + + +[Serializable] +public class CommandException : Exception +{ + public CommandException() { } + public CommandException(string message) : base(message) { } + public CommandException(string message, Exception inner) : base(message, inner) { } + protected CommandException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } +} Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/ICommonCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/ICommonCommand.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/ICommonCommand.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,9 @@ +?namespace MapGuide.RepositoryAdmin.Commands; + +public interface ICommonCommand +{ + DirectoryInfo InputPath { get; } + + + DirectoryInfo OutputPath { get; } +} Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,32 @@ +?using CommandLine; + +namespace MapGuide.RepositoryAdmin.Commands; + +[Verb("restore", HelpText = "VerbHelp_Restore", ResourceType = typeof(Strings))] +public class RestoreCommand : BaseCommand, ICommonCommand +{ + [Option('i', "input-path", Required = true, HelpText = "ArgHelp_Restore_InputPath", ResourceType = typeof(Strings))] + public override required DirectoryInfo InputPath { get; set; } + + [Option('o', "output-path", Required = true, HelpText = "ArgHelp_Restore_OutputPath", ResourceType = typeof(Strings))] + public override required DirectoryInfo OutputPath { get; set; } + + protected override int ExecuteCore(App app) + { + if (!InputPath.Exists) + { + app.Stderr(string.Format(Strings.IDS_ERR_DIRECTORY_NOT_FOUND, InputPath)); + return 1; + } + if (!OutputPath.Exists) + { + app.Stderr(string.Format(Strings.IDS_ERR_DIRECTORY_NOT_FOUND, OutputPath)); + return 1; + } + + app.Stdout($"Input path: {InputPath}"); + app.Stdout($"Output path: {OutputPath}"); + + return 0; + } +} Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,29 @@ +? + + + Exe + net9.0 + enable + enable + + + + + + + + + True + True + Strings.resx + + + + + + PublicResXFileCodeGenerator + Strings.Designer.cs + + + + Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,19 @@ +?using CommandLine; +using MapGuide.RepositoryAdmin.Commands; +using System.Reflection; + +var commandTypes = Assembly.GetExecutingAssembly() + .GetTypes() + .Where(t => typeof(BaseCommand).IsAssignableFrom(t) && t.GetCustomAttribute() != null && !t.IsAbstract) + .ToArray(); + +Parser.Default + .ParseArguments(args, commandTypes) + .WithParsed(opts => + { + Environment.ExitCode = ((BaseCommand)opts).Execute(Console.Out, Console.Error); + }) + .WithNotParsed(err => + { + Environment.ExitCode = 1; + }); \ No newline at end of file Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,378 @@ +?//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace MapGuide.RepositoryAdmin { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MapGuide.RepositoryAdmin.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Path to the source location from where the repository is backed up. + /// + public static string ArgHelp_Backup_InputPath { + get { + return ResourceManager.GetString("ArgHelp_Backup_InputPath", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path to the destination location to where the repository is backed up. For offline (cold) backups, repositories are archived to a time-stamped sub-directory. For online (hot) backups, repositories are acrhived to the 'CurrentHotBackup' or a time-stamped sub-directory when taking an incremental or full snapshot respectively. + /// + public static string ArgHelp_Backup_OutputPath { + get { + return ResourceManager.GetString("ArgHelp_Backup_OutputPath", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path to the MapGuide Server binaries. Defaults to ../bin if not specified. + /// + public static string ArgHelp_Common_BinPath { + get { + return ResourceManager.GetString("ArgHelp_Common_BinPath", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path to the source location from where the repository is restored. + /// + public static string ArgHelp_Restore_InputPath { + get { + return ResourceManager.GetString("ArgHelp_Restore_InputPath", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Path to the destination location to where the repository is restored. + /// + public static string ArgHelp_Restore_OutputPath { + get { + return ResourceManager.GetString("ArgHelp_Restore_OutputPath", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Argument out of range: {0}. + /// + public static string IDS_ERR_ARGUMENT_OUT_OF_RANGE { + get { + return ResourceManager.GetString("IDS_ERR_ARGUMENT_OUT_OF_RANGE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Database or log file not found.. + /// + public static string IDS_ERR_DATABASE_OR_LOG_FILE_NOT_FOUND { + get { + return ResourceManager.GetString("IDS_ERR_DATABASE_OR_LOG_FILE_NOT_FOUND", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A date and/or time error occurred.. + /// + public static string IDS_ERR_DATE_TIME { + get { + return ResourceManager.GetString("IDS_ERR_DATE_TIME", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Directory not found: "{0}". + /// + public static string IDS_ERR_DIRECTORY_NOT_FOUND { + get { + return ResourceManager.GetString("IDS_ERR_DIRECTORY_NOT_FOUND", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File not found: "{0}". + /// + public static string IDS_ERR_FILE_NOT_FOUND { + get { + return ResourceManager.GetString("IDS_ERR_FILE_NOT_FOUND", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid argument: {0}. + /// + public static string IDS_ERR_INVALID_ARGUMENT { + get { + return ResourceManager.GetString("IDS_ERR_INVALID_ARGUMENT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid operation.. + /// + public static string IDS_ERR_INVALID_OPERATION { + get { + return ResourceManager.GetString("IDS_ERR_INVALID_OPERATION", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to clean up log files.. + /// + public static string IDS_ERR_UNABLE_TO_CLEAN_UP_LOG_FILES { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_CLEAN_UP_LOG_FILES", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to copy file "{0}" to "{1}". + /// + public static string IDS_ERR_UNABLE_TO_COPY_FILE { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_COPY_FILE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to create directory: "{1}". + /// + public static string IDS_ERR_UNABLE_TO_CREATE_DIRECTORY { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_CREATE_DIRECTORY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to delete directory: "{0}". + /// + public static string IDS_ERR_UNABLE_TO_DELETE_DIRECTORY { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_DELETE_DIRECTORY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to delete file: "{0}". + /// + public static string IDS_ERR_UNABLE_TO_DELETE_FILE { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_DELETE_FILE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to execute program: {0}. + /// + public static string IDS_ERR_UNABLE_TO_EXECUTE_PROGRAM { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_EXECUTE_PROGRAM", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to move file "{0}" to "{1}". + /// + public static string IDS_ERR_UNABLE_TO_MOVE_FILE { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_MOVE_FILE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to perform checkpoint.. + /// + public static string IDS_ERR_UNABLE_TO_PERFORM_CHECKPOINT { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_PERFORM_CHECKPOINT", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to perform recovery.. + /// + public static string IDS_ERR_UNABLE_TO_PERFORM_RECOVERY { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_PERFORM_RECOVERY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to rename directory "{0}" to "{1}". + /// + public static string IDS_ERR_UNABLE_TO_RENAME_DIRECTORY { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_RENAME_DIRECTORY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to retrieve database files.. + /// + public static string IDS_ERR_UNABLE_TO_RETRIEVE_DATABASE_FILES { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_RETRIEVE_DATABASE_FILES", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to retrieve log files.. + /// + public static string IDS_ERR_UNABLE_TO_RETRIEVE_LOG_FILES { + get { + return ResourceManager.GetString("IDS_ERR_UNABLE_TO_RETRIEVE_LOG_FILES", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An unclassified exception occurred.. + /// + public static string IDS_ERR_UNCLASSIFIED { + get { + return ResourceManager.GetString("IDS_ERR_UNCLASSIFIED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Archiving file: "{0}". + /// + public static string IDS_PROGRESS_ARCHIVING_FILE { + get { + return ResourceManager.GetString("IDS_PROGRESS_ARCHIVING_FILE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backing up offline (cold) repository .... + /// + public static string IDS_PROGRESS_BACKING_UP_OFFLINE_REPOSITORY { + get { + return ResourceManager.GetString("IDS_PROGRESS_BACKING_UP_OFFLINE_REPOSITORY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Backing up online (hot) repository .... + /// + public static string IDS_PROGRESS_BACKING_UP_ONLINE_REPOSITORY { + get { + return ResourceManager.GetString("IDS_PROGRESS_BACKING_UP_ONLINE_REPOSITORY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Checking for required tools in {0}. + /// + public static string IDS_PROGRESS_CHECKING_TOOLS { + get { + return ResourceManager.GetString("IDS_PROGRESS_CHECKING_TOOLS", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operation failed!. + /// + public static string IDS_PROGRESS_OPERATION_FAILED { + get { + return ResourceManager.GetString("IDS_PROGRESS_OPERATION_FAILED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operation succeeded!. + /// + public static string IDS_PROGRESS_OPERATION_SUCCEEDED { + get { + return ResourceManager.GetString("IDS_PROGRESS_OPERATION_SUCCEEDED", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Recovering file: "{0}". + /// + public static string IDS_PROGRESS_RECOVERING_FILE { + get { + return ResourceManager.GetString("IDS_PROGRESS_RECOVERING_FILE", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Restoring backup repository .... + /// + public static string IDS_PROGRESS_RESTORING_BACKUP_REPOSITORY { + get { + return ResourceManager.GetString("IDS_PROGRESS_RESTORING_BACKUP_REPOSITORY", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Perform a hot or cold backup of the repository. + /// + public static string VerbHelp_Backup { + get { + return ResourceManager.GetString("VerbHelp_Backup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Perform a restore from a repository backup. + /// + public static string VerbHelp_Restore { + get { + return ResourceManager.GetString("VerbHelp_Restore", resourceCulture); + } + } + } +} Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx 2025-06-12 12:00:32 UTC (rev 10149) @@ -0,0 +1,225 @@ +? + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Path to the source location from where the repository is backed up + + + Path to the destination location to where the repository is backed up. For offline (cold) backups, repositories are archived to a time-stamped sub-directory. For online (hot) backups, repositories are acrhived to the 'CurrentHotBackup' or a time-stamped sub-directory when taking an incremental or full snapshot respectively + + + Path to the MapGuide Server binaries. Defaults to ../bin if not specified + + + Path to the source location from where the repository is restored + + + Path to the destination location to where the repository is restored + + + Argument out of range: {0} + + + Database or log file not found. + + + A date and/or time error occurred. + + + Directory not found: "{0}" + + + File not found: "{0}" + + + Invalid argument: {0} + + + Invalid operation. + + + Unable to clean up log files. + + + Unable to copy file "{0}" to "{1}" + + + Unable to create directory: "{1}" + + + Unable to delete directory: "{0}" + + + Unable to delete file: "{0}" + + + Unable to execute program: {0} + + + Unable to move file "{0}" to "{1}" + + + Unable to perform checkpoint. + + + Unable to perform recovery. + + + Unable to rename directory "{0}" to "{1}" + + + Unable to retrieve database files. + + + Unable to retrieve log files. + + + An unclassified exception occurred. + + + Archiving file: "{0}" + + + Backing up offline (cold) repository ... + + + Backing up online (hot) repository ... + + + Checking for required tools in {0} + + + Operation failed! + + + Operation succeeded! + + + Recovering file: "{0}" + + + Restoring backup repository ... + + + Perform a hot or cold backup of the repository + + + Perform a restore from a repository backup + + \ No newline at end of file From svn_mapguide at osgeo.org Thu Jun 12 05:58:59 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Thu, 12 Jun 2025 05:58:59 -0700 Subject: [mapguide-commits] r10150 - branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands Message-ID: <20250612125859.B14013F7DD0@trac.osgeo.org> Author: jng Date: 2025-06-12 05:58:58 -0700 (Thu, 12 Jun 2025) New Revision: 10150 Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs Log: #2879: Initial implementation of hot backup and restore Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-12 12:00:32 UTC (rev 10149) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-12 12:58:58 UTC (rev 10150) @@ -14,6 +14,42 @@ public void Stderr(string msg) => stderr.WriteLine(msg); + private void PerformRecovery(string homeDir) + { + var proc = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = dbRecover.FullName, + Arguments = $"-cv -h \"{homeDir}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true, + WorkingDirectory = dbRecover.DirectoryName + } + }; + proc.Start(); + proc.WaitForExit(); + } + + private void CleanUpLogFiles(string homeDir) + { + var proc = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = dbArchive.FullName, + Arguments = $"-dv -h \"{homeDir}\"", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true, + WorkingDirectory = dbArchive.DirectoryName + } + }; + proc.Start(); + proc.WaitForExit(); + } + private IEnumerable GetDatabaseFiles(string homeDir) { var proc = new Process @@ -116,17 +152,6 @@ } } - internal int BackupOfflineRepositories() - { - stdout.WriteLine(Strings.IDS_PROGRESS_BACKING_UP_OFFLINE_REPOSITORY); - - var outDir = cmd.OutputPath.CreateSubdirectory("LastColdBackup"); - TransferDatabaseFiles(outDir); - TransferLogFiles(outDir); - - return 0; - } - private void TransferFile(DirectoryInfo outDir, FileInfo file, bool move = false, bool overwrite = true) { var dest = Path.Combine(outDir.FullName, file.Name); @@ -151,8 +176,46 @@ } + internal int BackupOfflineRepositories() + { + stdout.WriteLine(Strings.IDS_PROGRESS_BACKING_UP_OFFLINE_REPOSITORY); + + // TODO: timestamp subdirectory computation + var outDir = cmd.OutputPath.CreateSubdirectory("LastColdBackup"); + TransferDatabaseFiles(outDir); + TransferLogFiles(outDir); + + return 0; + } + internal int BackupOnlineRepositories() { + stdout.WriteLine(Strings.IDS_PROGRESS_BACKING_UP_ONLINE_REPOSITORY); + + bool fullSnapshot = true; + // TODO: fullSnapshot flag determination logic + + var outDir = cmd.OutputPath.CreateSubdirectory("LastHotBackup"); + if (fullSnapshot) + { + TransferDatabaseFiles(outDir); + } + TransferLogFiles(outDir); + return 0; } + + internal int RestoreRepositories() + { + stdout.WriteLine(Strings.IDS_PROGRESS_RESTORING_BACKUP_REPOSITORY); + + // TODO: tempBackupDir determination + + TransferDatabaseFiles(cmd.OutputPath); + TransferLogFiles(cmd.OutputPath); + PerformRecovery(cmd.OutputPath.FullName); + CleanUpLogFiles(cmd.OutputPath.FullName); + + return 0; + } } Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs 2025-06-12 12:00:32 UTC (rev 10149) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs 2025-06-12 12:58:58 UTC (rev 10150) @@ -24,9 +24,9 @@ return 1; } - app.Stdout($"Input path: {InputPath}"); - app.Stdout($"Output path: {OutputPath}"); + //app.Stdout($"Input path: {InputPath}"); + //app.Stdout($"Output path: {OutputPath}"); - return 0; + return app.RestoreRepositories(); } } From svn_mapguide at osgeo.org Thu Jun 12 07:54:41 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Thu, 12 Jun 2025 07:54:41 -0700 Subject: [mapguide-commits] r10151 - in branches/4.0/MgDev/Server/RepositoryAdmin/app: . Commands Message-ID: <20250612145442.0AB8A3F7093@trac.osgeo.org> Author: jng Date: 2025-06-12 07:54:40 -0700 (Thu, 12 Jun 2025) New Revision: 10151 Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RootCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/nuget.config Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx Log: #2879: Migrate from CommandLine to DotMake.CommandLine as that supports trimming, which is a hard requirement as we intend to publish a trimmed, single-file, self-contained binary Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -7,7 +7,6 @@ TextWriter stdout, TextWriter stderr, FileInfo dbArchive, - FileInfo dbCheckpoint, FileInfo dbRecover) { public void Stdout(string msg) => stdout.WriteLine(msg); @@ -130,7 +129,7 @@ logFiles = this.GetLogFiles(cmd.InputPath.FullName, false).ToList(); numUnusedFiles = unusedFiles.Count; - if (bk.IncrementalLevel != BackupCommand.MIN_INCREMENTAL_LEVEL && numUnusedFiles > 0) + if (bk.Level != BackupCommand.MIN_INCREMENTAL_LEVEL && numUnusedFiles > 0) { this.TransferFiles(outDir, unusedFiles, 0, true); } Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BackupCommand.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -1,17 +1,22 @@ -using CommandLine; +using DotMake.CommandLine; namespace MapGuide.RepositoryAdmin.Commands; -[Verb("backup", HelpText = "VerbHelp_Backup", ResourceType = typeof(Strings))] +[CliCommand(Name = "backup", Description = nameof(Strings.VerbHelp_Backup))] public class BackupCommand : BaseCommand { - [Option('l', "incremental-level", Required = true)] - public required int IncrementalLevel { get; set; } + // HACK: Source generator won't generate if attribute placed on base property, so that has been made + // abstract and we're decorating here + [CliOption(Required = false, Description = nameof(Strings.ArgHelp_Common_BinPath))] + public override DirectoryInfo? BinPath { get; set; } - [Option('i', "input-path", Required = true, HelpText = "ArgHelp_Backup_InputPath", ResourceType = typeof(Strings))] + [CliOption(Description = nameof(Strings.ArgHelp_Backup_Level))] + public required int Level { get; set; } + + [CliOption(Description = nameof(Strings.ArgHelp_Backup_InputPath))] public override required DirectoryInfo InputPath { get; set; } - [Option('o', "output-path", Required = true, HelpText = "ArgHelp_Backup_OutputPath", ResourceType = typeof(Strings))] + [CliOption(Description = nameof(Strings.ArgHelp_Backup_OutputPath))] public override required DirectoryInfo OutputPath { get; set; } public const int MIN_INCREMENTAL_LEVEL = 0; @@ -28,9 +33,9 @@ { OutputPath.Create(); } - if (IncrementalLevel < MIN_INCREMENTAL_LEVEL || IncrementalLevel > MAX_INCREMENTAL_LEVEL) + if (Level < MIN_INCREMENTAL_LEVEL || Level > MAX_INCREMENTAL_LEVEL) { - app.Stderr(string.Format(Strings.IDS_ERR_ARGUMENT_OUT_OF_RANGE, IncrementalLevel)); + app.Stderr(string.Format(Strings.IDS_ERR_ARGUMENT_OUT_OF_RANGE, Level)); return 1; } @@ -38,7 +43,7 @@ //tools.Stdout($"Input path: {InputPath}"); //tools.Stdout($"Output path: {OutputPath}"); - if (IncrementalLevel == 0) + if (Level == 0) { return app.BackupOfflineRepositories(); } Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/BaseCommand.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -1,16 +1,15 @@ -using CommandLine; - namespace MapGuide.RepositoryAdmin.Commands; public abstract class BaseCommand : ICommonCommand { - [Option('b', "bin-path", Required = false, HelpText = "ArgHelp_Common_BinPath", ResourceType = typeof(Strings))] - public DirectoryInfo? BinPath { get; set; } + public abstract DirectoryInfo? BinPath { get; set; } public abstract required DirectoryInfo InputPath { get; set; } public abstract required DirectoryInfo OutputPath { get; set; } + public int Run() => Execute(Console.Out, Console.Error); + public int Execute(TextWriter stdout, TextWriter stderr) { var dir = BinPath ?? new DirectoryInfo("../bin"); @@ -21,7 +20,6 @@ } FileInfo? dbArchive = null; - FileInfo? dbCheckpoint = null; FileInfo? dbRecover = null; foreach (var f in dir.EnumerateFiles()) @@ -31,9 +29,6 @@ case string s when s.StartsWith("db_archive"): dbArchive = f; break; - case string s when s.StartsWith("db_checkpoint"): - dbCheckpoint = f; - break; case string s when s.StartsWith("db_recover"): dbRecover = f; break; @@ -47,11 +42,6 @@ stderr.WriteLine(string.Format(Strings.IDS_ERR_FILE_NOT_FOUND, "db_archive")); return 1; } - if (dbCheckpoint == null || !dbCheckpoint.Exists) - { - stderr.WriteLine(string.Format(Strings.IDS_ERR_FILE_NOT_FOUND, "db_checkpoint")); - return 1; - } if (dbRecover == null || !dbRecover.Exists) { stderr.WriteLine(string.Format(Strings.IDS_ERR_FILE_NOT_FOUND, "db_recover")); @@ -60,7 +50,7 @@ try { - var app = new App(this, stdout, stderr, dbArchive, dbCheckpoint, dbRecover); + var app = new App(this, stdout, stderr, dbArchive, dbRecover); var res = ExecuteCore(app); stdout.WriteLine(Strings.IDS_PROGRESS_OPERATION_SUCCEEDED); return res; Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/CommandException.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -7,7 +7,4 @@ public CommandException() { } public CommandException(string message) : base(message) { } public CommandException(string message, Exception inner) : base(message, inner) { } - protected CommandException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RestoreCommand.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -1,14 +1,19 @@ -?using CommandLine; +?using DotMake.CommandLine; namespace MapGuide.RepositoryAdmin.Commands; -[Verb("restore", HelpText = "VerbHelp_Restore", ResourceType = typeof(Strings))] +[CliCommand(Name = "restore", Description = nameof(Strings.VerbHelp_Restore))] public class RestoreCommand : BaseCommand, ICommonCommand { - [Option('i', "input-path", Required = true, HelpText = "ArgHelp_Restore_InputPath", ResourceType = typeof(Strings))] + // HACK: Source generator won't generate if attribute placed on base property, so that has been made + // abstract and we're decorating here + [CliOption(Required = false, Description = nameof(Strings.ArgHelp_Common_BinPath))] + public override DirectoryInfo? BinPath { get; set; } + + [CliOption(Description = nameof(Strings.ArgHelp_Restore_InputPath))] public override required DirectoryInfo InputPath { get; set; } - [Option('o', "output-path", Required = true, HelpText = "ArgHelp_Restore_OutputPath", ResourceType = typeof(Strings))] + [CliOption(Description = nameof(Strings.ArgHelp_Restore_OutputPath))] public override required DirectoryInfo OutputPath { get; set; } protected override int ExecuteCore(App app) Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RootCommand.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RootCommand.cs (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/RootCommand.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -0,0 +1,8 @@ +?using DotMake.CommandLine; + +namespace MapGuide.RepositoryAdmin.Commands; + +[CliCommand(Children = [ typeof(BackupCommand), typeof(RestoreCommand) ])] +public class RootCommand +{ +} Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/MapGuide.RepositoryAdmin.csproj 2025-06-12 14:54:40 UTC (rev 10151) @@ -5,10 +5,24 @@ net9.0 enable enable + true + true + true + true + true + + false + false + false + false + false + false + false + true - + Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Program.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -1,19 +1,5 @@ -?using CommandLine; +? +using DotMake.CommandLine; using MapGuide.RepositoryAdmin.Commands; -using System.Reflection; -var commandTypes = Assembly.GetExecutingAssembly() - .GetTypes() - .Where(t => typeof(BaseCommand).IsAssignableFrom(t) && t.GetCustomAttribute() != null && !t.IsAbstract) - .ToArray(); - -Parser.Default - .ParseArguments(args, commandTypes) - .WithParsed(opts => - { - Environment.ExitCode = ((BaseCommand)opts).Execute(Console.Out, Console.Error); - }) - .WithNotParsed(err => - { - Environment.ExitCode = 1; - }); \ No newline at end of file +return Cli.Run(args); \ No newline at end of file Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.Designer.cs 2025-06-12 14:54:40 UTC (rev 10151) @@ -70,6 +70,20 @@ } /// + /// Looks up a localized string similar to Incremental level (from 0 to 10). + ///= 0, Offline (cold) backup (A full snapshot is always taken) + ///> 0, Online (hot) backup. For example, for an incremental level value of 2: + /// - If the number of active log files in the previous snapshot is less than or equal to 2, an incremental snapshot is taken. + /// - If the number of active log files in the previous snapshot is greater than 2, a full snapshot is taken. + ///Note that active log files are files containing data that has NOT been saved to the database (by de [rest of string was truncated]";. + /// + public static string ArgHelp_Backup_Level { + get { + return ResourceManager.GetString("ArgHelp_Backup_Level", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Path to the destination location to where the repository is backed up. For offline (cold) backups, repositories are archived to a time-stamped sub-directory. For online (hot) backups, repositories are acrhived to the 'CurrentHotBackup' or a time-stamped sub-directory when taking an incremental or full snapshot respectively. /// public static string ArgHelp_Backup_OutputPath { Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx 2025-06-12 12:58:58 UTC (rev 10150) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Strings.resx 2025-06-12 14:54:40 UTC (rev 10151) @@ -120,6 +120,14 @@ Path to the source location from where the repository is backed up + + Incremental level (from 0 to 10). += 0, Offline (cold) backup (A full snapshot is always taken) +> 0, Online (hot) backup. For example, for an incremental level value of 2: + - If the number of active log files in the previous snapshot is less than or equal to 2, an incremental snapshot is taken. + - If the number of active log files in the previous snapshot is greater than 2, a full snapshot is taken. +Note that active log files are files containing data that has NOT been saved to the database (by default, the size of a log file is about 10MB) + Path to the destination location to where the repository is backed up. For offline (cold) backups, repositories are archived to a time-stamped sub-directory. For online (hot) backups, repositories are acrhived to the 'CurrentHotBackup' or a time-stamped sub-directory when taking an incremental or full snapshot respectively Added: branches/4.0/MgDev/Server/RepositoryAdmin/app/nuget.config =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/nuget.config (rev 0) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/nuget.config 2025-06-12 14:54:40 UTC (rev 10151) @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file From svn_mapguide at osgeo.org Thu Jun 12 08:01:44 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Thu, 12 Jun 2025 08:01:44 -0700 Subject: [mapguide-commits] r10152 - branches/4.0/MgDev/Server/RepositoryAdmin Message-ID: <20250612150144.8A68640044A@trac.osgeo.org> Author: jng Date: 2025-06-12 08:01:43 -0700 (Thu, 12 Jun 2025) New Revision: 10152 Modified: branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.bat branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.sh branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.bat branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.sh branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.bat branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.sh branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.bat branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.sh Log: #2879: Update affected wrapper batch files to point to the new tool Modified: branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.bat =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.bat 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.bat 2025-06-12 15:01:43 UTC (rev 10152) @@ -5,7 +5,7 @@ echo --- Site repository echo. if not exist "..\BackupRepositories\Site" md "..\BackupRepositories\Site" -php -n RepositoryAdmin.php -c Backup -l 0 -i "%cd%\..\Repositories\Site" -o "%cd%\..\BackupRepositories\Site" +MapGuide.RepositoryAdmin.exe backup -l 0 -i "%cd%\..\Repositories\Site" -o "%cd%\..\BackupRepositories\Site" echo. echo. @@ -12,7 +12,7 @@ echo --- Library repository echo. if not exist "..\BackupRepositories\Library" md "..\BackupRepositories\Library" -php -n RepositoryAdmin.php -c Backup -l 0 -i "%cd%\..\Repositories\Library" -o "%cd%\..\BackupRepositories\Library" +MapGuide.RepositoryAdmin.exe backup -l 0 -i "%cd%\..\Repositories\Library" -o "%cd%\..\BackupRepositories\Library" echo. @echo on Modified: branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.sh =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.sh 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOfflineRepositories.sh 2025-06-12 15:01:43 UTC (rev 10152) @@ -1,7 +1,6 @@ #!/bin/sh -php -c $(pwd) CheckVersion.php -STATUS=$? +STATUS=0 if [ $STATUS -eq 0 ]; then echo @@ -13,7 +12,7 @@ mkdir -p ../BackupRepositories/Site fi - php -c $(pwd) RepositoryAdmin.php -c Backup -l 0 -i "$(pwd)/../Repositories/Site" -o "$(pwd)/../BackupRepositories/Site" + ./MapGuide.RepositoryAdmin backup -l 0 -i "$(pwd)/../Repositories/Site" -o "$(pwd)/../BackupRepositories/Site" echo echo @@ -24,6 +23,6 @@ mkdir -p ../BackupRepositories/Library fi - php -c $(pwd) RepositoryAdmin.php -c Backup -l 0 -i "$(pwd)/../Repositories/Library" -o "$(pwd)/../BackupRepositories/Library" + ./MapGuide.RepositoryAdmin backup -l 0 -i "$(pwd)/../Repositories/Library" -o "$(pwd)/../BackupRepositories/Library" echo fi Modified: branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.bat =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.bat 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.bat 2025-06-12 15:01:43 UTC (rev 10152) @@ -5,7 +5,7 @@ echo --- Site repository echo. if not exist "..\BackupRepositories\Site" md "..\BackupRepositories\Site" -php -n RepositoryAdmin.php -c Backup -l 2 -i "%cd%\..\Repositories\Site" -o "%cd%\..\BackupRepositories\Site" +MapGuide.RepositoryAdmin.exe backup -l 2 -i "%cd%\..\Repositories\Site" -o "%cd%\..\BackupRepositories\Site" echo. echo. @@ -12,7 +12,7 @@ echo --- Library repository echo. if not exist "..\BackupRepositories\Library" md "..\BackupRepositories\Library" -php -n RepositoryAdmin.php -c Backup -l 2 -i "%cd%\..\Repositories\Library" -o "%cd%\..\BackupRepositories\Library" +MapGuide.RepositoryAdmin.exe backup -l 2 -i "%cd%\..\Repositories\Library" -o "%cd%\..\BackupRepositories\Library" echo. @echo on Modified: branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.sh =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.sh 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/BackUpOnlineRepositories.sh 2025-06-12 15:01:43 UTC (rev 10152) @@ -1,7 +1,6 @@ #!/bin/sh -php -c $(pwd) CheckVersion.php -STATUS=$? +STATUS=0 if [ $STATUS -eq 0 ]; then @@ -14,7 +13,7 @@ mkdir -p ../BackupRepositories/Site fi - php -c $(pwd) RepositoryAdmin.php -c Backup -l 2 -i "$(pwd)/../Repositories/Site" -o "$(pwd)/../BackupRepositories/Site" + ./MapGuide.RepositoryAdmin backup -l 2 -i "$(pwd)/../Repositories/Site" -o "$(pwd)/../BackupRepositories/Site" echo echo @@ -25,6 +24,6 @@ mkdir -p ../BackupRepositories/Library fi - php -c $(pwd) RepositoryAdmin.php -c Backup -l 2 -i "$(pwd)/../Repositories/Library" -o "$(pwd)/../BackupRepositories/Library" + ./MapGuide.RepositoryAdmin backup -l 2 -i "$(pwd)/../Repositories/Library" -o "$(pwd)/../BackupRepositories/Library" echo fi Modified: branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.bat =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.bat 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.bat 2025-06-12 15:01:43 UTC (rev 10152) @@ -4,13 +4,13 @@ echo. echo --- Site repository echo. -php -n RepositoryAdmin.php -c Restore -i "%cd%\..\BackupRepositories\Site\LastColdBackup" -o "%cd%\..\Repositories\Site" +MapGuide.RepositoryAdmin.exe restore -i "%cd%\..\BackupRepositories\Site\LastColdBackup" -o "%cd%\..\Repositories\Site" echo. echo. echo --- Library repository echo. -php -n RepositoryAdmin.php -c Restore -i "%cd%\..\BackupRepositories\Library\LastColdBackup" -o "%cd%\..\Repositories\Library" +MapGuide.RepositoryAdmin.exe restore -i "%cd%\..\BackupRepositories\Library\LastColdBackup" -o "%cd%\..\Repositories\Library" echo. @echo on Modified: branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.sh =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.sh 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/RestoreColdBackupRepositories.sh 2025-06-12 15:01:43 UTC (rev 10152) @@ -1,7 +1,6 @@ #!/bin/sh -php -c $(pwd) CheckVersion.php -STATUS=$? +STATUS=0 if [ $STATUS -eq 0 ]; then echo @@ -8,12 +7,12 @@ echo echo --- Site repository echo - php -c $(pwd) RepositoryAdmin.php -c Restore -i "$(pwd)/../BackupRepositories/Site/LastColdBackup" -o "$(pwd)/../Repositories/Site" + ./MapGuide.RepositoryAdmin restore -i "$(pwd)/../BackupRepositories/Site/LastColdBackup" -o "$(pwd)/../Repositories/Site" echo echo echo --- Library repository echo - php -c $(pwd) RepositoryAdmin.php -c Restore -i "$(pwd)/../BackupRepositories/Library/LastColdBackup" -o "$(pwd)/../Repositories/Library" + ./MapGuide.RepositoryAdmin restore -i "$(pwd)/../BackupRepositories/Library/LastColdBackup" -o "$(pwd)/../Repositories/Library" echo fi Modified: branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.bat =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.bat 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.bat 2025-06-12 15:01:43 UTC (rev 10152) @@ -4,13 +4,13 @@ echo. echo --- Site repository echo. -php -n RepositoryAdmin.php -c Restore -i "%cd%\..\BackupRepositories\Site\LastHotBackup" -o "%cd%\..\Repositories\Site" +MapGuide.RepositoryAdmin.exe restore -i "%cd%\..\BackupRepositories\Site\LastHotBackup" -o "%cd%\..\Repositories\Site" echo. echo. echo --- Library repository echo. -php -n RepositoryAdmin.php -c Restore -i "%cd%\..\BackupRepositories\Library\LastHotBackup" -o "%cd%\..\Repositories\Library" +MapGuide.RepositoryAdmin.exe restore -i "%cd%\..\BackupRepositories\Library\LastHotBackup" -o "%cd%\..\Repositories\Library" echo. @echo on Modified: branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.sh =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.sh 2025-06-12 14:54:40 UTC (rev 10151) +++ branches/4.0/MgDev/Server/RepositoryAdmin/RestoreHotBackupRepositories.sh 2025-06-12 15:01:43 UTC (rev 10152) @@ -1,7 +1,6 @@ #!/bin/sh -php -c $(pwd) CheckVersion.php -STATUS=$? +STATUS=0 if [ $STATUS -eq 0 ]; then echo @@ -8,12 +7,12 @@ echo echo --- Site repository echo - php -c $(pwd) RepositoryAdmin.php -c Restore -i "$(pwd)/../BackupRepositories/Site/LastHotBackup" -o "$(pwd)/../Repositories/Site" + ./MapGuide.RepositoryAdmin restore -i "$(pwd)/../BackupRepositories/Site/LastHotBackup" -o "$(pwd)/../Repositories/Site" echo echo echo --- Library repository echo - php -c $(pwd) RepositoryAdmin.php -c Restore -i "$(pwd)/../BackupRepositories/Library/LastHotBackup" -o "$(pwd)/../Repositories/Library" + ./MapGuide.RepositoryAdmin restore -i "$(pwd)/../BackupRepositories/Library/LastHotBackup" -o "$(pwd)/../Repositories/Library" echo fi From svn_mapguide at osgeo.org Thu Jun 12 08:06:57 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Thu, 12 Jun 2025 08:06:57 -0700 Subject: [mapguide-commits] r10153 - branches/4.0/MgDev Message-ID: <20250612150658.0E72D40233D@trac.osgeo.org> Author: jng Date: 2025-06-12 08:06:57 -0700 (Thu, 12 Jun 2025) New Revision: 10153 Modified: branches/4.0/MgDev/build.bat Log: #2879: Update root build to restore RepositoryAdmin preparations Modified: branches/4.0/MgDev/build.bat =================================================================== --- branches/4.0/MgDev/build.bat 2025-06-12 15:01:43 UTC (rev 10152) +++ branches/4.0/MgDev/build.bat 2025-06-12 15:06:57 UTC (rev 10153) @@ -311,12 +311,13 @@ %XCOPY% "%MG_SERVER%\bin\%TYPEBUILD%\wms" "%MG_OUTPUT_SERVER%\wms" echo [install]: Server - DBXML copy /Y "%MG_BUILD_DBXML_EXE_PATH%\*.exe" "%MG_OUTPUT_SERVER%\bin" -REM Temporarily disabled until we build replacement backup/restore scripts not requiring a super-ancient PHP binary -REM echo [install]: Server - RepositoryAdmin -REM %XCOPY% "%MG_SERVER%\RepositoryAdmin" "%MG_OUTPUT_SERVER%\RepositoryAdmin" -echo [install]: Server - Stub RepositoryAdmin +echo [install]: Server - RepositoryAdmin if not exist "%MG_OUTPUT_SERVER%\RepositoryAdmin" mkdir "%MG_OUTPUT_SERVER%\RepositoryAdmin" -copy /Y "%MG_SERVER%\RepositoryAdmin\README.txt" "%MG_OUTPUT_SERVER%\RepositoryAdmin" +%XCOPY% "%MG_SERVER%\RepositoryAdmin\*.txt" "%MG_OUTPUT_SERVER%\RepositoryAdmin" +%XCOPY% "%MG_SERVER%\RepositoryAdmin\*.bat" "%MG_OUTPUT_SERVER%\RepositoryAdmin" +pushd "%MG_SERVER%\RepositoryAdmin\app" +dotnet publish -c Release -r win-x64 -o "%MG_OUTPUT_SERVER%\RepositoryAdmin" +popd echo [install]: CsMap Dictionaries %XCOPY% "%MG_OEM%\CSMap\CsMapDev\Dictionaries" "%MG_OUTPUT_CSMAP%\Dictionaries" /EXCLUDE:csmap_excludes.txt echo [install]: PDBs - Common From svn_mapguide at osgeo.org Mon Jun 16 03:25:08 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Mon, 16 Jun 2025 03:25:08 -0700 Subject: [mapguide-commits] r10154 - branches/4.0/MgDev Message-ID: <20250616102509.6D1E165A831@trac.osgeo.org> Author: jng Date: 2025-06-16 03:25:06 -0700 (Mon, 16 Jun 2025) New Revision: 10154 Modified: branches/4.0/MgDev/build.bat Log: Use regular copy instead of xcopy Modified: branches/4.0/MgDev/build.bat =================================================================== --- branches/4.0/MgDev/build.bat 2025-06-12 15:06:57 UTC (rev 10153) +++ branches/4.0/MgDev/build.bat 2025-06-16 10:25:06 UTC (rev 10154) @@ -313,8 +313,8 @@ copy /Y "%MG_BUILD_DBXML_EXE_PATH%\*.exe" "%MG_OUTPUT_SERVER%\bin" echo [install]: Server - RepositoryAdmin if not exist "%MG_OUTPUT_SERVER%\RepositoryAdmin" mkdir "%MG_OUTPUT_SERVER%\RepositoryAdmin" -%XCOPY% "%MG_SERVER%\RepositoryAdmin\*.txt" "%MG_OUTPUT_SERVER%\RepositoryAdmin" -%XCOPY% "%MG_SERVER%\RepositoryAdmin\*.bat" "%MG_OUTPUT_SERVER%\RepositoryAdmin" +copy /Y "%MG_SERVER%\RepositoryAdmin\*.txt" "%MG_OUTPUT_SERVER%\RepositoryAdmin" +copy /Y "%MG_SERVER%\RepositoryAdmin\*.bat" "%MG_OUTPUT_SERVER%\RepositoryAdmin" pushd "%MG_SERVER%\RepositoryAdmin\app" dotnet publish -c Release -r win-x64 -o "%MG_OUTPUT_SERVER%\RepositoryAdmin" popd From svn_mapguide at osgeo.org Mon Jun 16 05:14:05 2025 From: svn_mapguide at osgeo.org (svn_mapguide at osgeo.org) Date: Mon, 16 Jun 2025 05:14:05 -0700 Subject: [mapguide-commits] r10155 - branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands Message-ID: <20250616121405.A58A067A908@trac.osgeo.org> Author: jng Date: 2025-06-16 05:14:03 -0700 (Mon, 16 Jun 2025) New Revision: 10155 Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs Log: #2879: Implement sub-directory determination for (cold) backup and restore commands Modified: branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs =================================================================== --- branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-16 10:25:06 UTC (rev 10154) +++ branches/4.0/MgDev/Server/RepositoryAdmin/app/Commands/App.cs 2025-06-16 12:14:03 UTC (rev 10155) @@ -179,8 +179,20 @@ { stdout.WriteLine(Strings.IDS_PROGRESS_BACKING_UP_OFFLINE_REPOSITORY); - // TODO: timestamp subdirectory computation - var outDir = cmd.OutputPath.CreateSubdirectory("LastColdBackup"); + var bkDir = new DirectoryInfo(Path.Combine(cmd.OutputPath.FullName, "LastColdBackup")); + if (bkDir.Exists) + { + // Rename current LastColdBackup to COLD_BK_yyyy-mm-dd-hh-mm-ss + var localNow = DateTime.Now; + var newName = $"COLD_BK_{localNow.Year}-{localNow.Month:00}-{localNow.Day:00}-{localNow.Hour:00}-{localNow.Minute:00}-{localNow.Second:00}"; + bkDir.MoveTo(newName); + + // Re-create a new LastColdBackup + bkDir = new DirectoryInfo(Path.Combine(cmd.OutputPath.FullName, "LastColdBackup")); + bkDir.Create(); + } + + var outDir = bkDir; TransferDatabaseFiles(outDir); TransferLogFiles(outDir); @@ -208,8 +220,28 @@ { stdout.WriteLine(Strings.IDS_PROGRESS_RESTORING_BACKUP_REPOSITORY); - // TODO: tempBackupDir determination + var targetDir = new DirectoryInfo(cmd.OutputPath.FullName); + if (targetDir.Exists) + { + var children = targetDir.GetFiles(); + if (children.Length > 0) + { + // Make TMP_BK_yyyy-mm-dd-hh-mm-ss subdirectory + var localNow = DateTime.Now; + var newName = $"TMP_BK_{localNow.Year}-{localNow.Month:00}-{localNow.Day:00}-{localNow.Hour:00}-{localNow.Minute:00}-{localNow.Second:00}"; + var subDir = new DirectoryInfo(Path.Combine(targetDir.FullName, newName)); + subDir.Create(); + + // Move children into it + foreach (var f in children) + { + var dst = Path.Combine(subDir.FullName, f.Name); + f.MoveTo(dst); + } + } + } + TransferDatabaseFiles(cmd.OutputPath); TransferLogFiles(cmd.OutputPath); PerformRecovery(cmd.OutputPath.FullName);