2022-09-10 12:09:19 +03:00
|
|
|
package execenv
|
2020-06-28 19:26:29 +03:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
|
2020-06-28 20:09:32 +03:00
|
|
|
"github.com/spf13/cobra"
|
|
|
|
|
|
|
|
"github.com/MichaelMure/git-bug/cache"
|
2022-08-19 00:34:05 +03:00
|
|
|
"github.com/MichaelMure/git-bug/entities/identity"
|
2020-06-28 19:26:29 +03:00
|
|
|
"github.com/MichaelMure/git-bug/repository"
|
2020-06-28 20:09:32 +03:00
|
|
|
"github.com/MichaelMure/git-bug/util/interrupt"
|
2020-06-28 19:26:29 +03:00
|
|
|
)
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
const RootCommandName = "git-bug"
|
|
|
|
|
2022-05-26 20:39:13 +03:00
|
|
|
const gitBugNamespace = "git-bug"
|
2022-05-25 14:55:28 +03:00
|
|
|
|
2020-06-28 19:26:29 +03:00
|
|
|
// Env is the environment of a command
|
|
|
|
type Env struct {
|
2022-09-10 12:09:19 +03:00
|
|
|
Repo repository.ClockedRepo
|
|
|
|
Backend *cache.RepoCache
|
|
|
|
Out Out
|
|
|
|
Err Out
|
2020-06-28 19:26:29 +03:00
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
func NewEnv() *Env {
|
2020-06-28 19:26:29 +03:00
|
|
|
return &Env{
|
2022-09-10 12:09:19 +03:00
|
|
|
Repo: nil,
|
|
|
|
Out: out{Writer: os.Stdout},
|
|
|
|
Err: out{Writer: os.Stderr},
|
2020-06-28 19:26:29 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
type Out interface {
|
|
|
|
io.Writer
|
|
|
|
Printf(format string, a ...interface{})
|
|
|
|
Print(a ...interface{})
|
|
|
|
Println(a ...interface{})
|
|
|
|
|
|
|
|
// String returns what have been written in the output before, as a string.
|
|
|
|
// This only works in test scenario.
|
|
|
|
String() string
|
|
|
|
// Bytes returns what have been written in the output before, as []byte.
|
|
|
|
// This only works in test scenario.
|
|
|
|
Bytes() []byte
|
|
|
|
// Reset clear what has been recorded as written in the output before.
|
|
|
|
// This only works in test scenario.
|
|
|
|
Reset()
|
|
|
|
}
|
|
|
|
|
2020-06-28 19:26:29 +03:00
|
|
|
type out struct {
|
|
|
|
io.Writer
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o out) Printf(format string, a ...interface{}) {
|
|
|
|
_, _ = fmt.Fprintf(o, format, a...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o out) Print(a ...interface{}) {
|
|
|
|
_, _ = fmt.Fprint(o, a...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o out) Println(a ...interface{}) {
|
|
|
|
_, _ = fmt.Fprintln(o, a...)
|
|
|
|
}
|
2020-06-28 20:09:32 +03:00
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
func (o out) String() string {
|
|
|
|
panic("only work with a test env")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o out) Bytes() []byte {
|
|
|
|
panic("only work with a test env")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o out) Reset() {
|
|
|
|
panic("only work with a test env")
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoadRepo is a pre-run function that load the repository for use in a command
|
|
|
|
func LoadRepo(env *Env) func(*cobra.Command, []string) error {
|
2020-06-28 20:09:32 +03:00
|
|
|
return func(cmd *cobra.Command, args []string) error {
|
|
|
|
cwd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("unable to get the current working directory: %q", err)
|
|
|
|
}
|
|
|
|
|
2022-12-29 12:26:47 +03:00
|
|
|
// Note: we are not loading clocks here because we assume that LoadRepo is only used
|
|
|
|
// when we don't manipulate entities, or as a child call of LoadBackend which will
|
|
|
|
// read all clocks anyway.
|
|
|
|
env.Repo, err = repository.OpenGoGitRepo(cwd, gitBugNamespace, nil)
|
2020-06-28 20:09:32 +03:00
|
|
|
if err == repository.ErrNotARepo {
|
2022-09-10 12:09:19 +03:00
|
|
|
return fmt.Errorf("%s must be run from within a git Repo", RootCommandName)
|
2020-06-28 20:09:32 +03:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
// LoadRepoEnsureUser is the same as LoadRepo, but also ensure that the user has configured
|
2020-06-28 20:09:32 +03:00
|
|
|
// an identity. Use this pre-run function when an error after using the configured user won't
|
|
|
|
// do.
|
2022-09-10 12:09:19 +03:00
|
|
|
func LoadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
|
2020-06-28 20:09:32 +03:00
|
|
|
return func(cmd *cobra.Command, args []string) error {
|
2022-09-10 12:09:19 +03:00
|
|
|
err := LoadRepo(env)(cmd, args)
|
2020-06-28 20:09:32 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
_, err = identity.GetUserIdentity(env.Repo)
|
2020-06-28 20:09:32 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
// LoadBackend is a pre-run function that load the repository and the Backend for use in a command
|
|
|
|
// When using this function you also need to use CloseBackend as a post-run
|
|
|
|
func LoadBackend(env *Env) func(*cobra.Command, []string) error {
|
2020-06-28 20:09:32 +03:00
|
|
|
return func(cmd *cobra.Command, args []string) error {
|
2022-09-10 12:09:19 +03:00
|
|
|
err := LoadRepo(env)(cmd, args)
|
2020-06-28 20:09:32 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-12-19 20:09:59 +03:00
|
|
|
var events chan cache.BuildEvent
|
2022-12-27 21:39:09 +03:00
|
|
|
env.Backend, events = cache.NewRepoCache(env.Repo)
|
2020-06-28 20:09:32 +03:00
|
|
|
|
2022-12-27 13:19:45 +03:00
|
|
|
for event := range events {
|
|
|
|
if event.Err != nil {
|
2022-12-27 21:39:09 +03:00
|
|
|
return event.Err
|
2022-12-27 13:19:45 +03:00
|
|
|
}
|
|
|
|
switch event.Event {
|
|
|
|
case cache.BuildEventCacheIsBuilt:
|
|
|
|
env.Err.Println("Building cache... ")
|
|
|
|
case cache.BuildEventStarted:
|
|
|
|
env.Err.Printf("[%s] started\n", event.Typename)
|
|
|
|
case cache.BuildEventFinished:
|
|
|
|
env.Err.Printf("[%s] done\n", event.Typename)
|
2022-12-19 20:09:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-28 20:09:32 +03:00
|
|
|
cleaner := func(env *Env) interrupt.CleanerFunc {
|
|
|
|
return func() error {
|
2022-09-10 12:09:19 +03:00
|
|
|
if env.Backend != nil {
|
|
|
|
err := env.Backend.Close()
|
|
|
|
env.Backend = nil
|
2020-06-28 20:09:32 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cleanup properly on interrupt
|
|
|
|
interrupt.RegisterCleaner(cleaner(env))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
// LoadBackendEnsureUser is the same as LoadBackend, but also ensure that the user has configured
|
2020-06-28 20:09:32 +03:00
|
|
|
// an identity. Use this pre-run function when an error after using the configured user won't
|
|
|
|
// do.
|
2022-09-10 12:09:19 +03:00
|
|
|
func LoadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error {
|
2020-06-28 20:09:32 +03:00
|
|
|
return func(cmd *cobra.Command, args []string) error {
|
2022-09-10 12:09:19 +03:00
|
|
|
err := LoadBackend(env)(cmd, args)
|
2020-06-28 20:09:32 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
_, err = identity.GetUserIdentity(env.Repo)
|
2020-06-28 20:09:32 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
// CloseBackend is a wrapper for a RunE function that will close the Backend properly
|
2020-06-28 20:09:32 +03:00
|
|
|
// if it has been opened.
|
2021-05-09 12:33:20 +03:00
|
|
|
// This wrapper style is necessary because a Cobra PostE function does not run if RunE return an error.
|
2022-09-10 12:09:19 +03:00
|
|
|
func CloseBackend(env *Env, runE func(cmd *cobra.Command, args []string) error) func(*cobra.Command, []string) error {
|
2020-06-28 20:09:32 +03:00
|
|
|
return func(cmd *cobra.Command, args []string) error {
|
2021-05-09 12:33:20 +03:00
|
|
|
errRun := runE(cmd, args)
|
|
|
|
|
2022-09-10 12:09:19 +03:00
|
|
|
if env.Backend == nil {
|
2020-06-28 20:09:32 +03:00
|
|
|
return nil
|
|
|
|
}
|
2022-09-10 12:09:19 +03:00
|
|
|
err := env.Backend.Close()
|
|
|
|
env.Backend = nil
|
2021-05-09 12:33:20 +03:00
|
|
|
|
|
|
|
// prioritize the RunE error
|
|
|
|
if errRun != nil {
|
|
|
|
return errRun
|
|
|
|
}
|
2020-06-28 20:09:32 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|