internal static bool ShouldCuratePackage(
            CuratedFeed curatedFeed, 
            Package galleryPackage,
            PackageReader nugetPackage)
        {
            var nuspec = nugetPackage.GetNuspecReader();

            return 
                // Must have min client version of null or <= 2.2
                (nuspec.GetMinClientVersion() == null || nuspec.GetMinClientVersion() <= new NuGetVersion(2, 2, 0)) &&

                // Must be latest stable
                galleryPackage.IsLatestStable &&

                // Must support net40
                SupportsNet40(galleryPackage) &&

                (
                    // Must have AspNetWebPages tag
                    ContainsAspNetWebPagesTag(galleryPackage) ||

                    // OR: Must not contain powershell or T4
                    DoesNotContainUnsupportedFiles(nugetPackage)
                ) &&

                // Dependencies on the gallery must be curated
                DependenciesAreCurated(galleryPackage, curatedFeed);
        }
Пример #2
0
        public void EnsureValid(PackageReader packageReader)
        {
            var packageMetadata = PackageMetadata.FromNuspecReader(packageReader.GetNuspecReader());

            ValidateNuGetPackageMetadata(packageMetadata);

            var supportedFrameworks = GetSupportedFrameworks(packageReader).Select(fn => fn.ToShortNameOrNull()).ToArray();
            if (!supportedFrameworks.AnySafe(sf => sf == null))
            {
                ValidateSupportedFrameworks(supportedFrameworks);
            }
        }
Пример #3
0
        public static void RewritingTheNuSpecDoesNotMessUpTheNuspecStream()
        {
            var packageStream = CreateTestPackageStream();
            var manifestStreamLengthOriginal = GetManifestStreamLength(packageStream);

            var longValue = new String('x', 200);
            var shortValue = "y";

            // Act 1 - Make the stream bigger
            NupkgRewriter.RewriteNupkgManifest(packageStream,
                    new List<Action<ManifestEdit>>
                    {
                        metadata => { metadata.Description = longValue; },
                        metadata => { metadata.Summary = longValue; }
                    });

            // Assert 1
            var manifestStreamLength1 = GetManifestStreamLength(packageStream);
            Assert.True(manifestStreamLength1 > manifestStreamLengthOriginal);

            using (var nupkg = new PackageReader(packageStream, leaveStreamOpen: true))
            {
                var nuspec = nupkg.GetNuspecReader();

                Assert.Equal("TestPackage", nuspec.GetId());
                Assert.Equal(NuGetVersion.Parse("0.0.0.1"), nuspec.GetVersion());
                Assert.Equal(longValue, nuspec.GetMetadata().First(kvp => kvp.Key == "description").Value);
                Assert.Equal(longValue, nuspec.GetMetadata().First(kvp => kvp.Key == "summary").Value);
            }

            // Act 2 - Make the stream smaller
            NupkgRewriter.RewriteNupkgManifest(packageStream,
                    new List<Action<ManifestEdit>>
                    {
                        metadata => { metadata.Description = shortValue; },
                        metadata => { metadata.Summary = shortValue; }
                    });

            // Assert 2
            var manifestStreamLength2 = GetManifestStreamLength(packageStream);
            Assert.True(manifestStreamLength2 < manifestStreamLength1);

            using (var nupkg = new PackageReader(packageStream, leaveStreamOpen: true))
            {
                var nuspec = nupkg.GetNuspecReader();

                Assert.Equal("TestPackage", nuspec.GetId());
                Assert.Equal(NuGetVersion.Parse("0.0.0.1"), nuspec.GetVersion());
                Assert.Equal(shortValue, nuspec.GetMetadata().First(kvp => kvp.Key == "description").Value);
                Assert.Equal(shortValue, nuspec.GetMetadata().First(kvp => kvp.Key == "summary").Value);
            }
        }
Пример #4
0
        public Package CreatePackage(PackageReader nugetPackage, PackageStreamMetadata packageStreamMetadata, User user, bool commitChanges = true)
        {
            var packageMetadata = PackageMetadata.FromNuspecReader(nugetPackage.GetNuspecReader());

            ValidateNuGetPackageMetadata(packageMetadata);

            var packageRegistration = CreateOrGetPackageRegistration(user, packageMetadata);

            var package = CreatePackageFromNuGetPackage(packageRegistration, nugetPackage, packageMetadata, packageStreamMetadata, user);
            packageRegistration.Packages.Add(package);
            UpdateIsLatest(packageRegistration, false);

            if (commitChanges)
            {
                _packageRegistrationRepository.CommitChanges();
                NotifyIndexingService();
            }

            return package;
        }
        public static void CanReadBasicMetadataProperties()
        {
            var packageStream = CreateTestPackageStream();
            var nupkg = new PackageReader(packageStream, leaveStreamOpen: false);
            var nuspec = nupkg.GetNuspecReader();

            // Act
            var packageMetadata = PackageMetadata.FromNuspecReader(nuspec);

            // Assert
            Assert.Equal("TestPackage", packageMetadata.Id);
            Assert.Equal(NuGetVersion.Parse("0.0.0.1"), packageMetadata.Version);
            Assert.Equal("Package A", packageMetadata.Title);
            Assert.Equal(2, packageMetadata.Authors.Count);
            Assert.Equal("ownera, ownerb", packageMetadata.Owners);
            Assert.False(packageMetadata.RequireLicenseAcceptance);
            Assert.Equal("package A description.", packageMetadata.Description);
            Assert.Equal("en-US", packageMetadata.Language);
            Assert.Equal("http://www.nuget.org/", packageMetadata.ProjectUrl.ToString());
            Assert.Equal("http://www.nuget.org/", packageMetadata.IconUrl.ToString());
            Assert.Equal("http://www.nuget.org/", packageMetadata.LicenseUrl.ToString());
        }
Пример #6
0
        public static void CanRewriteTheNuspecInANupkg()
        {
            var packageStream = CreateTestPackageStream();

            // Act
            NupkgRewriter.RewriteNupkgManifest(packageStream,
                    new List<Action<ManifestEdit>>
                    {
                        metadata => { metadata.Authors = "Me and You"; },
                        metadata => { metadata.Tags = "Peas In A Pod"; }
                    });

            // Assert
            using (var nupkg = new PackageReader(packageStream, leaveStreamOpen: false))
            {
                var nuspec = nupkg.GetNuspecReader();

                Assert.Equal("TestPackage", nuspec.GetId());
                Assert.Equal(NuGetVersion.Parse("0.0.0.1"), nuspec.GetVersion());
                Assert.Equal("Me and You", nuspec.GetMetadata().First(kvp => kvp.Key == "authors").Value);
                Assert.Equal("Peas In A Pod", nuspec.GetMetadata().First(kvp => kvp.Key == "tags").Value);
            }
        }
Пример #7
0
        private async Task<ActionResult> CreatePackageInternal()
        {
            // Get the user
            var user = GetCurrentUser();

            using (var packageStream = ReadPackageFromRequest())
            using (var packageToPush = new PackageReader(packageStream, leaveStreamOpen: false))
            {
                NuspecReader nuspec = null;
                try
                {
                    nuspec = packageToPush.GetNuspecReader();
                }
                catch (Exception ex)
                {
                    return new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, string.Format(
                        CultureInfo.CurrentCulture,
                        Strings.UploadPackage_InvalidNuspec,
                        ex.Message));
                }

                if (nuspec.GetMinClientVersion() > Constants.MaxSupportedMinClientVersion)
                {
                    return new HttpStatusCodeWithBodyResult(HttpStatusCode.BadRequest, string.Format(
                        CultureInfo.CurrentCulture,
                        Strings.UploadPackage_MinClientVersionOutOfRange,
                        nuspec.GetMinClientVersion()));
                }

                // Ensure that the user can push packages for this partialId.
                var packageRegistration = PackageService.FindPackageRegistrationById(nuspec.GetId());
                if (packageRegistration != null)
                {
                    if (!packageRegistration.IsOwner(user))
                    {
                        return new HttpStatusCodeWithBodyResult(HttpStatusCode.Forbidden, Strings.ApiKeyNotAuthorized);
                    }

                    // Check if a particular Id-Version combination already exists. We eventually need to remove this check.
                    string normalizedVersion = nuspec.GetVersion().ToNormalizedString();
                    bool packageExists =
                        packageRegistration.Packages.Any(
                            p => String.Equals(
                                p.NormalizedVersion,
                                normalizedVersion,
                                StringComparison.OrdinalIgnoreCase));

                    if (packageExists)
                    {
                        return new HttpStatusCodeWithBodyResult(
                            HttpStatusCode.Conflict,
                            String.Format(CultureInfo.CurrentCulture, Strings.PackageExistsAndCannotBeModified,
                                          nuspec.GetId(), nuspec.GetVersion().ToNormalizedStringSafe()));
                    }
                }

                var packageStreamMetadata = new PackageStreamMetadata
                {
                    HashAlgorithm = Constants.Sha512HashAlgorithmId,
                    Hash = CryptographyService.GenerateHash(packageStream.AsSeekableStream()),
                    Size = packageStream.Length,
                };

                var package = PackageService.CreatePackage(packageToPush, packageStreamMetadata, user, commitChanges: false);
                AutoCuratePackage.Execute(package, packageToPush, commitChanges: false);
                EntitiesContext.SaveChanges();

                using (Stream uploadStream = packageStream)
                {
                    uploadStream.Position = 0;
                    await PackageFileService.SavePackageFileAsync(package, uploadStream.AsSeekableStream());
                    IndexingService.UpdatePackage(package);
                }
            }

            return new HttpStatusCodeResult(HttpStatusCode.Created);
        }
        /// <summary>
        /// Given the nupkg file as a read-write stream with random access (e.g. MemoryStream),
        /// This will replace the .nuspec file with a new .nuspec generated from 
        /// a) the old .nuspec file
        /// b) supplied edits
        /// 
        /// This function leaves readWriteStream open.
        /// </summary>
        public static void RewriteNupkgManifest(Stream readWriteStream, IEnumerable<Action<ManifestEdit>> edits)
        {
            if (!readWriteStream.CanRead)
            {
                throw new ArgumentException(Strings.StreamMustBeReadable, nameof(readWriteStream));
            }

            if (!readWriteStream.CanWrite)
            {
                throw new ArgumentException(Strings.StreamMustBeWriteable, nameof(readWriteStream));
            }

            if (!readWriteStream.CanSeek)
            {
                throw new ArgumentException(Strings.StreamMustBeSeekable, nameof(readWriteStream));
            }

            using (var packageReader = new PackageReader(readWriteStream, leaveStreamOpen: true))
            {
                var nuspecReader = packageReader.GetNuspecReader();

                // Read <metadata> node from nuspec
                var metadataNode = nuspecReader.Xml.Root.Elements()
                    .FirstOrDefault(e => StringComparer.Ordinal.Equals(e.Name.LocalName, "metadata"));
                if (metadataNode == null)
                {
                    throw new PackagingException("The package manifest is missing the 'metadata' node.");
                }

                // Convert metadata into a ManifestEdit so that we can run it through the editing pipeline
                var editableManifestElements = new ManifestEdit
                {
                    Title = ReadFromMetadata(metadataNode, "title"),
                    Authors = ReadFromMetadata(metadataNode, "authors"),
                    Copyright = ReadFromMetadata(metadataNode, "copyright"),
                    Description = ReadFromMetadata(metadataNode, "description"),
                    IconUrl = ReadFromMetadata(metadataNode, "iconUrl"),
                    LicenseUrl = ReadFromMetadata(metadataNode, "licenseUrl"),
                    ProjectUrl = ReadFromMetadata(metadataNode, "projectUrl"),
                    ReleaseNotes = ReadFromMetadata(metadataNode, "releasenotes"),
                    RequireLicenseAcceptance = ReadBoolFromMetadata(metadataNode, "requireLicenseAcceptance"),
                    Summary = ReadFromMetadata(metadataNode, "summary"),
                    Tags = ReadFromMetadata(metadataNode, "tags")
                };
                
                // Perform edits
                foreach (var edit in edits)
                {
                    edit.Invoke(editableManifestElements);
                }

                // Update the <metadata> node
                WriteToMetadata(metadataNode, "title", editableManifestElements.Title);
                WriteToMetadata(metadataNode, "authors", editableManifestElements.Authors);
                WriteToMetadata(metadataNode, "copyright", editableManifestElements.Copyright);
                WriteToMetadata(metadataNode, "description", editableManifestElements.Description);
                WriteToMetadata(metadataNode, "iconUrl", editableManifestElements.IconUrl);
                WriteToMetadata(metadataNode, "licenseUrl", editableManifestElements.LicenseUrl);
                WriteToMetadata(metadataNode, "projectUrl", editableManifestElements.ProjectUrl);
                WriteToMetadata(metadataNode, "releasenotes", editableManifestElements.ReleaseNotes);
                WriteToMetadata(metadataNode, "requireLicenseAcceptance", editableManifestElements.RequireLicenseAcceptance.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
                WriteToMetadata(metadataNode, "summary", editableManifestElements.Summary);
                WriteToMetadata(metadataNode, "tags", editableManifestElements.Tags);
                
                // Update the package stream
                using (var newManifestStream = new MemoryStream())
                {
                    nuspecReader.Xml.Save(newManifestStream);

                    using (var archive = new ZipArchive(readWriteStream, ZipArchiveMode.Update, leaveOpen: true))
                    {
                        var manifestEntries = archive.Entries
                            .Where(entry => entry.FullName.IndexOf("/", StringComparison.OrdinalIgnoreCase) == -1
                                && entry.Name.EndsWith(".nuspec", StringComparison.OrdinalIgnoreCase)).ToList();

                        if (manifestEntries.Count == 0)
                        {
                            throw new PackagingException("Nuspec file does not exist in package.");
                        }

                        if (manifestEntries.Count > 1)
                        {
                            throw new PackagingException("Package contains multiple nuspec files.");
                        }

                        var manifestEntry = manifestEntries[0];

                        using (var manifestOutputStream = manifestEntry.Open())
                        {
                            manifestOutputStream.SetLength(0);
                            newManifestStream.Position = 0;
                            newManifestStream.CopyTo(manifestOutputStream);
                        }
                    }
                }
            }
        }
        public override void ExecuteCommand()
        {
            Log.Trace("Getting latest packages...");
            var packages = GetLatestStablePackages();
            Log.Trace("Getting previously curated packages...");
            var alreadyCuratedPackageIds = GetAlreadyCuratedPackageIds();
            Log.Trace("Calculating minimum difference set...");
            var packageIdsToCurate = packages.Keys.Except(alreadyCuratedPackageIds).ToList();

            var totalCount = packageIdsToCurate.Count;
            var processedCount = 0;
            Log.Trace(
                "Curating {0} packages for the WebMatrix curated on '{1}',",
                totalCount,
                ConnectionString);

            Parallel.ForEach(packageIdsToCurate, new ParallelOptions { MaxDegreeOfParallelism = 10 }, packageIdToCurate =>
            {
                var package = packages[packageIdToCurate];

                try
                {
                    var downloadPath = DownloadPackage(package);

                    bool shouldBeIncluded;
                    using (var nugetPackage = new PackageReader(File.OpenRead(downloadPath)))
                    {
                        var nuspecReader = nugetPackage.GetNuspecReader();
                        var metadata = nuspecReader.GetMetadata()
                            .ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);

                        string tags;
                        shouldBeIncluded = metadata.TryGetValue("tags", out tags) && tags.ToLowerInvariant().Contains("aspnetwebpages");

                        if (!shouldBeIncluded)
                        {
                            shouldBeIncluded = true;
                            foreach (var file in nugetPackage.GetFiles())
                            {
                                var fi = new FileInfo(file);
                                if (fi.Extension == ".ps1" || fi.Extension == ".t4")
                                {
                                    shouldBeIncluded = false;
                                    break;
                                }
                            }
                        }

                        if (shouldBeIncluded)
                        {
                            AddPackageToCuratedFeed(package);
                        }
                    }
                    
                    File.Delete(downloadPath);

                    Interlocked.Increment(ref processedCount);
                    Log.Info(
                        "{2} package '{0}.{1}' ({3} of {4}).",
                        package.Id,
                        package.Version,
                        shouldBeIncluded ? "Curated" : "Ignored",
                        processedCount,
                        totalCount);
                }
                catch(Exception ex)
                {
                    Interlocked.Increment(ref processedCount);
                    Log.Error(
                        "Error curating package '{0}.{1}' ({2} of {3}): {4}.",
                        package.Id,
                        package.Version,
                        processedCount,
                        totalCount,
                        ex.Message);
                }
            });
        }