Skip to content

Commit da1c44e

Browse files
authored
attempt to handle --version even in untagged builds (#161)
If we are installed via `go-install` rather than downloading a tagged binary from github, the `Tag` etc variables will all be empty, and therefore the `--version` flag is diked out. But there is a way around this! If the version info is not filled in via build-time flags, use `debug.BuildInfo` to introspect as much information as we can out of the module metadata: ``` $ go install github.com/odenio/goimports-reviser/[email protected] go: downloading github.com/odenio/goimports-reviser/v3 v3.6.6-pre5 $ ~/go/bin/goimports-reviser --version version: 3.6.6-pre5 built with: go1.22.4 tag: v3.6.6-pre5 commit: n/a source: github.com/odenio/goimports-reviser/v3 ``` Additionally, add a `--version-only` flag that prints only the version string itself, handy for use in shell pipelines. Can be used on its own or in combination with the `--version` flag: ``` $ ./go/bin/goimports-reviser --version-only 3.6.6-pre5 ```
1 parent e037fda commit da1c44e

File tree

1 file changed

+87
-14
lines changed

1 file changed

+87
-14
lines changed

main.go

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ package main
33
import (
44
"crypto/md5"
55
"encoding/hex"
6+
"errors"
67
"flag"
78
"fmt"
89
"log"
910
"os"
1011
"os/user"
1112
"path"
1213
"path/filepath"
14+
"regexp"
15+
"runtime/debug"
1316
"strings"
1417

1518
"github.com/incu6us/goimports-reviser/v3/helper"
@@ -19,6 +22,7 @@ import (
1922
const (
2023
projectNameArg = "project-name"
2124
versionArg = "version"
25+
versionOnlyArg = "version-only"
2226
removeUnusedImportsArg = "rm-unused"
2327
setAliasArg = "set-alias"
2428
companyPkgPrefixesArg = "company-prefixes"
@@ -31,6 +35,8 @@ const (
3135
useCacheArg = "use-cache"
3236
applyToGeneratedFiles = "apply-to-generated-files"
3337
excludesArg = "excludes"
38+
// using a regex here so that this will work with forked repos (at least on github.com)
39+
modulePathRegex = `^github.com/[\w-]+/goimports-reviser(/v\d+)?@?`
3440

3541
// Deprecated options
3642
localArg = "local"
@@ -45,6 +51,7 @@ var (
4551
GoVersion string
4652

4753
shouldShowVersion *bool
54+
shouldShowVersionOnly *bool
4855
shouldRemoveUnusedImports *bool
4956
shouldSetAlias *bool
5057
shouldFormat *bool
@@ -53,6 +60,7 @@ var (
5360
setExitStatus *bool
5461
isRecursive *bool
5562
isUseCache *bool
63+
modulePathMatcher = regexp.MustCompile(modulePathRegex)
5664
)
5765

5866
var (
@@ -168,13 +176,18 @@ Optional parameter.`,
168176
"Apply imports sorting and formatting(if the option is set) to generated files. Generated file is a file with first comment which starts with comment '// Code generated'. Optional parameter.",
169177
)
170178

171-
if Tag != "" {
172-
shouldShowVersion = flag.Bool(
173-
versionArg,
174-
false,
175-
"Show version.",
176-
)
177-
}
179+
shouldShowVersion = flag.Bool(
180+
versionArg,
181+
false,
182+
"Show version information",
183+
)
184+
185+
shouldShowVersionOnly = flag.Bool(
186+
versionOnlyArg,
187+
false,
188+
"Show only the version string",
189+
)
190+
178191
}
179192

180193
func printUsage() {
@@ -185,27 +198,87 @@ func printUsage() {
185198
flag.PrintDefaults()
186199
}
187200

201+
func getBuildInfo() *debug.BuildInfo {
202+
bi, ok := debug.ReadBuildInfo()
203+
if !ok {
204+
return nil
205+
}
206+
return bi
207+
}
208+
209+
func getMyModuleInfo(bi *debug.BuildInfo) (*debug.Module, error) {
210+
if bi == nil {
211+
return nil, errors.New("no build info available")
212+
}
213+
// depending on the context in which we are called, the main module may not be set
214+
if bi.Main.Path != "" {
215+
return &bi.Main, nil
216+
}
217+
// if the main module is not set, we need to find the dep that contains our module
218+
for _, m := range bi.Deps {
219+
if modulePathMatcher.MatchString(m.Path) {
220+
return m, nil
221+
}
222+
}
223+
return nil, errors.New("no matching module found in build info")
224+
}
225+
188226
func printVersion() {
227+
if Tag != "" {
228+
fmt.Printf(
229+
"version: %s\nbuilt with: %s\ntag: %s\ncommit: %s\nsource: %s\n",
230+
strings.TrimPrefix(Tag, "v"),
231+
GoVersion,
232+
Tag,
233+
Commit,
234+
SourceURL,
235+
)
236+
return
237+
}
238+
bi := getBuildInfo()
239+
myModule, err := getMyModuleInfo(bi)
240+
if err != nil {
241+
log.Fatalf("failed to get my module info: %s", err)
242+
}
189243
fmt.Printf(
190-
"version: %s\nbuild with: %s\ntag: %s\ncommit: %s\nsource: %s\n",
191-
strings.TrimPrefix(Tag, "v"),
192-
GoVersion,
193-
Tag,
194-
Commit,
195-
SourceURL,
244+
"version: %s\nbuilt with: %s\ntag: %s\ncommit: %s\nsource: %s\n",
245+
strings.TrimPrefix(myModule.Version, "v"),
246+
bi.GoVersion,
247+
myModule.Version,
248+
"n/a",
249+
myModule.Path,
196250
)
197251
}
198252

253+
func printVersionOnly() {
254+
if Tag != "" {
255+
fmt.Println(strings.TrimPrefix(Tag, "v"))
256+
return
257+
}
258+
bi := getBuildInfo()
259+
myModule, err := getMyModuleInfo(bi)
260+
if err != nil {
261+
log.Fatalf("failed to get my module info: %s", err)
262+
}
263+
fmt.Println(strings.TrimPrefix(myModule.Version, "v"))
264+
}
265+
199266
func main() {
200267
deprecatedMessagesCh := make(chan string, 10)
201268
flag.Parse()
202269

270+
if shouldShowVersionOnly != nil && *shouldShowVersionOnly {
271+
printVersionOnly()
272+
return
273+
}
274+
203275
if shouldShowVersion != nil && *shouldShowVersion {
204276
printVersion()
205277
return
206278
}
207279

208280
originPath := flag.Arg(0)
281+
209282
if filePath != "" {
210283
deprecatedMessagesCh <- fmt.Sprintf("-%s is deprecated. Put file name as last argument to the command(Example: goimports-reviser -rm-unused -set-alias -format goimports-reviser/main.go)", filePathArg)
211284
originPath = filePath
@@ -391,7 +464,7 @@ func validateRequiredParam(filePath string) error {
391464
stat, _ := os.Stdin.Stat()
392465
if stat.Mode()&os.ModeNamedPipe == 0 {
393466
// no data on stdin
394-
return fmt.Errorf("no data on stdin")
467+
return errors.New("no data on stdin")
395468
}
396469
}
397470
return nil

0 commit comments

Comments
 (0)