Documentation
¶
Overview ¶
Package provider reads another repository's ebuild versions, for comparing the overlay against it and reviving packages from it. Provider is the interface; it is implemented over the GitHub and GitLab APIs, a shallow git clone kept in a cache, and a local tree read in place.
Index ¶
- Constants
- Variables
- func ListAvailableRepositories(ctx context.Context, configRepos map[string]*RepositoryInfo, ...) []string
- func ValidateBranch(b string) error
- func ValidateRepoURL(raw string) error
- type CacheEntry
- type ContentEntry
- type GitCloneProvider
- func (p *GitCloneProvider) Close() error
- func (p *GitCloneProvider) ForceUpdate() error
- func (p *GitCloneProvider) GetName() string
- func (p *GitCloneProvider) GetPackageVersions(ctx context.Context, category, pkg string) ([]string, error)
- func (p *GitCloneProvider) LocalPackagePath(category, pkg string) (string, error)
- func (p *GitCloneProvider) RemoveCache() error
- func (p *GitCloneProvider) SetReporter(r tui.Reporter, id string)
- func (p *GitCloneProvider) SupportsAPI() bool
- type GitHubProvider
- func (p *GitHubProvider) Close() error
- func (p *GitHubProvider) GetName() string
- func (p *GitHubProvider) GetPackageVersions(ctx context.Context, category, pkg string) ([]string, error)
- func (p *GitHubProvider) GetRateLimitInfo(ctx context.Context) (remaining int, resetTime time.Time, err error)
- func (p *GitHubProvider) SetCacheDir(dir string) error
- func (p *GitHubProvider) SupportsAPI() bool
- type GitLabProvider
- type GitLabTreeEntry
- type PackageDirProvider
- type Provider
- type RepositoryInfo
- type RepositoryRegistry
Constants ¶
const DefaultGitCloneTimeout = 5 * time.Minute
DefaultGitCloneTimeout bounds each git run the provider makes against its remote: a clone, and an update's pull, fetch and reset taken together. When it elapses, git and every process it started are stopped, and the error wraps context.DeadlineExceeded and reads "git <op> timed out after 5m0s".
Variables ¶
var ( // ErrRepositoryNotFound indicates the repository was not found ErrRepositoryNotFound = errors.New("repository not found") // ErrInvalidProvider indicates an invalid provider type ErrInvalidProvider = errors.New("invalid provider type") )
var ( // ErrNotFound indicates the requested resource was not found ErrNotFound = errors.New("package not found in repository") // ErrRateLimit indicates API rate limit exceeded ErrRateLimit = errors.New("API rate limit exceeded") // ErrAPIError indicates a general API error ErrAPIError = errors.New("API error") // An error carrying it also matches ErrAPIError, so callers that only // know about ErrAPIError keep treating a 401 as one. ErrUnauthorized = errors.New("authentication rejected") // ErrCloneFailed indicates git clone operation failed ErrCloneFailed = errors.New("git clone failed") // ErrInvalidRepoURL indicates the repository URL has a scheme outside the // allowed set {http, https, git, ssh}, or an empty host. ErrInvalidRepoURL = errors.New("invalid repository URL") // ErrInvalidBranch indicates the git branch name fails git check-ref-format // style validation (control chars, "..", "@{", a leading "-", shell // metacharacters, and similar unsafe constructs). ErrInvalidBranch = errors.New("invalid git branch name") )
Functions ¶
func ListAvailableRepositories ¶
func ListAvailableRepositories(ctx context.Context, configRepos map[string]*RepositoryInfo, registry *RepositoryRegistry) []string
ListAvailableRepositories returns a sorted list of all available repository names from both config and registry sources, deduplicated.
func ValidateBranch ¶
ValidateBranch validates a git branch name against a conservative subset of "git check-ref-format". It rejects b when it:
- is empty,
- contains whitespace,
- contains an ASCII control character,
- contains the ".." sequence,
- contains the "@{" sequence,
- has a leading "-" (which enables git flag-injection),
- contains any of the metacharacters ~ ^ : ? * [ \,
- contains a Unicode right-to-left override (U+202E),
- contains a NUL byte,
- starts with "/", ends with "/", or contains "//" (empty path component),
- ends with ".",
- is exactly "@", or
- has a "/"-separated component that starts with "." or ends with ".lock".
On failure it returns an error wrapping ErrInvalidBranch. The rule set is intentionally never more permissive than git: any branch this function accepts also passes "git check-ref-format --branch".
func ValidateRepoURL ¶
ValidateRepoURL parses raw with net/url and rejects any repository URL whose scheme is outside the allowed set {http, https, git, ssh} or whose host is empty. The scheme comparison is case-insensitive.
A URL whose trimmed form begins with "-" is rejected outright (before any parsing): git would otherwise treat such a positional argument as an option, enabling flag-injection (e.g. "--upload-pack=...").
The scp-like SSH shorthand "user@host:path" (which net/url cannot parse) is treated as a valid SSH remote: it has no scheme and no shell metacharacters of concern here, and the design explicitly allows the "ssh" transport.
On failure it returns an error wrapping ErrInvalidRepoURL.
Types ¶
type CacheEntry ¶
type CacheEntry struct {
Versions []string `json:"versions"`
Timestamp time.Time `json:"timestamp"`
}
CacheEntry represents a cached API response
type ContentEntry ¶
type ContentEntry struct {
Name string `json:"name"`
Path string `json:"path"`
Type string `json:"type"` // "file" or "dir"
DownloadURL string `json:"download_url,omitempty"`
}
ContentEntry represents a file/directory entry from GitHub Contents API
type GitCloneProvider ¶
type GitCloneProvider struct {
RepoURL string
LocalPath string
Branch string
RepoName string
// UpdateInterval is how often to pull updates (default: 24h)
UpdateInterval time.Duration
// contains filtered or unexported fields
}
GitCloneProvider fetches package versions by cloning a git repository
func NewGitCloneProvider ¶
func NewGitCloneProvider(repoInfo *RepositoryInfo) (*GitCloneProvider, error)
NewGitCloneProvider creates a new git clone provider.
The resolved repository URL and branch name are validated before any work is done: a malicious scheme (e.g. file://, javascript:) or a branch name that enables git flag-injection causes an early error wrapping ErrInvalidRepoURL or ErrInvalidBranch respectively.
func NewLocalProvider ¶
func NewLocalProvider(repoInfo *RepositoryInfo) (*GitCloneProvider, error)
NewLocalProvider builds a provider that reads an on-disk package tree in place (provider "local"), without cloning. repoInfo.Path must be an existing directory; it is resolved to an absolute path and used as LocalPath directly. This is the "local tree" the revive/compare guidance documents — e.g. a synced /var/db/repos/gentoo, which has no .git of its own.
func (*GitCloneProvider) Close ¶
func (p *GitCloneProvider) Close() error
Close cleans up resources (nothing to clean for git clone)
func (*GitCloneProvider) ForceUpdate ¶
func (p *GitCloneProvider) ForceUpdate() error
ForceUpdate forces an update of the repository regardless of age. It is a no-op for a local in-place tree, which bentoo does not own and must not pull.
func (*GitCloneProvider) GetName ¶
func (p *GitCloneProvider) GetName() string
GetName returns the provider name
func (*GitCloneProvider) GetPackageVersions ¶
func (p *GitCloneProvider) GetPackageVersions(ctx context.Context, category, pkg string) ([]string, error)
GetPackageVersions returns all ebuild versions for a package. A ctx that is already done returns its error before the repository is touched.
func (*GitCloneProvider) LocalPackagePath ¶
func (p *GitCloneProvider) LocalPackagePath(category, pkg string) (string, error)
LocalPackagePath returns the on-disk directory for a package in the cloned repository, ensuring the repo is present/up-to-date first. It returns ErrNotFound if the package directory does not exist.
func (*GitCloneProvider) RemoveCache ¶
func (p *GitCloneProvider) RemoveCache() error
RemoveCache removes the cached repository. It is a no-op for a local in-place tree: LocalPath there is the user's real tree (e.g. /var/db/repos/gentoo), not a bentoo-managed cache, so os.RemoveAll must never run against it.
func (*GitCloneProvider) SetReporter ¶
func (p *GitCloneProvider) SetReporter(r tui.Reporter, id string)
SetReporter wires a reporter and task id for clone stage/done/tail events. A nil reporter is normalized to tui.Noop().
func (*GitCloneProvider) SupportsAPI ¶
func (p *GitCloneProvider) SupportsAPI() bool
SupportsAPI returns false - this provider uses git clone, not API
type GitHubProvider ¶
type GitHubProvider struct {
BaseURL string
Repository string // e.g., "gentoo/gentoo"
UserAgent string
Token string
HTTPClient *http.Client
CacheDir string
CacheTTL time.Duration
}
GitHubProvider fetches package versions from GitHub API
func NewGitHubProvider ¶
func NewGitHubProvider(repoInfo *RepositoryInfo) (*GitHubProvider, error)
NewGitHubProvider creates a new GitHub API provider
func (*GitHubProvider) GetName ¶
func (p *GitHubProvider) GetName() string
GetName returns the provider name
func (*GitHubProvider) GetPackageVersions ¶
func (p *GitHubProvider) GetPackageVersions(ctx context.Context, category, pkg string) ([]string, error)
GetPackageVersions fetches all ebuild versions for a package from GitHub
func (*GitHubProvider) GetRateLimitInfo ¶
func (p *GitHubProvider) GetRateLimitInfo(ctx context.Context) (remaining int, resetTime time.Time, err error)
GetRateLimitInfo returns current rate limit status. The request is bound to ctx: cancelling it aborts the lookup in flight, and the returned error wraps ctx.Err().
func (*GitHubProvider) SetCacheDir ¶
func (p *GitHubProvider) SetCacheDir(dir string) error
SetCacheDir sets the cache directory for API responses
func (*GitHubProvider) SupportsAPI ¶
func (p *GitHubProvider) SupportsAPI() bool
SupportsAPI returns true
type GitLabProvider ¶
type GitLabProvider struct {
BaseURL string // e.g., "https://gitlab.com" or "https://gitlab.gentoo.org"
ProjectID string // URL-encoded project path or numeric ID
Token string
UserAgent string
HTTPClient *http.Client
CacheDir string
CacheTTL time.Duration
}
GitLabProvider fetches package versions from GitLab API
func NewGitLabProvider ¶
func NewGitLabProvider(repoInfo *RepositoryInfo) (*GitLabProvider, error)
NewGitLabProvider creates a new GitLab API provider
func (*GitLabProvider) GetName ¶
func (p *GitLabProvider) GetName() string
GetName returns the provider name
func (*GitLabProvider) GetPackageVersions ¶
func (p *GitLabProvider) GetPackageVersions(ctx context.Context, category, pkg string) ([]string, error)
GetPackageVersions fetches all ebuild versions for a package from GitLab
func (*GitLabProvider) SupportsAPI ¶
func (p *GitLabProvider) SupportsAPI() bool
SupportsAPI returns true
type GitLabTreeEntry ¶
type GitLabTreeEntry struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"` // "blob" or "tree"
Path string `json:"path"`
Mode string `json:"mode"`
}
GitLabTreeEntry represents a file/directory entry from GitLab Repository Tree API
type PackageDirProvider ¶
PackageDirProvider is implemented by providers that expose an on-disk package directory (git clone / local tree). The revive flow type-asserts to it (autoupdate.CanRevive); an API-only provider simply does not implement it, which is the "API-only" signal.
type Provider ¶
type Provider interface {
// GetPackageVersions returns all ebuild versions for a package. ctx ends
// the lookup: an HTTP implementation sends its request with it.
GetPackageVersions(ctx context.Context, category, pkg string) ([]string, error)
// GetName returns a human-readable name for this provider
GetName() string
// SupportsAPI returns true if this provider uses an API (vs git clone)
SupportsAPI() bool
// Close cleans up any resources (e.g., temporary directories)
Close() error
}
Provider is the interface for fetching package versions from a repository
func NewProvider ¶
func NewProvider(repoInfo *RepositoryInfo, forceClone bool) (Provider, error)
NewProvider creates a new Provider based on the repository info If forceClone is true, always use git clone instead of API
type RepositoryInfo ¶
type RepositoryInfo struct {
Name string // e.g., "gentoo", "guru", "my-overlay"
Provider string // "github", "gitlab", "git", "local"
URL string // Full URL or org/repo for GitHub/GitLab/git (remote)
Path string // On-disk tree for provider "local" (read in place, no clone)
Token string // Optional auth token
Branch string // Branch to use (default: master/main)
}
RepositoryInfo contains information about a repository to compare against
func ResolveRepository ¶
func ResolveRepository(ctx context.Context, name string, configRepos map[string]*RepositoryInfo, registry *RepositoryRegistry) (*RepositoryInfo, error)
ResolveRepository resolves a repository name to its full info. Priority: config repos > registry > error.
func (*RepositoryInfo) Clone ¶
func (r *RepositoryInfo) Clone() *RepositoryInfo
Clone returns a copy of the RepositoryInfo
type RepositoryRegistry ¶
type RepositoryRegistry struct {
CacheDir string
CacheTTL time.Duration
XMLPath string
// contains filtered or unexported fields
}
RepositoryRegistry fetches, caches, and parses repositories.xml
func NewRepositoryRegistry ¶
func NewRepositoryRegistry() (*RepositoryRegistry, error)
func (*RepositoryRegistry) List ¶
func (r *RepositoryRegistry) List(ctx context.Context) ([]string, error)
List returns every repository name in the registry, sorted; a download it needs is cancellable through ctx.
func (*RepositoryRegistry) Resolve ¶
func (r *RepositoryRegistry) Resolve(ctx context.Context, name string) (*RepositoryInfo, error)
Resolve looks name up in the registry; a download it needs is cancellable through ctx.