protected virtual string IncludeBuildVersionInPackageVersion(string VersionNumber)
        {
            BuildVersion BuildVersionForPackage;

            if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out BuildVersionForPackage) && BuildVersionForPackage.Changelist != 0)
            {
                // Break apart the version number into individual elements
                string[] SplitVersionString = VersionNumber.Split('.');
                VersionNumber = string.Format("{0}.{1}.{2}.{3}",
                                              SplitVersionString[0],
                                              SplitVersionString[1],
                                              BuildVersionForPackage.Changelist / 10000,
                                              BuildVersionForPackage.Changelist % 10000);
            }

            return(VersionNumber);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Finds all the preprocessor definitions that need to be set for the current engine.
        /// </summary>
        /// <returns>List of preprocessor definitions that should be set</returns>
        public static List <string> GetPreprocessorDefinitions()
        {
            List <string> PreprocessorDefines = new List <string>();

            PreprocessorDefines.Add("WITH_FORWARDED_MODULE_RULES_CTOR");
            PreprocessorDefines.Add("WITH_FORWARDED_TARGET_RULES_CTOR");

            // Define macros for the UE4 version, starting with 4.17
            BuildVersion Version;

            if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version))
            {
                for (int MinorVersion = 17; MinorVersion <= Version.MinorVersion; MinorVersion++)
                {
                    PreprocessorDefines.Add(String.Format("UE_4_{0}_OR_LATER", MinorVersion));
                }
            }
            return(PreprocessorDefines);
        }
Exemplo n.º 3
0
        protected XElement GetIdentity(out string IdentityName)
        {
            // Read the PackageName from config
            var PackageName = Regex.Replace(GetConfigString("PackageName", "ProjectName", "DefaultUE4Project"), "[^-.A-Za-z0-9]", "");

            if (string.IsNullOrWhiteSpace(PackageName))
            {
                Log.TraceError("Invalid package name {0}. Package names must only contain letters, numbers, dash, and period and must be at least one character long.", PackageName);
                Log.TraceError("Consider using the setting [{0}]:PackageName to provide a specific value.", IniSection_PlatformTargetSettings);
            }

            var PublisherName = GetConfigString("PublisherName", "CompanyDistinguishedName", "CN=NoPublisher");
            var VersionNumber = GetConfigString("PackageVersion", "ProjectVersion", "1.0.0.0");

            VersionNumber = ValidatePackageVersion(VersionNumber);

            // If specified in the project settings attempt to retrieve the current build number and increment the version number by that amount, accounting for overflows
            bool bIncludeEngineVersionInPackageVersion;

            if (EngineIni.GetBool(IniSection_PlatformTargetSettings, "bIncludeEngineVersionInPackageVersion", out bIncludeEngineVersionInPackageVersion) && bIncludeEngineVersionInPackageVersion)
            {
                BuildVersion BuildVersionForPackage;
                if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out BuildVersionForPackage) && BuildVersionForPackage.Changelist != 0)
                {
                    // Break apart the version number into individual elements
                    string[] SplitVersionString = VersionNumber.Split('.');
                    VersionNumber = string.Format("{0}.{1}.{2}.{3}",
                                                  SplitVersionString[0],
                                                  SplitVersionString[1],
                                                  BuildVersionForPackage.Changelist / 10000,
                                                  BuildVersionForPackage.Changelist % 10000);
                }
            }

            IdentityName = PackageName;

            return(new XElement(GetName("Identity", Schema2010NS),
                                new XAttribute("Name", PackageName),
                                new XAttribute("Publisher", PublisherName),
                                new XAttribute("Version", VersionNumber)));
        }
Exemplo n.º 4
0
        public static void WriteDocumentation(Type RulesType, FileReference OutputFile)
        {
            // Get the path to the XML documentation
            FileReference InputDocumentationFile = new FileReference(Assembly.GetExecutingAssembly().Location).ChangeExtension(".xml");

            if (!FileReference.Exists(InputDocumentationFile))
            {
                throw new BuildException("Generated assembly documentation not found at {0}.", InputDocumentationFile);
            }

            // Get the current engine version for versioning the page
            BuildVersion Version;

            if (!BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version))
            {
                throw new BuildException("Unable to read the current build version");
            }

            // Read the documentation
            XmlDocument InputDocumentation = new XmlDocument();

            InputDocumentation.Load(InputDocumentationFile.FullName);

            // Filter the properties into read-only and read/write lists
            List <FieldInfo> ReadOnlyFields  = new List <FieldInfo>();
            List <FieldInfo> ReadWriteFields = new List <FieldInfo>();

            foreach (FieldInfo Field in RulesType.GetFields(BindingFlags.Instance | BindingFlags.SetProperty | BindingFlags.Public))
            {
                if (!Field.FieldType.IsClass || !Field.FieldType.Name.EndsWith("TargetRules"))
                {
                    if (Field.IsInitOnly)
                    {
                        ReadOnlyFields.Add(Field);
                    }
                    else
                    {
                        ReadWriteFields.Add(Field);
                    }
                }
            }

            // Make sure the output file is writable
            FileReference.MakeWriteable(OutputFile);

            // Generate the UDN documentation file
            using (StreamWriter Writer = new StreamWriter(OutputFile.FullName))
            {
                Writer.WriteLine("Availability: NoPublish");
                Writer.WriteLine("Title: Build Configuration Properties Page");
                Writer.WriteLine("Crumbs:");
                Writer.WriteLine("Description: This is a procedurally generated markdown page.");
                Writer.WriteLine("Version: {0}.{1}", Version.MajorVersion, Version.MinorVersion);
                Writer.WriteLine("");
                if (ReadOnlyFields.Count > 0)
                {
                    Writer.WriteLine("### Read-Only Properties");
                    Writer.WriteLine();
                    foreach (FieldInfo Field in ReadOnlyFields)
                    {
                        OutputField(InputDocumentation, Field, Writer);
                    }
                    Writer.WriteLine();
                }
                if (ReadWriteFields.Count > 0)
                {
                    Writer.WriteLine("### Read/Write Properties");
                    foreach (FieldInfo Field in ReadWriteFields)
                    {
                        OutputField(InputDocumentation, Field, Writer);
                    }
                    Writer.WriteLine("");
                }
            }

            // Success!
            Log.TraceInformation("Written documentation to {0}.", OutputFile);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Execute the command, having obtained the appropriate mutex
        /// </summary>
        /// <param name="Arguments">Command line arguments</param>
        /// <returns>Exit code</returns>
        private int ExecuteInternal(CommandLineArguments Arguments)
        {
            // Read the target info
            WriteMetadataTargetInfo TargetInfo = BinaryFormatterUtils.Load <WriteMetadataTargetInfo>(Arguments.GetFileReference("-Input="));
            bool bNoManifestChanges            = Arguments.HasOption("-NoManifestChanges");
            int  VersionNumber = Arguments.GetInteger("-Version=");

            Arguments.CheckAllArgumentsUsed();

            // Make sure the version number is correct
            if (VersionNumber != CurrentVersionNumber)
            {
                throw new BuildException("Version number to WriteMetadataMode is incorrect (expected {0}, got {1})", CurrentVersionNumber, VersionNumber);
            }

            // Check if we need to set a build id
            TargetReceipt Receipt = TargetInfo.Receipt;

            if (String.IsNullOrEmpty(Receipt.Version.BuildId))
            {
                // Check if there's an existing version file. If it exists, try to merge in any manifests that are valid (and reuse the existing build id)
                BuildVersion PreviousVersion;
                if (TargetInfo.VersionFile != null && BuildVersion.TryRead(TargetInfo.VersionFile, out PreviousVersion))
                {
                    // Check if we can reuse the existing manifests. This prevents unnecessary builds when switching between projects.
                    Dictionary <FileReference, ModuleManifest> PreviousFileToManifest = new Dictionary <FileReference, ModuleManifest>();
                    if (TryRecyclingManifests(PreviousVersion.BuildId, TargetInfo.FileToManifest.Keys, PreviousFileToManifest))
                    {
                        // Merge files from the existing manifests with the new ones
                        foreach (KeyValuePair <FileReference, ModuleManifest> Pair in PreviousFileToManifest)
                        {
                            ModuleManifest TargetManifest = TargetInfo.FileToManifest[Pair.Key];
                            MergeManifests(Pair.Value, TargetManifest);
                        }

                        // Update the build id to use the current one
                        Receipt.Version.BuildId = PreviousVersion.BuildId;
                    }
                }

                // If the build id is still not set, generate a new one from a GUID
                if (String.IsNullOrEmpty(Receipt.Version.BuildId))
                {
                    Receipt.Version.BuildId = Guid.NewGuid().ToString();
                }
            }
            else
            {
                // Read all the manifests and merge them into the new ones, if they have the same build id
                foreach (KeyValuePair <FileReference, ModuleManifest> Pair in TargetInfo.FileToManifest)
                {
                    ModuleManifest SourceManifest;
                    if (TryReadManifest(Pair.Key, out SourceManifest) && SourceManifest.BuildId == Receipt.Version.BuildId)
                    {
                        MergeManifests(SourceManifest, Pair.Value);
                    }
                }
            }

            // Update the build id in all the manifests, and write them out
            foreach (KeyValuePair <FileReference, ModuleManifest> Pair in TargetInfo.FileToManifest)
            {
                FileReference ManifestFile = Pair.Key;
                if (!UnrealBuildTool.IsFileInstalled(ManifestFile))
                {
                    ModuleManifest Manifest = Pair.Value;
                    Manifest.BuildId = Receipt.Version.BuildId;

                    if (!FileReference.Exists(ManifestFile))
                    {
                        // If the file doesn't already exist, just write it out
                        DirectoryReference.CreateDirectory(ManifestFile.Directory);
                        Manifest.Write(ManifestFile);
                    }
                    else
                    {
                        // Otherwise write it to a buffer first
                        string OutputText;
                        using (StringWriter Writer = new StringWriter())
                        {
                            Manifest.Write(Writer);
                            OutputText = Writer.ToString();
                        }

                        // And only write it to disk if it's been modified. Note that if a manifest is out of date, we should have generated a new build id causing the contents to differ.
                        string CurrentText = FileReference.ReadAllText(ManifestFile);
                        if (CurrentText != OutputText)
                        {
                            if (bNoManifestChanges)
                            {
                                Log.TraceError("Build modifies {0}. This is not permitted. Before:\n    {1}\nAfter:\n    {2}", ManifestFile, CurrentText.Replace("\n", "\n    "), OutputText.Replace("\n", "\n    "));
                            }
                            else
                            {
                                FileReference.WriteAllText(ManifestFile, OutputText);
                            }
                        }
                    }
                }
            }

            // Write out the version file, if it's changed. Since this file is next to the executable, it may be used by multiple targets, and we should avoid modifying it unless necessary.
            if (TargetInfo.VersionFile != null && !UnrealBuildTool.IsFileInstalled(TargetInfo.VersionFile))
            {
                DirectoryReference.CreateDirectory(TargetInfo.VersionFile.Directory);

                StringWriter Writer = new StringWriter();
                Receipt.Version.Write(Writer);

                string Text = Writer.ToString();
                if (!FileReference.Exists(TargetInfo.VersionFile) || File.ReadAllText(TargetInfo.VersionFile.FullName) != Text)
                {
                    File.WriteAllText(TargetInfo.VersionFile.FullName, Text);
                }
            }

            // Write out the receipt
            if (!UnrealBuildTool.IsFileInstalled(TargetInfo.ReceiptFile))
            {
                DirectoryReference.CreateDirectory(TargetInfo.ReceiptFile.Directory);
                Receipt.Write(TargetInfo.ReceiptFile);
            }

            return(0);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Generates documentation files for the available settings, by merging the XML documentation from the compiler.
        /// </summary>
        /// <param name="OutputFile">The documentation file to write</param>
        public static void WriteDocumentation(FileReference OutputFile)
        {
            // Find all the configurable types
            List <Type> ConfigTypes = FindConfigurableTypes();

            // Find all the configurable fields from the given types
            Dictionary <string, Dictionary <string, FieldInfo> > CategoryToFields = new Dictionary <string, Dictionary <string, FieldInfo> >();

            FindConfigurableFields(ConfigTypes, CategoryToFields);

            // Get the path to the XML documentation
            FileReference InputDocumentationFile = new FileReference(Assembly.GetExecutingAssembly().Location).ChangeExtension(".xml");

            if (!FileReference.Exists(InputDocumentationFile))
            {
                throw new BuildException("Generated assembly documentation not found at {0}.", InputDocumentationFile);
            }

            // Get the current engine version for versioning the page
            BuildVersion Version;

            if (!BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version))
            {
                throw new BuildException("Unable to read the current build version");
            }

            // Read the documentation
            XmlDocument InputDocumentation = new XmlDocument();

            InputDocumentation.Load(InputDocumentationFile.FullName);

            // Make sure we can write to the output file
            FileReference.MakeWriteable(OutputFile);

            // Generate the UDN documentation file
            using (StreamWriter Writer = new StreamWriter(OutputFile.FullName))
            {
                Writer.WriteLine("Availability: NoPublish");
                Writer.WriteLine("Title: Build Configuration Properties Page");
                Writer.WriteLine("Crumbs:");
                Writer.WriteLine("Description: This is a procedurally generated markdown page.");
                Writer.WriteLine("Version: {0}.{1}", Version.MajorVersion, Version.MinorVersion);
                Writer.WriteLine("");

                foreach (KeyValuePair <string, Dictionary <string, FieldInfo> > CategoryPair in CategoryToFields)
                {
                    string CategoryName = CategoryPair.Key;
                    Writer.WriteLine("### {0}", CategoryName);
                    Writer.WriteLine();

                    Dictionary <string, FieldInfo> Fields = CategoryPair.Value;
                    foreach (KeyValuePair <string, FieldInfo> FieldPair in Fields)
                    {
                        string FieldName = FieldPair.Key;

                        FieldInfo Field = FieldPair.Value;
                        XmlNode   Node  = InputDocumentation.SelectSingleNode(String.Format("//member[@name='F:{0}.{1}']/summary", Field.DeclaringType.FullName, Field.Name));
                        if (Node != null)
                        {
                            // Reflow the comments into paragraphs, assuming that each paragraph will be separated by a blank line
                            List <string> Lines = new List <string>(Node.InnerText.Trim().Split('\n').Select(x => x.Trim()));
                            for (int Idx = Lines.Count - 1; Idx > 0; Idx--)
                            {
                                if (Lines[Idx - 1].Length > 0 && !Lines[Idx].StartsWith("*") && !Lines[Idx].StartsWith("-"))
                                {
                                    Lines[Idx - 1] += " " + Lines[Idx];
                                    Lines.RemoveAt(Idx);
                                }
                            }

                            // Write the result to the .udn file
                            if (Lines.Count > 0)
                            {
                                Writer.WriteLine("$ {0} : {1}", FieldName, Lines[0]);
                                for (int Idx = 1; Idx < Lines.Count; Idx++)
                                {
                                    if (Lines[Idx].StartsWith("*") || Lines[Idx].StartsWith("-"))
                                    {
                                        Writer.WriteLine("        * {0}", Lines[Idx].Substring(1).TrimStart());
                                    }
                                    else
                                    {
                                        Writer.WriteLine("    * {0}", Lines[Idx]);
                                    }
                                }
                                Writer.WriteLine();
                            }
                        }
                    }
                }
            }

            // Success!
            Log.TraceInformation("Written documentation to {0}.", OutputFile);
        }
        /// <summary>
        /// Constructor. Compiles a rules assembly from the given source files.
        /// </summary>
        /// <param name="Plugins">All the plugins included in this assembly</param>
        /// <param name="ModuleFiles">List of module files to compile</param>
        /// <param name="TargetFiles">List of target files to compile</param>
        /// <param name="ModuleFileToPluginInfo">Mapping of module file to the plugin that contains it</param>
        /// <param name="AssemblyFileName">The output path for the compiled assembly</param>
        /// <param name="Parent">The parent rules assembly</param>
        public RulesAssembly(IReadOnlyList <PluginInfo> Plugins, List <FileReference> ModuleFiles, List <FileReference> TargetFiles, Dictionary <FileReference, PluginInfo> ModuleFileToPluginInfo, FileReference AssemblyFileName, RulesAssembly Parent)
        {
            this.Plugins = Plugins;
            this.ModuleFileToPluginInfo = ModuleFileToPluginInfo;
            this.Parent = Parent;

            // Find all the source files
            List <FileReference> AssemblySourceFiles = new List <FileReference>();

            AssemblySourceFiles.AddRange(ModuleFiles);
            AssemblySourceFiles.AddRange(TargetFiles);

            // Compile the assembly
            if (AssemblySourceFiles.Count > 0)
            {
                List <string> PreprocessorDefines = new List <string>();
                PreprocessorDefines.Add("WITH_FORWARDED_MODULE_RULES_CTOR");
                PreprocessorDefines.Add("WITH_FORWARDED_TARGET_RULES_CTOR");

                // Define macros for the UE4 version, starting with 4.17
                BuildVersion Version;
                if (BuildVersion.TryRead(BuildVersion.GetDefaultFileName(), out Version))
                {
                    for (int MinorVersion = 17; MinorVersion <= Version.MinorVersion; MinorVersion++)
                    {
                        PreprocessorDefines.Add(String.Format("UE_4_{0}_OR_LATER", MinorVersion));
                    }
                }

                CompiledAssembly = DynamicCompilation.CompileAndLoadAssembly(AssemblyFileName, AssemblySourceFiles, PreprocessorDefines: PreprocessorDefines);
            }

            // Setup the module map
            foreach (FileReference ModuleFile in ModuleFiles)
            {
                string ModuleName = ModuleFile.GetFileNameWithoutAnyExtensions();
                if (!ModuleNameToModuleFile.ContainsKey(ModuleName))
                {
                    ModuleNameToModuleFile.Add(ModuleName, ModuleFile);
                }
            }

            // Setup the target map
            foreach (FileReference TargetFile in TargetFiles)
            {
                string TargetName = TargetFile.GetFileNameWithoutAnyExtensions();
                if (!TargetNameToTargetFile.ContainsKey(TargetName))
                {
                    TargetNameToTargetFile.Add(TargetName, TargetFile);
                }
            }

            // Write any deprecation warnings for methods overriden from a base with the [ObsoleteOverride] attribute. Unlike the [Obsolete] attribute, this ensures the message
            // is given because the method is implemented, not because it's called.
            if (CompiledAssembly != null)
            {
                foreach (Type CompiledType in CompiledAssembly.GetTypes())
                {
                    foreach (MethodInfo Method in CompiledType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
                    {
                        ObsoleteOverrideAttribute Attribute = Method.GetCustomAttribute <ObsoleteOverrideAttribute>(true);
                        if (Attribute != null)
                        {
                            FileReference Location;
                            if (!TryGetFileNameFromType(CompiledType, out Location))
                            {
                                Location = new FileReference(CompiledAssembly.Location);
                            }
                            Log.TraceWarning("{0}: warning: {1}", Location, Attribute.Message);
                        }
                    }
                    if (CompiledType.BaseType == typeof(ModuleRules))
                    {
                        ConstructorInfo Constructor = CompiledType.GetConstructor(new Type[] { typeof(TargetInfo) });
                        if (Constructor != null)
                        {
                            FileReference Location;
                            if (!TryGetFileNameFromType(CompiledType, out Location))
                            {
                                Location = new FileReference(CompiledAssembly.Location);
                            }
                            Log.TraceWarning("{0}: warning: Module constructors should take a ReadOnlyTargetRules argument (rather than a TargetInfo argument) and pass it to the base class constructor from 4.15 onwards. Please update the method signature.", Location);
                        }
                    }
                }
            }
        }