From a8e328cbde2969545d7967490dc7b96bb9690a66 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 3 Oct 2025 10:37:51 +0200 Subject: [PATCH] Centralize logging utilities - Create pkg/util/log.go with centralized LogVerbose and IsVerbose functions - Replace all duplicate logVerbose functions across the codebase with util.LogVerbose - Remove duplicate isVerbose functions - Add util import to all files that use verbose logging - Maintain consistent [VERBOSE] prefix for all verbose log messages - Check MVX_VERBOSE environment variable in a single location --- pkg/executor/executor.go | 30 ++++++------- pkg/shell/shell.go | 17 +++----- pkg/tools/base_tool.go | 45 ++++++++++---------- pkg/tools/download.go | 3 +- pkg/tools/extraction.go | 10 +++-- pkg/tools/java.go | 79 ++++++++++++++++++----------------- pkg/tools/manager.go | 15 +++---- pkg/tools/path_utils.go | 4 +- pkg/tools/system.go | 12 ------ pkg/tools/url_replacements.go | 7 ++-- pkg/util/log.go | 18 ++++++++ 11 files changed, 122 insertions(+), 118 deletions(-) create mode 100644 pkg/util/log.go diff --git a/pkg/executor/executor.go b/pkg/executor/executor.go index f9c641b..97a9b50 100644 --- a/pkg/executor/executor.go +++ b/pkg/executor/executor.go @@ -11,15 +11,9 @@ import ( "github.com/gnodet/mvx/pkg/config" "github.com/gnodet/mvx/pkg/shell" "github.com/gnodet/mvx/pkg/tools" + "github.com/gnodet/mvx/pkg/util" ) -// logVerbose prints verbose log messages -func logVerbose(format string, args ...interface{}) { - if os.Getenv("MVX_VERBOSE") == "true" { - fmt.Printf("[VERBOSE] "+format+"\n", args...) - } -} - // Executor handles command execution with proper environment setup type Executor struct { config *config.Config @@ -166,7 +160,7 @@ func (e *Executor) setupEnvironment(cmdConfig config.CommandConfig) ([]string, e requiredTools = append(requiredTools, toolName) } } - logVerbose("Required tools for command: %v", requiredTools) + util.LogVerbose("Required tools for command: %v", requiredTools) // Add tool bin directories to PATH for _, toolName := range requiredTools { @@ -174,11 +168,11 @@ func (e *Executor) setupEnvironment(cmdConfig config.CommandConfig) ([]string, e // EnsureTool handles version resolution, installation check, auto-install, and path retrieval binPath, err := e.toolManager.EnsureTool(toolName, toolConfig) if err != nil { - logVerbose("Skipping tool %s: %v", toolName, err) + util.LogVerbose("Skipping tool %s: %v", toolName, err) continue } - logVerbose("Adding %s bin path to PATH: %s", toolName, binPath) + util.LogVerbose("Adding %s bin path to PATH: %s", toolName, binPath) pathDirs = append(pathDirs, binPath) } } @@ -191,9 +185,9 @@ func (e *Executor) setupEnvironment(cmdConfig config.CommandConfig) ([]string, e newPath = newPath + string(os.PathListSeparator) + currentPath } envVars["PATH"] = newPath - logVerbose("Updated PATH with %d tool directories: %s", len(pathDirs), newPath) + util.LogVerbose("Updated PATH with %d tool directories: %s", len(pathDirs), newPath) } else { - logVerbose("No tool directories added to PATH") + util.LogVerbose("No tool directories added to PATH") } // Convert environment map back to slice format @@ -219,11 +213,11 @@ func (e *Executor) processScriptString(script string, args []string) string { // executeScriptWithInterpreter executes a script using the specified interpreter func (e *Executor) executeScriptWithInterpreter(script, workDir string, env []string, interpreter string) error { - logVerbose("executeScriptWithInterpreter called with interpreter: '%s', script: '%s'", interpreter, script) + util.LogVerbose("executeScriptWithInterpreter called with interpreter: '%s', script: '%s'", interpreter, script) // Default to native interpreter if not specified if interpreter == "" || interpreter == "native" { - logVerbose("Using native interpreter") + util.LogVerbose("Using native interpreter") return e.executeNativeScript(script, workDir, env) } @@ -247,14 +241,14 @@ func (e *Executor) executeNativeScript(script, workDir string, env []string) err shellArgs = []string{"/c"} } - logVerbose("Executing native script: %s", script) - logVerbose("Working directory: %s", workDir) - logVerbose("Environment variables count: %d", len(env)) + util.LogVerbose("Executing native script: %s", script) + util.LogVerbose("Working directory: %s", workDir) + util.LogVerbose("Environment variables count: %d", len(env)) // Log PATH specifically for _, envVar := range env { if strings.HasPrefix(envVar, "PATH=") { - logVerbose("PATH in environment: %s", envVar) + util.LogVerbose("PATH in environment: %s", envVar) break } } diff --git a/pkg/shell/shell.go b/pkg/shell/shell.go index b93af44..9a17c61 100644 --- a/pkg/shell/shell.go +++ b/pkg/shell/shell.go @@ -7,6 +7,8 @@ import ( "path/filepath" "runtime" "strings" + + "github.com/gnodet/mvx/pkg/util" ) // MVXShell provides cross-platform command execution @@ -629,18 +631,11 @@ func (s *MVXShell) open(args []string) error { return cmd.Run() } -// logVerbose prints verbose log messages for mvx-shell -func logVerbose(format string, args ...interface{}) { - if os.Getenv("MVX_VERBOSE") == "true" { - fmt.Printf("[VERBOSE] "+format+"\n", args...) - } -} - // executeExternal executes an external command func (s *MVXShell) executeExternal(cmd Command) error { - logVerbose("mvx-shell executing external command: %s %v", cmd.Name, cmd.Args) - logVerbose("mvx-shell working directory: %s", s.workDir) - logVerbose("mvx-shell environment variables count: %d", len(s.env)) + util.LogVerbose("mvx-shell executing external command: %s %v", cmd.Name, cmd.Args) + util.LogVerbose("mvx-shell working directory: %s", s.workDir) + util.LogVerbose("mvx-shell environment variables count: %d", len(s.env)) execCmd := exec.Command(cmd.Name, cmd.Args...) execCmd.Dir = s.workDir @@ -675,7 +670,7 @@ func (s *MVXShell) executeExternal(cmd Command) error { // Log PATH specifically for _, envVar := range env { if strings.HasPrefix(envVar, "PATH=") { - logVerbose("mvx-shell PATH in environment: %s", envVar) + util.LogVerbose("mvx-shell PATH in environment: %s", envVar) break } } diff --git a/pkg/tools/base_tool.go b/pkg/tools/base_tool.go index 0a07be6..2c8d1f4 100644 --- a/pkg/tools/base_tool.go +++ b/pkg/tools/base_tool.go @@ -11,6 +11,7 @@ import ( "sync" "github.com/gnodet/mvx/pkg/config" + "github.com/gnodet/mvx/pkg/util" "github.com/gnodet/mvx/pkg/version" ) @@ -261,7 +262,7 @@ func (b *BaseTool) VerifyWithConfig(version string, cfg config.ToolConfig, verif // Set up environment for verification (needed for tools like Maven that depend on Java) env, err := b.setupVerificationEnvironment(cfg) if err != nil { - logVerbose("Failed to setup verification environment: %v", err) + util.LogVerbose("Failed to setup verification environment: %v", err) env = nil // Fall back to default environment } @@ -287,7 +288,7 @@ func (b *BaseTool) setupVerificationEnvironment(cfg config.ToolConfig) ([]string if tool, err := b.manager.GetTool(b.toolName); err == nil { if depProvider, ok := tool.(DependencyProvider); ok { dependencies := depProvider.GetDependencies() - logVerbose("Setting up dependencies for %s verification: %v", b.toolName, dependencies) + util.LogVerbose("Setting up dependencies for %s verification: %v", b.toolName, dependencies) // Add dependencies to the temporary config for _, depName := range dependencies { @@ -300,7 +301,7 @@ func (b *BaseTool) setupVerificationEnvironment(cfg config.ToolConfig) ([]string Distribution: installedVersions[0].Distribution, } tempConfig.Tools[depName] = depConfig - logVerbose("Added dependency %s %s to verification environment", depName, installedVersions[0].Version) + util.LogVerbose("Added dependency %s %s to verification environment", depName, installedVersions[0].Version) } } } @@ -342,7 +343,7 @@ func (b *BaseTool) setupVerificationEnvironment(cfg config.ToolConfig) ([]string func (b *BaseTool) SetupHomeEnvironment(version string, cfg config.ToolConfig, envVars map[string]string, envVarName string, getPath func(string, config.ToolConfig) (string, error)) error { binPath, err := getPath(version, cfg) if err != nil { - logVerbose("Could not determine %s for %s %s: %v", envVarName, b.toolName, version, err) + util.LogVerbose("Could not determine %s for %s %s: %v", envVarName, b.toolName, version, err) return nil } @@ -350,7 +351,7 @@ func (b *BaseTool) SetupHomeEnvironment(version string, cfg config.ToolConfig, e if strings.HasSuffix(binPath, "/bin") { homeDir := strings.TrimSuffix(binPath, "/bin") envVars[envVarName] = homeDir - logVerbose("Set %s=%s for %s %s", envVarName, homeDir, b.toolName, version) + util.LogVerbose("Set %s=%s for %s %s", envVarName, homeDir, b.toolName, version) } return nil @@ -544,7 +545,7 @@ func (b *BaseTool) getDownloadOptions() DownloadOptions { func (b *BaseTool) StandardInstall(version string, cfg config.ToolConfig, getDownloadURL func(string) string) error { // Check if we should use system tool instead of downloading if UseSystemTool(b.toolName) { - logVerbose("%s=true, forcing use of system %s", getSystemToolEnvVar(b.toolName), b.toolName) + util.LogVerbose("%s=true, forcing use of system %s", getSystemToolEnvVar(b.toolName), b.toolName) // Try primary binary name in PATH if toolPath, err := exec.LookPath(b.binaryName); err == nil { @@ -665,29 +666,29 @@ func (b *BaseTool) ListInstalledVersions(distribution string) []InstalledVersion func (b *BaseTool) StandardIsInstalled(versionSpec string, cfg config.ToolConfig, getPath func(string, config.ToolConfig) (string, error)) bool { if UseSystemTool(b.toolName) { if _, err := exec.LookPath(b.GetBinaryName()); err == nil { - logVerbose("System %s is available in PATH (MVX_USE_SYSTEM_%s=true)", b.toolName, strings.ToUpper(b.toolName)) + util.LogVerbose("System %s is available in PATH (MVX_USE_SYSTEM_%s=true)", b.toolName, strings.ToUpper(b.toolName)) return true } - logVerbose("System %s not available: not found in environment variables or PATH", b.toolName) + util.LogVerbose("System %s not available: not found in environment variables or PATH", b.toolName) return false } tool, err := b.manager.GetTool(b.toolName) if err != nil { - logVerbose("Failed to get tool %s: %v", b.toolName, err) + util.LogVerbose("Failed to get tool %s: %v", b.toolName, err) return false } spec, err := version.ParseSpec(versionSpec) if err != nil { - logVerbose("Failed to parse version spec %q: %v", versionSpec, err) + util.LogVerbose("Failed to parse version spec %q: %v", versionSpec, err) return false } targetVersion, resolveErr := b.resolveTargetVersion(tool, spec, versionSpec, cfg) if resolveErr != nil { - logVerbose("Failed to resolve target version for %s %s: %v", b.toolName, versionSpec, resolveErr) + util.LogVerbose("Failed to resolve target version for %s %s: %v", b.toolName, versionSpec, resolveErr) } installed := b.ListInstalledVersions(cfg.Distribution) @@ -700,7 +701,7 @@ func (b *BaseTool) StandardIsInstalled(versionSpec string, cfg config.ToolConfig for _, inst := range installed { parsed, err := version.ParseVersion(inst.Version) if err != nil { - logVerbose("Failed to parse installed version %s: %v", inst.Version, err) + util.LogVerbose("Failed to parse installed version %s: %v", inst.Version, err) continue } if spec.Matches(parsed) { @@ -718,7 +719,7 @@ func (b *BaseTool) StandardIsInstalled(versionSpec string, cfg config.ToolConfig // Check candidates in order, return immediately on first valid installation for _, candidate := range candidates { - logVerbose(" Checking installed version: %s (%s) at %s", candidate.info.Version, candidate.info.Distribution, candidate.info.Path) + util.LogVerbose(" Checking installed version: %s (%s) at %s", candidate.info.Version, candidate.info.Distribution, candidate.info.Path) candidateCfg := cfg candidateCfg.Version = candidate.info.Version @@ -728,12 +729,12 @@ func (b *BaseTool) StandardIsInstalled(versionSpec string, cfg config.ToolConfig binPath, err := getPath(candidate.info.Version, candidateCfg) if err != nil { - logVerbose("Failed to compute binary path for %s %s: %v", b.toolName, candidate.info.Version, err) + util.LogVerbose("Failed to compute binary path for %s %s: %v", b.toolName, candidate.info.Version, err) continue } if !b.IsInstalled(binPath) { - logVerbose("Binary for %s %s not found at %s", b.toolName, candidate.info.Version, binPath) + util.LogVerbose("Binary for %s %s not found at %s", b.toolName, candidate.info.Version, binPath) continue } @@ -742,7 +743,7 @@ func (b *BaseTool) StandardIsInstalled(versionSpec string, cfg config.ToolConfig // This avoids running "java -version", "mvn --version", etc. on every startup // Found a valid installation - return immediately - logVerbose("Using previously installed %s %s (%s)", b.toolName, candidate.info.Version, candidate.info.Distribution) + util.LogVerbose("Using previously installed %s %s (%s)", b.toolName, candidate.info.Version, candidate.info.Distribution) return true } @@ -751,26 +752,26 @@ func (b *BaseTool) StandardIsInstalled(versionSpec string, cfg config.ToolConfig } if targetVersion == "" { - logVerbose("Resolved target version for %s %s is empty", b.toolName, versionSpec) + util.LogVerbose("Resolved target version for %s %s is empty", b.toolName, versionSpec) return false } installCfg := cfg installCfg.Version = targetVersion - logVerbose("%s version %s not installed, attempting automatic installation", b.toolName, targetVersion) + util.LogVerbose("%s version %s not installed, attempting automatic installation", b.toolName, targetVersion) if err := tool.Install(targetVersion, installCfg); err != nil { - logVerbose("Automatic installation of %s %s failed: %v", b.toolName, targetVersion, err) + util.LogVerbose("Automatic installation of %s %s failed: %v", b.toolName, targetVersion, err) return false } if err := tool.Verify(targetVersion, installCfg); err != nil { - logVerbose("Verification after installing %s %s failed: %v", b.toolName, targetVersion, err) + util.LogVerbose("Verification after installing %s %s failed: %v", b.toolName, targetVersion, err) return false } b.clearPathCache() - logVerbose("Successfully installed %s %s on demand", b.toolName, targetVersion) + util.LogVerbose("Successfully installed %s %s on demand", b.toolName, targetVersion) return true } @@ -817,7 +818,7 @@ func (b *BaseTool) StandardGetPath(version string, cfg config.ToolConfig, getIns if UseSystemTool(b.toolName) { // Try primary binary name in PATH if _, err := exec.LookPath(b.GetBinaryName()); err == nil { - logVerbose("Using system %s from PATH (MVX_USE_SYSTEM_%s=true)", b.toolName, strings.ToUpper(b.toolName)) + util.LogVerbose("Using system %s from PATH (MVX_USE_SYSTEM_%s=true)", b.toolName, strings.ToUpper(b.toolName)) b.setCachedPath(cacheKey, "", nil) return "", nil } diff --git a/pkg/tools/download.go b/pkg/tools/download.go index 7c4fea0..8322e1b 100644 --- a/pkg/tools/download.go +++ b/pkg/tools/download.go @@ -13,6 +13,7 @@ import ( "time" "github.com/gnodet/mvx/pkg/config" + "github.com/gnodet/mvx/pkg/util" ) // DownloadConfig contains configuration for robust downloads with checksum verification @@ -72,7 +73,7 @@ func RobustDownload(config *DownloadConfig) (*DownloadResult, error) { originalURL := config.URL urlReplacer, err := LoadURLReplacer() if err != nil { - logVerbose("Warning: failed to load URL replacements: %v", err) + util.LogVerbose("Warning: failed to load URL replacements: %v", err) } else { config.URL = urlReplacer.ApplyReplacements(config.URL) if config.URL != originalURL { diff --git a/pkg/tools/extraction.go b/pkg/tools/extraction.go index 053d362..b916ef7 100644 --- a/pkg/tools/extraction.go +++ b/pkg/tools/extraction.go @@ -10,6 +10,8 @@ import ( "os/exec" "path/filepath" "strings" + + "github.com/gnodet/mvx/pkg/util" ) // detectSingleTopLevelDirectory checks if all files in a ZIP archive are under a single top-level directory @@ -295,7 +297,7 @@ func extractTarGzFile(src, dest string) error { } default: // Skip other file types (char devices, block devices, etc.) - logVerbose("Skipping unsupported file type %d for %s", header.Typeflag, header.Name) + util.LogVerbose("Skipping unsupported file type %d for %s", header.Typeflag, header.Name) } } @@ -334,14 +336,14 @@ func createSymlinkSafely(linkname, targetPath string) error { if existingLink, err := os.Readlink(targetPath); err == nil { if existingLink == linkname { // Already the correct symlink, nothing to do - logVerbose("Symlink %s already exists with correct target %s", targetPath, linkname) + util.LogVerbose("Symlink %s already exists with correct target %s", targetPath, linkname) return nil } // Different symlink target, remove and recreate - logVerbose("Removing existing symlink %s (target: %s) to create new one (target: %s)", targetPath, existingLink, linkname) + util.LogVerbose("Removing existing symlink %s (target: %s) to create new one (target: %s)", targetPath, existingLink, linkname) } else { // Not a symlink, but some other file/directory exists - logVerbose("Removing existing file/directory %s to create symlink (target: %s)", targetPath, linkname) + util.LogVerbose("Removing existing file/directory %s to create symlink (target: %s)", targetPath, linkname) } // Remove existing file/symlink/directory diff --git a/pkg/tools/java.go b/pkg/tools/java.go index 1558143..338226d 100644 --- a/pkg/tools/java.go +++ b/pkg/tools/java.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/gnodet/mvx/pkg/config" + "github.com/gnodet/mvx/pkg/util" "github.com/gnodet/mvx/pkg/version" ) @@ -137,7 +138,7 @@ func (j *JavaTool) Install(version string, cfg config.ToolConfig) error { getDownloadURLWrapper := func(v string) string { url, err := j.getDownloadURL(v, distribution) if err != nil { - logVerbose("Failed to get download URL for Java %s (%s): %v", v, distribution, err) + util.LogVerbose("Failed to get download URL for Java %s (%s): %v", v, distribution, err) return "" } return url @@ -151,7 +152,7 @@ func (j *JavaTool) Install(version string, cfg config.ToolConfig) error { func (j *JavaTool) installWithDistribution(version string, cfg config.ToolConfig, distribution string, getDownloadURL func(string) string) error { // Check if we should use system tool instead of downloading if UseSystemTool(j.toolName) { - logVerbose("%s=true, forcing use of system %s", getSystemToolEnvVar(j.toolName), j.toolName) + util.LogVerbose("%s=true, forcing use of system %s", getSystemToolEnvVar(j.toolName), j.toolName) return nil } @@ -181,9 +182,9 @@ func (j *JavaTool) installWithDistribution(version string, cfg config.ToolConfig URL: checksumInfo.URL, Filename: checksumInfo.Filename, } - logVerbose("Added checksum to configuration: %s", checksumInfo.Value) + util.LogVerbose("Added checksum to configuration: %s", checksumInfo.Value) } else { - logVerbose("Failed to get checksum from Disco API: %v", err) + util.LogVerbose("Failed to get checksum from Disco API: %v", err) } } @@ -208,7 +209,7 @@ func (j *JavaTool) installWithDistribution(version string, cfg config.ToolConfig if err := j.Verify(version, verifyConfig); err != nil { // Clean up failed installation if removeErr := os.RemoveAll(installDir); removeErr != nil { - logVerbose("Failed to clean up installation directory %s: %v", installDir, removeErr) + util.LogVerbose("Failed to clean up installation directory %s: %v", installDir, removeErr) } fmt.Printf(" 🧹 Cleaning up failed installation directory...\n") return InstallError(j.toolName, version, fmt.Errorf("installation verification failed: %w", err)) @@ -271,11 +272,11 @@ func (j *JavaTool) IsInstalled(version string, cfg config.ToolConfig) bool { if UseSystemTool(j.toolName) { // Try primary binary name in PATH if _, err := exec.LookPath(j.GetBinaryName()); err == nil { - logVerbose("System %s is available in PATH (MVX_USE_SYSTEM_%s=true)", j.toolName, strings.ToUpper(j.toolName)) + util.LogVerbose("System %s is available in PATH (MVX_USE_SYSTEM_%s=true)", j.toolName, strings.ToUpper(j.toolName)) return true } - logVerbose("System %s not available: not found in environment variables or PATH", j.toolName) + util.LogVerbose("System %s not available: not found in environment variables or PATH", j.toolName) return false } @@ -286,7 +287,7 @@ func (j *JavaTool) IsInstalled(version string, cfg config.ToolConfig) bool { } fullVersion, err := j.ResolveVersion(version, distribution) if err != nil { - logVerbose("Failed to resolve full Java version for check: %v", err) + util.LogVerbose("Failed to resolve full Java version for check: %v", err) return false } @@ -321,7 +322,7 @@ func (j *JavaTool) getJavaHomeUncached(version string, cfg config.ToolConfig) (s // If using system Java, return system JAVA_HOME if available (no version compatibility check) if UseSystemTool(ToolJava) { if systemJavaHome, err := getSystemJavaHome(); err == nil { - logVerbose("Using system Java from %s: %s (MVX_USE_SYSTEM_JAVA=true)", EnvJavaHome, systemJavaHome) + util.LogVerbose("Using system Java from %s: %s (MVX_USE_SYSTEM_JAVA=true)", EnvJavaHome, systemJavaHome) return systemJavaHome, nil } else { return "", EnvironmentError(ToolJava, version, fmt.Errorf("MVX_USE_SYSTEM_JAVA=true but system Java not available: %w", err)) @@ -335,19 +336,19 @@ func (j *JavaTool) getJavaHomeUncached(version string, cfg config.ToolConfig) (s return "", fmt.Errorf("Java %s is not installed", version) } - logVerbose("Checking Java installation in: %s", installDir) + util.LogVerbose("Checking Java installation in: %s", installDir) // Search for java executable recursively and determine JAVA_HOME from its location javaExePath, err := j.findJavaExecutable(installDir) if err != nil { - logVerbose("Java executable not found in %s: %v", installDir, err) + util.LogVerbose("Java executable not found in %s: %v", installDir, err) return "", fmt.Errorf("Java executable not found in %s", installDir) } // Determine JAVA_HOME from java executable path // java executable is typically at $JAVA_HOME/bin/java javaHome := filepath.Dir(filepath.Dir(javaExePath)) - logVerbose("Found Java executable at: %s, using %s: %s", javaExePath, EnvJavaHome, javaHome) + util.LogVerbose("Found Java executable at: %s, using %s: %s", javaExePath, EnvJavaHome, javaHome) return javaHome, nil } @@ -365,7 +366,7 @@ func (j *JavaTool) findJavaExecutable(dir string) (string, error) { if !d.IsDir() && d.Name() == javaExeName { // Verify it's in a bin directory (to avoid false positives) if filepath.Base(filepath.Dir(path)) == "bin" { - logVerbose("Found Java executable at: %s", path) + util.LogVerbose("Found Java executable at: %s", path) foundPath = path return filepath.SkipAll // Stop walking once we find it } @@ -589,7 +590,7 @@ func (j *JavaTool) getDetailedVersionsForMajor(majorVersion, distribution string url := fmt.Sprintf("%s/packages?version=%s&distribution=%s&operating_system=%s&architecture=%s&package_type=jdk&release_status=ga&latest=available", FoojayDiscoAPIBase, majorVersion, distribution, osName, arch) - logVerbose("Fetching detailed versions for Java %s (%s) from: %s", majorVersion, distribution, url) + util.LogVerbose("Fetching detailed versions for Java %s (%s) from: %s", majorVersion, distribution, url) resp, err := j.manager.Get(url) if err != nil { @@ -719,19 +720,19 @@ func (j *JavaTool) tryDiscoDistributionWithChecksum(version, distribution, osNam version, distribution, osName, arch, releaseStatus) // Add verbose logging for debugging - logVerbose("Disco API URL: %s", url) - logVerbose("Query parameters: version=%s, distribution=%s, os=%s, arch=%s, release_status=%s", + util.LogVerbose("Disco API URL: %s", url) + util.LogVerbose("Query parameters: version=%s, distribution=%s, os=%s, arch=%s, release_status=%s", version, distribution, osName, arch, releaseStatus) // Get package information resp, err := j.manager.Get(url) if err != nil { - logVerbose("HTTP request failed: %v", err) + util.LogVerbose("HTTP request failed: %v", err) return DiscoveryResult{}, fmt.Errorf("failed to query Disco API: %w", err) } defer resp.Body.Close() - logVerbose("HTTP response status: %s", resp.Status) + util.LogVerbose("HTTP response status: %s", resp.Status) if resp.StatusCode != http.StatusOK { return DiscoveryResult{}, fmt.Errorf("Disco API request failed with status: %s", resp.Status) @@ -762,20 +763,20 @@ func (j *JavaTool) tryDiscoDistributionWithChecksum(version, distribution, osNam return DiscoveryResult{}, fmt.Errorf("failed to read response body: %w", err) } - logVerbose("Raw API response: %s", string(body)) + util.LogVerbose("Raw API response: %s", string(body)) if err := json.Unmarshal(body, &packages); err != nil { - logVerbose("JSON parsing failed: %v", err) + util.LogVerbose("JSON parsing failed: %v", err) return DiscoveryResult{}, fmt.Errorf("failed to parse Disco API response: %w", err) } - logVerbose("Found %d packages in response", len(packages.Result)) + util.LogVerbose("Found %d packages in response", len(packages.Result)) for i, pkg := range packages.Result { downloadURI := pkg.DirectDownloadURI if downloadURI == "" { downloadURI = pkg.Links.PkgDownloadRedirect } - logVerbose("Package %d: filename=%s, version=%s, download_uri=%s", + util.LogVerbose("Package %d: filename=%s, version=%s, download_uri=%s", i+1, pkg.Filename, pkg.VersionNumber, downloadURI) } @@ -806,12 +807,12 @@ func (j *JavaTool) tryDiscoDistributionWithChecksum(version, distribution, osNam if pkg.LibCType == "musl" { if muslPkg == nil { muslPkg = &pkg - logVerbose("Found musl candidate: %s", pkg.Filename) + util.LogVerbose("Found musl candidate: %s", pkg.Filename) } } else if pkg.LibCType == "glibc" { if glibcPkg == nil { glibcPkg = &pkg - logVerbose("Found glibc candidate: %s", pkg.Filename) + util.LogVerbose("Found glibc candidate: %s", pkg.Filename) } } } @@ -819,10 +820,10 @@ func (j *JavaTool) tryDiscoDistributionWithChecksum(version, distribution, osNam // For all platforms: prefer tar.gz over zip (tar.gz is smaller and more standard) if pkg.ArchiveType == "tar.gz" && tarGzPkg == nil { tarGzPkg = &pkg - logVerbose("Found TAR.GZ candidate: %s", pkg.Filename) + util.LogVerbose("Found TAR.GZ candidate: %s", pkg.Filename) } else if pkg.ArchiveType == "zip" && zipPkg == nil { zipPkg = &pkg - logVerbose("Found ZIP candidate: %s", pkg.Filename) + util.LogVerbose("Found ZIP candidate: %s", pkg.Filename) } // Keep track of any package as fallback @@ -839,24 +840,24 @@ func (j *JavaTool) tryDiscoDistributionWithChecksum(version, distribution, osNam // 5. other packages (final fallback) if glibcPkg != nil { selectedPkg = glibcPkg - logVerbose("Selected glibc package: %s (lib_c_type: %s)", selectedPkg.Filename, selectedPkg.LibCType) + util.LogVerbose("Selected glibc package: %s (lib_c_type: %s)", selectedPkg.Filename, selectedPkg.LibCType) } else if muslPkg != nil { selectedPkg = muslPkg - logVerbose("Selected musl package: %s (lib_c_type: %s)", selectedPkg.Filename, selectedPkg.LibCType) + util.LogVerbose("Selected musl package: %s (lib_c_type: %s)", selectedPkg.Filename, selectedPkg.LibCType) } else if tarGzPkg != nil { selectedPkg = tarGzPkg - logVerbose("Selected TAR.GZ package: %s", selectedPkg.Filename) + util.LogVerbose("Selected TAR.GZ package: %s", selectedPkg.Filename) } else if zipPkg != nil { selectedPkg = zipPkg - logVerbose("Selected ZIP package: %s", selectedPkg.Filename) + util.LogVerbose("Selected ZIP package: %s", selectedPkg.Filename) } else if otherPkg != nil { selectedPkg = otherPkg - logVerbose("Selected fallback package: %s", selectedPkg.Filename) + util.LogVerbose("Selected fallback package: %s", selectedPkg.Filename) } else { return DiscoveryResult{}, fmt.Errorf("no suitable packages found for Java %s (%s)", version, distribution) } - logVerbose("Selected package: %s", selectedPkg.Filename) + util.LogVerbose("Selected package: %s", selectedPkg.Filename) downloadURL := selectedPkg.DirectDownloadURI if downloadURL == "" { downloadURL = selectedPkg.Links.PkgDownloadRedirect @@ -866,8 +867,8 @@ func (j *JavaTool) tryDiscoDistributionWithChecksum(version, distribution, osNam return DiscoveryResult{}, fmt.Errorf("no download URL found for Java %s (%s)", version, distribution) } - logVerbose("Selected download URL: %s", downloadURL) - logVerbose("Package ID for checksum: %s", selectedPkg.ID) + util.LogVerbose("Selected download URL: %s", downloadURL) + util.LogVerbose("Package ID for checksum: %s", selectedPkg.ID) return DiscoveryResult{ DownloadURL: downloadURL, @@ -884,7 +885,7 @@ func (j *JavaTool) getChecksumFromDiscoAPI(packageID string) (ChecksumInfo, erro // Build package info URL url := fmt.Sprintf(FoojayDiscoAPIBase+"/ids/%s", packageID) - logVerbose("Fetching checksum from Disco API: %s", url) + util.LogVerbose("Fetching checksum from Disco API: %s", url) resp, err := j.manager.Get(url) if err != nil { @@ -928,9 +929,9 @@ func (j *JavaTool) getChecksumFromDiscoAPI(packageID string) (ChecksumInfo, erro } if pkg.Checksum != "" { - logVerbose("Found checksum: %s (%s)", pkg.Checksum, pkg.ChecksumType) + util.LogVerbose("Found checksum: %s (%s)", pkg.Checksum, pkg.ChecksumType) } else if pkg.ChecksumURI != "" { - logVerbose("Found checksum URI: %s (%s)", pkg.ChecksumURI, pkg.Filename) + util.LogVerbose("Found checksum URI: %s (%s)", pkg.ChecksumURI, pkg.Filename) } else { return ChecksumInfo{}, fmt.Errorf("no checksum available for package") } @@ -999,7 +1000,7 @@ func (j *JavaTool) ResolveVersion(versionSpec, distribution string) (string, err if !strings.Contains(majorResolved, ".") { detailedVersions, err := j.getDetailedVersionsForMajor(majorResolved, distribution) if err != nil { - logVerbose("Failed to fetch detailed versions for Java %s: %v, using major version", majorResolved, err) + util.LogVerbose("Failed to fetch detailed versions for Java %s: %v, using major version", majorResolved, err) return majorResolved, nil // Fallback to major version } @@ -1017,7 +1018,7 @@ func (j *JavaTool) GetDownloadURL(version string) string { // Use default distribution (temurin) for URL generation url, err := j.getDownloadURL(version, "temurin") if err != nil { - logVerbose("Failed to get download URL for Java %s: %v", version, err) + util.LogVerbose("Failed to get download URL for Java %s: %v", version, err) return "" } return url diff --git a/pkg/tools/manager.go b/pkg/tools/manager.go index b56fed3..695f3ae 100644 --- a/pkg/tools/manager.go +++ b/pkg/tools/manager.go @@ -15,6 +15,7 @@ import ( "time" "github.com/gnodet/mvx/pkg/config" + "github.com/gnodet/mvx/pkg/util" "github.com/gnodet/mvx/pkg/version" ) @@ -385,7 +386,7 @@ func (m *Manager) discoverAndRegisterTools() error { for toolName, factory := range toolFactories { tool := factory(m) m.RegisterTool(tool) - logVerbose("Registered tool: %s", toolName) + util.LogVerbose("Registered tool: %s", toolName) } // Future enhancement: could also load tools from configuration files @@ -820,7 +821,7 @@ func (m *Manager) EnsureTool(toolName string, cfg config.ToolConfig) (string, er // Check if installed if !tool.IsInstalled(resolvedVersion, resolvedConfig) { // Auto-install - logVerbose("Auto-installing %s %s...", toolName, resolvedVersion) + util.LogVerbose("Auto-installing %s %s...", toolName, resolvedVersion) if err := tool.Install(resolvedVersion, resolvedConfig); err != nil { return "", fmt.Errorf("failed to install %s %s: %w", toolName, resolvedVersion, err) } @@ -898,7 +899,7 @@ func (m *Manager) SetupEnvironment(cfg *config.Config) (map[string]string, error if err == nil { if envProvider, ok := tool.(EnvironmentProvider); ok { if err := envProvider.SetupEnvironment(resolvedVersion, resolvedConfig, env); err != nil { - logVerbose("Failed to setup environment for %s %s: %v", toolName, resolvedVersion, err) + util.LogVerbose("Failed to setup environment for %s %s: %v", toolName, resolvedVersion, err) } } } @@ -932,7 +933,7 @@ func (m *Manager) ResolveVersion(toolName string, toolConfig config.ToolConfig) func (m *Manager) resolveVersion(toolName string, toolConfig config.ToolConfig) (string, error) { // Check for environment variable override first if overrideVersion := getToolVersionOverride(toolName); overrideVersion != "" { - logVerbose("Using version override from %s: %s", getToolVersionOverrideEnvVar(toolName), overrideVersion) + util.LogVerbose("Using version override from %s: %s", getToolVersionOverrideEnvVar(toolName), overrideVersion) // Fast path: Check if override version is already concrete if m.isConcreteVersion(toolName, overrideVersion) { return overrideVersion, nil @@ -957,11 +958,11 @@ func (m *Manager) resolveVersionInternal(toolName string, toolConfig config.Tool // Check cache first if cached, found := m.getCachedVersion(toolName, toolConfig.Version, distribution); found { - logVerbose("Using cached version resolution: %s %s (%s) -> %s", toolName, toolConfig.Version, distribution, cached) + util.LogVerbose("Using cached version resolution: %s %s (%s) -> %s", toolName, toolConfig.Version, distribution, cached) return cached, nil } - logVerbose("Resolving version online: %s %s (%s)", toolName, toolConfig.Version, distribution) + util.LogVerbose("Resolving version online: %s %s (%s)", toolName, toolConfig.Version, distribution) // Get the tool instance tool, err := m.GetTool(toolName) @@ -981,7 +982,7 @@ func (m *Manager) resolveVersionInternal(toolName string, toolConfig config.Tool resolved = toolConfig.Version } - logVerbose("Resolved %s %s (%s) -> %s (caching for 24h)", toolName, toolConfig.Version, distribution, resolved) + util.LogVerbose("Resolved %s %s (%s) -> %s (caching for 24h)", toolName, toolConfig.Version, distribution, resolved) // Cache the resolved version m.setCachedVersion(toolName, toolConfig.Version, distribution, resolved) diff --git a/pkg/tools/path_utils.go b/pkg/tools/path_utils.go index 9b7d122..d1f0559 100644 --- a/pkg/tools/path_utils.go +++ b/pkg/tools/path_utils.go @@ -5,6 +5,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/gnodet/mvx/pkg/util" ) // PathResolver provides common path resolution utilities for tools @@ -47,7 +49,7 @@ func (pem *PathEnvironmentManager) BuildToolPATH(tools map[string]ToolPathInfo) for toolName, info := range tools { if info.BinPath != "" { - logVerbose("Adding %s bin path to PATH: %s", toolName, info.BinPath) + util.LogVerbose("Adding %s bin path to PATH: %s", toolName, info.BinPath) pathDirs = append(pathDirs, info.BinPath) } } diff --git a/pkg/tools/system.go b/pkg/tools/system.go index 2424b14..237dda9 100644 --- a/pkg/tools/system.go +++ b/pkg/tools/system.go @@ -7,18 +7,6 @@ import ( "strings" ) -// isVerbose checks if verbose logging is enabled -func isVerbose() bool { - return os.Getenv("MVX_VERBOSE") == "true" -} - -// logVerbose prints verbose log messages -func logVerbose(format string, args ...interface{}) { - if isVerbose() { - fmt.Printf("[VERBOSE] "+format+"\n", args...) - } -} - // UseSystemTool checks if a system tool should be used instead of downloading // by checking the MVX_USE_SYSTEM_ environment variable func UseSystemTool(toolName string) bool { diff --git a/pkg/tools/url_replacements.go b/pkg/tools/url_replacements.go index ced7341..ef8089a 100644 --- a/pkg/tools/url_replacements.go +++ b/pkg/tools/url_replacements.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/gnodet/mvx/pkg/config" + "github.com/gnodet/mvx/pkg/util" ) // URLReplacer handles URL replacements for enterprise networks and mirrors @@ -27,7 +28,7 @@ func LoadURLReplacer() (*URLReplacer, error) { globalConfig, err := config.LoadGlobalConfig() if err != nil { // Log warning but continue - global config is optional - logVerbose("Warning: failed to load global config: %v", err) + util.LogVerbose("Warning: failed to load global config: %v", err) globalConfig = &config.GlobalConfig{} } @@ -78,7 +79,7 @@ func (r *URLReplacer) ApplyReplacements(originalURL string) string { replacement := r.replacements[pattern] newURL := r.applyReplacement(currentURL, pattern, replacement) if newURL != currentURL { - logVerbose("URL replacement applied: %s -> %s (pattern: %s)", currentURL, newURL, pattern) + util.LogVerbose("URL replacement applied: %s -> %s (pattern: %s)", currentURL, newURL, pattern) return newURL // Return after first match (like mise) } } @@ -103,7 +104,7 @@ func (r *URLReplacer) applyRegexReplacement(url, regexPattern, replacement strin // Compile the regex regex, err := regexp.Compile(regexPattern) if err != nil { - logVerbose("Warning: invalid regex pattern '%s': %v", regexPattern, err) + util.LogVerbose("Warning: invalid regex pattern '%s': %v", regexPattern, err) return url } diff --git a/pkg/util/log.go b/pkg/util/log.go new file mode 100644 index 0000000..2e83bb2 --- /dev/null +++ b/pkg/util/log.go @@ -0,0 +1,18 @@ +package util + +import ( + "fmt" + "os" +) + +// IsVerbose returns true if verbose logging is enabled +func IsVerbose() bool { + return os.Getenv("MVX_VERBOSE") == "true" +} + +// LogVerbose prints verbose log messages +func LogVerbose(format string, args ...interface{}) { + if IsVerbose() { + fmt.Printf("[VERBOSE] "+format+"\n", args...) + } +}