From 190a1a631b1be8b09bf59e7d18c4811d81508dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=99=E2=97=A6=20The=20Tablet=20=E2=9D=80=20GamerGirla?= =?UTF-8?q?ndCo=20=E2=97=A6=E2=9D=A7?= Date: Thu, 12 Sep 2024 19:35:20 -0400 Subject: [PATCH] =?UTF-8?q?hello=20world!=20=F0=9F=8C=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 28 ++++ .idea/gopack-internal.iml | 9 ++ .idea/inspectionProfiles/Project_Default.xml | 15 ++ .idea/modules.xml | 8 + README.md | 9 ++ go.mod | 8 + go.sum | 4 + main.go | 148 +++++++++++++++++++ 8 files changed, 229 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/gopack-internal.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/modules.xml create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9016277 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# ---> Go +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env + +.idea/material_theme_project_new.xml \ No newline at end of file diff --git a/.idea/gopack-internal.iml b/.idea/gopack-internal.iml new file mode 100644 index 0000000..338a266 --- /dev/null +++ b/.idea/gopack-internal.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..d20b53d --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8f67527 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8927e61 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# gopack + +internal utility to create zip files from go module directories + +## usage + +``` +gopack PACKAGE-NAME VERSION PATH [COMMA-SEPARATED-EXCLUSION-GLOBS] +``` \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3cd93d9 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module rockfic.com/gopack + +go 1.23.0 + +require ( + github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect + golang.org/x/mod v0.21.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2445da5 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= +github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= diff --git a/main.go b/main.go new file mode 100644 index 0000000..077e7e7 --- /dev/null +++ b/main.go @@ -0,0 +1,148 @@ +package main + +import ( + "bytes" + "fmt" + "github.com/bmatcuk/doublestar/v4" + "golang.org/x/mod/module" + "golang.org/x/mod/zip" + "io" + "log" + "os" + "path" + "path/filepath" + "slices" + "strings" +) + +type dirFile struct { + filePath, slashPath string + info os.FileInfo +} + +func (f dirFile) Path() string { return f.slashPath } +func (f dirFile) Lstat() (os.FileInfo, error) { return f.info, nil } +func (f dirFile) Open() (io.ReadCloser, error) { return os.Open(f.filePath) } + +func parseGitignore(wd string) []string { + f := make([]string, 0) + file, err := os.ReadFile(path.Join(wd, ".gitignore")) + if err == nil { + str := bytes.NewBuffer(file).String() + for _, rline := range strings.Split(str, "\n") { + line := strings.TrimSpace(rline) + if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "!") { + continue + } + if strings.HasPrefix(line, "*") { + f = append(f, line) + f = append(f, fmt.Sprintf("**/%s", line)) + } else if strings.HasSuffix(line, "/") { + f = append(f, fmt.Sprintf("%s/**", line)) + f = append(f, fmt.Sprintf("%s/**/*", line)) + } + } + } + fmt.Println(f) + return f +} + +func doWalk(wd string, exGlobs []string) []zip.File { + f := make([]zip.File, 0) + filepath.Walk(wd, func(p string, info os.FileInfo, err error) error { + slashed := filepath.ToSlash(p) + //fmt.Printf("%+v\n", exGlobs) + rel, _ := filepath.Rel(wd, slashed) + rel = filepath.ToSlash(rel) + if info.IsDir() { + if p == wd { + return nil + } + switch filepath.Base(p) { + case ".git", ".bzr", ".svn", ".hg": + return filepath.SkipDir + } + if goModInfo, err := os.Lstat(filepath.Join(p, "go.mod")); err == nil && !goModInfo.IsDir() { + return filepath.SkipDir + } + for _, pat := range exGlobs { + + ok, _ := doublestar.Match(pat, rel) + //fmt.Println("----ok----", rel, pat, ok, err) + if ok { + return filepath.SkipDir + } + } + + return nil + } + if !info.Mode().IsRegular() { + return nil + } + + fmt.Println("REL", rel) + ok, err := doublestar.Match(fmt.Sprintf("{%s}", strings.Join(exGlobs, ",")), rel) + if err != nil { + log.Fatal(err) + } + if !ok { + fmt.Println("----ok----", rel, ok, err) + if !slices.Contains(maps(f, func(t zip.File) string { + return t.Path() + }), slashed) { + f = append(f, dirFile{ + filePath: p, + info: info, + slashPath: rel, + }) + } + } + + return nil + }) + for _, file := range f { + fmt.Println(file.Path()) + } + return f +} + +func maps[T any, R any](slice []T, fn func(t T) R) []R { + ret := make([]R, 0) + for _, e := range slice { + ret = append(ret, fn(e)) + } + return ret +} + +func main() { + args := os.Args[1:] + if len(args) < 3 { + log.Fatal("usage: PACKAGE-NAME VERSION PATH [EXCLUSION-GLOBS...]") + } + version := args[1] + if !strings.HasPrefix(version, "v") { + version = fmt.Sprintf("v%s", version) + } + + var absPath string + absPath, _ = filepath.Abs(args[2]) + excludeGlobs := make([]string, 0) + excludeGlobs = append(excludeGlobs, ".*/*", "build/**") + excludeGlobs = append(excludeGlobs, parseGitignore(absPath)...) + if len(args) >= 4 { + excludeGlobs = append(excludeGlobs, args[3:]...) + } + + buildFile := fmt.Sprintf(filepath.Join(absPath, "build", "%s.zip"), version) + walked := doWalk(absPath, excludeGlobs) + fmt.Printf("%+v\n", walked) + _ = os.Remove(buildFile) + f, _ := os.Create(buildFile) + err := zip.Create(f, module.Version{ + Version: version, + Path: args[0], + }, walked) + if err != nil { + log.Fatal(err) + } +}