@@ -28,6 +28,7 @@ import (
2828 "regexp"
2929 "strconv"
3030 "strings"
31+ "sync"
3132 "time"
3233
3334 "github.com/apache/skywalking-eyes/pkg/logger"
@@ -447,44 +448,73 @@ func parseGemspecDependencies(path string) ([]string, error) {
447448 return deps , scanner .Err ()
448449}
449450
450- func findInstalledGemspec (name , version string ) (string , error ) {
451+ var (
452+ gemspecsCache map [string ][]string
453+ gemspecsCacheLock sync.Mutex
454+ )
455+
456+ func getAllGemspecs () []string {
457+ env := os .Getenv ("GEM_PATH" )
458+ if env == "" {
459+ env = os .Getenv ("GEM_HOME" )
460+ }
461+
462+ gemspecsCacheLock .Lock ()
463+ defer gemspecsCacheLock .Unlock ()
464+
465+ if gemspecsCache == nil {
466+ gemspecsCache = make (map [string ][]string )
467+ }
468+
469+ if cached , ok := gemspecsCache [env ]; ok {
470+ return cached
471+ }
472+
473+ var allGemspecs []string
451474 gemPaths := getGemPaths ()
452475 for _ , dir := range gemPaths {
453476 specsDir := filepath .Join (dir , "specifications" )
477+ entries , err := os .ReadDir (specsDir )
478+ if err != nil {
479+ continue
480+ }
481+ for _ , e := range entries {
482+ if ! e .IsDir () && strings .HasSuffix (e .Name (), ".gemspec" ) {
483+ allGemspecs = append (allGemspecs , filepath .Join (specsDir , e .Name ()))
484+ }
485+ }
486+ }
487+ gemspecsCache [env ] = allGemspecs
488+ return allGemspecs
489+ }
490+
491+ func findInstalledGemspec (name , version string ) (string , error ) {
492+ gems := getAllGemspecs ()
493+ for _ , path := range gems {
494+ filename := filepath .Base (path )
454495 if version != "" && rubyVersionRe .MatchString (version ) {
455- path := filepath .Join (specsDir , name + "-" + version + ".gemspec" )
456- if _ , err := os .Stat (path ); err == nil {
496+ if filename == name + "-" + version + ".gemspec" {
457497 return path , nil
458498 }
459499 } else {
460- entries , err := os .ReadDir (specsDir )
461- if err != nil {
500+ if ! strings .HasPrefix (filename , name + "-" ) {
462501 continue
463502 }
464- for _ , e := range entries {
465- if e .IsDir () || ! strings .HasPrefix (e .Name (), name + "-" ) || ! strings .HasSuffix (e .Name (), ".gemspec" ) {
466- continue
467- }
468- stem := strings .TrimSuffix (e .Name (), ".gemspec" )
469- // Ensure that the character immediately after the "name-" prefix
470- // is a digit, so we only consider filenames where the suffix is
471- // a version component (e.g., "foo-1.0.0.gemspec") and avoid
472- // similar names like "foo-bar-1.0.0.gemspec" when searching for "foo".
473- if len (stem ) <= len (name )+ 1 {
474- continue
475- }
476- versionStart := stem [len (name )+ 1 ]
477- if versionStart < '0' || versionStart > '9' {
478- continue
479- }
480- ver := strings .TrimPrefix (stem , name + "-" )
481- if ver == stem {
482- continue
483- }
484- path := filepath .Join (specsDir , e .Name ())
485- if specName , _ , err := parseGemspecInfo (path ); err == nil && specName == name {
486- return path , nil
487- }
503+ stem := strings .TrimSuffix (filename , ".gemspec" )
504+ // Ensure that the character immediately after the "name-" prefix
505+ // is a digit, so we only consider filenames where the suffix is
506+ // a version component (e.g., "foo-1.0.0.gemspec") and avoid
507+ // similar names like "foo-bar-1.0.0.gemspec" when searching for "foo".
508+ if len (stem ) <= len (name )+ 1 {
509+ continue
510+ }
511+ versionStart := stem [len (name )+ 1 ]
512+ if versionStart < '0' || versionStart > '9' {
513+ continue
514+ }
515+
516+ if specName , _ , err := parseGemspecInfo (path ); err == nil && specName == name {
517+ return path , nil
488518 }
489519 }
490520 }
@@ -510,35 +540,29 @@ func fetchLocalLicense(dir, targetName string) (string, error) {
510540}
511541
512542func fetchInstalledLicense (name , version string ) string {
513- gemPaths := getGemPaths ()
514- for _ , dir := range gemPaths {
515- specsDir := filepath .Join ( dir , "specifications" )
543+ gems := getAllGemspecs ()
544+ for _ , path := range gems {
545+ filename := filepath .Base ( path )
516546 // If version is specific
517547 if version != "" && rubyVersionRe .MatchString (version ) {
518- path := filepath .Join (specsDir , name + "-" + version + ".gemspec" )
519- if _ , license , err := parseGemspecInfo (path ); err == nil && license != "" {
520- return license
548+ if filename == name + "-" + version + ".gemspec" {
549+ if _ , license , err := parseGemspecInfo (path ); err == nil && license != "" {
550+ return license
551+ }
521552 }
522553 } else {
523554 // Scan for any version
524- entries , err := os .ReadDir (specsDir )
525- if err != nil {
555+ if ! strings .HasPrefix (filename , name + "-" ) {
526556 continue
527557 }
528- for _ , e := range entries {
529- if e .IsDir () || ! strings .HasPrefix (e .Name (), name + "-" ) || ! strings .HasSuffix (e .Name (), ".gemspec" ) {
530- continue
531- }
532- stem := strings .TrimSuffix (e .Name (), ".gemspec" )
533- ver := strings .TrimPrefix (stem , name + "-" )
534- // Ensure the character after the gem name corresponds to the start of a version
535- if ver == "" || ver [0 ] < '0' || ver [0 ] > '9' {
536- continue
537- }
538- path := filepath .Join (specsDir , e .Name ())
539- if specName , license , err := parseGemspecInfo (path ); err == nil && specName == name && license != "" {
540- return license
541- }
558+ stem := strings .TrimSuffix (filename , ".gemspec" )
559+ ver := strings .TrimPrefix (stem , name + "-" )
560+ // Ensure the character after the gem name corresponds to the start of a version
561+ if ver == "" || ver [0 ] < '0' || ver [0 ] > '9' {
562+ continue
563+ }
564+ if specName , license , err := parseGemspecInfo (path ); err == nil && specName == name && license != "" {
565+ return license
542566 }
543567 }
544568 }
0 commit comments