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  }