Example #1
0
        public BuildTarget(int lineNumber, PropertyGroup targetProps, ItemGroup targetItems)
        {
            LineNumber  = lineNumber;
            Properties  = targetProps;
            Items       = targetItems;
            Name        = targetProps.GetRequiredValue("TargetName");
            InputFiles  = targetItems.GetRequiredValue("TargetInputs");
            OutputFiles = targetItems.GetRequiredValue("TargetOutputs");

            Func <IList <ParsedPath>, IEnumerable <string> > extractAndSortExtensions = (files) =>
            {
                return(files.Select <ParsedPath, string>(f => f.Extension).Distinct <string>().OrderBy(s => s, StringComparer.CurrentCultureIgnoreCase));
            };

            InputExtensions  = extractAndSortExtensions(InputFiles);
            OutputExtensions = extractAndSortExtensions(OutputFiles);
        }
Example #2
0
        private List <CompilerClass> LoadCompilerClasses(ItemGroup itemGroup, PropertyGroup propGroup)
        {
            List <CompilerClass> compilerClasses = new List <CompilerClass>();
            IList <ParsedPath>   paths           = itemGroup.GetRequiredValue("CompilerAssembly");

            foreach (var path in paths)
            {
                Assembly assembly = null;

                try
                {
                    // We use Assembly.Load so that the test assembly and subsequently loaded
                    // assemblies end up in the correct load context.  If the assembly cannot be
                    // found it will raise a AssemblyResolve event where we will search for the
                    // assembly.
                    assembly = Assembly.LoadFrom(path);
                }
                catch (Exception e)
                {
                    throw new ApplicationException(String.Format("Unable to load content compiler assembly file '{0}'. {1}", path, e.ToString()), e);
                }

                Type[] types;

                // We won't get dependency errors until we actually try to reflect on all the types in the assembly
                try
                {
                    types = assembly.GetTypes();
                }
                catch (ReflectionTypeLoadException e)
                {
                    string message = String.Format("Unable to reflect on assembly '{0}'", path);

                    // There is one entry in the exceptions array for each null in the types array,
                    // and they correspond positionally.
                    foreach (Exception ex in e.LoaderExceptions)
                    {
                        message += Environment.NewLine + "   " + ex.Message;
                    }

                    // Not being able to reflect on classes in the test assembly is a critical error
                    throw new ApplicationException(message, e);
                }

                // Go through all the types in the test assembly and find all the
                // compiler classes, those that inherit from IContentCompiler.
                foreach (var type in types)
                {
                    Type interfaceType = type.GetInterface(typeof(IContentCompiler).ToString());

                    if (interfaceType != null)
                    {
                        CompilerClass compilerClass = new CompilerClass(assembly, type);

                        compilerClasses.Add(compilerClass);
                    }
                }
            }

            return(compilerClasses);
        }
Example #3
0
        private List <BuildTarget> PrepareBuildTargets(List <ContentFileV2.Target> rawTargets, ItemGroup globalItems, PropertyGroup globalProps)
        {
            List <BuildTarget> buildTargets = new List <BuildTarget>();

            foreach (var rawTarget in rawTargets)
            {
                try
                {
                    PropertyGroup targetProps = new PropertyGroup(globalProps);

                    targetProps.Set("TargetName", rawTarget.Name);

                    if (rawTarget.Properties != null)
                    {
                        targetProps.ExpandAndAddFromList(rawTarget.Properties, targetProps);
                    }

                    ItemGroup targetItems = new ItemGroup(globalItems);

                    ParsedPathList inputFiles = new ParsedPathList();
                    string[]       list       = rawTarget.Inputs.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (var rawInputFile in list)
                    {
                        ParsedPath pathSpec = null;
                        string     s        = targetProps.ReplaceVariables(rawInputFile);

                        try
                        {
                            pathSpec = new ParsedPath(s, PathType.File).MakeFullPath();
                        }
                        catch (Exception e)
                        {
                            throw new ContentFileException("Bad path '{0}'".CultureFormat(s), e);
                        }

                        if (pathSpec.HasWildcards)
                        {
                            if (!Directory.Exists(pathSpec.VolumeAndDirectory))
                            {
                                throw new ContentFileException("Directory '{0}' does not exist".CultureFormat(pathSpec.VolumeAndDirectory));
                            }

                            IList <ParsedPath> files = DirectoryUtility.GetFiles(pathSpec, SearchScope.DirectoryOnly);

                            if (files.Count == 0)
                            {
                                throw new ContentFileException("Wildcard input refers to no files after expansion");
                            }

                            inputFiles = new ParsedPathList(inputFiles.Concat(files));
                        }
                        else
                        {
                            if (!File.Exists(pathSpec))
                            {
                                throw new ContentFileException("Input file '{0}' does not exist".CultureFormat(pathSpec));
                            }

                            inputFiles.Add(pathSpec);
                        }
                    }

                    ParsedPathList outputFiles = new ParsedPathList();

                    list = rawTarget.Outputs.Split(';');

                    foreach (var rawOutputFile in list)
                    {
                        string s = targetProps.ReplaceVariables(rawOutputFile);

                        try
                        {
                            ParsedPath outputFile = new ParsedPath(s, PathType.File).MakeFullPath();

                            outputFiles.Add(outputFile);
                        }
                        catch (Exception e)
                        {
                            throw new ContentFileException("Bad path '{0}'".CultureFormat(s), e);
                        }
                    }

                    targetItems.Set("TargetInputs", inputFiles);
                    targetItems.Set("TargetOutputs", outputFiles);

                    bool needsRebuild = IsCompileRequired(inputFiles, outputFiles);

                    if (!needsRebuild)
                    {
                        continue;
                    }

                    buildTargets.Add(new BuildTarget(rawTarget.LineNumber, targetProps, targetItems));
                }
                catch (Exception e)
                {
                    throw new ContentFileException(this.ContentPath, rawTarget.LineNumber, "Error preparing targets", e);
                }
            }

            return(buildTargets);
        }
Example #4
0
        private void SafeExecute()
        {
            if (!NoLogo)
            {
                Console.WriteLine(Parser.LogoBanner);
            }

            if (!runningFromCommandLine)
            {
                Parser.GetTargetArguments(this);
                Output.Message(MessageImportance.Normal, Parser.CommandName + Parser.Arguments);
            }

            if (ShowHelp)
            {
                Console.WriteLine(Parser.Usage);
                return;
            }

            if (String.IsNullOrEmpty(ContentPath))
            {
                Output.Error("A .content file must be specified");
                return;
            }

            this.ContentPath = this.ContentPath.MakeFullPath();

            if (!File.Exists(this.ContentPath))
            {
                Output.Error("Content file '{0}' does not exist", this.ContentPath);
                return;
            }

            // Initialize properties from the environment and command line
            PropertyGroup globalProps = new PropertyGroup();

            globalProps.AddFromEnvironment();
            globalProps.AddWellKnownProperties(
                new ParsedPath(Assembly.GetExecutingAssembly().Location, PathType.File).VolumeAndDirectory,
                ContentPath.VolumeAndDirectory);
            globalProps.AddFromPropertyString(this.Properties);

            BuildContext buildContext = new BuildContext(this.Output, this.ContentPath);

            ContentFileV2 contentFile = null;

            try
            {
                contentFile = ContentFileReaderV2.ReadFile(this.ContentPath);
            }
            catch (Exception e)
            {
                throw new ContentFileException(this.ContentPath, (int)e.Data["LineNumber"], "Problem reading content file", e);
            }

            Output.Message(MessageImportance.Low, "Read content file '{0}'", this.ContentPath);

            ItemGroup globalItems = new ItemGroup();

            globalItems.ExpandAndAddFromList(contentFile.Items, globalProps);

            List <CompilerClass> compilerClasses = LoadCompilerClasses(globalItems, globalProps);

            this.NewestAssemblyWriteTime = FindNewestAssemblyWriteTime(compilerClasses);
            this.ContentPathWriteTime    = File.GetLastWriteTime(this.ContentPath);

            List <BuildTarget> BuildTargets = PrepareBuildTargets(contentFile.Targets, globalItems, globalProps);

            foreach (var buildTarget in BuildTargets)
            {
                bool compilerFound = false;

                foreach (var compilerClass in compilerClasses)
                {
                    if (buildTarget.InputExtensions.SequenceEqual(compilerClass.InputExtensions) &&
                        buildTarget.OutputExtensions.SequenceEqual(compilerClass.OutputExtensions))
                    {
                        compilerFound = true;

                        string msg = String.Format("Building target '{0}' with '{1}' compiler", buildTarget.Name, compilerClass.Name);

                        foreach (var input in buildTarget.InputFiles)
                        {
                            msg += Environment.NewLine + "\t" + input;
                        }

                        msg += Environment.NewLine + "\t->";

                        foreach (var output in buildTarget.OutputFiles)
                        {
                            msg += Environment.NewLine + "\t" + output;
                        }

                        Output.Message(MessageImportance.Normal, msg);

                        if (TestMode)
                        {
                            continue;
                        }

                        compilerClass.ContextProperty.SetValue(compilerClass.Instance, buildContext, null);
                        compilerClass.TargetProperty.SetValue(compilerClass.Instance, buildTarget, null);

                        try
                        {
                            compilerClass.CompileMethod.Invoke(compilerClass.Instance, null);
                        }
                        catch (TargetInvocationException e)
                        {
                            ContentFileException contentEx = e.InnerException as ContentFileException;

                            if (contentEx != null)
                            {
                                contentEx.EnsureFileNameAndLineNumber(buildContext.ContentFile, buildTarget.LineNumber);
                                throw contentEx;
                            }
                            else
                            {
                                throw new ContentFileException(
                                          this.ContentPath, buildTarget.LineNumber, "Unable to compile target '{0}'".CultureFormat(buildTarget.Name), e.InnerException);
                            }
                        }

                        // Ensure that the output files were generated
                        foreach (var outputFile in buildTarget.OutputFiles)
                        {
                            if (!File.Exists(outputFile))
                            {
                                throw new ContentFileException(this.ContentPath, buildTarget.LineNumber,
                                                               "Output file '{0}' was not generated".CultureFormat(outputFile));
                            }
                        }
                    }
                }

                if (!compilerFound)
                {
                    Output.Warning("No compiler found for target '{0}' for extensions '{1}' -> '{2}'",
                                   buildTarget.Name,
                                   String.Join(Path.PathSeparator.ToString(), buildTarget.InputExtensions),
                                   String.Join(Path.PathSeparator.ToString(), buildTarget.OutputExtensions));
                }
            }

            Output.Message(MessageImportance.Normal, "Done");
        }