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

     1  // bug manages plain text issue files.
     2  package main
     3  
     4  import (
     5  	"fmt"
     6  	fitapp "github.com/grantbow/fit/fitapp"
     7  	issues "github.com/grantbow/fit/issues"
     8  	scm "github.com/grantbow/fit/scm"
     9  	"os"
    10  	"strings"
    11  )
    12  
    13  func main() {
    14  
    15  	config := issues.Config{}
    16  	config.ProgramVersion = fitapp.ProgramVersion()
    17  	config.DescriptionFileName = "Description"
    18  	config.FitDirName = "fit"
    19  	rootPresent := false
    20  	skip := fitapp.SkipRootCheck(&os.Args) // too few args or help or env
    21  	// see fitapp/utils.go
    22  
    23  	// detect scm first to determine backup location for .fit.yml
    24  	scmoptions := make(map[string]bool)
    25  	handler, detectedDir, ErrH := scm.DetectSCM(scmoptions, config)
    26  	//a, b, c := scm.DetectSCM(scmoptions, config)
    27  	//fmt.Printf("%+v %+v %+v\n", a, b, c)
    28  	if ErrH != nil {
    29  		fmt.Printf("Warn: no .git or .hg directory. Use \"{git|hg} init\".\n")
    30  		//fmt.Printf("Warn: %s\n", ErrH) // No SCM found
    31  		//a, b := handler.SCMIssuesUpdaters()
    32  		//fmt.Printf("%+v %+v\n", a, b)
    33  		if handler != nil {
    34  			if _, ErrU := handler.SCMIssuesUpdaters(config); ErrU != nil {
    35  				if _, ErrCa := handler.SCMIssuesCacher(config); ErrCa != nil {
    36  					fmt.Printf("Warn: %s\n", ErrCa)
    37  				} else {
    38  					fmt.Printf("Warn: %s\n", ErrU)
    39  				}
    40  			}
    41  		}
    42  	} else {
    43  		config.ScmDir = string(detectedDir)
    44  		config.ScmType = handler.SCMTyper()
    45  	}
    46  
    47  	if rd := issues.RootDirer(&config); rd != "" {
    48  		// issues/Directory.go func RootDirer sets config.FitDir runs os.Chdir()
    49  		rootPresent = true
    50  		config.FitYmlDir = config.FitDir // default
    51  		fitYmlFileName := ".fit.yml"
    52  		bugYmlFileName := ".bug.yml"
    53  		if ErrC := issues.ConfigRead(fitYmlFileName, &config, fitapp.ProgramVersion()); ErrC == nil {
    54  			// tried to read FitDir fit config, must try both fit and bug
    55  			config.FitYmlDir = config.FitDir
    56  			config.FitYml = config.FitYmlDir + string(os.PathSeparator) + fitYmlFileName
    57  			//var sops = string(os.PathSeparator) not yet available
    58  			//var dops = Directory(os.PathSeparator)
    59  		} else if ErrC := issues.ConfigRead(bugYmlFileName, &config, fitapp.ProgramVersion()); ErrC == nil {
    60  			// tried to read FitDir bug config, must try both fit and bug
    61  			config.FitYmlDir = config.FitDir
    62  			config.FitYml = config.FitDir + string(os.PathSeparator) + bugYmlFileName
    63  		} else if config.ScmType == "git" {
    64  			// TODO: collapse else if ...git... && else if ...hg... with .git(4 char len, stl ScmTypeLen) and .hg(3 char len)
    65  			s := len(config.ScmDir)
    66  			//fmt.Printf("debug s01 %v\n scmdir %v\n dir %v\n", s, config.ScmDir, string(config.ScmDir[:s-4])+fitYmlFileName)
    67  			if ErrC := issues.ConfigRead(string(config.ScmDir[:s-4])+fitYmlFileName, &config, fitapp.ProgramVersion()); ErrC == nil {
    68  				// tried to read .git fit config
    69  				config.FitYmlDir = string(config.ScmDir[:s-5])
    70  				config.FitYml = string(config.ScmDir[:s-4]) + fitYmlFileName
    71  				//fmt.Printf("debug 02\n %v\n", config.FitYml)
    72  			} else if ErrC := issues.ConfigRead(string(config.ScmDir[:s-4])+bugYmlFileName, &config, fitapp.ProgramVersion()); ErrC == nil {
    73  				// tried to read .git bug config
    74  				config.FitYmlDir = string(config.ScmDir[:s-5])
    75  				config.FitYml = string(config.ScmDir[:s-4]) + bugYmlFileName
    76  			}
    77  		} else if config.ScmType == "hg" {
    78  			// try to read .hg fit config
    79  			s := len(config.ScmDir)
    80  			//fmt.Printf("debug s03 %v\n scmdir %v\n dir %v\n", s, config.ScmDir, string(config.ScmDir[:s-3])+fitYmlFileName)
    81  			if ErrC := issues.ConfigRead(string(config.ScmDir[:s-3])+fitYmlFileName, &config, fitapp.ProgramVersion()); ErrC == nil {
    82  				// tried to read .hg fit config
    83  				config.FitYmlDir = string(config.ScmDir[:s-4])
    84  				config.FitYml = string(config.ScmDir[:s-3]) + fitYmlFileName
    85  				//fmt.Printf("debug 04\n %v\n", config.FitYml)
    86  			} else if ErrC := issues.ConfigRead(string(config.ScmDir[:s-3])+bugYmlFileName, &config, fitapp.ProgramVersion()); ErrC == nil {
    87  				// tried to read .hg fit config
    88  				config.FitYmlDir = string(config.ScmDir[:s-4])
    89  				config.FitYml = string(config.ScmDir[:s-3]) + bugYmlFileName
    90  				//fmt.Printf("debug 04\n %v\n", config.FitYml)
    91  			}
    92  		}
    93  		//} else { // no
    94  	}
    95  
    96  	if !rootPresent {
    97  		if skip {
    98  			fmt.Printf("Warn: no `" + config.FitDirName + "` directory\n")
    99  		} else { // !skip
   100  			//fitapp.PrintVersion()
   101  			fmt.Printf("bug manages plain text issues with git or hg.\n")
   102  			fmt.Printf("Error: Could not find `fit` or `issues` directory.\n")
   103  			fmt.Printf("    Check that the current or a parent directory has a fit directory\n")
   104  			fmt.Printf("    or set the FIT environment variable.\n")
   105  			//fmt.Printf("Each issues directory contains issues.\n")
   106  			//fmt.Printf("Each issue directory contains a text file named Description.\n")
   107  			fmt.Printf("Use \"bug help\" or \"bug help help\" for details.\n")
   108  			fmt.Printf("Aborting.\n")
   109  			os.Exit(2)
   110  		}
   111  	}
   112  
   113  	issues.FitDirer(config) // from issues/Directory.go, uses config.FitDir from issues/Bug.go
   114  
   115  	// flags package is nice but this seemed more direct at the time
   116  	// because of subcommands and
   117  	// arguments that can be space separated names
   118  	// glog requires the use of flag
   119  	osArgs := os.Args // TODO: use an env var and assign to osArgs to setup for testing
   120  	//fmt.Printf("A %s %#v\n", "osArgs: ", osArgs)
   121  	if len(osArgs) <= 1 {
   122  		if rootPresent {
   123  			fitapp.List([]string{}, config, true)
   124  		} else {
   125  			fmt.Printf("Usage: " + os.Args[0] + " <command> [options]\n")
   126  			fmt.Printf("\nUse \"bug help\" or \"bug help <command>\" for details.\n")
   127  		}
   128  	} else if len(osArgs) == 2 &&
   129  		(osArgs[1] == "--help" ||
   130  			osArgs[1] == "help" ||
   131  			osArgs[1] == "-h") {
   132  		fitapp.Help("help") // just bug help
   133  	} else if len(osArgs) >= 3 &&
   134  		(osArgs[2] == "--help" ||
   135  			osArgs[2] == "help" ||
   136  			osArgs[2] == "-h") { // 'bug cmd --help' just like 'bug help cmd'
   137  		//fmt.Printf("B %s %#v\n", "osArgs: ", osArgs)
   138  		fitapp.Help(osArgs[1])
   139  	} else {
   140  		switch osArgs[1] {
   141  		// subcommands without osArgs first
   142  		case "notags", "notag":
   143  			fitapp.TagsNone(config)
   144  		case "idslist", "idsassigned", "ids", "identifiers":
   145  			fitapp.IdsAssigned(config)
   146  		case "noids", "noid", "noidentifiers", "noidentifier":
   147  			fitapp.IdsNone(config)
   148  		case "env", "environment", "config", "settings":
   149  			fitapp.Env(config)
   150  		case "pwd", "dir", "cwd":
   151  			fitapp.Pwd(config)
   152  		case "version", "about", "--version", "-v":
   153  			fitapp.PrintVersion()
   154  		case "purge":
   155  			fitapp.Purge(config)
   156  		case "twilio":
   157  			fitapp.Twilio(config)
   158  		case "staging", "staged", "cached", "cache", "index":
   159  			// TODO: scm/Staged.go
   160  			if b, err := handler.SCMIssuesUpdaters(config); err != nil {
   161  				fmt.Printf("Files in " + config.FitDirName + "/ need committing, see $ git status --porcelain -u -- :/" + config.FitDirName + "\nor if already in the index see     $ git diff --name-status --cached HEAD -- :/" + config.FitDirName + "\n")
   162  				if _, ErrCach := handler.SCMIssuesCacher(config); ErrCach != nil {
   163  					for _, bline := range strings.Split(string(b), "\n") {
   164  						//if c, bline
   165  						//if bline in c {
   166  						//} else {
   167  						fmt.Printf("%v\n", string(bline))
   168  						//}
   169  					}
   170  				} else {
   171  					fmt.Printf("%v\n", string(b))
   172  				}
   173  			} else {
   174  				fmt.Printf("No files in " + config.FitDirName + "/ need committing, see $ git status --porcelain -u :/" + config.FitDirName + " \":top\"\n")
   175  			}
   176  		// subcommands that pass osArgs
   177  		case "tagslist", "taglist", "tagsassigned", "tags":
   178  			fitapp.TagsAssigned(osArgs[2:], config)
   179  		case "list", "view", "show", "display", "ls":
   180  			// bug list with no parameters shouldn't autopage,
   181  			// bug list with issues to view should. So the original
   182  			fitapp.List(osArgs[2:], config, true)
   183  		case "find":
   184  			fitapp.Find(osArgs[2:], config)
   185  		case "create", "add", "new":
   186  			//fmt.Printf("%s %#v\n", "osArgs: ", len(osArgs))
   187  			fitapp.Create(osArgs[2:], config)
   188  			//fmt.Printf("%s %#v\n", "osArgs: ", len(osArgs))
   189  		case "edit":
   190  			fitapp.Edit(osArgs[2:], config)
   191  		case "retitle", "mv", "rename", "relabel":
   192  			fitapp.Relabel(osArgs[2:], config)
   193  		case "close", "rm":
   194  			fitapp.Close(osArgs[2:], config)
   195  		case "tag":
   196  			fitapp.Tag(osArgs[2:], config) // boolean only
   197  		case "id", "identifier":
   198  			fitapp.Identifier(osArgs[2:], config)
   199  		case "status":
   200  			if len(osArgs) == 2 {
   201  				// overview like a git status
   202  				fitapp.Env(config)
   203  			} else {
   204  				// get or set the status of an issue
   205  				fitapp.Status(osArgs[2:], config)
   206  			}
   207  		case "priority":
   208  			fitapp.Priority(osArgs[2:], config)
   209  		case "milestone":
   210  			fitapp.Milestone(osArgs[2:], config)
   211  		case "import":
   212  			fitapp.Import(osArgs[2:], config)
   213  		case "commit", "save":
   214  			fitapp.Commit(osArgs[2:], config)
   215  		case "roadmap":
   216  			fitapp.Roadmap(osArgs[2:], config)
   217  		case "help", "--help", "-h":
   218  			//fmt.Printf("C %s %#v\n", "osArgs: ", osArgs)
   219  			fitapp.Help(osArgs[2])
   220  		default:
   221  			//if
   222  			if len(osArgs) == 2 {
   223  				buglist, _ := issues.LoadIssueByHeuristic(osArgs[1], config)
   224  				//fmt.Printf("%+v\n", buglist)
   225  				if buglist != nil { // || ae, ok := bugerr.(issues.ErrNotFound); ! ok { // bug list when possible, not help
   226  					fitapp.List(osArgs[1:], config, true)
   227  				} else {
   228  					fitapp.Help(osArgs[1:]...)
   229  				}
   230  			}
   231  		}
   232  	}
   233  }