github.com/driusan/bug@v0.3.2-0.20190306121946-d7f4e7f33fea/bugs/Bug.go (about) 1 package bugs 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "regexp" 9 "strings" 10 ) 11 12 var NoDescriptionError = errors.New("No description provided") 13 var NotFoundError = errors.New("Could not find bug") 14 15 type Bug struct { 16 Dir Directory 17 descFile *os.File 18 } 19 20 type Tag string 21 22 func TitleToDir(title string) Directory { 23 replaceWhitespaceWithUnderscore := func(match string) string { 24 return strings.Replace(match, " ", "_", -1) 25 } 26 replaceDashWithMore := func(match string) string { 27 if strings.Count(match, " ") > 0 { 28 return match 29 } 30 return "-" + match 31 } 32 33 // Replace sequences of dashes with 1 more dash, 34 // as long as there's no whitespace around them 35 re := regexp.MustCompile("([\\s]*)(-+)([\\s]*)") 36 s := re.ReplaceAllStringFunc(title, replaceDashWithMore) 37 // If there are dashes with whitespace around them, 38 // replace the whitespace with underscores 39 // This is a two step process, because the whitespace 40 // can independently be on either side, so it's difficult 41 // to do with 1 regex.. 42 re = regexp.MustCompile("([\\s]+)(-+)") 43 s = re.ReplaceAllStringFunc(s, replaceWhitespaceWithUnderscore) 44 re = regexp.MustCompile("(-+)([\\s]+)") 45 s = re.ReplaceAllStringFunc(s, replaceWhitespaceWithUnderscore) 46 47 s = strings.Replace(s, " ", "-", -1) 48 s = strings.Replace(s, "/", " ", -1) 49 return Directory(s) 50 } 51 func (b Bug) GetDirectory() Directory { 52 return b.Dir 53 } 54 55 func (b *Bug) LoadBug(dir Directory) { 56 b.Dir = dir 57 58 } 59 60 func (b Bug) Title(options string) string { 61 var hasOption = func(o string) bool { 62 return strings.Contains(options, o) 63 } 64 65 title := b.Dir.GetShortName().ToTitle() 66 67 if id := b.Identifier(); hasOption("identifier") && id != "" { 68 title = fmt.Sprintf("(%s) %s", id, title) 69 } 70 if hasOption("tags") { 71 tags := b.StringTags() 72 if len(tags) > 0 { 73 title += fmt.Sprintf(" (%s)", strings.Join(tags, ", ")) 74 } 75 } 76 77 priority := hasOption("priority") && b.Priority() != "" 78 status := hasOption("status") && b.Status() != "" 79 if options == "" { 80 priority = false 81 status = false 82 } 83 84 if priority && status { 85 title += fmt.Sprintf(" (Status: %s; Priority: %s)", b.Status(), b.Priority()) 86 } else if priority { 87 title += fmt.Sprintf(" (Priority: %s)", b.Priority()) 88 } else if status { 89 title += fmt.Sprintf(" (Status: %s)", b.Status()) 90 } 91 return title 92 } 93 94 func (b Bug) Description() string { 95 value, err := ioutil.ReadAll(&b) 96 97 if err != nil { 98 if err == NoDescriptionError { 99 return "No description provided." 100 } 101 panic("Unhandled error" + err.Error()) 102 } 103 104 if string(value) == "" { 105 return "No description provided." 106 } 107 return string(value) 108 } 109 func (b Bug) SetDescription(val string) error { 110 dir := b.GetDirectory() 111 112 return ioutil.WriteFile(string(dir)+"/Description", []byte(val), 0644) 113 } 114 func (b *Bug) RemoveTag(tag Tag) { 115 if dir := b.GetDirectory(); dir != "" { 116 os.Remove(string(dir) + "/tags/" + string(tag)) 117 } else { 118 fmt.Printf("Error removing tag: %s", tag) 119 } 120 } 121 func (b *Bug) TagBug(tag Tag) { 122 if dir := b.GetDirectory(); dir != "" { 123 os.Mkdir(string(dir)+"/tags/", 0755) 124 ioutil.WriteFile(string(dir)+"/tags/"+string(tag), []byte(""), 0644) 125 } else { 126 fmt.Printf("Error tagging bug: %s", tag) 127 } 128 } 129 func (b Bug) ViewBug() { 130 if identifier := b.Identifier(); identifier != "" { 131 fmt.Printf("Identifier: %s\n", identifier) 132 } 133 134 fmt.Printf("Title: %s\n\n", b.Title("")) 135 fmt.Printf("Description:\n%s", b.Description()) 136 137 if status := b.Status(); status != "" { 138 fmt.Printf("\nStatus: %s", status) 139 } 140 if priority := b.Priority(); priority != "" { 141 fmt.Printf("\nPriority: %s", priority) 142 } 143 if milestone := b.Milestone(); milestone != "" { 144 fmt.Printf("\nMilestone: %s", milestone) 145 } 146 if tags := b.StringTags(); tags != nil { 147 fmt.Printf("\nTags: %s", strings.Join([]string(tags), ", ")) 148 } 149 150 } 151 152 func (b Bug) StringTags() []string { 153 dir := b.GetDirectory() 154 dir += "/tags/" 155 issues, err := ioutil.ReadDir(string(dir)) 156 if err != nil { 157 return nil 158 } 159 160 tags := make([]string, 0, len(issues)) 161 for _, issue := range issues { 162 tags = append(tags, issue.Name()) 163 } 164 return tags 165 } 166 167 func (b Bug) HasTag(tag Tag) bool { 168 allTags := b.Tags() 169 for _, bugTag := range allTags { 170 if bugTag == tag { 171 return true 172 } 173 } 174 return false 175 } 176 func (b Bug) Tags() []Tag { 177 dir := b.GetDirectory() 178 dir += "/tags/" 179 issues, err := ioutil.ReadDir(string(dir)) 180 if err != nil { 181 return nil 182 } 183 184 tags := make([]Tag, 0, len(issues)) 185 for _, issue := range issues { 186 tags = append(tags, Tag(issue.Name())) 187 } 188 return tags 189 190 } 191 192 func (b Bug) getField(fieldName string) string { 193 dir := b.GetDirectory() 194 field, err := ioutil.ReadFile(string(dir) + "/" + fieldName) 195 if err != nil { 196 return "" 197 } 198 lines := strings.Split(string(field), "\n") 199 if len(lines) > 0 { 200 return strings.TrimSpace(lines[0]) 201 } 202 return "" 203 } 204 205 func (b Bug) setField(fieldName, value string) error { 206 dir := b.GetDirectory() 207 oldValue, err := ioutil.ReadFile(string(dir) + "/" + fieldName) 208 var oldLines []string 209 if err == nil { 210 oldLines = strings.Split(string(oldValue), "\n") 211 } 212 213 newValue := "" 214 if len(oldLines) >= 1 { 215 // If there were 0 or 1 old lines, overwrite them 216 oldLines[0] = value 217 newValue = strings.Join(oldLines, "\n") 218 } else { 219 newValue = value 220 } 221 222 err = ioutil.WriteFile(string(dir)+"/"+fieldName, []byte(newValue), 0644) 223 if err != nil { 224 return err 225 } 226 return nil 227 } 228 229 func (b Bug) Status() string { 230 return b.getField("Status") 231 } 232 233 func (b Bug) SetStatus(newStatus string) error { 234 return b.setField("Status", newStatus) 235 } 236 func (b Bug) Priority() string { 237 return b.getField("Priority") 238 } 239 240 func (b Bug) SetPriority(newValue string) error { 241 return b.setField("Priority", newValue) 242 } 243 func (b Bug) Milestone() string { 244 return b.getField("Milestone") 245 } 246 247 func (b Bug) SetMilestone(newValue string) error { 248 return b.setField("Milestone", newValue) 249 } 250 251 func (b Bug) Identifier() string { 252 return b.getField("Identifier") 253 } 254 255 func (b Bug) SetIdentifier(newValue string) error { 256 return b.setField("Identifier", newValue) 257 } 258 259 func New(title string) (*Bug, error) { 260 expectedDir := GetIssuesDir() + TitleToDir(title) 261 err := os.Mkdir(string(expectedDir), 0755) 262 if err != nil { 263 return nil, err 264 } 265 return &Bug{Dir: expectedDir}, nil 266 }