aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/PPC/Tango.PPC.Common/Publish/PPCPublisher.cs
diff options
context:
space:
mode:
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.cs352
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,
+ });
+ }
+ }
+}