/// <summary> /// Returns true if it's either an empty directory or it contains CanvasManifest.json file. /// </summary> /// <returns></returns> private bool ValidateSafeToDelete(ErrorContainer errors) { if (Directory.EnumerateFiles(_directory).Any() && !File.Exists(Path.Combine(_directory, "CanvasManifest.json"))) { errors.BadParameter("Must provide path to either empty directory or a directory where the app was previously unpacked."); throw new DocumentException(); } return(true); }
// Write back out to a msapp file. public static void SaveAsMsApp(CanvasDocument app, string fullpathToMsApp, ErrorContainer errors, bool isValidation = false) { app.ApplyBeforeMsAppWriteTransforms(errors); if (!fullpathToMsApp.EndsWith(".msapp", StringComparison.OrdinalIgnoreCase) && fullpathToMsApp.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { errors.BadParameter("Only works for .msapp files"); return; } if (File.Exists(fullpathToMsApp)) // Overwrite! { File.Delete(fullpathToMsApp); } var checksum = new ChecksumMaker(); DirectoryWriter.EnsureFileDirExists(fullpathToMsApp); using (var z = ZipFile.Open(fullpathToMsApp, ZipArchiveMode.Create)) { foreach (FileEntry entry in app.GetMsAppFiles(errors)) { if (entry != null) { var e = z.CreateEntry(entry.Name.ToMsAppPath()); using (var dest = e.Open()) { dest.Write(entry.RawBytes, 0, entry.RawBytes.Length); checksum.AddFile(entry.Name.ToMsAppPath(), entry.RawBytes); } } } ComputeAndWriteChecksum(app, checksum, z, errors, isValidation); } // Undo BeforeWrite transforms so CanvasDocument representation is unchanged app.ApplyAfterMsAppLoadTransforms(errors); }
/// <summary> /// Load an .msapp file for a Canvas Document. /// </summary> /// <param name="fullPathToMsApp">path to an .msapp file</param> /// <returns>A tuple of the document and errors and warnings. If there are errors, the document is null. </returns> public static (CanvasDocument, ErrorContainer) LoadFromMsapp(string fullPathToMsApp) { var errors = new ErrorContainer(); Utilities.EnsurePathRooted(fullPathToMsApp); if (!fullPathToMsApp.EndsWith(".msapp", StringComparison.OrdinalIgnoreCase)) { errors.BadParameter("Only works for .msapp files"); } Utilities.VerifyFileExists(errors, fullPathToMsApp); if (errors.HasErrors) { return(null, errors); } using (var stream = new FileStream(fullPathToMsApp, FileMode.Open)) { var doc = Wrapper(() => MsAppSerializer.Load(stream, errors), errors); return(doc, errors); } }
// Full fidelity read-write public static CanvasDocument LoadFromSource(string directory2, ErrorContainer errors) { if (File.Exists(directory2)) { if (directory2.EndsWith(".msapp", StringComparison.OrdinalIgnoreCase)) { errors.BadParameter($"Must point to a source directory, not an msapp file ({directory2}"); } } Utilities.VerifyDirectoryExists(errors, directory2); if (errors.HasErrors) { return(null); } var dir = new DirectoryReader(directory2); var app = new CanvasDocument(); string appInsightsInstumentationKey = null; // Do the manifest check (and version check) first. // MAnifest lives in top-level directory. foreach (var file in dir.EnumerateFiles("", "*.json")) { switch (file.Kind) { case FileKind.CanvasManifest: var manifest = file.ToObject <CanvasManifestJson>(); if (manifest.FormatVersion != CurrentSourceVersion) { errors.FormatNotSupported($"This tool only supports {CurrentSourceVersion}, the manifest version is {manifest.FormatVersion}"); throw new DocumentException(); } app._properties = manifest.Properties; app._header = manifest.Header; app._publishInfo = manifest.PublishInfo; app._screenOrder = manifest.ScreenOrder; break; case FileKind.Templates: foreach (var kvp in file.ToObject <Dictionary <string, CombinedTemplateState> >()) { app._templateStore.AddTemplate(kvp.Key, kvp.Value); } break; case FileKind.ComponentReferences: var refs = file.ToObject <ComponentDependencyInfo[]>(); app._libraryReferences = refs; break; case FileKind.AppInsightsKey: var appInsights = file.ToObject <AppInsightsKeyJson>(); appInsightsInstumentationKey = appInsights.InstrumentationKey; break; } } if (appInsightsInstumentationKey != null) { app._properties.InstrumentationKey = appInsightsInstumentationKey; } if (app._header == null) { // Manifest not found. errors.FormatNotSupported($"Can't find CanvasManifest.json file - is sources an old version?"); throw new DocumentException(); } // Load template files, recreate References/templates.json LoadTemplateFiles(errors, app, Path.Combine(directory2, PackagesDir), out var templateDefaults); foreach (var file in dir.EnumerateFiles(EntropyDir)) { switch (file.Kind) { case FileKind.Entropy: app._entropy = file.ToObject <Entropy>(); break; case FileKind.AppCheckerResult: app._appCheckerResultJson = file.ToObject <AppCheckerResultJson>(); break; case FileKind.Checksum: app._checksum = file.ToObject <ChecksumJson>(); app._checksum.ClientBuildDetails = _buildVerJson; break; default: errors.GenericWarning($"Unexpected file in Entropy, discarding"); break; } } // The resource entries for sample data is sharded into individual json files. // Add each of these entries back into Resrouces.json var resources = new List <ResourceJson>(); app._resourcesJson = new ResourcesJson() { Resources = new ResourceJson[0] }; foreach (var file in dir.EnumerateFiles(AssetsDir, "*", false)) { var fileEntry = file.ToFileEntry(); if (fileEntry.Name.GetExtension() == ".json") { // If its a json file then this must be one of the sharded files from Resources.json resources.Add(file.ToObject <ResourceJson>()); } } // Add the resources from sharded files to _resourcesJson.Resources if (resources.Count > 0) { app._resourcesJson.Resources = resources.ToArray(); } // We have processed all the json files in Assets directory, now interate through all tge files to add the asset files. foreach (var file in dir.EnumerateFiles(AssetsDir)) { // Skip adding the json files which were created to contain the information for duplicate asset files. // The name of the such json files is of the format - <assetFileName>.<assetFileExtension>.json (eg. close_1.jpg.json) var fileName = file._relativeName; var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); // Check if the original extension was .json and the remaining file name has still got an extension, // Then this is an additional file that was created to contain information for duplicate assets. if (Path.HasExtension(fileNameWithoutExtension) && Path.GetExtension(fileName) == ".json") { var localAssetInfoJson = file.ToObject <LocalAssetInfoJson>(); app._localAssetInfoJson.Add(localAssetInfoJson.NewFileName, localAssetInfoJson); } // Add non json files to _assetFiles else if (Path.GetExtension(fileName) != ".json") { app.AddAssetFile(file.ToFileEntry()); } } app.GetLogoFile(); // Add the entries for local assets back to resrouces.json TranformResourceJson.AddLocalAssetEntriesToResourceJson(app); foreach (var file in dir.EnumerateFiles(OtherDir)) { // Special files like Header / Properties switch (file.Kind) { case FileKind.Unknown: // Track any unrecognized files so we can save back. app.AddFile(file.ToFileEntry()); break; default: // Shouldn't find anything else not unknown in here, but just ignore them for now errors.GenericWarning($"Unexpected file in Other, discarding"); break; } } // each loose file in '\other' LoadDataSources(app, dir, errors); LoadSourceFiles(app, dir, templateDefaults, errors); foreach (var file in dir.EnumerateFiles(ConnectionDir)) { // Special files like Header / Properties switch (file.Kind) { case FileKind.Connections: app._connections = file.ToObject <IDictionary <string, ConnectionJson> >(); break; } } // Defaults. // - DynamicTypes.Json, Resources.Json , Templates.Json - could all be empty // - Themes.json- default to app.OnLoadComplete(errors); return(app); }