/// <summary> /// Installs the package internal. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task InstallPackageInternal(PackageVersionInfo package, IProgress <double> progress, CancellationToken cancellationToken) { // Do the install await _packageManager.InstallPackage(progress, package, cancellationToken).ConfigureAwait(false); // Do plugin-specific processing if (!(Path.GetExtension(package.targetFilename) ?? "").Equals(".zip", StringComparison.OrdinalIgnoreCase)) { // Set last update time if we were installed before var plugin = ApplicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase)); if (plugin != null) { // Synchronize the UpdateClass value if (plugin.Configuration.UpdateClass != package.classification) { plugin.Configuration.UpdateClass = package.classification; plugin.SaveConfiguration(); } OnPluginUpdated(plugin, package); } else { OnPluginInstalled(package); } } }
private async Task PerformPackageInstallation(IProgress <double> progress, PackageVersionInfo package, CancellationToken cancellationToken) { // Target based on if it is an archive or single assembly // zip archives are assumed to contain directory structures relative to our ProgramDataPath var extension = Path.GetExtension(package.targetFilename); var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase); var target = Path.Combine(isArchive ? _appPaths.TempUpdatePath : _appPaths.PluginsPath, package.targetFilename); // Download to temporary file so that, if interrupted, it won't destroy the existing installation var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { Url = package.sourceUrl, CancellationToken = cancellationToken, Progress = progress }).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Validate with a checksum if (package.checksum != Guid.Empty) // support for legacy uploads for now { using (var crypto = new MD5CryptoServiceProvider()) using (var stream = new BufferedStream(File.OpenRead(tempFile), 100000)) { var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty)); if (check != package.checksum) { throw new ApplicationException(string.Format("Download validation failed for {0}. Probably corrupted during transfer.", package.name)); } } } cancellationToken.ThrowIfCancellationRequested(); // Success - move it to the real target try { File.Copy(tempFile, target, true); //If it is an archive - write out a version file so we know what it is if (isArchive) { File.WriteAllText(target + ".ver", package.versionStr); } } catch (IOException e) { _logger.ErrorException("Error attempting to move file from {0} to {1}", e, tempFile, target); throw; } try { File.Delete(tempFile); } catch (IOException e) { // Don't fail because of this _logger.ErrorException("Error deleting temp file {0]", e, tempFile); } }
protected override void OnLoadPackages() { var potentialPackages = Directory.GetFiles(LocalRepositoryPath, "*.zip", SearchOption.TopDirectoryOnly); foreach (var filePath in potentialPackages) { using (var archive = ArchiveFactory.Open(filePath)) foreach (var entry in archive.Entries) { if (!"manifest.json".Equals(Path.GetFileName(entry.Key))) { continue; } var manifestJson = string.Empty; using (var reader = new StreamReader(entry.OpenEntryStream())) manifestJson = reader.ReadToEnd(); var tsp = JsonUtility.FromJson <PackageVersion>(manifestJson); var versionId = Path.GetFileNameWithoutExtension(filePath); var author = versionId.Split('-')[0]; var groupId = $"{author}-{tsp.name}"; var versions = new PackageVersionInfo[] { new PackageVersionInfo(tsp.version_number, versionId, tsp.dependencies) }; AddPackageGroup(author, tsp.name, tsp.description, groupId, EmptyStringArray, versions); //don't process additional manifest files break; } } }
/// <summary> /// Installs the package internal. /// </summary> /// <param name="package">The package.</param> /// <param name="isPlugin">if set to <c>true</c> [is plugin].</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task InstallPackageInternal(PackageVersionInfo package, bool isPlugin, IProgress <double> progress, CancellationToken cancellationToken) { IPlugin plugin = null; if (isPlugin) { // Set last update time if we were installed before plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase)) ?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase)); } string targetPath = plugin == null ? null : plugin.AssemblyFilePath; // Do the install await PerformPackageInstallation(progress, targetPath, package, cancellationToken).ConfigureAwait(false); // Do plugin-specific processing if (isPlugin) { if (plugin == null) { OnPluginInstalled(package); } else { OnPluginUpdated(plugin, package); } } }
public bool DetectNewVersion() { using (FtpClient client = this.CreateFtpClient()) { PackageVersionInfo diffVersionInfo = GetDifferenceVersionInfoWithServer(client); return(diffVersionInfo != null && diffVersionInfo.Files.Length > 0); } }
/// <summary> /// Updates the application. /// </summary> /// <param name="package">The package that contains the update</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public override async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress <double> progress) { await InstallationManager.InstallPackage(package, progress, cancellationToken).ConfigureAwait(false); HasUpdateAvailable = false; OnApplicationUpdated(package); }
public async void Install(PackageVersionInfo version) { _installationManager.InstallPackage(version, new Progress <double>(), CancellationToken.None); await _nav.NavigateToSettingsPage(); _nav.RemovePagesFromHistory(3); }
/// <summary> /// Determines whether [is package version up to date] [the specified package version info]. /// </summary> /// <param name="packageVersionInfo">The package version info.</param> /// <param name="currentServerVersion">The current server version.</param> /// <returns><c>true</c> if [is package version up to date] [the specified package version info]; otherwise, <c>false</c>.</returns> private static bool IsPackageVersionUpToDate(PackageVersionInfo packageVersionInfo, Version currentServerVersion) { if (string.IsNullOrEmpty(packageVersionInfo.requiredVersionStr)) { return(true); } return(Version.TryParse(packageVersionInfo.requiredVersionStr, out var requiredVersion) && currentServerVersion >= requiredVersion); }
/// <summary> /// Called when [plugin updated]. /// </summary> /// <param name="plugin">The plugin.</param> /// <param name="newVersion">The new version.</param> private void OnPluginUpdated(IPlugin plugin, PackageVersionInfo newVersion) { _logger.LogInformation("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.versionStr ?? string.Empty, newVersion.classification); PluginUpdated?.Invoke(this, new GenericEventArgs <Tuple <IPlugin, PackageVersionInfo> > { Argument = new Tuple <IPlugin, PackageVersionInfo>(plugin, newVersion) }); _applicationHost.NotifyPendingRestart(); }
/// <summary> /// Called when [plugin installed]. /// </summary> /// <param name="package">The package.</param> private void OnPluginInstalled(PackageVersionInfo package) { _logger.LogInformation("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification); PluginInstalled?.Invoke(this, new GenericEventArgs <PackageVersionInfo> { Argument = package }); _applicationHost.NotifyPendingRestart(); }
/// <summary> /// Called when [plugin installed]. /// </summary> /// <param name="package">The package.</param> private void OnPluginInstalled(PackageVersionInfo package) { _logger.Info("New plugin installed: {0} {1} {2}", package.name, package.versionStr ?? string.Empty, package.classification); EventHelper.FireEventIfNotNull(PluginInstalled, this, new GenericEventArgs <PackageVersionInfo> { Argument = package }, _logger); _applicationHost.NotifyPendingRestart(); }
/// <summary> /// Called when [plugin updated]. /// </summary> /// <param name="plugin">The plugin.</param> /// <param name="newVersion">The new version.</param> private void OnPluginUpdated(IPlugin plugin, PackageVersionInfo newVersion) { _logger.Info("Plugin updated: {0} {1} {2}", newVersion.name, newVersion.versionStr ?? string.Empty, newVersion.classification); EventHelper.FireEventIfNotNull(PluginUpdated, this, new GenericEventArgs <Tuple <IPlugin, PackageVersionInfo> > { Argument = new Tuple <IPlugin, PackageVersionInfo>(plugin, newVersion) }, _logger); _applicationHost.NotifyPendingRestart(); }
/// <summary> /// Updates the application. /// </summary> /// <param name="package">The package that contains the update</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress <double> progress) { await PackageManager.InstallPackage(progress, package, cancellationToken).ConfigureAwait(false); EventHelper.QueueEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs <Version> { Argument = package.version }, Logger); NotifyPendingRestart(); }
/// <summary> /// Determines whether [is package version up to date] [the specified package version info]. /// </summary> /// <param name="packageVersionInfo">The package version info.</param> /// <param name="applicationVersion">The application version.</param> /// <returns><c>true</c> if [is package version up to date] [the specified package version info]; otherwise, <c>false</c>.</returns> private bool IsPackageVersionUpToDate(PackageVersionInfo packageVersionInfo, Version applicationVersion) { if (string.IsNullOrEmpty(packageVersionInfo.requiredVersionStr)) { return(true); } Version requiredVersion; return(Version.TryParse(packageVersionInfo.requiredVersionStr, out requiredVersion) && applicationVersion >= requiredVersion); }
/// <summary> /// Called when [application updated]. /// </summary> /// <param name="package">The package.</param> protected void OnApplicationUpdated(PackageVersionInfo package) { Logger.Info("Application has been updated to version {0}", package.versionStr); EventHelper.FireEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs <PackageVersionInfo> { Argument = package }, Logger); NotifyPendingRestart(); }
public bool TryUpgradeNow() { using (FtpClient client = this.CreateFtpClient()) { PackageVersionInfo diffVersionInfo = GetDifferenceVersionInfoWithServer(client); if (diffVersionInfo == null || diffVersionInfo.Files.Length == 0) { return(false); } UpgradeNow(client, diffVersionInfo); return(true); } }
private static void CopyVersionFile(PackageVersionInfo versionInfo, string sourceFolder, string toFolder) { foreach (var item in versionInfo.Files) { string filePath = Path.Combine(sourceFolder, item.File.TrimStart('\\', '/')); if (!File.Exists(filePath)) { continue; } string newFilePath = Path.Combine(toFolder, item.File.TrimStart('\\', '/')); Directory.CreateDirectory(Directory.GetParent(newFilePath).FullName); File.Copy(filePath, newFilePath, true); } }
private PackageVersionInfo GetDifferenceVersionInfoWithServer(FtpClient client) { if (!client.FileExists("/" + VersionFileName)) { return(null); } byte[] versionData = null; if (!client.Download(out versionData, "/" + VersionFileName)) { return(null); } PackageVersionInfo pvi = XmlSerializer.ToObject <PackageVersionInfo>(versionData); return(this._versionService.CompareDifference(_targetFolder, pvi)); }
/// <summary> /// Download our specified package to an archive in a temp location /// </summary> /// <returns>The fully qualified name of the downloaded package</returns> protected async Task <string> DownloadPackage(PackageVersionInfo version) { var success = false; var retryCount = 0; var archiveFile = Path.Combine(PrepareTempLocation(), version.targetFilename); try { while (!success && retryCount < 3) { // setup download progress and download the package MainClient.DownloadProgressChanged += DownloadProgressChanged; try { await MainClient.DownloadFileTaskAsync(version.sourceUrl, archiveFile); success = true; } catch (WebException e) { if (e.Status == WebExceptionStatus.RequestCanceled) { return(null); } if (retryCount < 3 && (e.Status == WebExceptionStatus.Timeout || e.Status == WebExceptionStatus.ConnectFailure || e.Status == WebExceptionStatus.ProtocolError)) { Thread.Sleep(500); //wait just a sec PrepareTempLocation(); //clear this out retryCount++; } else { throw; } } } return(archiveFile); } catch (Exception e) { SystemClose(e.GetType().FullName + "\n\n" + e.Message); } return(""); }
/// <summary> /// Gets the specified request. /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> public async Task <object> Get(GetPackageVersionUpdates request) { PackageVersionInfo[] result = null; if (string.Equals(request.PackageType, "UserInstalled", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase)) { result = (await _installationManager.GetAvailablePluginUpdates(_appHost.ApplicationVersion, false, CancellationToken.None).ConfigureAwait(false)).ToArray(); } else if (string.Equals(request.PackageType, "System", StringComparison.OrdinalIgnoreCase) || string.Equals(request.PackageType, "All", StringComparison.OrdinalIgnoreCase)) { var updateCheckResult = await _appHost .CheckForApplicationUpdate(CancellationToken.None, new SimpleProgress <double>()).ConfigureAwait(false); if (updateCheckResult.IsUpdateAvailable) { result = new PackageVersionInfo[] { updateCheckResult.Package }; } } return(ToOptimizedResult(result ?? new PackageVersionInfo[] { })); }
static void Main(string[] args) { try { var definition = Args.Configuration.Configure <CommandObject>(); var command = definition.CreateAndBind(args); if (command.Help != null) { var help = new Args.Help.HelpProvider().GenerateModelHelp(definition); var f = new ConsoleHelpFormatter(80, 1, 5); Console.WriteLine(f.GetHelp(help)); return; } Console.WriteLine($"正在生成..."); Console.WriteLine($"目标文件夹:{command.TargetFolder}"); Console.WriteLine($"秘钥:{command.SecretKey}"); Console.WriteLine($"忽略文件:{ ((command.Ignore == null || command.Ignore.Count == 0) ? "无" : string.Join(", ", command.Ignore))}"); VersionService versionService = new VersionService(command.SecretKey); if (command.Ignore == null) { command.Ignore = new List <string>(2); } command.Ignore.Add(Path.GetFileNameWithoutExtension(typeof(Program).Assembly.Location)); command.Ignore.Add(versionFileName); command.Ignore.Add("Zl.AutoUpgrade.Core"); PackageVersionInfo info = versionService.ComputeVersionInfo(command.TargetFolder, command.Ignore.ToArray()); XmlSerializer.SaveToFile(info, System.IO.Path.Combine(command.TargetFolder, versionFileName)); Console.WriteLine($"生成完毕."); } catch (Exception exc) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(exc); Console.ResetColor(); } }
/// <summary> /// Download our specified package to an archive in a temp location /// </summary> /// <returns>The fully qualified name of the downloaded package</returns> protected async Task <string> DownloadPackage(PackageVersionInfo version) { var retryCount = 0; while (retryCount < 3) { var archiveFile = Path.Combine(GetTempLocation(), version.targetFilename); // setup download progress and download the package MainClient.DownloadProgressChanged += DownloadProgressChanged; try { await MainClient.DownloadFileTaskAsync(version.sourceUrl, archiveFile); return(archiveFile); } catch (WebException e) { if (e.Status == WebExceptionStatus.RequestCanceled) { Trace.TraceInformation("Download cancelled"); return(null); } if (retryCount < 3 && (e.Status == WebExceptionStatus.Timeout || e.Status == WebExceptionStatus.ConnectFailure || e.Status == WebExceptionStatus.ProtocolError)) { Thread.Sleep(500); //wait just a sec retryCount++; } else { throw; } } } return(null); }
/// <summary> /// Installs the package internal. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task InstallPackageInternal(PackageVersionInfo package, IProgress <double> progress, CancellationToken cancellationToken) { // Do the install await PerformPackageInstallation(progress, package, cancellationToken).ConfigureAwait(false); var extension = Path.GetExtension(package.targetFilename) ?? ""; // Do plugin-specific processing if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) && !string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase)) { // Set last update time if we were installed before var plugin = _applicationHost.Plugins.FirstOrDefault(p => string.Equals(p.Id.ToString(), package.guid, StringComparison.OrdinalIgnoreCase)) ?? _applicationHost.Plugins.FirstOrDefault(p => p.Name.Equals(package.name, StringComparison.OrdinalIgnoreCase)); if (plugin != null) { OnPluginUpdated(plugin, package); } else { OnPluginInstalled(package); } } }
private async Task PerformPackageInstallation(IProgress <double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken) { // Target based on if it is an archive or single assembly // zip archives are assumed to contain directory structures relative to our ProgramDataPath var extension = Path.GetExtension(package.targetFilename); var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".rar", StringComparison.OrdinalIgnoreCase) || string.Equals(extension, ".7z", StringComparison.OrdinalIgnoreCase); if (target == null) { target = Path.Combine(isArchive ? _appPaths.TempUpdatePath : _appPaths.PluginsPath, package.targetFilename); } // Download to temporary file so that, if interrupted, it won't destroy the existing installation var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { Url = package.sourceUrl, CancellationToken = cancellationToken, Progress = progress }).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // Validate with a checksum var packageChecksum = string.IsNullOrWhiteSpace(package.checksum) ? Guid.Empty : new Guid(package.checksum); if (!packageChecksum.Equals(Guid.Empty)) // support for legacy uploads for now { using (var stream = _fileSystem.OpenRead(tempFile)) { var check = Guid.Parse(BitConverter.ToString(_cryptographyProvider.ComputeMD5(stream)).Replace("-", string.Empty)); if (check != packageChecksum) { throw new Exception(string.Format("Download validation failed for {0}. Probably corrupted during transfer.", package.name)); } } } cancellationToken.ThrowIfCancellationRequested(); // Success - move it to the real target try { _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(target)); _fileSystem.CopyFile(tempFile, target, true); //If it is an archive - write out a version file so we know what it is if (isArchive) { _fileSystem.WriteAllText(target + ".ver", package.versionStr); } } catch (IOException ex) { _logger.LogError(ex, "Error attempting to move file from {TempFile} to {TargetFile}", tempFile, target); throw; } try { _fileSystem.DeleteFile(tempFile); } catch (IOException ex) { // Don't fail because of this _logger.LogError(ex, "Error deleting temp file {TempFile}", tempFile); } }
/// <summary> /// Updates the application. /// </summary> /// <param name="package">The package that contains the update</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public abstract Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress <double> progress);
/// <summary> /// Installs the package. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">package</exception> public async Task InstallPackage(PackageVersionInfo package, IProgress <double> progress, CancellationToken cancellationToken) { if (package == null) { throw new ArgumentNullException("package"); } if (progress == null) { throw new ArgumentNullException("progress"); } var installationInfo = new InstallationInfo { Id = Guid.NewGuid().ToString("N"), Name = package.name, AssemblyGuid = package.guid, UpdateClass = package.classification, Version = package.versionStr }; var innerCancellationTokenSource = new CancellationTokenSource(); var tuple = new Tuple <InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource); // Add it to the in-progress list lock (CurrentInstallations) { CurrentInstallations.Add(tuple); } var innerProgress = new ActionableProgress <double>(); // Whenever the progress updates, update the outer progress object and InstallationInfo innerProgress.RegisterAction(percent => { progress.Report(percent); installationInfo.PercentComplete = percent; }); var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; var installationEventArgs = new InstallationEventArgs { InstallationInfo = installationInfo, PackageVersionInfo = package }; EventHelper.FireEventIfNotNull(PackageInstalling, this, installationEventArgs, _logger); try { await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false); lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } progress.Report(100); CompletedInstallations.Add(installationInfo); EventHelper.FireEventIfNotNull(PackageInstallationCompleted, this, installationEventArgs, _logger); } catch (OperationCanceledException) { lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr); EventHelper.FireEventIfNotNull(PackageInstallationCancelled, this, installationEventArgs, _logger); throw; } catch (Exception ex) { _logger.ErrorException("Package installation failed", ex); lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } EventHelper.FireEventIfNotNull(PackageInstallationFailed, this, new InstallationFailedEventArgs { InstallationInfo = installationInfo, Exception = ex }, _logger); throw; } finally { // Dispose the progress object and remove the installation from the in-progress list innerProgress.Dispose(); tuple.Item2.Dispose(); } }
private Version GetPackageVersion(PackageVersionInfo version) { return(new Version(ValueOrDefault(version.versionStr, "0.0.0.1"))); }
private void UpgradeNow(FtpClient client, PackageVersionInfo diffVersionInfo) { this.RaiseUpgradeStarted(); float percent = 0f; try { Directory.CreateDirectory(_targetFolder); var currVersionInfo = this._versionService.ComputeVersionInfo(_targetFolder); XmlSerializer.SaveToFile(diffVersionInfo, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "versionInfo_diff.xml")); XmlSerializer.SaveToFile(currVersionInfo, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "versionInfo_curr.xml")); this.RaiseUpgradeProgress(percent += 0.01f); } catch (Exception exc) { string msg = "计算版本信息文件出错"; Exception nexc = new CreateVersionInfoException(msg, exc); this.RaiseUpgradeEnded(msg, nexc); throw nexc; } //下载新版本,占比 90% string curentDownFile = string.Empty; try { DirectoryInfo newVersionTemp = Directory.CreateDirectory(NewVersionTempFolder); client.RetryAttempts = 3; long downLength = 0; foreach (var item in diffVersionInfo.Files) { curentDownFile = item.File; client.DownloadFile(Path.Combine(newVersionTemp.FullName, item.File.TrimStart('\\', '/')), item.File.Replace('\\', '/'), true, FtpVerify.Retry); downLength += item.Length; this.RaiseUpgradeProgress(percent += (float)Math.Round((downLength * 1.0 / diffVersionInfo.TotalLength * 0.9), 2)); } XmlSerializer.SaveToFile(diffVersionInfo, Path.Combine(newVersionTemp.FullName, VersionFileName)); } catch (Exception exc) { string msg = string.Format("下载新版文件({0})出错", curentDownFile); Exception nexc = new DownFileException(msg, exc); this.RaiseUpgradeEnded(msg, nexc); throw nexc; } //验证文件合法性,防篡改,占比 1% try { if (!this._versionService.Verify(diffVersionInfo, NewVersionTempFolder)) { string msg = "新版文件不合法"; Exception nexc = new UnlawfulException(msg, null); this.RaiseUpgradeEnded(msg, nexc); throw nexc; } this.RaiseUpgradeProgress(percent += 0.01f); } catch (UnlawfulException) { throw; } catch (Exception exc) { string msg = "新版文件验证出错"; Exception nexc = new UnlawfulException(msg, exc); this.RaiseUpgradeEnded(msg, nexc); throw nexc; } //备份当前版本,占比 3% try { CopyVersionFile(diffVersionInfo, this._targetFolder, LastVersionBakFolder); this.RaiseUpgradeProgress(percent += 0.03f); } catch (Exception exc) { string msg = "版本当前版本出错"; Exception nexc = new BackupFileException(msg, exc); this.RaiseUpgradeEnded(msg, nexc); throw nexc; } //新版覆盖当前版,占比 4% try { CopyVersionFile(diffVersionInfo, NewVersionTempFolder, this._targetFolder); XmlSerializer.SaveToFile(diffVersionInfo, Path.Combine(this._targetFolder, VersionFileName)); this.RaiseUpgradeProgress(percent += 0.04f); } catch (Exception exc) { try { CopyVersionFile(diffVersionInfo, LastVersionBakFolder, this._targetFolder); } catch (Exception exc1) { string msg1 = string.Format("新版覆盖当前版出错后回滚出错", curentDownFile); Exception nexc1 = new RollbackException(msg1, exc1); LogHelper.Log(nexc1, "升级忽略错误"); } string msg = string.Format("新版覆盖当前版出错", curentDownFile); Exception nexc = new ReplaceNewVersionException(msg, exc); this.RaiseUpgradeEnded(msg, nexc); throw nexc; } //删除临时文件,占比 1% try { Directory.Delete(NewVersionTempFolder, true); Directory.Delete(LastVersionBakFolder, true); this.RaiseUpgradeProgress(percent += 0.01f); } catch (Exception exc) { string msg = string.Format("删除临时文件出错", curentDownFile); Exception nexc = new DeleteTempFileException(msg, exc); LogHelper.Log(nexc, "升级忽略错误"); } this.RaiseUpgradeProgress(percent = 1f); this.RaiseUpgradeEnded(); }
private async Task PerformPackageInstallation(IProgress <double> progress, string target, PackageVersionInfo package, CancellationToken cancellationToken) { var extension = Path.GetExtension(package.targetFilename); var isArchive = string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase); if (!isArchive) { _logger.LogError("Only zip packages are supported. {Filename} is not a zip archive.", package.targetFilename); return; } if (target == null) { target = Path.Combine(_appPaths.PluginsPath, Path.GetFileNameWithoutExtension(package.targetFilename)); } // Download to temporary file so that, if interrupted, it won't destroy the existing installation var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions { Url = package.sourceUrl, CancellationToken = cancellationToken, Progress = progress }).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); // TODO: Validate with a checksum, *properly* // Success - move it to the real target try { using (var stream = File.OpenRead(tempFile)) { _zipClient.ExtractAllFromZip(stream, target, true); } } catch (IOException ex) { _logger.LogError(ex, "Error attempting to extract {TempFile} to {TargetFile}", tempFile, target); throw; } try { _fileSystem.DeleteFile(tempFile); } catch (IOException ex) { // Don't fail because of this _logger.LogError(ex, "Error deleting temp file {TempFile}", tempFile); } }
/// <summary> /// 添加版本记录 /// </summary> /// <param name=""></param> public void AddVersionRecord(string branchName, long versionCode, string versionName, string versionDesc, bool saveBinary, bool dialog = true, bool log = true) { //编辑器那边限制了不能添加“比最大版本号更小的版本号”的版本,(也就是说版本号只能变大),但是这里实际上没做这个限制。以后如果有需要,可以让编辑器UI上去掉限制。 if (mDict_Branches.TryGetValue(branchName, out var branch)) { //判断一下版本号啦 if (versionCode >= 0 && !branch.IsVersionCodeExists(versionCode)) { bool isMainPackage = (branch.BType == VersionBranch.BranchType.MainPackage); bool flag_process_error = false; //处理文件过程中如果出错则中断操作且不记录数据 string platform_name = XPlatformUtil.GetNameText(branch.Platform); string source_packages_folder_path = VFSEditorUtil.GetSourcePackagesFolderPath(platform_name); string data_folder = VFSEditorUtil.GetVersionDataFolderPath_InProjectVersion(branch.BranchName, versionCode); //存放数据的地方 string build_id = string.Empty; try { XDirectory.DeleteIfExists(data_folder, true); Directory.CreateDirectory(data_folder); //复制并存档assets_hash文件 string assets_hash_path = isMainPackage ? VFSEditorUtil.GetMainPackage_AssetsHashFilePath_InSourcePackagesFolder(platform_name) : VFSEditorUtil.GetExtensionGroup_AssetsHashFilePath_InSourcePackagesFolder(platform_name, branch.ExtensionGroupName); string assets_hash_target_path = Path.Combine(data_folder, VFSConst.AssetsHashFileName); if (File.Exists(assets_hash_path)) { File.Copy(assets_hash_path, assets_hash_target_path, true); } //复制并存档Manifest文件 string manifest_target_path = VFSEditorUtil.GetVersionData_Manifest_FolderOrFilePath(!isMainPackage, branchName, versionCode); string manifest_path = isMainPackage ? VFSEditorUtil.GetMainPackage_AssetBundleManifestsFolderPath_InSourcePackagesFolder(platform_name) : VFSEditorUtil.GetExtensionGroup_AssetBundleManifestPath_InInSourcePackagesFolder(platform_name, branch.ExtensionGroupName); if (isMainPackage) { if (Directory.Exists(manifest_path)) { XDirectory.CopyDir(manifest_path, manifest_target_path); } } else { if (File.Exists(manifest_path)) { File.Copy(manifest_path, manifest_target_path); } } //复制并存档AssetBundleHashs string ab_hash_path = isMainPackage ? VFSEditorUtil.GetMainPackage_AssetBundle_HashFiles_FolderPath_InSourcePackagesFolder(platform_name) : VFSEditorUtil.GetExtensionGroup_AssetBundle_HashFiles_Path_InInSourcePackagesFolder(platform_name, branch.ExtensionGroupName); string ab_hash_target_path = VFSEditorUtil.GetVersionData_AssetBundle_HashFile_FolderOrFilePath(!isMainPackage, branchName, versionCode); if (isMainPackage) { if (Directory.Exists(ab_hash_path)) { XDirectory.CopyDir(ab_hash_path, ab_hash_target_path); } } else { if (File.Exists(ab_hash_path)) { File.Copy(ab_hash_path, ab_hash_target_path); } } //复制并存档vfs config (main package) if (isMainPackage) { string vfs_config_path = VFSUtil.GetVFSConfigFilePath_InPackages(VFSEditorUtil.GetSourcePackagesFolderPath(platform_name)); if (File.Exists(vfs_config_path)) { string target_path = Path.Combine(data_folder, VFSConst.Config_Runtime_FileName); File.Copy(vfs_config_path, target_path, true); } } //Group Options if (!isMainPackage) { string group_option_path = VFSUtil.GetExtensionPackages_GroupOptions_FilePath(source_packages_folder_path, branch.ExtensionGroupName); if (File.Exists(group_option_path)) { string target_path = Path.Combine(data_folder, VFSConst.ExtensionGroup_GroupOption_FileName); File.Copy(group_option_path, target_path, true); } } //Group Info if (!isMainPackage) { string group_info_path = VFSUtil.GetExtensionGroup_GroupInfo_Path_InGroupPath(VFSUtil.GetExtensionGroupFolder(source_packages_folder_path, branch.ExtensionGroupName)); if (File.Exists(group_info_path)) { string target_path = Path.Combine(data_folder, VFSConst.VFS_ExtensionGroupInfo_FileName); File.Copy(group_info_path, target_path, true); } } //复制并存档editor build info string editor_build_info_path = VFSEditorUtil.Get_EditorBuildInfoPath(VFSEditorUtil.GetSourcePackagesFolderPath(platform_name)); if (File.Exists(editor_build_info_path)) { string target_path = VFSEditorUtil.GetVersionData_EditorBuildInfo_Path(branchName, versionCode); File.Copy(editor_build_info_path, target_path); } //复制并存档 build info string build_info_path = VFSUtil.GetMainPackage_BuildInfo_Path(VFSEditorUtil.GetSourcePackagesFolderPath(platform_name)); if (File.Exists(build_info_path)) { //存档 string target_path = VFSEditorUtil.GetVersionData_BuildInfo_Path(branchName, versionCode); File.Copy(build_info_path, target_path); //反写版本信息到source package string build_info_json = File.ReadAllText(target_path, Encoding.UTF8); var obj = JsonUtility.FromJson <BuildInfo>(build_info_json); build_id = obj.BuildID; //写出版本信息 var version_info = new PackageVersionInfo { version = versionCode, versionName = versionName, buildId = obj.BuildID, branch = branch.BranchName }; string version_info_path = isMainPackage ? VFSEditorUtil.Get_MainPackage_PackageVersionFilePath_InSourcePackages(platform_name) : VFSEditorUtil.Get_ExtensionGroups_PackageVersionFilePath_InSourcePackages(ref platform_name, ref branch.ExtensionGroupName); XFile.DeleteIfExists(version_info_path); XConfig.SaveJson(version_info, version_info_path, AssetLoadType.SystemIO); //检查当前StreamingAssets中是否有与之build id一致的情况,如果有,也写出 if (isMainPackage) { string buildinfo_in_stream = VFSUtil.GetMainPackage_BuildInfo_Path(VFSUtil.GetPackagesRootFolderInStreamingAssets(platform_name)); if (File.Exists(buildinfo_in_stream)) { try { var obj_stream = XConfig.GetJson <BuildInfo>(buildinfo_in_stream, AssetLoadType.SystemIO, false); if (obj_stream.BuildID == obj.BuildID) { //一致,写出 string target_stream = VFSUtil.GetMainPackage_VersionInfo_Path(VFSUtil.GetPackagesRootFolderInStreamingAssets(platform_name)); XConfig.SaveJson(version_info, target_stream, AssetLoadType.SystemIO); } } catch { } } } else { string buildinfo_in_stream = VFSUtil.GetExtensionGroup_BuildInfo_Path(VFSUtil.GetPackagesRootFolderInStreamingAssets(platform_name), branch.ExtensionGroupName); if (File.Exists(buildinfo_in_stream)) { try { var obj_stream = XConfig.GetJson <BuildInfo>(buildinfo_in_stream, AssetLoadType.SystemIO, false); if (obj_stream.BuildID == obj.BuildID) { //一致,写出 string target_stream = VFSUtil.GetExtensionGroup_VersionInfo_Path(VFSUtil.GetPackagesRootFolderInStreamingAssets(platform_name), branch.ExtensionGroupName); XConfig.SaveJson(version_info, target_stream, AssetLoadType.SystemIO); } } catch { } } } } } catch (Exception e) { XDirectory.DeleteIfExists(data_folder, true); flag_process_error = true; throw e; } //保存二进制文件 if (saveBinary && !flag_process_error) { string binary_path = VFSEditorUtil.Get_AssetsBinaryFolderPath_InVersion(branchName, versionCode); try { long total_count = 0; //把所有二进制文件直接全拷进去 string binary_path_temp = Path.Combine(binary_path, "temp"); string binary_path_temp_remote = Path.Combine(binary_path, "temp_remote"); XDirectory.DeleteIfExists(binary_path_temp, true); Directory.CreateDirectory(binary_path_temp); if (isMainPackage) { XDirectory.DeleteIfExists(binary_path_temp_remote, true); Directory.CreateDirectory(binary_path_temp_remote); } //移动文件 if (isMainPackage) { string local_path = VFSEditorUtil.Get_MainPackage_AssetsFolderPath_InSourcePackages(platform_name); int local_path_len = local_path.Length + 1; string[] local_files = Directory.GetFiles(local_path, "*.*", SearchOption.AllDirectories); if (local_files != null && local_files.Length > 0) { ArrayUtil.RemoveDuplicationElements(ref local_files); foreach (var item in local_files) { total_count++; string pure_path = item.Substring(local_path_len, item.Length - local_path_len); string target_path = Path.Combine(binary_path_temp, pure_path); XDirectory.CreateIfNotExists(Path.GetDirectoryName(target_path)); File.Copy(item, target_path); } } string remote_path = VFSEditorUtil.Get_MainPackage_RemoteAssetsFolderPath_InSourcePackages(platform_name); if (Directory.Exists(remote_path)) { int remote_path_len = remote_path.Length + 1; string[] remote_files = Directory.GetFiles(remote_path, "*.*", SearchOption.AllDirectories); if (remote_files != null && remote_files.Length > 0) { total_count++; ArrayUtil.RemoveDuplicationElements(ref remote_files); foreach (var item in remote_files) { string pure_path = item.Substring(remote_path_len, item.Length - remote_path_len); string target_path = Path.Combine(binary_path_temp_remote, pure_path); XDirectory.CreateIfNotExists(Path.GetDirectoryName(target_path)); File.Copy(item, target_path); } } } } else { string group_path = VFSEditorUtil.Get_ExtensionGroupFolderPath_InSourcePackages(platform_name, branch.ExtensionGroupName); int group_path_len = group_path.Length + 1; string[] group_files = Directory.GetFiles(group_path, "*.*", SearchOption.AllDirectories); if (group_files != null && group_files.Length > 0) { total_count++; ArrayUtil.RemoveDuplicationElements(ref group_files); foreach (var item in group_files) { string pure_path = item.Substring(group_path_len, item.Length - group_path_len); string target_path = Path.Combine(binary_path_temp, pure_path); XDirectory.CreateIfNotExists(Path.GetDirectoryName(target_path)); File.Copy(item, target_path); } } } long zip_counter = 0; int zip_counter_t = 0; //打包 string zip_file_path = Path.Combine(binary_path, VFSEditorConst.VFS_VERSION_AssetsBinary_Zip_Name); ZipUtil.ZipDirectory(binary_path_temp, zip_file_path, fileName => { if (log || dialog) { zip_counter++; if (total_count > 100) { zip_counter_t++; if (zip_counter_t >= 20) { zip_counter_t = 0; if (log) { Debug.Log($" Create Zip: {zip_counter}/{total_count}"); } if (dialog) { EditorUtility.DisplayProgressBar("Create Zip", $"{zip_counter}/{total_count}\n{fileName}", zip_counter / total_count); } } } else { if (log) { Debug.Log($" Create Zip: {zip_counter}/{total_count} : {fileName}"); } if (dialog) { EditorUtility.DisplayProgressBar("Create Zip", $"{zip_counter}/{total_count}\n{fileName}", zip_counter / total_count); } } } }); if (isMainPackage) { string zip_file_path_remote = Path.Combine(binary_path, VFSEditorConst.VFS_VERSION_AssetsBinary_REMOTE_Zip_Name); zip_counter = 0; zip_counter_t = 0; ZipUtil.ZipDirectory(binary_path_temp_remote, zip_file_path_remote, fileName => { if (log || dialog) { zip_counter++; if (total_count > 100) { zip_counter_t++; if (zip_counter_t >= 20) { zip_counter_t = 0; if (log) { Debug.Log($" Create Zip: {zip_counter}/{total_count}"); } if (dialog) { EditorUtility.DisplayProgressBar("Create Zip", $"{zip_counter}/{total_count}\n{fileName}", zip_counter / total_count); } } } else { if (log) { Debug.Log($" Create Zip: {zip_counter}/{total_count} : {fileName}"); } if (dialog) { EditorUtility.DisplayProgressBar("Create Zip", $"{zip_counter}/{total_count}\n{fileName}", zip_counter / total_count); } } } }); } if (dialog) { EditorUtility.ClearProgressBar(); //上面这个应该是同步方法,不会有时间错乱。(吧 } //删除temp XDirectory.DeleteIfExists(binary_path_temp); XDirectory.DeleteIfExists(binary_path_temp_remote); } catch (Exception e) { flag_process_error = true; XDirectory.DeleteIfExists(binary_path); throw e; } } if (!flag_process_error) { //登记到索引 var vr = new VersionRecord() { versionCode = versionCode, versionName = versionName, desc = versionDesc, build_id = build_id }; //记录版本 branch.AddVersion(ref vr); //保存版本索引 SaveBranchFile(ref branch); } } } }