<commit_before>﻿using System;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Versioning;
using NuGet;
using System.Diagnostics;
using System.Xml.Linq;
using System.Timers;
using System.Collections.Concurrent;

namespace VVVV.NuGetAssemblyLoader
{
    public interface IPackageWithPath : IPackage { string Path { get; } }

    public abstract class SrcPackage : IPackageWithPath
    {
        public abstract IEnumerable<IPackageAssemblyReference> AssemblyReferences { get; }
        public abstract IEnumerable<string> Authors { get; }
        public abstract string Copyright { get; }
        public abstract IEnumerable<PackageDependencySet> DependencySets { get; }
        public abstract string Description { get; }
        public abstract bool DevelopmentDependency { get; }
        public abstract int DownloadCount { get; }
        public abstract IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies { get; }
        public abstract Uri IconUrl { get; }
        public abstract string Id { get; }
        public abstract bool IsAbsoluteLatestVersion { get; }
        public abstract bool IsLatestVersion { get; }
        public abstract string Language { get; }
        public abstract Uri LicenseUrl { get; }
        public abstract bool Listed { get; }
        public abstract Version MinClientVersion { get; }
        public abstract IEnumerable<string> Owners { get; }
        public abstract ICollection<PackageReferenceSet> PackageAssemblyReferences { get; }
        public abstract string Path { get; }
        public abstract Uri ProjectUrl { get; }
        public abstract DateTimeOffset? Published { get; }
        public abstract string ReleaseNotes { get; }
        public abstract Uri ReportAbuseUrl { get; }
        public abstract bool RequireLicenseAcceptance { get; }
        public abstract string Summary { get; }
        public abstract string Tags { get; }
        public abstract string Title { get; }
        public abstract SemanticVersion Version { get; }

        public abstract void ExtractContents(IFileSystem fileSystem, string extractPath);
        public abstract IEnumerable<IPackageFile> GetFiles();
        public abstract Stream GetStream();
        public abstract IEnumerable<FrameworkName> GetSupportedFrameworks();
    }

    public class SrcPackageWithNuspec : SrcPackage
    {
        readonly IFileSystem _repositoryFileSystem;
        readonly string _packageName;
        readonly string _nuspecFile;
        PackageBuilder _builder;
        List<PhysicalPackageFile> _files;

        public SrcPackageWithNuspec(IFileSystem repositoryFileSystem, string packageName, string nuspecFile)
        {
            _repositoryFileSystem = repositoryFileSystem;
            _packageName = packageName;
            _nuspecFile = nuspecFile;
        }

        public string NuspecFile => _nuspecFile;

        public override string Path => _repositoryFileSystem.GetFullPath(_packageName);

        internal List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        private PackageBuilder Builder
        {
            get
            {
                if (_builder == null)
                {
                    var path = _repositoryFileSystem.GetFullPath(_nuspecFile);
                    try
                    {
                        _builder = new PackageBuilder(path, NullPropertyProvider.Instance, false);
                    }
                    catch (Exception e) when (e is FileNotFoundException || e is DirectoryNotFoundException)
                    {
                        // Create a dummy
                        _builder = new PackageBuilder();
                        Trace.TraceWarning($"The NuSpec file {path} seems to be corrupt: {e.Message}");
                    }
                }
                return _builder;
            }
        }

        public override bool IsAbsoluteLatestVersion => true;
        public override bool IsLatestVersion => true;
        public override bool Listed => false;
        public override DateTimeOffset? Published => null;
        public override IEnumerable<IPackageAssemblyReference> AssemblyReferences => GetAssemblyReferencesCore();
        public override string Title => Builder.Title;
        public override IEnumerable<string> Authors => Builder.Authors;
        public override IEnumerable<string> Owners => Builder.Owners;
        public override Uri IconUrl => Builder.IconUrl;
        public override Uri LicenseUrl => Builder.LicenseUrl;
        public override Uri ProjectUrl => Builder.ProjectUrl;
        public override bool RequireLicenseAcceptance => Builder.RequireLicenseAcceptance;
        public override bool DevelopmentDependency => Builder.DevelopmentDependency;
        public override string Description => Builder.Description;
        public override string Summary => Builder.Summary;
        public override string ReleaseNotes => Builder.ReleaseNotes;
        public override string Language => Builder.Language;
        public override string Tags => string.Join(", ", Builder.Tags);
        public override string Copyright => Builder.Copyright;
        public override IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies => Builder.FrameworkReferences;
        public override ICollection<PackageReferenceSet> PackageAssemblyReferences => Builder.PackageAssemblyReferences;
        public override IEnumerable<PackageDependencySet> DependencySets => Builder.DependencySets;
        public override Version MinClientVersion => Builder.MinClientVersion;
        public override string Id => _packageName;
        public override SemanticVersion Version => Builder.Version ?? new SemanticVersion(0, 0, 0, 0);
        public override Uri ReportAbuseUrl => null;
        public override int DownloadCount => -1;

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            return Builder.FrameworkReferences.SelectMany(f => f.SupportedFrameworks)
                .Concat(Files.SelectMany(f => f.SupportedFrameworks))
                .Distinct();
        }

        protected IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!AssemblyLoader.IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        public override IEnumerable<IPackageFile> GetFiles()
        {
            return Files;
        }

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var file in Builder.Files.OfType<PhysicalPackageFile>())
            {
                if (file.IsAssemblyFile())
                {
                    var sourcePath = file.SourcePath;
                    var sourceDir = System.IO.Path.GetDirectoryName(sourcePath);
                    if (sourceDir.EndsWith("Release") || sourceDir.EndsWith("Debug"))
                    {
                        var fileName = System.IO.Path.GetFileName(sourcePath);
                        var baseDir = System.IO.Path.GetDirectoryName(sourceDir);
                        var debugFile = System.IO.Path.Combine(baseDir, "Debug", fileName);
                        var releaseFile = System.IO.Path.Combine(baseDir, "Release", fileName);
                        var debugTime = File.Exists(debugFile) ? File.GetLastWriteTime(debugFile) : DateTime.MinValue;
                        var releaseTime = File.Exists(releaseFile) ? File.GetLastWriteTime(releaseFile) : DateTime.MinValue;
                        if (releaseTime > debugTime)
                            file.SourcePath = releaseFile;
                        else if (debugTime > releaseTime)
                            file.SourcePath = debugFile;
                    }
                }
                yield return file;
            }
        }

        public override Stream GetStream()
        {
            throw new NotImplementedException();
        }

        public override void ExtractContents(IFileSystem fileSystem, string extractPath)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            return this.GetFullName();
        }
    }

    public class SrcPackageWithoutNuspec : SrcPackage
    {
        readonly IFileSystem _packageFileSystem;
        readonly string _packageName;
        readonly string _vlFile;
        XDocument _mainFile;
        List<PhysicalPackageFile> _files;

        public SrcPackageWithoutNuspec(IFileSystem repositoryFileSystem, string packageName, string vlFile)
        {
            _packageFileSystem = new PhysicalFileSystem(repositoryFileSystem.GetFullPath(packageName));
            _packageName = packageName;
            _vlFile = repositoryFileSystem.GetFullPath(vlFile);
        }

        public override string Path => _packageFileSystem.Root;

        public XDocument MainFile => _mainFile ?? (_mainFile = XDocument.Load(_vlFile));

        internal List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        public override bool IsAbsoluteLatestVersion => true;
        public override bool IsLatestVersion => true;
        public override bool Listed => false;
        public override DateTimeOffset? Published => null;
        public override IEnumerable<IPackageAssemblyReference> AssemblyReferences => GetAssemblyReferencesCore();
        public override string Title => null;
        public override IEnumerable<string> Authors => Enumerable.Empty<string>();
        public override IEnumerable<string> Owners => Enumerable.Empty<string>();
        public override Uri IconUrl => null;
        public override Uri LicenseUrl => null;
        public override Uri ProjectUrl => null;
        public override bool RequireLicenseAcceptance => false;
        public override bool DevelopmentDependency => false;
        public override string Description => null;
        public override string Summary => null;
        public override string ReleaseNotes => null;
        public override string Language => null;
        public override string Tags => null;
        public override string Copyright => null;
        public override IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies => Enumerable.Empty<FrameworkAssemblyReference>();
        public override ICollection<PackageReferenceSet> PackageAssemblyReferences => Array.Empty<PackageReferenceSet>();

        public override IEnumerable<PackageDependencySet> DependencySets
        {
            get
            {
                var dependencies = MainFile.Root.Elements("NugetDependency")
                    .Select(d => d.Attribute("Location") != null ? new PackageDependency(d.Attribute("Location").Value) : null)
                    .Where(d => d != null);
                yield return new PackageDependencySet(AssemblyLoader.ExecutingFrameworkName, dependencies);
            }
        }

        public override Version MinClientVersion => new Version(0, 0, 0);
        public override string Id => _packageName;

        public override SemanticVersion Version
        {
            get
            {
                //var versionAttribute = MainFile.Root.Attribute("Version");
                //if (versionAttribute != null)
                //{
                //    SemanticVersion result;
                //    if (SemanticVersion.TryParse(versionAttribute.Value, out result))
                //        return result;
                //}
                return new SemanticVersion(0, 0, 0, 0);
            }
        }

        public override Uri ReportAbuseUrl => null;
        public override int DownloadCount => -1;

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            yield return AssemblyLoader.ExecutingFrameworkName;
        }

        protected IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!AssemblyLoader.IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        public override IEnumerable<IPackageFile> GetFiles()
        {
            return Files;
        }

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var f in _packageFileSystem.GetFiles("", "*", true))
            {
                yield return new PhysicalPackageFile()
                {
                    SourcePath = _packageFileSystem.GetFullPath(f),
                    TargetPath = f
                };
            }
        }

        public override Stream GetStream()
        {
            throw new NotImplementedException();
        }

        public override void ExtractContents(IFileSystem fileSystem, string extractPath)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            return this.GetFullName();
        }
    }

    public class SrcPackageRepository : PackageRepositoryBase
    {
        readonly DirectoryInfo _repositoryFolder;
        readonly IFileSystem _fileSystem;
        IQueryable<IPackage> _packages;

        public SrcPackageRepository(DirectoryInfo repositoryFolder)
        {
            _repositoryFolder = repositoryFolder;
            _fileSystem = new PhysicalFileSystem(repositoryFolder.FullName);
        }

        public override string Source => _repositoryFolder.FullName;

        public override bool SupportsPrereleasePackages => true;

        public override IQueryable<IPackage> GetPackages()
        {
            return Packages;
        }

        private IQueryable<IPackage> Packages
        {
            get
            {
                if (_packages == null)
                    _packages = GetPackagesCore().ToList().AsQueryable();
                return _packages;
            }
        }

        private IEnumerable<IPackage> GetPackagesCore()
        {
            foreach (var dir in _fileSystem.GetDirectories(string.Empty))
            {
                var hasNuspec = false;
                if (!hasNuspec)
                {
                    // VL.CoreLib/src/bin/$(Configuration)/$(TFM)/VL.CoreLib.nuspec
                    // VL.CoreLib/bin/$(Configuration)/$(TFM)/VL.CoreLib.nuspec
                    var nuspecFiles = _fileSystem.GetDirectories(Path.Combine(dir, "src", "bin"))
                        .Concat(_fileSystem.GetDirectories(Path.Combine(dir, "bin")))
                        .SelectMany(d => _fileSystem.GetDirectories(d))
                        .SelectMany(d => _fileSystem.GetFiles(d, $"{dir}{Constants.ManifestExtension}"))
                        .Select(f => new { File = f, Modified = File.GetLastWriteTime(_fileSystem.GetFullPath(f)) })
                        .OrderByDescending(f => f.Modified);
                    foreach (var nuspecFile in nuspecFiles)
                    {
                        hasNuspec = true;
                        yield return new SrcPackageWithNuspec(_fileSystem, dir, nuspecFile.File);
                        break;
                    }
                }
                if (!hasNuspec)
                {
                    // VL.CoreLib/VL.CoreLib.nusepc
                    foreach (var nuspecFile in _fileSystem.GetFiles(dir, $"{dir}{Constants.ManifestExtension}"))
                    {
                        hasNuspec = true;
                        yield return new SrcPackageWithNuspec(_fileSystem, dir, nuspecFile);
                        break;
                    }
                }
                if (!hasNuspec)
                {
                    foreach (var vlFile in _fileSystem.GetFiles(dir, $"{dir}.vl"))
                    {
                        hasNuspec = true;
                        yield return new SrcPackageWithoutNuspec(_fileSystem, dir, vlFile);
                        break;
                    }
                }
            }
        }
    }

    public class InstalledNupkgPackage : ZipPackage, IPackageWithPath
    {
        readonly IFileSystem _packageFileSystem;
        List<PhysicalPackageFile> _files;

        public InstalledNupkgPackage(IFileSystem repositoryFileSystem, string folder, string nupkgFile)
            : base(repositoryFileSystem.GetFullPath(nupkgFile))
        {
            _packageFileSystem = new PhysicalFileSystem(repositoryFileSystem.GetFullPath(folder));
        }

        public string Path => _packageFileSystem.Root;

        protected List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            return base.GetSupportedFrameworks();
        }

        protected override IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference()
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        protected override IEnumerable<IPackageFile> GetFilesBase() => Files;

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var file in _packageFileSystem.GetFiles(string.Empty, "*", true))
            {
                if (PackageHelper.IsManifest(file) || PackageHelper.IsPackageFile(file))
                    continue;
                var packageFile = new PhysicalPackageFile()
                {
                    SourcePath = _packageFileSystem.GetFullPath(file)
                };
                try
                {
                    packageFile.TargetPath = file;
                }
                catch (ArgumentException)
                {
                    // Some packages contain invalid target framework names
                }
                yield return packageFile;
            }
        }
    }

    public class InstalledNuspecPackage : LocalPackage, IPackageWithPath
    {
        readonly IFileSystem _packageFileSystem;
        List<PhysicalPackageFile> _files;

        public InstalledNuspecPackage(IFileSystem repositoryFileSystem, string folder, string nuspecFile)
        {
            _packageFileSystem = new PhysicalFileSystem(repositoryFileSystem.GetFullPath(folder));
            var f = repositoryFileSystem.GetFullPath(nuspecFile);
            using (var stream = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.Read))
                ReadManifest(stream);
        }

        public string Path => _packageFileSystem.Root;

        protected List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            return base.GetSupportedFrameworks();
        }

        protected override IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference()
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        protected override IEnumerable<IPackageFile> GetFilesBase() => Files;

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var file in _packageFileSystem.GetFiles(string.Empty, "*", true))
            {
                if (PackageHelper.IsManifest(file) || PackageHelper.IsPackageFile(file))
                    continue;
                var packageFile = new PhysicalPackageFile()
                {
                    SourcePath = _packageFileSystem.GetFullPath(file)
                };
                try
                {
                    packageFile.TargetPath = file;
                }
                catch (ArgumentException)
                {
                    // Some packages contain invalid target framework names
                }
                yield return packageFile;
            }
        }

        public override Stream GetStream()
        {
            throw new NotImplementedException();
        }

        public override void ExtractContents(IFileSystem fileSystem, string extractPath)
        {
            throw new NotImplementedException();
        }
    }

    public class InstalledPackageRepository : PackageRepositoryBase
    {
        readonly IFileSystem _fileSystem;
        readonly FileSystemWatcher _watcher;
        IQueryable<IPackage> _packages;
        Timer _delayTimer = new Timer(2000) { AutoReset = false };

        public InstalledPackageRepository(DirectoryInfo repositoryFolder)
        {
            _fileSystem = new PhysicalFileSystem(repositoryFolder.FullName);
            _watcher = new FileSystemWatcher(repositoryFolder.FullName);
            _watcher.NotifyFilter = NotifyFilters.DirectoryName;
            _watcher.Created += HandlePathChanged;
            _watcher.Deleted += HandlePathChanged;
            _watcher.Changed += HandlePathChanged;
            _watcher.EnableRaisingEvents = true;

            _delayTimer.Elapsed += _delayTimer_Elapsed;
        }

        private void HandlePathChanged(object sender, FileSystemEventArgs e)
        {
            _delayTimer.Stop();
            _delayTimer.Start();
        }

        private void _delayTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // Reset the cache
            _packages = null;

            AssemblyLoader.InvalidateCache();
        }

        public override string Source => _fileSystem.Root;
        public override bool SupportsPrereleasePackages => true;
        public override IQueryable<IPackage> GetPackages()
        {
            if (_packages == null)
                _packages = GetPackagesCore().ToList().AsQueryable();
            return _packages;
        }<commit_msg>Fixed package folder not being watched if empty at beginning<commit_after>﻿using System;
using System.IO;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Versioning;
using NuGet;
using System.Diagnostics;
using System.Xml.Linq;
using System.Timers;
using System.Collections.Concurrent;

namespace VVVV.NuGetAssemblyLoader
{
    public interface IPackageWithPath : IPackage { string Path { get; } }

    public abstract class WatchedPackageRepositoryBase : PackageRepositoryBase
    {
        readonly FileSystemWatcher _watcher;
        Timer _delayTimer = new Timer(2000) { AutoReset = false };

        public WatchedPackageRepositoryBase(DirectoryInfo repositoryFolder)
        {
            _watcher = new FileSystemWatcher(repositoryFolder.FullName);
            _watcher.NotifyFilter = NotifyFilters.DirectoryName;
            _watcher.Created += HandlePathChanged;
            _watcher.Deleted += HandlePathChanged;
            _watcher.Changed += HandlePathChanged;
            _watcher.EnableRaisingEvents = true;

            _delayTimer.Elapsed += _delayTimer_Elapsed;

            void HandlePathChanged(object sender, FileSystemEventArgs e)
            {
                _delayTimer.Stop();
                _delayTimer.Start();
            }

            void _delayTimer_Elapsed(object sender, ElapsedEventArgs e)
            {
                ResetCache();

                AssemblyLoader.InvalidateCache();
            }
        }

        protected abstract void ResetCache();
    }

    public abstract class SrcPackage : IPackageWithPath
    {
        public abstract IEnumerable<IPackageAssemblyReference> AssemblyReferences { get; }
        public abstract IEnumerable<string> Authors { get; }
        public abstract string Copyright { get; }
        public abstract IEnumerable<PackageDependencySet> DependencySets { get; }
        public abstract string Description { get; }
        public abstract bool DevelopmentDependency { get; }
        public abstract int DownloadCount { get; }
        public abstract IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies { get; }
        public abstract Uri IconUrl { get; }
        public abstract string Id { get; }
        public abstract bool IsAbsoluteLatestVersion { get; }
        public abstract bool IsLatestVersion { get; }
        public abstract string Language { get; }
        public abstract Uri LicenseUrl { get; }
        public abstract bool Listed { get; }
        public abstract Version MinClientVersion { get; }
        public abstract IEnumerable<string> Owners { get; }
        public abstract ICollection<PackageReferenceSet> PackageAssemblyReferences { get; }
        public abstract string Path { get; }
        public abstract Uri ProjectUrl { get; }
        public abstract DateTimeOffset? Published { get; }
        public abstract string ReleaseNotes { get; }
        public abstract Uri ReportAbuseUrl { get; }
        public abstract bool RequireLicenseAcceptance { get; }
        public abstract string Summary { get; }
        public abstract string Tags { get; }
        public abstract string Title { get; }
        public abstract SemanticVersion Version { get; }

        public abstract void ExtractContents(IFileSystem fileSystem, string extractPath);
        public abstract IEnumerable<IPackageFile> GetFiles();
        public abstract Stream GetStream();
        public abstract IEnumerable<FrameworkName> GetSupportedFrameworks();
    }

    public class SrcPackageWithNuspec : SrcPackage
    {
        readonly IFileSystem _repositoryFileSystem;
        readonly string _packageName;
        readonly string _nuspecFile;
        PackageBuilder _builder;
        List<PhysicalPackageFile> _files;

        public SrcPackageWithNuspec(IFileSystem repositoryFileSystem, string packageName, string nuspecFile)
        {
            _repositoryFileSystem = repositoryFileSystem;
            _packageName = packageName;
            _nuspecFile = nuspecFile;
        }

        public string NuspecFile => _nuspecFile;

        public override string Path => _repositoryFileSystem.GetFullPath(_packageName);

        internal List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        private PackageBuilder Builder
        {
            get
            {
                if (_builder == null)
                {
                    var path = _repositoryFileSystem.GetFullPath(_nuspecFile);
                    try
                    {
                        _builder = new PackageBuilder(path, NullPropertyProvider.Instance, false);
                    }
                    catch (Exception e) when (e is FileNotFoundException || e is DirectoryNotFoundException)
                    {
                        // Create a dummy
                        _builder = new PackageBuilder();
                        Trace.TraceWarning($"The NuSpec file {path} seems to be corrupt: {e.Message}");
                    }
                }
                return _builder;
            }
        }

        public override bool IsAbsoluteLatestVersion => true;
        public override bool IsLatestVersion => true;
        public override bool Listed => false;
        public override DateTimeOffset? Published => null;
        public override IEnumerable<IPackageAssemblyReference> AssemblyReferences => GetAssemblyReferencesCore();
        public override string Title => Builder.Title;
        public override IEnumerable<string> Authors => Builder.Authors;
        public override IEnumerable<string> Owners => Builder.Owners;
        public override Uri IconUrl => Builder.IconUrl;
        public override Uri LicenseUrl => Builder.LicenseUrl;
        public override Uri ProjectUrl => Builder.ProjectUrl;
        public override bool RequireLicenseAcceptance => Builder.RequireLicenseAcceptance;
        public override bool DevelopmentDependency => Builder.DevelopmentDependency;
        public override string Description => Builder.Description;
        public override string Summary => Builder.Summary;
        public override string ReleaseNotes => Builder.ReleaseNotes;
        public override string Language => Builder.Language;
        public override string Tags => string.Join(", ", Builder.Tags);
        public override string Copyright => Builder.Copyright;
        public override IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies => Builder.FrameworkReferences;
        public override ICollection<PackageReferenceSet> PackageAssemblyReferences => Builder.PackageAssemblyReferences;
        public override IEnumerable<PackageDependencySet> DependencySets => Builder.DependencySets;
        public override Version MinClientVersion => Builder.MinClientVersion;
        public override string Id => _packageName;
        public override SemanticVersion Version => Builder.Version ?? new SemanticVersion(0, 0, 0, 0);
        public override Uri ReportAbuseUrl => null;
        public override int DownloadCount => -1;

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            return Builder.FrameworkReferences.SelectMany(f => f.SupportedFrameworks)
                .Concat(Files.SelectMany(f => f.SupportedFrameworks))
                .Distinct();
        }

        protected IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!AssemblyLoader.IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        public override IEnumerable<IPackageFile> GetFiles()
        {
            return Files;
        }

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var file in Builder.Files.OfType<PhysicalPackageFile>())
            {
                if (file.IsAssemblyFile())
                {
                    var sourcePath = file.SourcePath;
                    var sourceDir = System.IO.Path.GetDirectoryName(sourcePath);
                    if (sourceDir.EndsWith("Release") || sourceDir.EndsWith("Debug"))
                    {
                        var fileName = System.IO.Path.GetFileName(sourcePath);
                        var baseDir = System.IO.Path.GetDirectoryName(sourceDir);
                        var debugFile = System.IO.Path.Combine(baseDir, "Debug", fileName);
                        var releaseFile = System.IO.Path.Combine(baseDir, "Release", fileName);
                        var debugTime = File.Exists(debugFile) ? File.GetLastWriteTime(debugFile) : DateTime.MinValue;
                        var releaseTime = File.Exists(releaseFile) ? File.GetLastWriteTime(releaseFile) : DateTime.MinValue;
                        if (releaseTime > debugTime)
                            file.SourcePath = releaseFile;
                        else if (debugTime > releaseTime)
                            file.SourcePath = debugFile;
                    }
                }
                yield return file;
            }
        }

        public override Stream GetStream()
        {
            throw new NotImplementedException();
        }

        public override void ExtractContents(IFileSystem fileSystem, string extractPath)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            return this.GetFullName();
        }
    }

    public class SrcPackageWithoutNuspec : SrcPackage
    {
        readonly IFileSystem _packageFileSystem;
        readonly string _packageName;
        readonly string _vlFile;
        XDocument _mainFile;
        List<PhysicalPackageFile> _files;

        public SrcPackageWithoutNuspec(IFileSystem repositoryFileSystem, string packageName, string vlFile)
        {
            _packageFileSystem = new PhysicalFileSystem(repositoryFileSystem.GetFullPath(packageName));
            _packageName = packageName;
            _vlFile = repositoryFileSystem.GetFullPath(vlFile);
        }

        public override string Path => _packageFileSystem.Root;

        public XDocument MainFile => _mainFile ?? (_mainFile = XDocument.Load(_vlFile));

        internal List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        public override bool IsAbsoluteLatestVersion => true;
        public override bool IsLatestVersion => true;
        public override bool Listed => false;
        public override DateTimeOffset? Published => null;
        public override IEnumerable<IPackageAssemblyReference> AssemblyReferences => GetAssemblyReferencesCore();
        public override string Title => null;
        public override IEnumerable<string> Authors => Enumerable.Empty<string>();
        public override IEnumerable<string> Owners => Enumerable.Empty<string>();
        public override Uri IconUrl => null;
        public override Uri LicenseUrl => null;
        public override Uri ProjectUrl => null;
        public override bool RequireLicenseAcceptance => false;
        public override bool DevelopmentDependency => false;
        public override string Description => null;
        public override string Summary => null;
        public override string ReleaseNotes => null;
        public override string Language => null;
        public override string Tags => null;
        public override string Copyright => null;
        public override IEnumerable<FrameworkAssemblyReference> FrameworkAssemblies => Enumerable.Empty<FrameworkAssemblyReference>();
        public override ICollection<PackageReferenceSet> PackageAssemblyReferences => Array.Empty<PackageReferenceSet>();

        public override IEnumerable<PackageDependencySet> DependencySets
        {
            get
            {
                var dependencies = MainFile.Root.Elements("NugetDependency")
                    .Select(d => d.Attribute("Location") != null ? new PackageDependency(d.Attribute("Location").Value) : null)
                    .Where(d => d != null);
                yield return new PackageDependencySet(AssemblyLoader.ExecutingFrameworkName, dependencies);
            }
        }

        public override Version MinClientVersion => new Version(0, 0, 0);
        public override string Id => _packageName;

        public override SemanticVersion Version
        {
            get
            {
                //var versionAttribute = MainFile.Root.Attribute("Version");
                //if (versionAttribute != null)
                //{
                //    SemanticVersion result;
                //    if (SemanticVersion.TryParse(versionAttribute.Value, out result))
                //        return result;
                //}
                return new SemanticVersion(0, 0, 0, 0);
            }
        }

        public override Uri ReportAbuseUrl => null;
        public override int DownloadCount => -1;

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            yield return AssemblyLoader.ExecutingFrameworkName;
        }

        protected IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!AssemblyLoader.IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        public override IEnumerable<IPackageFile> GetFiles()
        {
            return Files;
        }

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var f in _packageFileSystem.GetFiles("", "*", true))
            {
                yield return new PhysicalPackageFile()
                {
                    SourcePath = _packageFileSystem.GetFullPath(f),
                    TargetPath = f
                };
            }
        }

        public override Stream GetStream()
        {
            throw new NotImplementedException();
        }

        public override void ExtractContents(IFileSystem fileSystem, string extractPath)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            return this.GetFullName();
        }
    }

    public class SrcPackageRepository : WatchedPackageRepositoryBase
    {
        readonly DirectoryInfo _repositoryFolder;
        readonly IFileSystem _fileSystem;
        IQueryable<IPackage> _packages;

        public SrcPackageRepository(DirectoryInfo repositoryFolder) : base(repositoryFolder)
        {
            _repositoryFolder = repositoryFolder;
            _fileSystem = new PhysicalFileSystem(repositoryFolder.FullName);
        }

        protected override void ResetCache()
        {
            _packages = null;
        }

        public override string Source => _repositoryFolder.FullName;

        public override bool SupportsPrereleasePackages => true;

        public override IQueryable<IPackage> GetPackages()
        {
            return Packages;
        }

        private IQueryable<IPackage> Packages
        {
            get
            {
                if (_packages == null)
                    _packages = GetPackagesCore().ToList().AsQueryable();
                return _packages;
            }
        }

        private IEnumerable<IPackage> GetPackagesCore()
        {
            foreach (var dir in _fileSystem.GetDirectories(string.Empty))
            {
                var hasNuspec = false;
                if (!hasNuspec)
                {
                    // VL.CoreLib/src/bin/$(Configuration)/$(TFM)/VL.CoreLib.nuspec
                    // VL.CoreLib/bin/$(Configuration)/$(TFM)/VL.CoreLib.nuspec
                    var nuspecFiles = _fileSystem.GetDirectories(Path.Combine(dir, "src", "bin"))
                        .Concat(_fileSystem.GetDirectories(Path.Combine(dir, "bin")))
                        .SelectMany(d => _fileSystem.GetDirectories(d))
                        .SelectMany(d => _fileSystem.GetFiles(d, $"{dir}{Constants.ManifestExtension}"))
                        .Select(f => new { File = f, Modified = File.GetLastWriteTime(_fileSystem.GetFullPath(f)) })
                        .OrderByDescending(f => f.Modified);
                    foreach (var nuspecFile in nuspecFiles)
                    {
                        hasNuspec = true;
                        yield return new SrcPackageWithNuspec(_fileSystem, dir, nuspecFile.File);
                        break;
                    }
                }
                if (!hasNuspec)
                {
                    // VL.CoreLib/VL.CoreLib.nusepc
                    foreach (var nuspecFile in _fileSystem.GetFiles(dir, $"{dir}{Constants.ManifestExtension}"))
                    {
                        hasNuspec = true;
                        yield return new SrcPackageWithNuspec(_fileSystem, dir, nuspecFile);
                        break;
                    }
                }
                if (!hasNuspec)
                {
                    foreach (var vlFile in _fileSystem.GetFiles(dir, $"{dir}.vl"))
                    {
                        hasNuspec = true;
                        yield return new SrcPackageWithoutNuspec(_fileSystem, dir, vlFile);
                        break;
                    }
                }
            }
        }
    }

    public class InstalledNupkgPackage : ZipPackage, IPackageWithPath
    {
        readonly IFileSystem _packageFileSystem;
        List<PhysicalPackageFile> _files;

        public InstalledNupkgPackage(IFileSystem repositoryFileSystem, string folder, string nupkgFile)
            : base(repositoryFileSystem.GetFullPath(nupkgFile))
        {
            _packageFileSystem = new PhysicalFileSystem(repositoryFileSystem.GetFullPath(folder));
        }

        public string Path => _packageFileSystem.Root;

        protected List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            return base.GetSupportedFrameworks();
        }

        protected override IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference()
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        protected override IEnumerable<IPackageFile> GetFilesBase() => Files;

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var file in _packageFileSystem.GetFiles(string.Empty, "*", true))
            {
                if (PackageHelper.IsManifest(file) || PackageHelper.IsPackageFile(file))
                    continue;
                var packageFile = new PhysicalPackageFile()
                {
                    SourcePath = _packageFileSystem.GetFullPath(file)
                };
                try
                {
                    packageFile.TargetPath = file;
                }
                catch (ArgumentException)
                {
                    // Some packages contain invalid target framework names
                }
                yield return packageFile;
            }
        }
    }

    public class InstalledNuspecPackage : LocalPackage, IPackageWithPath
    {
        readonly IFileSystem _packageFileSystem;
        List<PhysicalPackageFile> _files;

        public InstalledNuspecPackage(IFileSystem repositoryFileSystem, string folder, string nuspecFile)
        {
            _packageFileSystem = new PhysicalFileSystem(repositoryFileSystem.GetFullPath(folder));
            var f = repositoryFileSystem.GetFullPath(nuspecFile);
            using (var stream = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.Read))
                ReadManifest(stream);
        }

        public string Path => _packageFileSystem.Root;

        protected List<PhysicalPackageFile> Files
        {
            get
            {
                if (_files == null)
                    _files = GetFilesCore().ToList();
                return _files;
            }
        }

        public override IEnumerable<FrameworkName> GetSupportedFrameworks()
        {
            return base.GetSupportedFrameworks();
        }

        protected override IEnumerable<IPackageAssemblyReference> GetAssemblyReferencesCore()
        {
            foreach (var file in Files)
            {
                if (!IsAssemblyReference(file.Path))
                    continue;
                yield return new PhysicalPackageAssemblyReference()
                {
                    SourcePath = file.SourcePath,
                    TargetPath = file.TargetPath
                };
            }
        }

        protected override IEnumerable<IPackageFile> GetFilesBase() => Files;

        private IEnumerable<PhysicalPackageFile> GetFilesCore()
        {
            foreach (var file in _packageFileSystem.GetFiles(string.Empty, "*", true))
            {
                if (PackageHelper.IsManifest(file) || PackageHelper.IsPackageFile(file))
                    continue;
                var packageFile = new PhysicalPackageFile()
                {
                    SourcePath = _packageFileSystem.GetFullPath(file)
                };
                try
                {
                    packageFile.TargetPath = file;
                }
                catch (ArgumentException)
                {
                    // Some packages contain invalid target framework names
                }
                yield return packageFile;
            }
        }

        public override Stream GetStream()
        {
            throw new NotImplementedException();
        }

        public override void ExtractContents(IFileSystem fileSystem, string extractPath)
        {
            throw new NotImplementedException();
        }
    }

    public class InstalledPackageRepository : WatchedPackageRepositoryBase
    {
        readonly IFileSystem _fileSystem;
        IQueryable<IPackage> _packages;

        public InstalledPackageRepository(DirectoryInfo repositoryFolder) : base(repositoryFolder)
        {
            _fileSystem = new PhysicalFileSystem(repositoryFolder.FullName);
        }

        protected override void ResetCache()
        {
            _packages = null;
        }

        public override string Source => _fileSystem.Root;
        public override bool SupportsPrereleasePackages => true;
        public override IQueryable<IPackage> GetPackages()
        {
            if (_packages == null)
                _packages = GetPackagesCore().ToList().AsQueryable();
            return _packages;
        }
{'fraction_non_alphanumeric': 0.07009644930010242, 'fraction_numerical': 0.0007255035848412428, 'mean_word_length': 1.8106633081444166, 'pattern_counts': {'":': 0, '<': 113, '<?xml version=': 0, '>': 261, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6601861', 'n_tokens_mistral': 10943, 'n_tokens_neox': 10294, 'n_words': 2603}