/// <exception cref = "FileNotFoundException">Version info does not exist at path</exception> /// <exception cref = "ArgumentException">versionInfoPath is empty</exception> /// <exception cref = "UnauthorizedAccessException">Admin priviledges needed to update the version info</exception> /// <exception cref = "InvalidOperationException">Version info could not be deserialized</exception> public PatchUpdater(string versionInfoPath, LogEvent logger = null) { versionInfoPath = versionInfoPath.Trim(); if (string.IsNullOrEmpty(versionInfoPath)) { throw new ArgumentException(Localization.Get(StringId.E_XCanNotBeEmpty, "'versionInfoPath'")); } if (!File.Exists(versionInfoPath)) { throw new FileNotFoundException(Localization.Get(StringId.E_PatchInfoDoesNotExistAtX, versionInfoPath)); } if (!PatchUtils.CheckWriteAccessToFolder(Path.GetDirectoryName(versionInfoPath))) { throw new UnauthorizedAccessException(Localization.Get(StringId.E_AccessToXIsForbiddenRunInAdminMode, versionInfoPath)); } this.versionInfoPath = versionInfoPath; VersionInfo = PatchUtils.GetVersionInfoFromPath(versionInfoPath); if (VersionInfo == null) { throw new InvalidOperationException(Localization.Get(StringId.E_VersionInfoCouldNotBeDeserializedFromX, versionInfoPath)); } Logger = logger; }
/// <exception cref = "DirectoryNotFoundException">Previous patch files' directory does not exist</exception> /// <exception cref = "FileNotFoundException">VersionInfo of the previous patch files does not exist</exception> /// <exception cref = "FormatException">VersionInfo of the previous patch could not be deserialized</exception> public PatchCreator SetPreviousPatchFilesRoot(string previousPatchFilesRoot, bool dontCreatePatchFilesForUnchangedFiles = false) { if (previousPatchFilesRoot != null) { previousPatchFilesRoot = previousPatchFilesRoot.Trim(); } if (string.IsNullOrEmpty(previousPatchFilesRoot)) { this.previousPatchFilesRoot = null; this.previousVersionInfo = null; this.dontCreatePatchFilesForUnchangedFiles = false; } else { previousPatchFilesRoot = PatchUtils.GetPathWithTrailingSeparatorChar(previousPatchFilesRoot); if (!Directory.Exists(previousPatchFilesRoot)) { throw new DirectoryNotFoundException(Localization.Get(StringId.E_XDoesNotExist, previousPatchFilesRoot)); } string previousVersionInfoPath = previousPatchFilesRoot + PatchParameters.VERSION_INFO_FILENAME; if (!File.Exists(previousVersionInfoPath)) { throw new FileNotFoundException(Localization.Get(StringId.E_XDoesNotExist, previousVersionInfoPath)); } VersionInfo previousVersionInfo = PatchUtils.GetVersionInfoFromPath(previousVersionInfoPath); if (previousVersionInfo == null) { throw new FormatException(Localization.Get(StringId.E_VersionInfoCouldNotBeDeserializedFromX, previousVersionInfoPath)); } this.previousPatchFilesRoot = previousPatchFilesRoot; this.previousVersionInfo = previousVersionInfo; this.dontCreatePatchFilesForUnchangedFiles = dontCreatePatchFilesForUnchangedFiles; } return(this); }
private PatchResult GeneratePatchInternal() { if (!Directory.Exists(versionsPath)) { Log(Localization.Get(StringId.E_XDoesNotExist, versionsPath)); return(PatchResult.Failed); } if (!File.Exists(projectInfoPath)) { Log(Localization.Get(StringId.E_XDoesNotExist, projectInfoPath)); return(PatchResult.Failed); } string[] versions = Directory.GetDirectories(versionsPath); if (versions.Length == 0) { Log(Localization.Get(StringId.E_DirectoryXIsEmpty, versionsPath)); return(PatchResult.Failed); } string validationResult = ValidateProject(); if (!string.IsNullOrEmpty(validationResult)) { Log(validationResult); return(PatchResult.Failed); } Stopwatch timer = Stopwatch.StartNew(); // Here's how it works: // Move previous incremental patch files to Temp\IncrementalFormer // Generate repair patch and installer patch files on Temp\Output // Foreach incremental patch to generate: // Generate incremental patch files on Temp\Incremental // Move the incremental patch files from there to Temp\IncrementalFormer // Replace the contents of outputPath with Temp\Output: // Delete outputPath directory // Move Temp\Output to outputPath // Move Temp\IncrementalFormer to outputPath // Delete Temp string tempRoot = projectRoot + "Temp" + Path.DirectorySeparatorChar; string tempOutput = tempRoot + "Output" + Path.DirectorySeparatorChar; string tempIncrementalOutput = tempRoot + "Incremental" + Path.DirectorySeparatorChar; string tempPrevIncrementalPatches = tempRoot + "IncrementalFormer" + Path.DirectorySeparatorChar; PatchUtils.DeleteDirectory(tempOutput); PatchUtils.DeleteDirectory(tempIncrementalOutput); // Preserve the previous incremental patches string versionInfoPath = outputPath + PatchParameters.VERSION_INFO_FILENAME; string incrementalPatchesPath = outputPath + PatchParameters.INCREMENTAL_PATCH_DIRECTORY; if (Directory.Exists(incrementalPatchesPath)) { PatchUtils.MoveDirectory(incrementalPatchesPath, tempPrevIncrementalPatches); } List <IncrementalPatch> incrementalPatches = new List <IncrementalPatch>(); if (File.Exists(versionInfoPath)) { VersionInfo oldVersionInfo = PatchUtils.GetVersionInfoFromPath(versionInfoPath); if (oldVersionInfo != null) { incrementalPatches.AddRange(oldVersionInfo.IncrementalPatches); } } Array.Sort(versions, new VersionComparer()); string latestVersion = versions[versions.Length - 1]; ProjectInfo projectInfo = PatchUtils.GetProjectInfoFromPath(projectInfoPath); if (projectInfo.IsSelfPatchingApp && Directory.Exists(selfPatcherPath) && Directory.GetFileSystemEntries(selfPatcherPath).Length > 0) { PatchUtils.CopyDirectory(selfPatcherPath, Path.Combine(latestVersion, PatchParameters.SELF_PATCHER_DIRECTORY)); } patchCreator = new PatchCreator(latestVersion, tempOutput, projectInfo.Name, Path.GetFileName(latestVersion)).SetListener(this). SetCompressionFormat(projectInfo.CompressionFormatRepairPatch, projectInfo.CompressionFormatInstallerPatch, projectInfo.CompressionFormatIncrementalPatch). CreateRepairPatch(projectInfo.CreateRepairPatch).CreateInstallerPatch(projectInfo.CreateInstallerPatch).CreateIncrementalPatch(false). AddIgnoredPaths(projectInfo.IgnoredPaths).SilentMode(silentMode).SetBaseDownloadURL(projectInfo.BaseDownloadURL).SetMaintenanceCheckURL(projectInfo.MaintenanceCheckURL); // Generate repair patch and installer patch files if (cancel || !ExecuteCurrentPatch()) { return(PatchResult.Failed); } if (projectInfo.CreateIncrementalPatch && versions.Length > 1) { string incrementalPatchesGenerated = tempIncrementalOutput + PatchParameters.INCREMENTAL_PATCH_DIRECTORY; string versionInfoGenerated = tempIncrementalOutput + PatchParameters.VERSION_INFO_FILENAME; patchCreator = new PatchCreator(latestVersion, tempIncrementalOutput, projectInfo.Name, Path.GetFileName(latestVersion)).SetListener(this). SetCompressionFormat(projectInfo.CompressionFormatRepairPatch, projectInfo.CompressionFormatInstallerPatch, projectInfo.CompressionFormatIncrementalPatch). AddIgnoredPaths(projectInfo.IgnoredPaths).SilentMode(silentMode).CreateRepairPatch(false).CreateInstallerPatch(false); for (int i = versions.Length - 2; i >= 0; i--) { Log(Localization.Get(StringId.CreatingIncrementalPatchX, Path.GetFileName(versions[i]) + "->" + Path.GetFileName(latestVersion))); // Generate incremental patch files patchCreator.CreateIncrementalPatch(true, versions[i], projectInfo.BinaryDiffQuality); if (cancel || !ExecuteCurrentPatch()) { return(PatchResult.Failed); } List <IncrementalPatch> newIncrementalPatches = PatchUtils.GetVersionInfoFromPath(versionInfoGenerated).IncrementalPatches; for (int j = incrementalPatches.Count - 1; j >= 0; j--) { // Don't allow duplicate IncrementalPatch entries for (int k = newIncrementalPatches.Count - 1; k >= 0; k--) { if (incrementalPatches[j].FromVersion == newIncrementalPatches[k].FromVersion && incrementalPatches[j].ToVersion == newIncrementalPatches[k].ToVersion) { incrementalPatches.RemoveAt(j); break; } } } incrementalPatches.AddRange(newIncrementalPatches); // Move incremental patch files to Temp PatchUtils.MoveDirectory(incrementalPatchesGenerated, tempPrevIncrementalPatches); PatchUtils.DeleteDirectory(tempIncrementalOutput); if (!projectInfo.CreateAllIncrementalPatches) { break; } } } PatchUtils.DeleteDirectory(outputPath); PatchUtils.MoveDirectory(tempOutput, outputPath); if (Directory.Exists(tempPrevIncrementalPatches)) { PatchUtils.MoveDirectory(tempPrevIncrementalPatches, incrementalPatchesPath); } VersionInfo versionInfo = PatchUtils.GetVersionInfoFromPath(versionInfoPath); incrementalPatches.Sort(PatchUtils.IncrementalPatchComparison); versionInfo.IncrementalPatches = incrementalPatches; PatchUtils.SerializeVersionInfoToXML(versionInfo, versionInfoPath); PatchUtils.DeleteDirectory(tempRoot); Log(Localization.Get(StringId.AllPatchesCreatedInXSeconds, timer.ElapsedSeconds())); return(PatchResult.Success); }