예제 #1
0
 /// <summary>
 /// Evaluates a string representing a condition from a "condition" attribute.
 /// If the condition is a malformed string, it throws an InvalidProjectFileException.
 /// This method uses cached expression trees to avoid generating them from scratch every time it's called.
 /// This method is thread safe and is called from engine and task execution module threads
 /// </summary>
 internal static bool EvaluateCondition <P, I>
 (
     string condition,
     ParserOptions options,
     Expander <P, I> expander,
     ExpanderOptions expanderOptions,
     string evaluationDirectory,
     ElementLocation elementLocation,
     ILoggingService loggingServices,
     BuildEventContext buildEventContext,
     IFileSystem fileSystem,
     ProjectRootElementCacheBase projectRootElementCache = null)
     where P : class, IProperty
     where I : class, IItem
 {
     return(EvaluateConditionCollectingConditionedProperties(
                condition,
                options,
                expander,
                expanderOptions,
                null /* do not collect conditioned properties */,
                evaluationDirectory,
                elementLocation,
                loggingServices,
                buildEventContext,
                fileSystem,
                projectRootElementCache));
 }
예제 #2
0
            internal ConditionEvaluationState
            (
                string condition,
                Expander <P, I> expander,
                ExpanderOptions expanderOptions,
                Dictionary <string, List <string> > conditionedPropertiesInProject,
                string evaluationDirectory,
                ElementLocation elementLocation,
                IFileSystem fileSystem,
                ProjectRootElementCacheBase projectRootElementCache = null
            )
            {
                ErrorUtilities.VerifyThrowArgumentNull(condition, nameof(condition));
                ErrorUtilities.VerifyThrowArgumentNull(expander, nameof(expander));
                ErrorUtilities.VerifyThrowArgumentNull(evaluationDirectory, nameof(evaluationDirectory));
                ErrorUtilities.VerifyThrowArgumentNull(elementLocation, nameof(elementLocation));

                Condition        = condition;
                _expander        = expander;
                _expanderOptions = expanderOptions;
                ConditionedPropertiesInProject = conditionedPropertiesInProject; // May be null
                EvaluationDirectory            = evaluationDirectory;
                ElementLocation     = elementLocation;
                LoadedProjectsCache = projectRootElementCache;
                FileSystem          = fileSystem;
            }
예제 #3
0
        /// <summary>
        /// Evaluates a string representing a condition from a "condition" attribute.
        /// If the condition is a malformed string, it throws an InvalidProjectFileException.
        /// This method uses cached expression trees to avoid generating them from scratch every time it's called.
        /// This method is thread safe and is called from engine and task execution module threads
        /// Logging service may be null.
        /// </summary>
        internal static bool EvaluateConditionCollectingConditionedProperties <P, I>
        (
            string condition,
            ParserOptions options,
            Expander <P, I> expander,
            ExpanderOptions expanderOptions,
            Dictionary <string, List <string> > conditionedPropertiesTable,
            string evaluationDirectory,
            ElementLocation elementLocation,
            ILoggingService loggingServices,
            BuildEventContext buildEventContext,
            IFileSystem fileSystem,
            ProjectRootElementCacheBase projectRootElementCache = null
        )
            where P : class, IProperty
            where I : class, IItem
        {
            ErrorUtilities.VerifyThrowArgumentNull(condition, "condition");
            ErrorUtilities.VerifyThrowArgumentNull(expander, "expander");
            ErrorUtilities.VerifyThrowArgumentLength(evaluationDirectory, "evaluationDirectory");
            ErrorUtilities.VerifyThrowArgumentNull(buildEventContext, "buildEventContext");

            // An empty condition is equivalent to a "true" condition.
            if (condition.Length == 0)
            {
                return(true);
            }

            // If the condition wasn't empty, there must be a location for it
            ErrorUtilities.VerifyThrowArgumentNull(elementLocation, "elementLocation");

            // Get the expression tree cache for the current parsing options.
            var cachedExpressionTreesForCurrentOptions = s_cachedExpressionTrees.GetOrAdd(
                (int)options,
                _ => new ExpressionTreeForCurrentOptionsWithSize(new ConcurrentDictionary <string, ConcurrentStack <GenericExpressionNode> >(StringComparer.Ordinal)));

            cachedExpressionTreesForCurrentOptions = FlushCacheIfLargerThanThreshold(options, cachedExpressionTreesForCurrentOptions);

            // Get the pool of expressions for this condition.
            var expressionPool = cachedExpressionTreesForCurrentOptions.GetOrAdd(condition, _ => new ConcurrentStack <GenericExpressionNode>());

            // Try and see if there's an available expression tree in the pool.
            // If not, parse a new expression tree and add it back to the pool.
            if (!expressionPool.TryPop(out var parsedExpression))
            {
                var conditionParser = new Parser();

                #region REMOVE_COMPAT_WARNING
                conditionParser.LoggingServices      = loggingServices;
                conditionParser.LogBuildEventContext = buildEventContext;
                #endregion

                parsedExpression = conditionParser.Parse(condition, options, elementLocation);
            }

            bool result;

            var state = new ConditionEvaluationState <P, I>(
                condition,
                expander,
                expanderOptions,
                conditionedPropertiesTable,
                evaluationDirectory,
                elementLocation,
                fileSystem,
                projectRootElementCache);

            // We are evaluating this expression now and it can cache some state for the duration,
            // so we don't want multiple threads working on the same expression
            lock (parsedExpression)
            {
                try
                {
                    result = parsedExpression.Evaluate(state);
                }
                finally
                {
                    parsedExpression.ResetState();
                    if (!s_disableExpressionCaching)
                    {
                        // Finished using the expression tree. Add it back to the pool so other threads can use it.
                        expressionPool.Push(parsedExpression);
                    }
                }
            }

            return(result);
        }