@@ -17,8 +17,10 @@ import (
17
17
"reflect"
18
18
"regexp"
19
19
"runtime"
20
+ "sort"
20
21
"strconv"
21
22
"strings"
23
+ "unicode"
22
24
23
25
"github.com/layer5io/meshkit/models/meshmodel/entity"
24
26
log "github.com/sirupsen/logrus"
@@ -400,7 +402,9 @@ func CreateDirectory(path string) error {
400
402
func ReplaceSpacesAndConvertToLowercase (s string ) string {
401
403
return strings .ToLower (strings .ReplaceAll (s , " " , "" ))
402
404
}
403
-
405
+ func ReplaceSpacesWithHyphenAndConvertToLowercase (s string ) string {
406
+ return strings .ToLower (strings .ReplaceAll (s , " " , "-" ))
407
+ }
404
408
func ExtractDomainFromURL (location string ) string {
405
409
parsedURL , err := url .Parse (location )
406
410
// If unable to extract domain return the location as is.
@@ -586,3 +590,129 @@ func Compress(src string, buf io.Writer) error {
586
590
return nil
587
591
})
588
592
}
593
+
594
+ // Check if a string is purely numeric
595
+ func isNumeric (s string ) bool {
596
+ for _ , r := range s {
597
+ if ! unicode .IsDigit (r ) {
598
+ return false
599
+ }
600
+ }
601
+ return true
602
+ }
603
+
604
+ // Split version into components (numeric and non-numeric) using both '.' and '-'
605
+ func splitVersion (version string ) []string {
606
+ version = strings .ReplaceAll (version , "-" , "." )
607
+ return strings .Split (version , "." )
608
+ }
609
+
610
+ // Compare two version strings
611
+ func compareVersions (v1 , v2 string ) int {
612
+ v1Components := splitVersion (v1 )
613
+ v2Components := splitVersion (v2 )
614
+
615
+ maxLen := len (v1Components )
616
+ if len (v2Components ) > maxLen {
617
+ maxLen = len (v2Components )
618
+ }
619
+
620
+ for i := 0 ; i < maxLen ; i ++ {
621
+ var part1 , part2 string
622
+ if i < len (v1Components ) {
623
+ part1 = v1Components [i ]
624
+ }
625
+ if i < len (v2Components ) {
626
+ part2 = v2Components [i ]
627
+ }
628
+
629
+ if isNumeric (part1 ) && isNumeric (part2 ) {
630
+ num1 , _ := strconv .Atoi (part1 )
631
+ num2 , _ := strconv .Atoi (part2 )
632
+ if num1 != num2 {
633
+ return num1 - num2
634
+ }
635
+ } else if isNumeric (part1 ) && ! isNumeric (part2 ) {
636
+ return - 1
637
+ } else if ! isNumeric (part1 ) && isNumeric (part2 ) {
638
+ return 1
639
+ } else {
640
+ if part1 != part2 {
641
+ return strings .Compare (part1 , part2 )
642
+ }
643
+ }
644
+ }
645
+
646
+ return 0
647
+ }
648
+
649
+ // Function to get all version directories sorted in descending order
650
+ func GetAllVersionDirsSortedDesc (modelVersionsDirPath string ) ([]string , error ) {
651
+ type versionInfo struct {
652
+ original string
653
+ dirPath string
654
+ }
655
+ entries , err := os .ReadDir (modelVersionsDirPath )
656
+ if err != nil {
657
+ return nil , fmt .Errorf ("failed to read versions directory '%s': %w" , modelVersionsDirPath , err )
658
+ }
659
+
660
+ if len (entries ) == 0 {
661
+ return nil , fmt .Errorf ("no version directories found in '%s'" , modelVersionsDirPath )
662
+ }
663
+
664
+ versions := []versionInfo {}
665
+ for _ , entry := range entries {
666
+ if ! entry .IsDir () {
667
+ continue
668
+ }
669
+
670
+ versionDirPath := filepath .Join (modelVersionsDirPath , entry .Name ())
671
+ versionStr := entry .Name ()
672
+
673
+ // Optionally remove leading 'v'
674
+ versionStr = strings .TrimPrefix (versionStr , "v" )
675
+
676
+ if versionStr == "" {
677
+ continue
678
+ }
679
+
680
+ versions = append (versions , versionInfo {
681
+ original : versionStr ,
682
+ dirPath : versionDirPath ,
683
+ })
684
+ }
685
+
686
+ if len (versions ) == 0 {
687
+ return nil , fmt .Errorf ("no valid version directories found in '%s'" , modelVersionsDirPath )
688
+ }
689
+
690
+ sort .Slice (versions , func (i , j int ) bool {
691
+ return compareVersions (versions [i ].original , versions [j ].original ) > 0
692
+ })
693
+
694
+ sortedDirPaths := make ([]string , len (versions ))
695
+ for i , v := range versions {
696
+ sortedDirPaths [i ] = v .dirPath
697
+ }
698
+
699
+ return sortedDirPaths , nil
700
+ }
701
+
702
+ // isDirectoryNonEmpty checks if a directory exists and is non-empty
703
+ func IsDirectoryNonEmpty (dirPath string ) bool {
704
+ fi , err := os .Stat (dirPath )
705
+ if err != nil {
706
+ return false
707
+ }
708
+ if ! fi .IsDir () {
709
+ return false
710
+ }
711
+
712
+ entries , err := os .ReadDir (dirPath )
713
+ if err != nil {
714
+ return false
715
+ }
716
+
717
+ return len (entries ) > 0
718
+ }
0 commit comments