Documentation
¶
Overview ¶
Copyright (c) 2025 Guilherme Silva Sousa Licensed under the MIT License See LICENSE file in the project root for full license information. Package repository provides interfaces and implementations for managing command repositories.
The repository package defines a flexible system for discovering, loading, and managing commands from various sources including local directories, Git repositories, and remote catalogs. It provides a unified interface that allows ccmd to work with multiple repository types seamlessly.
Core Concepts ¶
Repository: A source of commands, which can be local, remote, or version-controlled. Each repository type implements the Repository interface to provide consistent access to commands regardless of the underlying storage mechanism.
Manager: Handles the lifecycle of repository instances and maintains a registry of available repository types. New repository types can be registered at runtime.
Workspace: Provides a unified view across multiple repositories, handling command resolution, version management, and repository prioritization.
Repository Types ¶
The package supports several repository types out of the box:
- Local: Commands stored in local directories
- Git: Commands in Git repositories (with branch/tag support)
- HTTP: Commands served from HTTP endpoints
- S3: Commands stored in S3-compatible object storage
Usage Example ¶
// Create a repository manager
manager := repository.NewManager()
// Register repository types
manager.Register("local", repository.NewLocalFactory())
manager.Register("git", repository.NewGitFactory())
// Create a repository instance
repo, err := manager.Create("local", map[string]interface{}{
"path": "/path/to/commands",
})
if err != nil {
log.Fatal(err)
}
// Initialize and discover commands
ctx := context.Background()
if err := repo.Initialize(ctx); err != nil {
log.Fatal(err)
}
commands, err := repo.Discover(ctx)
if err != nil {
log.Fatal(err)
}
Extending with Custom Repository Types ¶
Custom repository types can be added by implementing the Repository interface and registering a factory function:
type MyCustomRepo struct {
// implementation
}
func (r *MyCustomRepo) Initialize(ctx context.Context) error {
// implementation
}
// ... implement other Repository methods
// Register the custom type
manager.Register("custom", func(config map[string]interface{}) (Repository, error) {
return &MyCustomRepo{
// initialize from config
}, nil
})
Error Handling ¶
The package defines specific error types for common failure scenarios:
- ErrRepositoryNotFound: Repository doesn't exist or is inaccessible
- ErrCommandNotFound: Command doesn't exist in the repository
- ErrInvalidConfiguration: Repository configuration is invalid
- ErrAuthenticationFailed: Repository requires authentication
Performance Considerations ¶
For remote repositories, implementations should consider:
- Caching discovered commands to reduce network calls
- Lazy loading of command details and resources
- Parallel discovery for improved performance
- Progress reporting for long-running operations
Security Considerations ¶
Repository implementations must:
- Validate all file paths to prevent directory traversal
- Sanitize command metadata to prevent injection attacks
- Handle credentials securely (never log or expose them)
- Verify checksums/signatures for downloaded content
Copyright (c) 2025 Guilherme Silva Sousa Licensed under the MIT License See LICENSE file in the project root for full license information.
Copyright (c) 2025 Guilherme Silva Sousa Licensed under the MIT License See LICENSE file in the project root for full license information.
Copyright (c) 2025 Guilherme Silva Sousa Licensed under the MIT License See LICENSE file in the project root for full license information.
Copyright (c) 2025 Guilherme Silva Sousa Licensed under the MIT License See LICENSE file in the project root for full license information.
Index ¶
- Variables
- func List() []string
- func NewCommandError(commandID, op string, err error) error
- func NewRepositoryError(op, repo string, err error, details string) error
- func Register(repoType string, factory Factory)
- type CacheableRepository
- type CommandError
- type Error
- type Factory
- type Manager
- type Repository
- type Workspace
Constants ¶
This section is empty.
Variables ¶
var ( // ErrRepositoryNotFound indicates the repository doesn't exist or is inaccessible ErrRepositoryNotFound = fmt.Errorf("repository not found") // ErrCommandNotFound indicates the command doesn't exist in the repository ErrCommandNotFound = fmt.Errorf("command not found") // ErrInvalidConfiguration indicates the repository configuration is invalid ErrInvalidConfiguration = fmt.Errorf("invalid repository configuration") // ErrAuthenticationFailed indicates authentication to the repository failed ErrAuthenticationFailed = fmt.Errorf("authentication failed") // ErrResourceNotFound indicates the requested resource doesn't exist ErrResourceNotFound = fmt.Errorf("resource not found") // ErrUnsupportedOperation indicates the operation is not supported by this repository type ErrUnsupportedOperation = fmt.Errorf("unsupported operation") // ErrCacheExpired indicates the cache is outdated and needs refresh ErrCacheExpired = fmt.Errorf("cache expired") // ErrNetworkError indicates a network-related error occurred ErrNetworkError = fmt.Errorf("network error") // ErrVersionConflict indicates multiple versions exist and resolution is ambiguous ErrVersionConflict = fmt.Errorf("version conflict") // ErrPermissionDenied indicates insufficient permissions to access the repository ErrPermissionDenied = fmt.Errorf("permission denied") )
Common error types for repository operations
var DefaultManager = NewManager()
DefaultManager is the global repository manager instance
Functions ¶
func NewCommandError ¶
NewCommandError creates a new CommandError
func NewRepositoryError ¶
NewRepositoryError creates a new repository Error
Types ¶
type CacheableRepository ¶
type CacheableRepository interface {
Repository
// RefreshCache updates the local cache with latest repository data.
//
// Parameters:
// - ctx: Context for cancellation and deadline control
//
// Returns:
// - error: Any error during cache refresh
RefreshCache(ctx context.Context) error
// ClearCache removes all cached data for this repository.
//
// Returns:
// - error: Any error during cache clearing
ClearCache() error
// GetCacheInfo returns information about the current cache state.
//
// Returns:
// - model.CacheInfo: Cache statistics and metadata
//
// TODO: Define CacheInfo model structure
GetCacheInfo() model.CacheInfo
}
CacheableRepository extends Repository with caching capabilities. Implementations can use this to improve performance for remote repositories.
type CommandError ¶
type CommandError struct {
CommandID string // Command identifier
Op string // Operation that failed
Err error // Underlying error
}
CommandError provides detailed error information for command operations
func (*CommandError) Error ¶
func (e *CommandError) Error() string
func (*CommandError) Unwrap ¶
func (e *CommandError) Unwrap() error
type Error ¶
type Error struct {
Op string // Operation that failed
Repository string // Repository identifier
Err error // Underlying error
Details string // Additional details
}
Error provides detailed error information for repository operations
type Factory ¶
type Factory func(config map[string]interface{}) (Repository, error)
Factory is a function that creates a new Repository instance. It receives configuration specific to the repository type.
Parameters:
- config: Type-specific configuration map
Returns:
- Repository: New repository instance
- error: Any error during creation
Example configurations:
- Local: {"path": "/path/to/commands"}
- Git: {"url": "https://github.com/user/repo.git", "branch": "main"}
- HTTP: {"url": "https://catalog.example.com", "apiKey": "..."}
type Manager ¶
type Manager interface {
// Register adds a new repository type with its factory function.
//
// Parameters:
// - repoType: Unique identifier for the repository type
// - factory: Function to create instances of this type
Register(repoType string, factory Factory)
// Create instantiates a new repository of the specified type.
//
// Parameters:
// - repoType: Type of repository to create
// - config: Configuration for the repository
//
// Returns:
// - Repository: New repository instance
// - error: Any error during creation
Create(repoType string, config map[string]interface{}) (Repository, error)
// List returns all registered repository types.
//
// Returns:
// - []string: List of registered type identifiers
List() []string
}
Manager handles multiple repository instances and provides unified access. It maintains a registry of repository types and can create instances dynamically.
type Repository ¶
type Repository interface {
// Initialize sets up the repository connection and prepares for operations.
// It should validate connectivity, check authentication, and prepare any
// necessary local storage or caches.
//
// Parameters:
// - ctx: Context for cancellation and deadline control
//
// Returns:
// - error: Any error encountered during initialization
Initialize(ctx context.Context) error
// Discover searches for available commands in the repository.
// It should recursively scan for ccmd.yaml files and build a catalog
// of available commands with their metadata.
//
// Parameters:
// - ctx: Context for cancellation and deadline control
//
// Returns:
// - []model.CommandInfo: List of discovered commands with metadata
// - error: Any error encountered during discovery
//
// Note: Implementations should handle large repositories efficiently,
// potentially using pagination or streaming for better performance.
Discover(ctx context.Context) ([]model.CommandInfo, error)
// Load retrieves a specific command by its identifier.
// The identifier format depends on the repository type:
// - Local: file path relative to repository root
// - Git: combination of repository URL and path
// - Remote: URL or catalog-specific identifier
//
// Parameters:
// - ctx: Context for cancellation and deadline control
// - id: Unique identifier for the command
//
// Returns:
// - *model.Command: The loaded command with full configuration
// - error: Any error encountered during loading
Load(ctx context.Context, id string) (*model.Command, error)
// GetResource retrieves a resource file associated with a command.
// Resources can include templates, configuration files, or documentation.
//
// Parameters:
// - ctx: Context for cancellation and deadline control
// - commandID: Identifier of the command owning the resource
// - resourcePath: Path to the resource relative to the command
//
// Returns:
// - io.ReadCloser: Reader for the resource content (caller must close)
// - error: Any error encountered accessing the resource
//
// Note: Implementations should validate resource paths to prevent
// directory traversal attacks.
GetResource(ctx context.Context, commandID, resourcePath string) (io.ReadCloser, error)
// Type returns the repository type identifier.
// Common types include "local", "git", "http", "s3", etc.
//
// Returns:
// - string: Repository type identifier
Type() string
// Info returns metadata about the repository.
// This includes connection details, capabilities, and current status.
//
// Returns:
// - model.RepositoryInfo: Repository metadata and status
//
// TODO: Define RepositoryInfo model structure including:
// - Connection status and health
// - Supported features and limitations
// - Cache status and statistics
// - Authentication status
Info() model.RepositoryInfo
}
Repository defines the interface for managing command repositories. It provides operations for discovering, loading, and accessing commands from various sources like local directories, Git repositories, and remote catalogs.
Implementation consideration: In Docker-in-Docker environments, git operations may fail with authentication issues. Implementations should handle these gracefully and provide fallback options (e.g., using cached data or local repositories).
type Workspace ¶
type Workspace interface {
// AddRepository adds a new repository to the workspace.
//
// Parameters:
// - repo: Repository instance to add
// - name: Unique name for this repository in the workspace
//
// Returns:
// - error: Any error during addition
AddRepository(repo Repository, name string) error
// RemoveRepository removes a repository from the workspace.
//
// Parameters:
// - name: Name of the repository to remove
//
// Returns:
// - error: Any error during removal
RemoveRepository(name string) error
// ListCommands returns all available commands across all repositories.
//
// Parameters:
// - ctx: Context for cancellation and deadline control
//
// Returns:
// - []model.CommandInfo: Aggregated list of all commands
// - error: Any error during listing
ListCommands(ctx context.Context) ([]model.CommandInfo, error)
// ResolveCommand finds and loads a command by name across all repositories.
// It should handle version resolution and repository priority.
//
// Parameters:
// - ctx: Context for cancellation and deadline control
// - name: Command name to resolve
// - version: Specific version or version constraint (optional)
//
// Returns:
// - *model.Command: Resolved and loaded command
// - error: Any error during resolution
ResolveCommand(ctx context.Context, name, version string) (*model.Command, error)
}
Workspace provides a unified interface for accessing multiple repositories. It manages repository lifecycle and provides command resolution across sources.