// TODO: Document public static void LoadPackageIntoStorage(ApplicationPackage package, string pathStorage) { File.Copy(package.PackagePath, Path.Combine(GetAppDirPathInStorage(package.PackageName, pathStorage), NamingHelper.GetPackageNameInStorage(package)), true); }
// TODO: Document public static string GetPackageNameInStorage(ApplicationPackage appPackage) { if (appPackage.GetType() == typeof(AndroidApplicationPackage)) { return String.Format("{0}-{1}.apk", appPackage.PackageName, appPackage.CodeVersion); } else { return String.Format("{0}-{1}", appPackage.PackageName, appPackage.CodeVersion); } }
public PatchManifest(string patchName, ApplicationPackage referencePackage, ApplicationPackage targetePackage, IEnumerable<string> filesNEW, IEnumerable<string> filesDELETE, IEnumerable<string> filesUPDATED) { this.PatchName = patchName; this.ReferencePackage = referencePackage; this.TargetPackage = targetePackage; FilesNEW = new SerializableHashSet<string>(filesNEW); FilesDELETE = new SerializableHashSet<string>(filesDELETE); FilesUPDATED = new SerializableHashSet<string>(filesUPDATED); }
public bool ValidatePackage(ApplicationPackage appPackage) { return true; }
/// <summary> /// Add the specified package to the storage and update the meta information /// </summary> /// <param name="appPackage"></param> public void LoadPackageIntoStorage(ApplicationPackage appPackage) { // If application is new and is not presented in storage yet if (!StorageOperations.IsAppInStorage(appPackage.PackageName, PathStorage)) { StorageOperations.CreateAppDirInStorage(appPackage.PackageName, PathStorage); StorageOperations.CreateEmptyStoredAppInfo(appPackage.PackageName, appPackage.ApplicationName, PathStorage); } StoredAppInfo appInfo = StorageOperations.GetStoredAppInfo(appPackage.PackageName, PathStorage); // Add new version if it is not already in storage if (!appInfo.ContainsVersion(appPackage.CodeVersion)) { string apkNameInStorage = NamingHelper.GetPackageNameInStorage(appPackage); // Physically copy package into storage StorageOperations.LoadPackageIntoStorage(appPackage, PathStorage); appInfo.AddVersion(appPackage.CodeVersion, apkNameInStorage); // Update meta info for the application and for the storage itself StorageOperations.UpdateStoredAppInfo(appInfo, PathStorage); StorageOperations.AddAppPackageToStorageInfo(appPackage.PackageName, PathStorage); } }
public static string GetPatchName(ApplicationPackage reference, ApplicationPackage target) { return (String.Format("{0}-{1}-{2}.deltapatch", reference.PackageName, reference.CodeVersion, target.CodeVersion)); }
//public PatchManifest() //{ // PatchName = String.Empty; // OldApk = target packageInfo(); // NewApk = target packageInfo(); // FilesNEW = new SerializableHashSet<string>(); // FilesDELETE = new SerializableHashSet<string>(); // FilesUPDATED = new SerializableHashSet<string>(); //} //public PatchManifest(string patchName) // : this() //{ // PatchName = patchName; //} public PatchManifest(string patchName, ApplicationPackage referencePackage, ApplicationPackage targetePackage) { this.PatchName = patchName; this.ReferencePackage = referencePackage; this.TargetPackage = targetePackage; }
public void ComputePatch(ApplicationPackage reference, ApplicationPackage target, string pathOutputPatch) { IDeltaEncodingAlgorithm deltaEncodingAlgorithm = new BSDIFFDeltaEncodingAlgortihm(); deltaEncodingAlgorithm.ComputeDelta(reference.PackagePath, target.PackagePath, pathOutputPatch); }
/// <summary> /// Checks that the specified file exists and has .apk extension. /// </summary> /// <param name="pathApk"> /// Path to the checked file. /// </param> /// <returns> /// TRUE - file is OK /// FALSE - file is NOT OK /// </returns> public static bool ValidatePackage(ApplicationPackage appPackage) { // Apk is considered bad only if the file does not exist or if it does not have .apk extension. if (!File.Exists(appPackage.PackagePath) || !Path.GetExtension(appPackage.PackagePath).Equals(".apk")) return false; return true; }
/// <summary> /// Computes patch file for two versions of application presented as two APK files. /// Step 1 - Validate both APK files /// Step 2 - Change extensions from .apk to .zip and save new files' paths /// Step 3 - Create patch directory /// Step 4 - Decompress both APKs into the patch directory /// Step 5 - Load manifests for both APKs /// Step 6 - Construct sets of marked files (files are marked as DELETE, NEW, SAME, UPDATED) /// Step 7 - Copy files that are marked NEW into the constructed patch main directory /// Step 8 - Delta encode files that are marked UPDATED nad copy .diff files into the patch /// Step 9 - Create PatchManifest.xml /// Step 10 - Compress patch /// Clean up /// </summary> /// <param name="reference"></param> /// <param name="target"></param> /// <param name="pathOutputPatch"></param> public void ComputePatch(ApplicationPackage reference, ApplicationPackage target, string pathOutputPatch) { // Step 1 - Validate both APK files if (!AndroidPackageManager.ValidatePackage(reference) || !AndroidPackageManager.ValidatePackage(target)) { LogManager.Log(LogMessageType.Error, "Bad APK input files", "Patcher"); return; } // Step 2 - Change extensions from .apk to .zip and save new files' paths //pathOldApk = FileManager.ChangeExtension(pathOldApk, ".zip"); //pathNewApk = FileManager.ChangeExtension(pathNewApk, ".zip"); // Step 3 - Create patch directory string pathPatchingWorkDir = Patcher.GetPatchingWorkDir(); ConstructPathingWorkDir(pathPatchingWorkDir); // Step 4 - Decompress both APKs into the temporary directory string pathReferenceDir = Path.Combine(pathPatchingWorkDir, NAME_REFERENCE_DIR); string pathTargetDir = Path.Combine(pathPatchingWorkDir, NAME_TARGET_DIR); CompressionManager.DecompressZIP(reference.PackagePath, pathReferenceDir); CompressionManager.DecompressZIP(target.PackagePath, pathTargetDir); // Step 5 - Load manifests for both APKs AndroidApplicationManifest referenceManifest = AndroidPackageManager.GetApplicationManifest(pathReferenceDir); AndroidApplicationManifest targetManifest = AndroidPackageManager.GetApplicationManifest(pathTargetDir); // Step 6 - Construct sets of marked files (files are marked as DELETE, NEW, SAME, UPDATED) // Mark DELETE files HashSet<AndroidApplicationManifestRecord> filesMarkedDELETE = MarkFilesDELETE(referenceManifest, targetManifest); // Mark NEW files HashSet<AndroidApplicationManifestRecord> filesMarkedNEW = MarkFilesNEW(referenceManifest, targetManifest); // Mark UPDATED files HashSet<AndroidApplicationManifestRecord> filesMarkedUPDATED = MarkFilesUPDATED(referenceManifest, targetManifest); // Step 7 - Copy files that are marked NEW into the constructed patch main directory foreach (AndroidApplicationManifestRecord record in filesMarkedNEW) { CopyFileIntoPatch(record.FileName, Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR), pathTargetDir); } // Step 8 - Delta encode files that are marked UPDATED nad copy .diff files into the patch var deltaEncodingAlgorithm = new BSDIFFDeltaEncodingAlgortihm(); foreach (AndroidApplicationManifestRecord record in filesMarkedUPDATED) { string pathDiffFile = Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR, record.FileName.Replace('\\', '+')) + ".diff"; deltaEncodingAlgorithm.ComputeDelta(Path.Combine(pathReferenceDir, record.FileName), Path.Combine(pathTargetDir, record.FileName), pathDiffFile); // We don't want to include .diff file into the patch if its size is greater than the new file size. // Instead, we include the new version of file itself. if (FileManager.GetFileSize(pathDiffFile) > FileManager.GetFileSize(Path.Combine(pathTargetDir, record.FileName))) { File.Delete(pathDiffFile); CopyFileIntoPatch(record.FileName, Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR), pathTargetDir); // Add files to filesMarkedNEW and filesMarkedDELETE // During deployment we will delete old file and copy the new one instead of patching the old file filesMarkedDELETE.Add(record); filesMarkedNEW.Add(record); } } // Remove all files that are in filesMarkedNEW from filesMarkedUPDATED filesMarkedUPDATED.ExceptWith(filesMarkedNEW); // Step 9 - Create PatchManifest.xml string patchName = NamingHelper.GetPatchName(reference, target); PatchManifest manifest = new PatchManifest(patchName, reference, target); // We need only files names in the manifest foreach (AndroidApplicationManifestRecord record in filesMarkedNEW) { manifest.AddFileNEW(record.FileName); } foreach (AndroidApplicationManifestRecord record in filesMarkedDELETE) { manifest.AddFileDELETE(record.FileName); } foreach (AndroidApplicationManifestRecord record in filesMarkedUPDATED) { manifest.AddFileUPDATED(record.FileName); } FileManager.SerializeObjectToXML(manifest, Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR, NAME_PATCH_MANIFEST)); // Step 10 - Compress patch CompressionManager.CompressDirToZIP(Path.Combine(pathPatchingWorkDir, NAME_PATCH_DIR), Path.Combine(pathPatchingWorkDir, patchName)); // Clean up // Delete temp directory FileManager.DeleteDirectory(pathPatchingWorkDir); Console.WriteLine(String.Format("Finished patch creation: {0} -> {1}", reference.PackagePath, target.PackagePath)); }