Пример #1
0
        public RuntimeGraph GetRuntimeGraph(string runtimeJsonPath)
        {
            if (string.IsNullOrEmpty(runtimeJsonPath))
            {
                throw new ArgumentNullException(nameof(runtimeJsonPath));
            }
            if (!Path.IsPathRooted(runtimeJsonPath))
            {
                throw new BuildErrorException("Path not rooted: {0}", runtimeJsonPath);
            }

            string key = GetTaskObjectKey(runtimeJsonPath);

            RuntimeGraph result;
            object       existingRuntimeGraphTaskObject = _buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.AppDomain);

            if (existingRuntimeGraphTaskObject == null)
            {
                result = JsonRuntimeFormat.ReadRuntimeGraph(runtimeJsonPath);

                _buildEngine.RegisterTaskObject(key, result, RegisteredTaskObjectLifetime.AppDomain, true);
            }
            else
            {
                result = (RuntimeGraph)existingRuntimeGraphTaskObject;
            }

            return(result);
        }
Пример #2
0
        public LockFile GetLockFile(string path)
        {
            if (!Path.IsPathRooted(path))
            {
                throw new ArgumentException(
                          $"The path '{path}' specified to LockFileCache.GetLockFile is not rooted. Only full paths are supported.",
                          nameof(path));
            }

            string lockFileKey = GetTaskObjectKey(path);

            LockFile result;
            object   existingLockFileTaskObject = _buildEngine.GetRegisteredTaskObject(lockFileKey, RegisteredTaskObjectLifetime.Build);

            if (existingLockFileTaskObject == null)
            {
                result = LoadLockFile(path);

                _buildEngine.RegisterTaskObject(lockFileKey, result, RegisteredTaskObjectLifetime.Build, true);
            }
            else
            {
                result = (LockFile)existingLockFileTaskObject;
            }

            return(result);
        }
Пример #3
0
        public LockFile GetLockFile(string path)
        {
            if (!Path.IsPathRooted(path))
            {
                throw new BuildErrorException("Assets file path '{0}' is not rooted. Only full paths are supported.", path);
            }

            string lockFileKey = GetTaskObjectKey(path);

            LockFile result;
            object   existingLockFileTaskObject = _buildEngine.GetRegisteredTaskObject(lockFileKey, RegisteredTaskObjectLifetime.Build);

            if (existingLockFileTaskObject == null)
            {
                result = LoadLockFile(path);

                _buildEngine.RegisterTaskObject(lockFileKey, result, RegisteredTaskObjectLifetime.Build, true);
            }
            else
            {
                result = (LockFile)existingLockFileTaskObject;
            }

            return(result);
        }
Пример #4
0
        public LockFile GetLockFile(string path)
        {
            if (!Path.IsPathRooted(path))
            {
                throw new BuildErrorException(Strings.AssetsFilePathNotRooted, path);
            }

            string lockFileKey = GetTaskObjectKey(path);

            LockFile result;
            object   existingLockFileTaskObject = _buildEngine.GetRegisteredTaskObject(lockFileKey, RegisteredTaskObjectLifetime.Build);

            if (existingLockFileTaskObject == null)
            {
                result = LoadLockFile(path);

                _buildEngine.RegisterTaskObject(lockFileKey, result, RegisteredTaskObjectLifetime.Build, true);
            }
            else
            {
                result = (LockFile)existingLockFileTaskObject;
            }

            return(result);
        }
Пример #5
0
        public static Aapt2Daemon GetInstance(IBuildEngine4 engine, string aapt2, int numberOfInstances, int initalNumberOfDaemons, bool registerInDomain = false)
        {
            var         area   = registerInDomain ? RegisteredTaskObjectLifetime.AppDomain : RegisteredTaskObjectLifetime.Build;
            Aapt2Daemon daemon = (Aapt2Daemon)engine.GetRegisteredTaskObject(typeof(Aapt2Daemon).FullName, area);

            if (daemon == null)
            {
                daemon = new Aapt2Daemon(aapt2, numberOfInstances, initalNumberOfDaemons);
                engine.RegisterTaskObject(typeof(Aapt2Daemon).FullName, daemon, area, allowEarlyCollection: false);
            }
            return(daemon);
        }
 public static bool SaveCustomViewMapFile(IBuildEngine4 engine, string mapFile, Dictionary <string, HashSet <string> > map)
 {
     engine?.RegisterTaskObject(mapFile, map, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
     using (var writer = MemoryStreamPool.Shared.CreateStreamWriter()) {
         foreach (var i in map.OrderBy(x => x.Key))
         {
             foreach (var v in i.Value.OrderBy(x => x))
             {
                 writer.WriteLine($"{i.Key};{v}");
             }
         }
         writer.Flush();
         return(CopyIfStreamChanged(writer.BaseStream, mapFile));
     }
 }
Пример #7
0
        /// <summary>
        /// Gets the registered task object.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="buildEngine">The build engine.</param>
        /// <param name="key">The key.</param>
        /// <param name="ctor">The ctor.</param>
        /// <param name="lifetime">The lifetime.</param>
        /// <returns></returns>
        public static TValue GetRegisteredTaskObject <TValue>(this IBuildEngine4 buildEngine, string key, Func <TValue> ctor, RegisteredTaskObjectLifetime lifetime = RegisteredTaskObjectLifetime.Build)
        {
            // when run as app, we don't have a filled Task
            if (buildEngine == null)
            {
                return(ctor());
            }

            // otherwise, this works
            var o = buildEngine.GetRegisteredTaskObject(key, lifetime);

            if (o == null)
            {
                o = ctor();
                buildEngine.RegisterTaskObject(key, o, lifetime, false);
            }
            return((TValue)o);
        }
Пример #8
0
        public static void SaveCustomViewMapFile(IBuildEngine4 engine, string mapFile, Dictionary <string, HashSet <string> > map)
        {
            engine?.RegisterTaskObject(mapFile, map, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
            var temp = Path.GetTempFileName();

            try {
                using (var m = new StreamWriter(temp)) {
                    foreach (var i in map.OrderBy(x => x.Key))
                    {
                        foreach (var v in i.Value.OrderBy(x => x))
                        {
                            m.WriteLine($"{i.Key};{v}");
                        }
                    }
                }
                CopyIfChanged(temp, mapFile);
            } finally {
                File.Delete(temp);
            }
        }
Пример #9
0
        public IEnumerable <ConflictItem> GetConflictItems(string frameworkListPath, Logger log)
        {
            if (frameworkListPath == null)
            {
                throw new ArgumentNullException(nameof(frameworkListPath));
            }

            if (!Path.IsPathRooted(frameworkListPath))
            {
                throw new BuildErrorException(Strings.FrameworkListPathNotRooted, frameworkListPath);
            }


            //  Need to include assembly name in the key here, since both Microsoft.NET.Build.Tasks and Microsoft.NET.Build.Extensions.Tasks share this code,
            //  but can't share the types of the ConflictItem objects.
            string assemblyName = typeof(FrameworkListReader).GetTypeInfo().Assembly.FullName;

            string objectKey = $"{assemblyName}:{nameof(FrameworkListReader)}:{frameworkListPath}";

            IEnumerable <ConflictItem> result;

            object existingConflictItems = _buildEngine.GetRegisteredTaskObject(objectKey, RegisteredTaskObjectLifetime.AppDomain);

            if (existingConflictItems == null)
            {
                result = LoadConflictItems(frameworkListPath, log);

                _buildEngine.RegisterTaskObject(objectKey, result, RegisteredTaskObjectLifetime.AppDomain, true);
            }
            else
            {
                result = (IEnumerable <ConflictItem>)existingConflictItems;
            }

            return(result);
        }
Пример #10
0
        private void LazyInitialize()
        {
            if (_isInitialized)
            {
                return;
            }

            _isInitialized = true;

            // Crack the search path just one time.
            Match match = s_crackAssemblyFoldersExSentinel.Value.Match(this.searchPathElement);

            _wasMatch = false;

            if (match.Success)
            {
                _registryKeyRoot      = match.Groups["REGISTRYKEYROOT"].Value.Trim();
                _targetRuntimeVersion = match.Groups["TARGETRUNTIMEVERSION"].Value.Trim();
                _registryKeySuffix    = match.Groups["REGISTRYKEYSUFFIX"].Value.Trim();
                _osVersion            = null;
                _platform             = null;
                Group conditions = match.Groups["CONDITIONS"];

                // Disregard if there are any empty values in the {Registry} tag.
                if (_registryKeyRoot.Length != 0 && _targetRuntimeVersion.Length != 0 && _registryKeySuffix.Length != 0)
                {
                    // Tolerate version keys that don't begin with "v" as these could come from user input
                    if (!_targetRuntimeVersion.StartsWith("v", StringComparison.OrdinalIgnoreCase))
                    {
                        _targetRuntimeVersion = _targetRuntimeVersion.Insert(0, "v");
                    }

                    if (conditions?.Value != null && conditions.Length > 0 && conditions.Value.Length > 0)
                    {
                        string value = conditions.Value.Trim();

                        // Parse the condition statement for OSVersion and Platform
                        foreach (string c in value.Split(MSBuildConstants.ColonChar))
                        {
                            if (String.Compare(c, 0, "OSVERSION=", 0, 10, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                _osVersion = c.Substring(10);
                            }
                            else if (String.Compare(c, 0, "PLATFORM=", 0, 9, StringComparison.OrdinalIgnoreCase) == 0)
                            {
                                _platform = c.Substring(9);
                            }
                        }
                    }
                    _wasMatch = true;

                    bool   useCache = Environment.GetEnvironmentVariable("MSBUILDDISABLEASSEMBLYFOLDERSEXCACHE") == null;
                    string key      = "ca22615d-aa83-444b-80b9-b32f3d5db097" + this.searchPathElement;
                    if (useCache && _buildEngine != null)
                    {
                        _assemblyFoldersCache = _buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.Build) as AssemblyFoldersExCache;
                    }

                    if (_assemblyFoldersCache == null)
                    {
                        AssemblyFoldersEx assemblyFolders = new AssemblyFoldersEx(_registryKeyRoot, _targetRuntimeVersion, _registryKeySuffix, _osVersion, _platform, _getRegistrySubKeyNames, _getRegistrySubKeyDefaultValue, this.targetProcessorArchitecture, _openBaseKey);
                        _assemblyFoldersCache = new AssemblyFoldersExCache(assemblyFolders, fileExists);
                        if (useCache)
                        {
                            _buildEngine?.RegisterTaskObject(key, _assemblyFoldersCache, RegisteredTaskObjectLifetime.Build, true /* dispose early ok*/);
                        }
                    }

                    fileExists = _assemblyFoldersCache.FileExists;
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Given a strong name, find its path in the GAC.
        /// </summary>
        /// <param name="strongName">The strong name.</param>
        /// <param name="targetProcessorArchitecture">Like x86 or IA64\AMD64.</param>
        /// <param name="getRuntimeVersion">Delegate to get the runtime version from a file path</param>
        /// <param name="targetedRuntimeVersion">What version of the runtime are we targeting</param>
        /// <param name="fullFusionName">Are we guranteed to have a full fusion name. This really can only happen if we have already resolved the assembly</param>
        /// <returns>The path to the assembly. Empty if none exists.</returns>
        internal static string GetLocation
        (
            IBuildEngine4 buildEngine,
            AssemblyNameExtension strongName,
            ProcessorArchitecture targetProcessorArchitecture,
            GetAssemblyRuntimeVersion getRuntimeVersion,
            Version targetedRuntimeVersion,
            bool fullFusionName,
            FileExists fileExists,
            GetPathFromFusionName getPathFromFusionName,
            GetGacEnumerator getGacEnumerator,
            bool specificVersion
        )
        {
            ConcurrentDictionary <AssemblyNameExtension, string> fusionNameToResolvedPath = null;
            bool useGacRarCache = Environment.GetEnvironmentVariable("MSBUILDDISABLEGACRARCACHE") == null;

            if (buildEngine != null && useGacRarCache)
            {
                string key = "44d78b60-3bbe-48fe-9493-04119ebf515f" + "|" + targetProcessorArchitecture.ToString() + "|" + targetedRuntimeVersion.ToString() + "|" + fullFusionName.ToString() + "|" + specificVersion.ToString();
                fusionNameToResolvedPath = buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.Build) as ConcurrentDictionary <AssemblyNameExtension, string>;
                if (fusionNameToResolvedPath == null)
                {
                    fusionNameToResolvedPath = new ConcurrentDictionary <AssemblyNameExtension, string>(AssemblyNameComparer.GenericComparer);
                    buildEngine.RegisterTaskObject(key, fusionNameToResolvedPath, RegisteredTaskObjectLifetime.Build, true /* dispose early ok*/);
                }
                else
                {
                    if (fusionNameToResolvedPath.ContainsKey(strongName))
                    {
                        string fusionName = null;
                        fusionNameToResolvedPath.TryGetValue(strongName, out fusionName);
                        return(fusionName);
                    }
                }
            }

            // Optimize out the case where the public key token is null, if it is null it is not a strongly named assembly and CANNOT be in the gac.
            // also passing it would cause the gac enumeration method to throw an exception indicating the assembly is not a strongnamed assembly.

            string location = null;

            // If the publickeyToken is null and the publickeytoken is in the fusion name then this means we are passing in a null or empty PublicKeyToken and then this cannot possibly be in the gac.
            if ((strongName.GetPublicKeyToken() == null || strongName.GetPublicKeyToken().Length == 0) && strongName.FullName.IndexOf("PublicKeyToken", StringComparison.OrdinalIgnoreCase) != -1)
            {
                if (fusionNameToResolvedPath != null)
                {
                    fusionNameToResolvedPath.TryAdd(strongName, location);
                }

                return(location);
            }

            // A delegate was not passed in to use the default one
            getPathFromFusionName = getPathFromFusionName ?? pathFromFusionName;

            // A delegate was not passed in to use the default one
            getGacEnumerator = getGacEnumerator ?? gacEnumerator;

            // If we have no processor architecture set then we can tryout a number of processor architectures.
            if (!strongName.HasProcessorArchitectureInFusionName)
            {
                if (targetProcessorArchitecture != ProcessorArchitecture.MSIL && targetProcessorArchitecture != ProcessorArchitecture.None)
                {
                    string processorArchitecture = ResolveAssemblyReference.ProcessorArchitectureToString(targetProcessorArchitecture);
                    // Try processor specific first.
                    if (fullFusionName)
                    {
                        location = CheckForFullFusionNameInGac(strongName, processorArchitecture, getPathFromFusionName);
                    }
                    else
                    {
                        location = GetLocationImpl(strongName, processorArchitecture, getRuntimeVersion, targetedRuntimeVersion, fileExists, getPathFromFusionName, getGacEnumerator, specificVersion);
                    }

                    if (location != null && location.Length > 0)
                    {
                        if (fusionNameToResolvedPath != null)
                        {
                            fusionNameToResolvedPath.TryAdd(strongName, location);
                        }
                        return(location);
                    }
                }

                // Next, try MSIL
                if (fullFusionName)
                {
                    location = CheckForFullFusionNameInGac(strongName, "MSIL", getPathFromFusionName);
                }
                else
                {
                    location = GetLocationImpl(strongName, "MSIL", getRuntimeVersion, targetedRuntimeVersion, fileExists, getPathFromFusionName, getGacEnumerator, specificVersion);
                }
                if (location != null && location.Length > 0)
                {
                    if (fusionNameToResolvedPath != null)
                    {
                        fusionNameToResolvedPath.TryAdd(strongName, location);
                    }
                    return(location);
                }
            }

            // Next, try no processor architecure
            if (fullFusionName)
            {
                location = CheckForFullFusionNameInGac(strongName, null, getPathFromFusionName);
            }
            else
            {
                location = GetLocationImpl(strongName, null, getRuntimeVersion, targetedRuntimeVersion, fileExists, getPathFromFusionName, getGacEnumerator, specificVersion);
            }

            if (location != null && location.Length > 0)
            {
                if (fusionNameToResolvedPath != null)
                {
                    fusionNameToResolvedPath.TryAdd(strongName, location);
                }
                return(location);
            }

            if (fusionNameToResolvedPath != null)
            {
                fusionNameToResolvedPath.TryAdd(strongName, null);
            }

            return(null);
        }
 public static void SaveResourceCaseMap(IBuildEngine4 engine, Dictionary <string, string> map) =>
 engine.RegisterTaskObject(ResourceCaseMapKey, map, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
Пример #13
0
        /// <summary>
        /// Given a strong name, find its path in the GAC.
        /// </summary>
        /// <param name="strongName">The strong name.</param>
        /// <param name="targetProcessorArchitecture">Like x86 or IA64\AMD64.</param>
        /// <param name="getRuntimeVersion">Delegate to get the runtime version from a file path</param>
        /// <param name="targetedRuntimeVersion">What version of the runtime are we targeting</param>
        /// <param name="fullFusionName">Are we guranteed to have a full fusion name. This really can only happen if we have already resolved the assembly</param>
        /// <returns>The path to the assembly. Empty if none exists.</returns>
        internal static string GetLocation
        (
            IBuildEngine4 buildEngine,
            AssemblyNameExtension strongName,
            ProcessorArchitecture targetProcessorArchitecture,
            GetAssemblyRuntimeVersion getRuntimeVersion,
            Version targetedRuntimeVersion,
            bool fullFusionName,
            FileExists fileExists,
            GetPathFromFusionName getPathFromFusionName,
            GetGacEnumerator getGacEnumerator,
            bool specificVersion
        )
        {
            ConcurrentDictionary<AssemblyNameExtension, string> fusionNameToResolvedPath = null;
            bool useGacRarCache = Environment.GetEnvironmentVariable("MSBUILDDISABLEGACRARCACHE") == null;
            if (buildEngine != null && useGacRarCache)
            {
                string key = "44d78b60-3bbe-48fe-9493-04119ebf515f" + "|" + targetProcessorArchitecture.ToString() + "|" + targetedRuntimeVersion.ToString() + "|" + fullFusionName.ToString() + "|" + specificVersion.ToString();
                fusionNameToResolvedPath = buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.Build) as ConcurrentDictionary<AssemblyNameExtension, string>;
                if (fusionNameToResolvedPath == null)
                {
                    fusionNameToResolvedPath = new ConcurrentDictionary<AssemblyNameExtension, string>(AssemblyNameComparer.GenericComparer);
                    buildEngine.RegisterTaskObject(key, fusionNameToResolvedPath, RegisteredTaskObjectLifetime.Build, true /* dispose early ok*/);
                }
                else
                {
                    if (fusionNameToResolvedPath.ContainsKey(strongName))
                    {
                        string fusionName = null;
                        fusionNameToResolvedPath.TryGetValue(strongName, out fusionName);
                        return fusionName;
                    }
                }
            }

            // Optimize out the case where the public key token is null, if it is null it is not a strongly named assembly and CANNOT be in the gac.
            // also passing it would cause the gac enumeration method to throw an exception indicating the assembly is not a strongnamed assembly.

            string location = null;

            // If the publickeyToken is null and the publickeytoken is in the fusion name then this means we are passing in a null or empty PublicKeyToken and then this cannot possibly be in the gac.
            if ((strongName.GetPublicKeyToken() == null || strongName.GetPublicKeyToken().Length == 0) && strongName.FullName.IndexOf("PublicKeyToken", StringComparison.OrdinalIgnoreCase) != -1)
            {
                if (fusionNameToResolvedPath != null)
                {
                    fusionNameToResolvedPath.TryAdd(strongName, location);
                }

                return location;
            }

            // A delegate was not passed in to use the default one
            getPathFromFusionName = getPathFromFusionName ?? pathFromFusionName;

            // A delegate was not passed in to use the default one
            getGacEnumerator = getGacEnumerator ?? gacEnumerator;

            // If we have no processor architecture set then we can tryout a number of processor architectures.
            if (!strongName.HasProcessorArchitectureInFusionName)
            {
                if (targetProcessorArchitecture != ProcessorArchitecture.MSIL && targetProcessorArchitecture != ProcessorArchitecture.None)
                {
                    string processorArchitecture = ResolveAssemblyReference.ProcessorArchitectureToString(targetProcessorArchitecture);
                    // Try processor specific first.
                    if (fullFusionName)
                    {
                        location = CheckForFullFusionNameInGac(strongName, processorArchitecture, getPathFromFusionName);
                    }
                    else
                    {
                        location = GetLocationImpl(strongName, processorArchitecture, getRuntimeVersion, targetedRuntimeVersion, fileExists, getPathFromFusionName, getGacEnumerator, specificVersion);
                    }

                    if (location != null && location.Length > 0)
                    {
                        if (fusionNameToResolvedPath != null)
                        {
                            fusionNameToResolvedPath.TryAdd(strongName, location);
                        }
                        return location;
                    }
                }

                // Next, try MSIL
                if (fullFusionName)
                {
                    location = CheckForFullFusionNameInGac(strongName, "MSIL", getPathFromFusionName);
                }
                else
                {
                    location = GetLocationImpl(strongName, "MSIL", getRuntimeVersion, targetedRuntimeVersion, fileExists, getPathFromFusionName, getGacEnumerator, specificVersion);
                }
                if (location != null && location.Length > 0)
                {
                    if (fusionNameToResolvedPath != null)
                    {
                        fusionNameToResolvedPath.TryAdd(strongName, location);
                    }
                    return location;
                }
            }

            // Next, try no processor architecure
            if (fullFusionName)
            {
                location = CheckForFullFusionNameInGac(strongName, null, getPathFromFusionName);
            }
            else
            {
                location = GetLocationImpl(strongName, null, getRuntimeVersion, targetedRuntimeVersion, fileExists, getPathFromFusionName, getGacEnumerator, specificVersion);
            }

            if (location != null && location.Length > 0)
            {
                if (fusionNameToResolvedPath != null)
                {
                    fusionNameToResolvedPath.TryAdd(strongName, location);
                }
                return location;
            }

            if (fusionNameToResolvedPath != null)
            {
                fusionNameToResolvedPath.TryAdd(strongName, null);
            }

            return null;
        }
Пример #14
0
        public IReadOnlyList <SolutionInfo> Create(IEnumerable <ITaskItem> solutionItems, IDictionary <string, string> properties, string defaultConfig, CancellationToken ct)
        {
            var timer = Stopwatch.StartNew();

            var solutions = new ConcurrentBag <SolutionInfo>();

            Parallel.ForEach(solutionItems, solution =>
            {
                if (ct.IsCancellationRequested)
                {
                    return;
                }

                var solutionFile  = solution.ItemSpec.Replace('\\', '/');
                var solutionProps = new Dictionary <string, string>(properties, StringComparer.OrdinalIgnoreCase);
                foreach (var prop in MSBuildListSplitter.GetNamedProperties(solution.GetMetadata("AdditionalProperties")))
                {
                    solutionProps[prop.Key] = prop.Value;
                }

                if (!solutionProps.TryGetValue("Configuration", out var configName))
                {
                    solutionProps["Configuration"] = configName = defaultConfig;
                }

                var key = $"SlnInfo:{solutionFile}:{configName}";
                var obj = _buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.Build);

                if (obj is SolutionInfo cachedSlnInfo)
                {
                    solutions.Add(cachedSlnInfo);
                    return;
                }

                _logger.LogMessage($"Analyzing {solutionFile} ({configName})");
                var projects     = new ConcurrentBag <ProjectInfo>();
                var projectFiles = GetProjectsForSolutionConfig(solutionFile, configName);
                using (var projCollection = new ProjectCollection(solutionProps)
                {
                    IsBuildEnabled = false
                })
                {
                    Parallel.ForEach(projectFiles, projectFile =>
                    {
                        if (ct.IsCancellationRequested)
                        {
                            return;
                        }

                        try
                        {
                            projects.Add(new ProjectInfoFactory(_logger).Create(projectFile, projCollection));
                        }
                        catch (Exception ex)
                        {
                            _logger.LogErrorFromException(ex);
                        }
                    });
                }

                bool.TryParse(solution.GetMetadata("Build"), out var shouldBuild);
                bool.TryParse(solution.GetMetadata("IsPatching"), out var isPatching);

                var solutionInfo = new SolutionInfo(
                    solutionFile,
                    configName,
                    projects.ToArray(),
                    shouldBuild,
                    isPatching);

                _buildEngine.RegisterTaskObject(key, solutionInfo, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: true);

                solutions.Add(solutionInfo);
            });

            timer.Stop();
            _logger.LogMessage(MessageImportance.High, $"Finished design-time build in {timer.ElapsedMilliseconds}ms");
            return(solutions.ToArray());
        }
        /// <summary>
        /// Get the SDK.
        /// </summary>
        /// <returns>true</returns>
        public override bool Execute()
        {
            // TargetPlatformVersion and TargetPlatformIdentifier are requried to correctly look for SDKs.
            if (String.IsNullOrEmpty(TargetPlatformVersion) || String.IsNullOrEmpty(TargetPlatformIdentifier))
            {
                Log.LogErrorWithCodeFromResources("GetInstalledSDKs.TargetPlatformInformationMissing");
                return(false);
            }

            // Dictionary of ESDKs. Each entry is a (location, platform version) tuple
            IDictionary <string, Tuple <string, string> > installedSDKs = null;

            try
            {
                Log.LogMessageFromResources("GetInstalledSDKs.SearchingForSDKs", _targetPlatformIdentifier, _targetPlatformVersion);

                Version platformVersion = Version.Parse(TargetPlatformVersion);
                installedSDKs = ToolLocationHelper.GetPlatformExtensionSDKLocationsAndVersions(SDKDirectoryRoots, SDKExtensionDirectoryRoots, SDKRegistryRoot, TargetPlatformIdentifier, platformVersion);
            }
            catch (Exception e)
            {
                if (ExceptionHandling.IsCriticalException(e))
                {
                    throw;
                }

                Log.LogErrorWithCodeFromResources("GetInstalledSDKs.CouldNotGetSDKList", e.Message);
            }

            List <ITaskItem> outputItems = new List <ITaskItem>();

            if (installedSDKs != null && installedSDKs.Count > 0)
            {
                Log.LogMessageFromResources(MessageImportance.Low, "GetInstalledSDKs.FoundSDKs", installedSDKs.Count);
                Log.LogMessageFromResources(MessageImportance.Low, "GetInstalledSDKs.ListInstalledSDKs");

                foreach (KeyValuePair <string, Tuple <string, string> > sdk in installedSDKs)
                {
                    string sdkInfo = ResourceUtilities.FormatResourceString("GetInstalledSDKs.SDKNameAndLocation", sdk.Key, sdk.Value.Item1);
                    Log.LogMessageFromResources(MessageImportance.Low, "ResolveAssemblyReference.FourSpaceIndent", sdkInfo);

                    TaskItem item = new TaskItem(sdk.Value.Item1);
                    item.SetMetadata("SDKName", sdk.Key);
                    item.SetMetadata("PlatformVersion", sdk.Value.Item2);

                    // Need to stash these so we can unroll the platform via GetMatchingPlatformSDK when we get the reference files for the sdks
                    item.SetMetadata(DirectoryRootsMetadataName, String.Join(";", SDKDirectoryRoots ?? new string[0]));
                    item.SetMetadata(ExtensionDirectoryRootsMetadataName, String.Join(";", SDKExtensionDirectoryRoots ?? new string[0]));
                    item.SetMetadata(RegistryRootMetadataName, SDKRegistryRoot);

                    outputItems.Add(item);
                }
            }
            else
            {
                Log.LogWarningWithCodeFromResources("GetInstalledSDKs.NoSDksFound");
            }

            InstalledSDKs = outputItems.ToArray();

            // We need to register an object so that at the end of the build we will clear the static toolLocationhelper caches.
            // this is important because if someone adds an SDK between builds we would not know about it and not be able to use it.
            // This code is mainly used to deal with the case where msbuild nodes hang around between builds.
            IBuildEngine4 buildEngine4 = BuildEngine as IBuildEngine4;

            if (buildEngine4 != null)
            {
                object staticCacheDisposer = buildEngine4.GetRegisteredTaskObject(StaticSDKCacheKey, RegisteredTaskObjectLifetime.Build);
                if (staticCacheDisposer == null)
                {
                    BuildCacheDisposeWrapper staticDisposer = new BuildCacheDisposeWrapper(new BuildCacheDisposeWrapper.CallDuringDispose(ToolLocationHelper.ClearSDKStaticCache));
                    buildEngine4.RegisterTaskObject(StaticSDKCacheKey, staticDisposer, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
                }
            }

            return(!Log.HasLoggedErrors);
        }
        /// <summary>
        /// Initialize this class if it hasn't been initialized yet.
        /// </summary>
        private void LazyInitialize()
        {
            if (_isInitialized)
            {
                return;
            }

            _isInitialized = true;

            // Crack the search path just one time.
            Match match = s_crackAssemblyFoldersFromConfigSentinel.Value.Match(this.searchPathElement);

            _wasMatch = false;

            if (match.Success)
            {
                _targetRuntimeVersion     = match.Groups["TARGETRUNTIMEVERSION"].Value.Trim();
                _assemblyFolderConfigFile = match.Groups["ASSEMBLYFOLDERCONFIGFILE"].Value.Trim();

                if (_targetRuntimeVersion.Length != 0)
                {
                    // Tolerate version keys that don't begin with "v" as these could come from user input
                    if (!_targetRuntimeVersion.StartsWith("v", StringComparison.OrdinalIgnoreCase))
                    {
                        _targetRuntimeVersion = _targetRuntimeVersion.Insert(0, "v");
                    }

                    _wasMatch = true;

                    bool   useCache = Environment.GetEnvironmentVariable("MSBUILDDISABLEASSEMBLYFOLDERSEXCACHE") == null;
                    string key      = "6f7de854-47fe-4ae2-9cfe-9b33682abd91" + searchPathElement;

                    if (useCache && _buildEngine != null)
                    {
                        _assemblyFoldersCache = _buildEngine.GetRegisteredTaskObject(key, RegisteredTaskObjectLifetime.Build) as AssemblyFoldersFromConfigCache;
                    }

                    if (_assemblyFoldersCache == null)
                    {
                        // This should never happen. Microsoft.Common.CurrentVersion.targets will not specify a AssemblyFoldersFromConfig search path
                        // if the specified (or default) file is not found.
                        ErrorUtilities.VerifyThrow(File.Exists(_assemblyFolderConfigFile),
                                                   $"The AssemblyFolders config file specified does not exist: {_assemblyFolderConfigFile}");

                        try
                        {
                            AssemblyFoldersFromConfig assemblyFolders = new AssemblyFoldersFromConfig(_assemblyFolderConfigFile, _targetRuntimeVersion, targetProcessorArchitecture);
                            _assemblyFoldersCache = new AssemblyFoldersFromConfigCache(assemblyFolders, fileExists);
                            if (useCache)
                            {
                                _buildEngine?.RegisterTaskObject(key, _assemblyFoldersCache, RegisteredTaskObjectLifetime.Build, true /* dispose early ok*/);
                            }
                        }
                        catch (SerializationException e)
                        {
                            _taskLogger.LogError(ResourceUtilities.GetResourceString("ResolveAssemblyReference.AssemblyFoldersConfigFileMalformed"), _assemblyFolderConfigFile, e.Message);
                            return;
                        }
                    }

                    fileExists = _assemblyFoldersCache.FileExists;
                }
            }
        }