Example #1
0
 public ApplicationUpdater(ApplicationUpdaterConfig config, CancellationToken cancellationToken = default)
 {
     this.cancellationToken = cancellationToken;
     this.config            = ApplicationUpdaterConfigFactory.Create(config);
 }
        public static ApplicationUpdaterConfig Create(ApplicationUpdaterConfig config = null, FileVersionInfo info = null, Assembly assembly = null)
        {
            var Args = config ?? new ApplicationUpdaterConfig();

            if (info == null)
            {
                var module = Process.GetCurrentProcess().MainModule;
                if (module == null)
                {
                    throw new NotSupportedException("Can't infer application updater args as the main module for the current process can't be found");
                }
                info = module.FileVersionInfo;
            }

            if (assembly == null)
            {
                assembly = Assembly.GetEntryAssembly();
            }

            // Infer any arguments from the running executable
            Args.FullFileName ??= info.FileName;
            Args.FileName ??= Path.GetFileName(Args.FullFileName);
            Args.Name ??= Path.GetFileNameWithoutExtension(Args.FileName);

            Args.Version ??= info.FileVersion;
            Args.AssetName ??= Args.FileName;
            Args.CompanyName ??= info.CompanyName;
            Args.ProductName ??= info.ProductName;
            Args.Progress ??= new Progress <ProgressModel>();

            if (Args.Name == null)
            {
                throw new ArgumentNullException(nameof(Args.Name), "Short filename is null");
            }
            Args.InstallPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", Args.Name);

            Args.UpdateSuffix ??= ApplicationUpdaterConfig.DefaultUpdateSuffix;

            // Get the InstallSharp attribute, which has custom configuration that might not be inferred or passed in manual configuration
            var attribute = assembly?.GetCustomAttribute <InstallSharpAttribute>();

            // Find the application url if not passed
            if (Args.UpdateUrl == null)
            {
                if (!string.IsNullOrWhiteSpace(attribute?.Url))
                {
                    // The application url is specified in the InstallSharpAttribute
                    Args.UpdateUrl = attribute.Url;
                }
                else
                {
                    // Try to automatically infer a GitHub url from the application name and company
                    Args.UpdateUrl = "github.com/" + Args.CompanyName.Replace(" ", "") + "/" + Args.Name.Replace(" ", "");
                }
            }

            // Get a GUID for the program. In order of precendance, it can be specified:
            //
            // 1. In the ApplicationUpdateConfig passed to ApplicationUpdater
            // 2. In the InstallSharpAttribute on the application assembly
            // 3. In the GuidAttribute on the application assembly

            // 1. In the ApplicationUpdateConfig passed to ApplicationUpdater
            if (Args.Guid != Guid.Empty)
            {
                return(Args);
            }

            // 2. In the InstallSharpAttribute on the application assembly
            if (!string.IsNullOrWhiteSpace(attribute?.Guid))
            {
                if (!Guid.TryParse(attribute.Guid, out var guid))
                {
                    throw new FormatException($"Couldn't parse GUID from InstallSharpAttribute: '{attribute.Guid}'");
                }
                Args.Guid = guid;
                return(Args);
            }

            // 3. In the GuidAttribute on the application assembly
            var guidAttribute = assembly.GetCustomAttribute <GuidAttribute>();

            if (!string.IsNullOrWhiteSpace(guidAttribute?.Value))
            {
                if (!Guid.TryParse(guidAttribute.Value, out var guid))
                {
                    throw new FormatException($"Couldn't parse GUID from assembly attribute: '{guidAttribute.Value}'");
                }
                Args.Guid = guid;
                return(Args);
            }

            return(Args);
        }
        public static CommandLineArguments Parse(ApplicationUpdaterConfig config)
        {
            var cmd = new CommandLineArguments();

            // Default to no setup command unless we can find one
            cmd.Command = Command.None;

            var commandLine = config.CommandLine ?? Environment.CommandLine;

            // Split the command line up into strings we can parse

            // Args are positional, and exclude any flags (args that start with '/', '+' or '-')
            cmd.Args = commandLine.Split(" ", StringSplitOptions.RemoveEmptyEntries).Where(x => !IsFlag(x)).Select(x => x.Trim()).ToArray();

            // Collect the flags, removing the leading flag characters, then trimming and making lower case for later comparison
            cmd.Flags = commandLine.Split(" ", StringSplitOptions.RemoveEmptyEntries).Where(IsFlag)
                        .Select(x => x.TrimStart(flagChars).Trim().ToLowerInvariant())
                        .ToArray();

            // If we're executing as *.update.exe, then applying a side-by-side update is inferred
            var isUpdateExe = config.FileName?.EndsWith(config.UpdateSuffix, StringComparison.OrdinalIgnoreCase);

            if (isUpdateExe == true)
            {
                cmd.Command = Command.ApplyUpdate;
            }
            else
            {
                // If there is no first argument, or it isn't "setup", then this isn't a setup commandline, so we do nothing.
                if (cmd.Args.Length == 0)
                {
                    return(cmd);
                }
                if (!cmd.Args[0].Equals(config.CommandLineArgument ?? ApplicationUpdaterConfig.DefaultSetupArg, StringComparison.OrdinalIgnoreCase))
                {
                    return(cmd);
                }

                if (cmd.Args.Length == 1)
                {
                    // If the only command was "setup" then we can infer "install" as the command
                    cmd.Command = Command.Install;
                }
                else
                {
                    // Parse the command
                    if (!Enum.TryParse(cmd.Args[1].Trim(), true, out Command command))
                    {
                        Console.WriteLine($"Unknown command: ${cmd.Args[1].Trim()}");
                        return(cmd);
                    }

                    cmd.Command = command;
                }
            }

            // Parse optional flag arguments that can exist on any commands
            foreach (var arg in cmd.Flags)
            {
                if (silentArgs.Any(x => x == arg))
                {
                    cmd.Silent = true;
                }
                else if (launchArgs.Any(x => x == arg))
                {
                    cmd.Launch = true;
                }
                else if (adminArgs.Any(x => x == arg))
                {
                    cmd.Elevate = true;
                }
            }

            // Parse optional positional arguments for specific commands
            switch (cmd.Command)
            {
            case Command.Install:
            case Command.Update:
                if (cmd.Args.Length > 2)
                {
                    cmd.Target = Path.GetFullPath(cmd.Args[2]);
                }
                break;
            }

            return(cmd);
        }