public int Execute(Execution execution) { if (!Directory.Exists(execution.PackageSourceFolder)) { throw new InvalidOperationException("The source folder " + execution.PackageSourceFolder + " does not exist."); } var allowAutopackage = true; var moduleExpectedPath = Path.Combine(execution.PackageSourceFolder, "Build", "Module.xml"); ModuleInfo rootModule = null; if (!File.Exists(moduleExpectedPath)) { if (execution.PackageFilterFile == null) { Console.WriteLine( "There is no module in the path '" + execution.PackageSourceFolder + "' (expected to " + "find a Build\\Module.xml file within that directory)."); return 1; } else { // We allow this mode if the user has provided a filter file and are constructing // the package manually. allowAutopackage = false; } } else { rootModule = ModuleInfo.Load(moduleExpectedPath); } var customDirectives = new Dictionary<string, Action<FileFilter>>() { { "autopackage", f => { if (allowAutopackage && rootModule != null) { this.m_AutomaticProjectPackager.Autopackage( f, execution, rootModule, execution.PackageSourceFolder, execution.PackagePlatform); } else { Console.WriteLine( "WARNING: There is no module in the path '" + execution.PackageSourceFolder + "' (expected to " + "find a Build\\Module.xml file within that directory). Ignoring the 'autopackage' directive."); } } } }; Console.WriteLine("Starting package creation for " + execution.PackagePlatform); var filter = new FileFilter(GetRecursiveFilesInPath(execution.PackageSourceFolder)); if (execution.PackageFilterFile != null) { using (var reader = new StreamReader(execution.PackageFilterFile)) { var contents = reader.ReadToEnd(); contents = contents.Replace("%PLATFORM%", execution.PackagePlatform); using (var inputStream = new MemoryStream(Encoding.ASCII.GetBytes(contents))) { this.m_FileFilterParser.ParseAndApply(filter, inputStream, customDirectives); } } } else { customDirectives["autopackage"](filter); } if (File.Exists(execution.PackageDestinationFile)) { Console.WriteLine("The destination file " + execution.PackageDestinationFile + " already exists; it will be overwritten."); File.Delete(execution.PackageDestinationFile); } filter.ImplyDirectories(); var filterDictionary = filter.ToDictionary(k => k.Key, v => v.Value); if (!filterDictionary.ContainsValue("Build/")) { Console.WriteLine("ERROR: The Build directory does not exist in the source folder."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return 1; } if (!filterDictionary.ContainsValue("Build/Projects/")) { Console.WriteLine("ERROR: The Build\\Projects directory does not exist in the source folder."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return 1; } if (!filterDictionary.ContainsValue("Build/Module.xml")) { Console.WriteLine("ERROR: The Build\\Module.xml file does not exist in the source folder."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return 1; } if (filterDictionary.ContainsValue("Protobuild.exe")) { Console.WriteLine("ERROR: The Protobuild.exe file should not be included in the package file."); if (execution.PackageFilterFile != null) { this.PrintFilterMappings(filterDictionary); } return 1; } using (var target = new FileStream(execution.PackageDestinationFile, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { var archive = new MemoryStream(); switch (execution.PackageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: { Console.WriteLine("Writing package in tar/gzip format..."); break; } case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { Console.WriteLine("Writing package in tar/lzma format..."); break; } } switch (execution.PackageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { var state = this.m_Deduplicator.CreateState(); Console.Write("Deduplicating files in package..."); var progressHelper = new DedupProgressRenderer(filter.Count()); var current = 0; foreach (var kv in filter.OrderBy(kv => kv.Value)) { if (kv.Value.EndsWith("/")) { // Directory this.m_Deduplicator.AddDirectory(state, kv.Value); } else { // File var realFile = Path.Combine(execution.PackageSourceFolder, kv.Key); var realFileInfo = new FileInfo(realFile); this.m_Deduplicator.AddFile(state, realFileInfo, kv.Value); } current++; progressHelper.SetProgress(current); } Console.WriteLine(); Console.WriteLine("Adding files to package..."); using (var writer = new tar_cs.TarWriter(archive)) { this.m_Deduplicator.PushToTar(state, writer); } break; } } archive.Seek(0, SeekOrigin.Begin); switch (execution.PackageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: { Console.WriteLine("Compressing package..."); using (var compress = new GZipStream(target, CompressionMode.Compress)) { archive.CopyTo(compress); } break; } case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { Console.Write("Compressing package..."); var progressHelper = new CompressProgressRenderer(archive.Length); LZMA.LzmaHelper.Compress(archive, target, progressHelper); Console.WriteLine(); break; } } } Console.WriteLine("\rPackage written to " + execution.PackageDestinationFile + " successfully."); return 0; }
public void Create(Stream target, FileFilter filter, string basePath, string packageFormat) { Stream archive = new MemoryStream(); string cleanUp = null; try { switch (packageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: { Console.WriteLine("Writing package in tar/gzip format..."); break; } case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { Console.WriteLine("Writing package in tar/lzma format..."); break; } } switch (packageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { var state = _deduplicator.CreateState(); Console.Write("Deduplicating files in package..."); var progressHelper = new DedupProgressRenderer(filter.Count()); var current = 0; foreach (var kv in filter.OrderBy(kv => kv.Value)) { if (kv.Value.EndsWith("/")) { // Directory _deduplicator.AddDirectory(state, kv.Value); } else { // File var realFile = Path.Combine(basePath, kv.Key); var realFileInfo = new FileInfo(realFile); _deduplicator.AddFile(state, realFileInfo, kv.Value); } current++; progressHelper.SetProgress(current); } Console.WriteLine(); Console.WriteLine("Adding files to package..."); try { using (var writer = new tar_cs.TarWriter(archive)) { _deduplicator.PushToTar(state, writer); } } catch (OutOfMemoryException ex) { // It's possible the archive is too large to store in memory. Fall // back to using a temporary file on disk. cleanUp = Path.GetTempFileName(); Console.WriteLine( "WARNING: Out-of-memory while creating TAR file, falling back to storing " + "temporary file on disk at " + cleanUp + " during package creation."); archive.Dispose(); archive = new FileStream(cleanUp, FileMode.Create, FileAccess.ReadWrite); using (var writer = new tar_cs.TarWriter(archive)) { _deduplicator.PushToTar(state, writer); } } break; } } archive.Seek(0, SeekOrigin.Begin); switch (packageFormat) { case PackageManager.ARCHIVE_FORMAT_TAR_GZIP: { Console.WriteLine("Compressing package..."); using (var compress = new GZipStream(target, CompressionMode.Compress)) { archive.CopyTo(compress); } break; } case PackageManager.ARCHIVE_FORMAT_TAR_LZMA: default: { Console.Write("Compressing package..."); var progressHelper = new CompressProgressRenderer(archive.Length); LZMA.LzmaHelper.Compress(archive, target, progressHelper); Console.WriteLine(); break; } } } finally { if (cleanUp != null) { try { File.Delete(cleanUp); } catch { Console.WriteLine("WARNING: Unable to clean up temporary package file at " + cleanUp); } } } }
static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("must have at least 1 argument."); return; } switch (args[0]) { case "create": { if (args.Length < 2) { Console.WriteLine("must have at least 2 arguments (create <appname>)."); return; } string appname = args[1]; Cache c = new Cache(false); if (c.Exists("server/" + appname)) { Console.WriteLine("this app is already created."); return; } if (!File.Exists(".pvdeploy")) { Console.WriteLine("no .pvdeploy file found; please create one."); return; } FileFilter filter = FileFilterParser.Parse(".pvdeploy", GetRecursiveFilesInCwd()); foreach (KeyValuePair <string, string> kv in filter) { // Key is original filename. // Value is filename to store as. Hash hash = Hash.FromFile(Path.Combine(Environment.CurrentDirectory, kv.Key)); Console.WriteLine(Hash.Empty.ToString() + " => " + hash.ToString() + " " + kv.Value); c.Set <Hash>("server/" + appname + "/hashes/" + kv.Value, hash); if (c.Exists("server/" + appname + "/store/" + kv.Value)) { c.Delete("server/" + appname + "/store/" + kv.Value); } File.Copy(Path.Combine(Environment.CurrentDirectory, kv.Key), c.GetFilePath("server/" + appname + "/store/" + kv.Value)); } return; } case "test-pvdeploy": { if (args.Length < 1) { Console.WriteLine("must have at least 1 argument (test-pvdeploy)."); return; } if (!File.Exists(".pvdeploy")) { Console.WriteLine("no .pvdeploy file found; please create one."); return; } FileFilter filter = FileFilterParser.Parse(".pvdeploy", GetRecursiveFilesInCwd()); foreach (KeyValuePair <string, string> kv in filter) { // Key is original filename. // Value is filename to store as. Console.WriteLine(kv.Key + " => " + kv.Value); } return; } case "flash": { if (args.Length < 2) { Console.WriteLine("must have at least 2 arguments (flash <appname>)."); return; } string appname = args[1]; Cache c = new Cache(false); if (!c.Exists("server/" + appname)) { Console.WriteLine("use create to create this app first."); return; } if (!File.Exists(".pvdeploy")) { Console.WriteLine("no .pvdeploy file found; please create one."); return; } // Find all files in the current working directory. diff_match_patch dmf = new diff_match_patch(); FileFilter filter = FileFilterParser.Parse(".pvdeploy", GetRecursiveFilesInCwd()); foreach (KeyValuePair <string, string> kv in filter) { if (c.Exists("server/" + appname + "/store/" + kv.Value)) { // File is being updated, get a hash for the current version // and for the stored version. Hash oldHash = Hash.FromFile(c.GetFilePath("server/" + appname + "/store/" + kv.Value)); Hash newHash = Hash.FromFile(Path.Combine(Environment.CurrentDirectory, kv.Key)); if (oldHash != newHash) { // Files are different, produce a diff. byte[] oldData = FileUtils.GetAllBytes(c.GetFilePath("server/" + appname + "/store/" + kv.Value)); byte[] newData = FileUtils.GetAllBytes(Path.Combine(Environment.CurrentDirectory, kv.Key)); List <Patch> patches = dmf.patch_make(Encoding.ASCII.GetString(oldData), Encoding.ASCII.GetString(newData)); string result = dmf.patch_toText(patches); c.Set <string>("server/" + appname + "/patches/" + kv.Value + "/" + oldHash + "-" + newHash, result); c.Set <Hash>("server/" + appname + "/hashes/" + kv.Value, newHash); if (c.Exists("server/" + appname + "/store/" + kv.Value)) { c.Delete("server/" + appname + "/store/" + kv.Value); } File.Copy(Path.Combine(Environment.CurrentDirectory, kv.Key), c.GetFilePath("server/" + appname + "/store/" + kv.Value)); if (!c.Exists("server/" + appname + "/store/" + kv.Value)) { throw new InvalidOperationException("Unable to copy file to server store."); } Console.WriteLine(oldHash + " => " + newHash + " " + kv.Value); } } else { // A new file is being stored. Hash newHash = Hash.FromFile(Path.Combine(Environment.CurrentDirectory, kv.Key)); byte[] newData = FileUtils.GetAllBytes(Path.Combine(Environment.CurrentDirectory, kv.Key)); List <Patch> patches = dmf.patch_make("", Encoding.ASCII.GetString(newData)); string result = dmf.patch_toText(patches); c.Set <string>("server/" + appname + "/patches/" + kv.Value + "/" + Hash.Empty + "-" + newHash, result); c.Set <Hash>("server/" + appname + "/hashes/" + kv.Value, newHash); if (c.Exists("server/" + appname + "/store/" + kv.Value)) { c.Delete("server/" + appname + "/store/" + kv.Value); } File.Copy(Path.Combine(Environment.CurrentDirectory, kv.Key), c.GetFilePath("server/" + appname + "/store/" + kv.Value)); if (!c.Exists("server/" + appname + "/store/" + kv.Value)) { throw new InvalidOperationException("Unable to copy file to server store."); } Console.WriteLine(Hash.Empty + " => " + newHash + " " + kv.Value); } } foreach (string s in c.ListRecursive("server/" + appname + "/store")) { if (filter.Count(v => v.Value == s) == 0) { // A file is being deleted. Hash oldHash = Hash.FromFile(c.GetFilePath("server/" + appname + "/store/" + s)); byte[] oldData = FileUtils.GetAllBytes(c.GetFilePath("server/" + appname + "/store/" + s)); List <Patch> patches = dmf.patch_make(Encoding.ASCII.GetString(oldData), ""); string result = dmf.patch_toText(patches); c.Set <string>("server/" + appname + "/patches/" + s + "/" + oldHash.ToString() + "-" + Hash.Empty.ToString(), result); c.Set <Hash>("server/" + appname + "/hashes/" + s, Hash.Empty); if (c.Exists("server/" + appname + "/store/" + s)) { c.Delete("server/" + appname + "/store/" + s); } if (c.Exists("server/" + appname + "/store/" + s)) { throw new InvalidOperationException("Unable to delete file from server store."); } Console.WriteLine(oldHash + " => " + Hash.Empty + " " + s); } } Console.WriteLine("flash complete."); return; } case "state": { if (args.Length < 2) { Console.WriteLine("must have at least 2 arguments (state <appname>)."); return; } string appname = args[1]; Cache c = new Cache(false); if (!c.Exists("server/" + appname)) { Console.WriteLine("this app does not exist."); return; } foreach (string s in c.ListRecursive("server/" + appname + "/hashes")) { Console.WriteLine(c.Get <Hash>("server/" + appname + "/hashes/" + s) + " " + s); } return; } default: Console.WriteLine("invalid command (must be 'flash', 'create', 'state' or 'test-pvdeploy')."); return; } }