@@ -116,17 +116,21 @@ func ExecuteConanInfoCmd(ctx context.Context, cmdInfo *CmdInfo, dir string) (str
116116 }
117117 jsonP := getConanInfoJsonPath ()
118118 major := ConanMajorVersion (cmdInfo .Version )
119+ remoteCreds , credErr := getConanRemoteCredentialsFromConfig (major )
120+ if credErr != nil {
121+ logger .Warn ("Conan remote credential precheck failed when reading config" , zap .Error (credErr ))
122+ }
119123 logger .Sugar ().Infof ("Conan detected: path=%s version=%s major=%d" , cmdInfo .Path , cmdInfo .Version , major )
120124 logger .Sugar ().Infof ("Conan verbose mode: -v %s" , conanVerboseArg )
121125 logConanRemoteConfigPaths (logger , major )
122- loginWarnings := ensureConanRemoteLogin (ctx , cmdInfo .Path , major )
126+ loginWarnings := ensureConanRemoteLogin (ctx , cmdInfo .Path , major , remoteCreds )
123127 logger .Sugar ().Debugf ("temp file: %s" , jsonP )
124128 if major >= 2 {
125- if e := ensureConan2DefaultProfile (ctx , cmdInfo .Path ); e != nil {
129+ if e := ensureConan2DefaultProfile (ctx , cmdInfo .Path , major , remoteCreds ); e != nil {
126130 return "" , "" , e
127131 }
128132 logger .Info ("Conan mode selected: graph" )
129- if e := executeConanGraphInfoCmd (ctx , cmdInfo .Path , dir , jsonP ); e != nil {
133+ if e := executeConanGraphInfoCmd (ctx , cmdInfo .Path , dir , jsonP , major , remoteCreds ); e != nil {
130134 if len (loginWarnings ) > 0 {
131135 return "" , "" , fmt .Errorf ("%w; login warnings: %s" , e , strings .Join (loginWarnings , " | " ))
132136 }
@@ -136,7 +140,7 @@ func ExecuteConanInfoCmd(ctx context.Context, cmdInfo *CmdInfo, dir string) (str
136140 return jsonP , ConanJsonKindGraph , nil
137141 }
138142 logger .Info ("Conan mode selected: info" )
139- if e := executeConanInfoCmd (ctx , cmdInfo .Path , dir , jsonP ); e != nil {
143+ if e := executeConanInfoCmd (ctx , cmdInfo .Path , dir , jsonP , major , remoteCreds ); e != nil {
140144 if len (loginWarnings ) > 0 {
141145 return "" , "" , fmt .Errorf ("%w; login warnings: %s" , e , strings .Join (loginWarnings , " | " ))
142146 }
@@ -146,7 +150,7 @@ func ExecuteConanInfoCmd(ctx context.Context, cmdInfo *CmdInfo, dir string) (str
146150 return jsonP , ConanJsonKindInfo , nil
147151}
148152
149- func ensureConan2DefaultProfile (ctx context.Context , conanPath string ) error {
153+ func ensureConan2DefaultProfile (ctx context.Context , conanPath string , major int , remoteCreds [] conanRemoteCredential ) error {
150154 logger := logctx .Use (ctx )
151155 home , err := os .UserHomeDir ()
152156 if err != nil || home == "" {
@@ -162,10 +166,10 @@ func ensureConan2DefaultProfile(ctx context.Context, conanPath string) error {
162166 }
163167
164168 logger .Sugar ().Infof ("Conan default profile missing: %s, running detect" , profilePath )
165- args := conanArgs ("profile" , "detect" , "--force" )
169+ args := conanArgs (major , "profile" , "detect" , "--force" )
166170 c := exec .CommandContext (ctx , conanPath , args ... )
167171 logger .Sugar ().Infof ("Command: %s" , c .String ())
168- c .Env = getEnvForConan ()
172+ c .Env = getEnvForConan (major , remoteCreds )
169173 start := time .Now ()
170174 sb := suffixbuf .NewSize (1024 )
171175 logPipe := logpipe .New (logger , "conan" )
@@ -185,12 +189,12 @@ func ensureConan2DefaultProfile(ctx context.Context, conanPath string) error {
185189 return nil
186190}
187191
188- func executeConanInfoCmd (ctx context.Context , conanPath string , dir string , jsonP string ) error {
192+ func executeConanInfoCmd (ctx context.Context , conanPath string , dir string , jsonP string , major int , remoteCreds [] conanRemoteCredential ) error {
189193 logger := logctx .Use (ctx )
190- args := conanArgs ("info" , "." , "-j" , jsonP )
194+ args := conanArgs (major , "info" , "." , "-j" , jsonP )
191195 c := exec .Command (conanPath , args ... )
192196 logger .Sugar ().Infof ("Command: %s" , c .String ())
193- c .Env = getEnvForConan ()
197+ c .Env = getEnvForConan (major , remoteCreds )
194198 c .Dir = dir
195199 start := time .Now ()
196200 sb := suffixbuf .NewSize (1024 )
@@ -206,12 +210,12 @@ func executeConanInfoCmd(ctx context.Context, conanPath string, dir string, json
206210 return nil
207211}
208212
209- func executeConanGraphInfoCmd (ctx context.Context , conanPath string , dir string , jsonP string ) error {
213+ func executeConanGraphInfoCmd (ctx context.Context , conanPath string , dir string , jsonP string , major int , remoteCreds [] conanRemoteCredential ) error {
210214 logger := logctx .Use (ctx )
211- args := conanArgs ("graph" , "info" , "." , "--format=json" )
215+ args := conanArgs (major , "graph" , "info" , "." , "--format=json" )
212216 c := exec .Command (conanPath , args ... )
213217 logger .Sugar ().Infof ("Command: %s" , c .String ())
214- c .Env = getEnvForConan ()
218+ c .Env = getEnvForConan (major , remoteCreds )
215219 c .Dir = dir
216220 start := time .Now ()
217221 sb := suffixbuf .NewSize (1024 )
@@ -237,79 +241,38 @@ type conanRemoteCredential struct {
237241 Password string
238242}
239243
240- func ensureConanRemoteLogin (ctx context.Context , conanPath string , major int ) []string {
244+ func ensureConanRemoteLogin (ctx context.Context , conanPath string , major int , creds [] conanRemoteCredential ) []string {
241245 warnings := make ([]string , 0 )
242246 if major < 2 {
243247 return warnings
244248 }
245249 logger := logctx .Use (ctx )
246- creds , err := getConanRemoteCredentialsFromConfig (major )
247- if err != nil {
248- logger .Warn ("Conan remote login precheck failed when reading config" , zap .Error (err ))
249- return warnings
250- }
251250 if len (creds ) == 0 {
252251 logger .Info ("Conan remote login skipped: no credentials found in remote URLs" )
253252 return warnings
254253 }
255254 for _ , cred := range creds {
256- authenticated , authOutput , authErr := isConanRemoteAuthenticated (ctx , conanPath , cred .Name , cred .Username )
257- if authErr != nil {
258- logger .Sugar ().Warnf ("Conan remote auth probe failed for %s: %v" , cred .Name , authErr )
259- } else {
260- logger .Sugar ().Infof ("Conan remote auth probe: remote=%s user=%s authenticated=%t output=%q" ,
261- cred .Name , cred .Username , authenticated , strings .TrimSpace (authOutput ))
262- }
263- if authenticated {
264- logger .Sugar ().Infof ("Conan remote auth already valid: remote=%s" , cred .Name )
265- continue
266- }
267- args := conanArgs ("remote" , "login" , cred .Name , cred .Username , "-p" , cred .Password )
255+ args := conanArgs (major , "remote" , "auth" , cred .Name , "--force" )
268256 c := exec .CommandContext (ctx , conanPath , args ... )
269- c .Env = getEnvForConan ()
257+ c .Env = getEnvForConan (major , [] conanRemoteCredential { cred } )
270258 sb := suffixbuf .NewSize (1024 )
271259 logPipe := logpipe .New (logger , "conan" )
272- logger .Sugar ().Infof ("Command: %s remote login %s %s -p ****** " , conanPath , cred .Name , cred . Username )
260+ logger .Sugar ().Infof ("Command: %s remote auth %s --force (credentials from env) " , conanPath , cred .Name )
273261 c .Stdout = io .MultiWriter (sb , logPipe )
274262 c .Stderr = io .MultiWriter (sb , logPipe )
275263 if runErr := c .Run (); runErr != nil {
276264 logPipe .Close ()
277- msg := fmt .Sprintf ("conan remote login failed for %s(user=%s): %v, details: %s" , cred .Name , cred .Username , runErr , strings .TrimSpace (string (sb .Bytes ())))
265+ msg := fmt .Sprintf ("conan remote auth failed for %s(user=%s): %v, details: %s" , cred .Name , cred .Username , runErr , strings .TrimSpace (string (sb .Bytes ())))
278266 logger .Warn (msg )
279267 warnings = append (warnings , msg )
280268 continue
281269 }
282270 logPipe .Close ()
283- logger .Sugar ().Infof ("Conan remote login completed: remote=%s user=%s" , cred .Name , cred .Username )
271+ logger .Sugar ().Infof ("Conan remote auth completed: remote=%s user=%s" , cred .Name , cred .Username )
284272 }
285273 return warnings
286274}
287275
288- func isConanRemoteAuthenticated (ctx context.Context , conanPath string , remoteName string , expectedUser string ) (bool , string , error ) {
289- c := exec .CommandContext (ctx , conanPath , conanArgs ("remote" , "auth" , remoteName , "--with-user" )... )
290- c .Env = getEnvForConan ()
291- out , err := c .CombinedOutput ()
292- output := strings .TrimSpace (string (out ))
293- if err != nil {
294- return false , output , fmt .Errorf ("auth check failed: %w, output: %s" , err , output )
295- }
296- lower := strings .ToLower (output )
297- if output == "" {
298- return false , output , nil
299- }
300- if strings .Contains (lower , "anonymous" ) || strings .Contains (lower , "anonymously" ) {
301- return false , output , nil
302- }
303- if strings .Contains (lower , "not authenticated" ) || strings .Contains (lower , "authenticated: false" ) {
304- return false , output , nil
305- }
306- if expectedUser != "" && strings .Contains (lower , strings .ToLower (expectedUser )) {
307- return true , output , nil
308- }
309- // Conan output format may vary by version; if we cannot infer a user match, treat as unauthenticated.
310- return false , output , nil
311- }
312-
313276type conanRemotesFile struct {
314277 Remotes []struct {
315278 Name string `json:"name"`
@@ -367,7 +330,10 @@ func conanRemotesConfigPath(major int) (string, error) {
367330 return filepath .Join (home , ".conan" , "remotes.json" ), nil
368331}
369332
370- func conanArgs (args ... string ) []string {
333+ func conanArgs (major int , args ... string ) []string {
334+ if major >= 2 {
335+ args = append (args , "-cc" , "core:non_interactive=True" )
336+ }
371337 return append (args , "-v" , conanVerboseArg )
372338}
373339
@@ -385,7 +351,7 @@ func LocateConan(ctx context.Context) (string, error) {
385351
386352func GetConanVersion (ctx context.Context , conanPath string ) (string , error ) {
387353 c := exec .CommandContext (ctx , conanPath , "-v" )
388- c .Env = getEnvForConan ()
354+ c .Env = getBaseEnvForConan ()
389355 if data , e := c .Output (); e != nil {
390356 return "" , errors .WithCause (ErrGetConanVersionFail , e )
391357 } else {
@@ -403,9 +369,46 @@ func ConanMajorVersion(version string) int {
403369 return v
404370}
405371
406- func getEnvForConan () []string {
372+ func getBaseEnvForConan () []string {
407373 osEnv := os .Environ ()
408374 var rs = make ([]string , 0 , len (osEnv )+ 3 )
409375 rs = append (rs , osEnv ... )
410376 return append (rs , "CONAN_NON_INTERACTIVE=1" , "NO_COLOR=1" , "CLICOLOR=0" )
411377}
378+
379+ func getEnvForConan (major int , remoteCreds []conanRemoteCredential ) []string {
380+ rs := getBaseEnvForConan ()
381+ if major < 1 || len (remoteCreds ) == 0 {
382+ return rs
383+ }
384+ for _ , cred := range remoteCreds {
385+ suffix := conanRemoteEnvVarSuffix (cred .Name )
386+ if suffix == "" || cred .Username == "" || cred .Password == "" {
387+ continue
388+ }
389+ rs = append (rs ,
390+ fmt .Sprintf ("CONAN_LOGIN_USERNAME_%s=%s" , suffix , cred .Username ),
391+ fmt .Sprintf ("CONAN_PASSWORD_%s=%s" , suffix , cred .Password ),
392+ )
393+ }
394+ return rs
395+ }
396+
397+ func conanRemoteEnvVarSuffix (remoteName string ) string {
398+ remoteName = strings .TrimSpace (remoteName )
399+ if remoteName == "" {
400+ return ""
401+ }
402+ var b strings.Builder
403+ for _ , r := range remoteName {
404+ switch {
405+ case r >= 'a' && r <= 'z' :
406+ b .WriteRune (r - ('a' - 'A' ))
407+ case (r >= 'A' && r <= 'Z' ) || (r >= '0' && r <= '9' ):
408+ b .WriteRune (r )
409+ default :
410+ b .WriteRune ('_' )
411+ }
412+ }
413+ return b .String ()
414+ }
0 commit comments