示例#1
0
        public void PropertyCollectorEvaluationContextTest()
        {
            var collector = new PropertyValueCollector(false);

            collector.Mark("Hello");
            collector.Collect("Hello", new ExpressionText(0, "One", true));
            collector.Collect("Hello", new ExpressionText(0, "Two", true));

            var ctx = new MSBuildCollectedValuesEvaluationContext(
                new TestEvaluationContext(),
                collector
                );

            var vals = ctx.EvaluateWithPermutation("$(Hello)").ToList();

            Assert.AreEqual(2, vals.Count);
            Assert.AreEqual("One", vals[0]);
            Assert.AreEqual("Two", vals[1]);
        }
        internal IEnumerable <Import> ResolveImport(
            IMSBuildEvaluationContext fileContext,
            string thisFilePath,
            ExpressionNode importExpr,
            string importExprString,
            string sdk)
        {
            //FIXME: add support for MSBuildUserExtensionsPath, the context does not currently support it
            if (importExprString.IndexOf("$(MSBuildUserExtensionsPath)", StringComparison.OrdinalIgnoreCase) > -1)
            {
                yield break;
            }

            //TODO: can we we re-use this context? the propvals may change between evaluations
            var context = new MSBuildCollectedValuesEvaluationContext(fileContext, PropertyCollector);

            bool foundAny   = false;
            bool isWildcard = false;

            foreach (var filename in context.EvaluatePathWithPermutation(importExpr, Path.GetDirectoryName(thisFilePath)))
            {
                if (string.IsNullOrEmpty(filename))
                {
                    continue;
                }

                //dedup
                if (!ImportedFiles.Add(filename))
                {
                    foundAny = true;
                    continue;
                }

                //wildcards
                var wildcardIdx = filename.IndexOf('*');

                //arbitrary limit to skip improbably short values from bad evaluation
                const int MIN_WILDCARD_STAR_IDX    = 15;
                const int MIN_WILDCARD_PATTERN_IDX = 10;
                if (wildcardIdx > MIN_WILDCARD_STAR_IDX)
                {
                    isWildcard = true;
                    var lastSlash = filename.LastIndexOf(Path.DirectorySeparatorChar);
                    if (lastSlash < MIN_WILDCARD_PATTERN_IDX)
                    {
                        continue;
                    }
                    if (lastSlash > wildcardIdx)
                    {
                        continue;
                    }

                    string[] files;
                    try {
                        var dir = filename.Substring(0, lastSlash);
                        if (!Directory.Exists(dir))
                        {
                            continue;
                        }

                        //finding the folder's enough for this to "count" as resolved even if there aren't any files in it
                        foundAny = true;

                        var pattern = filename.Substring(lastSlash + 1);

                        files = Directory.GetFiles(dir, pattern);
                    } catch (Exception ex) when(IsNotCancellation(ex))
                    {
                        LoggingService.LogError($"Error evaluating wildcard in import candidate '{filename}'", ex);
                        continue;
                    }

                    foreach (var f in files)
                    {
                        Import wildImport;
                        try {
                            wildImport = GetCachedOrParse(importExprString, f, sdk, File.GetLastWriteTimeUtc(f));
                        } catch (Exception ex) when(IsNotCancellation(ex))
                        {
                            LoggingService.LogError($"Error reading wildcard import candidate '{files}'", ex);
                            continue;
                        }
                        yield return(wildImport);
                    }

                    continue;
                }

                Import import;
                try {
                    var fi = new FileInfo(filename);
                    if (!fi.Exists)
                    {
                        continue;
                    }
                    import = GetCachedOrParse(importExprString, filename, sdk, fi.LastWriteTimeUtc);
                } catch (Exception ex) when(IsNotCancellation(ex))
                {
                    LoggingService.LogError($"Error reading import candidate '{filename}'", ex);
                    continue;
                }

                foundAny = true;
                yield return(import);

                continue;
            }

            //yield a placeholder for tooltips, imports pad etc to query
            if (!foundAny)
            {
                yield return(new Import(importExprString, sdk, null, DateTime.MinValue));
            }

            // we skip logging for wildcards as these are generally extensibility points that are often unused
            // this is here (rather than being folded into the next condition) for ease of breakpointing
            if (!foundAny && !isWildcard)
            {
                if (PreviousRootDocument == null && failedImports.Add(importExprString))
                {
                    LoggingService.LogDebug($"Could not resolve MSBuild import '{importExprString}'");
                }
            }
        }
        void CollectTaskDefinition(XElement element)
        {
            string taskName = null, assemblyFile = null, assemblyName = null, taskFactory = null;

            foreach (var att in element.Attributes)
            {
                switch (att.Name.Name.ToLowerInvariant())
                {
                case "assemblyfile":
                    assemblyFile = att.Value;
                    break;

                case "assemblyname":
                    assemblyName = att.Value;
                    break;

                case "taskfactory":
                    taskFactory = att.Value;
                    break;

                case "taskname":
                    taskName = att.Value;
                    break;
                }
            }

            if (taskName == null)
            {
                return;
            }

            int    nameIdx = taskName.LastIndexOf('.');
            string name    = taskName.Substring(nameIdx + 1);

            if (string.IsNullOrEmpty(name))
            {
                return;
            }

            if (taskFactory == null && (assemblyName != null || assemblyFile != null))
            {
                //FIXME create this lazily and cache it
                var      evalCtx = new MSBuildCollectedValuesEvaluationContext(new MSBuildFileEvaluationContext(parseContext.RuntimeEvaluationContext, parseContext.ProjectPath, Filename), parseContext.PropertyCollector);
                TaskInfo info    = parseContext.TaskBuilder.CreateTaskInfo(taskName, assemblyName, assemblyFile, Filename, element.Span.Start, evalCtx);
                if (info != null)
                {
                    Document.Tasks[info.Name] = info;
                    return;
                }
            }

            //HACK: RoslynCodeTaskFactory determines the parameters automatically from the code, until we
            //can do this too we need to force inference
            bool forceInferAttributes = taskFactory != null && (
                string.Equals(taskFactory, "RoslynCodeTaskFactory", StringComparison.OrdinalIgnoreCase) || (
                    string.Equals(taskFactory, "CodeTaskFactory", StringComparison.OrdinalIgnoreCase) &&
                    string.Equals(assemblyFile, "$(RoslynCodeTaskFactory)", StringComparison.OrdinalIgnoreCase
                                  )) &&
                !element.Elements.Any(n => n.Name.Name == "ParameterGroup"));

            Document.Tasks[name] = new TaskInfo(name, null, null, null, null, Filename, element.Span.Start)
            {
                ForceInferAttributes = forceInferAttributes
            };
        }