From 900b12c4ebdc13d2ad3300ca68293ebbf3c68020 Mon Sep 17 00:00:00 2001 From: devlights Date: Tue, 13 May 2025 06:18:07 +0000 Subject: [PATCH 1/2] Add examples/singleapp/git_archive --- examples/singleapp/git_archive/.gitignore | 2 + examples/singleapp/git_archive/README.md | 21 ++ examples/singleapp/git_archive/Taskfile.yml | 20 ++ examples/singleapp/git_archive/main.go | 203 ++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 examples/singleapp/git_archive/.gitignore create mode 100644 examples/singleapp/git_archive/README.md create mode 100644 examples/singleapp/git_archive/Taskfile.yml create mode 100644 examples/singleapp/git_archive/main.go diff --git a/examples/singleapp/git_archive/.gitignore b/examples/singleapp/git_archive/.gitignore new file mode 100644 index 00000000..48427d27 --- /dev/null +++ b/examples/singleapp/git_archive/.gitignore @@ -0,0 +1,2 @@ +app +*.zip \ No newline at end of file diff --git a/examples/singleapp/git_archive/README.md b/examples/singleapp/git_archive/README.md new file mode 100644 index 00000000..e48490f5 --- /dev/null +++ b/examples/singleapp/git_archive/README.md @@ -0,0 +1,21 @@ +# これは何? + +gitのコミット差分から変更があったファイルのみを抽出してアーカイブするツールです。 + +コマンドラインで利用するツールとなります。 + +gitを使っての実務作業をしていると、毎日たくさんのメンバーがPUSHを行います。 + +その都度、リポジトリには更新が反映されるのですが、ファイルが多くなってくると + +「どのファイルが更新されたのか?」を判断するのが面倒になります。 + +実は、gitコマンドを以下のように発行すると指定したコミット間の変更ファイル一式を取得することが出来ます。 + +```sh +$ git archive --prefix=archive/ main $(git diff --name-only HEAD~1 HEAD) -o archive.zip +``` + +上記のコマンドを実行すると、直近のコミットで変更されたファイルがzipファイルで取得できます。 + +でも、毎回こんなコマンドを実行するの面倒くさいってことで作ったツールです。 diff --git a/examples/singleapp/git_archive/Taskfile.yml b/examples/singleapp/git_archive/Taskfile.yml new file mode 100644 index 00000000..b225e278 --- /dev/null +++ b/examples/singleapp/git_archive/Taskfile.yml @@ -0,0 +1,20 @@ +# https://taskfile.dev + +version: '3' + +tasks: + default: + cmds: + - task: clean + - task: build + - task: run + clean: + cmds: + - rm -f ./app + build: + cmds: + - go build -o app . + run: + cmds: + - ./app + - unzip -l archive.zip \ No newline at end of file diff --git a/examples/singleapp/git_archive/main.go b/examples/singleapp/git_archive/main.go new file mode 100644 index 00000000..eecc7985 --- /dev/null +++ b/examples/singleapp/git_archive/main.go @@ -0,0 +1,203 @@ +package main + +import ( + "archive/zip" + "bytes" + "flag" + "fmt" + "io" + "log" + "os" + "os/exec" + "strings" +) + +const ( + DefaultCommitFrom = "HEAD~1" + DefaultCommitTo = "HEAD" + DefaultRepoPath = "." + DefaultArchivePrefix = "archive" + DefaultArchiveFilePath = "./archive.zip" +) + +type ( + Gitcmd string +) + +func NewGitcmd() Gitcmd { + return Gitcmd("git") +} + +func (me Gitcmd) Exec(args ...string) ([]byte, error) { + var ( + cmd = exec.Command(string(me), args...) + out []byte + err error + ) + out, err = cmd.CombinedOutput() + if err != nil { + return nil, err + } + + return bytes.TrimSuffix(out, []byte("\n")), nil +} + +func (me Gitcmd) ExecString(args ...string) (string, error) { + var ( + out []byte + err error + ) + out, err = me.Exec(args...) + if err != nil { + return "", err + } + + return string(out), nil +} + +type ( + Args struct { + CommitFrom string + CommitTo string + RepoPath string + ArchivePrefix string + ArchiveFilePath string + Verbose bool + } +) + +func (me *Args) restore() { + if me.CommitFrom == "" { + me.CommitFrom = DefaultCommitFrom + } + if me.CommitTo == "" { + me.CommitTo = DefaultCommitTo + } + if me.RepoPath == "" { + me.RepoPath = DefaultRepoPath + } + if me.ArchivePrefix == "" { + me.ArchivePrefix = DefaultArchivePrefix + } + if me.ArchiveFilePath == "" { + me.ArchiveFilePath = DefaultArchiveFilePath + } +} + +var ( + args Args +) + +func init() { + flag.StringVar(&args.CommitFrom, "from", DefaultCommitFrom, "起点となるコミットハッシュ") + flag.StringVar(&args.CommitTo, "to", DefaultCommitTo, "終点となるコミットハッシュ") + flag.StringVar(&args.RepoPath, "repo", DefaultRepoPath, "リポジトリパス") + flag.StringVar(&args.ArchivePrefix, "prefix", DefaultArchivePrefix, "アーカイブ内のプレフィックスディレクトリ") + flag.StringVar(&args.ArchiveFilePath, "archive", DefaultArchiveFilePath, "アーカイブファイル") + flag.BoolVar(&args.Verbose, "v", false, "詳細表示") +} + +func main() { + log.SetFlags(0) + flag.Parse() + + (&args).restore() + + if err := run(); err != nil { + log.Fatal(err) + } +} + +func run() error { + var ( + git = NewGitcmd() + err error + ) + + // リポジトリの場所に移動 + err = os.Chdir(args.RepoPath) + if err != nil { + return err + } + + // 最新のコミットハッシュを取得 + var ( + from string + to string + ) + from, err = git.ExecString("rev-parse", args.CommitFrom) + if err != nil { + return err + } + to, err = git.ExecString("rev-parse", args.CommitTo) + if err != nil { + return err + } + + if args.Verbose { + log.Printf("起点コミットハッシュ: %s(%s)", args.CommitFrom, from) + log.Printf("終点コミットハッシュ: %s(%s)", args.CommitTo, to) + } + + // 変更されたファイルの一覧を取得 + var ( + diff string + files []string + ) + diff, err = git.ExecString("diff", "--name-only", from, to) + if err != nil { + return err + } + files = strings.Split(diff, "\n") + if len(files) == 0 { + return nil + } + + // ZIPファイルを作成 + var ( + zipFile *os.File + writer *zip.Writer + ) + zipFile, err = os.Create(args.ArchiveFilePath) + if err != nil { + return err + } + defer zipFile.Close() + + writer = zip.NewWriter(zipFile) + defer writer.Close() + + for _, file := range files { + if file == "" { + continue + } + + // ファイルの内容を取得し、ZIPファイルにエントリ書き込み + var ( + contents []byte + entry io.Writer + ) + contents, err = git.Exec("show", fmt.Sprintf("%s:%s", to, file)) + if err != nil { + return err + } + + entry, err = writer.Create(fmt.Sprintf("%s/%s", args.ArchivePrefix, file)) + if err != nil { + return err + } + + if _, err = entry.Write(contents); err != nil { + return err + } + + if args.Verbose { + log.Printf("ファイル追加: %s", file) + } + } + if err = writer.Close(); err != nil { + return err + } + + return nil +} From ba81eca241e01cca914904876483709a3bd7cad1 Mon Sep 17 00:00:00 2001 From: devlights Date: Tue, 13 May 2025 06:20:20 +0000 Subject: [PATCH 2/2] Update --- examples/singleapp/git_archive/.gitignore | 2 +- examples/singleapp/git_archive/README.md | 2 ++ examples/singleapp/git_archive/Taskfile.yml | 9 ++++++--- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/singleapp/git_archive/.gitignore b/examples/singleapp/git_archive/.gitignore index 48427d27..2f071cd3 100644 --- a/examples/singleapp/git_archive/.gitignore +++ b/examples/singleapp/git_archive/.gitignore @@ -1,2 +1,2 @@ -app +gitar *.zip \ No newline at end of file diff --git a/examples/singleapp/git_archive/README.md b/examples/singleapp/git_archive/README.md index e48490f5..2809680f 100644 --- a/examples/singleapp/git_archive/README.md +++ b/examples/singleapp/git_archive/README.md @@ -1,5 +1,7 @@ # これは何? +git + ar(chive) = gitar + gitのコミット差分から変更があったファイルのみを抽出してアーカイブするツールです。 コマンドラインで利用するツールとなります。 diff --git a/examples/singleapp/git_archive/Taskfile.yml b/examples/singleapp/git_archive/Taskfile.yml index b225e278..6e9997d4 100644 --- a/examples/singleapp/git_archive/Taskfile.yml +++ b/examples/singleapp/git_archive/Taskfile.yml @@ -2,6 +2,9 @@ version: '3' +vars: + APP_NAME: gitar + tasks: default: cmds: @@ -10,11 +13,11 @@ tasks: - task: run clean: cmds: - - rm -f ./app + - rm -f ./{{.APP_NAME}} build: cmds: - - go build -o app . + - go build -o {{.APP_NAME}} . run: cmds: - - ./app + - ./{{.APP_NAME}} - unzip -l archive.zip \ No newline at end of file