1package commands
2
3import (
4 "fmt"
5 "io"
6 "os"
7
8 "github.com/spf13/cobra"
9
10 "github.com/MichaelMure/git-bug/bug"
11 "github.com/MichaelMure/git-bug/cache"
12 "github.com/MichaelMure/git-bug/identity"
13 "github.com/MichaelMure/git-bug/repository"
14 "github.com/MichaelMure/git-bug/util/interrupt"
15)
16
17// Env is the environment of a command
18type Env struct {
19 repo repository.ClockedRepo
20 backend *cache.RepoCache
21 out out
22 err out
23}
24
25func newEnv() *Env {
26 return &Env{
27 repo: nil,
28 out: out{Writer: os.Stdout},
29 err: out{Writer: os.Stderr},
30 }
31}
32
33type out struct {
34 io.Writer
35}
36
37func (o out) Printf(format string, a ...interface{}) {
38 _, _ = fmt.Fprintf(o, format, a...)
39}
40
41func (o out) Print(a ...interface{}) {
42 _, _ = fmt.Fprint(o, a...)
43}
44
45func (o out) Println(a ...interface{}) {
46 _, _ = fmt.Fprintln(o, a...)
47}
48
49// loadRepo is a pre-run function that load the repository for use in a command
50func loadRepo(env *Env) func(*cobra.Command, []string) error {
51 return func(cmd *cobra.Command, args []string) error {
52 cwd, err := os.Getwd()
53 if err != nil {
54 return fmt.Errorf("unable to get the current working directory: %q", err)
55 }
56
57 env.repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
58 if err == repository.ErrNotARepo {
59 return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
60 }
61
62 if err != nil {
63 return err
64 }
65
66 return nil
67 }
68}
69
70// loadRepoEnsureUser is the same as loadRepo, but also ensure that the user has configured
71// an identity. Use this pre-run function when an error after using the configured user won't
72// do.
73func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
74 return func(cmd *cobra.Command, args []string) error {
75 err := loadRepo(env)(cmd, args)
76 if err != nil {
77 return err
78 }
79
80 _, err = identity.GetUserIdentity(env.repo)
81 if err != nil {
82 return err
83 }
84
85 return nil
86 }
87}
88
89// loadBackend is a pre-run function that load the repository and the backend for use in a command
90// When using this function you also need to use closeBackend as a post-run
91func loadBackend(env *Env) func(*cobra.Command, []string) error {
92 return func(cmd *cobra.Command, args []string) error {
93 err := loadRepo(env)(cmd, args)
94 if err != nil {
95 return err
96 }
97
98 env.backend, err = cache.NewRepoCache(env.repo)
99 if err != nil {
100 return err
101 }
102
103 cleaner := func(env *Env) interrupt.CleanerFunc {
104 return func() error {
105 if env.backend != nil {
106 err := env.backend.Close()
107 env.backend = nil
108 return err
109 }
110 return nil
111 }
112 }
113
114 // Cleanup properly on interrupt
115 interrupt.RegisterCleaner(cleaner(env))
116 return nil
117 }
118}
119
120// loadBackendEnsureUser is the same as loadBackend, but also ensure that the user has configured
121// an identity. Use this pre-run function when an error after using the configured user won't
122// do.
123func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error {
124 return func(cmd *cobra.Command, args []string) error {
125 err := loadRepo(env)(cmd, args)
126 if err != nil {
127 return err
128 }
129
130 _, err = identity.GetUserIdentity(env.repo)
131 if err != nil {
132 return err
133 }
134
135 return nil
136 }
137}
138
139// closeBackend is a post-run function that will close the backend properly
140// if it has been opened.
141func closeBackend(env *Env) func(*cobra.Command, []string) error {
142 return func(cmd *cobra.Command, args []string) error {
143 if env.backend == nil {
144 return nil
145 }
146 err := env.backend.Close()
147 env.backend = nil
148 return err
149 }
150}