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