public OpportunisticInternLegacySimpleConcurrecy_Tests(ITestOutputHelper testOutput)
     : base(testOutput)
 {
     _env.SetEnvironmentVariable("MSBuildUseLegacyStringInterner", "1");
     _env.SetEnvironmentVariable("MSBuildUseSimpleInternConcurrency", "1");
     OpportunisticIntern.ResetForTests();
 }
Esempio n. 2
0
        /// <summary>
        /// Execute the task.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            ArrayList inPathList    = new ArrayList();
            ArrayList outOfPathList = new ArrayList();

            string conePath;

            try
            {
                conePath = OpportunisticIntern.InternStringIfPossible(System.IO.Path.GetFullPath(_path.ItemSpec));
                conePath = FileUtilities.EnsureTrailingSlash(conePath);
            }
            catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
            {
                Log.LogErrorWithCodeFromResources(null, "", 0, 0, 0, 0,
                                                  "FindUnderPath.InvalidParameter", "Path", _path.ItemSpec, e.Message);
                return(false);
            }

            int conePathLength = conePath.Length;

            Log.LogMessageFromResources(MessageImportance.Low, "FindUnderPath.ComparisonPath", Path.ItemSpec);

            foreach (ITaskItem item in Files)
            {
                string fullPath;
                try
                {
                    fullPath = OpportunisticIntern.InternStringIfPossible(System.IO.Path.GetFullPath(item.ItemSpec));
                }
                catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
                {
                    Log.LogErrorWithCodeFromResources(null, "", 0, 0, 0, 0,
                                                      "FindUnderPath.InvalidParameter", "Files", item.ItemSpec, e.Message);
                    return(false);
                }

                // Compare the left side of both strings to see if they're equal.
                if (String.Compare(conePath, 0, fullPath, 0, conePathLength, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    // If we should use the absolute path, update the item contents
                    // Since ItemSpec, which fullPath comes from, is unescaped, re-escape when setting
                    // item.ItemSpec, since the setter for ItemSpec expects an escaped value.
                    if (_updateToAbsolutePaths)
                    {
                        item.ItemSpec = EscapingUtilities.Escape(fullPath);
                    }

                    inPathList.Add(item);
                }
                else
                {
                    outOfPathList.Add(item);
                }
            }

            InPath    = (ITaskItem[])inPathList.ToArray(typeof(ITaskItem));
            OutOfPath = (ITaskItem[])outOfPathList.ToArray(typeof(ITaskItem));
            return(true);
        }
Esempio n. 3
0
        private static bool IsInternable(OpportunisticIntern.IInternable internable)
        {
            string i1 = OpportunisticIntern.InternableToString(internable);
            string i2 = OpportunisticIntern.InternableToString(internable);

            Assert.Equal(i1, i2); // No matter what, the same string value should return.
            return(Object.ReferenceEquals(i1, i2));
        }
        /// <summary>
        ///     Parse the given <paramref name="fileSpec" /> into a <see cref="MSBuildGlob" /> using a given
        ///     <paramref name="globRoot" />.
        /// </summary>
        /// <param name="globRoot">
        ///     The root of the glob.
        ///     The fixed directory part of the glob and the match arguments (<see cref="IsMatch" /> and <see cref="MatchInfo" />)
        ///     will get normalized against this root.
        ///     If empty, the current working directory is used.
        ///     Cannot be null, and cannot contain invalid path arguments.
        /// </param>
        /// <param name="fileSpec">The string to parse</param>
        /// <returns></returns>
        public static MSBuildGlob Parse(string globRoot, string fileSpec)
        {
            ErrorUtilities.VerifyThrowArgumentNull(globRoot, nameof(globRoot));
            ErrorUtilities.VerifyThrowArgumentNull(fileSpec, nameof(fileSpec));
            ErrorUtilities.VerifyThrowArgumentInvalidPath(globRoot, nameof(globRoot));

            if (globRoot == string.Empty)
            {
                globRoot = Directory.GetCurrentDirectory();
            }

            globRoot = OpportunisticIntern.InternStringIfPossible(FileUtilities.NormalizePath(globRoot).WithTrailingSlash());

            var lazyState = new Lazy <GlobState>(() =>
            {
                string fixedDirectoryPart    = null;
                string wildcardDirectoryPart = null;
                string filenamePart          = null;

                string matchFileExpression;
                bool needsRecursion;
                bool isLegalFileSpec;

                FileMatcher.Default.GetFileSpecInfo(
                    fileSpec,
                    out fixedDirectoryPart,
                    out wildcardDirectoryPart,
                    out filenamePart,
                    out matchFileExpression,
                    out needsRecursion,
                    out isLegalFileSpec,
                    (fixedDirPart, wildcardDirPart, filePart) =>
                {
                    var normalizedFixedPart = NormalizeTheFixedDirectoryPartAgainstTheGlobRoot(fixedDirPart, globRoot);

                    return(Tuple.Create(normalizedFixedPart, wildcardDirPart, filePart));
                });

                // compile the regex since it's expected to be used multiple times
                var regex = isLegalFileSpec
                    ? new Regex(matchFileExpression, FileMatcher.DefaultRegexOptions | RegexOptions.Compiled)
                    : null;

                return(new GlobState(globRoot, fileSpec, isLegalFileSpec, fixedDirectoryPart, wildcardDirectoryPart, filenamePart, matchFileExpression, needsRecursion, regex));
            },
                                                 true);

            return(new MSBuildGlob(lazyState));
        }
Esempio n. 5
0
        /// <summary>
        /// Adds instances of %XX in the input string where the char to be escaped appears
        /// XX is the hex value of the ASCII code for the char.  Caches if requested.
        /// </summary>
        /// <param name="unescapedString">The string to escape.</param>
        /// <param name="cache">
        /// True if the cache should be checked, and if the resultant string
        /// should be cached.
        /// </param>
        private static string EscapeWithOptionalCaching(string unescapedString, bool cache)
        {
            // If there are no special chars, just return the original string immediately.
            // Don't even instantiate the StringBuilder.
            if (String.IsNullOrEmpty(unescapedString) || !ContainsReservedCharacters(unescapedString))
            {
                return(unescapedString);
            }

            // next, if we're caching, check to see if it's already there.
            if (cache)
            {
                string cachedEscapedString = null;
                lock (s_unescapedToEscapedStrings)
                {
                    if (s_unescapedToEscapedStrings.TryGetValue(unescapedString, out cachedEscapedString))
                    {
                        return(cachedEscapedString);
                    }
                }
            }

            // This is where we're going to build up the final string to return to the caller.
            StringBuilder escapedStringBuilder = StringBuilderCache.Acquire(unescapedString.Length * 2);

            AppendEscapedString(escapedStringBuilder, unescapedString);

            if (!cache)
            {
                return(StringBuilderCache.GetStringAndRelease(escapedStringBuilder));
            }

            string escapedString = OpportunisticIntern.StringBuilderToString(escapedStringBuilder);

            StringBuilderCache.Release(escapedStringBuilder);

            lock (s_unescapedToEscapedStrings)
            {
                s_unescapedToEscapedStrings[unescapedString] = escapedString;
            }

            return(escapedString);
        }
Esempio n. 6
0
            /// <summary>
            /// Returns a whitespace-trimmed and possibly interned substring of the expression.
            /// </summary>
            /// <param name="startIndex">Start index of the substring.</param>
            /// <param name="length">Length of the substring.</param>
            /// <returns>Equivalent to _expression.Substring(startIndex, length).Trim() or null if the trimmed substring is empty.</returns>
            private string GetExpressionSubstring(int startIndex, int length)
            {
                int endIndex = startIndex + length;

                while (startIndex < endIndex && char.IsWhiteSpace(_expression[startIndex]))
                {
                    startIndex++;
                }
                while (startIndex < endIndex && char.IsWhiteSpace(_expression[endIndex - 1]))
                {
                    endIndex--;
                }
                if (startIndex < endIndex)
                {
                    var target = new SubstringInternTarget(_expression, startIndex, endIndex - startIndex);
                    return(OpportunisticIntern.InternableToString(target));
                }
                return(null);
            }
 public OpportunisticIntern_Tests(ITestOutputHelper testOutput)
     : base(testOutput)
 {
     OpportunisticIntern.ResetForTests();
 }
Esempio n. 8
0
        /// <summary>
        /// Given a string of semi-colon delimited name=value pairs, this method parses it and creates
        /// a hash table containing the property names as keys and the property values as values.
        /// This method escapes any special characters found in the property values, in case they
        /// are going to be passed to a method (such as that expects the appropriate escaping to have happened
        /// already.
        /// </summary>
        /// <returns>true on success, false on failure.</returns>
        internal static bool GetTableWithEscaping(TaskLoggingHelper log, string parameterName, string syntaxName, string[] propertyNameValueStrings, out Dictionary <string, string> finalPropertiesTable)
        {
            finalPropertiesTable = null;

            if (propertyNameValueStrings != null)
            {
                finalPropertiesTable = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                var finalPropertiesList = new List <PropertyNameValuePair>();

                // Loop through the array.  Each string in the array should be of the form:
                //          MyPropName=MyPropValue
                foreach (string propertyNameValueString in propertyNameValueStrings)
                {
                    // Find the first '=' sign in the string.
                    int indexOfEqualsSign = propertyNameValueString.IndexOf('=');

                    if (indexOfEqualsSign != -1)
                    {
                        // If we found one, then grab the stuff before it and put it into "propertyName",
                        // and grab the stuff after it and put it into "propertyValue".  But trim the
                        // whitespace from beginning and end of both name and value.  (When authoring a
                        // project/targets file, people like to use whitespace and newlines to pretty up
                        // the file format.)
                        string propertyName  = propertyNameValueString.Substring(0, indexOfEqualsSign).Trim();
                        string propertyValue = EscapingUtilities.Escape(propertyNameValueString.Substring(indexOfEqualsSign + 1).Trim());

                        // Make sure we have a property name and property value (though the value is allowed to be blank).
                        if (propertyName.Length == 0)
                        {
                            // No property name?  That's no good to us.
                            log?.LogErrorWithCodeFromResources("General.InvalidPropertyError", syntaxName, propertyNameValueString);

                            return(false);
                        }

                        // Store the property in our list.
                        finalPropertiesList.Add(new PropertyNameValuePair(propertyName, propertyValue));
                    }
                    else
                    {
                        // There's no '=' sign in the string.  When this happens, we treat this string as basically
                        // an appendage on the value of the previous property.  For example, if the project file contains
                        //
                        //      <PropertyGroup>
                        //          <WarningsAsErrors>1234;5678;9999</WarningsAsErrors>
                        //      </PropertyGroup>
                        //      <Target Name="Build">
                        //          <MSBuild Projects="ConsoleApplication1.csproj"
                        //                   Properties="WarningsAsErrors=$(WarningsAsErrors)"/>
                        //      </Target>
                        //
                        // , then this method (GetTableWithEscaping) will see this:
                        //
                        //      propertyNameValueStrings[0] = "WarningsAsErrors=1234"
                        //      propertyNameValueStrings[1] = "5678"
                        //      propertyNameValueStrings[2] = "9999"
                        //
                        // And what we actually want to end up with in our final hashtable is this:
                        //
                        //      NAME                    VALUE
                        //      ===================     ================================
                        //      WarningsAsErrors        1234;5678;9999
                        //
                        if (finalPropertiesList.Count > 0)
                        {
                            // There was a property definition previous to this one.  Append the current string
                            // to that previous value, using semicolon as a separator.
                            string propertyValue = EscapingUtilities.Escape(propertyNameValueString.Trim());
                            finalPropertiesList[finalPropertiesList.Count - 1].Value.Append(';');
                            finalPropertiesList[finalPropertiesList.Count - 1].Value.Append(propertyValue);
                        }
                        else
                        {
                            // No equals sign in the very first property?  That's a problem.
                            log?.LogErrorWithCodeFromResources("General.InvalidPropertyError", syntaxName, propertyNameValueString);

                            return(false);
                        }
                    }
                }

                // Convert the data in the List to a Hashtable, because that's what the MSBuild task eventually
                // needs to pass onto the engine.
                log?.LogMessageFromText(parameterName, MessageImportance.Low);

                foreach (PropertyNameValuePair propertyNameValuePair in finalPropertiesList)
                {
                    string propertyValue = OpportunisticIntern.StringBuilderToString(propertyNameValuePair.Value);
                    finalPropertiesTable[propertyNameValuePair.Name] = propertyValue;
                    log?.LogMessageFromText(
                        $"  {propertyNameValuePair.Name}={propertyValue}",
                        MessageImportance.Low);
                }
            }

            return(true);
        }