Пример #1
0
 public InstalledPackage(
     string id,
     string version,
     IEnumerable<PackageRequest> dependencies,
     string folder,
     PackageRequest request,
     string source)
 {
     Id = id;
     Version = version;
     Dependencies = dependencies;
     Folder = folder;
     Request = request;
     Source = source;
 }
Пример #2
0
 public InstalledPackage(
     string id,
     string version,
     IEnumerable <PackageRequest> dependencies,
     string folder,
     PackageRequest request,
     string source,
     List <ContentFile> contentFiles = null)
 {
     Id           = id;
     Version      = version;
     Dependencies = dependencies;
     Folder       = folder;
     Request      = request;
     Source       = source;
     ContentFiles = contentFiles ?? FilesFromFolder(folder, id);
 }
Пример #3
0
        private void ValidatePackage(InstalledPackage installedPackage, PackageRequest request, List <InstalledPackage> installedPackages)
        {
            if (request.Id != null)
            {
                if (installedPackage.Id != request.Id)
                {
                    throw new UserException(string.Format(
                                                "Package ID '{0}' at location '{1}' does not match package ID '{2}' requested from {3}.",
                                                installedPackage.Id, installedPackage.Source, request.Id, request.RequestedBy));
                }
            }

            var currentRhetosVersion = SystemUtility.GetRhetosVersion();

            if (installedPackage.RequiredRhetosVersion != null)
            {
                if (!VersionUtility.ParseVersionSpec(installedPackage.RequiredRhetosVersion).Satisfies(SemanticVersion.Parse(currentRhetosVersion)))
                {
                    DependencyError(string.Format(
                                        "Package '{0}, version {1}' requires Rhetos version {2}. It is incompatible with current Rhetos version {3}.",
                                        installedPackage.Id, installedPackage.Version, installedPackage.RequiredRhetosVersion, currentRhetosVersion));
                }
            }

            if (request.VersionsRange != null)
            {
                if (!VersionUtility.ParseVersionSpec(request.VersionsRange).Satisfies(SemanticVersion.Parse(installedPackage.Version)))
                {
                    DependencyError(string.Format(
                                        "Incompatible package version '{0}, version {1}'. Version {2} is requested from {3}'.",
                                        installedPackage.Id, installedPackage.Version,
                                        request.VersionsRange, request.RequestedBy));
                }
            }

            var similarOldPackage = installedPackages.FirstOrDefault(oldPackage => oldPackage.Id != installedPackage.Id &&
                                                                     SimplifyPackageName(oldPackage.Id) == SimplifyPackageName(installedPackage.Id));

            if (similarOldPackage != null)
            {
                throw new UserException(string.Format(
                                            "Incompatible package names '{0}' (requested from {1}) and '{2}' (requested from {3}).",
                                            installedPackage.Id, installedPackage.Request.RequestedBy,
                                            similarOldPackage.Id, similarOldPackage.Request.RequestedBy));
            }
        }
Пример #4
0
        private InstalledPackage GetPackage(PackageRequest request, FileSyncer binFileSyncer)
        {
            var packageSources = SelectPackageSources(request);

            foreach (var source in packageSources)
            {
                var installedPackage = TryGetPackage(source, request, binFileSyncer);
                if (installedPackage != null)
                {
                    return(installedPackage);
                }
            }

            throw new UserException("Cannot download package " + request.ReportIdVersionsRange()
                                    + ". Looked at " + packageSources.Count() + " sources:"
                                    + string.Concat(packageSources.Select(source => "\r\n" + source.ProcessedLocation)));
        }
Пример #5
0
        private void ValidatePackage(InstalledPackage installedPackage, PackageRequest request)
        {
            if (request.Id != null &&
                !string.Equals(installedPackage.Id, request.Id, StringComparison.OrdinalIgnoreCase))
            {
                throw new UserException(string.Format(
                                            "Package ID '{0}' at location '{1}' does not match package ID '{2}' requested from {3}.",
                                            installedPackage.Id, installedPackage.Source, request.Id, request.RequestedBy));
            }

            if (request.VersionsRange != null &&
                !VersionUtility.ParseVersionSpec(request.VersionsRange).Satisfies(SemanticVersion.Parse(installedPackage.Version)))
            {
                DependencyError(string.Format(
                                    "Incompatible package version '{0}, version {1}'. Version {2} is requested from {3}'.",
                                    installedPackage.Id, installedPackage.Version,
                                    request.VersionsRange, request.RequestedBy));
            }
        }
Пример #6
0
        //================================================================

        private static string CreateVersionInRangeOrZero(PackageRequest request)
        {
            if (request.VersionsRange != null)
            {
                var versionSpec = VersionUtility.ParseVersionSpec(request.VersionsRange);
                if (versionSpec.MinVersion != null)
                {
                    if (versionSpec.IsMinInclusive)
                    {
                        return(versionSpec.MinVersion.ToString());
                    }
                    else
                    {
                        var v = versionSpec.MinVersion.Version;
                        return(new Version(v.Major, v.Minor, v.Build + 1).ToString());
                    }
                }
            }
            return("0.0");
        }
Пример #7
0
        /// <summary>
        /// Returns null if the zip package is not supported for this request.
        /// </summary>
        private ExpectedZipPackage GetExpectedZipPackage(PackageRequest request)
        {
            if (request.VersionsRange == null)
            {
                return(null);
            }

            var requestVersionsRange = VersionUtility.ParseVersionSpec(request.VersionsRange);

            if (!SpecifiedMinVersion(requestVersionsRange))
            {
                return(null);
            }

            string version = requestVersionsRange.MinVersion.ToString();

            return(new ExpectedZipPackage {
                FileName = $"{request.Id}_{version?.Replace('.', '_')}.zip", Version = version
            });
        }
Пример #8
0
        //================================================================
        #region Getting the package from NuGet

        private InstalledPackage TryGetPackageFromNuGet(PackageSource source, PackageRequest request, FileSyncer binFileSyncer)
        {
            var sw = Stopwatch.StartNew();

            var nugetRepository = (source.Path != null && IsLocalPath(source.Path))
                ? new LocalPackageRepository(source.Path, enableCaching: false) // When developer rebuilds a package, the package version does not need to be increased every time.
                : PackageRepositoryFactory.Default.CreateRepository(source.ProcessedLocation);
            var requestVersionsRange = !string.IsNullOrEmpty(request.VersionsRange)
                ? VersionUtility.ParseVersionSpec(request.VersionsRange)
                : new VersionSpec();
            var package = nugetRepository.FindPackage(request.Id, requestVersionsRange, allowPrereleaseVersions: true, allowUnlisted: true);

            _performanceLogger.Write(sw, () => "PackageDownloader find NuGet package " + request.Id + ".");

            if (package == null)
            {
                _logger.Trace("Package " + request.ReportIdVersionsRange() + " not found by NuGet at " + source.ProcessedLocation + ".");
                return(null);
            }
            else
            {
                _logger.Trace("Downloading NuGet package " + package.Id + " " + package.Version + " from " + source.ProcessedLocation + ".");
            }

            var packageManager = new PackageManager(nugetRepository, Paths.PackagesFolder)
            {
                Logger = new LoggerForNuget(_logProvider)
            };

            packageManager.LocalRepository.PackageSaveMode = PackageSaveModes.Nuspec;

            packageManager.InstallPackage(package, ignoreDependencies: true, allowPrereleaseVersions: true);
            _performanceLogger.Write(sw, () => "PackageDownloader install NuGet package " + request.Id + ".");

            string targetFolder = packageManager.PathResolver.GetInstallPath(package);

            binFileSyncer.AddFolderContent(Path.Combine(targetFolder, "Plugins"), Paths.PluginsFolder, recursive: false);
            binFileSyncer.AddFolderContent(Path.Combine(targetFolder, "Resources"), Paths.ResourcesFolder, SimplifyPackageName(package.Id), recursive: true);

            return(new InstalledPackage(package.Id, package.Version.ToString(), GetNuGetPackageDependencies(package), targetFolder, request, source.ProcessedLocation, GetNuGetRequiredRhetosVersion(package)));
        }
Пример #9
0
        private bool CheckAlreadyDownloaded(PackageRequest request, List <InstalledPackage> installedPackages)
        {
            var existing = installedPackages.FirstOrDefault(op => string.Equals(op.Id, request.Id, StringComparison.OrdinalIgnoreCase));

            if (existing == null)
            {
                return(false);
            }

            var requestVersionsRange = VersionUtility.ParseVersionSpec(request.VersionsRange);
            var existingVersion      = SemanticVersion.Parse(existing.Version);

            if (!requestVersionsRange.Satisfies(existingVersion))
            {
                DependencyError($"Incompatible package version '{request.ReportIdVersionRequestSource()}'" +
                                $" conflicts with previously downloaded package '{existing.ReportIdVersionRequestSource()}'.");
            }

            _logger.Trace(() => $"Package '{request.ReportIdVersionsRange()}' already downloaded: '{existing.ReportIdVersionRequestSource()}'.");
            return(true);
        }
Пример #10
0
        private bool CheckAlreadyDownloaded(PackageRequest request, List <InstalledPackage> installedPackages)
        {
            var existing = installedPackages.FirstOrDefault(op => string.Equals(op.Id, request.Id, StringComparison.OrdinalIgnoreCase));

            if (existing == null)
            {
                return(false);
            }

            var requestVersionsRange = VersionUtility.ParseVersionSpec(request.VersionsRange);
            var existingVersion      = SemanticVersion.Parse(existing.Version);

            if (!requestVersionsRange.Satisfies(existingVersion))
            {
                DependencyError(string.Format(
                                    "Incompatible package version '{0}, version {1}, requested by {2}' conflicts with previously downloaded package '{3}, version {4}, requested by {5} ({6})'.",
                                    request.Id, request.VersionsRange ?? "not specified", request.RequestedBy,
                                    existing.Id, existing.Version, existing.Request.RequestedBy, existing.Request.VersionsRange));
            }

            return(true);
        }
Пример #11
0
        //================================================================
        #region Getting the package from legacy zip file

        private InstalledPackage TryGetPackageFromLegacyZipPackage(PackageSource source, PackageRequest request, FileSyncer binFileSyncer)
        {
            if (source.Path == null)
            {
                return(null);
            }

            var zipPackage = GetExpectedZipPackage(request);

            if (zipPackage == null)
            {
                return(null);
            }

            string zipPackagePath = Path.Combine(source.Path, zipPackage.FileName);

            if (!File.Exists(zipPackagePath))
            {
                _logger.Trace(() => $"There is no legacy zip package at {zipPackagePath}.");
                return(null);
            }

            _logger.Trace(() => $"Reading package {request.Id} from legacy file {zipPackagePath}.");
            _logger.Info(() => $"Reading {request.Id} from legacy zip file.");

            string targetFolder = GetTargetFolder(request.Id, zipPackage.Version);

            _filesUtility.EmptyDirectory(targetFolder);
            ZipFile.ExtractToDirectory(zipPackagePath, targetFolder);

            binFileSyncer.AddFolderContent(Path.Combine(targetFolder, "Plugins"), Paths.PluginsFolder, recursive: false);

            return(new InstalledPackage(request.Id, zipPackage.Version, new List <PackageRequest> {
            }, targetFolder, request, source.ProcessedLocation));
        }
Пример #12
0
 private string GetZipPackageName(PackageRequest request)
 {
     return(request.Id + (request.VersionsRange != null ? "_" + request.VersionsRange.Replace('.', '_') : "") + ".zip");
 }
Пример #13
0
        //================================================================
        #region Getting the package from legacy zip file

        private InstalledPackage TryGetPackageFromLegacyZipPackage(PackageSource source, PackageRequest request, FileSyncer binFileSyncer)
        {
            if (source.Path == null)
            {
                return(null);
            }
            Version simpleVersion;

            if (!Version.TryParse(request.VersionsRange, out simpleVersion))
            {
                return(null);
            }

            string zipPackageName = GetZipPackageName(request);
            string zipPackagePath = Path.Combine(source.Path, zipPackageName);

            if (!File.Exists(zipPackagePath))
            {
                _logger.Trace(() => "There is no legacy file " + zipPackageName + " in " + source.ProvidedLocation + ".");
                return(null);
            }

            _logger.Trace(() => "Reading package " + request.Id + " from legacy file " + zipPackageName + ".");

            string targetFolder = GetTargetFolder(request.Id, request.VersionsRange);

            _filesUtility.EmptyDirectory(targetFolder);
            using (var zipFile = ZipFile.Read(zipPackagePath))
                foreach (var zipEntry in zipFile)
                {
                    zipEntry.Extract(targetFolder, ExtractExistingFileAction.OverwriteSilently);
                }

            binFileSyncer.AddFolderContent(Path.Combine(targetFolder, "Plugins"), Paths.PluginsFolder, recursive: false);
            binFileSyncer.AddFolderContent(Path.Combine(targetFolder, "Resources"), Paths.ResourcesFolder, SimplifyPackageName(request.Id), recursive: true);

            return(new InstalledPackage(request.Id, request.VersionsRange, new List <PackageRequest> {
            }, targetFolder, request, source.ProcessedLocation));
        }
Пример #14
0
        private InstalledPackage UseFilesFromUnpackedSourceWithoutMetadata(string sourceFolder, PackageRequest request, FileSyncer binFileSyncer)
        {
            string sourcePluginsFolder = Path.Combine(sourceFolder, "Plugins");

            if (Directory.Exists(sourcePluginsFolder) &&
                Directory.EnumerateFiles(sourcePluginsFolder, "*.dll", SearchOption.AllDirectories).FirstOrDefault() != null &&
                Directory.EnumerateFiles(sourcePluginsFolder, "*.dll", SearchOption.TopDirectoryOnly).FirstOrDefault() == null)
            {
                _logger.Error(() => "Package " + request.Id + " source folder contains Plugins that will not be installed to the Rhetos server. Add '" + request.Id + ".nuspec' file to define the which plugin files should be installed.");
            }

            binFileSyncer.AddFolderContent(Path.Combine(sourceFolder, "Plugins"), Paths.PluginsFolder, recursive: false);
            binFileSyncer.AddFolderContent(Path.Combine(sourceFolder, "Resources"), Paths.ResourcesFolder, SimplifyPackageName(request.Id), recursive: true);

            string defaultVersion = CreateVersionInRangeOrZero(request);

            return(new InstalledPackage(request.Id, defaultVersion, new List <PackageRequest> {
            }, sourceFolder, request, sourceFolder));
        }
Пример #15
0
        private InstalledPackage UseFilesFromUnpackedSourceWithMetadata(string metadataFile, PackageRequest request, FileSyncer binFileSyncer)
        {
            var properties = new SimplePropertyProvider
            {
                { "Configuration", "Debug" },
            };
            var packageBuilder = new PackageBuilder(metadataFile, properties, includeEmptyDirectories: false);

            var sourceFolder = Path.GetDirectoryName(metadataFile);
            var targetFolder = GetTargetFolder(packageBuilder.Id, packageBuilder.Version.ToString());

            // Copy binary files and resources:

            foreach (PhysicalPackageFile file in FilterCompatibleLibFiles(packageBuilder.Files))
            {
                binFileSyncer.AddFile(file.SourcePath, Paths.PluginsFolder, Path.Combine(Paths.PluginsFolder, file.EffectivePath));
            }

            foreach (PhysicalPackageFile file in packageBuilder.Files)
            {
                if (file.Path.StartsWith(@"Plugins\")) // Obsolete bin folder; lib should be used instead.
                {
                    binFileSyncer.AddFile(file.SourcePath, Paths.PluginsFolder);
                }
                else if (file.Path.StartsWith(@"Resources\"))
                {
                    binFileSyncer.AddFile(file.SourcePath, Paths.ResourcesFolder, Path.Combine(SimplifyPackageName(packageBuilder.Id), file.Path.Substring(@"Resources\".Length)));
                }
            }

            return(new InstalledPackage(packageBuilder.Id, packageBuilder.Version.ToString(), GetNuGetPackageDependencies(packageBuilder),
                                        sourceFolder, request, sourceFolder));
        }
Пример #16
0
        //================================================================
        #region Getting the package from unpacked source folder

        private InstalledPackage TryGetPackageFromUnpackedSourceFolder(PackageSource source, PackageRequest request, FileSyncer binFileSyncer)
        {
            if (request.Source == null) // Unpacked source folder must be explicitly set in the package request.
            {
                return(null);
            }
            if (source.Path == null || !Directory.Exists(source.Path))
            {
                return(null);
            }

            var packageExtensions    = new[] { "*.nupkg", GetZipPackageName(request) };
            var existingPackageFiles = packageExtensions.SelectMany(ext => Directory.GetFiles(source.Path, ext));

            var existingMetadataFiles = Directory.GetFiles(source.Path, "*.nuspec");

            if (existingMetadataFiles.Length > 1)
            {
                // If any nuspec file exactly matches the packages name, use that one.
                var standardFileName = existingMetadataFiles.Where(f => string.Equals(Path.GetFileName(f), request.Id + ".nuspec", StringComparison.OrdinalIgnoreCase)).ToArray();
                if (standardFileName.Length == 1)
                {
                    existingMetadataFiles = standardFileName;
                }
            }

            var packageSourceSubfolders  = new[] { "DslScripts", "DataMigration", "Plugins", "Resources" };
            var existingSourceSubfolders = packageSourceSubfolders.Where(subfolder => Directory.Exists(Path.Combine(source.Path, subfolder)));

            if (existingPackageFiles.Count() > 0)
            {
                string ambiguousAlternative = null;
                if (existingMetadataFiles.Count() > 0)
                {
                    ambiguousAlternative = $".nuspec file '{Path.GetFileName(existingMetadataFiles.First())}'";
                }
                else if (existingSourceSubfolders.Count() > 0)
                {
                    ambiguousAlternative = $"source folder '{existingSourceSubfolders.First()}'";
                }

                if (ambiguousAlternative != null)
                {
                    throw new FrameworkException($"Ambiguous source for package {request.Id}. Source folder '{source.Path}' contains both" +
                                                 $" package file '{Path.GetFileName(existingPackageFiles.First())}' and {ambiguousAlternative}.");
                }

                _logger.Trace(() => $"Package {request.Id} source folder is not considered as unpacked source because" +
                              $" it contains a package file '{Path.GetFileName(existingPackageFiles.First())}'.");
                return(null);
            }
            else if (existingMetadataFiles.Length > 1)
            {
                _logger.Info(() => "Package " + request.Id + " source folder '" + source.ProvidedLocation + "' contains multiple .nuspec metadata files.");
                return(null);
            }
            else if (existingMetadataFiles.Length == 1)
            {
                _logger.Trace(() => "Reading package " + request.Id + " from unpacked source folder with metadata " + Path.GetFileName(existingMetadataFiles.Single()) + ".");
                return(UseFilesFromUnpackedSourceWithMetadata(existingMetadataFiles.Single(), request, binFileSyncer));
            }
            else if (existingSourceSubfolders.Any())
            {
                _logger.Trace(() => "Reading package " + request.Id + " from unpacked source folder without metadata file.");
                return(UseFilesFromUnpackedSourceWithoutMetadata(source.Path, request, binFileSyncer));
            }
            else
            {
                return(null);
            }
        }
Пример #17
0
 private InstalledPackage TryGetPackage(PackageSource source, PackageRequest request, FileSyncer binFileSyncer)
 {
     return(TryGetPackageFromUnpackedSourceFolder(source, request, binFileSyncer)
            ?? TryGetPackageFromLegacyZipPackage(source, request, binFileSyncer)
            ?? TryGetPackageFromNuGet(source, request, binFileSyncer));
 }
Пример #18
0
        private InstalledPackage UseFilesFromUnpackedSourceWithMetadata(string metadataFile, PackageRequest request, FileSyncer binFileSyncer)
        {
            var properties = new SimplePropertyProvider
            {
                { "Configuration", "Debug" },
            };
            var packageBuilder = new PackageBuilder(metadataFile, properties, includeEmptyDirectories: false);

            string sourceFolder = Path.GetDirectoryName(metadataFile);

            // Copy binary files:

            foreach (var file in FilterCompatibleLibFiles(packageBuilder.Files).Cast <PhysicalPackageFile>())
            {
                binFileSyncer.AddFile(file.SourcePath, Paths.PluginsFolder, Path.Combine(Paths.PluginsFolder, file.EffectivePath));
            }

            foreach (var file in packageBuilder.Files.Cast <PhysicalPackageFile>())
            {
                if (file.Path.StartsWith(@"Plugins\")) // Obsolete bin folder; lib should be used instead.
                {
                    binFileSyncer.AddFile(file.SourcePath, Paths.PluginsFolder);
                }
            }

            var contentFiles = packageBuilder.Files.Cast <PhysicalPackageFile>()
                               .Select(file => new ContentFile {
                PhysicalPath = file.SourcePath, InPackagePath = file.Path
            })
                               .ToList();

            return(new InstalledPackage(packageBuilder.Id, packageBuilder.Version.ToString(), GetNuGetPackageDependencies(packageBuilder),
                                        sourceFolder, request, sourceFolder, contentFiles));
        }
Пример #19
0
        //================================================================
        #region Getting the package from unpacked source folder

        private InstalledPackage TryGetPackageFromUnpackedSourceFolder(PackageSource source, PackageRequest request, FileSyncer binFileSyncer)
        {
            if (request.Source == null) // Unpacked source folder must be explicitly set in the package request.
            {
                return(null);
            }
            if (source.Path == null || !Directory.Exists(source.Path))
            {
                return(null);
            }

            foreach (string packedExtension in new[] { "zip", "nupkg" })
            {
                if (Directory.GetFiles(source.Path, "*." + packedExtension).Length > 0)
                {
                    _logger.Trace(() => "Package " + request.Id + " source folder is not considered as unpacked source because it contains ." + packedExtension + " files.");
                    return(null);
                }
            }

            var metadataFiles = Directory.GetFiles(source.Path, "*.nuspec");

            // Disambiguation by name:
            if (metadataFiles.Length > 1)
            {
                var standardFileName = metadataFiles.Where(f => string.Equals(Path.GetFileName(f), request.Id + ".nuspec", StringComparison.OrdinalIgnoreCase)).ToArray();
                if (standardFileName.Length == 1)
                {
                    metadataFiles = standardFileName;
                }
            }

            if (metadataFiles.Length > 1)
            {
                _logger.Info(() => "Package " + request.Id + " source folder '" + source.ProvidedLocation + "' contains multiple .nuspec metadata files.");
                return(null);
            }
            else if (metadataFiles.Length == 1)
            {
                _logger.Trace(() => "Reading package " + request.Id + " from unpacked source folder with metadata " + Path.GetFileName(metadataFiles.Single()) + ".");
                return(UseFilesFromUnpackedSourceWithMetadata(metadataFiles.Single(), request, binFileSyncer));
            }
            else
            {
                var rhetosPackageSubfolders = new[] { "DslScripts", "DataMigration", "Plugins", "Resources" };
                if (rhetosPackageSubfolders.Any(subfolder => Directory.Exists(Path.Combine(source.Path, subfolder))))
                {
                    _logger.Trace(() => "Reading package " + request.Id + " from unpacked source folder without metadata file.");
                    return(UseFilesFromUnpackedSourceWithoutMetadata(source.Path, request, binFileSyncer));
                }
                else
                {
                    return(null);
                }
            }
        }