/
gocmd.go
137 lines (125 loc) · 3.79 KB
/
gocmd.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package gocmd provides helers for invoking Go tooling.
package gocmd
import (
"errors"
"fmt"
"io/fs"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"cloud.google.com/go/internal/gapicgen/execv"
)
var (
// ErrBuildConstraint is returned when the Go command returns this error.
ErrBuildConstraint error = errors.New("build constraints exclude all Go files")
)
// ModTidy tidies go.mod file in the specified directory
func ModTidy(dir string) error {
log.Printf("[%s] running go mod tidy", dir)
c := execv.Command("go", "mod", "tidy")
c.Dir = dir
c.Env = []string{
fmt.Sprintf("PATH=%s", os.Getenv("PATH")), // TODO(deklerk): Why do we need to do this? Doesn't seem to be necessary in other exec.Commands.
fmt.Sprintf("HOME=%s", os.Getenv("HOME")), // TODO(deklerk): Why do we need to do this? Doesn't seem to be necessary in other exec.Commands.
}
return c.Run()
}
// ModTidyAll tidies all mod files from the specified root directory.
func ModTidyAll(dir string) error {
log.Printf("[%s] finding all modules", dir)
var modDirs []string
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.Name() == "go.mod" {
modDirs = append(modDirs, filepath.Dir(path))
}
return nil
})
if err != nil {
return err
}
for _, modDir := range modDirs {
if err := ModTidy(modDir); err != nil {
return err
}
}
return nil
}
// ListModName finds a modules name for a given directory.
func ListModName(dir string) (string, error) {
modC := execv.Command("go", "list", "-m")
modC.Dir = dir
mod, err := modC.Output()
return string(mod), err
}
// ListModDirName finds the directory in which the module resides. Returns
// ErrBuildConstraint if all files in a module are constrained.
func ListModDirName(dir string) (string, error) {
var out []byte
var err error
c := execv.Command("go", "list", "-f", "'{{.Module.Dir}}'")
c.Dir = dir
if out, err = c.Output(); err != nil {
if ee, ok := err.(*exec.ExitError); ok {
if strings.Contains(string(ee.Stderr), "build constraints exclude all Go files") {
return "", ErrBuildConstraint
}
}
return "", err
}
return strings.Trim(strings.TrimSpace(string(out)), "'"), nil
}
// Build attempts to build all packages recursively from the given directory.
func Build(dir string) error {
log.Println("building generated code")
c := execv.Command("go", "build", "./...")
c.Dir = dir
if _, err := c.Output(); err != nil {
if ee, ok := err.(*exec.ExitError); ok {
log.Printf("Error Output: %s", ee.Stderr)
}
return err
}
return nil
}
// Vet runs linters on all .go files recursively from the given directory.
func Vet(dir string) error {
log.Println("vetting generated code")
c := execv.Command("goimports", "-w", ".")
c.Dir = dir
if err := c.Run(); err != nil {
return err
}
c = execv.Command("gofmt", "-s", "-d", "-w", "-l", ".")
c.Dir = dir
return c.Run()
}
// CurrentMod returns the module name of the provided directory.
func CurrentMod(dir string) (string, error) {
log.Println("detecting current module")
c := execv.Command("go", "list", "-m")
c.Dir = dir
var out []byte
var err error
if out, err = c.Output(); err != nil {
return "", err
}
return strings.TrimSpace(string(out)), nil
}