improve selection flow, allow fallback in auto discovery

This commit is contained in:
Chen Asraf
2022-05-24 21:56:33 +03:00
parent d77ffa2a53
commit 92dceab3a3
6 changed files with 94 additions and 99 deletions

View File

@@ -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)
}
}

View File

@@ -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

31
internal/core.go Normal file
View File

@@ -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.")
}

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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
}