diff --git a/main.go b/main.go index 155f185..b2c8829 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "log" "os" @@ -10,6 +11,8 @@ import ( "github.com/spf13/cobra" ) +const Version = "0.1.0" + var rootCmd = &cobra.Command{ Use: "zsvo", Short: "A simple source-based package manager", @@ -47,6 +50,9 @@ func init() { } func main() { + // Print version + fmt.Printf("zsvo v%s\n", Version) + // Detect language from environment i18n.DetectLanguage() diff --git a/test/test_singleton_fix.go b/test/test_singleton_fix.go new file mode 100644 index 0000000..74055e9 --- /dev/null +++ b/test/test_singleton_fix.go @@ -0,0 +1,121 @@ +package main + +import ( + "fmt" + "os" + "time" + + "zsvo/pkg/resolver" +) + +func main() { + fmt.Println("๐Ÿงช Testing Singleton Resolver Fix") + fmt.Println("=================================") + + cacheDir := "/tmp/zsvo_test_singleton" + mirror := "https://deb.debian.org/debian" + suite := "stable" + component := "main" + + // Remove any existing cache + os.RemoveAll(cacheDir) + + // Test 1: Multiple GetGlobalResolver calls should only parse once + fmt.Printf("\n๐Ÿ“ฆ Test 1: Multiple GetGlobalResolver calls...\n") + + start := time.Now() + + // First call - should parse Sources.xz + fmt.Printf("Call 1: ") + r1, err := resolver.GetGlobalResolver(cacheDir, mirror, suite, component) + if err != nil { + fmt.Printf("โŒ Error: %v\n", err) + return + } + duration1 := time.Since(start) + fmt.Printf("โœ… %v\n", duration1) + + // Second call - should be instant + start = time.Now() + fmt.Printf("Call 2: ") + r2, err := resolver.GetGlobalResolver(cacheDir, mirror, suite, component) + if err != nil { + fmt.Printf("โŒ Error: %v\n", err) + return + } + duration2 := time.Since(start) + fmt.Printf("โœ… %v\n", duration2) + + // Third call - should also be instant + start = time.Now() + fmt.Printf("Call 3: ") + r3, err := resolver.GetGlobalResolver(cacheDir, mirror, suite, component) + if err != nil { + fmt.Printf("โŒ Error: %v\n", err) + return + } + duration3 := time.Since(start) + fmt.Printf("โœ… %v\n", duration3) + + // Verify same instance + if r1 == r2 && r2 == r3 { + fmt.Printf("โœ… Same resolver instance (singleton working)\n") + } else { + fmt.Printf("โŒ Different instances (singleton failed)\n") + } + + // Test 2: Multiple dependency resolutions should not re-parse + fmt.Printf("\n๐Ÿ“ฆ Test 2: Multiple dependency resolutions...\n") + + totalStart := time.Now() + resolutions := 0 + + for i := 0; i < 5; i++ { + start = time.Now() + + // Try to resolve a package (this will trigger dependency resolution) + graph, err := r1.ResolveDependencies("cmake") + if err != nil { + fmt.Printf(" Resolution %d: โŒ %v\n", i+1, err) + } else { + duration := time.Since(start) + nodeCount, maxLevel := graph.GetStats() + fmt.Printf(" Resolution %d: โœ… %v (%d packages, %d levels)\n", + i+1, duration, nodeCount, maxLevel) + } + resolutions++ + } + + totalDuration := time.Since(totalStart) + avgDuration := totalDuration / time.Duration(resolutions) + + fmt.Printf("๐Ÿ“Š Total time for %d resolutions: %v\n", resolutions, totalDuration) + fmt.Printf("๐Ÿ“ˆ Average per resolution: %v\n", avgDuration) + + // Results + fmt.Printf("\n๐ŸŽฏ Test Results:\n") + fmt.Printf("โ€ข First resolver init: %v\n", duration1) + fmt.Printf("โ€ข Second resolver init: %v\n", duration2) + fmt.Printf("โ€ข Third resolver init: %v\n", duration3) + fmt.Printf("โ€ข Average resolution time: %v\n", avgDuration) + + // Check if singleton is working correctly + if duration2 < time.Millisecond && duration3 < time.Millisecond { + fmt.Printf("โœ… SUCCESS: Singleton pattern working (subsequent calls <1ms)\n") + } else { + fmt.Printf("โŒ FAILED: Singleton pattern broken (subsequent calls >1ms)\n") + fmt.Printf(" Expected: <1ms, Got: %v, %v\n", duration2, duration3) + } + + // Check for performance regression + if avgDuration < 10*time.Millisecond { + fmt.Printf("โœ… SUCCESS: No repeated parsing (avg resolution <10ms)\n") + } else { + fmt.Printf("โŒ FAILED: Repeated parsing detected (avg resolution >10ms)\n") + } + + fmt.Printf("\n๐Ÿ“‹ Expected behavior:\n") + fmt.Printf("โ€ข LoadIndex() should execute only once inside sync.Once\n") + fmt.Printf("โ€ข Subsequent GetGlobalResolver() calls should be <1ms\n") + fmt.Printf("โ€ข Dependency resolutions should not trigger re-parsing\n") +} diff --git a/test/test_singleton_resolver.go b/test/test_singleton_resolver.go deleted file mode 100644 index ac69dfa..0000000 --- a/test/test_singleton_resolver.go +++ /dev/null @@ -1,104 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "zsvo/pkg/resolver" -) - -func main() { - fmt.Println("๐Ÿš€ Testing Singleton Resolver Performance") - fmt.Println("=======================================") - - cacheDir := "/tmp/zsvo_singleton_test" - mirror := "https://deb.debian.org/debian" - suite := "stable" - component := "main" - - // Test 1: First resolver creation (should parse Sources.xz) - fmt.Printf("\n๐Ÿ“ฆ Test 1: First resolver creation...\n") - start := time.Now() - - r1, err := resolver.GetGlobalResolver(cacheDir, mirror, suite, component) - if err != nil { - fmt.Printf("โŒ Error: %v\n", err) - return - } - - duration1 := time.Since(start) - fmt.Printf("โœ… First resolver created in: %v\n", duration1) - - // Test 2: Second resolver creation (should be instant, reuse cache) - fmt.Printf("\n๐Ÿ“ฆ Test 2: Second resolver creation...\n") - start = time.Now() - - r2, err := resolver.GetGlobalResolver(cacheDir, mirror, suite, component) - if err != nil { - fmt.Printf("โŒ Error: %v\n", err) - return - } - - duration2 := time.Since(start) - fmt.Printf("โœ… Second resolver created in: %v\n", duration2) - - // Verify they are the same instance - if r1 == r2 { - fmt.Printf("โœ… Same resolver instance (singleton pattern working)\n") - } else { - fmt.Printf("โŒ Different resolver instances (singleton failed)\n") - } - - // Test 3: Multiple resolver calls (should all be instant) - fmt.Printf("\n๐Ÿ“ฆ Test 3: Multiple resolver calls...\n") - totalStart := time.Now() - - for i := 0; i < 5; i++ { - start = time.Now() - _, err := resolver.GetGlobalResolver(cacheDir, mirror, suite, component) - duration := time.Since(start) - - if err != nil { - fmt.Printf("โŒ Error in call %d: %v\n", i+1, err) - } else { - fmt.Printf(" Call %d: %v\n", i+1, duration) - } - } - - totalDuration := time.Since(totalStart) - fmt.Printf("โœ… Total time for 5 calls: %v\n", totalDuration) - fmt.Printf("๐Ÿ“ˆ Average per call: %v\n", totalDuration/5) - - // Test 4: Test package resolution performance - fmt.Printf("\n๐Ÿ“ฆ Test 4: Package resolution performance...\n") - - // Resolve a few packages - packages := []string{"cmake", "pkg-config", "libssl-dev"} - - for _, pkg := range packages { - start := time.Now() - graph, err := r1.ResolveDependencies(pkg) - duration := time.Since(start) - - if err != nil { - fmt.Printf("โŒ Failed to resolve %s: %v\n", pkg, err) - } else { - nodeCount, maxLevel := graph.GetStats() - fmt.Printf("โœ… Resolved %s in %v: %d packages, %d levels\n", - pkg, duration, nodeCount, maxLevel) - } - } - - fmt.Printf("\n๐ŸŽฏ Performance Summary:\n") - fmt.Printf("โ€ข First resolver init: %v (includes Sources.xz parsing)\n", duration1) - fmt.Printf("โ€ข Subsequent resolver init: %v (singleton reuse)\n", duration2) - fmt.Printf("โ€ข Performance improvement: %.1fx faster\n", float64(duration1)/float64(duration2)) - - if duration2 < time.Millisecond { - fmt.Printf("๐ŸŽฏ TARGET ACHIEVED: Subsequent calls <1ms\n") - } else { - fmt.Printf("โš ๏ธ Target not achieved: %v > 1ms\n", duration2) - } - - fmt.Printf("\nโœ… Singleton resolver ensures Sources.xz is parsed only once!\n") -}