z_mirror/fmm
git clone https://git.raiguard.me/z_mirror/fmm
76c75f2
trunk
1package fmm 2 3import ( 4"encoding/json" 5"fmt" 6"strings" 7) 8 9type Dependency struct { 10Name string 11Version * Version 12Kind DependencyKind 13Req VersionCmpRes 14} 15 16type DependencyKind uint8 17 18const ( 19DependencyRequired DependencyKind = iota 20DependencyOptional 21DependencyHiddenOptional 22DependencyIncompatible 23DependencyNoLoadOrder 24DependencyRecommended 25) 26 27var dependencyKindString = map [DependencyKind ]string { 28DependencyOptional :"? " , 29DependencyHiddenOptional :"(?) " , 30DependencyIncompatible :"! " , 31DependencyNoLoadOrder :"~ " , 32DependencyRecommended :"+ " , 33} 34 35func NewDependency (input string ) (* Dependency ,error ) { 36input = strings .TrimSpace (input ) 37 38kind := DependencyRequired 39if strings .HasPrefix (input ,"!" ) { 40kind = DependencyIncompatible 41input = strings .TrimPrefix (input ,"!" ) 42 }else if strings .HasPrefix (input ,"?" ) { 43kind = DependencyOptional 44input = strings .TrimPrefix (input ,"?" ) 45 }else if strings .HasPrefix (input ,"(?)" ) { 46kind = DependencyHiddenOptional 47input = strings .TrimPrefix (input ,"(?)" ) 48 }else if strings .HasPrefix (input ,"~" ) { 49kind = DependencyNoLoadOrder 50input = strings .TrimPrefix (input ,"~" ) 51 }else if strings .HasPrefix (input ,"+" ) { 52kind = DependencyRecommended 53input = strings .TrimPrefix (input ,"+" ) 54 } 55 56// Iterate in reverse and find the first non-digit and non-dot 57var ver * Version 58for i := len (input )- 1 ;i >= 0 ;i -- { 59if i > 0 && ! (input [i ]== '.' || (input [i ]>= '0' && input [i ]<= '9' )) { 60parsed ,err := NewVersion (input [i + 1 :]) 61if err == nil { 62ver = parsed 63input = strings .TrimSpace (input [:i + 1 ]) 64 } 65break 66 } 67 } 68 69req := VersionAny 70if strings .HasSuffix (input ,"<=" ) { 71req = VersionLtEq 72input = strings .TrimSuffix (input ,"<=" ) 73 }else if strings .Contains (input ,"<" ) { 74req = VersionLt 75input = strings .TrimSuffix (input ,"<" ) 76 }else if strings .Contains (input ,">=" ) { 77req = VersionGtEq 78input = strings .TrimSuffix (input ,">=" ) 79 }else if strings .Contains (input ,">" ) { 80req = VersionGt 81input = strings .TrimSuffix (input ,">" ) 82 }else if strings .Contains (input ,"=" ) { 83req = VersionEq 84input = strings .TrimSuffix (input ,"=" ) 85 } 86 87name := strings .TrimSpace (input ) 88 89return & Dependency {name ,ver ,kind ,req },nil 90} 91 92func (d * Dependency )Test (ver * Version )bool { 93if ver == nil { 94return true 95 } 96 97if d .Kind == DependencyIncompatible { 98return false 99 } 100 101if d .Req == VersionAny { 102return true 103 } 104 105return d .Req & ver .Cmp (d .Version )> 0 106} 107 108func (d * Dependency )ToString ()string { 109versionStr := "" 110if d .Version != nil { 111versionStr = d .Version .ToString (false ) 112 } 113return fmt .Sprintf ("%s%s %s %s" ,dependencyKindString [d .Kind ],d .Name ,versionCmpResString [d .Req ],versionStr ) 114} 115 116func (d * Dependency )UnmarshalJSON (data []byte )error { 117var s string 118if err := json .Unmarshal (data ,& s );err != nil { 119return err 120 } 121 122dep ,err := NewDependency (s ) 123if err != nil { 124return err 125 } 126 127d .Name = dep .Name 128d .Version = dep .Version 129d .Kind = dep .Kind 130d .Req = dep .Req 131 132return nil 133}