Data Flow
How data flows through govman during various operations.
Overview
govman follows a layered architecture:
User (CLI) → CLI Commands → Manager → Core Services → External APIs/Filesystem
Install Flow
User Command
govman install 1.25.1
Flow Diagram
1. CLI (install.go)
↓ calls
2. Manager.Install(version)
↓ resolves version
3. Golang.GetDownloadURL(version)
↓ fetches from API
4. go.dev API
↓ returns metadata
5. Downloader.Download(url, installDir, version)
↓ downloads
6. HTTP GET official Go archive
↓ streams to
7. Cache (~/.govman/cache/)
↓ verifies
8. SHA-256 checksum
↓ extracts to
9. Install directory (~/.govman/versions/go1.25.1/)
↓ success
10. User notified
Detailed Steps
-
Command Parsing (
internal/cli/install.go):- Parse version argument
- Validate input
-
Version Resolution (
internal/manager/manager.go):- Resolve "latest" or partial versions
- Query API for available versions
-
Download URL Lookup (
internal/golang/releases.go):- Fetch release metadata from go.dev
- Find appropriate file for OS/architecture
- Return download URL
-
Download (
internal/downloader/downloader.go):- Check cache for existing file
- Download with progress tracking
- Save to cache directory
-
Verification (
internal/downloader/downloader.go):- Calculate SHA-256 of downloaded file
- Compare with official checksum
- Reject if mismatch
-
Extraction (
internal/downloader/downloader.go):- Extract .tar.gz or .zip
- Copy files to install directory
- Set appropriate permissions
-
Completion:
- Remove temporary files
- Log success message
Use Flow
User Command
govman use 1.25.1 --default
Flow Diagram
1. CLI (use.go)
↓ calls
2. Manager.Use(version, setDefault=true, setLocal=false)
↓ validates
3. Check if version installed
↓ if yes
4. Update configuration (DefaultVersion)
↓ saves
5. Config file (~/.govman/config.yaml)
↓ creates/updates
6. Symlink (~/.govman/bin/go → ~/.govman/versions/go1.25.1/bin/go)
↓ outputs
7. PATH export command (for shell wrapper)
↓ success
8. User notified
Detailed Steps
-
Command Parsing (
internal/cli/use.go):- Parse version and flags
- Determine activation mode
-
Validation (
internal/manager/manager.go):- Check if version is installed
- Resolve version if needed
-
Configuration Update (if
--default):- Update
config.DefaultVersion - Save to
~/.govman/config.yaml
- Update
-
Local Version File (if
--local):- Write version to
.govman-goversion - In current directory
- Write version to
-
Symlink Creation (if
--default):- Create
~/.govman/bin/gosymlink - pointing to version's
bin/go
- Create
-
PATH Update (always):
- Generate PATH command
- Output for shell wrapper to eval
List Flow
User Command
govman list --remote
Flow Diagram
1. CLI (list.go)
↓ calls
2. Manager.ListRemote(includeUnstable=false)
↓ calls
3. Golang.GetAvailableVersions(includeUnstable)
↓ checks cache
4. In-memory cache (if valid)
↓ or fetches from
5. go.dev API
↓ parses JSON
6. Release data
↓ sorts versions
7. Sorted version list
↓ returns to
8. CLI formatter
↓ displays
9. User output
Auto-Switch Flow
Trigger
cd /path/to/project # With .govman-goversion file
Flow Diagram
1. Shell hook (chpwd/PROMPT_COMMAND/etc.)
↓ triggers
2. govman_auto_switch() function
↓ checks config
3. ~/.govman/config.yaml (auto_switch.enabled)
↓ if enabled, looks for
4. .govman-goversion file in current directory
↓ reads version
5. Required version (e.g., "1.25.1")
↓ checks current
6. go version output
↓ if different
7. govman use <required-version>
↓ follows Use Flow
8. Version switched automatically
Download Cache Flow
Cache Hit
Request version
↓ check cache
~/.govman/cache/go1.25.1.linux-amd64.tar.gz exists
↓ verify size matches expected
Cache hit → Skip download → Use cached file
Cache Miss
Request version
↓ check cache
File not in cache or size mismatch
↓ download
HTTP GET from go.dev
↓ save to cache
~/.govman/cache/go1.25.1.linux-amd64.tar.gz
↓ use for installation
Extract to install directory
Configuration Flow
Loading
1. Application starts
↓ CLI init
2. Config.Load() called
↓ checks
3. ~/.govman/config.yaml exists?
↓ if no, create with defaults
4. Load YAML file
↓ parse
5. Viper unmarshals to Config struct
↓ expand paths
6. Resolve ~ in paths
↓ validate
7. Check path safety
↓ create directories
8. Ensure install/cache dirs exist
↓ return
9. Loaded Config available to application
Saving
1. Config.Save() called (e.g., after 'use --default')
↓ set values
2. Viper.Set() for each field
↓ write
3. Viper.WriteConfigAs()
↓ saves to
4. ~/.govman/config.yaml
Shell Integration Flow
Initialization
govman init
Flow Diagram
1. CLI (init.go)
↓ detects
2. Shell.Detect() → Current shell type
↓ gets setup code
3. Shell.SetupCommands(binPath) → Integration code
↓ reads existing
4. Shell config file (~/.bashrc, etc.)
↓ removes old
5. Remove existing GOVMAN sections
↓ appends new
6. Add new integration code
↓ writes
7. Updated shell config file
↓ notifies
8. User to reload shell
Self-Update Flow
User Command
govman selfupdate
Flow Diagram
1. CLI (selfupdate.go)
↓ fetches
2. GitHub API (latest release)
↓ parses
3. Release metadata
↓ compares
4. Current version vs Latest version
↓ if newer available
5. Construct download URL for platform
↓ downloads
6. New govman binary (temp file)
↓ backup
7. Rename current binary to .bak
↓ replace
8. Move new binary to current location
↓ set permissions
9. chmod +x
↓ verify
10. Run new binary --version
↓ cleanup
11. Remove backup (if successful)
↓ success
12. User notified
Error Handling Flow
Download Failure Example
Download attempt
↓ fails (network error)
Retry logic (up to retry_count times)
↓ all retries failed
Log error details
↓ clean up
Remove partial download
↓ return error
Manager catches error
↓ formats
CLI formats user-friendly message
↓ display
User sees: "Failed to download: network timeout"
↓ suggest
Help message: "Check internet connection"
↓ exit
Exit code 4 (network error)
Data Persistence
Filesystem Layout
~/.govman/
├── config.yaml # Configuration (persisted)
├── bin/
│ └── go → versions/go1.25.1/bin/go # Symlink (persisted)
├── versions/
│ ├── go1.25.1/ # Installed version (persisted)
│ ├── go1.24.0/ # Installed version (persisted)
│ └── ...
└── cache/
├── go1.25.1.linux-amd64.tar.gz # Download cache (temporary)
└── ...
Ephemeral Data
- API responses (cached in memory for 10 minutes)
- Progress bar state
- Current session PATH modifications
Persistent Data
- Configuration file
- Installed Go versions
- Download cache (until cleaned)
- Shell configuration (in shell RC files)
- .govman-goversion project files
Concurrency
govman is primarily single-threaded for simplicity and safety:
No Concurrent Operations
- Only one
govmancommand runs at a time per user - Configuration updates are atomic (write to temp, then rename)
- No lock files needed (user-space isolation)
Safe Concurrency
- Multiple users can run govman simultaneously (separate home directories)
- Download cache uses file system atomicity
- Symlink updates are atomic at OS level
API Interactions
go.dev API
Endpoint: https://go.dev/dl/?mode=json&include=all
Request:
GET https://go.dev/dl/?mode=json&include=all
Response: JSON array of releases
Caching: 10 minutes in-memory
GitHub API (Self-Update)
Endpoint: https://api.github.com/repos/justjundana/govman/releases/latest
Request:
GET https://api.github.com/repos/justjundana/govman/releases/latest
Response: JSON release object
Caching: None (explicit user action)
Data Transformation
Version String Normalization
User input → "latest"
↓ resolve
API query → All stable versions
↓ sort
Semantic version comparison
↓ select
"1.25.1"
↓ use in
Installation/switching
Path Handling
Config: install_dir: "~/.govman/versions"
↓ expand
Absolute: "/home/user/.govman/versions"
↓ validate
Check no ".." traversal
↓ use in
File operations