1package _select
2
3import (
4 "fmt"
5 "io"
6 "io/ioutil"
7 "os"
8
9 "github.com/pkg/errors"
10
11 "github.com/MichaelMure/git-bug/bug"
12 "github.com/MichaelMure/git-bug/cache"
13 "github.com/MichaelMure/git-bug/entity"
14)
15
16const selectFile = "select"
17
18var ErrNoValidId = errors.New("you must provide a bug id or use the \"select\" command first")
19
20// ResolveBug first try to resolve a bug using the first argument of the command
21// line. If it fails, it fallback to the select mechanism.
22//
23// Returns:
24// - the bug if any
25// - the new list of command line arguments with the bug prefix removed if it
26// has been used
27// - an error if the process failed
28func ResolveBug(repo *cache.RepoCache, args []string) (*cache.BugCache, []string, error) {
29 // At first, try to use the first argument as a bug prefix
30 if len(args) > 0 {
31 b, err := repo.ResolveBugPrefix(args[0])
32
33 if err == nil {
34 return b, args[1:], nil
35 }
36
37 if err != bug.ErrBugNotExist {
38 return nil, nil, err
39 }
40 }
41
42 // first arg is not a valid bug prefix, we can safely use the preselected bug if any
43
44 b, err := selected(repo)
45
46 // selected bug is invalid
47 if err == bug.ErrBugNotExist {
48 // we clear the selected bug
49 err = Clear(repo)
50 if err != nil {
51 return nil, nil, err
52 }
53 return nil, nil, ErrNoValidId
54 }
55
56 // another error when reading the bug
57 if err != nil {
58 return nil, nil, err
59 }
60
61 // bug is successfully retrieved
62 if b != nil {
63 return b, args, nil
64 }
65
66 // no selected bug and no valid first argument
67 return nil, nil, ErrNoValidId
68}
69
70// Select will select a bug for future use
71func Select(repo *cache.RepoCache, id entity.Id) error {
72 f, err := repo.LocalStorage().OpenFile(selectFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
73 if err != nil {
74 return err
75 }
76
77 _, err = f.Write([]byte(id.String()))
78 if err != nil {
79 return err
80 }
81
82 return f.Close()
83}
84
85// Clear will clear the selected bug, if any
86func Clear(repo *cache.RepoCache) error {
87 return repo.LocalStorage().Remove(selectFile)
88}
89
90func selected(repo *cache.RepoCache) (*cache.BugCache, error) {
91 f, err := repo.LocalStorage().Open(selectFile)
92 if err != nil {
93 if os.IsNotExist(err) {
94 return nil, nil
95 } else {
96 return nil, err
97 }
98 }
99
100 buf, err := ioutil.ReadAll(io.LimitReader(f, 100))
101 if err != nil {
102 return nil, err
103 }
104 if len(buf) == 100 {
105 return nil, fmt.Errorf("the select file should be < 100 bytes")
106 }
107
108 id := entity.Id(buf)
109 if err := id.Validate(); err != nil {
110 err = repo.LocalStorage().Remove(selectFile)
111 if err != nil {
112 return nil, errors.Wrap(err, "error while removing invalid select file")
113 }
114
115 return nil, fmt.Errorf("select file in invalid, removing it")
116 }
117
118 b, err := repo.ResolveBug(id)
119 if err != nil {
120 return nil, err
121 }
122
123 err = f.Close()
124 if err != nil {
125 return nil, err
126 }
127
128 return b, nil
129}