-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
104 lines (97 loc) · 3.66 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// The proto-gen-go command runs an explicitly versioned protoc
// command, with Go and Twirp plugins, inside a container, to generate
// Go declarations for protocol messages and Twirp RPC interfaces in a
// set of .proto files. Run this program manually (or via Make) after
// changing your .proto files.
//
// Usage:
//
// $ go run github.com/github/[email protected] [flags] [--] [protoc-flags] [proto files]
//
// When invoked from build scripts, it is best to use an explicit
// module version (not 'latest') to ensure build reproducibility.
// All of the tool's own dependencies are explicitly versioned.
//
// If you add this special comment to a Go source file in your proto/ directory:
//
// package proto
// //go:generate sh -c "go run github.com/github/[email protected] ..."
//
// then you'll be able to update your generated code by running this
// command from the root:
//
// $ go generate ./proto
//
// All flags and arguments are passed directly to protoc. Assuming a
// go:generate directive in the proto/ directory, typical arguments are:
//
// --proto_path=$(pwd) Root of proto import tree; absolute path recommended.
// --go_out=.. Root of tree for generated files for messages.
// --twirp_out=. Root of tree for generated files for Twirp services.
// --go_opt=paths=source_relative Generated filenames mirror source file names.
// messages.proto services.proto List of proto files.
//
// Protoc is quite particular about the use of absolute vs. relative
// paths, which is why the example above used "sh -c", to allow
// arguments to reference $(pwd).
//
// This program uses Docker to ensure maximum reproducibility and
// minimum side effects. In particular:
// - Thanks to volume mounts, the program can only change files
// beneath $(pwd); changes outside this tree are not reflected
// outside the container. If you want the command to write the
// generated files outside the proto/ tree, you'll need to use
// 'cd .. && go run ...' and adjust the flags accordingly.
// - By always running protoc on Linux, we needn't worry about
// downloading an appropriate executable.
package main
import (
"bytes"
_ "embed"
"flag"
"fmt"
"log"
"os"
"os/exec"
"strings"
)
// dockerfile contains the docker specification for our versioned dependencies
//go:embed Dockerfile
var dockerfile string
func main() {
log.SetPrefix("proto-gen-go: ")
log.SetFlags(0)
flag.Parse()
pwd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
// Build the protoc container image specified by the Dockerfile.
// The dockerized program assumes linux/amd64, and the --platform flag enables
// dynamic binary translation on M1 hardware.
// The docker context is empty.
log.Printf("building protoc container image...")
cmd := exec.Command("docker", "build", "--platform=linux/amd64", "-q", "-")
cmd.Stdin = strings.NewReader(dockerfile)
cmd.Stderr = os.Stderr
cmd.Stdout = new(bytes.Buffer)
if err := cmd.Run(); err != nil {
log.Fatalf("docker build failed: %v", err)
}
id := strings.TrimSpace(fmt.Sprint(cmd.Stdout)) // docker image id
// Log the command, neatly.
protocArgs := flag.Args()
cmdstr := "protoc " + strings.ReplaceAll(strings.Join(protocArgs, " "), pwd, "$(pwd)")
log.Println(cmdstr)
// Run protoc, in a container.
// We assume pwd does not conflict with some critical part
// of the docker image, and volume-mount it.
cmd = exec.Command("docker", "run", "-v", pwd+":"+pwd, "--platform=linux/amd64", id)
cmd.Args = append(cmd.Args, protocArgs...)
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatalf("protoc command failed: %v", err)
}
log.Println("done")
}