1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

fix: accepting non-main.go files as well

Previous code was handling only main.go as the main build file, but
the main function can actually be in any file.

Now, if a specific file (*.go) is passed, that file will be checked
for the main function.

If a folder is passed, the package will be scanned for the main
function.
This commit is contained in:
Carlos Alexandro Becker 2017-11-20 10:49:57 -02:00 committed by Carlos Alexandro Becker
parent 13d2bca06f
commit 9a9b9373a2
2 changed files with 73 additions and 18 deletions

View File

@ -45,7 +45,17 @@ func (Pipe) Run(ctx *context.Context) error {
}
func checkMain(ctx *context.Context, build config.Build) error {
var dir = strings.Replace(build.Main, "main.go", "", -1)
if strings.HasSuffix(build.Main, ".go") {
file, err := parser.ParseFile(token.NewFileSet(), build.Main, nil, 0)
if err != nil {
return errors.Wrapf(err, "failed to parse file: %s", build.Main)
}
if !hasMain(file) {
return fmt.Errorf("build for %s does not contain a main function", build.Binary)
}
return nil
}
var dir = build.Main
if dir == "" {
dir = "."
}
@ -55,21 +65,27 @@ func checkMain(ctx *context.Context, build config.Build) error {
}
for _, pack := range packs {
for _, file := range pack.Files {
for _, decl := range file.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok {
continue
}
log.Info(fn.Name.Name)
if fn.Name.Name == "main" && fn.Recv == nil {
return nil
}
if hasMain(file) {
return nil
}
}
}
return fmt.Errorf("build for %s does not contain a main function", build.Binary)
}
func hasMain(file *ast.File) bool {
for _, decl := range file.Decls {
fn, isFn := decl.(*ast.FuncDecl)
if !isFn {
continue
}
if fn.Name.Name == "main" && fn.Recv == nil {
return true
}
}
return false
}
func runPipeOnBuild(ctx *context.Context, build config.Build) error {
if err := runHook(build.Env, build.Hooks.Pre); err != nil {
return errors.Wrap(err, "pre hook failed")

View File

@ -277,7 +277,7 @@ func TestRunPipeWithouMainFunc(t *testing.T) {
})
t.Run("not main.go", func(t *testing.T) {
ctx.Config.Builds[0].Main = "foo.go"
assert.EqualError(t, Pipe{}.Run(ctx), `failed to parse dir: foo.go: open foo.go: no such file or directory`)
assert.EqualError(t, Pipe{}.Run(ctx), `failed to parse file: foo.go: open foo.go: no such file or directory`)
})
t.Run("glob", func(t *testing.T) {
ctx.Config.Builds[0].Main = "."
@ -289,23 +289,62 @@ func TestRunPipeWithouMainFunc(t *testing.T) {
})
}
func TestRunPipeWithMainFuncNotInMainGoFile(t *testing.T) {
folder, back := testlib.Mktmp(t)
defer back()
assert.NoError(t, ioutil.WriteFile(
filepath.Join(folder, "foo.go"),
[]byte("package main\nfunc main() {println(0)}"),
0644,
))
var config = config.Project{
Builds: []config.Build{
{
Binary: "foo",
Hooks: config.Hooks{},
Goos: []string{
runtime.GOOS,
},
Goarch: []string{
runtime.GOARCH,
},
},
},
}
var ctx = context.New(config)
t.Run("empty", func(t *testing.T) {
ctx.Config.Builds[0].Main = ""
assert.NoError(t, Pipe{}.Run(ctx))
})
t.Run("foo.go", func(t *testing.T) {
ctx.Config.Builds[0].Main = "foo.go"
assert.NoError(t, Pipe{}.Run(ctx))
})
t.Run("glob", func(t *testing.T) {
ctx.Config.Builds[0].Main = "."
assert.NoError(t, Pipe{}.Run(ctx))
})
}
func exists(file string) bool {
_, err := os.Stat(file)
return !os.IsNotExist(err)
}
func writeMainWithoutMainFunc(t *testing.T, folder string) {
writeFile(t, folder, "package main\nconst a = 2\nfunc notMain() {println(0)}")
assert.NoError(t, ioutil.WriteFile(
filepath.Join(folder, "main.go"),
[]byte("package main\nconst a = 2\nfunc notMain() {println(0)}"),
0644,
))
}
func writeGoodMain(t *testing.T, folder string) {
writeFile(t, folder, "package main\nvar a = 1\nfunc main() {println(0)}")
}
func writeFile(t *testing.T, folder, content string) {
assert.NoError(t, ioutil.WriteFile(
filepath.Join(folder, "main.go"), []byte(content), 0644),
)
filepath.Join(folder, "main.go"),
[]byte("package main\nvar a = 1\nfunc main() {println(0)}"),
0644,
))
}
func assertContainsError(t *testing.T, err error, s string) {