Documentation ¶
Overview ¶
borges archives repositories in a universal git library.
The goal of borges is fetching repositories and maintain them updated. Repositories are arranged in a repository storage where that contains one repository per init commit found.
We define root commit as any commit with no parents (the first commit of a repository). Note that a repository can contain multiple root commits.
For each reference, we define its init commit as the root commit that is reached by following the first parent of each commit in the history. This is the commit that would be obtained with:
$ git rev-list --first-parent <ref> | tail -n 1
When borges fetches a repository, it groups all references by init commit and pushes each group of references to a repository for its init commit.
Index ¶
- Constants
- Variables
- func RepositoryID(endpoints []string, isFork *bool, storer storage.RepoStore) (uuid.UUID, error)
- func ResolveCommit(r *git.Repository, h plumbing.Hash) (*object.Commit, error)
- func StoreConfig(r *git.Repository, mr *model.Repository) error
- type Action
- type Archiver
- type Changes
- type Command
- type Consumer
- type Executor
- type Job
- type JobIter
- type Producer
- type Referencer
- type TemporaryCloner
- type TemporaryRepository
- type Worker
- type WorkerJob
- type WorkerPool
Constants ¶
const ( Create Action = "create" Update = "update" Delete = "delete" Invalid = "invalid" )
const ( FetchRefSpec = config.RefSpec("refs/*:refs/*") FetchHEAD = config.RefSpec("HEAD:refs/heads/HEAD") )
Variables ¶
var ( ErrCleanRepositoryDir = errors.NewKind("cleaning up local repo dir failed") ErrClone = errors.NewKind("cloning %s failed") ErrPushToRootedRepository = errors.NewKind("push to rooted repo %s failed") ErrArchivingRoots = errors.NewKind("archiving %d out of %d roots failed: %s") ErrEndpointsEmpty = errors.NewKind("endpoints is empty") ErrRepositoryIDNotFound = errors.NewKind("repository id not found: %s") ErrChanges = errors.NewKind("error computing changes") ErrAlreadyFetching = errors.NewKind("repository %s was already in a fetching status") ErrSetStatus = errors.NewKind("unable to set repository to status: %s") )
var ( // ErrAlreadyStopped signals that an operation cannot be done because // the entity is already sopped. ErrAlreadyStopped = errors.NewKind("already stopped: %s") ErrWaitForJobs = errors.NewKind("no more jobs at the moment") ErrReferencedObjectTypeNotSupported error = stderrors.New("referenced object type not supported") )
Functions ¶
func RepositoryID ¶
RepositoryID tries to find a repository by the endpoint into the database. If no repository is found, it creates a new one and returns the ID.
func ResolveCommit ¶
ResolveCommit gets the hash of a commit that is referenced by a tag, per example. The only resolvable objects are Tags and Commits. If the object is not one of them, This method will return an ErrReferencedObjectTypeNotSupported. The output hash always will be a Commit hash.
func StoreConfig ¶ added in v0.6.0
func StoreConfig(r *git.Repository, mr *model.Repository) error
Types ¶
type Archiver ¶
type Archiver struct { // TemporaryCloner is used to clone repositories into temporary storage. TemporaryCloner TemporaryCloner // Timeout is the deadline to cancel a job. Timeout time.Duration // Store is the component where repository models are stored. Store storage.RepoStore // RootedTransactioner is used to push new references to our repository // storage. RootedTransactioner repository.RootedTransactioner // LockSession is a locker service to prevent concurrent access to the same // rooted reporitories. LockSession lock.Session // contains filtered or unexported fields }
Archiver archives repositories. Archiver instances are thread-safe and can be reused.
See borges documentation for more details about the archiving rules.
func NewArchiver ¶
func NewArchiver(log log15.Logger, r storage.RepoStore, tx repository.RootedTransactioner, tc TemporaryCloner, ls lock.Session, to time.Duration) *Archiver
type Changes ¶
Changes represents several actions to realize to our root repositories. The map key is the hash of a init commit, and the value is a slice of Command that can be add a new reference, delete a reference or update the hash a reference points to.
func NewChanges ¶
func NewChanges(old, new Referencer) (Changes, error)
NewChanges returns Changes needed to obtain the current state of the repository from a set of old references. The Changes could be create, update or delete. If an old reference has the same name of a new one, but the init commit is different, then the changes will contain a delete command and a create command. If a new reference has more than one init commit, at least one create command per init commit will be created.
Here are all possible cases for up to one reference. We use the notation a<11,01> to refer to reference 'a', pointing to hash '11' with initial commit '01'.
Old New Changes --- --- ------- Ø Ø Ø Ø a<11,01> 01 -> c<a,11> a<11,01> Ø 01 -> d<a,11> a<11,01> a<12,01> 01 -> u<a,11,12> a<11,01> a<11,02> 01 -> d<a,11> | 02 -> c<a,11> (invalid) a<11,01> a<12,02> 01 -> d<a,11> | 02 -> c<a,12>
type Command ¶
Command is the way to represent a change into a reference. It could be: - Create: A new reference is created - Update: A previous reference is updated. This means its head changes. - Delete: A previous reference does not exist now.
type Consumer ¶
type Consumer struct { Notifiers struct { QueueError func(error) } WorkerPool *WorkerPool Queue queue.Queue // contains filtered or unexported fields }
Consumer consumes jobs from a queue and uses multiple workers to process them.
func NewConsumer ¶
func NewConsumer(queue queue.Queue, pool *WorkerPool) *Consumer
NewConsumer creates a new consumer.
type Executor ¶ added in v0.8.0
type Executor struct {
// contains filtered or unexported fields
}
Executor retrieves jobs from an job iterator and passes them to a worker pool to be executed. Executor acts as a producer-consumer in a single component.
type Job ¶
type Job struct {
RepositoryID uuid.UUID
}
Job represents a borges job to fetch and archive a repository.
type JobIter ¶
type JobIter interface { io.Closer // Next returns the next job. It returns io.EOF if there are no more // jobs. If there are no more jobs at the moment, but there can be // in the future, it returns an error of kind ErrWaitForJobs. Next() (*Job, error) }
JobIter is an iterator of Job.
func NewLineJobIter ¶
func NewLineJobIter(r io.ReadCloser, storer storage.RepoStore) JobIter
NewLineJobIter returns a JobIter that returns jobs generated from a reader with a list of repository URLs, one per line.
type Producer ¶
type Producer struct {
// contains filtered or unexported fields
}
Producer is a service to generate jobs and put them to the queue.
func NewProducer ¶
NewProducer creates a new producer.
type Referencer ¶
type Referencer interface { // References retrieves a slice of *model.Reference or an error. References() ([]*model.Reference, error) }
Referencer can retrieve reference models (*model.Reference).
func NewGitReferencer ¶
func NewGitReferencer(r *git.Repository) Referencer
NewGitReferencer takes a *git.Repository and returns a Referencer that retrieves any valid reference from it. Symbolic references and references that do not point to commits (possibly through a tag) are silently ignored. It might return an error if any operation fails in the underlying repository.
func NewModelReferencer ¶
func NewModelReferencer(r *model.Repository) Referencer
NewModelReferencer takes a *model.Repository and returns a Referencer that accesses its references. The resulting Referencer never returns an error.
type TemporaryCloner ¶
type TemporaryCloner interface {
Clone(ctx context.Context, id, url string) (TemporaryRepository, error)
}
func NewTemporaryCloner ¶
func NewTemporaryCloner(tmpFs billy.Filesystem) TemporaryCloner
type TemporaryRepository ¶
type Worker ¶
type Worker struct {
// contains filtered or unexported fields
}
Worker is a worker that processes jobs from a channel.
func NewWorker ¶
NewWorker creates a new Worker. The first parameter is a WorkerContext that will be passed to the processing function on every call. The second parameter is the processing function itself that will be called for every job. The third parameter is a channel that the worker will consume jobs from.
type WorkerJob ¶
type WorkerJob struct { *Job queue.Acknowledger }
A WorkerJob is a job to be passed to the worker. It contains the Job itself and an acknowledger that the worker uses to signal that it finished the job.
type WorkerPool ¶
type WorkerPool struct {
// contains filtered or unexported fields
}
WorkerPool is a pool of workers that can process jobs.
func NewArchiverWorkerPool ¶
func NewArchiverWorkerPool( log log15.Logger, r storage.RepoStore, tx repository.RootedTransactioner, tc TemporaryCloner, ls lock.Service, to time.Duration) *WorkerPool
NewArchiverWorkerPool creates a new WorkerPool that uses an Archiver to process jobs. It takes optional start, stop and warn notifier functions that are equal to the Archiver notifiers but with additional WorkerContext.
func NewWorkerPool ¶
NewWorkerPool creates a new empty worker pool. It takes a function to be used by workers to process jobs. The pool is started with no workers. SetWorkerCount must be called to start them.
func (*WorkerPool) Close ¶
func (wp *WorkerPool) Close() error
Close stops all the workers in the pool and frees resources used by it. Workers are It blocks until it finishes.
func (*WorkerPool) Do ¶
func (wp *WorkerPool) Do(j *WorkerJob)
Do executes a job. It blocks until a worker is assigned to process the job and then it returns, with the worker processing the job asynchronously.
func (*WorkerPool) Len ¶
func (wp *WorkerPool) Len() int
Len returns the number of workers currently in the pool.
func (*WorkerPool) SetWorkerCount ¶
func (wp *WorkerPool) SetWorkerCount(workers int)
SetWorkerCount changes the number of running workers. Workers will be started or stopped as necessary to satisfy the new worker count. It blocks until the all required workers are started or stopped. Each worker, if busy, will finish its current job before stopping.