/// <summary>
 /// Constructor taking a delegate for unit test purposes only
 /// </summary>
 internal ToolsetConfigurationReader(PropertyDictionary <ProjectPropertyInstance> environmentProperties, PropertyDictionary <ProjectPropertyInstance> globalProperties, Func <Configuration> readApplicationConfiguration)
     : base(environmentProperties, globalProperties)
 {
     ErrorUtilities.VerifyThrowArgumentNull(readApplicationConfiguration, "readApplicationConfiguration");
     _readApplicationConfiguration  = readApplicationConfiguration;
     _projectImportSearchPathsCache = new Dictionary <string, Dictionary <string, List <string> > >(StringComparer.OrdinalIgnoreCase);
 }
Beispiel #2
0
 /// <summary>
 /// Rename an entry in the cache.
 /// Entry must already be in the cache.
 /// </summary>
 internal void RenameEntry(string oldFullPath, ProjectRootElement projectRootElement)
 {
     lock (_locker)
     {
         ErrorUtilities.VerifyThrowArgumentLength(oldFullPath, "oldFullPath");
         RenameEntryInternal(oldFullPath, projectRootElement);
     }
 }
Beispiel #3
0
        /// <summary>
        /// Creates a new property
        /// </summary>
        /// <param name="name">The property name</param>
        /// <param name="value">The property value</param>
        /// <param name="source">The property source</param>
        public ToolsetPropertyDefinition(string name, string value, IElementLocation source)
        {
            ErrorUtilities.VerifyThrowArgumentLength(name, "name");
            ErrorUtilities.VerifyThrowArgumentNull(source, "source");

            // value can be the empty string but not null
            ErrorUtilities.VerifyThrowArgumentNull(value, "value");

            _name   = name;
            _value  = value;
            _source = source;
        }
Beispiel #4
0
        /// <summary>
        /// Forces a removal of a project root element from the weak cache if it is present.
        /// </summary>
        /// <param name="projectRootElement">The project root element to remove.</param>
        /// <remarks>
        /// No exception is thrown if this project root element is in use by currently loaded projects
        /// by this method.  The calling method must know that this is a safe operation.
        /// There may of course be strong references to the project root element from customer code.
        /// The assumption is that when they instruct the project collection to unload it, which
        /// leads to this being called, they are releasing their strong references too (or it doesn't matter)
        /// </remarks>
        internal void DiscardAnyWeakReference(ProjectRootElement projectRootElement)
        {
            ErrorUtilities.VerifyThrowArgumentNull(projectRootElement, "projectRootElement");

            // A PRE may be unnamed if it was only used in memory.
            if (projectRootElement.FullPath != null)
            {
                lock (_locker)
                {
                    _weakCache.Remove(projectRootElement.FullPath);
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Cleanse the project name, by replacing characters like '@', '$' with '_'
        /// </summary>
        /// <param name="projectName">The name to be cleansed</param>
        /// <returns>string</returns>
        private static string CleanseProjectName(string projectName)
        {
            ErrorUtilities.VerifyThrow(projectName != null, "Null strings not allowed.");

            // If there are no special chars, just return the original string immediately.
            // Don't even instantiate the StringBuilder.
            int indexOfChar = projectName.IndexOfAny(s_charsToCleanse);

            if (indexOfChar == -1)
            {
                return(projectName);
            }

            // This is where we're going to work on the final string to return to the caller.
            var cleanProjectName = new StringBuilder(projectName);

            // Replace each unclean character with a clean one
            foreach (char uncleanChar in s_charsToCleanse)
            {
                cleanProjectName.Replace(uncleanChar, cleanCharacter);
            }

            return(cleanProjectName.ToString());
        }
Beispiel #6
0
        /// <summary>
        /// Add or rename an entry in the cache.
        /// Old full path may be null iff it was not already in the cache.
        /// </summary>
        /// <remarks>
        /// Must be called within the cache lock.
        /// </remarks>
        private void RenameEntryInternal(string oldFullPathIfAny, ProjectRootElement projectRootElement)
        {
            ErrorUtilities.VerifyThrowInternalNull(projectRootElement.FullPath, "FullPath");

            if (oldFullPathIfAny != null)
            {
                ErrorUtilities.VerifyThrowInternalRooted(oldFullPathIfAny);
                ErrorUtilities.VerifyThrow(_weakCache[oldFullPathIfAny] == projectRootElement, "Should already be present");
                _weakCache.Remove(oldFullPathIfAny);
            }

            // There may already be a ProjectRootElement in the cache with the new name. In this case we cannot throw an exception;
            // we must merely replace it. This is because it may be an unrooted entry
            // (and thus gone from the client's point of view) that merely remains
            // in the cache because we still have a reference to it from our strong cache.
            // Another possibility is that there are two, unrelated, un-saved, in-memory projects that were given the same path.
            // Replacing the cache entry does not in itself cause a problem -- if there are any actual users of the old
            // entry they will not be affected. There would then exist more than one ProjectRootElement with the same path,
            // but clients ought not get themselves into such a state - and unless they save them to disk,
            // it may not be a problem. Replacing also doesn't cause a problem for the strong cache,
            // as it is never consulted by us, but it is reasonable for us to remove the old entry in that case.
            ProjectRootElement existingWeakEntry;

            _weakCache.TryGetValue(projectRootElement.FullPath, out existingWeakEntry);

            if (existingWeakEntry != null && !Object.ReferenceEquals(existingWeakEntry, projectRootElement))
            {
                _strongCache.Remove(existingWeakEntry);
                RaiseProjectRootElementRemovedFromStrongCache(existingWeakEntry);
            }

            DebugTraceCache("Adding: ", projectRootElement.FullPath);
            _weakCache[projectRootElement.FullPath] = projectRootElement;

            BoostEntryInStrongCache(projectRootElement);
        }
Beispiel #7
0
        /// <summary>
        /// Changes the unique name of the project.
        /// </summary>
        internal void UpdateUniqueProjectName(string newUniqueName)
        {
            ErrorUtilities.VerifyThrowArgumentLength(newUniqueName, nameof(newUniqueName));

            _uniqueProjectName = newUniqueName;
        }
Beispiel #8
0
        /// <summary>
        /// Returns an existing ProjectRootElement for the specified file path, if any.
        /// If none exists, calls the provided delegate to load one, and adds that to the cache.
        /// The reason that it calls back to do this is so that the cache is locked between determining
        /// that the entry does not exist and adding the entry.
        ///
        /// If <see cref="_autoReloadFromDisk"/> was set to true, and the file on disk has changed since it was cached,
        /// it will be reloaded before being returned.
        ///
        /// Thread safe.
        /// </summary>
        /// <remarks>
        /// Never needs to consult the strong cache as well, since if the item is in there, it will
        /// not have left the weak cache.
        /// If item is found, boosts it to the top of the strong cache.
        /// </remarks>
        /// <param name="projectFile">The project file which contains the ProjectRootElement.  Must be a full path.</param>
        /// <param name="openProjectRootElement">The delegate to use to load if necessary. May be null.</param>
        /// <param name="isExplicitlyLoaded"><code>true</code> if the project is explicitly loaded, otherwise <code>false</code>.</param>
        /// <param name="preserveFormatting"><code>true</code> to the project was loaded with the formated preserved, otherwise <code>false</code>.</param>
        /// <returns>The ProjectRootElement instance if one exists.  Null otherwise.</returns>
        internal ProjectRootElement Get(string projectFile, OpenProjectRootElement openProjectRootElement, bool isExplicitlyLoaded,
                                        bool?preserveFormatting)
        {
            // Should already have been canonicalized
            ErrorUtilities.VerifyThrowInternalRooted(projectFile);

            lock (_locker)
            {
                ProjectRootElement projectRootElement;
                _weakCache.TryGetValue(projectFile, out projectRootElement);

                if (preserveFormatting != null && projectRootElement != null && projectRootElement.XmlDocument.PreserveWhitespace != preserveFormatting)
                {
                    //  Cached project doesn't match preserveFormatting setting, so reload it
                    projectRootElement.Reload(true, preserveFormatting);
                }

                if (projectRootElement != null && _autoReloadFromDisk)
                {
                    var fileInfo = FileUtilities.GetFileInfoNoThrow(projectFile);

                    // If the file doesn't exist on disk, go ahead and use the cached version.
                    // It's an in-memory project that hasn't been saved yet.
                    if (fileInfo != null)
                    {
                        bool forgetEntry = false;

                        if (fileInfo.LastWriteTime != projectRootElement.LastWriteTimeWhenRead)
                        {
                            // File was changed on disk by external means. Cached version is no longer reliable.
                            // We could throw here or ignore the problem, but it is a common and reasonable pattern to change a file
                            // externally and load a new project over it to see the new content. So we dump it from the cache
                            // to force a load from disk. There might then exist more than one ProjectRootElement with the same path,
                            // but clients ought not get themselves into such a state - and unless they save them to disk,
                            // it may not be a problem.
                            forgetEntry = true;
                        }
                        else if (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("MSBUILDCACHECHECKFILECONTENT")))
                        {
                            // QA tests run too fast for the timestamp check to work. This environment variable is for their
                            // use: it checks the file content as well as the timestamp. That's better than completely disabling
                            // the cache as we get test coverage of the rest of the cache code.
                            XmlDocument document = new XmlDocument();
                            document.PreserveWhitespace = projectRootElement.XmlDocument.PreserveWhitespace;

                            using (var xtr = XmlReaderExtension.Create(projectRootElement.FullPath, projectRootElement.ProjectRootElementCache.LoadProjectsReadOnly))
                            {
                                document.Load(xtr.Reader);
                            }

                            string diskContent  = document.OuterXml;
                            string cacheContent = projectRootElement.XmlDocument.OuterXml;

                            if (diskContent != cacheContent)
                            {
                                forgetEntry = true;
                            }
                        }

                        if (forgetEntry)
                        {
                            ForgetEntry(projectRootElement);

                            DebugTraceCache("Out of date dropped from XML cache: ", projectFile);
                            projectRootElement = null;
                        }
                    }
                }

                if (projectRootElement == null && openProjectRootElement != null)
                {
                    projectRootElement = openProjectRootElement(projectFile, this);

                    ErrorUtilities.VerifyThrowInternalNull(projectRootElement, "projectRootElement");
                    ErrorUtilities.VerifyThrow(projectRootElement.FullPath == projectFile, "Got project back with incorrect path");
                    ErrorUtilities.VerifyThrow(_weakCache.Contains(projectFile), "Open should have renamed into cache and boosted");
                }
                else if (projectRootElement != null)
                {
                    DebugTraceCache("Satisfied from XML cache: ", projectFile);
                    BoostEntryInStrongCache(projectRootElement);
                }

                // An implicit load will never reset the explicit flag.
                if (projectRootElement != null && isExplicitlyLoaded)
                {
                    projectRootElement.MarkAsExplicitlyLoaded();
                }

                return(projectRootElement);
            }
        }
Beispiel #9
0
        internal override ProjectRootElement Get(string projectFile, OpenProjectRootElement loadProjectRootElement, bool isExplicitlyLoaded,
                                                 bool?preserveFormatting)
        {
#if DEBUG
            // Verify that loadProjectRootElement delegate does not call ProjectRootElementCache.Get().
            s_getEntriesNumber++;
            ErrorUtilities.VerifyThrow(
                s_getEntriesNumber == 1,
                "Reentrance to the ProjectRootElementCache.Get function detected."
                );

            try {
#endif
            // Should already have been canonicalized
            ErrorUtilities.VerifyThrowInternalRooted(projectFile);

            ProjectRootElement projectRootElement;
            lock (_locker)
            {
                _weakCache.TryGetValue(projectFile, out projectRootElement);

                if (projectRootElement != null)
                {
                    BoostEntryInStrongCache(projectRootElement);

                    // An implicit load will never reset the explicit flag.
                    if (isExplicitlyLoaded)
                    {
                        projectRootElement.MarkAsExplicitlyLoaded();
                    }
                }
                else
                {
                    DebugTraceCache("Not found in cache: ", projectFile);
                }

                if (preserveFormatting != null && projectRootElement != null && projectRootElement.XmlDocument.PreserveWhitespace != preserveFormatting)
                {
                    // Cached project doesn't match preserveFormatting setting, so reload it
                    projectRootElement.Reload(true, preserveFormatting);
                }
            }

            bool projectRootElementIsInvalid = IsInvalidEntry(projectFile, projectRootElement);
            if (projectRootElementIsInvalid)
            {
                DebugTraceCache("Not satisfied from cache: ", projectFile);
                ForgetEntryIfExists(projectRootElement);
            }

            if (loadProjectRootElement == null)
            {
                if (projectRootElement == null || projectRootElementIsInvalid)
                {
                    return(null);
                }
                else
                {
                    DebugTraceCache("Satisfied from XML cache: ", projectFile);
                    return(projectRootElement);
                }
            }

            // Use openProjectRootElement to reload the element if the cache element does not exist or need to be reloaded.
            if (projectRootElement == null || projectRootElementIsInvalid)
            {
                // We do not lock loading with common _locker of the cache, to avoid lock contention.
                // Decided also not to lock this section with the key specific locker to avoid the overhead and code overcomplication, as
                // it is not likely that two threads would use Get function for the same project simultaneously and it is not a big deal if in some cases we load the same project twice.

                projectRootElement = loadProjectRootElement(projectFile, this);
                ErrorUtilities.VerifyThrowInternalNull(projectRootElement, "projectRootElement");
                ErrorUtilities.VerifyThrow(
                    projectRootElement.FullPath.Equals(projectFile, StringComparison.OrdinalIgnoreCase),
                    "Got project back with incorrect path. Expected path: {0}, received path: {1}.",
                    projectFile,
                    projectRootElement.FullPath
                    );

                // An implicit load will never reset the explicit flag.
                if (isExplicitlyLoaded)
                {
                    projectRootElement.MarkAsExplicitlyLoaded();
                }

                // Update cache element.
                // It is unlikely, but it might be that while without the lock, the projectRootElement in cache was updated by another thread.
                // And here its entry will be replaced with the loaded projectRootElement. This is fine:
                // if loaded projectRootElement is out of date (so, it changed since the time we loaded it), it will be updated the next time some thread calls Get function.
                AddEntry(projectRootElement);
            }
            else
            {
                DebugTraceCache("Satisfied from XML cache: ", projectFile);
            }


            return(projectRootElement);

#if DEBUG
        }

        finally
        {
            s_getEntriesNumber--;
        }
#endif
        }
            internal static string GetItemSpecModifier(string currentDirectory, string itemSpec, string modifier, ref CopyOnWriteDictionary <string, string> cachedModifiers)
            {
                ErrorUtilities.VerifyThrow(itemSpec != null, "Need item-spec to modify.");
                ErrorUtilities.VerifyThrow(modifier != null, "Need modifier to apply to item-spec.");
                string fullPath = null;

                if (cachedModifiers != null)
                {
                    cachedModifiers.TryGetValue(modifier, out fullPath);
                }
                if (fullPath == null)
                {
                    bool flag = true;
                    try
                    {
                        if (string.Compare(modifier, "FullPath", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            if (currentDirectory == null)
                            {
                                currentDirectory = string.Empty;
                            }
                            fullPath = FileUtilities.GetFullPath(itemSpec, currentDirectory);
                            ThrowForUrl(fullPath, itemSpec, currentDirectory);
                        }
                        else if (string.Compare(modifier, "RootDir", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            string str2;
                            if (currentDirectory == null)
                            {
                                currentDirectory = string.Empty;
                            }
                            if ((cachedModifiers == null) || !cachedModifiers.TryGetValue("FullPath", out str2))
                            {
                                str2 = FileUtilities.GetFullPath(itemSpec, currentDirectory);
                                ThrowForUrl(str2, itemSpec, currentDirectory);
                            }
                            fullPath = Path.GetPathRoot(str2);
                            if (!FileUtilities.EndsWithSlash(fullPath))
                            {
                                ErrorUtilities.VerifyThrow(FileUtilitiesRegex.UNCPattern.IsMatch(fullPath), "Only UNC shares should be missing trailing slashes.");
                                fullPath = fullPath + Path.DirectorySeparatorChar;
                            }
                        }
                        else if (string.Compare(modifier, "Filename", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            if (Path.GetDirectoryName(itemSpec) == null)
                            {
                                fullPath = string.Empty;
                            }
                            else
                            {
                                fullPath = Path.GetFileNameWithoutExtension(itemSpec);
                            }
                        }
                        else if (string.Compare(modifier, "Extension", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            if (Path.GetDirectoryName(itemSpec) == null)
                            {
                                fullPath = string.Empty;
                            }
                            else
                            {
                                fullPath = Path.GetExtension(itemSpec);
                            }
                        }
                        else if (string.Compare(modifier, "RelativeDir", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            fullPath = FileUtilities.GetDirectory(itemSpec);
                        }
                        else if (string.Compare(modifier, "Directory", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            string str3;
                            if (currentDirectory == null)
                            {
                                currentDirectory = string.Empty;
                            }
                            if ((cachedModifiers == null) || !cachedModifiers.TryGetValue("FullPath", out str3))
                            {
                                str3 = FileUtilities.GetFullPath(itemSpec, currentDirectory);
                                ThrowForUrl(str3, itemSpec, currentDirectory);
                            }
                            fullPath = FileUtilities.GetDirectory(str3);
                            Match match = FileUtilitiesRegex.DrivePattern.Match(fullPath);
                            if (!match.Success)
                            {
                                match = FileUtilitiesRegex.UNCPattern.Match(fullPath);
                            }
                            if (match.Success)
                            {
                                ErrorUtilities.VerifyThrow((fullPath.Length > match.Length) && FileUtilities.IsSlash(fullPath[match.Length]), "Root directory must have a trailing slash.");
                                fullPath = fullPath.Substring(match.Length + 1);
                            }
                        }
                        else if (string.Compare(modifier, "RecursiveDir", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            fullPath = string.Empty;
                        }
                        else if (string.Compare(modifier, "Identity", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            flag     = cachedModifiers != null;
                            fullPath = itemSpec;
                        }
                        else if (string.Compare(modifier, "ModifiedTime", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            flag = false;
                            FileInfo fileInfoNoThrow = FileUtilities.GetFileInfoNoThrow(EscapingUtilities.UnescapeAll(itemSpec));
                            if (fileInfoNoThrow != null)
                            {
                                fullPath = fileInfoNoThrow.LastWriteTime.ToString("yyyy'-'MM'-'dd HH':'mm':'ss'.'fffffff", null);
                            }
                            else
                            {
                                fullPath = string.Empty;
                            }
                        }
                        else if (string.Compare(modifier, "CreatedTime", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            flag = false;
                            string path = EscapingUtilities.UnescapeAll(itemSpec);
                            if (File.Exists(path))
                            {
                                fullPath = File.GetCreationTime(path).ToString("yyyy'-'MM'-'dd HH':'mm':'ss'.'fffffff", null);
                            }
                            else
                            {
                                fullPath = string.Empty;
                            }
                        }
                        else if (string.Compare(modifier, "AccessedTime", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            flag = false;
                            string str6 = EscapingUtilities.UnescapeAll(itemSpec);
                            if (File.Exists(str6))
                            {
                                fullPath = File.GetLastAccessTime(str6).ToString("yyyy'-'MM'-'dd HH':'mm':'ss'.'fffffff", null);
                            }
                            else
                            {
                                fullPath = string.Empty;
                            }
                        }
                        else
                        {
                            ErrorUtilities.VerifyThrow(false, "\"{0}\" is not a valid item-spec modifier.", modifier);
                        }
                    }
                    catch (Exception exception)
                    {
                        if (ExceptionHandling.NotExpectedException(exception))
                        {
                            throw;
                        }
                        ErrorUtilities.VerifyThrowInvalidOperation(false, "Shared.InvalidFilespecForTransform", modifier, itemSpec, exception.Message);
                    }
                    ErrorUtilities.VerifyThrow(fullPath != null, "The item-spec modifier \"{0}\" was not evaluated.", modifier);
                    if (flag)
                    {
                        if (cachedModifiers == null)
                        {
                            cachedModifiers = new CopyOnWriteDictionary <string, string>(StringComparer.OrdinalIgnoreCase);
                        }
                        cachedModifiers[modifier] = fullPath;
                    }
                }
                return(fullPath);
            }
 /// <summary>
 /// Constructor taking a delegate for unit test purposes only
 /// </summary>
 internal ToolsetConfigurationReader(PropertyDictionary <ProjectPropertyInstance> environmentProperties, PropertyDictionary <ProjectPropertyInstance> globalProperties, ReadApplicationConfiguration readApplicationConfiguration)
     : base(environmentProperties, globalProperties)
 {
     ErrorUtilities.VerifyThrowArgumentNull(readApplicationConfiguration, "readApplicationConfiguration");
     _readApplicationConfiguration = readApplicationConfiguration;
 }
Beispiel #12
0
 /// <summary>
 /// Add an assemblyNameExtension which represents an assembly name which was mapped to THIS assemblyName.
 /// </summary>
 internal void AddRemappedAssemblyName(AssemblyNameExtension extensionToAdd)
 {
     ErrorUtilities.VerifyThrow(extensionToAdd.Immutable, "ExtensionToAdd is not immutable");
     InitializeRemappedFrom();
     remappedFrom.Add(extensionToAdd);
 }
Beispiel #13
0
        /// <summary>
        /// Given two MSBuildArchitecture values, returns the concrete result of merging the two.  If the merge fails, the merged architecture
        /// string is returned null, and the return value of the method is false.  Otherwise, if the merge succeeds, the method returns
        /// true with the merged architecture value.  E.g.:
        /// "x86" + "x64" = null (false)
        /// "x86" + "don't care" = "x86" (true)
        /// "current architecture" + "x86" = "x86" (true) on a 32-bit process, and null (false) on a 64-bit process
        /// "current architecture" + "don't care" = "x86" (true) on a 32-bit process, and "x64" (true) on a 64-bit process
        /// A null or empty string is interpreted as "don't care".
        /// If both specify "don't care", then defaults to whatever the current process architecture is.
        /// </summary>
        internal static bool TryMergeArchitectureValues(string architectureA, string architectureB, out string mergedArchitecture)
        {
            ErrorUtilities.VerifyThrow(architectureA != String.Empty && architectureB != String.Empty, "We should never get an empty string passed to this method");

            // set up the defaults
            if (architectureA == null)
            {
                architectureA = MSBuildArchitectureValues.any;
            }

            if (architectureB == null)
            {
                architectureB = MSBuildArchitectureValues.any;
            }

            string currentArchitecture = GetCurrentMSBuildArchitecture();

            // if they're equal, then there's no problem -- just return the equivalent runtime.
            if (architectureA.Equals(architectureB, StringComparison.OrdinalIgnoreCase))
            {
                if (architectureA.Equals(MSBuildArchitectureValues.currentArchitecture, StringComparison.OrdinalIgnoreCase) ||
                    architectureA.Equals(MSBuildArchitectureValues.any, StringComparison.OrdinalIgnoreCase))
                {
                    mergedArchitecture = currentArchitecture;
                }
                else
                {
                    mergedArchitecture = architectureA;
                }

                return(true);
            }

            // if both A and B are one of CLR4, don't care, or current, then the end result will be CLR4 no matter what.
            if (
                (
                    architectureA.Equals(currentArchitecture, StringComparison.OrdinalIgnoreCase) ||
                    architectureA.Equals(MSBuildArchitectureValues.currentArchitecture, StringComparison.OrdinalIgnoreCase) ||
                    architectureA.Equals(MSBuildArchitectureValues.any, StringComparison.OrdinalIgnoreCase)
                ) &&
                (
                    architectureB.Equals(currentArchitecture, StringComparison.OrdinalIgnoreCase) ||
                    architectureB.Equals(MSBuildArchitectureValues.currentArchitecture, StringComparison.OrdinalIgnoreCase) ||
                    architectureB.Equals(MSBuildArchitectureValues.any, StringComparison.OrdinalIgnoreCase)
                )
                )
            {
                mergedArchitecture = currentArchitecture;
                return(true);
            }

            // If A doesn't care, then it's B -- and we can say B straight out, because if B were one of the
            // special cases (current runtime or don't care) then it would already have been caught in the
            // previous clause.
            if (architectureA.Equals(MSBuildArchitectureValues.any, StringComparison.OrdinalIgnoreCase))
            {
                mergedArchitecture = architectureB;
                return(true);
            }

            // And vice versa
            if (architectureB.Equals(MSBuildArchitectureValues.any, StringComparison.OrdinalIgnoreCase))
            {
                mergedArchitecture = architectureA;
                return(true);
            }

            // and now we've run out of things that it could be -- all the remaining options are non-matches.
            mergedArchitecture = null;
            return(false);
        }
Beispiel #14
0
            internal static string GetItemSpecModifier(string currentDirectory, string itemSpec, string definingProjectEscaped, string modifier, ref string fullPath)
            {
                ErrorUtilities.VerifyThrow(itemSpec != null, "Need item-spec to modify.");
                ErrorUtilities.VerifyThrow(modifier != null, "Need modifier to apply to item-spec.");

                string modifiedItemSpec = null;

                try
                {
                    if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.FullPath, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        if (fullPath != null)
                        {
                            return(fullPath);
                        }

                        if (currentDirectory == null)
                        {
                            currentDirectory = String.Empty;
                        }

                        modifiedItemSpec = GetFullPath(itemSpec, currentDirectory);
                        fullPath         = modifiedItemSpec;

                        ThrowForUrl(modifiedItemSpec, itemSpec, currentDirectory);
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.RootDir, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, ItemSpecModifiers.FullPath, ref fullPath);

                        modifiedItemSpec = Path.GetPathRoot(fullPath);

                        if (!EndsWithSlash(modifiedItemSpec))
                        {
                            ErrorUtilities.VerifyThrow(FileUtilitiesRegex.UNCPattern.IsMatch(modifiedItemSpec),
                                                       "Only UNC shares should be missing trailing slashes.");

                            // restore/append trailing slash if Path.GetPathRoot() has either removed it, or failed to add it
                            // (this happens with UNC shares)
                            modifiedItemSpec += Path.DirectorySeparatorChar;
                        }
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Filename, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // if the item-spec is a root directory, it can have no filename
                        if (Path.GetDirectoryName(itemSpec) == null)
                        {
                            // NOTE: this is to prevent Path.GetFileNameWithoutExtension() from treating server and share elements
                            // in a UNC file-spec as filenames e.g. \\server, \\server\share
                            modifiedItemSpec = String.Empty;
                        }
                        else
                        {
                            modifiedItemSpec = Path.GetFileNameWithoutExtension(itemSpec);
                        }
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Extension, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // if the item-spec is a root directory, it can have no extension
                        if (Path.GetDirectoryName(itemSpec) == null)
                        {
                            // NOTE: this is to prevent Path.GetExtension() from treating server and share elements in a UNC
                            // file-spec as filenames e.g. \\server.ext, \\server\share.ext
                            modifiedItemSpec = String.Empty;
                        }
                        else
                        {
                            modifiedItemSpec = Path.GetExtension(itemSpec);
                        }
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.RelativeDir, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        modifiedItemSpec = GetDirectory(itemSpec);
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Directory, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        GetItemSpecModifier(currentDirectory, itemSpec, definingProjectEscaped, ItemSpecModifiers.FullPath, ref fullPath);

                        modifiedItemSpec = GetDirectory(fullPath);

                        if (NativeMethodsShared.IsWindows)
                        {
                            Match root = FileUtilitiesRegex.DrivePattern.Match(modifiedItemSpec);

                            if (!root.Success)
                            {
                                root = FileUtilitiesRegex.UNCPattern.Match(modifiedItemSpec);
                            }

                            if (root.Success)
                            {
                                ErrorUtilities.VerifyThrow((modifiedItemSpec.Length > root.Length) && IsSlash(modifiedItemSpec[root.Length]),
                                                           "Root directory must have a trailing slash.");

                                modifiedItemSpec = modifiedItemSpec.Substring(root.Length + 1);
                            }
                        }
                        else
                        {
                            ErrorUtilities.VerifyThrow(!string.IsNullOrEmpty(modifiedItemSpec) && IsSlash(modifiedItemSpec[0]),
                                                       "Expected a full non-windows path rooted at '/'.");

                            // A full unix path is always rooted at
                            // `/`, and a root-relative path is the
                            // rest of the string.
                            modifiedItemSpec = modifiedItemSpec.Substring(1);
                        }
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.RecursiveDir, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // only the BuildItem class can compute this modifier -- so leave empty
                        modifiedItemSpec = String.Empty;
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.Identity, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        modifiedItemSpec = itemSpec;
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.ModifiedTime, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // About to go out to the filesystem.  This means data is leaving the engine, so need
                        // to unescape first.
                        string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);

                        FileInfo info = FileUtilities.GetFileInfoNoThrow(unescapedItemSpec);

                        if (info != null)
                        {
                            modifiedItemSpec = info.LastWriteTime.ToString(FileTimeFormat, null);
                        }
                        else
                        {
                            // File does not exist, or path is a directory
                            modifiedItemSpec = String.Empty;
                        }
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.CreatedTime, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // About to go out to the filesystem.  This means data is leaving the engine, so need
                        // to unescape first.
                        string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);

                        if (File.Exists(unescapedItemSpec))
                        {
                            modifiedItemSpec = File.GetCreationTime(unescapedItemSpec).ToString(FileTimeFormat, null);
                        }
                        else
                        {
                            // File does not exist, or path is a directory
                            modifiedItemSpec = String.Empty;
                        }
                    }
                    else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.AccessedTime, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // About to go out to the filesystem.  This means data is leaving the engine, so need
                        // to unescape first.
                        string unescapedItemSpec = EscapingUtilities.UnescapeAll(itemSpec);

                        if (File.Exists(unescapedItemSpec))
                        {
                            modifiedItemSpec = File.GetLastAccessTime(unescapedItemSpec).ToString(FileTimeFormat, null);
                        }
                        else
                        {
                            // File does not exist, or path is a directory
                            modifiedItemSpec = String.Empty;
                        }
                    }
                    else if (IsDefiningProjectModifier(modifier))
                    {
                        if (String.IsNullOrEmpty(definingProjectEscaped))
                        {
                            // We have nothing to work with, but that's sometimes OK -- so just return String.Empty
                            modifiedItemSpec = String.Empty;
                        }
                        else
                        {
                            if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectDirectory, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                // ItemSpecModifiers.Directory does not contain the root directory
                                modifiedItemSpec = Path.Combine
                                                   (
                                    GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, ItemSpecModifiers.RootDir),
                                    GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, ItemSpecModifiers.Directory)
                                                   );
                            }
                            else
                            {
                                string additionalModifier = null;

                                if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectFullPath, StringComparison.OrdinalIgnoreCase) == 0)
                                {
                                    additionalModifier = ItemSpecModifiers.FullPath;
                                }
                                else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectName, StringComparison.OrdinalIgnoreCase) == 0)
                                {
                                    additionalModifier = ItemSpecModifiers.Filename;
                                }
                                else if (String.Compare(modifier, FileUtilities.ItemSpecModifiers.DefiningProjectExtension, StringComparison.OrdinalIgnoreCase) == 0)
                                {
                                    additionalModifier = ItemSpecModifiers.Extension;
                                }
                                else
                                {
                                    ErrorUtilities.ThrowInternalError("\"{0}\" is not a valid item-spec modifier.", modifier);
                                }

                                modifiedItemSpec = GetItemSpecModifier(currentDirectory, definingProjectEscaped, null, additionalModifier);
                            }
                        }
                    }
                    else
                    {
                        ErrorUtilities.ThrowInternalError("\"{0}\" is not a valid item-spec modifier.", modifier);
                    }
                }
                catch (Exception e) when(ExceptionHandling.IsIoRelatedException(e))
                {
                    ErrorUtilities.VerifyThrowInvalidOperation(false, "Shared.InvalidFilespecForTransform", modifier, itemSpec, e.Message);
                }

                return(modifiedItemSpec);
            }
Beispiel #15
0
        /// <summary>
        /// Creates an instance of this class using the information in the given XmlException and file location.
        /// </summary>
        internal BuildEventFileInfo(string file, XmlException e) : this(e)
        {
            ErrorUtilities.VerifyThrowArgumentNull(file, nameof(file));

            _file = file;
        }
Beispiel #16
0
            /// <summary>
            /// Constructor
            /// </summary>
            internal AssemblyLoadInfoWithFile(string assemblyFile)
            {
                ErrorUtilities.VerifyThrow(Path.IsPathRooted(assemblyFile), "Assembly file path should be rooted");

                _assemblyFile = assemblyFile;
            }