github.com/grantbow/fit@v0.7.1-0.20220916164603-1f7c88ac81e6/fitapp/be.go (about)

     1  package fitapp
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	bugs "github.com/grantbow/fit/issues"
     7  	"io/ioutil"
     8  	"os"
     9  	"sort"
    10  	"strings"
    11  )
    12  
    13  //var dops = bugs.Directory(os.PathSeparator)
    14  //var sops = string(os.PathSeparator)
    15  
    16  func beImportComments(b bugs.Issue, directory string, includeHeaders bool) string {
    17  	file := directory + sops + "body"
    18  	data, _ := ioutil.ReadFile(file)
    19  	if includeHeaders == false {
    20  		return string(data)
    21  	}
    22  
    23  	/* Be appears to store comment metadata in a JSON file named values
    24  	   with the format:
    25  	   {
    26  	       "Author": "Dave MacFarlane <driusan@gmail.com>",
    27  	       "Content-type": "text/plain",
    28  	       "Date": "Tue, 12 Jan 2016 21:44:24 +0000"
    29  	   }
    30  	*/
    31  	type BeValues struct {
    32  		Author      string `json:"Author"`
    33  		ContentType string `json:"Content-type"`
    34  		Date        string `json:"Date"`
    35  	}
    36  	file = directory + sops + "values"
    37  	jsonVal, _ := ioutil.ReadFile(file)
    38  	var beComment BeValues
    39  	json.Unmarshal([]byte(jsonVal), &beComment)
    40  	return "---------- Comment ---------\nFrom:" + beComment.Author + "\nDate:" + beComment.Date + "\n\n" + string(data)
    41  }
    42  
    43  func beImportIssue(identifier, issuesDir, fullbepath string, config bugs.Config) {
    44  	/* BE appears to store the top level data of a bug
    45  	   in a json file with the format:
    46  	    {
    47  	        "creator": "Dave MacFarlane <driusan@gmail.com>",
    48  	        "reporter": "Dave MacFarlane <driusan@gmail.com>",
    49  	        "severity": "minor",
    50  	        "status": "open",
    51  	        "summary": "abc",
    52  	        "time": "Tue, 12 Jan 2016 00:05:28 +0000"
    53  	    }
    54  
    55  	    and the Description of bugs entirely in comments.
    56  	    All we really care about is the summary so that we
    57  	    can get the directory name for the issues/ directory,
    58  	    but the severity+status can also be used as a status
    59  	    to ensure that we have at least 1 file to be tracked
    60  	    by git.
    61  	*/
    62  
    63  	type BeValues struct {
    64  		Creator  string `json:"creator"`
    65  		Reporter string `json:"reporter"`
    66  		Severity string `json:"severity"`
    67  		Status   string `json:"status"`
    68  		Summary  string `json:"summary"`
    69  		Time     string `json:"time"`
    70  	}
    71  	file := fullbepath + sops + "values"
    72  
    73  	fmt.Printf("File: %s\n", file)
    74  	data, _ := ioutil.ReadFile(file)
    75  	var beIssue BeValues
    76  	err := json.Unmarshal([]byte(data), &beIssue)
    77  	if err != nil {
    78  		fmt.Printf("Error unmarshalling data: %s\n", err.Error())
    79  	}
    80  
    81  	fmt.Printf("%s\n", beIssue)
    82  
    83  	bugdir := bugs.TitleToDir(beIssue.Summary)
    84  
    85  	b := bugs.Issue{Dir: bugs.Directory(issuesDir) + bugdir}
    86  	if dir := b.Direr(); dir != "" {
    87  		os.Mkdir(string(dir), 0755)
    88  	}
    89  	if beIssue.Status != "" && beIssue.Severity != "" {
    90  		b.SetStatus(beIssue.Status+":"+beIssue.Severity, config)
    91  	}
    92  
    93  	comments := fullbepath + sops + "comments" + sops
    94  	dir, err := os.Open(comments)
    95  
    96  	files, err := dir.Readdir(-1)
    97  	var DescriptionStr string
    98  	if len(files) > 0 && err == nil {
    99  		for _, file := range files {
   100  			if file.IsDir() {
   101  				DescriptionStr = DescriptionStr + "\n" +
   102  					beImportComments(b, comments+file.Name(), len(files) > 1)
   103  			}
   104  		}
   105  	}
   106  	b.SetDescription(DescriptionStr, config)
   107  	b.SetIdentifier(identifier, config)
   108  }
   109  func beImportIssues(prefix, issuesdir, bedir, dirname string, config bugs.Config) {
   110  	bugsdir := bedir + sops + dirname + sops + "bugs"
   111  	dir, err := os.Open(bugsdir)
   112  	if err != nil {
   113  		fmt.Fprintf(os.Stderr, "Could not open directory %s\n", bugsdir)
   114  	}
   115  	files, _ := dir.Readdir(-1)
   116  
   117  	lastIdentifier := ""
   118  	nextIdentifier := ""
   119  	sort.Sort(fileSorter(files))
   120  	for idx, file := range files {
   121  		if file.IsDir() {
   122  			if idx < len(files)-1 {
   123  				nextIdentifier = files[idx+1].Name()
   124  			}
   125  			name := shortestPrefix(file.Name(), nextIdentifier, lastIdentifier, 3)
   126  			identifier := fmt.Sprintf("%s%s%s", prefix, sops, name)
   127  			beImportIssue(identifier, issuesdir, bugsdir+sops+file.Name(), config)
   128  			lastIdentifier = file.Name()
   129  		}
   130  	}
   131  }
   132  
   133  type fileSorter []os.FileInfo
   134  
   135  func (a fileSorter) Len() int {
   136  	return len(a)
   137  }
   138  func (a fileSorter) Less(i, j int) bool {
   139  	return a[i].Name() < a[j].Name()
   140  }
   141  func (a fileSorter) Swap(i, j int) {
   142  	a[i], a[j] = a[j], a[i]
   143  }
   144  
   145  func beImport(config bugs.Config) {
   146  	wd, err := os.Getwd()
   147  	if dir := walkAndSearch(wd, []string{".be"}); err != nil || dir == nil {
   148  		fmt.Fprintf(os.Stderr, "Could not find any Bugs Everywhere repository relative to current path.\n")
   149  		os.Exit(3)
   150  	} else {
   151  		files, err := dir.Readdir(-1)
   152  		sort.Sort(fileSorter(files))
   153  		if err != nil {
   154  			fmt.Fprintf(os.Stderr, "Error importing BE database: %s\n", err.Error())
   155  			os.Exit(4)
   156  		}
   157  
   158  		issuesDir := bugs.FitDirer(config)
   159  		lastIdentifier := ""
   160  		nextIdentifier := ""
   161  		for idx, file := range files {
   162  			if file.IsDir() {
   163  				if idx < len(files)-1 {
   164  					nextIdentifier = files[idx+1].Name()
   165  				}
   166  				name := shortestPrefix(file.Name(), nextIdentifier, lastIdentifier, 3)
   167  
   168  				beImportIssues(name, string(issuesDir), dir.Name(), file.Name(), config)
   169  				lastIdentifier = file.Name()
   170  			}
   171  		}
   172  	}
   173  }
   174  
   175  func walkAndSearch(startpath string, dirnames []string) *os.File {
   176  	for _, dirname := range dirnames {
   177  		if dirinfo, err := os.Stat(startpath + sops + dirname); err == nil && dirinfo.IsDir() {
   178  			file, err := os.Open(startpath + sops + dirname)
   179  			if err != nil {
   180  				return nil
   181  			}
   182  			return file
   183  		}
   184  	}
   185  
   186  	pieces := strings.Split(startpath, sops)
   187  
   188  	for i := len(pieces); i > 0; i -= 1 {
   189  		dir := strings.Join(pieces[0:i], sops)
   190  		for _, dirname := range dirnames {
   191  			if dirinfo, err := os.Stat(dir + sops + dirname); err == nil && dirinfo.IsDir() {
   192  				file, err := os.Open(dir + sops + dirname)
   193  				if err != nil {
   194  					return nil
   195  				}
   196  				return file
   197  			}
   198  		}
   199  	}
   200  	return nil
   201  }
   202  
   203  func shortestPrefix(name, nextIdentifier, lastIdentifier string, min int) string {
   204  	for i := 0; i < len(name); i += 1 {
   205  		if i < min {
   206  			continue
   207  		}
   208  		if nextIdentifier != "" && len(nextIdentifier) <= i {
   209  			if name[0:i] == nextIdentifier[0:i] {
   210  				continue
   211  			}
   212  		}
   213  
   214  		if lastIdentifier != "" && len(lastIdentifier) <= i {
   215  			if name[0:i] == lastIdentifier[0:i] {
   216  				continue
   217  			}
   218  		}
   219  		return name[0:i]
   220  	}
   221  	return name
   222  }