mirror of
https://github.com/chenasraf/gi_gen.git
synced 2026-05-17 17:48:01 +00:00
poc ready
This commit is contained in:
16
file_iter.go
16
file_iter.go
@@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func getGitignores(sourceDir string) ([]string, error) {
|
||||
return filepath.Glob(filepath.Join(sourceDir, "*.gitignore"))
|
||||
}
|
||||
|
||||
func readFile(path string) string {
|
||||
res, err := os.ReadFile(path)
|
||||
handleErr(err)
|
||||
return string(res)
|
||||
}
|
||||
107
gi_gen.go
107
gi_gen.go
@@ -1,72 +1,83 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
// "github.com/tcnksm/go-input"
|
||||
)
|
||||
|
||||
// UNUSED allows unused variables to be included in Go programs
|
||||
func UNUSED(x ...interface{}) {}
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
// create line cache map for skipping previously checked glob lines
|
||||
var lineCache = make(map[string]bool)
|
||||
|
||||
func main() {
|
||||
var callerSkip = 0 // might need to be 1 in release mode?
|
||||
_, filename, _, _ := runtime.Caller(callerSkip)
|
||||
binDir := filepath.Dir(filename)
|
||||
sourceDir := filepath.Join(binDir, ".github.gitignore")
|
||||
wd, _ := os.Getwd()
|
||||
allFiles, err := prepareGitignores()
|
||||
|
||||
log.Println(binDir)
|
||||
|
||||
if !fileExists(sourceDir) {
|
||||
log.Println("Getting gitignore files...")
|
||||
runCmd("git", "clone", "--depth=1", repoUrl, sourceDir)
|
||||
}
|
||||
|
||||
if getNeedsUpdate() {
|
||||
log.Println("Updating gitignore files...")
|
||||
runCmd("git", "pull", "origin", "master")
|
||||
}
|
||||
|
||||
allFiles, err := getGitignores(sourceDir)
|
||||
handleErr(err)
|
||||
|
||||
keep := []string{}
|
||||
files := make(map[string]string)
|
||||
fileNames := []string{}
|
||||
|
||||
log.Println("Found:")
|
||||
for _, v := range allFiles {
|
||||
log.Println("Parsing file: " + v)
|
||||
contents := readFile(v)
|
||||
lines := strings.Split(contents, "\n")
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
_, exists := lineCache[trimmed]
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
lineCache[trimmed] = true
|
||||
if len(trimmed) == 0 || strings.ToLower(string(trimmed[0])) == "#" {
|
||||
lineCache[trimmed] = false
|
||||
continue
|
||||
}
|
||||
log.Println("Parsing line: " + line)
|
||||
if globExists(filepath.Join(wd, line)) {
|
||||
keep = append(keep, line)
|
||||
}
|
||||
for _, filename := range allFiles {
|
||||
contents := readFile(filename)
|
||||
basename := filepath.Base(filename)
|
||||
langName := basename[:strings.Index(basename, ".")]
|
||||
|
||||
if findFileMatches(contents) {
|
||||
sep := "#========================================================================\n"
|
||||
header := fmt.Sprintf(sep+"# %s\n"+sep+"\n", basename)
|
||||
files[langName] = header + contents
|
||||
fileNames = append(fileNames, langName)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Done")
|
||||
log.Println("Done.")
|
||||
|
||||
log.Println("Final output:")
|
||||
for _, v := range keep {
|
||||
log.Println(v)
|
||||
selected := []string{}
|
||||
keys := maps.Keys(files)
|
||||
|
||||
if len(keys) > 1 {
|
||||
prompt := &survey.MultiSelect{
|
||||
Message: "Found matches in your project for the following gitignore files.\nPlease select which you want to write to .gitignore:",
|
||||
Options: fileNames,
|
||||
}
|
||||
|
||||
var inp []string
|
||||
survey.AskOne(prompt, &inp)
|
||||
|
||||
for _, sel := range inp {
|
||||
selected = append(selected, files[sel])
|
||||
}
|
||||
} else {
|
||||
selected = keys
|
||||
}
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
out := filepath.Join(wd, ".gitignore")
|
||||
|
||||
if fileExists(out) {
|
||||
prompt2 := &survey.Select{
|
||||
Message: ".gitignore file found in this directory. Please pick an option:",
|
||||
Options: []string{"Overwrite", "Append", "Skip"},
|
||||
}
|
||||
var inp2 string
|
||||
survey.AskOne(prompt2, &inp2)
|
||||
switch inp2 {
|
||||
case "Overwrite":
|
||||
log.Printf("Writing to %s", out)
|
||||
writeFile(out, strings.Join(selected, "\n"), true)
|
||||
break
|
||||
case "Append":
|
||||
log.Printf("Appending to %s", out)
|
||||
writeFile(out, strings.Join(selected, "\n"), false)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
log.Printf("Writing to %s", out)
|
||||
writeFile(out, strings.Join(selected, "\n"), true)
|
||||
}
|
||||
}
|
||||
|
||||
16
go.mod
16
go.mod
@@ -5,7 +5,17 @@ go 1.18
|
||||
require github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.8 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.3.4
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 // indirect
|
||||
golang.org/x/exp v0.0.0-20220516143420-24438e51023a
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 // indirect
|
||||
)
|
||||
|
||||
31
go.sum
31
go.sum
@@ -1,9 +1,40 @@
|
||||
github.com/AlecAivazis/survey/v2 v2.3.4 h1:pchTU9rsLUSvWEl2Aq9Pv3k0IE2fkqtGxazskAMd9Ng=
|
||||
github.com/AlecAivazis/survey/v2 v2.3.4/go.mod h1:hrV6Y/kQCLhIZXGcriDCUBtB3wnN7156gMXJ3+b23xM=
|
||||
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8 h1:RB0v+/pc8oMzPsN97aZYEwNuJ6ouRJ2uhjxemJ9zvrY=
|
||||
github.com/tcnksm/go-input v0.0.0-20180404061846-548a7d7a8ee8/go.mod h1:IlWNj9v/13q7xFbaK4mbyzMNwrZLaWSHx/aibKIZuIg=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20220516143420-24438e51023a h1:tiLLxEjKNE6Hrah/Dp/cyHvsyjDLcMFSocOHO5XDmOM=
|
||||
golang.org/x/exp v0.0.0-20220516143420-24438e51023a/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
102
ignore_files.go
Normal file
102
ignore_files.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func prepareGitignores() ([]string, error) {
|
||||
var callerSkip = 0 // might need to be 1 in release mode?
|
||||
_, filename, _, _ := runtime.Caller(callerSkip)
|
||||
binDir := filepath.Dir(filename)
|
||||
gitignoresDir := filepath.Join(binDir, ".github.gitignore")
|
||||
|
||||
if !fileExists(gitignoresDir) {
|
||||
log.Println("Getting gitignore files...")
|
||||
runCmd("git", "clone", "--depth=1", repoUrl, gitignoresDir)
|
||||
}
|
||||
|
||||
if getNeedsUpdate() {
|
||||
log.Println("Updating gitignore files...")
|
||||
runCmd("git", "pull", "origin", "master")
|
||||
}
|
||||
|
||||
return getGitignores(gitignoresDir)
|
||||
}
|
||||
|
||||
func getGitignores(sourceDir string) ([]string, error) {
|
||||
return filepath.Glob(filepath.Join(sourceDir, "*.gitignore"))
|
||||
}
|
||||
|
||||
var ignoreLines = []string{
|
||||
"/*",
|
||||
".",
|
||||
".vscode",
|
||||
".vscode/*",
|
||||
".idea",
|
||||
".idea/*",
|
||||
}
|
||||
|
||||
func findFileMatches(patterns string) bool {
|
||||
lines := strings.Split(patterns, "\n")
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
for _, line := range lines {
|
||||
// ignore empty lines / comments
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
if len(line) == 0 || strings.ToLower(line)[0] == '#' {
|
||||
continue
|
||||
}
|
||||
idx := strings.Index(line, "#")
|
||||
// ignore comments at end of line
|
||||
if idx > -1 && (idx == 0 || line[idx-1] != '\\') {
|
||||
line = strings.TrimSpace(line[0:idx])
|
||||
}
|
||||
if len(line) == 0 || contains(ignoreLines, line) {
|
||||
continue
|
||||
}
|
||||
if globExists(filepath.Join(wd, line)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func removeUnusedPatterns(filename string, keep []string) []string {
|
||||
wd, _ := os.Getwd()
|
||||
contents := readFile(filename)
|
||||
lines := strings.Split(contents, "\n")
|
||||
keepCopy := []string{}
|
||||
copy(keep, keepCopy)
|
||||
found := false
|
||||
|
||||
for _, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
_, exists := lineCache[trimmed]
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
lineCache[trimmed] = true
|
||||
if len(trimmed) == 0 || strings.ToLower(string(trimmed[0])) == "#" {
|
||||
lineCache[trimmed] = false
|
||||
continue
|
||||
}
|
||||
|
||||
if globExists(filepath.Join(wd, line)) {
|
||||
found = true
|
||||
keepCopy = append(keepCopy, line)
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
keepCopy = insert(keepCopy, 0, fmt.Sprintf("\n# %s", filepath.Base(filename)))
|
||||
}
|
||||
|
||||
return keep
|
||||
}
|
||||
47
utils.go
47
utils.go
@@ -1,23 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// UNUSED allows unused variables to be included in Go programs
|
||||
func UNUSED(x ...interface{}) {}
|
||||
|
||||
var repoUrl = "https://github.com/github/gitignore"
|
||||
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
exists := os.IsExist(err)
|
||||
exists := !os.IsNotExist(err)
|
||||
return exists
|
||||
}
|
||||
|
||||
func globExists(path string) bool {
|
||||
res, err := filepath.Glob(path)
|
||||
// log.Println("globExists? " + path)
|
||||
handleErr(err)
|
||||
return res != nil
|
||||
}
|
||||
@@ -44,9 +47,49 @@ func runCmd(cmd string, args ...string) (string, error) {
|
||||
return string(res), err
|
||||
}
|
||||
|
||||
func readFile(path string) string {
|
||||
res, err := os.ReadFile(path)
|
||||
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), fs.ModeAppend)
|
||||
} else {
|
||||
f, _ := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
defer f.Close()
|
||||
_, err = f.WriteString("\n" + data)
|
||||
}
|
||||
handleErr(err)
|
||||
return true
|
||||
}
|
||||
|
||||
func handleErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func insert[T any](a []T, i int, item T) []T {
|
||||
return append(a[:i], append([]T{item}, a[i:]...)...)
|
||||
}
|
||||
|
||||
func contains[T comparable](list []T, item T) bool {
|
||||
for _, v := range list {
|
||||
if v == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ternary[T any](cond bool, whenTrue T, whenFalse T) T {
|
||||
if cond {
|
||||
return whenTrue
|
||||
}
|
||||
return whenFalse
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user