@@ -2,7 +2,8 @@ package cmdexec
2
2
3
3
import (
4
4
"bufio"
5
- "log"
5
+ "fmt"
6
+ "io"
6
7
"os"
7
8
"os/exec"
8
9
)
@@ -12,17 +13,46 @@ import (
12
13
// # REFERENCES
13
14
// - https://pkg.go.dev/os@go1.24.4#Pipe
14
15
func OsPipe () error {
16
+ //
17
+ // (*Cmd).StdoutPipe()で同じことが出来るが
18
+ // os.Pipe()の使い方を勉強するために
19
+ // 意図的に利用している
20
+ //
21
+
22
+ ///////////////////////////////////
23
+ // パイプ取得
24
+ ///////////////////////////////////
25
+
15
26
var (
16
27
pr * os.File
17
28
pw * os.File
18
29
err error
19
30
)
20
- pr , pw , err = os .Pipe ()
21
- if err != nil {
31
+ if pr , pw , err = os .Pipe (); err != nil {
22
32
return err
23
33
}
24
34
defer pr .Close ()
25
35
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
+
26
56
var (
27
57
name = "git"
28
58
args = []string {"--no-pager" , "log" , "-m" , "-r" , "--name-only" , "--pretty=raw" , "-z" }
@@ -34,7 +64,10 @@ func OsPipe() error {
34
64
return err
35
65
}
36
66
37
- // 終了待機
67
+ ///////////////////////////////////
68
+ // 終了待機用のゴルーチンを用意
69
+ ///////////////////////////////////
70
+
38
71
var (
39
72
done = make (chan error , 1 )
40
73
)
@@ -43,26 +76,55 @@ func OsPipe() error {
43
76
done <- cmd .Wait ()
44
77
}()
45
78
79
+ ///////////////////////////////////
80
+ // コマンドの出力を読み出し
81
+ ///////////////////////////////////
82
+
46
83
const (
47
- MaxTokenSize = 1024 * 1024
84
+ MaxTokenSize = 1024 * 1024 // 1行のサイズが大きい可能性を考慮してバッファサイズを底上げ
48
85
)
49
86
var (
50
87
scanner = bufio .NewScanner (pr )
51
88
buf = make ([]byte , MaxTokenSize )
89
+ count int
52
90
)
53
91
scanner .Buffer (buf , MaxTokenSize )
54
92
55
93
for scanner .Scan () {
56
- log .Println (scanner .Text ())
94
+ io .Discard .Write (scanner .Bytes ())
95
+ count ++
57
96
}
58
97
59
98
if err = scanner .Err (); err != nil {
60
99
return err
61
100
}
62
101
102
+ ///////////////////////////////////
103
+ // コマンド終了待機
104
+ ///////////////////////////////////
105
+
63
106
if err = <- done ; err != nil {
64
107
return err
65
108
}
66
109
110
+ ///////////////////////////////////
111
+ // 結果出力
112
+ ///////////////////////////////////
113
+
114
+ fmt .Printf ("Total lines: %d\n " , count )
115
+
67
116
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
+ */
68
130
}
0 commit comments