diff --git a/RombaSharp/RombaSharp.Help.cs b/RombaSharp/RombaSharp.Help.cs index d1b2da6d..c4511ef4 100644 --- a/RombaSharp/RombaSharp.Help.cs +++ b/RombaSharp/RombaSharp.Help.cs @@ -9,6 +9,17 @@ namespace RombaSharp { #region Private Flag features + private static Feature copyFlag + { + get + { + return new Feature( + "copy", + "-copy", + "Copy files to output instead of rebuilding", + FeatureType.Flag); + } + } // Unique to RombaSharp private static Feature fixdatOnlyFlag { get @@ -30,7 +41,7 @@ namespace RombaSharp "Only write out actions to log", FeatureType.Flag); } - } // Unique to RombaSharp + } private static Feature noDbFlag { get @@ -308,6 +319,17 @@ namespace RombaSharp #endregion + #region Script + + Feature script = new Feature( + "Script", + "--script", + "Enable script mode (no clear screen)", + FeatureType.Flag, + longDescription: "For times when RombaSharp is being used in a scripted environment, the user may not want the screen to be cleared every time that it is called. This flag allows the user to skip clearing the screen on run just like if the console was being redirected."); + + #endregion + #region Archive Feature archive = new Feature( @@ -345,6 +367,7 @@ output dir. The files will be placed in the specified location using a folder structure according to the original DAT master directory tree structure."); build.AddFeature(outStringInput); build.AddFeature(fixdatOnlyFlag); + build.AddFeature(copyFlag); build.AddFeature(workersInt32Input); build.AddFeature(subworkersInt32Input); @@ -560,6 +583,9 @@ structure. It also deletes the specified DATs from the DAT index."); "purge-delete", "Deletes DAT index entries for orphaned DATs", FeatureType.Flag); + purgeDelete.AddFeature(workersInt32Input); + purgeDelete.AddFeature(depotListStringInput); + purgeDelete.AddFeature(datsListStringInput); purgeDelete.AddFeature(logOnlyFlag); #endregion @@ -615,6 +641,7 @@ contents of any changed dats."); // Now, add all of the main features to the Help object help.Add(helpFeature); + help.Add(script); help.Add(archive); help.Add(build); help.Add(cancel); diff --git a/RombaSharp/RombaSharp.Inits.cs b/RombaSharp/RombaSharp.Inits.cs index 88f4b1bf..e5be8b2b 100644 --- a/RombaSharp/RombaSharp.Inits.cs +++ b/RombaSharp/RombaSharp.Inits.cs @@ -25,8 +25,28 @@ namespace RombaSharp /// /// List of input folders to use /// True if only files in the database and don't exist are added, false otherwise - private static void InitArchive(List inputs, bool onlyNeeded) + /// Resume a previously interrupted operation from the specified path + /// flag value == 1 means: add Zip files themselves into the depot in addition to their contents, flag value > 1 means add Zip files themselves but don't add content + /// How many workers to launch for the job, default from config + /// flag value == 1 means: add GZip files themselves into the depot in addition to their contents, flag value > 1 means add GZip files themselves but don't add content + /// flag value == 1 means: add 7Zip files themselves into the depot in addition to their contents, flag value > 1 means add 7Zip files themselves but don't add content + /// True to skip the initial scan of the files to determine amount of work, false otherwise + /// True to use go zip implementation instead of zlib, false otherwise + /// True to archive into depot but do not touch DB index and ignore only-needed flag, false otherwise + private static void InitArchive( + List inputs, + bool onlyNeeded, + string resume, + int includeZips, + int workers, + int includeGZips, + int include7Zips, + bool skipInitialScan, + bool useGolangZip, + bool noDb) { + Globals.Logger.Error("This feature is not yet implemented: archive"); + // First we want to get just all directories from the inputs List onlyDirs = new List(); foreach (string input in inputs) @@ -185,8 +205,18 @@ namespace RombaSharp /// Wrap building all files from a set of DATs /// /// List of input DATs to rebuild from + /// Output file + /// True to only fix dats and don't generate torrentzips, false otherwise /// True if files should be copied to output, false for rebuild - private static void InitBuild(List inputs, bool copy) + /// How many workers to launch for the job, default from config + /// How many subworkers to launch for each worker, default from config + private static void InitBuild( + List inputs, + string outdat, + bool fixdatOnly, + bool copy, + int workers, + int subworkers) { // Verify the filenames Dictionary foundDats = GetValidDats(inputs); @@ -223,74 +253,126 @@ namespace RombaSharp } /// - /// Wrap finding all files that are in both the database and a new Dat + /// Wrap cancelling a long-running job /// - /// - private static void InitDiffDat(string newdat) + private static void InitCancel() { - Globals.Logger.User("This feature is not yet implemented: diffdat"); - - // First, we want to read in the DAT. Then for each file listed in the DAT, we check if it's in there or not. - // If it is in there, we add it to an output DAT. If it's not, we skip. Then we output the DAT. + Globals.Logger.Error("This feature is not yet implemented: cancel"); } /// - /// Wrap creating a Dat from a directory + /// Wrap printing dat stats /// - /// - private static void InitDir2Dat(List inputs) + /// List of input DATs to get stats from + private static void InitDatStats(List inputs) { - // Create a simple Dat output - DatFile datdata = new DatFile() - { - FileName = Path.GetFileName(inputs[0]) + " Dir2Dat", - Name = Path.GetFileName(inputs[0]) + " Dir2Dat", - Description = Path.GetFileName(inputs[0]) + " Dir2Dat", - DatFormat = DatFormat.Logiqx, - }; + Globals.Logger.Error("This feature is not yet implemented: datstats"); + } - foreach (string input in inputs) - { - // TODO: All instances of Hash.DeepHashes should be made into 0x0 eventually - datdata.PopulateFromDir(input, Hash.DeepHashes /* omitFromScan */, true /* bare */, false /* archivesAsFiles */, - SkipFileType.None, false /* addBlanks */, false /* addDate */, _tmpdir /* tempDir */, false /* copyFiles */, - null /* headerToCheckAgainst */, true /* chdsAsFiles */); - datdata.Write(); - } + /// + /// Wrap printing db stats + /// + private static void InitDbStats() + { + DisplayDBStats(); + } + + /// + /// Wrap creating a diffdat for a given old and new dat + /// + /// Output file + /// Old DAT file + /// New DAT file + /// Name value in DAT header + /// Description value in DAT header + private static void InitDiffDat( + string outdat, + string old, + string newdat, + string name, + string description) + { + Globals.Logger.Error("This feature is not yet implemented: diffdat"); + } + + /// + /// Wrap creating a dir2dat from a given source + /// + /// Output file + /// Source directory + /// Name value in DAT header + /// Description value in DAT header + private static void InitDir2Dat( + string outdat, + string source, + string name, + string description) + { + Globals.Logger.Error("This feature is not yet implemented: dir2dat"); + } + + /// + /// Wrap creating a diffdat for a given old and new dat + /// + /// Output file + /// Old DAT file + /// New DAT file + private static void InitEDiffDat( + string outdat, + string old, + string newdat) + { + Globals.Logger.Error("This feature is not yet implemented: ediffdat"); + } + + /// + /// Wrap exporting the database to CSV + /// + private static void InitExport() + { + ExportDatabase(); } /// /// Wrap creating a fixdat for each Dat /// - /// - private static void InitFixdat(List inputs) + /// List of input DATs to get fixdats for + /// Output directory + /// True to only fix dats and don't generate torrentzips, false otherwise + /// How many workers to launch for the job, default from config + /// How many subworkers to launch for each worker, default from config + private static void InitFixdat( + List inputs, + string outdat, + bool fixdatOnly, + int workers, + int subworkers) { - Globals.Logger.User("This feature is not yet implemented: fixdat"); - - // Verify the filenames - Dictionary foundDats = GetValidDats(inputs); - - // Once we have each DAT, look up each associated hash based on the hash of the DATs. - // Then, for each rom, check to see if they exist in the folder. If they don't, add it - // to the fixDAT. Then output when the DAT is done, processing, moving on to the next... - // NOTE: This might share code with InitMiss + Globals.Logger.Error("This feature is not yet implemented: fixdat"); } /// /// Wrap importing CSVs into the database /// - /// + /// List of input CSV files to import information from private static void InitImport(List inputs) { - Globals.Logger.User("This feature is not yet implemented: import"); + Globals.Logger.Error("This feature is not yet implemented: import"); } /// /// Wrap looking up if hashes exist in the database /// /// List of input strings representing hashes to check for - private static void InitLookup(List inputs) + /// Size to limit hash by, -1 otherwise + /// Output directory + private static void InitLookup( + List inputs, + long size, + string outdat) { + Globals.Logger.Error("This feature is not yet implemented: lookup"); + // First, try to figure out what type of hash each is by length and clean it List crc = new List(); List md5 = new List(); @@ -383,33 +465,130 @@ namespace RombaSharp dbc.Dispose(); } + /// + /// Wrap printing memory stats + /// + private static void InitMemstats() + { + DisplayMemoryStats(); + } + /// /// Wrap merging an external depot into an existing one /// - /// - /// - /// - private static void InitMerge(List inputs, string depotPath, bool onlyNeeded) + /// List of input depots to merge in + /// True if only files in the database and don't exist are added, false otherwise + /// Resume a previously interrupted operation from the specified path + /// How many workers to launch for the job, default from config + /// True to skip the initial scan of the files to determine amount of work, false otherwise + /// TODO: Add way of specifying "current depot" since that's what Romba relies on + private static void InitMerge( + List inputs, + bool onlyNeeded, + string resume, + int workers, + bool skipInitialscan) { - Globals.Logger.User("This feature is not yet implemented: merge"); + Globals.Logger.Error("This feature is not yet implemented: merge"); } /// /// Wrap creating a havefile and a missfile for each Dat /// - /// + /// List of DAT files to get a miss and have for private static void InitMiss(List inputs) { - Globals.Logger.User("This feature is not yet implemented: miss"); + Globals.Logger.Error("This feature is not yet implemented: miss"); + } - // Verify the filenames - Dictionary foundDats = GetValidDats(inputs); + /// + /// Wrap showing progress of currently running command + /// + private static void InitProgress() + { + Globals.Logger.Error("This feature is not yet implemented: progress"); + } - // Once we have each DAT, look up each associated hash based on the hash of the DATs. - // Then, for each rom, check to see if they exist in the folder. If they do, add it - // to the have DAT, else wise go to the miss DAT. Then output both when the DAT is done - // processing, moving on to the next... - // NOTE: This might share code with InitFixdat + /// + /// Wrap backing up of no longer needed files from the depots + /// + /// Backup directory where backup files are moved to + /// How many workers to launch for the job, default from config + /// List of depots to scan files in, empty means all + /// List of DATs to use as the basis of scanning, empty means all + /// True if only the output of the operation is shown, false to actually run + private static void InitPurgeBackup( + string backup, + int workers, + List depot, + List dats, + bool logOnly) + { + Globals.Logger.Error("This feature is not yet implemented: purge-backup"); + + PurgeBackup(logOnly); + } + + /// + /// Wrap deleting of no longer needed files from the depots + /// + /// How many workers to launch for the job, default from config + /// List of depots to scan files in, empty means all + /// List of DATs to use as the basis of scanning, empty means all + /// True if only the output of the operation is shown, false to actually run + private static void InitPurgeDelete( + int workers, + List depot, + List dats, + bool logOnly) + { + Globals.Logger.Error("This feature is not yet implemented: purge-delete"); + + PurgeDelete(logOnly); + } + + /// + /// Wrap refreshing the database with potentially new dats + /// + /// How many workers to launch for the job, default from config + /// Write paths of dats with missing sha1s into this file + private static void InitRefreshDats( + int workers, + string missingSha1s) + { + Globals.Logger.Error("This feature is not yet implemented: refresh-dats"); + + RefreshDatabase(); + } + + /// + /// Wrap rescanning depots + /// + /// List of depots to rescan, empty means all + private static void InitRescanDepots(List inputs) + { + Globals.Logger.Error("This feature is not yet implemented: rescan-depots"); + + foreach (string depot in inputs) + { + Rescan(depot); + } + } + + /// + /// Wrap gracefully shutting down the server + /// + private static void InitShutdown() + { + Globals.Logger.Error("This feature is not yet implemented: shutdown"); + } + + /// + /// Wrap printing the version + /// + private static void InitVersion() + { + Globals.Logger.Error("This feature is not yet implemented: version"); } #endregion diff --git a/RombaSharp/RombaSharp.cs b/RombaSharp/RombaSharp.cs index 0eb03cf0..738f5a97 100644 --- a/RombaSharp/RombaSharp.cs +++ b/RombaSharp/RombaSharp.cs @@ -59,12 +59,24 @@ namespace RombaSharp DatabaseTools.EnsureDatabase(_dbSchema, _db, _connectionString); // Create a new Help object for this program - _help = RetrieveHelp(); + _help = RombaSharp.RetrieveHelp(); - // If output is being redirected, don't allow clear screens - if (!Console.IsOutputRedirected) + // Get the location of the script tag, if it exists + int scriptLocation = (new List(args)).IndexOf("--script"); + + // If output is being redirected or we are in script mode, don't allow clear screens + if (!Console.IsOutputRedirected && scriptLocation == -1) { Console.Clear(); + Build.PrepareConsole("RombaSharp"); + } + + // Now we remove the script tag because it messes things up + if (scriptLocation > -1) + { + List newargs = new List(args); + newargs.RemoveAt(scriptLocation); + args = newargs.ToArray(); } // Credits take precidence over all @@ -85,13 +97,31 @@ namespace RombaSharp // User flags bool copy = false, + fixdatOnly = false, logOnly = false, - onlyNeeded = false; + noDb = false, + onlyNeeded = false, + skipInitialScan = false, + useGolangZip = false; // User inputs - string depotPath = "", + string backup = "", + description = "", + missingSha1s = "", + name = "", newdat = "", - outdat = ""; + old = "", + outdat = "", + resume = "", + source = ""; + int include7Zips = 0, + includeGZips = 0, + includeZips = 0, + subworkers = 0, + workers = 0; + long size = -1; + List dats = new List(); + List depot = new List(); List inputs = new List(); // Get the first argument as a feature flag @@ -154,27 +184,102 @@ namespace RombaSharp // Check all of the flag names and translate to arguments switch (feat.Key) { - // User flags + #region User Flags + case "copy": copy = true; break; + case "fixdatOnly": + fixdatOnly = true; + break; case "log-only": logOnly = true; break; + case "no-db": + noDb = true; + break; case "only-needed": onlyNeeded = true; break; + case "skip-initial-scan": + skipInitialScan = true; + break; + case "use-golang-zip": + useGolangZip = true; + break; - // User inputs + #endregion + + #region User Int32 Inputs + + case "include-7zips": + include7Zips = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 0; + break; + case "include-gzips": + includeGZips = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 0; + break; + case "include-zips": + includeZips = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : 0; + break; + case "subworkers": + subworkers = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : _cores; + break; + case "workers": + workers = (int)feat.Value.GetValue() == Int32.MinValue ? (int)feat.Value.GetValue() : _cores; + break; + + #endregion + + #region User Int64 Inputs + + case "size": + size = (long)feat.Value.GetValue() == Int64.MinValue ? (long)feat.Value.GetValue() : 0; + break; + + #endregion + + #region User List Inputs + + case "dats": + dats.AddRange((List)feat.Value.GetValue()); + break; case "depot": - depotPath = (string)feat.Value.GetValue(); + depot.AddRange((List)feat.Value.GetValue()); + break; + + #endregion + + #region User String Inputs + + case "backup": + backup = (string)feat.Value.GetValue(); + break; + case "description": + description = (string)feat.Value.GetValue(); + break; + case "missingSha1s": + missingSha1s = (string)feat.Value.GetValue(); + break; + case "name": + name = (string)feat.Value.GetValue(); break; case "new": newdat = (string)feat.Value.GetValue(); break; + case "old": + old = (string)feat.Value.GetValue(); + break; case "out": outdat = (string)feat.Value.GetValue(); break; + case "resume": + resume = (string)feat.Value.GetValue(); + break; + case "source": + source = (string)feat.Value.GetValue(); + break; + + #endregion } } @@ -187,44 +292,48 @@ namespace RombaSharp // Adds ROM files from the specified directories to the ROM archive case "Archive": VerifyInputs(inputs, feature); - InitArchive(inputs, onlyNeeded); + InitArchive(inputs, onlyNeeded, resume, includeZips, workers, includeGZips, include7Zips, skipInitialScan, useGolangZip, noDb); break; // For each specified DAT file it creates the torrentzip files case "Build": VerifyInputs(inputs, feature); - InitBuild(inputs, copy); + InitBuild(inputs, outdat, fixdatOnly, copy, workers, subworkers); + break; + // Cancels current long-running job + case "Cancel": + InitCancel(); + break; + // Prints dat stats + case "DatStats": + VerifyInputs(inputs, feature); + InitDatStats(inputs); break; // Prints db stats - case "Stats": - DisplayDBStats(); + case "DbStats": + InitDbStats(); break; - // Rescan a specific depot - case "Rescan Depots": - VerifyInputs(inputs, feature); - foreach (string input in inputs) - { - Rescan(input); - } - break; - // Creates a DAT file with those entries that are in new DAT + // Creates a DAT file with those entries that are in -new DAT case "Diffdat": - InitDiffDat(newdat); + InitDiffDat(outdat, old, newdat, name, description); break; - // Creates a DAT file for the specified input directory + // Creates a DAT file for the specified input directory and saves it to the -out filename case "Dir2Dat": - VerifyInputs(inputs, feature); - InitDir2Dat(inputs); + InitDir2Dat(outdat, source, name, description); break; - // Export the database to file + // Creates a DAT file with those entries that are in -new DAT + case "EDiffdat": + InitEDiffDat(outdat, old, newdat); + break; + // Exports db to export.csv case "Export": - ExportDatabase(); + InitExport(); break; // For each specified DAT file it creates a fix DAT case "Fixdat": VerifyInputs(inputs, feature); - InitFixdat(inputs); + InitFixdat(inputs, outdat, fixdatOnly, workers, subworkers); break; - // Import a CSV into the database + // Import a database from a formatted CSV file case "Import": VerifyInputs(inputs, feature); InitImport(inputs); @@ -232,41 +341,52 @@ namespace RombaSharp // For each specified hash it looks up any available information case "Lookup": VerifyInputs(inputs, feature); - InitLookup(inputs); + InitLookup(inputs, size, outdat); break; // Prints memory stats case "Memstats": - DisplayMemoryStats(); + InitMemstats(); break; - // Merges depots + // Merges depot case "Merge": VerifyInputs(inputs, feature); - InitMerge(inputs, depotPath, onlyNeeded); + InitMerge(inputs, onlyNeeded, resume, workers, skipInitialScan); break; - // For each specified DAT file it creates a miss file and a have file + // Create miss and have file case "Miss": VerifyInputs(inputs, feature); InitMiss(inputs); break; + // Shows progress of the currently running command + case "Progress": + InitProgress(); + break; // Moves DAT index entries for orphaned DATs case "Purge Backup": - PurgeBackup(logOnly); + InitPurgeBackup(backup, workers, depot, dats, logOnly); break; // Deletes DAT index entries for orphaned DATs case "Purge Delete": - PurgeDelete(logOnly); + InitPurgeDelete(workers, depot, dats, logOnly); break; // Refreshes the DAT index from the files in the DAT master directory tree case "Refresh DATs": - RefreshDatabase(); + InitRefreshDats(workers, missingSha1s); break; - // Shows progress of the currently running command - case "Progress": - Globals.Logger.User("This feature is not used in RombaSharp: progress"); + // Rescan a specific depot + case "Rescan Depots": + VerifyInputs(inputs, feature); + InitRescanDepots(inputs); break; + // Gracefully shuts down server case "Shutdown": - Globals.Logger.User("This feature is not used in RombaSharp: shutdown"); + InitShutdown(); break; + // Prints version + case "Version": + InitVersion(); + break; + // If nothing is set, show the help default: _help.OutputGenericHelp(); break;