@@ -22,7 +22,9 @@ package xrootd
2222
2323import (
2424 "os/exec"
25+ "regexp"
2526 "strings"
27+ "sync"
2628
2729 "github.com/hashicorp/go-version"
2830 "github.com/pkg/errors"
@@ -33,19 +35,65 @@ import (
3335// This version must be kept in sync with the version specified in .goreleaser.yml (two locations: RPM and DEB dependencies).
3436const MinXrootdVersion = "5.8.2"
3537
38+ var (
39+ xrootdVersionOnce sync.Once
40+ xrootdVersionOutput string
41+ xrootdVersionErr error
42+ )
43+
44+ // ResetXrootdVersionForTesting resets the cached XRootD version output.
45+ // This should only be used in tests.
46+ func ResetXrootdVersionForTesting () {
47+ xrootdVersionOnce = sync.Once {}
48+ xrootdVersionOutput = ""
49+ xrootdVersionErr = nil
50+ }
51+
52+ // getXrootdVersionOutput runs 'xrootd -v' once and caches the result.
53+ // Subsequent calls return the cached output without re-executing the command.
54+ func getXrootdVersionOutput () (string , error ) {
55+ xrootdVersionOnce .Do (func () {
56+ // Execute xrootd -v to get version information
57+ // Note: xrootd outputs version to stderr, not stdout
58+ cmd := exec .Command ("xrootd" , "-v" )
59+ output , err := cmd .CombinedOutput ()
60+ if err != nil {
61+ xrootdVersionErr = err
62+ return
63+ }
64+ xrootdVersionOutput = strings .TrimSpace (string (output ))
65+ })
66+ return xrootdVersionOutput , xrootdVersionErr
67+ }
68+
69+ // GetXrootdMajorVersion returns the major version number of the installed XRootD
70+ // (e.g., "5" or "6"). Returns an empty string if the version cannot be determined.
71+ // The result is cached after the first call.
72+ func GetXrootdMajorVersion () string {
73+ output , err := getXrootdVersionOutput ()
74+ if err != nil || output == "" {
75+ return ""
76+ }
77+
78+ re := regexp .MustCompile (`v?(\d+)\.\d+\.\d+` )
79+ matches := re .FindStringSubmatch (output )
80+ if len (matches ) > 1 {
81+ return matches [1 ]
82+ }
83+ return ""
84+ }
85+
3686/*
3787* CheckXrootdVersion checks if the installed XRootD version meets the minimum requirement.
3888* It executes 'xrootd -v' to retrieve the version and compares it against MinXrootdVersion.
89+ * The xrootd binary is only invoked once; subsequent calls use the cached result.
3990* Returns an error if:
4091* - The xrootd binary is not found in PATH
4192* - The version cannot be determined
4293* - The version is below the minimum requirement
4394 */
4495func CheckXrootdVersion () error {
45- // Execute xrootd -v to get version information
46- // Note: xrootd outputs version to stderr, not stdout
47- cmd := exec .Command ("xrootd" , "-v" )
48- output , err := cmd .CombinedOutput ()
96+ output , err := getXrootdVersionOutput ()
4997 if err != nil {
5098 // Check if this is a "command not found" error
5199 if exitErr , ok := err .(* exec.ExitError ); ok {
@@ -60,20 +108,19 @@ func CheckXrootdVersion() error {
60108 }
61109
62110 // Parse the version output
63- versionStr := strings .TrimSpace (string (output ))
64- log .Debugf ("XRootD version output: %s" , versionStr )
111+ log .Debugf ("XRootD version output: %s" , output )
65112
66113 // Remove leading 'v' if present (e.g., "v5.8.2" -> "5.8.2")
67- versionStr = strings .TrimPrefix (versionStr , "v" )
114+ versionStr : = strings .TrimPrefix (output , "v" )
68115
69116 // Parse the version string
70- xrootdVersion , err := version .NewVersion (versionStr )
117+ xrootdVer , err := version .NewVersion (versionStr )
71118 if err != nil {
72119 return errors .Wrapf (err , "failed to parse XRootD version string '%s'. Please ensure XRootD is properly installed" , versionStr )
73120 }
74121
75122 // Normalize to core version (strips pre-release suffixes like -rc1, +git123)
76- xrootdVersion = xrootdVersion .Core ()
123+ xrootdVer = xrootdVer .Core ()
77124
78125 // Parse the minimum required version
79126 requiredVersion , err := version .NewVersion (MinXrootdVersion )
@@ -83,13 +130,13 @@ func CheckXrootdVersion() error {
83130 }
84131
85132 // Compare versions
86- if xrootdVersion .LessThan (requiredVersion ) {
133+ if xrootdVer .LessThan (requiredVersion ) {
87134 return errors .Errorf ("XRootD version %s is insufficient (minimum required: %s). " +
88135 "Please upgrade XRootD to version %s or later. " +
89136 "This requirement is necessary for proper operation of Pelican Cache and Origin servers." ,
90- xrootdVersion .String (), MinXrootdVersion , MinXrootdVersion )
137+ xrootdVer .String (), MinXrootdVersion , MinXrootdVersion )
91138 }
92139
93- log .Debugf ("XRootD version check passed: %s >= %s" , xrootdVersion .String (), MinXrootdVersion )
140+ log .Debugf ("XRootD version check passed: %s >= %s" , xrootdVer .String (), MinXrootdVersion )
94141 return nil
95142}
0 commit comments