diff --git a/cmd/gi_gen.go b/cmd/gi_gen.go index 42170d2..ee1f2d3 100644 --- a/cmd/gi_gen.go +++ b/cmd/gi_gen.go @@ -3,11 +3,8 @@ package cmd import ( "flag" "fmt" - "log" - "os" - "path/filepath" - . "github.com/chenasraf/gi_gen/internal" + "github.com/chenasraf/gi_gen/internal" ) func RunMainCmd() { @@ -18,7 +15,7 @@ func RunMainCmd() { return } - RunGIGen() + internal.GIGen() } func cleanCommand() bool { @@ -26,7 +23,7 @@ func cleanCommand() bool { flag.Parse() if *clean { - RemoveCacheDir() + internal.RemoveCacheDir() return true } return false @@ -46,27 +43,3 @@ func helpCommand() { flag.Bool("help", false, "Display help message") } - -func RunGIGen() { - wd, err := os.Getwd() - HandleErr(err) - - outFile := filepath.Join(wd, ".gitignore") - allFiles, err := PrepareGitignores() - HandleErr(err) - - fileNames, files := DiscoverRelevantFiles(allFiles) - - log.Println("Done.") - - selected, selectedKeys := GetLanguageSelections(files, fileNames) - cleanupSelection := AskCleanup() - outContents := Ternary(cleanupSelection, CleanupMultipleFiles(selected, selectedKeys), GetAllRaw(selected, selectedKeys)) - - if FileExists(outFile) { - HandleFileOverwrite(outFile, outContents) - } else { - log.Printf("Writing to %s", outFile) - WriteFile(outFile, outContents, true) - } -} diff --git a/internal/ask.go b/internal/ask.go index 3845861..7a8ce19 100644 --- a/internal/ask.go +++ b/internal/ask.go @@ -1,17 +1,14 @@ package internal import ( - "fmt" - "github.com/AlecAivazis/survey/v2" + "golang.org/x/exp/maps" ) func AskLanguage(fileNames []string, selected []string, files map[string]string) ([]string, []string) { langPrompt := &survey.MultiSelect{ - Message: "Found " + fmt.Sprint(len(fileNames)) + - " possible matches in your project for gitignore files.\n" + - "Please select which you want to write to .gitignore:\n", - Options: fileNames, + Message: "Please select which you want to write to .gitignore:\n", + Options: maps.Keys(files), } var langSelections []string diff --git a/internal/core.go b/internal/core.go new file mode 100644 index 0000000..ca666da --- /dev/null +++ b/internal/core.go @@ -0,0 +1,31 @@ +package internal + +import ( + "fmt" + "os" + "path/filepath" +) + +func GIGen() { + wd, err := os.Getwd() + handleErr(err) + + outFile := filepath.Join(wd, ".gitignore") + allFiles, err := prepareGitignores() + handleErr(err) + + fileNames, files := autoDiscover(allFiles) + + selected, selectedKeys := getLanguageSelections(files, fileNames) + cleanupSelection := AskCleanup() + outContents := Ternary(cleanupSelection, cleanupMultipleFiles(selected, selectedKeys), getAllRaw(selected, selectedKeys)) + + if FileExists(outFile) { + HandleFileOverwrite(outFile, outContents) + } else { + fmt.Printf("Writing to %s\n", outFile) + WriteFile(outFile, outContents, true) + } + + fmt.Println("Done.") +} diff --git a/internal/discovery.go b/internal/discovery.go index b1d73b7..136c54b 100644 --- a/internal/discovery.go +++ b/internal/discovery.go @@ -1,7 +1,6 @@ package internal import ( - "fmt" "os" "path/filepath" "strings" @@ -9,18 +8,21 @@ import ( "golang.org/x/exp/maps" ) -func DiscoverRelevantFiles(allFiles []string) ([]string, map[string]string) { +func autoDiscover(allFiles []string) ([]string, map[string]string) { answer := AskDiscovery() if !answer { - return allFiles, getAll(allFiles) + return allFiles, getAllFiles(allFiles) } - byType := discoverProjectType() - return maps.Keys(byType), byType + list := discoverByExplicitProjectType() + if len(list) == 0 { + list = discoverByExistingPatterns(allFiles) + } + return maps.Keys(list), list } -func getAll(allFiles []string) map[string]string { +func getAllFiles(allFiles []string) map[string]string { files := make(map[string]string) for _, filename := range allFiles { @@ -34,26 +36,24 @@ func getAll(allFiles []string) map[string]string { return files } -func discoverExistingPatterns(allFiles []string, answer bool, files map[string]string) map[string]string { +func discoverByExistingPatterns(allFiles []string) map[string]string { + files := make(map[string]string) + for _, filename := range allFiles { contents := ReadFile(filename) basename := filepath.Base(filename) langName := basename[:strings.Index(basename, ".")] - if answer { - if FindFileMatches(contents) { - files[langName] = contents - } - } else { + if findPatternFileMatches(contents) { files[langName] = contents } } return files } -func discoverProjectType() map[string]string { +func discoverByExplicitProjectType() map[string]string { wd, err := os.Getwd() - HandleErr(err) + handleErr(err) discoveryMap := make(map[string]string) discoveryMap["package.json"] = "Node" @@ -72,13 +72,11 @@ func discoverProjectType() map[string]string { for _, key := range maps.Keys(discoveryMap) { langName := discoveryMap[key] - ignoreFile := filepath.Join(GetCacheDir(), langName+".gitignore") + ignoreFile := filepath.Join(getCacheDir(), langName+".gitignore") checkFile := filepath.Join(wd, key) - fmt.Println("Trying file " + checkFile) _, keyExists := results[langName] if !keyExists && FileExists(checkFile) { - fmt.Println("Found lang " + langName) results[langName] = ReadFile(ignoreFile) } } diff --git a/internal/ignore_files.go b/internal/ignore_files.go index f683757..1e7a454 100644 --- a/internal/ignore_files.go +++ b/internal/ignore_files.go @@ -2,7 +2,6 @@ package internal import ( "fmt" - "log" "os" "os/exec" "path/filepath" @@ -11,48 +10,42 @@ import ( "golang.org/x/exp/maps" ) -func PrepareGitignores() ([]string, error) { - gitignoresDir := GetCacheDir() +func prepareGitignores() ([]string, error) { + gitignoresDir := getCacheDir() if !FileExists(gitignoresDir) { - log.Println("Getting gitignore files...") + fmt.Println("Getting gitignore files...") RunCmd("git", "clone", "--depth=1", repoUrl, gitignoresDir) - } else if GetNeedsUpdate() { - log.Println("Updating gitignore files...") + } else if isCacheNeedsUpdate() { + fmt.Println("Updating gitignore files...") RunCmd("git", "-C", gitignoresDir, "pull", "origin", "master") } - return GetGitignores(gitignoresDir) + return getGitignoreFiles(gitignoresDir) } func RemoveCacheDir() { - cacheDir := GetCacheDir() - log.Printf("Removing cache directory: %s...\n", cacheDir) + cacheDir := getCacheDir() + fmt.Printf("Removing cache directory: %s...\n", cacheDir) os.RemoveAll(cacheDir) - log.Println("Done") + fmt.Println("Done") } -func GetCacheDir() string { +func getCacheDir() string { homeDir, _ := os.UserHomeDir() return filepath.Join(homeDir, ".github.gitignore") } -func GetGitignores(sourceDir string) ([]string, error) { +func getGitignoreFiles(sourceDir string) ([]string, error) { return filepath.Glob(filepath.Join(sourceDir, "*.gitignore")) } -func GetNeedsUpdate() bool { - gitignoresDir := GetCacheDir() +func isCacheNeedsUpdate() bool { + gitignoresDir := getCacheDir() localBytes, localErr := exec.Command("git", "-C", gitignoresDir, "rev-parse", "@").Output() + handleErr(localErr) baseBytes, baseErr := exec.Command("git", "-C", gitignoresDir, "merge-base", "@", "@{u}").Output() - if localErr != nil { - log.Fatal(localErr) - os.Exit(1) - } - if baseErr != nil { - log.Fatal(baseErr) - os.Exit(1) - } + handleErr(baseErr) localStr := string(localBytes) baseStr := string(baseBytes) @@ -68,7 +61,7 @@ var ignoreLines = []string{ ".idea/*", } -func FindFileMatches(patterns string) bool { +func findPatternFileMatches(patterns string) bool { lines := strings.Split(patterns, "\n") wd, _ := os.Getwd() @@ -99,7 +92,7 @@ func FindFileMatches(patterns string) bool { var patternCache []string = []string{} -func RemoveUnusedPatterns(contents string) string { +func removeUnusedPatterns(contents string) string { wd, _ := os.Getwd() lines := strings.Split(contents, "\n") keep := []string{} @@ -120,7 +113,7 @@ func RemoveUnusedPatterns(contents string) string { patternCache = append(patternCache, trimmed) if i > 0 { - keep = GatherPreviousCommentGroup(i, lastTakenIdx, lines, keep) + keep = gatherPreviousCommentGroup(i, lastTakenIdx, lines, keep) } keep = append(keep, line) @@ -130,7 +123,7 @@ func RemoveUnusedPatterns(contents string) string { return strings.Join(keep, "\n") } -func GatherPreviousCommentGroup(i int, lastTakenIdx int, lines []string, keep []string) []string { +func gatherPreviousCommentGroup(i int, lastTakenIdx int, lines []string, keep []string) []string { j := 1 foundComment := false comments := []string{} @@ -159,44 +152,48 @@ func GatherPreviousCommentGroup(i int, lastTakenIdx int, lines []string, keep [] return keep } -func GetLanguageSelections(files map[string]string, fileNames []string) ([]string, []string) { +func getLanguageSelections(files map[string]string, fileNames []string) ([]string, []string) { selected := []string{} allKeys := maps.Keys(files) selectedKeys := maps.Keys(files) if len(allKeys) == 0 { - selected = []string{} + fmt.Println("Found no templates. Quitting.") + os.Exit(1) } else if len(allKeys) > 1 { + fmt.Println("Found " + fmt.Sprint(len(fileNames)) + + " possible matches in your project for gitignore files.") selected, selectedKeys = AskLanguage(fileNames, selected, files) } else { + fmt.Printf("Found one match for your project: %s. Proceeding...\n", allKeys[0]) selected = []string{files[allKeys[0]]} } return selected, selectedKeys } -func LangHeader(langName string) string { +func langHeader(langName string) string { sep := "#========================================================================\n" header := fmt.Sprintf(sep+"# %s\n"+sep+"\n", langName) return header } -func GetAllRaw(selected []string, selectedKeys []string) string { +func getAllRaw(selected []string, selectedKeys []string) string { for i, selection := range selected { - header := Ternary(len(selected) > 1, LangHeader(selectedKeys[i]), "") + header := Ternary(len(selected) > 1, langHeader(selectedKeys[i]), "") selected[i] = header + selection } return strings.Join(selected, "\n") } -func CleanupMultipleFiles(files []string, langKeys []string) string { +func cleanupMultipleFiles(files []string, langKeys []string) string { out := []string{} for i, selection := range files { - cleanSelection := RemoveUnusedPatterns(selection) + cleanSelection := removeUnusedPatterns(selection) if strings.TrimSpace(cleanSelection) == "" { continue } - header := Ternary(len(files) > 1, LangHeader(langKeys[i]), "") + header := Ternary(len(files) > 1, langHeader(langKeys[i]), "") prefixNewline := Ternary(i > 0, "\n", "") contents := prefixNewline + header + cleanSelection out = append(out, contents) diff --git a/internal/utils.go b/internal/utils.go index f22722c..265229d 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -2,7 +2,6 @@ package internal import ( "fmt" - "log" "os" "os/exec" "path/filepath" @@ -21,7 +20,7 @@ func FileExists(path string) bool { func GlobExists(path string) bool { res, err := filepath.Glob(path) - HandleErr(err) + handleErr(err) return res != nil } @@ -32,30 +31,30 @@ func RunCmd(cmd string, args ...string) (string, error) { func ReadFile(path string) string { res, err := os.ReadFile(path) - HandleErr(err) + handleErr(err) return string(res) } func WriteFile(path string, data string, overwrite bool) bool { var err error if overwrite { - // os.Create(path) err = os.WriteFile(path, []byte(data), 0644) - HandleErr(err) + handleErr(err) } else { f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - HandleErr(err) + handleErr(err) defer f.Close() _, err = f.WriteString("\n" + data) - HandleErr(err) + handleErr(err) } return true } -func HandleErr(err error) { +func handleErr(err error) { if err != nil { - log.Println("Encountered an error while running gi_gen:") - log.Fatalln(err) + fmt.Println("Encountered an error while running gi_gen:") + fmt.Println(err) + os.Exit(1) } } @@ -90,11 +89,11 @@ func HandleFileOverwrite(path string, contents string) { Quit() break case "Overwrite": - log.Printf("Writing to %s", path) + fmt.Printf("Writing to %s\n", path) WriteFile(path, contents, true) break case "Append": - log.Printf("Appending to %s", path) + fmt.Printf("Appending to %s\n", path) WriteFile(path, contents, false) break }