/// <summary> /// The (non-static) startup method /// </summary> /// <param name = "args"> /// The command line arguments. /// </param> /// <returns> /// Process return code. /// </returns> protected override int Main(IEnumerable<string> args) { try { pkgMgr = new PackageManager(); #region command line parsing // default: var options = args.Switches(); var parameters = args.Parameters(); foreach (var arg in options.Keys) { var argumentParameters = options[arg]; switch (arg) { /* options */ /* global switches */ case "load-config": // all ready done, but don't get too picky. break; case "nologo": this.Assembly().SetLogo(string.Empty); break; case "show-tools": showTools = Boolean.Parse(argumentParameters.First()); break; case "help": return Help(); default: if (arg.StartsWith("package-")) { var argName = arg.Substring(8); var argValue = argumentParameters.First(); switch (argName) { case "name": package.PackageName = argValue; break; case "version": package.PackageVersion = argValue; break; case "arch": package.PackageArch = argValue; break; case "icon": package.IconPath = argValue; break; case "short-desc": package.ShortDescriptionPath = argValue; break; case "description": package.DescriptionPath = argValue; break; case "author-version": package.AuthorVersion = argValue; break; case "display-name": package.DisplayName = argValue; break; case "policy": package.BindingPolicy = argValue; break; case "license": package.LicensePath = argValue; break; case "license-url": package.LicenseUrlEntry = argValue; break; case "orig-location": package.Location = argValue; break; case "feed-location": package.Feed = argValue; break; default: throw new ConsoleException(Resources.UnknownParameter, arg); } } else if (arg.StartsWith("identity-")) { var argName = arg.Substring(9); var argValue = argumentParameters.First(); switch (argName) { case "cert-file": package.CertificateFile = argValue; break; case "cert-pass": certificatePassword = argValue; break; case "email": package.PubEmail = argValue; break; case "website": package.PubWebsite = argValue; break; default: throw new ConsoleException(Resources.UnknownParameter, arg); } } //we do else if (arg.StartsWith("dependency-")) { var argName = arg.Substring(11); var argValue = argumentParameters.First(); ; switch (argName) { case "add": package.DependencyNames.Add(argValue); break; default: throw new ConsoleException(Resources.UnknownParameter, arg); } } else if (arg.StartsWith("app-")) { if (package.Apps == null) package.Apps = new App(); parseAppArgument(arg.Substring(4), argumentParameters.First()); } else if (arg.StartsWith("sharedlib-")) { if (package.SharedLibs == null) package.SharedLibs = new SharedLib(); parseSharedLibArgument(arg.Substring(10), argumentParameters.First()); } else { throw new ConsoleException(Resources.UnknownParameter, arg); } break; } } Logo(); /* if (parameters.Count() < 1) { throw new ConsoleException(Resources.MissingCommand); } */ #endregion // GS01: I'm putting this in here so that feed resoltion happens before we actually get around to doing something. // Look into the necessity later. Tasklet.WaitforCurrentChildTasks(); #region Tool Scanning Console.Write(Resources.ToolLookup); _candle = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("candle.exe")); _light = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("light.exe")); _mt = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("mt.exe")); _makecat = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("makecat.exe")); _al = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("al.exe")); _signTool = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("signTool.exe")); _sn = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("sn.exe")); _pktExtract = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("pktExtract.exe")); if (_candle.Executable == null) errors.Add(Resources.MissingCandle); if (_light.Executable == null) errors.Add(Resources.MissingLight); if (_mt.Executable == null) errors.Add(Resources.MissingMt); if (_makecat.Executable == null) errors.Add(Resources.MissingMakeCat); if (_al.Executable == null) errors.Add(Resources.MissingAl); if (_signTool.Executable == null) errors.Add(Resources.MissingSignTool); if (_sn.Executable == null) errors.Add(Resources.MissingSn); if (_pktExtract.Executable == null) errors.Add(Resources.MissingPktExtract); if (errors.AreFatal()) { throw new ConsoleException(errors.StringOut()); } Console.WriteLine(Resources.Finished); if (showTools) { Console.WriteLine("Tools:"); Console.WriteLine(_candle.Executable); Console.WriteLine(_light.Executable); Console.WriteLine(_mt.Executable); Console.WriteLine(_makecat.Executable); Console.WriteLine(_al.Executable); Console.WriteLine(_signTool.Executable); Console.WriteLine(_sn.Executable); } #endregion Console.WriteLine(Resources.ScanningInstalledPackages); var installedPackages = pkgMgr.GetInstalledPackages(new PackageManagerMessages { PackageScanning = (progress) => { Resources.Scanning.PrintProgressBar(progress); } }); installedPackages.Wait(); // the progress bar never sends in a line break Console.WriteLine(); //TODO check for invalid file paths //TODO check for pre-signed files and whether they're properly signed //TODO make sure files in app roles are proper children //TODO this doesn't work if the packages are a superceding version of the one given //TODO this doesn't work if the packages are in the same directory //get the dependencies and Assemblies foreach (var dep in package.DependencyNames) { var depPackage = (from p in installedPackages.Result where p.CosmeticName.IsWildcardMatch(dep) orderby p.Version descending select p).FirstOrDefault(); if (depPackage == null) { errors.Add(Resources.DepNotSatifiable.format(dep)); } else { package.DependencyInfo.Add(depPackage); } } //TODO make sure the numbers are not larger than the max a part of a version string var policyRegex = new Regex(@"^policy\.\d{1,5}\.\d{1,5}\.\S+$"); var dependentAssemblies = from p in package.DependencyInfo from a in p.Assemblies where !a.Type.Contains("policy") && !policyRegex.IsMatch(a.Name) select a; #region Sanity checking primarily //let's check for valid roles! if (package.SharedLibs == null && package.Apps == null) errors.Add(Resources.NoRoles); if (package.PackageArch == null || (!ValidArchs.Contains(package.PackageArch.ToLower()) && package.PackageArch != "auto")) errors.Add(Resources.MissingPackageArch); if (package.PackageVersion == null || !package.PackageVersion.IsValidVersion() && package.PackageVersion != "auto") errors.Add(Resources.MissingPackageVersion); if ((package.PackageArch == "auto" || package.PackageVersion == "auto") && firstBinFile == null) errors.Add(Resources.NoBinaryFileProvided); //get Arch and Version if it's auto if (package.PackageArch == "auto") { if (firstBinFile != null) { var binType = ProgramFinder.GetExeType(firstBinFile); if (binType.HasFlag(ExecutableInfo.any) || binType.HasFlag(ExecutableInfo.managed)) package.PackageArch = "any"; else if (binType.HasFlag(ExecutableInfo.x86)) package.PackageArch = "x86"; else if (binType.HasFlag(ExecutableInfo.x64)) package.PackageArch = "x64"; else errors.Add(Resources.NoArchDiscovered.format(firstBinFile)); } } if (package.PackageVersion == "auto") { if (firstBinFile != null) { var versionStr = ProgramFinder.GetToolVersion(firstBinFile); if (versionStr == null || !versionStr.IsValidVersion()) errors.Add(Resources.NoVersionDiscovered.format(firstBinFile)); else package.PackageVersion = versionStr; } } //TODO make sure the name is valid! //make sure the major minors given are valid if (package.SharedLibs != null) { foreach (var i in package.SharedLibs.MajorMinorsToReplace) { if (!i.IsValidMajorMinorVersion()) { errors.Add(Resources.InvalidMajorMinor.format(i)); } } } //load and check pfx file var pfxStore = PfxStoreLoader.Load(package.CertificateFile, certificatePassword); if (pfxStore == null) errors.Add(Resources.InvalidPfx); else { var codeSigningCert = pfxStore.FindCodeSigningCert(); if (codeSigningCert == null) errors.Add(Resources.NoCodeSigningCert); else { if ((package.PubToken = codeSigningCert.PublicKeyTokenAsString()) == null) { errors.Add(Resources.FailedPktExtraction); } var nameParts = codeSigningCert.GetSubjectNameParts(); if (nameParts.ContainsKey("CN")) { package.PubName = nameParts["CN"]; } else { errors.Add(Resources.NoNameExtracted.format(package.CertificateFile)); } if (package.PubEmail == "auto") { if (nameParts.ContainsKey("E")) { package.PubEmail = nameParts["E"]; } else { errors.Add(Resources.NoPubEmailFound.format(package.CertificateFile)); } } } } if (package.PubEmail != null && !package.PubEmail.IsEmail()) { errors.Add(Resources.InvalidEmail.format(package.PubEmail)); } if (package.IconPath != null) { try { var iconFile = File.ReadAllBytes(package.IconPath); using (var bytes = new MemoryStream(iconFile)) { Image image = Image.FromStream(bytes); if (image.RawFormat != ImageFormat.Png || image.Height != REQUIRED_ICON_HEIGHT || image.Width != REQUIRED_ICON_WIDTH) { errors.Add(Resources.InvalidIconFile. format(package.IconPath, REQUIRED_ICON_WIDTH, REQUIRED_ICON_HEIGHT)); } } package.Icon = Convert.ToBase64String(iconFile); } catch (OutOfMemoryException) { errors.Add(Resources.InvalidIconFile. format(package.IconPath, REQUIRED_ICON_WIDTH, REQUIRED_ICON_HEIGHT)); } catch (IOException) { errors.Add(Resources.FailedIconFileOpen.format(package.IconPath)); } } else { package.Icon = Convert.ToBase64String(Resources.blankicon); } if (package.ShortDescriptionPath != null) { try { package.ShortDescription = File.ReadAllText(package.ShortDescriptionPath); if (package.ShortDescriptionPath.Length > MAX_SUMMARY_DESCRIPTION_LENGTH) { errors.Add(Resources.ShortDescriptionTooLong. format(package.ShortDescriptionPath, MAX_SUMMARY_DESCRIPTION_LENGTH)); } } catch (NotSupportedException) { errors.Add(Resources.InvalidShortDescriptionFile.format(package.ShortDescriptionPath)); } catch (IOException) { errors.Add(Resources.FailedShortDescriptionFileOpen.format(package.ShortDescriptionPath)); } } if (package.DescriptionPath != null) { try { package.Description = File.ReadAllText(package.DescriptionPath); } catch (NotSupportedException) { errors.Add(Resources.InvalidDescriptionFile.format(package.DescriptionPath)); } catch (IOException) { errors.Add(Resources.FailedDescriptionFileOpen.format(package.DescriptionPath)); } } if (package.PublishDate != null) { try { DateTime.Parse(package.PublishDate); } catch (FormatException) { errors.Add(Resources.InvalidPublishDate.format(package.PublishDate)); } } else { package.PublishDate = DateTime.Now.ToShortDateString(); } if (package.LicensePath != null) { try { package.LicenseText = File.ReadAllText(package.LicensePath); if (package.LicenseUrlEntry != null) { try { var uri = new Uri(package.LicenseUrlEntry); if (!uri.IsHttpScheme()) errors.Add(Resources.InvalidLicenseUrlScheme.format(package.LicenseUrlEntry)); package.LicenseUrl = package.CreateUrl(package.LicenseUrlEntry, "license"); } catch (UriFormatException) { errors.Add(Resources.InvalidLicenseUrl.format(package.LicenseUrlEntry)); } } } catch (NotSupportedException) { errors.Add(Resources.InvalidLicenseText.format(package.LicensePath)); } catch (IOException) { errors.Add(Resources.FailedLicenseFileOpen.format(package.LicensePath)); } } else { if (package.LicenseUrlEntry != null) { errors.Add(Resources.LicenseUrlWithoutText, false); } } if (package.Feed != null) { try { var uri = new Uri(package.Feed); if (!uri.IsHttpScheme()) errors.Add(Resources.InvalidFeedUrlScheme.format(package.Feed)); package.FeedUrl = package.CreateUrl(package.Feed, "feed_location"); } catch (UriFormatException) { errors.Add(Resources.InvalidFeedUrl.format(package.Feed)); } } if (package.Location != null) { try { var uri = new Uri(package.Location); if (!uri.IsHttpScheme()) errors.Add(Resources.InvalidOriginalUrlScheme.format(package.Location)); package.LocationUrl = package.CreateUrl(package.Location, "original_location"); } catch (UriFormatException) { errors.Add(Resources.InvalidOriginalUrl.format(package.Location)); } } if (errors.AreFatal()) { throw new ConsoleException(errors.StringOut()); } foreach (Match m in Regex.Matches(package.BindingPolicy, @"{{(\$CURRENT-\d+)}}")) { var i = m.Groups[1].Value; var two = i.Split('-'); package.BindingPolicy = package.BindingPolicy.Replace(m.Value, (package.PackageVersion.VersionStringToUInt64() - UInt64.Parse(two[1])).UInt64VersiontoString()); } if (package.BindingPolicy.IsValidVersion()) { if (package.BindingPolicy.VersionStringToUInt64() >= package.PackageVersion.VersionStringToUInt64()) { errors.Add(Resources.BindingVersionTooHigh.format(package.BindingPolicy)); } else { package.BindingMin = package.BindingPolicy; package.BindingMax = package.BindingPolicy; } } else { var parts = package.BindingPolicy.Split('-'); bool ret = parts.Length == 2; for (int i = 0; ret && i < 2; i++) { ret &= parts[i].IsValidVersion(); } if (!ret) { errors.Add(Resources.InvalidPolicy.format(package.BindingPolicy)); } else { if (parts[0].VersionStringToUInt64() >= package.PackageVersion.VersionStringToUInt64()) { errors.Add(Resources.BindingVersionTooHigh.format(parts[0])); } if (parts[1].VersionStringToUInt64() >= package.PackageVersion.VersionStringToUInt64()) { errors.Add(Resources.BindingVersionTooHigh.format(parts[1])); } package.BindingMin = parts[0]; package.BindingMax = parts[1]; } } //find all the files that need to be found recursively if (package.Apps != null) { var wildcards = (from p in package.Apps.FilePaths where p.Contains("*") select p).ToList(); foreach (var w in wildcards) { package.Apps.FilePaths.AddRange(w.FindFilesSmarter(SearchOption.AllDirectories)); } //remove wildcards package.Apps.FilePaths.RemoveAll((fp) => fp.Contains("*")); //remove duplicates based on canonical path and make them relative var exeFiles = package.Apps.PrimaryExes.Values.Select((e) => e.ExeFile); var sharedLibFiles = package.SharedLibs.Assemblies.Values. SelectMany((a) => a.PrimaryFile.SingleItemAsEnumerable().Concat(a.OtherFiles)); package.Apps.FilePaths = package.Apps.FilePaths.Except(exeFiles.Concat(sharedLibFiles), new PathEqualityComparer()).Select((p) => Environment.CurrentDirectory.RelativePathTo(p)).ToList(); } if (errors.AreFatal()) { throw new ConsoleException(errors.StringOut()); } #endregion #region Handle Shared Libraries //first create the string of all the dependencies elements var sharedlib = package.SharedLibs; if (sharedlib != null) { Console.Write(Resources.SharedLibCreation); if (package.PackageArch != "any") { var dependencyStr = new StringBuilder(); foreach (var dep in dependentAssemblies) { dependencyStr.Append(DependencyEntry.Replace("[$LIBTYPE]", dep.Type).Replace("[$LIBNAME]", dep.Name). Replace("[$LIBVERSION]", dep.Version).Replace("[$ARCH]", dep.Arch). Replace("[$PUBLICKEYTOKEN]", dep.PublicKeyToken)); } foreach (var a in sharedlib.Assemblies.Values) { var manifestFilesString = new StringBuilder(); var filesString = new StringBuilder(); filesString.Append(FileEntry.Replace("[$FILE]", Path.GetFileName(a.PrimaryFile))); foreach (var f in a.OtherFiles) { filesString.Append(FileEntry.Replace("[$FILE]", Path.GetFileName(f))); } manifestFilesString.Append(SharedLibraryManifest.Replace("[$LIBNAME]", a.Name). Replace("[$LIBVERSION]", package.PackageVersion). Replace("[$DEPENDENCY]", dependencyStr.ToString()).Replace("[$PUBLICKEYTOKEN]", package.PubToken). Replace("[$ARCH]", package.PackageArch).Replace("[$FILES]", filesString.ToString())); a.Manifest = Path.Combine(new FileInfo(a.PrimaryFile).DirectoryName, a.PrimaryFile + ".manifest"); //TODO do file checking File.WriteAllText(a.Manifest, manifestFilesString.ToString()); // sign all the non-primary BinFiles var binFiles = from f in a.OtherFiles where Path.GetExtension(f) == ".exe" || Path.GetExtension(f) == ".dll" select f; foreach (var f in binFiles) { signFile(f); } //manifest created. Let's embed it. if (!createManifestAndEmbed(a.PrimaryFile)) { throw new ConsoleException(errors.StringOut()); } //sign the primary file if (!signFile(a.PrimaryFile)) throw new ConsoleException(errors.StringOut()); a.CatFile = a.PrimaryFile + ".cat"; if (!createAndSignCat(a.Manifest)) { throw new ConsoleException(errors.StringOut()); } //we're going to create the policy assemblies foreach (var p in package.SharedLibs.MajorMinorsToReplace) { var pa = new PolicyAssemblyDescription(p, a.Name); package.SharedLibs.PolicyAssemblies.Add(pa); var paManifestString = PublisherConfiguration.Replace("[$ASSMNAME]", a.Name). Replace("[$LIBMAJORMINOR]", p).Replace("[$PUBLICKEYTOKEN]", package.PubToken). Replace("[$LIBVERSION]", package.PackageVersion).Replace("[$ARCH]", package.PackageArch). Replace("[$OLDVERSION]", package.BindingPolicy); pa.Manifest = Path.Combine(new FileInfo(a.PrimaryFile).DirectoryName, pa.Name + ".manifest"); File.WriteAllText(pa.Manifest, paManifestString); pa.CatFile = pa.Manifest.Replace(".manifest", "") + ".cat"; if (!createAndSignCat(pa.Manifest)) throw new ConsoleException(errors.StringOut()); } } } else { // it's .NET foreach (var a in sharedlib.Assemblies.Values) { if (!StrongName(a.PrimaryFile)) { throw new ConsoleException(errors.StringOut()); } if (!signFile(a.PrimaryFile)) throw new ConsoleException(errors.StringOut()); foreach (var p in package.SharedLibs.MajorMinorsToReplace) { var pa = new PolicyAssemblyDescription(p, a.Name); package.SharedLibs.PolicyAssemblies.Add(pa); pa.PrimaryFile = Path.Combine(new FileInfo(a.PrimaryFile).DirectoryName, pa.Name + ".dll"); var paManifestString = MSILPublisherConfiguration.Replace("[$ASSMNAME]", a.Name). Replace("[$PUBLICKEYTOKEN]", package.PubToken). Replace("[$LIBVERSION]", package.PackageVersion). Replace("[$OLDVERSION]", package.BindingPolicy); pa.Manifest = pa.PrimaryFile + ".config"; // cleanupFiles.Add(pa.Manifest); File.WriteAllText(pa.Manifest, paManifestString); if (!extractPublicKey()) throw new ConsoleException(errors.StringOut()); if (_al.Exec("/link:{0} /out:{1} /delaysign+ /keyfile:{2} /v:{3}", pa.Manifest, pa.PrimaryFile, publicKeyFile, package.PackageVersion) != 0) { errors.Add(Resources.FailedPolicyAssemblyBuild.format(pa.PrimaryFile)); throw new ConsoleException(errors.StringOut()); } if (!StrongName(pa.PrimaryFile)) { throw new ConsoleException(errors.StringOut()); } if (!signFile(pa.PrimaryFile)) { throw new ConsoleException(errors.StringOut()); } } } } Console.WriteLine(Resources.Finished); } #endregion #region Handle Apps var apps = package.Apps; if (apps != null) { Console.Write(Resources.AppCreation); if (package.PackageArch != "any") { //it's native var dependencyStr = new StringBuilder(); foreach (var dep in dependentAssemblies) { dependencyStr.Append(DependencyEntry.Replace("[$LIBTYPE]", dep.Type).Replace("[$LIBNAME]", dep.Name). Replace("[$LIBVERSION]", dep.Version).Replace("[$ARCH]", dep.Arch). Replace("[$PUBLICKEYTOKEN]", dep.PublicKeyToken)); } //we needs to add in the other assemblies in this package if (sharedlib != null) { foreach (var dep in sharedlib.Assemblies.Values) { dependencyStr.Append(DependencyEntry.Replace("[$LIBTYPE]", "win32"). Replace("[$LIBNAME]", dep.Name).Replace("[$LIBVERSION]", package.PackageVersion). Replace("[$ARCH]", package.PackageArch).Replace("[$PUBLICKEYTOKEN]", package.PubToken)); } } foreach (var e in apps.PrimaryExes.Values) { var configFilename = e.ExeFile + ".config"; File.WriteAllText(configFilename, dependencyStr.ToString()); if (!embedManifest(e.ExeFile, configFilename)) //we can't keep working on this one but we'll try the rest before failing continue; signFile(e.ExeFile); } } else { //it's .net foreach (var e in apps.PrimaryExes.Values) { if (!StrongName(e.ExeFile)) { //we can't keep working on this one but we'll try the rest before failing continue; } signFile(e.ExeFile); } } } if (errors.AreFatal()) throw new ConsoleException(errors.StringOut()); Console.WriteLine(Resources.Finished); #endregion #region Write Msi OutToFile Console.Write(Resources.CreatingMSI); var tempPrefix = Path.GetTempFileName(); File.WriteAllText(tempPrefix + ".wxs", package.ConvertToWix()); var outputFile = "{0}-{1}-{2}.msi".format(package.PackageName, package.PackageVersion, package.PackageArch); /* if (!_dontCreateMsi) { */ //we suppress the lack of UpgradeCode warning since we don't use them if (_candle.Exec("-nologo -sw1075 -out {0}.wixobj {0}.wxs", tempPrefix) != 0) errors.Add(Resources.FailedCandleExe.format(_candle.StandardOut)); if (errors.AreFatal()) throw new ConsoleException(errors.StringOut()); //we suppress the lack of UpgradeCode warning since we don't use them if (_light.Exec("-nologo -sw1076 -out {1} {0}.wixobj", tempPrefix, outputFile) != 0) errors.Add(Resources.FailedLightExe.format(_light.StandardOut)); if (errors.AreFatal()) throw new ConsoleException(errors.StringOut()); signFile(outputFile); if (errors.AreFatal()) throw new ConsoleException(errors.StringOut()); Console.WriteLine(Resources.Finished); #endregion Console.WriteLine(errors.StringOut()); } catch (ConsoleException failure) { CancellationTokenSource.Cancel(); Fail("{0}\r\n\r\n {1}", failure.Message, Resources.ForCommandLineHelp); } finally { foreach (var f in cleanupFiles) { File.Delete(f); } } return 0; }
/// <summary> /// The (non-static) startup method /// </summary> /// <param name = "args"> /// The command line arguments. /// </param> /// <returns> /// Process return code. /// </returns> protected override int Main(IEnumerable<string> args) { try { _package.CertificateFile = _certificateSettings["#CurrentCertificate"].EncryptedStringValue; PackageManager.Instance.Connect("autopackage"); if (!PackageManager.Instance.IsReady.WaitOne(5000)) { //Verbose("# not connected..."); throw new ConsoleException("# Unable to connect to CoApp Service."); } _pkgMgr = PackageManager.Instance; PropertySheet propSheet; _pkgMgr.AddFeed(Environment.CurrentDirectory); var exceptions = new List<Exception>(); #region command line parsing var configLoaded = false; // default: var options = args.Switches(); var parameters = args.Parameters(); foreach (var arg in options.Keys) { var argumentParameters = options[arg]; switch (arg) { /* options */ /* global switches */ case "load-config": // all ready done, but don't get too picky. break; case "load": propSheet = PropertySheet.Load(argumentParameters.First()); PropSheetParser parser = new PropSheetParser(_package); //parser.Parse(propSheet); configLoaded = true; break; case "nologo": this.Assembly().SetLogo(string.Empty); break; case "show-tools": _showTools = Boolean.Parse(argumentParameters.First()); break; case "password": _package.CertificatePassword = argumentParameters.First(); break; case "autosign": _autosign = true; break; case "remember": _remember = true; break; case "accept-old-bs": _acceptOldBs = true; break; case "help": return Help(); default: throw new ConsoleException(Resources.UnknownParameter, arg); } } Logo(); if (!configLoaded) throw new ConsoleException(Resources.NoConfigFileLoaded); #endregion // GS01: I'm putting this in here so that feed resoltion happens before we actually get around to doing something. // Look into the necessity later. // Tasklet.WaitforCurrentChildTasks(); #region Tool Scanning Console.Write(Resources.ToolLookup); _candle = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("candle.exe")); _light = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("light.exe")); _mt = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("mt.exe")); _makecat = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("makecat.exe")); _al = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("al.exe")); _signTool = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("signTool.exe")); _sn = new ProcessUtility(ProgramFinder.ProgramFilesAndDotNet.ScanForFile("sn.exe")); if (_candle.Executable == null) exceptions.Add(CreateEndUserException(144)); if (_light.Executable == null) exceptions.Add(CreateEndUserException(145)); if (_mt.Executable == null) exceptions.Add(CreateEndUserException(146)); if (_makecat.Executable == null) exceptions.Add(CreateEndUserException(147)); if (_al.Executable == null) exceptions.Add(CreateEndUserException(148)); if (_signTool.Executable == null) exceptions.Add(CreateEndUserException(149)); if (_sn.Executable == null) exceptions.Add(CreateEndUserException(150)); if (exceptions.Count > 0) { throw new AggregateException(exceptions); } Console.WriteLine(Resources.Finished); if (_showTools) { Console.WriteLine("Tools:"); Console.WriteLine(_candle.Executable); Console.WriteLine(_light.Executable); Console.WriteLine(_mt.Executable); Console.WriteLine(_makecat.Executable); Console.WriteLine(_al.Executable); Console.WriteLine(_sn.Executable); Console.WriteLine(_signTool.Executable); } ReadPassword(); #endregion Console.WriteLine(Resources.ScanningInstalledPackages); //TODO What will happen when we have feeds in other places???? IEnumerable<Package> allPackages = null; /* var tsk = _pkgMgr.GetPackagesInScanLocations(new PackageManagerMessages { PackageScanning = (progress) => Resources.Scanning.PrintProgressBar(progress) }).ContinueWith((antecedent) => { allPackages = antecedent.Result; " ".PrintProgressBar(100); Console.WriteLine("\r"); },TaskContinuationOptions.AttachedToParent); tsk.Wait(); */ //find all the files that need to be found recursively //verify that the lefthand side of includes are valid subpaths foreach (var i in _package.AllIncludes.Keys) { foreach (var include in _package.AllIncludes[i]) { if (!include.L.IsSimpleSubPath()) { exceptions.Add(CreateEndUserPropertyException(i.IncludeToProp[include.L], 160, include.L)); } } } if (_package.Apps != null) { if (_package.Apps.GlobalBinEntry != null) { if (!_package.Apps.GlobalBinEntry.IsBoolean()) { exceptions.Add(CreateEndUserPropertyException(_package.Apps.GlobalBinEntryProp, 152)); } else { _package.Apps.GlobalBin = Boolean.Parse(_package.Apps.GlobalBinEntry); } } _package.Apps.EvaluateIncludes(); //set up the input files foreach (var e in _package.Apps.PrimaryExes) { var input = (from a in _package.Apps.FinalInclude where a.R.Path.IsWildcardMatch(e.ExeFile) select a).FirstOrDefault(); if (input == null) { if (!File.Exists(e.ExeFile)) exceptions.Add(CreateEndUserException(153, e.ExeFile)); else { //Exefile wasn't found in the Includes but it really does exist _package.Apps.FinalInclude = _package.Apps.FinalInclude.Concat(new OutputTup { L = new FileInfo(e.ExeFile.Original).Name, R = e.ExeFile }.SingleItemAsEnumerable()); } } else { e.ExeFile = input.R; } if (e.GlobalBinEntry != null) { if (!e.GlobalBinEntry.IsBoolean()) { exceptions.Add(CreateEndUserPropertyException(e.GlobalBinEntryProp, 152)); } else { e.GlobalBin = Boolean.Parse(e.GlobalBinEntry); } } } } if (_package.SharedLibs != null) { var shared = _package.SharedLibs; var sharedEntryValid = false; if (shared.GlobalEntry != null) { if (!shared.GlobalEntry.IsBoolean()) { exceptions.Add(CreateEndUserPropertyException(shared.GlobalEntryProp, 170)); } else { shared.Global = Boolean.Parse(shared.GlobalEntry); sharedEntryValid = true; } } foreach (var a in _package.SharedLibs.Assemblies) { a.EvaluateIncludes(true); if (a.GlobalEntry != null) { if (!a.GlobalEntry.IsBoolean()) { exceptions.Add(CreateEndUserPropertyException(a.GlobalEntryProp, 170)); } else { a.Global = Boolean.Parse(a.GlobalEntry); } } else if (sharedEntryValid) { a.Global = shared.Global; } } } if (_package.DeveloperLibs != null) { BasicIncludeAndExclude[] items = { _package.DeveloperLibs.Headers, _package.DeveloperLibs.ImportLibs, _package.DeveloperLibs.StaticLibs }; foreach (var sec in items) { if (sec.GlobalLinkEntry != null) { if (!sec.GlobalLinkEntry.IsBoolean()) { exceptions.Add(CreateEndUserPropertyException(sec.GlobalLinkEntryProp, 169)); } else { sec.GlobalLink = Boolean.Parse(sec.GlobalLinkEntry); } } sec.EvaluateIncludes(); } //add the proper prefix to all the files _package.DeveloperLibs.Headers.AddPrefix(HEADERS_DIR_NAME); _package.DeveloperLibs.ImportLibs.AddPrefix(IMPORTLIB_DIR_NAME); _package.DeveloperLibs.StaticLibs.AddPrefix(STATICLIB_DIR_NAME); } if (_package.SourceCodes != null) { var sc = _package.SourceCodes; sc.EvaluateIncludes(); sc.AddPrefix(SRC_DIR_NAME); } //copy all the stuff that needs to go to Temp TO Temp _package.Prepare(); foreach (var dep in _package.DependencyNames) { /* var temp = new EditableTup<string, string> {L = dep.L, R = _package.ResolveVariables(dep.R)}; //TODO this doesn't work if a packages is a superceding version of the one given var depPackage = (from p in allPackages where p.CosmeticName.IsWildcardMatch(temp.R) orderby p.Version descending select p).FirstOrDefault(); if (depPackage == null) { if (_package.DependencyNamesProp.ContainsKey(temp.R)) { exceptions.Add(CreateEndUserPropertyException(_package.DependencyNamesProp[dep.R], 133, dep.R)); } else { exceptions.Add(CreateEndUserException(133, dep.R)); } } else { _package.DependencyInfo.Add(depPackage); }*/ } //TODO make sure the numbers are not larger than the max a part of a version string var policyRegex = new Regex(@"^policy\.\d{1,5}\.\d{1,5}\.\S+$"); /* var dependentAssemblies = from p in _package.DependencyInfo from a in p.Assemblies where !a.Type.Contains("policy") && !policyRegex.IsMatch(a.Name) select a; */ //let's check for valid roles! if (_package.Roles.IsNullOrEmpty()) exceptions.Add(CreateEndUserException(131)); //make sure the major minors given are valid if (_package.SharedLibs != null) { foreach (var i in _package.SharedLibs.MajorMinorsToReplace) { if (!i.IsValidMajorMinorVersion()) { if (_package.SharedLibs.MajorMinorsToReplaceProp.ContainsKey(i)) { exceptions.Add(CreateEndUserPropertyException(_package.SharedLibs.MajorMinorsToReplaceProp[i], 132, i)); } else { exceptions.Add(CreateEndUserException(132, i)); } } } } if (_package.Apps != null) { foreach (var e in _package.Apps.PrimaryExes) { if (e.StartMenu != null) { if (!e.StartMenu.IsSimpleSubPath()) { exceptions.Add(CreateEndUserPropertyException(e.StartMenuProp, 168, e.StartMenu)); continue; } if (!e.StartMenu.EndsWith(".lnk")) { e.StartMenu += ".lnk"; } } } } if (exceptions.Count > 0) { throw new AggregateException(exceptions); } #region Handle Shared Libraries //first create the string of all the dependencies elements var sharedlib = _package.SharedLibs; if (sharedlib != null) { //set all the assembly names properly foreach (var a in sharedlib.Assemblies) { if (a.Name == null) { var fi = new FileInfo(a.PrimaryFile); a.Name = fi.NameWithoutExt().Replace(" ", "_"); } } Console.Write(Resources.SharedLibCreation); if (_package.PackageArch != "any") { var dependencyStr = new StringBuilder(); /* foreach (var dep in dependentAssemblies) { dependencyStr.Append(DependencyEntry.Replace("[$LIBTYPE]", dep.Type).Replace("[$LIBNAME]", dep.Name). Replace("[$LIBVERSION]", dep.Version).Replace("[$ARCH]", dep.Arch). Replace("[$PUBLICKEYTOKEN]", dep.PublicKeyToken)); } */ foreach (var a in sharedlib.Assemblies) { /* var manifestFilesString = new StringBuilder(); var filesString = new StringBuilder(); filesString.Append(FileEntry.Replace("[$FILE]", Path.GetFileName(a.PrimaryFile))); foreach (var f in a.FinalInclude) { filesString.Append(FileEntry.Replace("[$FILE]", f.L)); } manifestFilesString.Append(SharedLibraryManifest.Replace("[$LIBNAME]", a.Name). Replace("[$LIBVERSION]", _package.PackageVersion). Replace("[$DEPENDENCY]", dependencyStr.ToString()).Replace("[$PUBLICKEYTOKEN]", _package.PubToken). Replace("[$ARCH]", _package.PackageArch).Replace("[$FILES]", filesString.ToString())); a.Manifest = Path.Combine(new FileInfo(a.PrimaryFile).DirectoryName, a.PrimaryFile + ".manifest"); //TODO do file checking File.WriteAllText(a.Manifest, manifestFilesString.ToString()); */ // sign all the non-primary BinFiles var binFiles = from f in a.FinalInclude.BinaryFiles() select f.R; exceptions.AddRange(VerifySigning(binFiles, false)); //manifest created. Let's embed it. if (!EmbedManifest(a.PrimaryFile)) { exceptions.Add(CreateEndUserException(137, a.PrimaryFile + ".manifest", a.PrimaryFile)); continue; } //sign the primary file if (!SignFile(a.PrimaryFile)) { exceptions.Add(CreateEndUserException(136, a.PrimaryFile)); continue; } a.CatFile = a.PrimaryFile + ".cat"; if (!CreateAndSignCat(a.Manifest)) { exceptions.Add(CreateEndUserException(138, a.Manifest + ".cdf")); continue; } //we're going to create the policy assemblies foreach (var p in _package.SharedLibs.MajorMinorsToReplace) { var pa = new PolicyAssemblyDescription(p, a.Name); _package.SharedLibs.PolicyAssemblies.Add(pa); var paManifestString = PublisherConfiguration.Replace("[$ASSMNAME]", a.Name). Replace("[$LIBMAJORMINOR]", p).Replace("[$PUBLICKEYTOKEN]", _package.PubToken). Replace("[$LIBVERSION]", _package.PackageVersion).Replace("[$ARCH]", _package.PackageArch). Replace("[$OLDVERSION]", _package.BindingPolicy); pa.Manifest = Path.Combine(new FileInfo(a.PrimaryFile).DirectoryName, pa.Name + ".manifest"); File.WriteAllText(pa.Manifest, paManifestString); pa.CatFile = pa.Manifest.Replace(".manifest", "") + ".cat"; if (!CreateAndSignCat(pa.Manifest)) { exceptions.Add(CreateEndUserException(138, pa.Manifest + ".cdf")); continue; } } } } else { // it's .NET foreach (var a in sharedlib.Assemblies) { if (!_codeSigningCert.FinishStrongNaming(a.PrimaryFile)) { exceptions.Add(CreateEndUserException(139, a.PrimaryFile)); continue; } if (!SignFile(a.PrimaryFile)) { exceptions.Add(CreateEndUserException(136, a.PrimaryFile)); continue; } foreach (var p in _package.SharedLibs.MajorMinorsToReplace) { var pa = new PolicyAssemblyDescription(p, a.Name); _package.SharedLibs.PolicyAssemblies.Add(pa); pa.PrimaryFile = Path.Combine(new FileInfo(a.PrimaryFile).DirectoryName, pa.Name + ".dll"); var paManifestString = MSILPublisherConfiguration.Replace("[$ASSMNAME]", a.Name). Replace("[$PUBLICKEYTOKEN]", _package.PubToken). Replace("[$LIBVERSION]", _package.PackageVersion). Replace("[$OLDVERSION]", _package.BindingMin + "-" + _package.BindingMax); pa.Manifest = pa.PrimaryFile + ".config"; // cleanupFiles.Add(pa.Manifest); File.WriteAllText(pa.Manifest, paManifestString); if (!ExtractPublicKey()) { exceptions.Add(CreateEndUserPropertyException(_package.SharedLibs.MajorMinorsToReplaceProp[p], 140, _package.CertificateFile)); continue; } if (_al.Exec("/link:{0} /out:{1} /delaysign+ /keyfile:{2} /v:{3}", pa.Manifest, pa.PrimaryFile, _publicKeyFile, _package.PackageVersion) != 0) { exceptions.Add(CreateEndUserPropertyException(_package.SharedLibs.MajorMinorsToReplaceProp[p], 141, pa.PrimaryFile)); continue; } if (!_codeSigningCert.FinishStrongNaming(pa.PrimaryFile)) { exceptions.Add(CreateEndUserPropertyException(_package.SharedLibs.MajorMinorsToReplaceProp[p], 139, pa.PrimaryFile)); continue; } if (!SignFile(pa.PrimaryFile)) { exceptions.Add(CreateEndUserPropertyException(_package.SharedLibs.MajorMinorsToReplaceProp[p], 136, pa.PrimaryFile)); continue; } } } } if (exceptions.Count > 0) { throw new AggregateException(exceptions); } Console.WriteLine(Resources.Finished); } #endregion #region Handle Apps var apps = _package.Apps; if (apps != null) { Console.Write(Resources.AppCreation); if (_package.PackageArch != "any") { //it's native var dependencyStr = new StringBuilder(); /* foreach (var dep in dependentAssemblies) { dependencyStr.Append(DependencyEntry.Replace("[$LIBTYPE]", dep.Type).Replace("[$LIBNAME]", dep.Name). Replace("[$LIBVERSION]", dep.Version).Replace("[$ARCH]", dep.Arch). Replace("[$PUBLICKEYTOKEN]", dep.PublicKeyToken)); } //we needs to add in the other assemblies in this package if (sharedlib != null) { foreach (var dep in sharedlib.Assemblies) { dependencyStr.Append(DependencyEntry.Replace("[$LIBTYPE]", "win32"). Replace("[$LIBNAME]", dep.Name).Replace("[$LIBVERSION]", _package.PackageVersion). Replace("[$ARCH]", _package.PackageArch).Replace("[$PUBLICKEYTOKEN]", _package.PubToken)); } }*/ foreach (var e in apps.PrimaryExes) { /* if (dependencyStr.Length > 0) { var configFilename = e.InputFile + ".config"; var execManifest = new StringBuilder(); execManifest.Append(ExecutableManifest.Replace("[$DEPENDENCY]", dependencyStr.ToString())); File.WriteAllText(configFilename, execManifest.ToString()); if (!EmbedManifest(e.InputFile, configFilename)) { exceptions.Add(CreateEndUserException(137, configFilename, e.InputFile)); continue; } }*/ if (!SignFile(e.InputFile)) { exceptions.Add(CreateEndUserException(136, e.InputFile)); continue; } } } else { //it's .net foreach (var e in apps.PrimaryExes) { if (!_codeSigningCert.FinishStrongNaming(e.InputFile)) { exceptions.Add(CreateEndUserException(139, e.InputFile)); continue; } if (!SignFile(e.InputFile)) { exceptions.Add(CreateEndUserException(136, e.InputFile)); continue; } } } if (exceptions.Count > 0) { throw new AggregateException(exceptions); } Console.WriteLine(Resources.Finished); } //check if every binary is actually signed at all //yes this is really messy var binFilesToCheck = Enumerable.Empty<TempedFile>(); if (apps != null) binFilesToCheck = binFilesToCheck.Concat(from i in apps.BinaryFilesMinusPrimaries select i.R); if (_package.SourceCodes != null) binFilesToCheck = binFilesToCheck.Concat(from i in _package.SourceCodes.FinalInclude.BinaryFiles() select i.R); if (_package.DeveloperLibs != null) binFilesToCheck = binFilesToCheck.Concat(from i in _package.DeveloperLibs.Headers.FinalInclude. Concat(_package.DeveloperLibs.ImportLibs.FinalInclude). Concat(_package.DeveloperLibs.StaticLibs.FinalInclude). BinaryFiles() select i.R); exceptions.AddRange(VerifySigning(binFilesToCheck)); exceptions.AddRange(DownloadBootstrapManifest()); if (exceptions.Count > 0) { throw new AggregateException(exceptions); } #endregion #region Write Msi OutToFile Console.Write(Resources.CreatingMSI); var tempPrefix = Path.GetTempFileName(); File.WriteAllText(tempPrefix + ".wxs", _package.ConvertToWix()); //we suppress the lack of UpgradeCode warning since we don't use them if (_candle.Exec("-nologo -sw1075 -out {0}.wixobj {0}.wxs", tempPrefix) != 0) exceptions.Add(CreateEndUserException(142, _candle.StandardOut)); if (exceptions.Count > 0) { throw new AggregateException(exceptions); } //we suppress the lack of UpgradeCode warning since we don't use them if (_light.Exec("-nologo -sw1076 -out {1} {0}.wixobj", tempPrefix, _package.DefaultOutputFile) != 0) exceptions.Add(CreateEndUserException(143, _light.StandardOut)); if (exceptions.Count > 0) { throw new AggregateException(exceptions); } if (!SignFile(_package.DefaultOutputFile)) { exceptions.Add(CreateEndUserException(136, _package.DefaultOutputFile)); } if (exceptions.Count > 0) { throw new AggregateException(exceptions); } if (_remember) { //Verbose("Storing certificate details in the registry."); _certificateSettings["#CurrentCertificate"].EncryptedStringValue = _package.CertificateFile; _certificateSettings[Path.GetFileName(_package.CertificateFile), "Password"].EncryptedStringValue = _package.CertificatePassword; } Console.WriteLine(Resources.Finished); #endregion } catch (AggregateException failures) { CancellationTokenSource.Cancel(); Fail("{0}\r\n\r\n {1}", failures.InnerExceptions, Resources.ForCommandLineHelp); } catch (Exception failure) { CancellationTokenSource.Cancel(); Fail("{0}\r\n\r\n {1}", "{0} - stacktrace: {1}".format(failure.Message, failure.StackTrace) , Resources.ForCommandLineHelp); } finally { foreach (var f in _cleanupFiles) { File.Delete(f); } } return 0; }