Example #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="FileExpressionLiteral"/> class.
        /// </summary>
        /// <param name="rawExpression">An unprocessed string for a single expression.</param>
        /// <param name="project">The project where the expression exists.</param>
        /// <param name="task">The task where the expression exists.</param>
        public FileExpressionLiteral(string rawExpression, ProjectInstance project, ProjectTaskInstance task = null)
            : base(rawExpression, project, task)
        {
            string expandedFileListString = project.ExpandString(ProcessedExpression);

            EvaluatedFiles = expandedFileListString.SplitStringList();
        }
Example #2
0
        /// <summary>
        /// Evaluates a given value in a project's context.
        /// </summary>
        /// <param name="projectInstance">The MSBuild Project instance to use for the evaluation context.</param>
        /// <param name="unevaluatedValue">Unevaluated value.</param>
        /// <returns>List of evaluated values.</returns>
        public static IEnumerable <string> EvaluateValue(this ProjectInstance projectInstance, string unevaluatedValue)
        {
            if (string.IsNullOrWhiteSpace(unevaluatedValue))
            {
                return(Enumerable.Empty <string>());
            }

            string evaluated = projectInstance.ExpandString(unevaluatedValue);

            return(SplitStringListEnumerable(evaluated));
        }
        private IEnumerable <string> GetTargetDependencies(string targetName)
        {
            ProjectTargetInstance targetInstance;

            if (projectInstance.Targets.TryGetValue(targetName, out targetInstance))
            {
                return(SplitTargets(projectInstance.ExpandString(targetInstance.DependsOnTargets)));
            }
            else
            {
                return(Enumerable.Empty <string>());
            }
        }
Example #4
0
        public void ExpandStringWithMetadata()
        {
            string project_xml = @"<Project xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
  <ItemGroup>
    <Foo Include='xxx'><M>x</M></Foo>
    <Foo Include='yyy'><M>y</M></Foo>
  </ItemGroup>
</Project>";
            var    xml         = XmlReader.Create(new StringReader(project_xml));
            var    root        = ProjectRootElement.Create(xml);

            root.FullPath = "ProjectInstanceTest.ExpandStringWithMetadata.proj";
            var proj = new ProjectInstance(root);

            Assert.AreEqual("xxx;yyy", proj.ExpandString("@(FOO)"), "#1");               // so, metadata is gone...
        }
        /// <summary>
        /// Evaluates a batch expression, e.g. '%(Compile.fileName).%(Compile.extension))'.
        /// </summary>
        /// <param name="expression">An unprocessed string for a single expression.</param>
        /// <param name="project">The project where the expression exists.</param>
        /// <param name="task">The task where the expression exists.</param>
        private static List <string> EvaluateBatchedExpression(string expression, ProjectInstance project, ProjectTaskInstance task)
        {
            expression = ProcessExpression(expression, project, task);

            // Copy task has batching in it. Get the batched items if possible, then parse inputs.
            Match regexMatch = BatchedItemRegex.Match(expression);

            if (regexMatch.Success)
            {
                // If the user didn't specify a metadata item, then we default to Identity
                string transformItem = string.IsNullOrEmpty(regexMatch.Groups[2].Value)
                    ? BatchedItemRegex.Replace(expression, @"%(Identity)")
                    : BatchedItemRegex.Replace(expression, @"%($2)");

                // Convert the batch into a transform. If this is an item -> metadata based transition then it will do the replacements for you.
                string expandedString = project.ExpandString($"@({regexMatch.Groups["ItemType"].Value}-> '{transformItem}')");
                return(expandedString.SplitStringList());
            }
            else
            {
                throw new InvalidOperationException();
            }
        }
Example #6
0
        bool BuildTargetByName(string targetName, InternalBuildArguments args)
        {
            var request    = submission.BuildRequest;
            var parameters = submission.BuildManager.OngoingBuildParameters;
            ProjectTargetInstance target;
            TargetResult          dummyResult;

            if (args.Result.ResultsByTarget.TryGetValue(targetName, out dummyResult) && dummyResult.ResultCode == TargetResultCode.Success)
            {
                LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because it was already built successfully.", targetName), null, null, MessageImportance.Low));
                return(true);                // do not add result.
            }

            var targetResult = new TargetResult();

            // null key is allowed and regarded as blind success(!) (as long as it could retrieve target)
            if (!request.ProjectInstance.Targets.TryGetValue(targetName, out target))
            {
                // FIXME: from MSBuild.exe it is given MSB4057. Can we assign a number too?
                throw new InvalidOperationException(string.Format("target '{0}' was not found in project '{1}'", targetName, project.FullPath));
            }
            else if (!args.Project.EvaluateCondition(target.Condition))
            {
                LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because condition '{1}' was not met.", target.Name, target.Condition), null, null, MessageImportance.Low));
                targetResult.Skip();
            }
            else
            {
                // process DependsOnTargets first.
                foreach (var dep in project.ExpandString(target.DependsOnTargets).Split(';').Select(s => s.Trim()).Where(s => !string.IsNullOrEmpty(s)))
                {
                    LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' depends on '{1}'.", target.Name, dep), null, null, MessageImportance.Low));
                    if (!BuildTargetByName(dep, args))
                    {
                        LogMessageEvent(new BuildMessageEventArgs(string.Format("Quit target '{0}', as dependency target '{1}' has failed.", target.Name, dep), null, null, MessageImportance.Low));
                        return(false);
                    }
                }

                Func <string, ITaskItem> creator = s => new TargetOutputTaskItem()
                {
                    ItemSpec = s
                };

                event_source.FireTargetStarted(this, new TargetStartedEventArgs("Target Started", null, target.Name, project.FullPath, target.FullPath));
                try {
                    // FIXME: examine in which scenario Inputs/Outputs inconsistency results in errors. Now it rather prevents csproj build.

                    /*if (!string.IsNullOrEmpty (target.Inputs) != !string.IsNullOrEmpty (target.Outputs)) {
                     *      targetResult.Failure (new InvalidProjectFileException (target.Location, null, string.Format ("Target {0} has mismatching Inputs and Outputs specification. When one is specified, another one has to be specified too.", targetName), null, null, null));
                     * } else*/{
                        bool skip = false;
                        if (!string.IsNullOrEmpty(target.Inputs))
                        {
                            var inputs = args.Project.GetAllItems(target.Inputs, string.Empty, creator, creator, s => true, (t, s) => {
                            });
                            if (!inputs.Any())
                            {
                                LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because there is no input.", target.Name), null, null, MessageImportance.Low));
                                skip = true;
                            }
                            else
                            {
                                var outputs      = args.Project.GetAllItems(target.Outputs, string.Empty, creator, creator, s => true, (t, s) => {
                                });
                                var needsUpdates = GetOlderOutputsThanInputs(inputs, outputs).FirstOrDefault();
                                if (needsUpdates != null)
                                {
                                    LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' needs to be built because new output {1} is needed.", target.Name, needsUpdates.ItemSpec), null, null, MessageImportance.Low));
                                }
                                else
                                {
                                    LogMessageEvent(new BuildMessageEventArgs(string.Format("Target '{0}' was skipped because all the outputs are newer than all the inputs.", target.Name), null, null, MessageImportance.Low));
                                    skip = true;
                                }
                            }
                        }
                        if (skip)
                        {
                            targetResult.Skip();
                        }
                        else
                        {
                            if (DoBuildTarget(target, targetResult, args))
                            {
                                var items = args.Project.GetAllItems(target.Outputs, string.Empty, creator, creator, s => true, (t, s) => {
                                });
                                targetResult.Success(items);
                            }
                        }
                    }
                } finally {
                    event_source.FireTargetFinished(this, new TargetFinishedEventArgs("Target Finished", null, targetName, project.FullPath, target.FullPath, targetResult.ResultCode != TargetResultCode.Failure));
                }
            }
            args.AddTargetResult(targetName, targetResult);

            return(targetResult.ResultCode != TargetResultCode.Failure);
        }
 /// <summary>
 /// Evaluates a literal expression, e.g. '$(Outdir)\foo.dll'.
 /// </summary>
 /// <param name="expression">An unprocessed string for a single expression.</param>
 /// <param name="project">The project where the expression exists.</param>
 /// <param name="task">The task where the expression exists.</param>
 /// <returns>The set of all files in the evaluated expression.</returns>
 private static List <string> EvaluateLiteralExpression(string expression, ProjectInstance project, ProjectTaskInstance task)
 {
     expression = ProcessExpression(expression, project, task);
     expression = project.ExpandString(expression);
     return(expression.SplitStringList());
 }
        // FIXME: my guess is the tasks does not have to be loaded entirely but only requested tasks must be loaded at invocation time.
        void LoadUsingTasks(ProjectInstance projectInstance, IEnumerable <ProjectUsingTaskElement> usingTasks)
        {
            Func <string, bool> cond = s => projectInstance != null?projectInstance.EvaluateCondition(s) : Convert.ToBoolean(s);

            Func <string, string> expand = s => projectInstance != null?projectInstance.ExpandString(s) : s;

            foreach (var ut in usingTasks)
            {
                var aName = expand(ut.AssemblyName);
                var aFile = expand(ut.AssemblyFile);
                if (string.IsNullOrEmpty(aName) && string.IsNullOrEmpty(aFile))
                {
                    var errorNoAssembly = string.Format("Task '{0}' does not specify either of AssemblyName or AssemblyFile.", ut.TaskName);
                    engine.LogWarningEvent(new BuildWarningEventArgs(null, null, projectInstance.FullPath, ut.Location.Line, ut.Location.Column, 0, 0, errorNoAssembly, null, null));
                    continue;
                }
                var ta = assemblies.FirstOrDefault(a => a.AssemblyFile.Equals(aFile, StringComparison.OrdinalIgnoreCase) || a.AssemblyName.Equals(aName, StringComparison.OrdinalIgnoreCase));
                if (ta == null)
                {
                    var path = Path.GetDirectoryName(string.IsNullOrEmpty(ut.Location.File) ? projectInstance.FullPath : ut.Location.File);
                    ta = new TaskAssembly()
                    {
                        AssemblyName = aName, AssemblyFile = aFile
                    };
                    try {
                        ta.LoadedAssembly = !string.IsNullOrEmpty(ta.AssemblyName) ? Assembly.Load(ta.AssemblyName) : Assembly.LoadFile(Path.Combine(path, ta.AssemblyFile));
                    } catch {
                        var errorNotLoaded = string.Format("For task '{0}' Specified assembly '{1}' was not found", ut.TaskName, string.IsNullOrEmpty(ta.AssemblyName) ? Path.Combine(path, ta.AssemblyFile) : ta.AssemblyName);
                        engine.LogWarningEvent(new BuildWarningEventArgs(null, null, projectInstance.FullPath, ut.Location.Line, ut.Location.Column, 0, 0, errorNotLoaded, null, null));
                        continue;
                    }
                    assemblies.Add(ta);
                }
                var pg = ut.ParameterGroup == null ? null : ut.ParameterGroup.Parameters.Select(p => new TaskPropertyInfo(p.Name, Type.GetType(p.ParameterType), cond(p.Output), cond(p.Required)))
                         .ToDictionary(p => p.Name);


                Type            type  = null;
                string          error = null;
                TaskDescription task  = new TaskDescription()
                {
                    TaskAssembly          = ta,
                    Name                  = ut.TaskName,
                    TaskFactoryParameters = pg,
                    TaskBody              = ut.TaskBody != null && cond(ut.TaskBody.Condition) ? ut.TaskBody.TaskBody : null,
                };
                if (string.IsNullOrEmpty(ut.TaskFactory))
                {
                    type = LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskName);
                    if (type == null)
                    {
                        error = string.Format("For task '{0}' Specified type '{1}' was not found in assembly '{2}'", ut.TaskName, ut.TaskName, ta.LoadedAssembly.FullName);
                    }
                    else
                    {
                        task.TaskType = type;
                    }
                }
                else
                {
                    type = LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskFactory);
                    if (type == null)
                    {
                        error = string.Format("For task '{0}' Specified factory type '{1}' was not found in assembly '{2}'", ut.TaskName, ut.TaskFactory, ta.LoadedAssembly.FullName);
                    }
                    else
                    {
                        task.TaskFactoryType = type;
                    }
                }
                if (error != null)
                {
                    engine.LogWarningEvent(new BuildWarningEventArgs(null, null, projectInstance.FullPath, ut.Location.Line, ut.Location.Column, 0, 0, error, null, null));
                }
                else
                {
                    task_descs.Add(task);
                }
            }
        }