func (r *Repo) errorIfNotReady() error {
	switch r.status {
	case RepoReady:
		return nil
	case RepoNoConfig:
		return ErrNoConfig
	default:
		return NotReadyError{r.err}
	}
}
errorIfNotReady returns the appropriate error if the repo is not
ready, and `nil` otherwise.
package git
import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"sync"
	"context"
	"time"
)
const (
	defaultInterval = 5 * time.Minute
	defaultTimeout  = 20 * time.Second
	CheckPushTagPrefix = "flux-write-check"
)
var (
	ErrNoChanges  = errors.New("no changes made in repo")
	ErrNoConfig   = errors.New("git repo does not have valid config")
	ErrNotCloned  = errors.New("git repo has not been cloned yet")
	ErrClonedOnly = errors.New("git repo has been cloned but not yet checked for write access")
)
type NotReadyError struct {
	underlying error
}
func (err NotReadyError) Unwrap() error { return err.underlying }
func (err NotReadyError) Error() string {
	return "git repo not ready: " + err.underlying.Error()
}
type GitRepoStatus string
const (
	RepoNoConfig    GitRepoStatus = "unconfigured"  
	RepoNew         GitRepoStatus = "new"           
	RepoCloned      GitRepoStatus = "cloned"        
	RepoReady       GitRepoStatus = "ready"         
	RepoUnreachable GitRepoStatus = "unreachable"   
)
type Repo struct {
	origin   Remote
	branch   string
	interval time.Duration
	timeout  time.Duration
	readonly bool
	mu     sync.RWMutex
	status GitRepoStatus
	err    error
	dir    string
	notify chan struct{}
	C      chan struct{}
}
type Option interface {
	apply(*Repo)
}
type optionFunc func(*Repo)
func (f optionFunc) apply(r *Repo) {
	f(r)
}
type PollInterval time.Duration
func (p PollInterval) apply(r *Repo) {
	r.interval = time.Duration(p)
}
type Timeout time.Duration
func (t Timeout) apply(r *Repo) {
	r.timeout = time.Duration(t)
}
type Branch string
func (b Branch) apply(r *Repo) {
	r.branch = string(b)
}
type IsReadOnly bool
func (ro IsReadOnly) apply(r *Repo) {
	r.readonly = bool(ro)
}
var ReadOnly IsReadOnly = true
func NewRepo(origin Remote, opts ...Option) *Repo {
	status := RepoNew
	if origin.URL == "" {
		status = RepoNoConfig
	}
	r := &Repo{
		origin:   origin,
		status:   status,
		interval: defaultInterval,
		timeout:  defaultTimeout,
		err:      ErrNotCloned,
		notify:   make(chan struct{}, 1),  
		C:        make(chan struct{}, 1),  
	}
	for _, opt := range opts {
		opt.apply(r)
	}
	return r
}
func (r *Repo) Origin() Remote {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.origin
}
func (r *Repo) Readonly() bool {
	return r.readonly
}
func (r *Repo) Dir() string {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.dir
}
func (r *Repo) Clean() {
	r.mu.Lock()
	if r.dir != "" {
		os.RemoveAll(r.dir)
	}
	r.dir = ""
	r.status = RepoNew
	r.mu.Unlock()
}
func (r *Repo) Status() (GitRepoStatus, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	return r.status, r.err
}
func (r *Repo) setUnready(s GitRepoStatus, err error) {
	metricGitReady.Set(MetricRepoUnready)
	r.mu.Lock()
	r.status = s
	r.err = err
	r.mu.Unlock()
}
func (r *Repo) setReady() {
	metricGitReady.Set(MetricRepoReady)
	r.mu.Lock()
	r.status = RepoReady
	r.err = nil
	r.mu.Unlock()
}
func (r *Repo) Notify() {
	select {
	case r.notify <- struct{}{}:
	default:
	}
}
func (r *Repo) refreshed() {
	select {
	case r.C <- struct{}{}:
	default:
	}
}