<commit_before>﻿namespace Paket

open System
open System.Xml
open System.IO
open Xml
open Paket.Requirements
open Paket.Domain

///  Nuspec reference type inside of nuspec files.
[<RequireQualifiedAccess>]
type NuspecReferences = 
    | All
    | Explicit of string list

/// Framework assembly reference inside of nuspec files.
type FrameworkAssemblyReference = {
    AssemblyName: string
    FrameworkRestrictions : FrameworkRestrictions }

module internal NuSpecParserHelper =
    let getDependency fileName node = 
        let name = 
            match node |> getAttribute "id" with
            | Some name -> PackageName name
            | None -> failwithf "unable to find dependency id in %s" fileName
        let version = 
            match node |> getAttribute "version" with
            | Some version -> VersionRequirement.Parse version
            | None ->         VersionRequirement.Parse "0"
        let restriction =
            let parent = node.ParentNode 
            match parent.Name.ToLower(), parent |> getAttribute "targetFramework" with
            | "group", Some framework -> 
                match FrameworkDetection.Extract framework with
                | Some x -> [FrameworkRestriction.Exactly x]
                | None -> []
            | _ -> []
        name,version,restriction

    let getAssemblyRefs node =
        let name = node |> getAttribute "assemblyName"
        let targetFrameworks = node |> getAttribute "targetFramework"
        match name,targetFrameworks with
        | Some name, Some targetFrameworks when targetFrameworks = "" ->
            [{ AssemblyName = name; FrameworkRestrictions = [] }]
        | Some name, None ->
            [{ AssemblyName = name; FrameworkRestrictions = [] }]
        | Some name, Some targetFrameworks ->
            targetFrameworks.Split([|','; ' '|],System.StringSplitOptions.RemoveEmptyEntries)
            |> Array.choose FrameworkDetection.Extract
            |> Array.map (fun fw -> { AssemblyName = name; FrameworkRestrictions = [FrameworkRestriction.Exactly fw] })
            |> Array.toList
        | _ -> []

type Nuspec = 
    { References : NuspecReferences 
      Dependencies : (PackageName * VersionRequirement * FrameworkRestrictions) list
      OfficialName : string
      LicenseUrl : string
      IsDevelopmentDependency : bool
      FrameworkAssemblyReferences : FrameworkAssemblyReference list }

    static member All = { References = NuspecReferences.All; Dependencies = []; FrameworkAssemblyReferences = []; OfficialName = ""; LicenseUrl = ""; IsDevelopmentDependency = false }
    static member Explicit references = { References = NuspecReferences.Explicit references; Dependencies = []; FrameworkAssemblyReferences = []; OfficialName = ""; LicenseUrl = ""; IsDevelopmentDependency = false }

    static member Load(root,groupName,version,includeVersionInPath,name:PackageName) =
        let folder = DirectoryInfo(getTargetFolder root groupName name version includeVersionInPath).FullName
        let nuspec = Path.Combine(folder,sprintf "%O.nuspec" name)
        Nuspec.Load nuspec

    static member Load(fileName : string) = 
        let fi = FileInfo(fileName)
        if not fi.Exists then Nuspec.All
        else 
            let doc = new XmlDocument()
            try
                doc.Load fi.FullName
            with
            | exn -> failwithf "Could not load %s. Message: %s" fi.FullName exn.Message

            let frameworks =
                doc 
                |> getDescendants "group" 
                |> List.map (fun node ->
                    match node |> getAttribute "targetFramework" with
                    | Some framework ->
                        match FrameworkDetection.Extract framework with
                        | Some x -> [PackageName "",VersionRequirement.NoRestriction,[FrameworkRestriction.Exactly x]]
                        | None -> []
                    | _ -> [])
                |> List.concat

            let dependencies = 
                doc 
                |> getDescendants "dependency"
                |> List.map (NuSpecParserHelper.getDependency fileName)
                |> List.append frameworks
                |> Requirements.optimizeDependencies 
            
            let references = 
                doc
                |> getDescendants "reference"
                |> List.choose (getAttribute "file")
           
            { References = if references = [] then NuspecReferences.All else NuspecReferences.Explicit references
              Dependencies = dependencies
              OfficialName = 
                match doc |> getNode "package" |> optGetNode "metadata" |> optGetNode "id" with
                | Some node -> node.InnerText
                | None -> failwithf "unable to find package id in %s" fileName
              LicenseUrl = 
                match doc |> getNode "package" |> optGetNode "metadata" |> optGetNode "licenseUrl" with
                | Some link -> link.InnerText
                | None -> ""
              IsDevelopmentDependency =
                match doc |> getNode "package" |> optGetNode "metadata" |> optGetNode "developmentDependency" with
                | Some link -> link.InnerText.ToLower() = "true"
                | None -> false
              FrameworkAssemblyReferences = 
                let grouped =
                    doc
                    |> getDescendants "frameworkAssembly"
                    |> List.collect NuSpecParserHelper.getAssemblyRefs
                    |> List.groupBy (fun r -> r.AssemblyName)

                [for name,restrictions in grouped do
                    yield { AssemblyName = name
                            FrameworkRestrictions = List.collect (fun x -> x.FrameworkRestrictions) restrictions } ] }<commit_msg>work around mono bug https://github.com/fsprojects/Paket/issues/1189<commit_after>﻿namespace Paket

open System
open System.Xml
open System.IO
open Xml
open Paket.Requirements
open Paket.Domain

///  Nuspec reference type inside of nuspec files.
[<RequireQualifiedAccess>]
type NuspecReferences = 
    | All
    | Explicit of string list

/// Framework assembly reference inside of nuspec files.
type FrameworkAssemblyReference = {
    AssemblyName: string
    FrameworkRestrictions : FrameworkRestrictions }

module internal NuSpecParserHelper =
    let getDependency fileName node = 
        let name = 
            match node |> getAttribute "id" with
            | Some name -> PackageName name
            | None -> failwithf "unable to find dependency id in %s" fileName
        let version = 
            match node |> getAttribute "version" with
            | Some version -> VersionRequirement.Parse version
            | None ->         VersionRequirement.Parse "0"
        let restriction =
            let parent = node.ParentNode 
            match parent.Name.ToLower(), parent |> getAttribute "targetFramework" with
            | "group", Some framework -> 
                match FrameworkDetection.Extract framework with
                | Some x -> [FrameworkRestriction.Exactly x]
                | None -> []
            | _ -> []
        name,version,restriction

    let getAssemblyRefs node =
        let name = node |> getAttribute "assemblyName"
        let targetFrameworks = node |> getAttribute "targetFramework"
        match name,targetFrameworks with
        | Some name, Some targetFrameworks when targetFrameworks = "" ->
            [{ AssemblyName = name; FrameworkRestrictions = [] }]
        | Some name, None ->
            [{ AssemblyName = name; FrameworkRestrictions = [] }]
        | Some name, Some targetFrameworks ->
            targetFrameworks.Split([|','; ' '|],System.StringSplitOptions.RemoveEmptyEntries)
            |> Array.choose FrameworkDetection.Extract
            |> Array.map (fun fw -> { AssemblyName = name; FrameworkRestrictions = [FrameworkRestriction.Exactly fw] })
            |> Array.toList
        | _ -> []

type Nuspec = 
    { References : NuspecReferences 
      Dependencies : (PackageName * VersionRequirement * FrameworkRestrictions) list
      OfficialName : string
      LicenseUrl : string
      IsDevelopmentDependency : bool
      FrameworkAssemblyReferences : FrameworkAssemblyReference list }

    static member All = { References = NuspecReferences.All; Dependencies = []; FrameworkAssemblyReferences = []; OfficialName = ""; LicenseUrl = ""; IsDevelopmentDependency = false }
    static member Explicit references = { References = NuspecReferences.Explicit references; Dependencies = []; FrameworkAssemblyReferences = []; OfficialName = ""; LicenseUrl = ""; IsDevelopmentDependency = false }

    static member Load(root,groupName,version,includeVersionInPath,name:PackageName) =
        let folder = DirectoryInfo(getTargetFolder root groupName name version includeVersionInPath).FullName
        let nuspec = Path.Combine(folder,sprintf "%O.nuspec" name)
        Nuspec.Load nuspec

    static member Load(fileName : string) = 
        let fi = FileInfo(fileName)
        if not fi.Exists then Nuspec.All
        else 
            let doc = new XmlDocument()
            try
                doc.Load fi.FullName
            with
            | exn -> 
                let text = File.ReadAllText(fi.FullName)  // work around mono bug https://github.com/fsprojects/Paket/issues/1189
                doc.LoadXml(text)

            let frameworks =
                doc 
                |> getDescendants "group" 
                |> List.map (fun node ->
                    match node |> getAttribute "targetFramework" with
                    | Some framework ->
                        match FrameworkDetection.Extract framework with
                        | Some x -> [PackageName "",VersionRequirement.NoRestriction,[FrameworkRestriction.Exactly x]]
                        | None -> []
                    | _ -> [])
                |> List.concat

            let dependencies = 
                doc 
                |> getDescendants "dependency"
                |> List.map (NuSpecParserHelper.getDependency fileName)
                |> List.append frameworks
                |> Requirements.optimizeDependencies 
            
            let references = 
                doc
                |> getDescendants "reference"
                |> List.choose (getAttribute "file")
           
            { References = if references = [] then NuspecReferences.All else NuspecReferences.Explicit references
              Dependencies = dependencies
              OfficialName = 
                match doc |> getNode "package" |> optGetNode "metadata" |> optGetNode "id" with
                | Some node -> node.InnerText
                | None -> failwithf "unable to find package id in %s" fileName
              LicenseUrl = 
                match doc |> getNode "package" |> optGetNode "metadata" |> optGetNode "licenseUrl" with
                | Some link -> link.InnerText
                | None -> ""
              IsDevelopmentDependency =
                match doc |> getNode "package" |> optGetNode "metadata" |> optGetNode "developmentDependency" with
                | Some link -> link.InnerText.ToLower() = "true"
                | None -> false
              FrameworkAssemblyReferences = 
                let grouped =
                    doc
                    |> getDescendants "frameworkAssembly"
                    |> List.collect NuSpecParserHelper.getAssemblyRefs
                    |> List.groupBy (fun r -> r.AssemblyName)

                [for name,restrictions in grouped do
                    yield { AssemblyName = name
                            FrameworkRestrictions = List.collect (fun x -> x.FrameworkRestrictions) restrictions } ] }
{'fraction_non_alphanumeric': 0.08251807741386644, 'fraction_numerical': 0.0008507018290089324, 'mean_word_length': 1.923650833126088, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 119, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6240846', 'n_tokens_mistral': 2993, 'n_tokens_neox': 2693, 'n_words': 766}