123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- using System.Buffers;
- using System.Diagnostics;
- using System.IO.Compression;
- namespace PackTool
- {
- internal static partial class ZipFileUtils
- {
- // Per the .ZIP File Format Specification 4.4.17.1 all slashes should be forward slashes
- private const char PathSeparatorChar = '/';
- private const string PathSeparatorString = "/";
- public static string EntryFromPath(string entry, int offset, int length, ref char[] buffer, bool appendPathSeparator = false)
- {
- Debug.Assert(length <= entry.Length - offset);
- Debug.Assert(buffer != null);
- // Remove any leading slashes from the entry name:
- while (length > 0)
- {
- if (entry[offset] != Path.DirectorySeparatorChar &&
- entry[offset] != Path.AltDirectorySeparatorChar)
- break;
- offset++;
- length--;
- }
- if (length == 0)
- return appendPathSeparator ? PathSeparatorString : string.Empty;
- int resultLength = appendPathSeparator ? length + 1 : length;
- EnsureCapacity(ref buffer, resultLength);
- entry.CopyTo(offset, buffer, 0, length);
- // '/' is a more broadly recognized directory separator on all platforms (eg: mac, linux)
- // We don't use Path.DirectorySeparatorChar or AltDirectorySeparatorChar because this is
- // explicitly trying to standardize to '/'
- for (int i = 0; i < length; i++)
- {
- char ch = buffer[i];
- if (ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar)
- buffer[i] = PathSeparatorChar;
- }
- if (appendPathSeparator)
- buffer[length] = PathSeparatorChar;
- return new string(buffer, 0, resultLength);
- }
- public static void EnsureCapacity(ref char[] buffer, int min)
- {
- Debug.Assert(buffer != null);
- Debug.Assert(min > 0);
- if (buffer.Length < min)
- {
- int newCapacity = buffer.Length * 2;
- if (newCapacity < min)
- newCapacity = min;
- char[] oldBuffer = buffer;
- buffer = ArrayPool<char>.Shared.Rent(newCapacity);
- ArrayPool<char>.Shared.Return(oldBuffer);
- }
- }
- public static bool IsDirEmpty(DirectoryInfo possiblyEmptyDir)
- {
- using (IEnumerator<string> enumerator = Directory.EnumerateFileSystemEntries(possiblyEmptyDir.FullName).GetEnumerator())
- return !enumerator.MoveNext();
- }
- }
- class Program
- {
- private static void CreateZipFileFromDir(string sourceDirectoryName, string destinationArchiveFileName, string[] excludeFolders)
- {
- sourceDirectoryName = Path.GetFullPath(sourceDirectoryName);
- destinationArchiveFileName = Path.GetFullPath(destinationArchiveFileName);
- using (ZipArchive archive = ZipFile.Open(destinationArchiveFileName, ZipArchiveMode.Create))
- {
- //add files and directories
- DirectoryInfo di = new DirectoryInfo(sourceDirectoryName);
- var basePath = di.FullName;
- // Windows' MaxPath (260) is used as an arbitrary default capacity, as it is likely
- // to be greater than the length of typical entry names from the file system, even
- // on non-Windows platforms. The capacity will be increased, if needed.
- const int DefaultCapacity = 260;
- char[] entryNameBuffer = ArrayPool<char>.Shared.Rent(DefaultCapacity);
- try
- {
- foreach (FileSystemInfo file in di.EnumerateFileSystemInfos("*", SearchOption.AllDirectories))
- {
- bool exclude = false;
- var fileName = file.FullName.ToLower();
- foreach(var excludeFolder in excludeFolders)
- {
- if (fileName.StartsWith(excludeFolder))
- {
- exclude = true;
- break;
- }
- }
- if (exclude)
- {
- continue;
- }
- int entryNameLength = file.FullName.Length - basePath.Length;
- if (file is FileInfo)
- {
- // Create entry for file:
- string entryName = ZipFileUtils.EntryFromPath(file.FullName, basePath.Length, entryNameLength, ref entryNameBuffer);
- ZipFileExtensions.CreateEntryFromFile(archive, file.FullName, entryName);
- }
- else
- {
- // Entry marking an empty dir:
- if (file is DirectoryInfo possiblyEmpty && ZipFileUtils.IsDirEmpty(possiblyEmpty))
- {
- // FullName never returns a directory separator character on the end,
- // but Zip archives require it to specify an explicit directory:
- string entryName = ZipFileUtils.EntryFromPath(file.FullName, basePath.Length, entryNameLength, ref entryNameBuffer, appendPathSeparator: true);
- archive.CreateEntry(entryName);
- }
- }
- } // foreach
- }
- finally
- {
- ArrayPool<char>.Shared.Return(entryNameBuffer);
- }
- }
- }
- private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
- {
- // Get the subdirectories for the specified directory.
- DirectoryInfo dir = new DirectoryInfo(sourceDirName);
- if (!dir.Exists)
- {
- throw new DirectoryNotFoundException(
- "Source directory does not exist or could not be found: "
- + sourceDirName);
- }
- DirectoryInfo[] dirs = dir.GetDirectories();
- // If the destination directory doesn't exist, create it.
- Directory.CreateDirectory(destDirName);
- // Get the files in the directory and copy them to the new location.
- FileInfo[] files = dir.GetFiles();
- foreach (FileInfo file in files)
- {
- string tempPath = Path.Combine(destDirName, file.Name);
- file.CopyTo(tempPath, true);
- }
- // If copying subdirectories, copy them and their contents to new location.
- if (copySubDirs)
- {
- foreach (DirectoryInfo subdir in dirs)
- {
- string tempPath = Path.Combine(destDirName, subdir.Name);
- DirectoryCopy(subdir.FullName, tempPath, copySubDirs);
- }
- }
- }
- private static void CopyFiles(string reveiveSource, string copyDest, string repoName, string productName, bool unzip)
- {
- var distRootFolder = Environment.GetEnvironmentVariable("DistFolder");
- if (string.IsNullOrEmpty(distRootFolder))
- {
- Console.WriteLine("The environment variable [DistFolder] is missing, use default dist folder.");
- //Using default repackFolder
- distRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Packages");
- }
- if (!Directory.Exists(distRootFolder))
- {
- Directory.CreateDirectory(distRootFolder);
- }
- var repoDistFolder = Path.Combine(distRootFolder, repoName, "Dist");
- if (!Directory.Exists(repoDistFolder))
- {
- Directory.CreateDirectory(repoDistFolder);
- }
- var productRootFolder = Environment.GetEnvironmentVariable("ProductFolder");
- if (string.IsNullOrEmpty(productRootFolder))
- {
- Console.WriteLine("The environment variable [ProductFolder] is missing, use default product folder.");
- //Using default repackFolder
- productRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Product");
- }
- if (!Directory.Exists(productRootFolder))
- {
- Directory.CreateDirectory(productRootFolder);
- }
- var productFolder = Path.Combine(productRootFolder, productName);
- if (!Directory.Exists(productFolder))
- {
- Directory.CreateDirectory(productFolder);
- }
- var source = Path.Combine(repoDistFolder, reveiveSource);
- var dest = Path.Combine(productFolder, copyDest);
- if (!File.Exists(source) && !Directory.Exists(source))
- {
- Console.WriteLine($"The received file/s {reveiveSource} can not be found.");
- return;
- }
- if (File.Exists(source))
- {
- if (unzip)
- {
- ZipFile.ExtractToDirectory(source, dest, true);
- }
- else
- {
- var destInfo = new FileInfo(dest);
- if (destInfo.Directory != null)
- {
- var destFolder = destInfo.Directory.FullName;
- if (!Directory.Exists(destFolder))
- {
- Directory.CreateDirectory(destFolder);
- }
- }
- File.Copy(source, dest, true);
- }
- }
- else
- {
- if (!Directory.Exists(dest))
- {
- Directory.CreateDirectory(dest);
- }
- DirectoryCopy(source, dest, true);
- }
- }
- private static void UpdateVersion(string productName, string repoName, string repoVersion)
- {
- var productRootFolder = Environment.GetEnvironmentVariable("ProductFolder");
- if (string.IsNullOrEmpty(productRootFolder))
- {
- Console.WriteLine("The environment variable [ProductFolder] is missing, use default product folder.");
- //Using default repackFolder
- productRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Product");
- }
- if (!Directory.Exists(productRootFolder))
- {
- Directory.CreateDirectory(productRootFolder);
- }
- var productFolder = Path.Combine(productRootFolder, productName);
- if (!Directory.Exists(productFolder))
- {
- Directory.CreateDirectory(productFolder);
- }
- var projectVersionFile = Path.Combine(productFolder, "Versions.txt");
- var versions = new List<string>();
- if (File.Exists(projectVersionFile))
- {
- versions = File.ReadLines(projectVersionFile).ToList();
- bool updated = false;
- for (var i = 0; i < versions.Count; i++)
- {
- var line = versions[i];
- var nameAndVersion = line.Split('=');
- var name = nameAndVersion[0];
- if (name == repoName)
- {
- versions[i] = repoName + "=" + repoVersion;
- File.WriteAllLines(projectVersionFile, versions);
- updated = true;
- break;
- }
- }
- if (!updated)
- {
- versions.Add(repoName + "=" + repoVersion);
- File.WriteAllLines(projectVersionFile, versions);
- }
- }
- else
- {
- versions.Add(repoName + "=" + repoVersion);
- File.WriteAllLines(projectVersionFile, versions);
- }
- }
- private static void RepackProduct(string productName, string[] excludeFolderNames, bool attachTimestamp)
- {
- var productRootFolder = Environment.GetEnvironmentVariable("ProductFolder");
- if (string.IsNullOrEmpty(productRootFolder))
- {
- Console.WriteLine("The environment variable [ProductFolder] is missing, use default product folder.");
- //Using default repackFolder
- productRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Product");
- }
- if (!Directory.Exists(productRootFolder))
- {
- Directory.CreateDirectory(productRootFolder);
- }
- var productFolder = Path.Combine(productRootFolder, productName);
- if (!Directory.Exists(productFolder))
- {
- Directory.CreateDirectory(productFolder);
- }
- var excludeFolders = new List<string>();
- foreach (var excludeFolderName in excludeFolderNames)
- {
- excludeFolders.Add(Path.Combine(productFolder.ToLower(), excludeFolderName.ToLower()));
- }
- var repackRootFolder = Environment.GetEnvironmentVariable("RepackFolder");
- if (string.IsNullOrEmpty(repackRootFolder))
- {
- Console.WriteLine("The environment variable [RepackFolder] is missing, use default repack folder.");
- //Using default repackFolder
- repackRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Repack");
- }
- if (!Directory.Exists(repackRootFolder))
- {
- Directory.CreateDirectory(repackRootFolder);
- }
- var repackFolder = Path.Combine(repackRootFolder, productName, DateTime.Now.ToString("yyyyMMdd"));
- if (!Directory.Exists(repackFolder))
- {
- Directory.CreateDirectory(repackFolder);
- }
- var repackFilePath = Path.Combine(repackFolder, $"{productName}.zip");
- if (attachTimestamp)
- {
- var timestamp = DateTime.Now.ToString("yyyyMMdd");
- var buildTime = 1;
- var formattedBuildTime = buildTime.ToString("D2");
- repackFilePath = Path.Combine(repackFolder, $"{productName}_{timestamp}.{formattedBuildTime}.zip");
- while (File.Exists(repackFilePath))
- {
- buildTime++;
- formattedBuildTime = buildTime.ToString("D2");
- repackFilePath = Path.Combine(repackFolder, $"{productName}_{timestamp}.{formattedBuildTime}.zip");
- }
- }
- if (File.Exists(repackFilePath))
- {
- File.Delete(repackFilePath);
- }
- CreateZipFileFromDir(productFolder, repackFilePath, excludeFolders.ToArray());
- }
- private static void HandleCopy(Dictionary<string, string> argMap)
- {
- //Copy the file/s
- if (!argMap.TryGetValue("/rs", out var receivedSource))
- {
- Console.WriteLine($"The [/rs] - received source argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/cd", out var extractDest))
- {
- Console.WriteLine($"The [/cd] - copy dest argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/pn", out var productName))
- {
- Console.WriteLine($"The [/pn] - product name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/rn", out var repoName))
- {
- Console.WriteLine($"The [/rn] - repo name argument is missing.");
- return;
- }
- var unzip = false;
- if (argMap.TryGetValue("/unzip", out var unzipStr))
- {
- if (!bool.TryParse(unzipStr, out unzip))
- {
- Console.WriteLine($"The unzip argument {unzipStr} is not a bool value.");
- }
- }
- CopyFiles(receivedSource, extractDest, repoName, productName, unzip);
- }
- private static void HandleUpdateVersion(Dictionary<string, string> argMap)
- {
- //Only update version.
- if (!argMap.TryGetValue("/pn", out var productName))
- {
- Console.WriteLine($"The [/pn] - product name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/rn", out var repoName))
- {
- Console.WriteLine($"The [/rn] - repo name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/rv", out var repoVersion))
- {
- Console.WriteLine($"The [/rv] - repo version argument is missing.");
- return;
- }
- UpdateVersion(productName, repoName, repoVersion);
- }
- private static void HandleRepack(Dictionary<string, string> argMap)
- {
- if (!argMap.TryGetValue("/pn", out var productName))
- {
- Console.WriteLine($"The [/pn] - product name argument is missing.");
- return;
- }
- var excludFoldereNames = new List<string>();
- if (argMap.TryGetValue("/ef", out var excludes))
- {
- excludFoldereNames.AddRange(excludes.Split(','));
- }
- Console.WriteLine($"Exclude folders: [{string.Join(',', excludFoldereNames)}]");
- var attachTimestamp = true;
- if (argMap.TryGetValue("/at", out var attachTimestampStr))
- {
- if (!bool.TryParse(attachTimestampStr, out attachTimestamp))
- {
- Console.WriteLine($"The attachTimestamp argument {attachTimestampStr} is not a bool value.");
- }
- }
- RepackProduct(productName, excludFoldereNames.ToArray(), attachTimestamp);
- }
- private static void HandleFull(Dictionary<string, string> argMap)
- {
- if (!argMap.TryGetValue("/rs", out var receivedSource))
- {
- Console.WriteLine($"The [/rs] - received source argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/cd", out var extractDest))
- {
- Console.WriteLine($"The [/cd] - copy dest argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/pn", out var productName))
- {
- Console.WriteLine($"The [/pn] - product name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/rn", out var repoName))
- {
- Console.WriteLine($"The [/rn] - repo name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/rv", out var repoVersion))
- {
- Console.WriteLine($"The [/rv] - repo version argument is missing.");
- return;
- }
- var excludFoldereNames = new List<string>();
- if (argMap.TryGetValue("/ef", out var excludes))
- {
- excludFoldereNames.AddRange(excludes.Split(','));
- }
- var unzip = false;
- if (argMap.TryGetValue("/unzip", out var unzipStr))
- {
- if (!bool.TryParse(unzipStr, out unzip))
- {
- Console.WriteLine($"The unzip argument {unzipStr} is not a bool value.");
- }
- }
- CopyFiles(receivedSource, extractDest, repoName, productName, unzip);
- UpdateVersion(productName, repoName, repoVersion);
- var attachTimestamp = true;
- if (argMap.TryGetValue("/at", out var attachTimestampStr))
- {
- if (!bool.TryParse(attachTimestampStr, out attachTimestamp))
- {
- Console.WriteLine($"The attachTimestamp argument {attachTimestampStr} is not a bool value.");
- }
- }
- RepackProduct(productName, excludFoldereNames.ToArray(), attachTimestamp);
- }
- private static void StartInno(string innoSourceFileName, string setupSource, string productName, string productVersion, string outputDir)
- {
- var productRootFolder = Environment.GetEnvironmentVariable("ProductFolder");
- if (string.IsNullOrEmpty(productRootFolder))
- {
- Console.WriteLine("The environment variable [ProductFolder] is missing, use default product folder.");
- //Using default repackFolder
- productRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Product");
- }
- if (!Directory.Exists(productRootFolder))
- {
- Directory.CreateDirectory(productRootFolder);
- }
- var productFolder = Path.Combine(productRootFolder, productName);
- if (!Directory.Exists(productFolder))
- {
- Directory.CreateDirectory(productFolder);
- }
- var innoSourceFilePath = Path.Combine(productFolder, innoSourceFileName);
- var projectSetupSource = Path.Combine(productFolder, setupSource);
- var setupOutputDir = Path.Combine(productFolder, outputDir);
- if (!File.Exists(innoSourceFilePath))
- {
- Console.WriteLine("The inno setup source file does not exist.");
- return;
- }
- if (!Directory.Exists(projectSetupSource))
- {
- Console.WriteLine("The setup project source folder does not exist");
- return;
- }
- if (Directory.GetFiles(projectSetupSource).Length == 0)
- {
- Console.WriteLine("No file in setup project source folder.");
- return;
- }
- if (!Directory.Exists(setupOutputDir))
- {
- Directory.CreateDirectory(setupOutputDir);
- }
- var iscc_argument = $"/dProjectFolder={projectSetupSource} /dSetupAppVersion={productVersion} /dSetupOutputDir={setupOutputDir} {innoSourceFilePath}";
- Console.WriteLine($"Inno arg: {iscc_argument}");
- var process = Process.Start(new ProcessStartInfo("ISCC", iscc_argument) { UseShellExecute = true });
- process?.WaitForExit();
- }
- private static void HandleInno(Dictionary<string, string> argMap)
- {
- if (!argMap.TryGetValue("/pn", out var productName))
- {
- Console.WriteLine($"The [/pn] - product name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/pv", out var productVersion))
- {
- Console.WriteLine($"The [/pv] - product version argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/ss", out var setupSource))
- {
- Console.WriteLine($"The [/ss] - setup source argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/od", out var outputDir))
- {
- Console.WriteLine($"The [/od] - output dir argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/iss", out var issFile))
- {
- Console.WriteLine($"The [/iss] - inno setup source argument is missing.");
- return;
- }
- StartInno(issFile, setupSource, productName, productVersion, outputDir);
- }
- private static void DeleteFileOrFolder(string productName, string deleteTraget)
- {
- var productRootFolder = Environment.GetEnvironmentVariable("ProductFolder");
- if (string.IsNullOrEmpty(productRootFolder))
- {
- Console.WriteLine("The environment variable [ProductFolder] is missing, use default product folder.");
- //Using default repackFolder
- productRootFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Product");
- }
- if (!Directory.Exists(productRootFolder))
- {
- Directory.CreateDirectory(productRootFolder);
- }
- var productFolder = Path.Combine(productRootFolder, productName);
- if (!Directory.Exists(productFolder))
- {
- Directory.CreateDirectory(productFolder);
- }
- var target = Path.Combine(productFolder, deleteTraget);
- if (File.Exists(target))
- {
- File.Delete(target);
- }
- else if (Directory.Exists(target))
- {
- Directory.Delete(target, true);
- }
- else
- {
- Console.WriteLine($"File or dir {deleteTraget} does not exist.");
- }
- }
- private static void HandleDelete(Dictionary<string, string> argMap)
- {
- if (!argMap.TryGetValue("/pn", out var productName))
- {
- Console.WriteLine($"The [/pn] - product name argument is missing.");
- return;
- }
- if (!argMap.TryGetValue("/dt", out var deleteTarget))
- {
- Console.WriteLine($"The [/dt] - delete target argument is missing.");
- return;
- }
- DeleteFileOrFolder(productName, deleteTarget);
- }
- static void Main(string[] args)
- {
- var argMap = new Dictionary<string, string>();
- foreach (var arg in args)
- {
- var nameAndValue = arg.Split('=');
- if (nameAndValue.Length == 2)
- {
- var name = nameAndValue[0].ToLower();
- if (string.IsNullOrEmpty(name))
- {
- Console.WriteLine("An empty arg name is not acceptable.");
- return;
- }
- if (argMap.ContainsKey(name))
- {
- Console.WriteLine($"Arg name {name} already exists");
- return;
- }
- argMap.Add(name, nameAndValue[1]);
- }
- }
- if (!argMap.TryGetValue("/mode", out var mode))
- {
- mode = "full";
- }
- Console.WriteLine($"Run in {mode} mode.");
- switch (mode)
- {
- case "full":
- //Copy files then pack the files then update the version then pack the files.
- HandleFull(argMap);
- break;
- case "copy":
- HandleCopy(argMap);
- break;
- case "version":
- HandleUpdateVersion(argMap);
- break;
- case "repack":
- //Obly Pack the files.
- HandleRepack(argMap);
- break;
- case "inno":
- HandleInno(argMap);
- break;
- case "delete":
- HandleDelete(argMap);
- break;
- default:
- Console.WriteLine($"Not suported mode: {mode}");
- break;
- }
- }
- }
- }
|