aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/MachineStudio')
-rw-r--r--Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/MachineStudioPublisher.cs249
-rw-r--r--Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishOptions.cs87
-rw-r--r--Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishProgressEventArgs.cs16
3 files changed, 352 insertions, 0 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/MachineStudioPublisher.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/MachineStudioPublisher.cs
new file mode 100644
index 000000000..19f186525
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/MachineStudioPublisher.cs
@@ -0,0 +1,249 @@
+using CommandLine;
+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.Cryptography;
+using Tango.Core.Helpers;
+using Tango.MachineStudio.Common.Web;
+using Tango.Transport.Web;
+using Tango.Web;
+
+namespace Tango.MachineStudio.Common.Publish
+{
+ public class MachineStudioPublisher : ExtendedObject
+ {
+ private IMachineStudioService _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="MachineStudioPublisher"/> class.
+ /// </summary>
+ public MachineStudioPublisher()
+ {
+ _client = new MachineStudioService();
+ Options = new PublishOptions();
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MachineStudioPublisher"/> class.
+ /// </summary>
+ /// <param name="publishOptions">The publish options.</param>
+ public MachineStudioPublisher(PublishOptions publishOptions) : this()
+ {
+ Options = publishOptions;
+ }
+
+ /// <summary>
+ /// Gets the latest version.
+ /// </summary>
+ /// <returns></returns>
+ public async Task<String> GetRemoteVersion()
+ {
+ _client.Environment = Options.Environment;
+ var response = await _client.GetLatestVersion(new LatestVersionRequest());
+ 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(GetMachineStudioExecutablePath()).ProductVersion;
+ }
+
+ /// <summary>
+ /// Gets the machine studio executable path.
+ /// </summary>
+ /// <returns></returns>
+ public String GetMachineStudioExecutablePath()
+ {
+ String appPath = Path.Combine(Options.GetApplicationPath(), "Tango.MachineStudio.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()
+ {
+ Email = Options.Email,
+ Password = Options.Password,
+ Version = GetLocalVersion(),
+ }).Result.AccessToken;
+ });
+ }
+
+ /// <summary>
+ /// Publish a machine studio version using the specified <see cref="Options"/>.
+ /// </summary>
+ /// <returns></returns>
+ public Task Publish()
+ {
+ _client.Environment = Options.Environment;
+
+ String appPath = GetMachineStudioExecutablePath();
+ String folder = Options.GetApplicationPath();
+ String accessToken = String.Empty;
+
+ if (!File.Exists(appPath))
+ {
+ throw new FileNotFoundException($"Could not locate the machine studio executable at {appPath}.");
+ }
+
+ String tempFile = TemporaryManager.CreateFile();
+
+ return Task.Factory.StartNew(() =>
+ {
+ 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().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()
+ {
+ AccessToken = accessToken,
+ Version = local_version,
+ Comments = Options.Comments,
+ }).Result;
+
+ OnPublishProgress(0, 100, $"Starting version packaging...");
+
+ using (ZipFile zip = new ZipFile())
+ {
+ zip.AddDirectory(Path.Combine(folder, "x86"), "/x86");
+ zip.AddDirectory(Path.Combine(folder, "x64"), "/x64");
+
+ var files = Directory.GetFiles(folder, "*.*", SearchOption.TopDirectoryOnly).ToList();
+
+ foreach (var file in files)
+ {
+ 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(0, 100, $"Starting version upload...");
+
+ using (StorageBlobUploader uploader = new StorageBlobUploader(response.BlobAddress, tempFile))
+ {
+ uploader.Progress += (x, e) =>
+ {
+ 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,
+ }).Wait();
+
+ remote_version = GetRemoteVersion().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>
+ /// 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,
+ });
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishOptions.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishOptions.cs
new file mode 100644
index 000000000..047d7c0b4
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishOptions.cs
@@ -0,0 +1,87 @@
+using CommandLine;
+using CommandLine.Text;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tango.Core;
+using Tango.Web;
+
+namespace Tango.MachineStudio.Common.Publish
+{
+ public class PublishOptions : ExtendedObject
+ {
+ public event EventHandler EnvironmentChanged;
+ public event EventHandler BuidConfigChanged;
+ public event EventHandler BasicInfoChanged;
+
+ private String basePath;
+ [Option("path", HelpText = "Specifies the application base path.", Required = false)]
+ public String BasePath
+ {
+ get { return basePath; }
+ set { basePath = value; RaisePropertyChangedAuto(); }
+ }
+
+ private String _buildConfig;
+ [Option("build", HelpText = "Specifies the build configuration.", Required = false, DefaultValue = "Release")]
+ public String BuildConfig
+ {
+ get { return _buildConfig; }
+ set { _buildConfig = value; RaisePropertyChangedAuto(); BuidConfigChanged?.Invoke(this, new EventArgs()); }
+ }
+
+ private String _email;
+ [Option("email", HelpText = "Email account used for login to the machine service.", Required = true)]
+ public String Email
+ {
+ get { return _email; }
+ set { _email = value; RaisePropertyChangedAuto(); BasicInfoChanged?.Invoke(this, new EventArgs()); }
+ }
+
+ private String _password;
+ [Option("pass", HelpText = "Password used for login to the machine service.", Required = true)]
+ public String Password
+ {
+ get { return _password; }
+ set { _password = value; RaisePropertyChangedAuto(); BasicInfoChanged?.Invoke(this, new EventArgs()); }
+ }
+
+ private String _comments;
+ [Option("comments", HelpText = "Optional comments that are attached to this release.", Required = false, DefaultValue = "No comments.")]
+ public String Comments
+ {
+ get { return _comments; }
+ set { _comments = value; RaisePropertyChangedAuto(); BasicInfoChanged?.Invoke(this, new EventArgs()); }
+ }
+
+ private DeploymentSlot _environment;
+ [Option("env", HelpText = "Specifies the target environment to publish.", Required = true)]
+ public DeploymentSlot Environment
+ {
+ get { return _environment; }
+ set { _environment = value; RaisePropertyChangedAuto(); EnvironmentChanged?.Invoke(this, new EventArgs()); }
+ }
+
+ private String _installerProject;
+ [Option("installer-project-file", HelpText = "Specifies the advanced installer project file to build and upload.", Required = false)]
+ public String InstallerProject
+ {
+ get { return _installerProject; }
+ set { _installerProject = value; RaisePropertyChangedAuto(); }
+ }
+
+ public PublishOptions()
+ {
+ BasePath = AppDomain.CurrentDomain.BaseDirectory + "..\\";
+ BuildConfig = "Release";
+ }
+
+ public String GetApplicationPath()
+ {
+ return Path.Combine(BasePath, BuildConfig);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishProgressEventArgs.cs b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishProgressEventArgs.cs
new file mode 100644
index 000000000..ff550b9de
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Publish/PublishProgressEventArgs.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tango.MachineStudio.Common.Publish
+{
+ public class PublishProgressEventArgs : EventArgs
+ {
+ public double Progress { get; set; }
+ public double Total { get; set; }
+ public String Message { get; set; }
+ public bool SingleLineRecommended { get; set; }
+ }
+}