internal void MoveAttributesTo(WixEntity dest) { var attrs = this.Attributes; var attrsDefinition = this.AttributesDefinition; this.Attributes.Clear(); this.AttributesDefinition = null; dest.Attributes = attrs; dest.AttributesDefinition = attrsDefinition; }
/// <summary> /// For future use /// </summary> /// <param name="entity">The entity.</param> /// <returns></returns> private string HashedIdAlgorithm(WixEntity entity) { if (entity is File file) { var target_path = this.GetTargetPathOf(file); var hash = target_path.GetHashCode32(); // WiX does not allow '-' char in ID. So need to use `Math.Abs` return($"{target_path.PathGetFileName()}_{Math.Abs(hash)}"); } return(null); // next two lines produce the same result // return WixEntity.DefaultIdAlgorithm(entity); // return WixEntity.IncrementalIdFor(entity); }
/// <summary> /// Algorithm for generating deterministic <see cref="T:WixSharp.File"/>Id(s) based on the hash of the target path. /// <para>This algorithm addresses the limitation of the incremental-Id legacy algorithm, which it quite reliable but /// non deterministic.</para> /// </summary> /// <param name="entity">The entity.</param> /// <returns></returns> public string HashedTargetPathIdAlgorithm(WixEntity entity) { if (entity is File file) { var target_path = this.GetTargetPathOf(file); var dir_hash = Math.Abs(target_path.PathGetDirName().GetHashCode32()); var file_name = target_path.PathGetFileName(); return($"{file_name}.{dir_hash}"); } return(null); // pass to default Id generator }
/// <summary> /// Algorithm for generating deterministic <see cref="T:WixSharp.File"/>Id(s) based on the hash of the target path. /// <para>This algorithm addresses the limitation of the incremental-Id legacy algorithm, which it quite reliable but /// non deterministic.</para> /// </summary> /// <param name="entity">The entity.</param> /// <returns></returns> public string HashedTargetPathIdAlgorithm(WixEntity entity) { if (entity is File file) { var target_path = this.GetTargetPathOf(file); var dir_hash = Math.Abs(target_path.PathGetDirName().GetHashCode32()); var file_name = target_path.PathGetFileName().EscapeIllegalCharacters(); if (Compiler.AutoGeneration.HashedTargetPathIdAlgorithm_FileIdMask != null) { return(Compiler.AutoGeneration.HashedTargetPathIdAlgorithm_FileIdMask .Replace("{file_name}", file_name) .Replace("{dir_hash}", dir_hash.ToString()) .FormatWith(file_name, dir_hash)); } else { return($"{file_name}.{dir_hash}"); } } return(null); // pass to default Id generator }
/// <summary> /// Builds the WiX source file (*.wxs) from the specified <see cref="Bundle"/> instance. /// </summary> /// <param name="project">The project.</param> /// <returns></returns> public static string BuildWxs(Bundle project) { lock (typeof(Compiler)) { //very important to keep "ClientAssembly = " in all "public Build*" methods to ensure GetCallingAssembly //returns the build script assembly but not just another method of Compiler. if (ClientAssembly.IsEmpty()) { ClientAssembly = System.Reflection.Assembly.GetCallingAssembly().GetLocation(); } project.Validate(); lock (Compiler.AutoGeneration.WxsGenerationSynchObject) { var oldAlgorithm = AutoGeneration.CustomIdAlgorithm; try { WixEntity.ResetIdGenerator(false); AutoGeneration.CustomIdAlgorithm = project.CustomIdAlgorithm ?? AutoGeneration.CustomIdAlgorithm; string file = IO.Path.GetFullPath(IO.Path.Combine(project.OutDir, project.OutFileName) + ".wxs"); if (IO.File.Exists(file)) { IO.File.Delete(file); } string extraNamespaces = project.WixNamespaces.Distinct() .Select(x => x.StartsWith("xmlns:") ? x : "xmlns:" + x) .ConcatItems(" "); var wix3Namespace = "http://schemas.microsoft.com/wix/2006/wi"; var wix4Namespace = "http://wixtoolset.org/schemas/v4/wxs"; var wixNamespace = Compiler.IsWix4 ? wix4Namespace : wix3Namespace; var doc = XDocument.Parse( @"<?xml version=""1.0"" encoding=""utf-8""?> " + $"<Wix xmlns=\"{wixNamespace}\" {extraNamespaces} " + @" > </Wix>"); doc.Root.Add(project.ToXml()); AutoElements.NormalizeFilePaths(doc, project.SourceBaseDir, EmitRelativePaths); project.InvokeWixSourceGenerated(doc); AutoElements.ExpandCustomAttributes(doc, project); if (WixSourceGenerated != null) { WixSourceGenerated(doc); } string xml = ""; using (IO.StringWriter sw = new StringWriterWithEncoding(Encoding.Default)) { doc.Save(sw, SaveOptions.None); xml = sw.ToString(); } //of course you can use XmlTextWriter.WriteRaw but this is just a temporary quick'n'dirty solution //http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2657663&SiteID=1 xml = xml.Replace("xmlns=\"\"", ""); DefaultWixSourceFormatedHandler(ref xml); project.InvokeWixSourceFormated(ref xml); if (WixSourceFormated != null) { WixSourceFormated(ref xml); } using (var sw = new IO.StreamWriter(file, false, Encoding.Default)) sw.WriteLine(xml); Compiler.OutputWriteLine("\n----------------------------------------------------------\n"); Compiler.OutputWriteLine("Wix project file has been built: " + file + "\n"); project.InvokeWixSourceSaved(file); if (WixSourceSaved != null) { WixSourceSaved(file); } return(file); } finally { AutoGeneration.CustomIdAlgorithm = oldAlgorithm; } } } }
internal void ResetAutoIdGeneration(bool supressWarning) { ResetWixGuidStartValue(); WixEntity.ResetIdGenerator(supressWarning); }
/// <summary> /// Index based Id generation algorithm. /// <para>It is the default algorithm, which generates the most human readable Id. Thus if the /// project has two `index.html` files one will be assigned Id `index.html` and another one /// `index.html.1`.</para> /// <para> Limitations: If two files have the same name it is non-deterministic which one gets /// clear Id and which one the indexed one.</para> /// </summary> /// <param name="entity">The entity.</param> /// <returns></returns> public static string IncrementalIdFor(WixEntity entity) { if (!idMaps.ContainsKey(entity.GetType())) { idMaps[entity.GetType()] = new Dictionary <string, int>(); } var rawName = entity.Name.Expand(); if (rawName.IsEmpty()) { rawName = entity.GetType().Name; } if (IO.Path.IsPathRooted(entity.Name)) { rawName = IO.Path.GetFileName(entity.Name).Expand(); } if (entity.GetType() != typeof(Dir) && entity.GetType().BaseType != typeof(Dir) && entity.Name.IsNotEmpty()) { rawName = IO.Path.GetFileName(entity.Name).Expand(); } //Maximum allowed length for a stream name is 62 characters long; In some cases more but to play it safe keep 62 limit // //Note: the total limit 62 needs to include in some cases MSI auto prefix (e.g. table name) ~15 chars // our hash code (max 10 chars) and our decoration (separators). So 30 seems to be a safe call // int maxLength = 30; if (rawName.Length > maxLength) { //some chars are illegal as star if the ID so work around this with '_' prefix rawName = "_..." + rawName.Substring(rawName.Length - maxLength); } string rawNameKey = rawName.ToLower(); /* * "bin\Release\similarFiles.txt" and "bin\similarfiles.txt" will produce the following IDs * "Component.similarFiles.txt" and "Component.similariles.txt", which will be treated by Wix compiler as duplication */ if (!idMaps[entity.GetType()].ContainsSimilarKey(rawName)) //this Type has not been generated yet { idMaps[entity.GetType()][rawNameKey] = 0; entity.id = rawName; if (char.IsDigit(entity.id.Last())) { entity.id += "_"; // work around for https://wixsharp.codeplex.com/workitem/142 } // to avoid potential collision between ids that end with digit // and auto indexed (e.g. [rawName + "." + index]) } else { //The Id has been already generated for this Type with this rawName //so just increase the index var index = idMaps[entity.GetType()][rawNameKey] + 1; entity.id = rawName + "." + index; idMaps[entity.GetType()][rawNameKey] = index; } //Trace.WriteLine(">>> " + GetType() + " >>> " + id); if (rawName.IsNotEmpty() && char.IsDigit(rawName[0])) { entity.id = "_" + entity.id; } while (alreadyTakenIds.Contains(entity.id)) //last line of defense against duplication { entity.id += "_"; } alreadyTakenIds.Add(entity.id); return(entity.id); }