public void Generate(string outputPath, string propertyVersionNamePrefix, string propertyPathNamePrefix, PackageRestoreData restoreData)
        {
            // Delete an existing file in case there are no properties generated and we don't end up saving the file
            //
            if (File.Exists(outputPath))
            {
                Retry(() => File.Delete(outputPath), TimeSpan.FromMilliseconds(500));
            }

            ProjectRootElement          project       = ProjectRootElement.Create();
            ProjectPropertyGroupElement propertyGroup = project.AddPropertyGroup();

            propertyGroup.SetProperty("MSBuildAllProjects", "$(MSBuildAllProjects);$(MSBuildThisFileFullPath)");

            ProjectItemGroupElement itemGroup = project.AddItemGroup();

            bool anyPropertiesCreated = false;

            foreach (string packageConfigPath in _packageConfigPaths)
            {
                _logger.LogMessage(MessageImportance.Low, $"Parsing '{packageConfigPath}'");

                IEnumerable <PackageIdentityWithPath> parsedPackages = null;

                INuGetPackageConfigParser configParser = null;

                // A bug in nuget sometimes causes "NuGet.Configuration.NuGetConfigurationException: Unexpected failure reading NuGet.Config." when multiple instances are running in parrallel such as in the quickbuild scenario.
                Retry(() => configParser = _configParsersLazy.Value.FirstOrDefault(i => i.TryGetPackages(packageConfigPath, restoreData, out parsedPackages)), TimeSpan.FromMilliseconds(1000));

                if (configParser != null && parsedPackages != null)
                {
                    anyPropertiesCreated = true;

                    foreach (PackageIdentityWithPath packageInfo in parsedPackages)
                    {
                        propertyGroup.SetProperty($"{propertyPathNamePrefix}{packageInfo.Id.Replace(".", "_")}", $"{packageInfo.FullPath}");

                        propertyGroup.SetProperty($"{propertyVersionNamePrefix}{packageInfo.Id.Replace(".", "_")}", $"{packageInfo.Version.ToString()}");

                        // Consider adding item metadata of packageid and version for ease of consumption of this property.
                        itemGroup.AddItem("CBTNuGetPackageDir", packageInfo.FullPath);
                    }
                }
            }

            // Don't save the file if no properties were created.  In Visual Studio design time builds, this can be called multiple times until there are finally
            // properties that can be created.  If we generate an empty file, it won't get regenerated once there are properties to create.
            //
            if (anyPropertiesCreated)
            {
                Retry(() => project.Save(outputPath), TimeSpan.FromMilliseconds(500));
            }
        }
Example #2
0
        public override bool TryGetPackages(string packageConfigPath, PackageRestoreData packageRestoreData, out IEnumerable <PackageIdentityWithPath> packages)
        {
            packages = null;


            // NuGet sets the project restore style to "Unknown" if its not PackageReference or ProjectJson
            //
            if (String.Equals("Unknown", packageRestoreData?.RestoreProjectStyle))
            {
                // Attempt to check if there's a packages.config next to the project
                //
                packageConfigPath = Path.Combine(Path.GetDirectoryName(packageConfigPath), PackageConfigFilename);

                if (!File.Exists(packageConfigPath))
                {
                    return(false);
                }
            }

            if (!IsPackagesConfigFile(packageConfigPath))
            {
                return(false);
            }

            string repositoryPath = SettingsUtility.GetRepositoryPath(NuGetSettings);

            if (String.IsNullOrWhiteSpace(repositoryPath))
            {
                throw new NuGetConfigurationException("Unable to determine the NuGet repository path.  Ensure that you are you specifying a path in your NuGet.config (https://docs.microsoft.com/en-us/nuget/schema/nuget-config-file#config-section).");
            }

            repositoryPath = Path.GetFullPath(repositoryPath);

            if (!Directory.Exists(repositoryPath))
            {
                throw new DirectoryNotFoundException($"The NuGet repository '{repositoryPath}' does not exist.  Ensure that NuGet is restore packages to the location specified in your NuGet.config.");
            }

            Log.LogMessage(MessageImportance.Low, $"Using repository path: '{repositoryPath}'");

            PackagePathResolver packagePathResolver = new PackagePathResolver(repositoryPath);

            XDocument document = XDocument.Load(packageConfigPath);

            PackagesConfigReader packagesConfigReader = new PackagesConfigReader(document);

            packages = packagesConfigReader.GetPackages(allowDuplicatePackageIds: true).Select(i =>
            {
                string installPath = packagePathResolver.GetInstallPath(i.PackageIdentity);

                if (!String.IsNullOrWhiteSpace(installPath))
                {
                    installPath = Path.GetFullPath(installPath);
                }
                else
                {
                    Log.LogWarning($"The package '{i.PackageIdentity.Id}' was not found in the repository.");
                }

                return(new PackageIdentityWithPath(i.PackageIdentity, installPath));
            }).Where(i => !String.IsNullOrWhiteSpace(i.FullPath));

            return(true);
        }
Example #3
0
        public override bool TryGetPackages(string packageConfigPath, PackageRestoreData packageRestoreData, out IEnumerable <PackageIdentityWithPath> packages)
        {
            packages = null;

            // This parser cannot do anything for packages.config or project.json
            //
            if (NuGetPackagesConfigParser.IsPackagesConfigFile(packageConfigPath) || ProjectJsonPathUtilities.IsProjectConfig(packageConfigPath))
            {
                return(false);
            }

            // This parser requires that the restore info file was created
            //
            if (packageRestoreData == null)
            {
                Log.LogMessage("Missing expected assets file directory.  This is typically because the flag generated at $(CBTModuleNuGetAssetsFlagFile) does not exist or is empty.  Ensure the GenerateModuleAssetFlagFile target is running. It may also be because the CBTModules.proj does not import CBT build.props in some fashion.");
                return(false);
            }

            if (!String.Equals("PackageReference", packageRestoreData.RestoreProjectStyle, StringComparison.OrdinalIgnoreCase))
            {
                return(false);
            }

            string lockFilePath = Path.Combine(packageRestoreData.RestoreOutputAbsolutePath, LockFileFormat.AssetsFileName);

            if (!File.Exists(lockFilePath))
            {
                throw new FileNotFoundException($"Missing expected NuGet assets file '{lockFilePath}'.  If you are redefining BaseIntermediateOutputPath ensure it is unique per project. ");
            }

            HashSet <string> processedPackages = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            LockFile lockFile = LockFileUtilities.GetLockFile(lockFilePath, NullLogger.Instance);

            string globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(NuGetSettings);

            if (String.IsNullOrWhiteSpace(globalPackagesFolder))
            {
                throw new NuGetConfigurationException(@"Unable to determine the NuGet repository path.  This usually defaults to ""%UserProfile%\.nuget\packages"", ""%NUGET_PACKAGES%"", or the ""globalPackagesFolder"" in your NuGet.config.");
            }

            globalPackagesFolder = Path.GetFullPath(globalPackagesFolder);

            if (!Directory.Exists(globalPackagesFolder))
            {
                throw new DirectoryNotFoundException($"The NuGet repository '{globalPackagesFolder}' does not exist.  Ensure that NuGet restored packages to the location specified in your NuGet.config.");
            }

            Log.LogMessage(MessageImportance.Low, $"Using repository path: '{globalPackagesFolder}'");

            VersionFolderPathResolver versionFolderPathResolver = new VersionFolderPathResolver(globalPackagesFolder);

            packages = new List <PackageIdentityWithPath>();

            foreach (RestorePackage package in packageRestoreData.PackageImportOrder)
            {
                // In <PackageReference only one version of a nuGet package will be installed.  That version may not be the one specified in the <PackageReference item.  So we can not match the version specified in the CBTModules.proj with the version actually installed.  If we want to do any such matching it would simply need to result in a build error.
                IEnumerable <PackageDependency> dependencies = lockFile.Targets.First().Libraries.Where(lib => lib.Name.Equals(package.Id, StringComparison.OrdinalIgnoreCase)).Select(lib => lib.Dependencies).SelectMany(p => p.Select(i => i));

                foreach (PackageDependency dependency in dependencies)
                {
                    // In the <PackageReference scenario nuGet will only install one packageId.  If you have two packages that reference different package versions of a third package then it will choose the common highest version and if there is no common version it will error.  If you have two packages listed with two different versions it will choose the first entry and silently not install the other.
                    // If the package is already processed then skip.  If the package is explicitly added then skip to use that order.
                    if (!processedPackages.Contains(dependency.Id, StringComparer.OrdinalIgnoreCase) && !packageRestoreData.PackageImportOrder.Any(pio => pio.Id.Equals(dependency.Id, StringComparison.OrdinalIgnoreCase)))
                    {
                        LockFileLibrary installedPackage = lockFile.Libraries.First(lockPkg => lockPkg.Name.Equals(dependency.Id, StringComparison.OrdinalIgnoreCase));

                        processedPackages.Add(dependency.Id);

                        AddPackage((List <PackageIdentityWithPath>)packages, installedPackage, versionFolderPathResolver);
                    }
                }

                if (!processedPackages.Contains(package.Id))
                {
                    LockFileLibrary installedPackage = lockFile.Libraries.First(lockPkg => lockPkg.Name.Equals(package.Id, StringComparison.OrdinalIgnoreCase));

                    processedPackages.Add(package.Id);

                    AddPackage((List <PackageIdentityWithPath>)packages, installedPackage, versionFolderPathResolver);
                }
            }

            return(true);
        }
Example #4
0
 public abstract bool TryGetPackages(string packageConfigPath, PackageRestoreData packageRestoreData, out IEnumerable <PackageIdentityWithPath> packages);
        public override bool TryGetPackages(string packageConfigPath, PackageRestoreData packageRestoreData, out IEnumerable <PackageIdentityWithPath> packages)
        {
            packages = null;

            string projectJsonPath;

            if (ProjectJsonPathUtilities.IsProjectConfig(packageConfigPath))
            {
                projectJsonPath = packageConfigPath;
            }
            else
            {
                if (!String.Equals("ProjectJson", packageRestoreData?.RestoreProjectStyle, StringComparison.OrdinalIgnoreCase) || String.IsNullOrWhiteSpace(packageRestoreData?.ProjectJsonPath))
                {
                    return(false);
                }

                projectJsonPath = packageRestoreData.ProjectJsonPath;
            }

            string lockFilePath = ProjectJsonPathUtilities.GetLockFilePath(projectJsonPath);

            if (!File.Exists(lockFilePath))
            {
                throw new FileNotFoundException($"The lock file '{lockFilePath}' does not exist.  Ensure that the restore succeeded and that the lock file was generated.");
            }

            LockFile lockFile = LockFileUtilities.GetLockFile(lockFilePath, NullLogger.Instance);

            string globalPackagesFolder = SettingsUtility.GetGlobalPackagesFolder(NuGetSettings);

            if (String.IsNullOrWhiteSpace(globalPackagesFolder))
            {
                throw new NuGetConfigurationException(@"Unable to determine the NuGet repository path.  This usually defaults to ""%UserProfile%\.nuget\packages"", ""%NUGET_PACKAGES%"", or the ""globalPackagesFolder"" in your NuGet.config.");
            }

            globalPackagesFolder = Path.GetFullPath(globalPackagesFolder);

            if (!Directory.Exists(globalPackagesFolder))
            {
                throw new DirectoryNotFoundException($"The NuGet repository '{globalPackagesFolder}' does not exist.  Ensure that NuGet is restore packages to the location specified in your NuGet.config.");
            }

            Log.LogMessage(MessageImportance.Low, $"Using repository path: '{globalPackagesFolder}'");

            VersionFolderPathResolver versionFolderPathResolver = new VersionFolderPathResolver(globalPackagesFolder);

            packages = lockFile.Libraries.Select(i =>
            {
                string installPath = versionFolderPathResolver.GetInstallPath(i.Name, i.Version);

                if (!String.IsNullOrWhiteSpace(installPath))
                {
                    installPath = Path.GetFullPath(installPath);
                }
                else
                {
                    Log.LogWarning($"The package '{i.Name}' was not found in the repository.");
                }

                return(new PackageIdentityWithPath(i.Name, i.Version, installPath));
            }).Where(i => !String.IsNullOrWhiteSpace(i.FullPath));

            return(true);
        }