-
-
Notifications
You must be signed in to change notification settings - Fork 1
version management
Complete guide to managing versions in CyberPatchMaker.
CyberPatchMaker uses a version registry system that tracks all registered software versions and their locations. Versions can be stored anywhere on your system - different drives, network paths, or even cloud storage mounts.
Key Concepts:
- Version Directory: A folder containing a complete snapshot of your software at a specific version
- Version Number: A unique identifier (e.g., 1.0.0, 2.1.3) following semantic versioning
- Key File: A designated file (usually main executable) that uniquely identifies the version
- Version Registry: Internal tracking of all registered versions and their locations
Each version is a complete directory containing all files for that version:
versions/
├── 1.0.0/ # Version 1.0.0
│ ├── program.exe # Key file (main executable)
│ ├── data/
│ │ ├── config.json
│ │ └── assets/
│ │ └── image.png
│ └── libs/
│ └── library.dll
├── 1.0.1/ # Version 1.0.1
│ ├── program.exe
│ ├── data/
│ │ ├── config.json
│ │ └── assets/
│ │ ├── image.png
│ │ └── new_image.png # New file
│ └── libs/
│ └── library.dll
└── 1.0.2/ # Version 1.0.2
├── program.exe
├── data/
│ └── config.json
│ # assets/ folder removed
└── libs/
└── library.dll
A key file is a designated file that uniquely identifies a version. It's typically the main program executable.
Purpose:
- Uniquely identifies each version
- Prevents applying wrong patches
- Detects corrupted installations
How it works:
- System calculates SHA-256 hash of key file
- Hash is stored in version manifest
- Hash is embedded in patch files
- Patch applier verifies hash before applying
The generator automatically detects key files using this priority order:
-
program.exe(highest priority) game.exeapp.exemain.exe
Note: If none of these files are found, you must specify a key file manually using the --key-file option.
Example:
Version directory contains:
├── myapp.exe
├── game.exe
├── launcher.exe
└── data/
Key file selected: game.exe (priority 2)
Follow semantic versioning format: MAJOR.MINOR.PATCH
1.0.0 → 1.0.1 # Patch release (bug fixes)
1.0.1 → 1.1.0 # Minor release (new features)
1.1.0 → 2.0.0 # Major release (breaking changes)
Why use semantic versioning?
- Clear upgrade path
- Easy to understand changes
- Standard convention
- Predictable version ordering
Good:
1.0.0, 1.0.1, 1.0.2, 1.1.0, 2.0.0
Avoid:
v1.0.0 # Don't use 'v' prefix
1.0 # Always use three parts
1.0.0.1 # Don't use four parts
2023-01-15 # Don't use dates
alpha, beta # Don't use text-only versions
Pre-release versions:
1.0.0-alpha
1.0.0-beta
1.0.0-rc1
Build metadata:
1.0.0+20230115
1.0.0+build.123
All versions in one directory:
versions/
├── 1.0.0/
├── 1.0.1/
├── 1.0.2/
├── 1.1.0/
└── 2.0.0/
Pros:
- Simple and clear
- Easy to navigate
- Works for most projects
Cons:
- Can get cluttered with many versions
Group by major version:
versions/
├── v1/
│ ├── 1.0.0/
│ ├── 1.0.1/
│ ├── 1.0.2/
│ └── 1.1.0/
└── v2/
├── 2.0.0/
├── 2.0.1/
└── 2.1.0/
Pros:
- Organized for large projects
- Clear major version separation
Cons:
- More complex structure
- Nested paths
Organize by release date:
versions/
├── 2023/
│ ├── 01-January/
│ │ └── 1.0.0/
│ └── 02-February/
│ └── 1.0.1/
└── 2024/
└── 01-January/
└── 2.0.0/
Pros:
- Historical context
- Easy to find by date
Cons:
- Harder to find specific version
- Not version-number ordered
Versions on different storage:
C:\releases\ # Production releases
├── 1.0.0/
├── 1.0.1/
└── 1.0.2/
D:\dev-builds\ # Development builds
├── 1.1.0-alpha/
└── 1.1.0-beta/
\\server\archive\ # Archived versions
├── 0.9.0/
└── 0.9.5/
Pros:
- Separation of concerns
- Different storage types
- Network/cloud storage support
Cons:
- More complex management
- Multiple locations to track
The version.Manager (in internal/core/version/manager.go) provides the following public methods:
| Method | Description |
|---|---|
NewManager() |
Create a new version manager with default settings (single-threaded) |
SetWorkerThreads(threads int) |
Set number of parallel workers for scanning (minimum 1) |
GetScanCache() |
Returns the *cache.ScanCache instance (nil if caching not enabled) |
GetRegistry() |
Returns the *Registry containing all registered versions |
SaveRegistry(filePath string) |
Persist all version manifests to disk (each version gets its own JSON file in a manifests/ subdirectory) |
LoadRegistry(filePath string) |
Load version manifests from disk (reads all .json files from the manifests/ subdirectory) |
EnableScanCache(cacheDir string, forceRescan bool) |
Enable scan caching with specified cache directory |
RegisterVersion(versionNumber, location, keyFilePath string) |
Register and scan a new version |
UnregisterVersion(versionNumber string) |
Remove a version from the registry |
GetVersion(versionNumber string) |
Retrieve a registered version (returns *utils.Version, error) |
ListVersions() |
Return all registered versions |
RescanVersion(versionNumber string) |
Rescan a version's directory and update its manifest |
VerifyVersion(versionNumber string) |
Verify all files in a version match their checksums (returns []string, error) |
When generating patches, versions are automatically registered:
# This automatically registers all versions in ./versions
patch-gen --versions-dir ./versions \
--new-version 1.0.2 \
--output ./patches- Scan versions directory: Find all subdirectories
- Validate version names: Must be valid version numbers
- Find key file: Use priority order (program.exe → game.exe → app.exe → main.exe)
- Calculate hash: SHA-256 of key file
- Scan files: Recursively scan all files and directories
- Create manifest: Store file list with hashes
- Register version: Add to internal registry
Required for valid version:
- ✓ Directory exists
- ✓ Contains at least one file
- ✓ Has detectable key file
- ✓ Name follows semantic versioning format (recommended but not enforced)
Example validation:
# Valid
./versions/1.0.0/ # ✓ Valid version number
├── program.exe # ✓ Has key file
└── data/
└── config.json # ✓ Has files
# Invalid
./versions/latest/ # ✗ Not a semantic version
./versions/1.0.0/ # ✗ Directory empty
./versions/v1.0.0/ # ✗ "v" prefix not recommended1. Archive old versions:
# Move old versions to archive
mkdir versions/archive
mv versions/0.* versions/archive/2. Use symbolic links:
# Link to versions on different drives
ln -s /mnt/storage/versions/1.0.0 versions/1.0.03. Generate patches incrementally:
# Generate patches for recent versions only
patch-gen --versions-dir ./versions \
--new-version 2.1.0 \
--from 2.0.0 \
--output ./patches
patch-gen --versions-dir ./versions \
--new-version 2.1.0 \
--from 2.0.5 \
--output ./patches4. Clean up old patches:
# Keep only recent patches
rm patches/0.*-to-*.patch
rm patches/1.0.*-to-*.patchScanning time:
- 10 versions: < 1 second
- 100 versions: < 10 seconds
- 1000 versions: < 2 minutes
Factors affecting performance:
- Number of files per version
- Storage speed (SSD vs HDD)
- Network latency (for network paths)
Optimization tips:
- Use local storage for active versions
- Archive old versions to slower storage
- Use SSD for version directories
- Limit number of active versions
-
Identify versions to remove:
# List all versions ls -la versions/ # Check which patches exist ls -la patches/
-
Verify not needed:
- Are patches still being generated from this version?
- Do users still need to upgrade from this version?
- Is this version used for testing?
-
Archive before deleting:
# Create archive mkdir versions/archive # Move old versions mv versions/0.9.* versions/archive/ # Compress archive (optional) tar -czf versions-archive-2023.tar.gz versions/archive/
-
Delete safely:
# Delete archived versions rm -rf versions/archive/
Example cleanup script (Bash):
#!/bin/bash
# Keep versions from last 6 months
CUTOFF_DATE=$(date -d '6 months ago' +%s)
# Find old versions
for VERSION_DIR in versions/*/; do
VERSION_TIME=$(stat -c %Y "$VERSION_DIR")
if [ "$VERSION_TIME" -lt "$CUTOFF_DATE" ]; then
echo "Archiving old version: $VERSION_DIR"
mv "$VERSION_DIR" versions/archive/
fi
done
# Compress archive
tar -czf versions-archive-$(date +%Y%m%d).tar.gz versions/archive/
rm -rf versions/archive/Scenario: Moving versions from C: to D:
# 1. Copy versions to new location
xcopy C:\versions D:\versions /E /I
# 2. Update generator usage
patch-gen --versions-dir D:\versions \
--new-version 1.0.3 \
--output D:\patches
# 3. Verify patches work
patch-apply --patch D:\patches\1.0.0-to-1.0.3.patch \
--current-dir ./test-app \
--dry-run \
--verify
# 4. Delete old versions (after verification)
rm -rf C:\versionsScenario: Moving to network share
# Windows - Map network drive
net use Z: \\server\software-versions
# Copy versions
xcopy C:\versions Z:\versions /E /I
# Update generator usage
.\patch-gen.exe --versions-dir Z:\versions `
--new-version 1.0.3 `
--output Z:\patchesScenario: Moving to cloud storage (Dropbox, OneDrive, etc.)
# 1. Move versions to cloud folder
mv versions ~/Dropbox/CyberPatchMaker/versions
# 2. Create symbolic link (optional)
ln -s ~/Dropbox/CyberPatchMaker/versions versions
# 3. Generate patches
patch-gen --versions-dir ~/Dropbox/CyberPatchMaker/versions \
--new-version 1.0.3 \
--output ~/Dropbox/CyberPatchMaker/patchesNote: Cloud storage may be slower due to sync time.
Manual comparison:
# Linux/macOS - Use diff
diff -r versions/1.0.0 versions/1.0.1
# Show only differences
diff -rq versions/1.0.0 versions/1.0.1
# Windows - Use fc or PowerShell
fc /b versions\1.0.0\program.exe versions\1.0.1\program.exeOutput from generator shows:
Comparing versions 1.0.0 → 1.0.1:
Files added: 5
Files modified: 12
Files deleted: 3
Total changes: 20
Recommended: Version changelog:
versions/
├── 1.0.0/
├── 1.0.1/
├── 1.0.2/
└── CHANGELOG.md # Track changes
CHANGELOG.md example:
# Changelog
## 1.0.2 - 2024-01-15
### Added
- New configuration options
### Fixed
- Bug in file processing
## 1.0.1 - 2024-01-10
### Fixed
- Critical security vulnerability
## 1.0.0 - 2024-01-01
### Initial Release- Use semantic versioning (MAJOR.MINOR.PATCH)
- Keep version directories organized
- Archive old versions regularly
- Document changes in CHANGELOG
- Verify versions after copying/moving
- Use consistent naming conventions
- Test patches after generating
- Use 'v' prefix in version numbers
- Mix version formats (1.0 vs 1.0.0)
- Delete versions without archiving
- Store versions on slow network drives (if possible)
- Modify version directories after registration
- Use spaces or special characters in version numbers
Cause: Version directory doesn't exist or path is wrong
Solution:
# Check versions directory
ls -la versions/
# Verify version exists
ls -la versions/1.0.0/
# Use absolute path
patch-gen --versions-dir /full/path/to/versions \
--new-version 1.0.1 \
--output ./patchesCause: Version name doesn't follow semantic versioning
Solution:
# Rename version directory
mv versions/v1.0.0 versions/1.0.0
mv versions/version-1.0 versions/1.0.0
mv versions/latest versions/1.0.0Cause: No recognized executable in version directory
Solution:
# Add a key file
cp myapp.exe versions/1.0.0/program.exe
# Or rename existing file
mv versions/1.0.0/myapp.exe versions/1.0.0/program.exe- Quick Start - Getting started
- Generator Guide - Generating patches
- Architecture - System design
- Troubleshooting - Common issues