@@ -2,7 +2,8 @@ package cmdexec
22
33import (
44 "bufio"
5- "log"
5+ "fmt"
6+ "io"
67 "os"
78 "os/exec"
89)
@@ -12,17 +13,46 @@ import (
1213// # REFERENCES
1314// - https://pkg.go.dev/os@go1.24.4#Pipe
1415func OsPipe () error {
16+ //
17+ // (*Cmd).StdoutPipe()で同じことが出来るが
18+ // os.Pipe()の使い方を勉強するために
19+ // 意図的に利用している
20+ //
21+
22+ ///////////////////////////////////
23+ // パイプ取得
24+ ///////////////////////////////////
25+
1526 var (
1627 pr * os.File
1728 pw * os.File
1829 err error
1930 )
20- pr , pw , err = os .Pipe ()
21- if err != nil {
31+ if pr , pw , err = os .Pipe (); err != nil {
2232 return err
2333 }
2434 defer pr .Close ()
2535
36+ ///////////////////////////////////
37+ // コマンド実行
38+ //
39+ // git log コマンドを実行しているため
40+ // リポジトリによっては長大な出力が発生する。
41+ //
42+ // 簡易なコマンド実行である (*Cmd).Output() で取得しようとすると
43+ // OSのバッファが一杯になってしまう可能性があるため、このような場合は
44+ // ストリーミング処理が必須となる。
45+ //
46+ // 以下で実行している git コマンドのオプションは以下の通り
47+ // - --no-pager : ページャーを使用しない
48+ // - log : ログを表示
49+ // - -m : マージコミットの差分も表示
50+ // - -r : 再帰的に処理
51+ // - --name-only : ファイル名のみ表示
52+ // - --pretty=raw: 生フォーマットで表示
53+ // - -z : NULL文字で区切る
54+ ///////////////////////////////////
55+
2656 var (
2757 name = "git"
2858 args = []string {"--no-pager" , "log" , "-m" , "-r" , "--name-only" , "--pretty=raw" , "-z" }
@@ -34,7 +64,10 @@ func OsPipe() error {
3464 return err
3565 }
3666
37- // 終了待機
67+ ///////////////////////////////////
68+ // 終了待機用のゴルーチンを用意
69+ ///////////////////////////////////
70+
3871 var (
3972 done = make (chan error , 1 )
4073 )
@@ -43,26 +76,55 @@ func OsPipe() error {
4376 done <- cmd .Wait ()
4477 }()
4578
79+ ///////////////////////////////////
80+ // コマンドの出力を読み出し
81+ ///////////////////////////////////
82+
4683 const (
47- MaxTokenSize = 1024 * 1024
84+ MaxTokenSize = 1024 * 1024 // 1行のサイズが大きい可能性を考慮してバッファサイズを底上げ
4885 )
4986 var (
5087 scanner = bufio .NewScanner (pr )
5188 buf = make ([]byte , MaxTokenSize )
89+ count int
5290 )
5391 scanner .Buffer (buf , MaxTokenSize )
5492
5593 for scanner .Scan () {
56- log .Println (scanner .Text ())
94+ io .Discard .Write (scanner .Bytes ())
95+ count ++
5796 }
5897
5998 if err = scanner .Err (); err != nil {
6099 return err
61100 }
62101
102+ ///////////////////////////////////
103+ // コマンド終了待機
104+ ///////////////////////////////////
105+
63106 if err = <- done ; err != nil {
64107 return err
65108 }
66109
110+ ///////////////////////////////////
111+ // 結果出力
112+ ///////////////////////////////////
113+
114+ fmt .Printf ("Total lines: %d\n " , count )
115+
67116 return nil
117+
118+ /*
119+ $ task
120+ task: [build] go build .
121+ task: [run] ./try-golang -onetime
122+
123+ ENTER EXAMPLE NAME: cmdexec_ospipe
124+
125+ [Name] "cmdexec_ospipe"
126+ Total lines: 29988
127+
128+ [Elapsed] 123.966649ms
129+ */
68130}
0 commit comments