Exemple #1
0
        /// <summary>
        /// Evaluates a condition in the context of a flattened ProjectInstance,
        /// avoiding processing where the condition contains constructs that are
        /// difficult to evaluate statically.
        /// </summary>
        /// <returns>
        /// If condition true or false. If any MSBuild project exception is thrown during evaluation,
        /// result will be false.
        /// </returns>
        /// <exception cref="InvalidProjectFileException">
        /// Thrown by MSBuild when evaluation fails. This exception cannot be easily
        /// handled locally, e.g. by catching and returning false, as it will usually
        /// leave the Project in a bad state, e.g. an empty Targets collection,
        /// which will affect downstream code that tries to evaluate targets.
        /// </exception>
        public static bool EvaluateConditionCarefully(this ProjectInstance projectInstance, string condition)
        {
            // To avoid extra work, return true (default) if condition is empty.
            if (string.IsNullOrWhiteSpace(condition))
            {
                return(true);
            }

            // We cannot handle %(...) metadata accesses in conditions. For example, see these conditions
            // in Microsoft.WebApplication.targets:
            //
            //   <Copy SourceFiles="@(Content)" Condition="'%(Content.Link)' == ''"
            //   <Copy SourceFiles="@(Content)" Condition="!$(DisableLinkInCopyWebApplication) And '%(Content.Link)' != ''"
            //
            // Attempting to evaluate these conditions throws an MSB4191 exception from
            // Project.ReevaluateIfNecessary(), trashing Project (Project.Targets collection
            // becomes empty, for example). Extra info at:
            // http://stackoverflow.com/questions/4721879/ms-build-access-compiler-settings-in-a-subsequent-task
            // ProjectInstance.EvaluateCondition() also does not support bare metadata based condition parsing,
            // it uses the internal Expander class with option ExpandPropertiesAndItems but not the
            // more extensive ExpandAll or ExpandMetadata.
            // https://github.com/Microsoft/msbuild/blob/master/src/Build/Instance/ProjectInstance.cs#L1763
            if (condition.IndexOf("%(", StringComparison.Ordinal) != -1)
            {
                return(false);
            }

            return(projectInstance.EvaluateCondition(condition));
        }
Exemple #2
0
        void LoadUsingTasks(ProjectInstance projectInstance, ProjectRootElement project)
        {
            Func <string, bool> cond = s => projectInstance != null?projectInstance.EvaluateCondition(s) : Convert.ToBoolean(s);

            foreach (var ut in project.UsingTasks)
            {
                var ta = assemblies.FirstOrDefault(a => a.AssemblyFile.Equals(ut.AssemblyFile, StringComparison.OrdinalIgnoreCase) || a.AssemblyName.Equals(ut.AssemblyName, StringComparison.OrdinalIgnoreCase));
                if (ta == null)
                {
                    ta = new TaskAssembly()
                    {
                        AssemblyName = ut.AssemblyName, AssemblyFile = ut.AssemblyFile
                    };
                    ta.LoadedAssembly = ta.AssemblyName != null?Assembly.Load(ta.AssemblyName) : Assembly.LoadFile(ta.AssemblyFile);

                    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);
                var task = new TaskDescription()
                {
                    TaskAssembly          = ta,
                    Name                  = ut.TaskName,
                    TaskFactoryType       = string.IsNullOrEmpty(ut.TaskFactory) ? null : LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskFactory),
                    TaskType              = string.IsNullOrEmpty(ut.TaskFactory) ? LoadTypeFrom(ta.LoadedAssembly, ut.TaskName, ut.TaskName) : null,
                    TaskFactoryParameters = pg,
                    TaskBody              = ut.TaskBody != null && cond(ut.TaskBody.Condition) ? ut.TaskBody.Evaluate : null,
                };
                task_descs.Add(task);
            }
        }
        bool RunBuildTask(ProjectTargetInstance target, ProjectTaskInstance taskInstance, TargetResult targetResult, InternalBuildArguments args)
        {
            var request = submission.BuildRequest;

            var host = request.HostServices == null ? null : request.HostServices.GetHostObject(request.ProjectFullPath, target.Name, taskInstance.Name);

            // Create Task instance.
            var factoryIdentityParameters = new Dictionary <string, string> ();

            factoryIdentityParameters ["MSBuildRuntime"]      = taskInstance.MSBuildRuntime;
            factoryIdentityParameters ["MSBuildArchitecture"] = taskInstance.MSBuildArchitecture;
            var task = args.BuildTaskFactory.CreateTask(taskInstance.Name, factoryIdentityParameters, this);

            if (task == null)
            {
                throw new InvalidOperationException(string.Format("TaskFactory {0} returned null Task", args.BuildTaskFactory));
            }
            LogMessageEvent(new BuildMessageEventArgs(string.Format("Using task {0} from {1}", taskInstance.Name, task.GetType()), null, null, MessageImportance.Low));
            task.HostObject  = host;
            task.BuildEngine = this;

            // Prepare task parameters.
            var evaluator           = new ExpressionEvaluator(project);
            var evaluatedTaskParams = taskInstance.Parameters.Select(p => new KeyValuePair <string, string> (p.Key, project.ExpandString(evaluator, p.Value)));

            var requiredProps = task.GetType().GetProperties()
                                .Where(p => p.CanWrite && p.GetCustomAttributes(typeof(RequiredAttribute), true).Any());
            var missings = requiredProps.Where(p => !evaluatedTaskParams.Any(tp => tp.Key.Equals(p.Name, StringComparison.OrdinalIgnoreCase)));

            if (missings.Any())
            {
                throw new InvalidOperationException(string.Format("Task {0} of type {1} is used without specifying mandatory property: {2}",
                                                                  taskInstance.Name, task.GetType(), string.Join(", ", missings.Select(p => p.Name).ToArray())));
            }

            foreach (var p in evaluatedTaskParams)
            {
                switch (p.Key.ToLower())
                {
                case "condition":
                case "continueonerror":
                    continue;
                }
                var prop = task.GetType().GetProperty(p.Key);
                if (prop == null)
                {
                    throw new InvalidOperationException(string.Format("Task {0} does not have property {1}", taskInstance.Name, p.Key));
                }
                if (!prop.CanWrite)
                {
                    throw new InvalidOperationException(string.Format("Task {0} has property {1} but it is read-only.", taskInstance.Name, p.Key));
                }
                if (string.IsNullOrEmpty(p.Value) && !requiredProps.Contains(prop))
                {
                    continue;
                }
                try {
                    prop.SetValue(task, ConvertTo(p.Value, prop.PropertyType, evaluator), null);
                } catch (Exception ex) {
                    throw new InvalidOperationException(string.Format("Failed to convert '{0}' for property '{1}' of type {2}", p.Value, prop.Name, prop.PropertyType), ex);
                }
            }

            // Do execute task.
            bool taskSuccess = false;

            event_source.FireTaskStarted(this, new TaskStartedEventArgs("Task Started", null, project.FullPath, taskInstance.FullPath, taskInstance.Name));
            try {
                taskSuccess = task.Execute();

                if (!taskSuccess)
                {
                    targetResult.Failure(null);
                    if (!ContinueOnError)
                    {
                        return(false);
                    }
                }
                else
                {
                    // Evaluate task output properties and items.
                    foreach (var to in taskInstance.Outputs)
                    {
                        if (!project.EvaluateCondition(to.Condition))
                        {
                            continue;
                        }
                        var    toItem        = to as ProjectTaskOutputItemInstance;
                        var    toProp        = to as ProjectTaskOutputPropertyInstance;
                        string taskParameter = toItem != null ? toItem.TaskParameter : toProp.TaskParameter;
                        var    pi            = task.GetType().GetProperty(taskParameter);
                        if (pi == null)
                        {
                            throw new InvalidOperationException(string.Format("Task {0} does not have property {1} specified as TaskParameter", taskInstance.Name, toItem.TaskParameter));
                        }
                        if (!pi.CanRead)
                        {
                            throw new InvalidOperationException(string.Format("Task {0} has property {1} specified as TaskParameter, but it is write-only", taskInstance.Name, toItem.TaskParameter));
                        }
                        var value       = pi.GetValue(task, null);
                        var valueString = ConvertFrom(value);
                        if (toItem != null)
                        {
                            LogMessageEvent(new BuildMessageEventArgs(string.Format("Output Item {0} from TaskParameter {1}: {2}", toItem.ItemType, toItem.TaskParameter, valueString), null, null, MessageImportance.Low));
                            Action <ITaskItem> addItem = i => {
                                var metadata = new ArrayList(i.MetadataNames).ToArray().Cast <string> ().Select(n => new KeyValuePair <string, string> (n, i.GetMetadata(n)));
                                args.Project.AddItem(toItem.ItemType, i.ItemSpec, metadata);
                            };
                            var taskItemArray = value as ITaskItem [];
                            if (taskItemArray != null)
                            {
                                foreach (var ti in taskItemArray)
                                {
                                    addItem(ti);
                                }
                            }
                            else
                            {
                                var taskItem = value as ITaskItem;
                                if (taskItem != null)
                                {
                                    addItem(taskItem);
                                }
                                else
                                {
                                    foreach (var item in valueString.Split(';'))
                                    {
                                        args.Project.AddItem(toItem.ItemType, item);
                                    }
                                }
                            }
                        }
                        else
                        {
                            LogMessageEvent(new BuildMessageEventArgs(string.Format("Output Property {0} from TaskParameter {1}: {2}", toProp.PropertyName, toProp.TaskParameter, valueString), null, null, MessageImportance.Low));
                            args.Project.SetProperty(toProp.PropertyName, valueString);
                        }
                    }
                }
            } finally {
                event_source.FireTaskFinished(this, new TaskFinishedEventArgs("Task Finished", null, project.FullPath, taskInstance.FullPath, taskInstance.Name, taskSuccess));
            }
            return(true);
        }
Exemple #4
0
        // 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);

            foreach (var ut in usingTasks)
            {
                var ta = assemblies.FirstOrDefault(a => a.AssemblyFile.Equals(ut.AssemblyFile, StringComparison.OrdinalIgnoreCase) || a.AssemblyName.Equals(ut.AssemblyName, StringComparison.OrdinalIgnoreCase));
                if (ta == null)
                {
                    var path = Path.GetDirectoryName(string.IsNullOrEmpty(ut.Location.File) ? projectInstance.FullPath : ut.Location.File);
                    ta = new TaskAssembly()
                    {
                        AssemblyName = ut.AssemblyName, AssemblyFile = ut.AssemblyFile
                    };
                    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) ? 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.Evaluate : 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);
                }
            }
        }
        public static bool EvaluateCondition(string condition, Dictionary <string, string> conditionParameters)
        {
            var projectInstance = new ProjectInstance(ProjectRootElement.Create(), conditionParameters, null, new ProjectCollection());

            return(projectInstance.EvaluateCondition(condition));
        }