diff options
Diffstat (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs')
| -rw-r--r-- | Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs new file mode 100644 index 000000000..1c69f0934 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs @@ -0,0 +1,352 @@ +using Ionic.Zip; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.Helpers; +using Tango.PPC.Common.Web; +using Tango.SQLExaminer; +using Tango.Transport.Web; +using Tango.Web; + +namespace Tango.PPC.Common.Publish +{ + public class PPCPublisher : ExtendedObject + { + private IPPCWebService _client; + + /// <summary> + /// Occurs on publish progress. + /// </summary> + public event EventHandler<PublishProgressEventArgs> PublishProgress; + + private PublishOptions _options; + /// <summary> + /// Gets or sets the publish options. + /// </summary> + public PublishOptions Options + { + get { return _options; } + set { _options = value; RaisePropertyChangedAuto(); } + } + + /// <summary> + /// Initializes a new instance of the <see cref="PPCPublisher"/> class. + /// </summary> + public PPCPublisher() + { + _client = new PPCWebService(); + Options = new PublishOptions(); + } + + /// <summary> + /// Initializes a new instance of the <see cref="PPCPublisher"/> class. + /// </summary> + /// <param name="publishOptions">The publish options.</param> + public PPCPublisher(PublishOptions publishOptions) : this() + { + Options = publishOptions; + } + + /// <summary> + /// Gets the latest version. + /// </summary> + /// <returns></returns> + public async Task<String> GetRemoteVersion(String machineVersionGuid) + { + _client.Environment = Options.Environment; + var response = await _client.GetLatestVersion(new LatestVersionRequest() + { + MachineVersionGuid = machineVersionGuid, + }); + return response.Version; + } + + /// <summary> + /// Gets the latest version. + /// </summary> + /// <returns></returns> + public async Task<String> GetRemoteVersion(DeploymentSlot environment) + { + _client.Environment = environment; + var response = await _client.GetLatestVersion(new LatestVersionRequest()); + return response.Version; + } + + /// <summary> + /// Gets the latest version. + /// </summary> + /// <returns></returns> + public String GetLocalVersion() + { + return FileVersionInfo.GetVersionInfo(GetPPCExecutablePath()).ProductVersion; + } + + /// <summary> + /// Gets the PPC executable path. + /// </summary> + /// <returns></returns> + public String GetPPCExecutablePath() + { + String appPath = Path.Combine(Options.GetApplicationPath(), "Tango.PPC.UI.exe"); + return appPath; + } + + /// <summary> + /// Login to machine service and returns an access token. + /// </summary> + /// <returns></returns> + private Task<String> Login() + { + return Task.Factory.StartNew<String>(() => + { + return _client.Login(new LoginRequest() + { + Mode = LoginMode.User, + Email = Options.Email, + Password = Options.Password, + }).Result.AccessToken; + }); + } + + /// <summary> + /// Publish a PPC version using the specified <see cref="Options"/>. + /// </summary> + /// <returns></returns> + public Task Publish() + { + _client.Environment = Options.Environment; + + String appPath = GetPPCExecutablePath(); + String folder = Options.GetApplicationPath(); + String accessToken = String.Empty; + + if (!File.Exists(appPath)) + { + throw new FileNotFoundException($"Could not locate the PPC executable at {appPath}."); + } + + return Task.Factory.StartNew(() => + { + String tempFile = TemporaryManager.CreateFile(".zip"); + + try + { + OnPublishProgress(0, 100, $"Logging in to machine service at {Options.Environment.ToAddress()}..."); + accessToken = Login().Result; + + OnPublishProgress(0, 100, $"Fetching remote version from {Options.Environment.ToAddress()}..."); + + String remote_version = GetRemoteVersion(Options.MachineVersionGuid).Result; + String local_version = GetLocalVersion(); + + OnPublishProgress(0, 100, $"Remote version: {remote_version}"); + OnPublishProgress(0, 100, $"Local version: {local_version}"); + + if (Version.Parse(local_version) <= Version.Parse(remote_version)) + { + throw new InvalidOperationException($"The local version '{local_version}' is not greater than the remote version '{remote_version}'."); + } + + OnPublishProgress(0, 100, $"Requesting version upload..."); + + var response = _client.UploadVersion(new UploadVersionRequest() + { + Comments = Options.Comments, + Version = local_version, + MachineVersionGuid = Options.MachineVersionGuid, + AccessToken = accessToken, + }).Result; + + CreateTupPackage(tempFile).Wait(); + + OnPublishProgress(0, 100, $"Starting version upload..."); + + using (StorageBlobUploader uploader = new StorageBlobUploader(response.BlobAddress, tempFile)) + { + uploader.Progress += (x, e) => + { + InvokeUINow(() => + { + OnPublishProgress(e.Current, e.Total, $"Uploading to storage {(((double)e.Current / (double)e.Total) * 100d).ToString("0.0")}%...", true); + }); + }; + + uploader.Upload().Wait(); + } + + OnPublishProgress(100, 100, $"Finalizing version upload..."); + + _client.NotifyUploadCompleted(new UploadCompletedRequest() + { + AccessToken = accessToken, + Token = response.Token, + }); + + remote_version = GetRemoteVersion(Options.MachineVersionGuid).Result; + local_version = GetLocalVersion(); + + OnPublishProgress(0, 0, $"Remote version: {remote_version}"); + OnPublishProgress(0, 0, $"Local version: {local_version}"); + + if (remote_version != local_version) + { + throw new InvalidOperationException("The remote version does not seems to have been updated."); + } + + OnPublishProgress(0, 0, "Version published successfully."); + } + catch (Exception ex) + { + OnPublishProgress(0, 100, $"Failed: {ex.Message}"); + throw ex; + } + finally + { + PathHelper.TryDeleteFile(tempFile); + } + }); + } + + /// <summary> + /// Creates a Tango Update Package (.tup) file. + /// </summary> + /// <param name="filePath">The file path.</param> + /// <returns></returns> + public Task CreateTupPackage(String filePath) + { + return Task.Factory.StartNew(() => + { + try + { + OnPublishProgress(0, 100, "Generating .tup file..."); + + String appPath = GetPPCExecutablePath(); + String folder = Options.GetApplicationPath(); + + if (!File.Exists(appPath)) + { + throw new FileNotFoundException($"Could not locate the PPC executable at {appPath}."); + } + + if (!File.Exists(Options.TfpPath)) + { + throw new FileNotFoundException($"Could not locate TFP file at {Options.TfpPath}."); + } + + var tempFile = filePath; + + using (ZipFile zip = new ZipFile()) + { + zip.AddFile(Options.TfpPath, "/"); + + String provision_dir = "Provision Scripts"; + + zip.AddDirectoryByName(provision_dir); + + ExaminerSequenceConfiguration provision_config = new ExaminerSequenceConfiguration(); + + OnPublishProgress(0, 100, "Processing provisioning scripts..."); + + foreach (var item in Options.Synchronization.ProvisionSequenceItems) + { + OnPublishProgress(0, 100, $"Processing provisioning script '{item.Name}'..."); + + provision_config.Items.Add(new ExaminerSequenceItem() + { + Direction = item.Direction, + FileName = item.FileName, + Index = item.Index, + Name = item.Name, + Type = item.Type, + RequiresSerialNumber = item.RequiresSerialNumber + }); + + zip.AddFile(item.FilePath, provision_dir); + } + + String provision_config_file = TemporaryManager.CreateFile(".zip"); + provision_config.ToFile(provision_config_file); + + var cf = zip.AddFile(provision_config_file, provision_dir); + cf.FileName = provision_dir + "\\config.xml"; + + String update_dir = "Update Scripts"; + + zip.AddDirectoryByName(update_dir); + + ExaminerSequenceConfiguration update_config = new ExaminerSequenceConfiguration(); + + OnPublishProgress(0, 100, "Processing update scripts..."); + + foreach (var item in Options.Synchronization.UpdateSequenceItems) + { + OnPublishProgress(0, 100, $"Processing update script '{item.Name}'..."); + + update_config.Items.Add(new ExaminerSequenceItem() + { + Direction = item.Direction, + FileName = item.FileName, + Index = item.Index, + Name = item.Name, + Type = item.Type, + RequiresSerialNumber = item.RequiresSerialNumber + }); + + zip.AddFile(item.FilePath, update_dir); + } + + String update_config_file = TemporaryManager.CreateFile(".zip"); + update_config.ToFile(update_config_file); + + var cuf = zip.AddFile(update_config_file, update_dir); + cuf.FileName = update_dir + "\\config.xml"; + + foreach (var file in Directory.GetFiles(folder, "*.*", SearchOption.TopDirectoryOnly)) + { + zip.AddFile(file, "/"); + } + + zip.SaveProgress += (x, e) => + { + if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry) + { + OnPublishProgress(e.EntriesSaved + 1, e.EntriesTotal, $"Compressing files {(((double)(e.EntriesSaved + 1) / (double)e.EntriesTotal) * 100d).ToString("0.0")}%...", true); + } + }; + + zip.Save(tempFile); + + OnPublishProgress(100, 100, "TUP file generated successfully."); + } + } + catch (Exception ex) + { + OnPublishProgress(0, 100, $"Failed: {ex.Message}"); + throw ex; + } + }); + } + + /// <summary> + /// Raises the publish progress event. + /// </summary> + /// <param name="progress">The progress.</param> + /// <param name="total">The total.</param> + /// <param name="message">The message.</param> + protected virtual void OnPublishProgress(double progress, double total, String message, bool singleLine = false) + { + PublishProgress?.Invoke(this, new PublishProgressEventArgs() + { + Progress = progress, + Total = total, + Message = message, + SingleLineRecommended = singleLine, + }); + } + } +} |
