From acb8fb631bb1e845b2ca3368cc84a73722e8827e Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Tue, 10 Mar 2020 09:33:41 -0700 Subject: [PATCH 01/18] Initial commit to go mod --- go.mod | 27 +++++ harness/build.go | 15 ++- model/command_config.go | 237 ++++++++++++++++++++++++++++----------- model/revel_container.go | 57 +++++----- parser/imports.go | 3 +- parser/utils.go | 18 +++ parser2/read.go | 123 ++++++++++++++++++++ revel/build.go | 14 +-- revel/new.go | 119 +++++++++++--------- revel/new_test.go | 4 +- revel/revel.go | 2 +- revel/run.go | 2 +- revel/test.go | 2 +- revel/version.go | 22 ++-- utils/file.go | 94 +++++++++------- 15 files changed, 525 insertions(+), 214 deletions(-) create mode 100644 go.mod create mode 100644 parser/utils.go create mode 100644 parser2/read.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a6e1c32 --- /dev/null +++ b/go.mod @@ -0,0 +1,27 @@ +module github.com/revel/cmd + +go 1.13 + +require ( + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/agtorre/gocolorize v1.0.0 + github.com/fsnotify/fsnotify v1.4.7 // indirect + github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect + github.com/jessevdk/go-flags v1.4.0 + github.com/mattn/go-colorable v0.1.4 + github.com/myesui/uuid v1.0.0 // indirect + github.com/pkg/errors v0.9.1 + github.com/revel/config v0.21.0 + github.com/revel/log15 v2.11.20+incompatible + github.com/revel/pathtree v0.0.0-20140121041023-41257a1839e9 // indirect + github.com/revel/revel v0.21.0 + github.com/stretchr/testify v1.4.0 + github.com/twinj/uuid v1.0.0 // indirect + github.com/xeonx/timeago v1.0.0-rc4 // indirect + golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect + golang.org/x/tools v0.0.0-20200219054238-753a1d49df85 + gopkg.in/fsnotify/fsnotify.v1 v1.4.7 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 + gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0 + gopkg.in/stretchr/testify.v1 v1.2.2 // indirect +) diff --git a/harness/build.go b/harness/build.go index ea6b7ef..b8bc7f9 100644 --- a/harness/build.go +++ b/harness/build.go @@ -19,8 +19,10 @@ import ( "time" "github.com/revel/cmd/model" - "github.com/revel/cmd/parser" + _ "github.com/revel/cmd/parser" "github.com/revel/cmd/utils" + "github.com/revel/cmd/parser2" + "github.com/revel/cmd/parser" ) var importErrorPattern = regexp.MustCompile("cannot find package \"([^\"]+)\"") @@ -40,7 +42,13 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err // First, clear the generated files (to avoid them messing with ProcessSource). cleanSource(paths, "tmp", "routes") - sourceInfo, err := parser.ProcessSource(paths) + var sourceInfo *model.SourceInfo + + if c.HistoricBuildMode { + sourceInfo, err = parser.ProcessSource(paths) + } else { + sourceInfo, err = parser2.ProcessSource(paths) + } if err != nil { return } @@ -151,7 +159,6 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err if len(c.BuildFlags) == 0 { flags = []string{ "build", - "-i", "-ldflags", versionLinkerFlags, "-tags", buildTags, "-o", binName} @@ -178,7 +185,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err // This is Go main path gopath := c.GoPath for _, o := range paths.ModulePathMap { - gopath += string(filepath.ListSeparator) + o + gopath += string(filepath.ListSeparator) + o.Path } // Note: It's not applicable for filepath.* usage diff --git a/model/command_config.go b/model/command_config.go index 93b355b..6cbbe76 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -2,6 +2,9 @@ package model import ( "fmt" + "github.com/revel/cmd" +// "github.com/revel/cmd/logger" + "github.com/revel/cmd/utils" "go/ast" "go/build" "go/parser" @@ -11,10 +14,7 @@ import ( "os/exec" "path/filepath" "strings" - - "github.com/revel/cmd" - "github.com/revel/cmd/logger" - "github.com/revel/cmd/utils" + "runtime" ) // The constants @@ -45,15 +45,17 @@ type ( SrcRoot string // The source root AppPath string // The application path (absolute) AppName string // The application name - Vendored bool // True if the application is vendored + HistoricBuildMode bool `long:"historic-build-mode" description:"If set the code is scanned using the original parsers, not the go.1.11+"` // True if debug is active + Vendored bool // True if the application is vendored PackageResolver func(pkgName string) error // a packge resolver for the config BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` // The new command New struct { - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` - Vendored bool `short:"V" long:"vendor" description:"True if project should contain a vendor folder to be initialized. Creates the vendor folder and the 'Gopkg.toml' file in the root"` - Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` + ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` + SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` + Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` + Vendored bool `short:"V" long:"vendor" description:"True if project should contain a vendor folder to be initialized. Creates the vendor folder and the 'Gopkg.toml' file in the root"` + Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` } `command:"new"` // The build command Build struct { @@ -89,7 +91,7 @@ type ( // The version command Version struct { ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - Update bool `short:"u" long:"update" description:"Update the framework and modules" required:"false"` + Update bool `short:"u" long:"Update the framework and modules" required:"false"` } `command:"version"` } ) @@ -103,14 +105,19 @@ func (c *CommandConfig) UpdateImportPath() error { importPath = c.New.ImportPath case RUN: importPath = c.Run.ImportPath + c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) case BUILD: importPath = c.Build.ImportPath + c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) case PACKAGE: importPath = c.Package.ImportPath + c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) case CLEAN: importPath = c.Clean.ImportPath + c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) case TEST: importPath = c.Test.ImportPath + c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) case VERSION: importPath = c.Version.ImportPath required = false @@ -135,8 +142,7 @@ func (c *CommandConfig) UpdateImportPath() error { if strings.HasPrefix(currentPath, path) && len(currentPath) > len(path)+1 { importPath = currentPath[len(path)+1:] // Remove the source from the path if it is there - isSRC := strings.ToLower(importPath[0:4]) - if len(importPath) > 4 && (isSRC == "src/" || isSRC == "src\\") { + if len(importPath) > 4 && strings.ToLower(importPath[0:4]) == "src/" { importPath = importPath[4:] } else if importPath == "src" { if c.Index != VERSION { @@ -151,12 +157,14 @@ func (c *CommandConfig) UpdateImportPath() error { } c.ImportPath = importPath - utils.Logger.Info("Returned import path", "path", importPath, "buildpath", build.Default.GOPATH) + // We need the source root determined at this point to check the setversions + c.initAppFolder() + utils.Logger.Info("Returned import path", "path", importPath) if required && c.Index != NEW { if err := c.SetVersions(); err != nil { utils.Logger.Panic("Failed to fetch revel versions", "error", err) } - if err := c.FrameworkVersion.CompatibleFramework(c); err != nil { + if err:=c.FrameworkVersion.CompatibleFramework(c);err!=nil { utils.Logger.Fatal("Compatibility Error", "message", err, "Revel framework version", c.FrameworkVersion.String(), "Revel tool version", c.CommandVersion.String()) } @@ -165,34 +173,130 @@ func (c *CommandConfig) UpdateImportPath() error { if !required { return nil } - if len(importPath) == 0 { + if len(importPath) == 0 { return fmt.Errorf("Unable to determine import path from : %s", importPath) } return nil } +func (c *CommandConfig) initAppFolder() (err error) { + utils.Logger.Info("initAppFolder") + // check for go executable + c.GoCmd, err = exec.LookPath("go") + if err != nil { + utils.Logger.Fatal("Go executable not found in PATH.") + } + + // First try to determine where the application is located - this should be the import value + appFolder := c.ImportPath + wd,err := os.Getwd() + if len(appFolder) == 0 { + // We will assume the working directory is the appFolder + appFolder = wd + } else if strings.LastIndex(wd,appFolder)==len(wd)-len(appFolder) { + // Check for existence of an /app folder + if utils.Exists(filepath.Join(wd,"app")) { + appFolder = wd + } else { + appFolder = filepath.Join(wd,appFolder) + } + } else if strings.Contains(appFolder,".") { + appFolder = filepath.Join(wd,filepath.Base(c.ImportPath)) + } else if !filepath.IsAbs(appFolder) { + appFolder = filepath.Join(wd,appFolder) + } + + utils.Logger.Info("Determined app folder to be", "folder",appFolder, "working",wd) + + // Use app folder to read the go.mod if it exists and extract the package information + goModFile := filepath.Join(appFolder,"go.mod") + if utils.Exists(goModFile) { + c.Vendored = true + file,err:=ioutil.ReadFile(goModFile) + if err!=nil { + return err + } + for _,line := range strings.Split(string(file),"\n") { + if strings.Index(line,"module ")==0 { + c.ImportPath = strings.TrimSpace(strings.Split(line,"module")[1]) + c.AppPath = appFolder + c.SrcRoot = appFolder + utils.Logger.Info("Set application path and package based on go mod", "path", c.AppPath, "sourceroot", c.SrcRoot) + return nil + } + } + } + + utils.Logger.Fatal("Trying to set path based on gopath") + // lookup go path + c.GoPath = build.Default.GOPATH + if c.GoPath == "" { + utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " + + "Please refer to http://golang.org/doc/code.html to configure your Go environment.") + } + + // revel/revel#1004 choose go path relative to current working directory + + // What we want to do is to add the import to the end of the + // gopath, and discover which import exists - If none exist this is an error except in the case + // where we are dealing with new which is a special case where we will attempt to target the working directory first + workingDir, _ := os.Getwd() + goPathList := filepath.SplitList(c.GoPath) + bestpath := "" + for _, path := range goPathList { + if c.Index == NEW { + // If the GOPATH is part of the working dir this is the most likely target + if strings.HasPrefix(workingDir, path) { + bestpath = path + } + } else { + if utils.Exists(filepath.Join(path, "src", c.ImportPath)) { + c.SrcRoot = path + break + } + } + } + + utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath",bestpath) + if len(c.SrcRoot) == 0 && len(bestpath) > 0 { + c.SrcRoot = bestpath + } + + // If source root is empty and this isn't a version then skip it + if len(c.SrcRoot) == 0 { + if c.Index == NEW { + c.SrcRoot = c.New.ImportPath + } else { + if c.Index != VERSION { + utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.") + } + return nil + } + } + + // set go src path + c.SrcRoot = filepath.Join(c.SrcRoot, "src") + + c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath)) + utils.Logger.Info("Set application path", "path", c.AppPath) + return nil +} + // Used to initialize the package resolver func (c *CommandConfig) InitPackageResolver() { - c.Vendored = utils.DirExists(filepath.Join(c.AppPath, "vendor")) + c.Vendored = utils.DirExists(filepath.Join(c.AppPath, "go.mod")) if c.Index == NEW && c.New.Vendored { c.Vendored = true } utils.Logger.Info("InitPackageResolver", "useVendor", c.Vendored, "path", c.AppPath) - var ( - depPath string - err error - ) if c.Vendored { - utils.Logger.Info("Vendor folder detected, scanning for deps in path") - depPath, err = exec.LookPath("dep") - if err != nil { + utils.Logger.Info("Vendor folder detected, for go version") + if runtime.Version()!="" { // Do not halt build unless a new package needs to be imported - utils.Logger.Fatal("Build: `dep` executable not found in PATH, but vendor folder detected." + - "Packages can only be added automatically to the vendor folder using the `dep` tool. " + - "You can install the `dep` tool by doing a `go get -u github.com/golang/dep/cmd/dep`") + utils.Logger.Fatal(`Go version 1.11 or newer is required to build`) } } @@ -200,45 +304,42 @@ func (c *CommandConfig) InitPackageResolver() { c.PackageResolver = func(pkgName string) error { //useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor")) - var getCmd *exec.Cmd + //var getCmd *exec.Cmd utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored) if c.Vendored { - utils.Logger.Info("Using dependency manager to import package", "package", pkgName) - - if depPath == "" { - utils.Logger.Error("Build: Vendor folder found, but the `dep` tool was not found, " + - "if you use a different vendoring (package management) tool please add the following packages by hand, " + - "or install the `dep` tool into your gopath by doing a `go get -u github.com/golang/dep/cmd/dep`. " + - "For more information and usage of the tool please see http://github.com/golang/dep") - utils.Logger.Error("Missing package", "package", pkgName) - return fmt.Errorf("Missing package %s", pkgName) - } - // Check to see if the package exists locally - _, err := build.Import(pkgName, c.AppPath, build.FindOnly) - if err != nil { - getCmd = exec.Command(depPath, "ensure", "-add", pkgName) - } else { - getCmd = exec.Command(depPath, "ensure", "-update", pkgName) - } - - } else { - utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName) - getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName) + goModCmd := exec.Command("go", "mod", "tidy") + utils.CmdInit(goModCmd, c.AppPath) + return nil } - - utils.CmdInit(getCmd, c.AppPath) - utils.Logger.Info("Go get command ", "exec", getCmd.Path, "dir", getCmd.Dir, "args", getCmd.Args, "env", getCmd.Env, "package", pkgName) - output, err := getCmd.CombinedOutput() - if err != nil { - fmt.Printf("Error stack %v\n", logger.NewCallStack()) - utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output)) - } - return err + //utils.Logger.Info("Using dependency manager to import package", "package", pkgName) + // + //// Check to see if the package exists locally + //_, err := build.Import(pkgName, c.AppPath, build.FindOnly) + //if err != nil { + // getCmd = exec.Command(depPath, "ensure", "-add", pkgName) + //} else { + // getCmd = exec.Command(depPath, "ensure", "-update", pkgName) + //} + // + // + //} else { + // utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName) + // getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName) + //} + // + //utils.CmdInit(getCmd, c.AppPath) + //utils.Logger.Info("Go get command ", "exec", getCmd.Path, "dir", getCmd.Dir, "args", getCmd.Args, "env", getCmd.Env, "package", pkgName) + //output, err := getCmd.CombinedOutput() + //if err != nil { + // fmt.Printf("Error stack %v\n", logger.NewCallStack()) + // utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output)) + //} + return nil } } // lookup and set Go related variables -func (c *CommandConfig) InitGoPaths() { +func (c *CommandConfig) InitGoPathsOld() { utils.Logger.Info("InitGoPaths") // lookup go path c.GoPath = build.Default.GOPATH @@ -276,17 +377,21 @@ func (c *CommandConfig) InitGoPaths() { } } - utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) + utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath",bestpath) if len(c.SrcRoot) == 0 && len(bestpath) > 0 { c.SrcRoot = bestpath } // If source root is empty and this isn't a version then skip it if len(c.SrcRoot) == 0 { - if c.Index != VERSION { - utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.") + if c.Index == NEW { + c.SrcRoot = c.New.ImportPath + } else { + if c.Index != VERSION { + utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.") + } + return } - return } // set go src path @@ -299,14 +404,14 @@ func (c *CommandConfig) InitGoPaths() { // Sets the versions on the command config func (c *CommandConfig) SetVersions() (err error) { c.CommandVersion, _ = ParseVersion(cmd.Version) - _, revelPath, err := utils.FindSrcPaths(c.ImportPath, RevelImportPath, c.PackageResolver) + pathMap, err := utils.FindSrcPaths(c.AppPath, []string{RevelImportPath}, c.PackageResolver) if err == nil { - utils.Logger.Info("Fullpath to revel", "dir", revelPath) + utils.Logger.Info("Fullpath to revel", "dir", pathMap[RevelImportPath]) fset := token.NewFileSet() // positions are relative to fset - versionData, err := ioutil.ReadFile(filepath.Join(revelPath, RevelImportPath, "version.go")) + versionData, err := ioutil.ReadFile(filepath.Join(pathMap[RevelImportPath], "version.go")) if err != nil { - utils.Logger.Error("Failed to find Revel version:", "error", err, "path", revelPath) + utils.Logger.Error("Failed to find Revel version:", "error", err, "path", pathMap[RevelImportPath]) } // Parse src but stop after processing the imports. diff --git a/model/revel_container.go b/model/revel_container.go index f15a665..0647208 100644 --- a/model/revel_container.go +++ b/model/revel_container.go @@ -4,13 +4,12 @@ package model import ( "github.com/revel/cmd/utils" "github.com/revel/config" - "go/build" - "errors" "fmt" "path/filepath" "sort" "strings" + "golang.org/x/tools/go/packages" ) type ( @@ -65,7 +64,11 @@ type ( CookieSecure bool // True if cookie is secure SecretStr string // The secret string MimeConfig *config.Context // The mime configuration - ModulePathMap map[string]string // The module path map + ModulePathMap map[string]*ModuleInfo // The module path map + } + ModuleInfo struct { + ImportPath string + Path string } WrappedRevelCallback struct { @@ -96,30 +99,22 @@ var RevelModulesImportPath = "github.com/revel/modules" // This function returns a container object describing the revel application // eventually this type of function will replace the global variables. -func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp *RevelContainer, err error) { - rp = &RevelContainer{ModulePathMap: map[string]string{}} +func NewRevelPaths(mode, importPath, appSrcPath string, callback RevelCallback) (rp *RevelContainer, err error) { + rp = &RevelContainer{ModulePathMap: map[string]*ModuleInfo{}} // Ignore trailing slashes. rp.ImportPath = strings.TrimRight(importPath, "/") - rp.SourcePath = srcPath + rp.SourcePath = appSrcPath rp.RunMode = mode - // If the SourcePath is not specified, find it using build.Import. - var revelSourcePath string // may be different from the app source path - if rp.SourcePath == "" { - rp.SourcePath, revelSourcePath, err = utils.FindSrcPaths(importPath, RevelImportPath, callback.PackageResolver) - if err != nil { - return - } - } else { - // If the SourcePath was specified, assume both Revel and the app are within it. - rp.SourcePath = filepath.Clean(rp.SourcePath) - revelSourcePath = rp.SourcePath + // We always need to determine the paths for files + pathMap, err := utils.FindSrcPaths(appSrcPath, []string{importPath+"/app", RevelImportPath}, callback.PackageResolver) + if err != nil { + return } - + rp.AppPath, rp.RevelPath = pathMap[importPath], pathMap[RevelImportPath] // Setup paths for application - rp.RevelPath = filepath.Join(revelSourcePath, filepath.FromSlash(RevelImportPath)) - rp.BasePath = filepath.Join(rp.SourcePath, filepath.FromSlash(importPath)) - rp.PackageInfo.Vendor = utils.Exists(filepath.Join(rp.BasePath, "vendor")) + rp.BasePath = rp.SourcePath + rp.PackageInfo.Vendor = utils.Exists(filepath.Join(rp.BasePath, "go.mod")) rp.AppPath = filepath.Join(rp.BasePath, "app") // Sanity check , ensure app and conf paths exist @@ -188,6 +183,7 @@ func NewRevelPaths(mode, importPath, srcPath string, callback RevelCallback) (rp rp.SecretStr = rp.Config.StringDefault("app.secret", "") callback.FireEvent(REVEL_BEFORE_MODULES_LOADED, nil) + utils.Logger.Info("Loading modules") if err := rp.loadModules(callback); err != nil { return rp, err } @@ -248,9 +244,10 @@ func (rp *RevelContainer) loadModules(callback RevelCallback) (err error) { // Adds a module paths to the container object func (rp *RevelContainer) addModulePaths(name, importPath, modulePath string) { + utils.Logger.Info("Adding module path","name", name,"import path", importPath,"system path", modulePath) if codePath := filepath.Join(modulePath, "app"); utils.DirExists(codePath) { rp.CodePaths = append(rp.CodePaths, codePath) - rp.ModulePathMap[name] = modulePath + rp.ModulePathMap[name] = &ModuleInfo{importPath, modulePath} if viewsPath := filepath.Join(modulePath, "app", "views"); utils.DirExists(viewsPath) { rp.TemplatePaths = append(rp.TemplatePaths, viewsPath) } @@ -273,13 +270,21 @@ func (rp *RevelContainer) ResolveImportPath(importPath string) (string, error) { if rp.Packaged { return filepath.Join(rp.SourcePath, importPath), nil } + config := &packages.Config{ + Mode: packages.LoadSyntax, + Dir:rp.AppPath, + } - modPkg, err := build.Import(importPath, rp.AppPath, build.FindOnly) + pkgs, err := packages.Load(config, importPath) + if len(pkgs)==0 { + return "", errors.New("No packages found for import " + importPath +" using app path "+ rp.AppPath) + } +// modPkg, err := build.Import(importPath, rp.AppPath, build.FindOnly) if err != nil { return "", err } - if rp.PackageInfo.Vendor && !strings.HasPrefix(modPkg.Dir,rp.BasePath) { - return "", fmt.Errorf("Module %s was found outside of path %s.",importPath, modPkg.Dir) + if len(pkgs[0].GoFiles)>0 { + return filepath.Dir(pkgs[0].GoFiles[0]), nil } - return modPkg.Dir, nil + return pkgs[0].PkgPath, errors.New("No files found in import path " + importPath) } diff --git a/parser/imports.go b/parser/imports.go index 150c6ed..8f40285 100644 --- a/parser/imports.go +++ b/parser/imports.go @@ -42,13 +42,14 @@ func addImports(imports map[string]string, decl ast.Decl, srcDir string) { // 2. Exempt the standard library; their directories always match the package name. // 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly if pkgAlias == "" { + utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH) pkg, err := build.Import(fullPath, srcDir, 0) if err != nil { // We expect this to happen for apps using reverse routing (since we // have not yet generated the routes). Don't log that. if !strings.HasSuffix(fullPath, "/app/routes") { - utils.Logger.Error("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err) + utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err) } continue } else { diff --git a/parser/utils.go b/parser/utils.go new file mode 100644 index 0000000..8239d15 --- /dev/null +++ b/parser/utils.go @@ -0,0 +1,18 @@ +package parser + +import ( + //"golang.org/x/tools/go/packages" + //"github.com/revel/cmd/utils" +) +//import "golang.org/x/tools/go/packages" +// +//func GetPackage(appPath, importPath string) { +// config := &packages.Config{ +// Mode: packages.NeedName | packages.NeedFiles, +// Dir:appPath, +// } +// +// pkgs, err := packages.Load(config, []string{importPath}) +// utils.Logger.Info("Loaded packegs ", "len results", len(pkgs), "error",err) +// +//} diff --git a/parser2/read.go b/parser2/read.go new file mode 100644 index 0000000..ed30a69 --- /dev/null +++ b/parser2/read.go @@ -0,0 +1,123 @@ +package parser2 + +import ( + "go/ast" + "go/token" + + "github.com/revel/cmd/model" + "golang.org/x/tools/go/packages" + "github.com/revel/cmd/utils" + "github.com/pkg/errors" + "golang.org/x/tools/go/ssa/interp/testdata/src/strings" +) +func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.SourceInfo, compileError error) { + utils.Logger.Info("ProcessSource") + // Combine packages for modules and app and revel + allPackages := []string{revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} + for _,module := range revelContainer.ModulePathMap { + allPackages = append(allPackages,module.ImportPath+"/app/controllers/...") + } + + config := &packages.Config{ + Mode: packages.NeedName | packages.NeedFiles | packages.LoadTypes | packages.NeedTypes | packages.NeedSyntax , //| packages.NeedImports | + // packages.NeedTypes, // packages.LoadTypes | packages.NeedSyntax | packages.NeedTypesInfo, + //packages.LoadSyntax | packages.NeedDeps, + Dir:revelContainer.AppPath, + } + utils.Logger.Info("Before ","apppath", config.Dir,"paths",allPackages) + pkgs, err := packages.Load(config, allPackages...) + utils.Logger.Info("***Loaded packegs ", "len results", len(pkgs), "error",err) + // Lets see if we can output all the path names + //packages.Visit(pkgs,func(p *packages.Package) bool{ + // println("Got pre",p.ID) + // return true + //}, func(p *packages.Package) { + //}) + counter := 0 + for _, p := range pkgs { + utils.Logger.Info("Errores","error",p.Errors, "id",p.ID) + //for _,g := range p.GoFiles { + // println("File", g) + //} + //for _, t:= range p.Syntax { + // utils.Logger.Info("File","name",t.Name) + //} + println("package typoe fouhnd ",p.Types.Name()) + imports := map[string]string{} + + for _,s := range p.Syntax { + println("File ",s.Name.Name ) + for _, decl := range file.Decls { + if decl.Tok == token.IMPORT { + } + } + } + //p.Fset.Iterate(func(file *token.File) bool{ + // + // // utils.Logger.Info("Output","Found file", p.ID," AND NAME ", f.Name()) + // // For each declaration in the source file... + // //for _, decl := range file.Decls { + // // addImports(imports, decl, pkgPath) + // //} + // counter ++ + // return true + //}) + } + + err = errors.New("Incompleted") + println("*******************", counter) + utils.Logger.Panic("Not implemented") + return +} + + + +// Add imports to the map from the source dir +func addImports(imports map[string]string, decl ast.Decl, srcDir string) { + genDecl, ok := decl.(*ast.GenDecl) + if !ok { + return + } + + if genDecl.Tok != token.IMPORT { + return + } + + for _, spec := range genDecl.Specs { + importSpec := spec.(*ast.ImportSpec) + var pkgAlias string + if importSpec.Name != nil { + pkgAlias = importSpec.Name.Name + if pkgAlias == "_" { + continue + } + } + quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" + fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes + + // If the package was not aliased (common case), we have to import it + // to see what the package name is. + // TODO: Can improve performance here a lot: + // 1. Do not import everything over and over again. Keep a cache. + // 2. Exempt the standard library; their directories always match the package name. + // 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly + if pkgAlias == "" { + + utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH) + pkg, err := build.Import(fullPath, srcDir, 0) + if err != nil { + // We expect this to happen for apps using reverse routing (since we + // have not yet generated the routes). Don't log that. + if !strings.HasSuffix(fullPath, "/app/routes") { + utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err) + } + continue + } else { + utils.Logger.Debug("Found package in dir", "dir", pkg.Dir, "name", pkg.ImportPath) + } + pkgAlias = pkg.Name + } + + imports[pkgAlias] = fullPath + } +} \ No newline at end of file diff --git a/revel/build.go b/revel/build.go index 352fc0f..e929114 100644 --- a/revel/build.go +++ b/revel/build.go @@ -13,7 +13,6 @@ import ( "github.com/revel/cmd/harness" "github.com/revel/cmd/model" "github.com/revel/cmd/utils" - "go/build" ) var cmdBuild = &Command{ @@ -153,10 +152,10 @@ func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, destPath := filepath.Join(c.Build.TargetPath, "src") // Find all the modules used and copy them over. config := revel_paths.Config.Raw() - modulePaths := make(map[string]string) // import path => filesystem path // We should only copy over the section of options what the build is targeted for // We will default to prod + moduleImportList := []string{} for _, section := range config.Sections() { // If the runmode is defined we will only import modules defined for that run mode if c.Build.Mode != "" && c.Build.Mode != section { @@ -171,14 +170,15 @@ func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, if moduleImportPath == "" { continue } + moduleImportList =append(moduleImportList,moduleImportPath) - modPkg, err := build.Import(moduleImportPath, revel_paths.RevelPath, build.FindOnly) - if err != nil { - utils.Logger.Fatalf("Failed to load module %s (%s): %s", key[len("module."):], c.ImportPath, err) - } - modulePaths[moduleImportPath] = modPkg.Dir } } + modulePaths, err := utils.FindSrcPaths(c.AppPath, moduleImportList, c.PackageResolver) + + if err != nil { + utils.Logger.Fatalf("Failed to load modules ", "error", err) + } // Copy the the paths for each of the modules for importPath, fsPath := range modulePaths { diff --git a/revel/new.go b/revel/new.go index 84f848e..051f0c0 100644 --- a/revel/new.go +++ b/revel/new.go @@ -76,56 +76,15 @@ func newApp(c *model.CommandConfig) (err error) { return utils.NewBuildError("Abort: Unable to create app path.", "path", c.AppPath) } - if c.New.Vendored { - utils.Logger.Info("Creating a new vendor app") - - vendorPath := filepath.Join(c.AppPath, "vendor") - if !utils.DirExists(vendorPath) { - - if err := os.MkdirAll(vendorPath, os.ModePerm); err != nil { - return utils.NewBuildError("Failed to create "+vendorPath, "error", err) - } - } - - // In order for dep to run there needs to be a source file in the folder - tempPath := filepath.Join(c.AppPath, "tmp") - utils.Logger.Info("Checking for temp folder for source code", "path", tempPath) - if !utils.DirExists(tempPath) { - if err := os.MkdirAll(tempPath, os.ModePerm); err != nil { - return utils.NewBuildIfError(err, "Failed to create "+vendorPath) - } - - if err = utils.GenerateTemplate(filepath.Join(tempPath, "main.go"), NEW_MAIN_FILE, nil); err != nil { - return utils.NewBuildIfError(err, "Failed to create main file "+vendorPath) - } - } - - // Create a package template file if it does not exist - packageFile := filepath.Join(c.AppPath, "Gopkg.toml") - utils.Logger.Info("Checking for Gopkg.toml", "path", packageFile) - if !utils.Exists(packageFile) { - utils.Logger.Info("Generating Gopkg.toml", "path", packageFile) - if err := utils.GenerateTemplate(packageFile, VENDOR_GOPKG, nil); err != nil { - return utils.NewBuildIfError(err, "Failed to generate template") - } - } else { - utils.Logger.Info("Package file exists in skeleto, skipping adding") - } - - getCmd := exec.Command("dep", "ensure", "-v") - utils.CmdInit(getCmd, c.AppPath) - - utils.Logger.Info("Exec:", "args", getCmd.Args, "env", getCmd.Env, "workingdir",getCmd.Dir) - getOutput, err := getCmd.CombinedOutput() - if err != nil { - return utils.NewBuildIfError(err, string(getOutput)) - } + if len(c.New.Package)>0 { + c.New.Vendored = true } // checking and setting application if err = setApplicationPath(c); err != nil { return err } + // At this point the versions can be set c.SetVersions() @@ -136,12 +95,8 @@ func newApp(c *model.CommandConfig) (err error) { // Rerun the dep tool if vendored if c.New.Vendored { - getCmd := exec.Command("dep", "ensure", "-v") - utils.CmdInit(getCmd, c.AppPath) - utils.Logger.Info("Exec:", "args", getCmd.Args) - getOutput, err := getCmd.CombinedOutput() - if err != nil { - utils.Logger.Fatal(string(getOutput)) + if err=createModVendor(c); err!=nil { + return } } @@ -156,6 +111,70 @@ func newApp(c *model.CommandConfig) (err error) { return } +func createModVendor(c *model.CommandConfig) (err error) { + + utils.Logger.Info("Creating a new mod app") + goModCmd := exec.Command("go", "mod", "init", filepath.Join(c.New.Package,c.AppName)) + + + utils.CmdInit(goModCmd, c.AppPath) + + utils.Logger.Info("Exec:", "args", goModCmd.Args, "env", goModCmd.Env, "workingdir",goModCmd.Dir) + getOutput, err := goModCmd.CombinedOutput() + if err != nil { + return utils.NewBuildIfError(err, string(getOutput)) + } + return +} + +func createDepVendor(c *model.CommandConfig) (err error) { + + utils.Logger.Info("Creating a new vendor app") + + vendorPath := filepath.Join(c.AppPath, "vendor") + if !utils.DirExists(vendorPath) { + + if err := os.MkdirAll(vendorPath, os.ModePerm); err != nil { + return utils.NewBuildError("Failed to create "+vendorPath, "error", err) + } + } + + // In order for dep to run there needs to be a source file in the folder + tempPath := filepath.Join(c.AppPath, "tmp") + utils.Logger.Info("Checking for temp folder for source code", "path", tempPath) + if !utils.DirExists(tempPath) { + if err := os.MkdirAll(tempPath, os.ModePerm); err != nil { + return utils.NewBuildIfError(err, "Failed to create "+vendorPath) + } + + if err = utils.GenerateTemplate(filepath.Join(tempPath, "main.go"), NEW_MAIN_FILE, nil); err != nil { + return utils.NewBuildIfError(err, "Failed to create main file "+vendorPath) + } + } + + // Create a package template file if it does not exist + packageFile := filepath.Join(c.AppPath, "Gopkg.toml") + utils.Logger.Info("Checking for Gopkg.toml", "path", packageFile) + if !utils.Exists(packageFile) { + utils.Logger.Info("Generating Gopkg.toml", "path", packageFile) + if err := utils.GenerateTemplate(packageFile, VENDOR_GOPKG, nil); err != nil { + return utils.NewBuildIfError(err, "Failed to generate template") + } + } else { + utils.Logger.Info("Package file exists in skeleto, skipping adding") + } + + getCmd := exec.Command("dep", "ensure", "-v") + utils.CmdInit(getCmd, c.AppPath) + + utils.Logger.Info("Exec:", "args", getCmd.Args, "env", getCmd.Env, "workingdir",getCmd.Dir) + getOutput, err := getCmd.CombinedOutput() + if err != nil { + return utils.NewBuildIfError(err, string(getOutput)) + } + return +} + // Used to generate a new secret key const alphaNumeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" diff --git a/revel/new_test.go b/revel/new_test.go index c1d3bca..31aa2b4 100644 --- a/revel/new_test.go +++ b/revel/new_test.go @@ -55,12 +55,12 @@ func TestNewVendor(t *testing.T) { a := assert.New(t) gopath := setup("revel-test-new-vendor", a) precall := func(c *model.CommandConfig) { - c.New.Vendored = true + c.New.DepVendored = true } t.Run("New", func(t *testing.T) { a := assert.New(t) c := newApp("onlyone/v/a", model.NEW, precall, a) - c.New.Vendored = true + c.New.DepVendored = true a.Nil(main.Commands[model.NEW].RunWith(c), "New failed") }) t.Run("Test", func(t *testing.T) { diff --git a/revel/revel.go b/revel/revel.go index dd95b43..1538066 100644 --- a/revel/revel.go +++ b/revel/revel.go @@ -101,7 +101,7 @@ func main() { println("Revel executing:", command.Short) // Setting go paths - c.InitGoPaths() + // c.InitGoPaths() // Setup package resolver c.InitPackageResolver() diff --git a/revel/run.go b/revel/run.go index c7bd5ee..a149afd 100644 --- a/revel/run.go +++ b/revel/run.go @@ -126,7 +126,7 @@ func runApp(c *model.CommandConfig) (err error) { c.Run.Mode = "dev" } - revel_path, err := model.NewRevelPaths(c.Run.Mode, c.ImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver)) + revel_path, err := model.NewRevelPaths(c.Run.Mode, c.ImportPath, c.AppPath, model.NewWrappedRevelCallback(nil, c.PackageResolver)) if err != nil { return utils.NewBuildIfError(err, "Revel paths") } diff --git a/revel/test.go b/revel/test.go index d1ec415..8465f6b 100644 --- a/revel/test.go +++ b/revel/test.go @@ -258,7 +258,7 @@ func getTestsList(baseURL string) (*[]tests.TestSuiteDesc, error) { func runTestSuites(paths *model.RevelContainer, baseURL, resultPath string, testSuites *[]tests.TestSuiteDesc) (*[]tests.TestSuiteResult, bool) { // We can determine the testsuite location by finding the test module and extracting the data from it - resultFilePath := filepath.Join(paths.ModulePathMap["testrunner"], "app", "views", "TestRunner/SuiteResult.html") + resultFilePath := filepath.Join(paths.ModulePathMap["testrunner"].Path, "app", "views", "TestRunner/SuiteResult.html") var ( overallSuccess = true diff --git a/revel/version.go b/revel/version.go index 1000693..af0a43e 100644 --- a/revel/version.go +++ b/revel/version.go @@ -77,7 +77,7 @@ func (v *VersionCommand) RunWith(c *model.CommandConfig) (err error) { versionInfo, needsUpdates = v.doRepoCheck(x==0) } - fmt.Println(versionInfo) + fmt.Printf("%s\n\nGo Location:%s\n\n",versionInfo,c.GoCmd) cmd := exec.Command(c.GoCmd, "version") cmd.Stdout = os.Stdout if e := cmd.Start(); e != nil { @@ -234,28 +234,20 @@ func (v *VersionCommand) updateLocalVersions() { v.cmdVersion.BuildDate = cmd.BuildDate v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion - var modulePath, revelPath string - _, revelPath, err := utils.FindSrcPaths(v.Command.ImportPath, model.RevelImportPath, v.Command.PackageResolver) + pathMap, err := utils.FindSrcPaths(v.Command.AppPath,[]string{model.RevelImportPath,model.RevelModulesImportPath}, v.Command.PackageResolver) if err != nil { - utils.Logger.Warn("Unable to extract version information from Revel library", "error,err") + utils.Logger.Warn("Unable to extract version information from Revel library", "path",pathMap[model.RevelImportPath], "error",err) return } - revelPath = revelPath + model.RevelImportPath - utils.Logger.Info("Fullpath to revel", "dir", revelPath) - v.revelVersion, err = v.versionFromFilepath(revelPath) + utils.Logger.Info("Fullpath to revel", "dir", pathMap[model.RevelModulesImportPath]) + v.revelVersion, err = v.versionFromFilepath(pathMap[model.RevelModulesImportPath]) if err != nil { utils.Logger.Warn("Unable to extract version information from Revel", "error,err") } - _, modulePath, err = utils.FindSrcPaths(v.Command.ImportPath, model.RevelModulesImportPath, v.Command.PackageResolver) + v.modulesVersion, err = v.versionFromFilepath(pathMap[model.RevelModulesImportPath]) if err != nil { - utils.Logger.Warn("Unable to extract version information from Revel library", "error,err") - return - } - modulePath = modulePath + model.RevelModulesImportPath - v.modulesVersion, err = v.versionFromFilepath(modulePath) - if err != nil { - utils.Logger.Warn("Unable to extract version information from Revel Modules", "error", err) + utils.Logger.Warn("Unable to extract version information from Revel Modules", "path", pathMap[model.RevelModulesImportPath], "error", err) } return diff --git a/utils/file.go b/utils/file.go index cb714ee..c070c35 100644 --- a/utils/file.go +++ b/utils/file.go @@ -6,13 +6,13 @@ import ( "compress/gzip" "errors" "fmt" - "go/build" "html/template" "io" "io/ioutil" "os" "path/filepath" "strings" + "golang.org/x/tools/go/packages" ) // DirExists returns true if the given path exists and is a directory. @@ -320,49 +320,63 @@ func Empty(dirname string) bool { } // Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory -func FindSrcPaths(appImportPath, revelImportPath string, packageResolver func(pkgName string) error) (appSourcePath, revelSourcePath string, err error) { - var ( - gopaths = filepath.SplitList(build.Default.GOPATH) - goroot = build.Default.GOROOT - ) - - if len(gopaths) == 0 { - err = errors.New("GOPATH environment variable is not set. " + - "Please refer to http://golang.org/doc/code.html to configure your Go environment.") - return - } - - if ContainsString(gopaths, goroot) { - err = fmt.Errorf("GOPATH (%s) must not include your GOROOT (%s). "+ - "Please refer to http://golang.org/doc/code.html to configure your Go environment. ", - build.Default.GOPATH, goroot) - return - - } - - appPkgDir := "" - appPkgSrcDir := "" - if len(appImportPath)>0 { - Logger.Info("Seeking app package","app",appImportPath) - appPkg, err := build.Import(appImportPath, "", build.FindOnly) - if err != nil { - err = fmt.Errorf("Failed to import " + appImportPath + " with error %s", err.Error()) - return "","",err +func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkgName string) error) (sourcePathsmap map[string]string, err error) { + sourcePathsmap, missingList,err := findSrcPaths(appPath,packageList) + if err != nil && packageResolver != nil { + for _, item := range missingList { + if err = packageResolver(item); err != nil { + return + } } - appPkgDir,appPkgSrcDir =appPkg.Dir, appPkg.SrcRoot + sourcePathsmap,missingList,err = findSrcPaths(appPath,packageList) } - Logger.Info("Seeking remote package","using",appImportPath, "remote",revelImportPath) - revelPkg, err := build.Default.Import(revelImportPath, appPkgDir, build.FindOnly) - if err != nil { - Logger.Info("Resolved called Seeking remote package","using",appImportPath, "remote",revelImportPath) - packageResolver(revelImportPath) - revelPkg, err = build.Import(revelImportPath, appPkgDir, build.FindOnly) - if err != nil { - err = fmt.Errorf("Failed to find Revel with error: %s", err.Error()) - return + if err!=nil && len(missingList)>0 { + for _, missing := range missingList { + Logger.Error("Unable to import this package", "package", missing) } } - revelSourcePath, appSourcePath = revelPkg.Dir[:len(revelPkg.Dir)-len(revelImportPath)], appPkgSrcDir + return +} +var NO_APP_FOUND = errors.New("No app found") +var NO_REVEL_FOUND = errors.New("No revel found") + +// Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory +func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[string]string, missingList[] string, err error) { + // Use packages to fetch + // by not specifying env, we will use the default env + config := &packages.Config{ + Mode: packages.NeedName | packages.NeedFiles, + Dir:appPath, + } + sourcePathsmap = map[string]string{} + + pkgs, err := packages.Load(config, packagesList...) + Logger.Info("Loaded packegs ", "len results", len(pkgs), "error",err) + for _, packageName := range packagesList { + found := false + log:= Logger.New("seeking",packageName) + for _, pck := range pkgs { + log.Info("Found package","package",pck.ID) + if pck.ID == packageName { + if pck.Errors!=nil && len(pck.Errors)>0 { + Logger.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID,"errors",pck.Errors) + + } + //a,_ := pck.MarshalJSON() + Logger.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID) + sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0]) + found = true + } + } + if !found { + if packageName == "github.com/revel/revel" { + err = NO_REVEL_FOUND + } else { + err = NO_APP_FOUND + } + missingList = append(missingList,packageName) + } + } return } From 9a9511d28f9ced6aeb7cec6c734a93090f8206b9 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sat, 25 Apr 2020 09:18:29 -0700 Subject: [PATCH 02/18] Updated so revel new works and revel run starts parsing the source. --- logger/revel_logger.go | 2 +- model/command_config.go | 41 ++++++-------- parser2/read.go | 116 ++++++++++++++++++++-------------------- revel/new.go | 24 +++++---- revel/revel.go | 11 ++-- revel/run.go | 4 +- 6 files changed, 97 insertions(+), 101 deletions(-) diff --git a/logger/revel_logger.go b/logger/revel_logger.go index b3a6f86..3010d49 100644 --- a/logger/revel_logger.go +++ b/logger/revel_logger.go @@ -81,7 +81,7 @@ func (rl *RevelLogger) SetStackDepth(amount int) MultiLogger { // Create a new logger func New(ctx ...interface{}) MultiLogger { r := &RevelLogger{Logger: log15.New(ctx...)} - r.SetStackDepth(1) + r.SetStackDepth(0) return r } diff --git a/model/command_config.go b/model/command_config.go index 6cbbe76..ef1fd9a 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -14,7 +14,6 @@ import ( "os/exec" "path/filepath" "strings" - "runtime" ) // The constants @@ -54,7 +53,7 @@ type ( ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` - Vendored bool `short:"V" long:"vendor" description:"True if project should contain a vendor folder to be initialized. Creates the vendor folder and the 'Gopkg.toml' file in the root"` + NotVendored bool `short:"V" long:"vendor" description:"True if project should not be configured with a go.mod"` Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` } `command:"new"` // The build command @@ -105,19 +104,19 @@ func (c *CommandConfig) UpdateImportPath() error { importPath = c.New.ImportPath case RUN: importPath = c.Run.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) case BUILD: importPath = c.Build.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) case PACKAGE: importPath = c.Package.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) case CLEAN: importPath = c.Clean.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) case TEST: importPath = c.Test.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"src","go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) case VERSION: importPath = c.Version.ImportPath required = false @@ -180,7 +179,8 @@ func (c *CommandConfig) UpdateImportPath() error { } func (c *CommandConfig) initAppFolder() (err error) { - utils.Logger.Info("initAppFolder") + utils.Logger.Info("initAppFolder","vendored", c.Vendored) + // check for go executable c.GoCmd, err = exec.LookPath("go") if err != nil { @@ -227,7 +227,7 @@ func (c *CommandConfig) initAppFolder() (err error) { } } - utils.Logger.Fatal("Trying to set path based on gopath") + utils.Logger.Debug("Trying to set path based on gopath") // lookup go path c.GoPath = build.Default.GOPATH if c.GoPath == "" { @@ -275,31 +275,22 @@ func (c *CommandConfig) initAppFolder() (err error) { } // set go src path - c.SrcRoot = filepath.Join(c.SrcRoot, "src") + if c.Vendored { + c.AppPath = c.SrcRoot - c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath)) + } else { + c.SrcRoot = filepath.Join(c.SrcRoot, "src") + + c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath)) + } utils.Logger.Info("Set application path", "path", c.AppPath) return nil } // Used to initialize the package resolver func (c *CommandConfig) InitPackageResolver() { - c.Vendored = utils.DirExists(filepath.Join(c.AppPath, "go.mod")) - if c.Index == NEW && c.New.Vendored { - c.Vendored = true - } - utils.Logger.Info("InitPackageResolver", "useVendor", c.Vendored, "path", c.AppPath) - - if c.Vendored { - utils.Logger.Info("Vendor folder detected, for go version") - if runtime.Version()!="" { - // Do not halt build unless a new package needs to be imported - utils.Logger.Fatal(`Go version 1.11 or newer is required to build`) - } - } - // This should get called when needed c.PackageResolver = func(pkgName string) error { //useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor")) diff --git a/parser2/read.go b/parser2/read.go index ed30a69..3e1e738 100644 --- a/parser2/read.go +++ b/parser2/read.go @@ -1,14 +1,14 @@ package parser2 import ( - "go/ast" - "go/token" + //"go/ast" + //"go/token" "github.com/revel/cmd/model" "golang.org/x/tools/go/packages" "github.com/revel/cmd/utils" - "github.com/pkg/errors" - "golang.org/x/tools/go/ssa/interp/testdata/src/strings" + "errors" + ) func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.SourceInfo, compileError error) { utils.Logger.Info("ProcessSource") @@ -43,13 +43,13 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour // utils.Logger.Info("File","name",t.Name) //} println("package typoe fouhnd ",p.Types.Name()) - imports := map[string]string{} + //imports := map[string]string{} for _,s := range p.Syntax { println("File ",s.Name.Name ) - for _, decl := range file.Decls { - if decl.Tok == token.IMPORT { - } + //for _, decl := range s.Decls { + // if decl.Tok == token.IMPORT { + // } } } //p.Fset.Iterate(func(file *token.File) bool{ @@ -62,9 +62,9 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour // counter ++ // return true //}) - } + //} - err = errors.New("Incompleted") +compileError = errors.New("Incompleted") println("*******************", counter) utils.Logger.Panic("Not implemented") return @@ -73,51 +73,51 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour // Add imports to the map from the source dir -func addImports(imports map[string]string, decl ast.Decl, srcDir string) { - genDecl, ok := decl.(*ast.GenDecl) - if !ok { - return - } - - if genDecl.Tok != token.IMPORT { - return - } - - for _, spec := range genDecl.Specs { - importSpec := spec.(*ast.ImportSpec) - var pkgAlias string - if importSpec.Name != nil { - pkgAlias = importSpec.Name.Name - if pkgAlias == "_" { - continue - } - } - quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" - fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes - - // If the package was not aliased (common case), we have to import it - // to see what the package name is. - // TODO: Can improve performance here a lot: - // 1. Do not import everything over and over again. Keep a cache. - // 2. Exempt the standard library; their directories always match the package name. - // 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly - if pkgAlias == "" { - - utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH) - pkg, err := build.Import(fullPath, srcDir, 0) - if err != nil { - // We expect this to happen for apps using reverse routing (since we - // have not yet generated the routes). Don't log that. - if !strings.HasSuffix(fullPath, "/app/routes") { - utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err) - } - continue - } else { - utils.Logger.Debug("Found package in dir", "dir", pkg.Dir, "name", pkg.ImportPath) - } - pkgAlias = pkg.Name - } - - imports[pkgAlias] = fullPath - } -} \ No newline at end of file +//func addImports(imports map[string]string, decl ast.Decl, srcDir string) { +// genDecl, ok := decl.(*ast.GenDecl) +// if !ok { +// return +// } +// +// if genDecl.Tok != token.IMPORT { +// return +// } +// +// for _, spec := range genDecl.Specs { +// importSpec := spec.(*ast.ImportSpec) +// var pkgAlias string +// if importSpec.Name != nil { +// pkgAlias = importSpec.Name.Name +// if pkgAlias == "_" { +// continue +// } +// } +// quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" +// fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes +// +// // If the package was not aliased (common case), we have to import it +// // to see what the package name is. +// // TODO: Can improve performance here a lot: +// // 1. Do not import everything over and over again. Keep a cache. +// // 2. Exempt the standard library; their directories always match the package name. +// // 3. Can use build.FindOnly and then use parser.ParseDir with mode PackageClauseOnly +// if pkgAlias == "" { +// +// utils.Logger.Debug("Reading from build", "path", fullPath, "srcPath", srcDir, "gopath", build.Default.GOPATH) +// pkg, err := build.Import(fullPath, srcDir, 0) +// if err != nil { +// // We expect this to happen for apps using reverse routing (since we +// // have not yet generated the routes). Don't log that. +// if !strings.HasSuffix(fullPath, "/app/routes") { +// utils.Logger.Warn("Could not find import:", "path", fullPath, "srcPath", srcDir, "error", err) +// } +// continue +// } else { +// utils.Logger.Debug("Found package in dir", "dir", pkg.Dir, "name", pkg.ImportPath) +// } +// pkgAlias = pkg.Name +// } +// +// imports[pkgAlias] = fullPath +// } +//} \ No newline at end of file diff --git a/revel/new.go b/revel/new.go index 051f0c0..ae8941f 100644 --- a/revel/new.go +++ b/revel/new.go @@ -46,14 +46,23 @@ func init() { // Called when unable to parse the command line automatically and assumes an old launch func updateNewConfig(c *model.CommandConfig, args []string) bool { c.Index = model.NEW + if len(c.New.Package)>0 { + c.New.NotVendored = false + } + c.Vendored = !c.New.NotVendored + if len(args) == 0 { - fmt.Fprintf(os.Stderr, cmdNew.Long) - return false + if len(c.New.ImportPath)==0 { + fmt.Fprintf(os.Stderr, cmdNew.Long) + return false + } + return true } c.New.ImportPath = args[0] if len(args) > 1 { c.New.SkeletonPath = args[1] } + return true } @@ -76,10 +85,6 @@ func newApp(c *model.CommandConfig) (err error) { return utils.NewBuildError("Abort: Unable to create app path.", "path", c.AppPath) } - if len(c.New.Package)>0 { - c.New.Vendored = true - } - // checking and setting application if err = setApplicationPath(c); err != nil { return err @@ -93,8 +98,9 @@ func newApp(c *model.CommandConfig) (err error) { return } - // Rerun the dep tool if vendored - if c.New.Vendored { + // Run the vendor tool if needed + println("********** here",c.Vendored) + if c.Vendored { if err=createModVendor(c); err!=nil { return } @@ -199,7 +205,7 @@ func setApplicationPath(c *model.CommandConfig) (err error) { } // If we are running a vendored version of Revel we do not need to check for it. - if !c.New.Vendored { + if !c.Vendored { _, err = build.Import(model.RevelImportPath, "", build.FindOnly) if err != nil { //// Go get the revel project diff --git a/revel/revel.go b/revel/revel.go index 1538066..c783e4e 100644 --- a/revel/revel.go +++ b/revel/revel.go @@ -142,13 +142,10 @@ func ParseArgs(c *model.CommandConfig, parser *flags.Parser, args []string) (err } } - if len(extraArgs) > 0 { - utils.Logger.Info("Found additional arguements, setting them") - if !Commands[c.Index].UpdateConfig(c, extraArgs) { - buffer := &bytes.Buffer{} - parser.WriteHelp(buffer) - err = fmt.Errorf("Invalid command line arguements %v\n%s", extraArgs, buffer.String()) - } + if !Commands[c.Index].UpdateConfig(c, extraArgs) { + buffer := &bytes.Buffer{} + parser.WriteHelp(buffer) + err = fmt.Errorf("Invalid command line arguements %v\n%s", extraArgs, buffer.String()) } return diff --git a/revel/run.go b/revel/run.go index a149afd..adce55c 100644 --- a/revel/run.go +++ b/revel/run.go @@ -106,7 +106,9 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool { } case 0: // Attempt to set the import path to the current working director. - c.Run.ImportPath,_ = os.Getwd() + if c.Run.ImportPath=="" { + c.Run.ImportPath, _ = os.Getwd() + } } c.Index = model.RUN return true From 548cbc1764b3d4a3b98dcccb227825aa8456f877 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sat, 25 Apr 2020 15:32:29 -0700 Subject: [PATCH 03/18] Upatede Error type to SourceError Added processor object to code Verified compile errors appearing Signed-off-by: notzippy@gmail.com --- harness/build.go | 6 +- harness/harness.go | 16 +-- parser/reflect.go | 2 +- parser/utils.go | 18 ---- parser2/read.go | 252 +++++++++++++++++++++++++++++++++---------- tests/testrunner.go | 2 +- utils/build_error.go | 59 ++++++++++ utils/error.go | 12 +-- utils/file.go | 2 +- watcher/watcher.go | 12 +-- 10 files changed, 282 insertions(+), 99 deletions(-) delete mode 100644 parser/utils.go diff --git a/harness/build.go b/harness/build.go index b8bc7f9..51adb64 100644 --- a/harness/build.go +++ b/harness/build.go @@ -388,7 +388,7 @@ func containsValue(m map[string]string, val string) bool { // Parse the output of the "go build" command. // Return a detailed Error. -func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error { +func newCompileError(paths *model.RevelContainer, output []byte) *utils.SourceError { errorMatch := regexp.MustCompile(`(?m)^([^:#]+):(\d+):(\d+:)? (.*)$`). FindSubmatch(output) if errorMatch == nil { @@ -396,7 +396,7 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error { if errorMatch == nil { utils.Logger.Error("Failed to parse build errors", "error", string(output)) - return &utils.Error{ + return &utils.SourceError{ SourceType: "Go code", Title: "Go Compilation Error", Description: "See console for build error.", @@ -429,7 +429,7 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.Error { absFilename = findInPaths(relFilename) line, _ = strconv.Atoi(string(errorMatch[2])) description = string(errorMatch[4]) - compileError = &utils.Error{ + compileError = &utils.SourceError{ SourceType: "Go code", Title: "Go Compilation Error", Path: relFilename, diff --git a/harness/harness.go b/harness/harness.go index 546016e..bdf8002 100644 --- a/harness/harness.go +++ b/harness/harness.go @@ -89,12 +89,12 @@ func (h *Harness) renderError(iw http.ResponseWriter, ir *http.Request, err erro fmt.Fprintf(iw, "An error ocurred %s", err.Error()) return } - var revelError *utils.Error + var revelError *utils.SourceError switch e := err.(type) { - case *utils.Error: + case *utils.SourceError: revelError = e case error: - revelError = &utils.Error{ + revelError = &utils.SourceError{ Title: "Server Error", Description: e.Error(), } @@ -199,7 +199,7 @@ func NewHarness(c *model.CommandConfig, paths *model.RevelContainer, runMode str // Refresh method rebuilds the Revel application and run it on the given port. // called by the watcher -func (h *Harness) Refresh() (err *utils.Error) { +func (h *Harness) Refresh() (err *utils.SourceError) { // Allow only one thread to rebuild the process // If multiple requests to rebuild are queued only the last one is executed on // So before a build is started we wait for a second to determine if @@ -217,10 +217,10 @@ func (h *Harness) Refresh() (err *utils.Error) { h.app, newErr = Build(h.config, h.paths) if newErr != nil { utils.Logger.Error("Build detected an error", "error", newErr) - if castErr, ok := newErr.(*utils.Error); ok { + if castErr, ok := newErr.(*utils.SourceError); ok { return castErr } - err = &utils.Error{ + err = &utils.SourceError{ Title: "App failed to start up", Description: err.Error(), } @@ -231,10 +231,10 @@ func (h *Harness) Refresh() (err *utils.Error) { h.app.Port = h.port if err2 := h.app.Cmd(h.runMode).Start(h.config); err2 != nil { utils.Logger.Error("Could not start application", "error", err2) - if err,k :=err2.(*utils.Error);k { + if err,k :=err2.(*utils.SourceError);k { return err } - return &utils.Error{ + return &utils.SourceError{ Title: "App failed to start up", Description: err2.Error(), } diff --git a/parser/reflect.go b/parser/reflect.go index b4390f2..212e14e 100644 --- a/parser/reflect.go +++ b/parser/reflect.go @@ -85,7 +85,7 @@ func (pc *processContainer) processPath(path string, info os.FileInfo, err error if err != nil { if errList, ok := err.(scanner.ErrorList); ok { var pos = errList[0].Pos - newError := &utils.Error{ + newError := &utils.SourceError{ SourceType: ".go source", Title: "Go Compilation Error", Path: pos.Filename, diff --git a/parser/utils.go b/parser/utils.go deleted file mode 100644 index 8239d15..0000000 --- a/parser/utils.go +++ /dev/null @@ -1,18 +0,0 @@ -package parser - -import ( - //"golang.org/x/tools/go/packages" - //"github.com/revel/cmd/utils" -) -//import "golang.org/x/tools/go/packages" -// -//func GetPackage(appPath, importPath string) { -// config := &packages.Config{ -// Mode: packages.NeedName | packages.NeedFiles, -// Dir:appPath, -// } -// -// pkgs, err := packages.Load(config, []string{importPath}) -// utils.Logger.Info("Loaded packegs ", "len results", len(pkgs), "error",err) -// -//} diff --git a/parser2/read.go b/parser2/read.go index 3e1e738..f1ed059 100644 --- a/parser2/read.go +++ b/parser2/read.go @@ -1,76 +1,218 @@ package parser2 import ( - //"go/ast" - //"go/token" + "go/ast" + "go/token" "github.com/revel/cmd/model" "golang.org/x/tools/go/packages" "github.com/revel/cmd/utils" "errors" + "fmt" + "strings" + "github.com/revel/cmd/logger" + +) +type ( + SourceProcessor struct { + revelContainer *model.RevelContainer + log logger.MultiLogger + packageList []*packages.Package + importMap map[string]string + } ) func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.SourceInfo, compileError error) { utils.Logger.Info("ProcessSource") - // Combine packages for modules and app and revel - allPackages := []string{revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} - for _,module := range revelContainer.ModulePathMap { - allPackages = append(allPackages,module.ImportPath+"/app/controllers/...") - } - - config := &packages.Config{ - Mode: packages.NeedName | packages.NeedFiles | packages.LoadTypes | packages.NeedTypes | packages.NeedSyntax , //| packages.NeedImports | - // packages.NeedTypes, // packages.LoadTypes | packages.NeedSyntax | packages.NeedTypesInfo, - //packages.LoadSyntax | packages.NeedDeps, - Dir:revelContainer.AppPath, - } - utils.Logger.Info("Before ","apppath", config.Dir,"paths",allPackages) - pkgs, err := packages.Load(config, allPackages...) - utils.Logger.Info("***Loaded packegs ", "len results", len(pkgs), "error",err) - // Lets see if we can output all the path names - //packages.Visit(pkgs,func(p *packages.Package) bool{ - // println("Got pre",p.ID) - // return true - //}, func(p *packages.Package) { - //}) - counter := 0 - for _, p := range pkgs { - utils.Logger.Info("Errores","error",p.Errors, "id",p.ID) - //for _,g := range p.GoFiles { - // println("File", g) - //} - //for _, t:= range p.Syntax { - // utils.Logger.Info("File","name",t.Name) - //} - println("package typoe fouhnd ",p.Types.Name()) - //imports := map[string]string{} - - for _,s := range p.Syntax { - println("File ",s.Name.Name ) - //for _, decl := range s.Decls { - // if decl.Tok == token.IMPORT { - // } - } - } - //p.Fset.Iterate(func(file *token.File) bool{ - // - // // utils.Logger.Info("Output","Found file", p.ID," AND NAME ", f.Name()) - // // For each declaration in the source file... - // //for _, decl := range file.Decls { - // // addImports(imports, decl, pkgPath) - // //} - // counter ++ - // return true - //}) + processor := NewSourceProcessor(revelContainer) + sourceInfo, compileError = processor.parse() + fmt.Printf("From parsers \n%v\n%v\n",sourceInfo,compileError) + //// Combine packages for modules and app and revel + //allPackages := []string{revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} + //for _,module := range revelContainer.ModulePathMap { + // allPackages = append(allPackages,module.ImportPath+"/app/controllers/...") //} - -compileError = errors.New("Incompleted") - println("*******************", counter) + //allPackages = []string{revelContainer.ImportPath+"/app/controllers/..."} + // + //config := &packages.Config{ + // // ode: packages.NeedSyntax | packages.NeedCompiledGoFiles, + // Mode: packages.NeedTypes | packages.NeedSyntax , + // //Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | + // // packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | + // // packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | + // // packages.NeedTypesSizes, + // + // //Mode: packages.NeedName | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedFiles | + // // packages.NeedCompiledGoFiles | packages.NeedTypesSizes | + // // packages.NeedSyntax | packages.NeedCompiledGoFiles , + // //Mode: packages.NeedSyntax | packages.NeedCompiledGoFiles | packages.NeedName | packages.NeedFiles | + // // packages.LoadTypes | packages.NeedTypes | packages.NeedDeps, //, // | + // // packages.NeedTypes, // packages.LoadTypes | packages.NeedSyntax | packages.NeedTypesInfo, + // //packages.LoadSyntax | packages.NeedDeps, + // Dir:revelContainer.AppPath, + //} + //utils.Logger.Info("Before ","apppath", config.Dir,"paths",allPackages) + //pkgs, err := packages.Load(config, allPackages...) + //utils.Logger.Info("***Loaded packegs ", "len results", len(pkgs), "error",err) + //// Lets see if we can output all the path names + ////packages.Visit(pkgs,func(p *packages.Package) bool{ + //// println("Got pre",p.ID) + //// return true + ////}, func(p *packages.Package) { + ////}) + //counter := 0 + //for _, p := range pkgs { + // utils.Logger.Info("Errores","error",p.Errors, "id",p.ID) + // //for _,g := range p.GoFiles { + // // println("File", g) + // //} + // //for _, t:= range p.Syntax { + // // utils.Logger.Info("File","name",t.Name) + // //} + // //println("package typoe fouhnd ",p.Types.Name()) + // //imports := map[string]string{} + // + // for _,s := range p.Syntax { + // println("File ",s.Name.Name ) + // for _, decl := range s.Decls { + // genDecl, ok := decl.(*ast.GenDecl) + // if !ok { + // continue + // } + // + // if genDecl.Tok == token.IMPORT { + // for _, spec := range genDecl.Specs { + // importSpec := spec.(*ast.ImportSpec) + // fmt.Printf("*** import specification %#v\n", importSpec) + // var pkgAlias string + // if importSpec.Name != nil { + // pkgAlias = importSpec.Name.Name + // if pkgAlias == "_" { + // continue + // } + // } + // quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" + // fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes + // if pkgAlias == "" { + // pkgAlias = fullPath + // if index:=strings.LastIndex(pkgAlias,"/");index>0 { + // pkgAlias = pkgAlias[index+1:] + // } + // } + // //imports[pkgAlias] = fullPath + // println("Package ", pkgAlias, "fullpath", fullPath) + // } + // } + // } + // } + // } + // //p.Fset.Iterate(func(file *token.File) bool{ + // // + // // // utils.Logger.Info("Output","Found file", p.ID," AND NAME ", f.Name()) + // // // For each declaration in the source file... + // // //for _, decl := range file.Decls { + // // // addImports(imports, decl, pkgPath) + // // //} + // // counter ++ + // // return true + // //}) + ////} +if false { + compileError = errors.New("Incompleted") utils.Logger.Panic("Not implemented") +} return } +func NewSourceProcessor(revelContainer *model.RevelContainer) *SourceProcessor { + return &SourceProcessor{revelContainer:revelContainer, log:utils.Logger.New("parser","SourceProcessor")} +} +func (s *SourceProcessor) parse() (sourceInfo *model.SourceInfo, compileError error) { + if compileError=s.addPackages();compileError!=nil { + return + } + if compileError = s.addImportMap();compileError!=nil { + return + } + return +} +func (s *SourceProcessor) addPackages() (err error) { + allPackages := []string{s.revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} + for _,module := range s.revelContainer.ModulePathMap { + allPackages = append(allPackages,module.ImportPath+"/app/controllers/...") + } + allPackages = []string{s.revelContainer.ImportPath+"/app/controllers/..."} + + config := &packages.Config{ + // ode: packages.NeedSyntax | packages.NeedCompiledGoFiles, + Mode: packages.NeedTypes | packages.NeedSyntax , + //Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | + // packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | + // packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | + // packages.NeedTypesSizes, + + //Mode: packages.NeedName | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedFiles | + // packages.NeedCompiledGoFiles | packages.NeedTypesSizes | + // packages.NeedSyntax | packages.NeedCompiledGoFiles , + //Mode: packages.NeedSyntax | packages.NeedCompiledGoFiles | packages.NeedName | packages.NeedFiles | + // packages.LoadTypes | packages.NeedTypes | packages.NeedDeps, //, // | + // packages.NeedTypes, // packages.LoadTypes | packages.NeedSyntax | packages.NeedTypesInfo, + //packages.LoadSyntax | packages.NeedDeps, + Dir:s.revelContainer.AppPath, + } + s.packageList, err = packages.Load(config, allPackages...) + s.log.Info("***Loaded packegs ", "len results", len(s.packageList), "error",err) + return +} +func (s *SourceProcessor) addImportMap() (err error) { + s.importMap = map[string]string{} + for _, p := range s.packageList { + if len(p.Errors)>0 { + // Generate a compile error + for _,e:=range p.Errors { + err = utils.NewCompileError("","",e) + } + + } + utils.Logger.Info("Errores","error",p.Errors, "id",p.ID) + + for _,tree := range p.Syntax { + println("File ",tree.Name.Name ) + for _, decl := range tree.Decls { + genDecl, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + + if genDecl.Tok == token.IMPORT { + for _, spec := range genDecl.Specs { + importSpec := spec.(*ast.ImportSpec) + fmt.Printf("*** import specification %#v\n", importSpec) + var pkgAlias string + if importSpec.Name != nil { + pkgAlias = importSpec.Name.Name + if pkgAlias == "_" { + continue + } + } + quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" + fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes + if pkgAlias == "" { + pkgAlias = fullPath + if index:=strings.LastIndex(pkgAlias,"/");index>0 { + pkgAlias = pkgAlias[index+1:] + } + } + s.importMap[pkgAlias] = fullPath + println("Package ", pkgAlias, "fullpath", fullPath) + } + } + } + } + } + return +} // Add imports to the map from the source dir //func addImports(imports map[string]string, decl ast.Decl, srcDir string) { diff --git a/tests/testrunner.go b/tests/testrunner.go index 6117873..a2fb9bd 100644 --- a/tests/testrunner.go +++ b/tests/testrunner.go @@ -107,7 +107,7 @@ func describeSuite(testSuite interface{}) TestSuiteDesc { } // errorSummary gets an error and returns its summary in human readable format. -func errorSummary(err *utils.Error) (message string) { +func errorSummary(err *utils.SourceError) (message string) { expectedPrefix := "(expected)" actualPrefix := "(actual)" errDesc := err.Description diff --git a/utils/build_error.go b/utils/build_error.go index 6412bbb..8655a96 100644 --- a/utils/build_error.go +++ b/utils/build_error.go @@ -3,6 +3,8 @@ package utils import ( "fmt" "github.com/revel/cmd/logger" + "strconv" + "regexp" ) type ( @@ -43,3 +45,60 @@ func NewBuildIfError(err error, message string, args ...interface{}) (b error) { func (b *BuildError) Error() string { return fmt.Sprint(b.Message, b.Args) } + +// Parse the output of the "go build" command. +// Return a detailed Error. +func NewCompileError(importPath, errorLink string, error error) *SourceError { + // Get the stack from the error + + errorMatch := regexp.MustCompile(`(?m)^([^:#]+):(\d+):(\d+:)? (.*)$`). + FindSubmatch([]byte(error.Error())) + if errorMatch == nil { + errorMatch = regexp.MustCompile(`(?m)^(.*?):(\d+):\s(.*?)$`).FindSubmatch([]byte(error.Error())) + + if errorMatch == nil { + Logger.Error("Failed to parse build errors", "error", error) + return &SourceError{ + SourceType: "Go code", + Title: "Go Compilation Error", + Description: "See console for build error.", + } + } + + errorMatch = append(errorMatch, errorMatch[3]) + + Logger.Error("Build errors", "errors", error) + } + + + // Read the source for the offending file. + var ( + relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go" + absFilename = relFilename + line, _ = strconv.Atoi(string(errorMatch[2])) + description = string(errorMatch[4]) + compileError = &SourceError{ + SourceType: "Go code", + Title: "Go Compilation Error", + Path: relFilename, + Description: description, + Line: line, + } + ) + + // errorLink := paths.Config.StringDefault("error.link", "") + + if errorLink != "" { + compileError.SetLink(errorLink) + } + + fileStr, err := ReadLines(absFilename) + if err != nil { + compileError.MetaError = absFilename + ": " + err.Error() + Logger.Info("Unable to readlines "+compileError.MetaError, "error", err) + return compileError + } + + compileError.SourceLines = fileStr + return compileError +} \ No newline at end of file diff --git a/utils/error.go b/utils/error.go index e03e1f3..1146d72 100644 --- a/utils/error.go +++ b/utils/error.go @@ -8,7 +8,7 @@ import ( // The error is a wrapper for the type ( - Error struct { + SourceError struct { SourceType string // The type of source that failed to build. Title, Path, Description string // Description of the error, as presented to the user. Line, Column int // Where the error was encountered. @@ -24,8 +24,8 @@ type ( } ) // Return a new error object -func NewError(source, title,path,description string) *Error { - return &Error { +func NewError(source, title,path,description string) *SourceError { + return &SourceError{ SourceType:source, Title:title, Path:path, @@ -34,7 +34,7 @@ func NewError(source, title,path,description string) *Error { } // Creates a link based on the configuration setting "errors.link" -func (e *Error) SetLink(errorLink string) { +func (e *SourceError) SetLink(errorLink string) { errorLink = strings.Replace(errorLink, "{{Path}}", e.Path, -1) errorLink = strings.Replace(errorLink, "{{Line}}", strconv.Itoa(e.Line), -1) @@ -44,7 +44,7 @@ func (e *Error) SetLink(errorLink string) { // Error method constructs a plaintext version of the error, taking // account that fields are optionally set. Returns e.g. Compilation Error // (in views/header.html:51): expected right delim in end; got "}" -func (e *Error) Error() string { +func (e *SourceError) Error() string { if e == nil { panic("opps") } @@ -69,7 +69,7 @@ func (e *Error) Error() string { // ContextSource method returns a snippet of the source around // where the error occurred. -func (e *Error) ContextSource() []SourceLine { +func (e *SourceError) ContextSource() []SourceLine { if e.SourceLines == nil { return nil } diff --git a/utils/file.go b/utils/file.go index c070c35..6272820 100644 --- a/utils/file.go +++ b/utils/file.go @@ -150,7 +150,7 @@ func MustChmod(filename string, mode os.FileMode) { // Called if panic func PanicOnError(err error, msg string) { - if revErr, ok := err.(*Error); (ok && revErr != nil) || (!ok && err != nil) { + if revErr, ok := err.(*SourceError); (ok && revErr != nil) || (!ok && err != nil) { Logger.Panicf("Abort: %s: %s %s", msg, revErr, err) } } diff --git a/watcher/watcher.go b/watcher/watcher.go index c2d19fa..f4ee0be 100644 --- a/watcher/watcher.go +++ b/watcher/watcher.go @@ -20,7 +20,7 @@ import ( type Listener interface { // Refresh is invoked by the watcher on relevant filesystem events. // If the listener returns an error, it is served to the user on the current request. - Refresh() *utils.Error + Refresh() *utils.SourceError } // DiscerningListener allows the receiver to selectively watch files. @@ -44,7 +44,7 @@ type Watcher struct { paths *model.RevelContainer refreshTimer *time.Timer // The timer to countdown the next refresh timerMutex *sync.Mutex // A mutex to prevent concurrent updates - refreshChannel chan *utils.Error + refreshChannel chan *utils.SourceError refreshChannelCount int refreshTimerMS time.Duration // The number of milliseconds between refreshing builds } @@ -61,7 +61,7 @@ func NewWatcher(paths *model.RevelContainer, eagerRefresh bool) *Watcher { paths.Config.BoolDefault("watch", true) && paths.Config.StringDefault("watch.mode", "normal") == "eager", timerMutex: &sync.Mutex{}, - refreshChannel: make(chan *utils.Error, 10), + refreshChannel: make(chan *utils.SourceError, 10), refreshChannelCount: 0, } } @@ -178,7 +178,7 @@ func (w *Watcher) NotifyWhenUpdated(listener Listener, watcher *fsnotify.Watcher // Notify causes the watcher to forward any change events to listeners. // It returns the first (if any) error returned. -func (w *Watcher) Notify() *utils.Error { +func (w *Watcher) Notify() *utils.SourceError { if w.serial { // Serialize Notify() calls. w.notifyMutex.Lock() @@ -207,7 +207,7 @@ func (w *Watcher) Notify() *utils.Error { utils.Logger.Info("Watcher:Notify refresh state", "Current Index", i, " last error index", w.lastError) if w.forceRefresh || refresh || w.lastError == i { - var err *utils.Error + var err *utils.SourceError if w.serial { err = listener.Refresh() } else { @@ -229,7 +229,7 @@ func (w *Watcher) Notify() *utils.Error { // Build a queue for refresh notifications // this will not return until one of the queue completes -func (w *Watcher) notifyInProcess(listener Listener) (err *utils.Error) { +func (w *Watcher) notifyInProcess(listener Listener) (err *utils.SourceError) { shouldReturn := false // This code block ensures that either a timer is created // or that a process would be added the the h.refreshChannel From 3f54665d4e56c4d1bdd926a568374962b283416b Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sat, 25 Apr 2020 22:45:04 -0700 Subject: [PATCH 04/18] Added processor to read the functions in the imported files, and populate the SourceInfo object the same as before --- model/source_info.go | 12 + parser2/read.go | 93 +++++--- parser2/source_info_processor.go | 375 +++++++++++++++++++++++++++++++ 3 files changed, 445 insertions(+), 35 deletions(-) create mode 100644 parser2/source_info_processor.go diff --git a/model/source_info.go b/model/source_info.go index f4c9a4a..c7ca05f 100644 --- a/model/source_info.go +++ b/model/source_info.go @@ -123,3 +123,15 @@ func (s *SourceInfo) TestSuites() []*TypeInfo { } return s.testSuites } + +func (s *SourceInfo) Merge(srcInfo2 *SourceInfo) { + s.StructSpecs = append(s.StructSpecs, srcInfo2.StructSpecs...) + s.InitImportPaths = append(s.InitImportPaths, srcInfo2.InitImportPaths...) + for k, v := range srcInfo2.ValidationKeys { + if _, ok := s.ValidationKeys[k]; ok { + utils.Logger.Warn("Warn: Key conflict when scanning validation calls:", "key", k) + continue + } + s.ValidationKeys[k] = v + } +} \ No newline at end of file diff --git a/parser2/read.go b/parser2/read.go index f1ed059..48b35a1 100644 --- a/parser2/read.go +++ b/parser2/read.go @@ -12,21 +12,25 @@ import ( "fmt" "strings" "github.com/revel/cmd/logger" - ) + type ( SourceProcessor struct { - revelContainer *model.RevelContainer - log logger.MultiLogger - packageList []*packages.Package - importMap map[string]string + revelContainer *model.RevelContainer + log logger.MultiLogger + packageList []*packages.Package + importMap map[string]string + sourceInfoProcessor *SourceInfoProcessor + sourceInfo *model.SourceInfo } ) + func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.SourceInfo, compileError error) { utils.Logger.Info("ProcessSource") processor := NewSourceProcessor(revelContainer) - sourceInfo, compileError = processor.parse() - fmt.Printf("From parsers \n%v\n%v\n",sourceInfo,compileError) + compileError = processor.parse() + sourceInfo = processor.sourceInfo + fmt.Printf("From parsers \n%v\n%v\n", sourceInfo, compileError) //// Combine packages for modules and app and revel //allPackages := []string{revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} //for _,module := range revelContainer.ModulePathMap { @@ -117,36 +121,45 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour // // return true // //}) ////} -if false { - compileError = errors.New("Incompleted") - utils.Logger.Panic("Not implemented") -} + if false { + compileError = errors.New("Incompleted") + utils.Logger.Panic("Not implemented") + } return } func NewSourceProcessor(revelContainer *model.RevelContainer) *SourceProcessor { - return &SourceProcessor{revelContainer:revelContainer, log:utils.Logger.New("parser","SourceProcessor")} + s := &SourceProcessor{revelContainer:revelContainer, log:utils.Logger.New("parser", "SourceProcessor")} + s.sourceInfoProcessor = NewSourceInfoProcessor(s) + return s } -func (s *SourceProcessor) parse() (sourceInfo *model.SourceInfo, compileError error) { - if compileError=s.addPackages();compileError!=nil { +func (s *SourceProcessor) parse() (compileError error) { + if compileError = s.addPackages(); compileError != nil { return } - if compileError = s.addImportMap();compileError!=nil { + if compileError = s.addImportMap(); compileError != nil { + return + } + if compileError = s.addSourceInfo(); compileError != nil { return } return } func (s *SourceProcessor) addPackages() (err error) { - allPackages := []string{s.revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} - for _,module := range s.revelContainer.ModulePathMap { - allPackages = append(allPackages,module.ImportPath+"/app/controllers/...") + allPackages := []string{s.revelContainer.ImportPath + "/..."} //,model.RevelImportPath} + for _, module := range s.revelContainer.ModulePathMap { + allPackages = append(allPackages, module.ImportPath + "/...") // +"/app/controllers/...") } - allPackages = []string{s.revelContainer.ImportPath+"/app/controllers/..."} + allPackages = []string{s.revelContainer.ImportPath + "/..."} //+"/app/controllers/..."} config := &packages.Config{ // ode: packages.NeedSyntax | packages.NeedCompiledGoFiles, - Mode: packages.NeedTypes | packages.NeedSyntax , + Mode: + packages.NeedTypes | // For compile error + packages.NeedDeps | // To load dependent files + packages.NeedName | // Loads the full package name + packages.NeedSyntax, // To load ast tree (for end points) //Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | // packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | // packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | @@ -161,24 +174,22 @@ func (s *SourceProcessor) addPackages() (err error) { //packages.LoadSyntax | packages.NeedDeps, Dir:s.revelContainer.AppPath, } - s.packageList, err = packages.Load(config, allPackages...) - s.log.Info("***Loaded packegs ", "len results", len(s.packageList), "error",err) + s.packageList, err = packages.Load(config, allPackages...) + s.log.Info("Loaded packages ", "len results", len(s.packageList), "error", err) return } func (s *SourceProcessor) addImportMap() (err error) { s.importMap = map[string]string{} for _, p := range s.packageList { - if len(p.Errors)>0 { + if len(p.Errors) > 0 { // Generate a compile error - for _,e:=range p.Errors { - err = utils.NewCompileError("","",e) + for _, e := range p.Errors { + if !strings.Contains(e.Msg, "fsnotify") { + err = utils.NewCompileError("", "", e) + } } - } - utils.Logger.Info("Errores","error",p.Errors, "id",p.ID) - - for _,tree := range p.Syntax { - println("File ",tree.Name.Name ) + for _, tree := range p.Syntax { for _, decl := range tree.Decls { genDecl, ok := decl.(*ast.GenDecl) if !ok { @@ -188,7 +199,7 @@ func (s *SourceProcessor) addImportMap() (err error) { if genDecl.Tok == token.IMPORT { for _, spec := range genDecl.Specs { importSpec := spec.(*ast.ImportSpec) - fmt.Printf("*** import specification %#v\n", importSpec) + //fmt.Printf("*** import specification %#v\n", importSpec) var pkgAlias string if importSpec.Name != nil { pkgAlias = importSpec.Name.Name @@ -197,15 +208,14 @@ func (s *SourceProcessor) addImportMap() (err error) { } } quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" - fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes + fullPath := quotedPath[1 : len(quotedPath) - 1] // Remove the quotes if pkgAlias == "" { pkgAlias = fullPath - if index:=strings.LastIndex(pkgAlias,"/");index>0 { - pkgAlias = pkgAlias[index+1:] + if index := strings.LastIndex(pkgAlias, "/"); index > 0 { + pkgAlias = pkgAlias[index + 1:] } } s.importMap[pkgAlias] = fullPath - println("Package ", pkgAlias, "fullpath", fullPath) } } } @@ -214,6 +224,19 @@ func (s *SourceProcessor) addImportMap() (err error) { return } +func (s *SourceProcessor) addSourceInfo() (err error) { + for _, p := range s.packageList { + if sourceInfo := s.sourceInfoProcessor.processPackage(p); sourceInfo != nil { + if s.sourceInfo != nil { + s.sourceInfo.Merge(sourceInfo) + } else { + s.sourceInfo = sourceInfo + } + } + } + return +} + // Add imports to the map from the source dir //func addImports(imports map[string]string, decl ast.Decl, srcDir string) { // genDecl, ok := decl.(*ast.GenDecl) diff --git a/parser2/source_info_processor.go b/parser2/source_info_processor.go new file mode 100644 index 0000000..1aca9ca --- /dev/null +++ b/parser2/source_info_processor.go @@ -0,0 +1,375 @@ +package parser2 + +import ( + "github.com/revel/cmd/utils" + "golang.org/x/tools/go/packages" + "github.com/revel/cmd/model" + "go/ast" + "go/token" + "strings" +) + +type ( + SourceInfoProcessor struct { + sourceProcessor *SourceProcessor + } +) +func NewSourceInfoProcessor(sourceProcessor *SourceProcessor) *SourceInfoProcessor { + return &SourceInfoProcessor{sourceProcessor:sourceProcessor} +} + + +func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *model.SourceInfo) { + sourceInfo = &model.SourceInfo{ + ValidationKeys: map[string]map[int]string{}, + } + var ( + isController = strings.HasSuffix(p.PkgPath, "/controllers") || + strings.Contains(p.PkgPath, "/controllers/") + isTest = strings.HasSuffix(p.PkgPath, "/tests") || + strings.Contains(p.PkgPath, "/tests/") + methodMap = map[string][]*model.MethodSpec{} + ) + for _,tree := range p.Syntax { + for _, decl := range tree.Decls { + spec, found := s.getStructTypeDecl(decl, p.Fset) + if found { + if isController || isTest { + controllerSpec := s.getControllerSpec(spec, p) + sourceInfo.StructSpecs = append(sourceInfo.StructSpecs, controllerSpec) + } + } else { + // Not a type definition, this could be a method for a controller try to extract that + // Func declaration? + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok { + continue + } + // This could be a controller action endpoint, check and add if needed + if isController && + funcDecl.Recv!=nil && // Must have a receiver + funcDecl.Name.IsExported() && // be public + funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) == 1 { // return one result + if m, receiver:=s.getControllerFunc(funcDecl,p);m!=nil { + methodMap[receiver]=append(methodMap[receiver],m) + s.sourceProcessor.log.Info("Added method map to ","receiver",receiver,"method",m.Name) + } + } + // Check for validation + if lineKeyMap := s.getValidation(funcDecl,p);len(lineKeyMap)>1 { + sourceInfo.ValidationKeys[p.PkgPath+"."+s.getFuncName(funcDecl)] = lineKeyMap + } + if funcDecl.Name.Name == "init" { + sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths,p.PkgPath) + } + } + } + } + + // Add the method specs to the struct specs. + for _, spec := range sourceInfo.StructSpecs { + spec.MethodSpecs = methodMap[spec.StructName] + } + + return +} +// Scan app source code for calls to X.Y(), where X is of type *Validation. +// +// Recognize these scenarios: +// - "Y" = "Validation" and is a member of the receiver. +// (The common case for inline validation) +// - "X" is passed in to the func as a parameter. +// (For structs implementing Validated) +// +// The line number to which a validation call is attributed is that of the +// surrounding ExprStmt. This is so that it matches what runtime.Callers() +// reports. +// +// The end result is that we can set the default validation key for each call to +// be the same as the local variable. +func (s *SourceInfoProcessor) getValidation(funcDecl *ast.FuncDecl,p *packages.Package) (map[int]string) { + var ( + lineKeys = make(map[int]string) + + // Check the func parameters and the receiver's members for the *revel.Validation type. + validationParam = s.getValidationParameter(funcDecl) + ) + + ast.Inspect(funcDecl.Body, func(node ast.Node) bool { + // e.g. c.Validation.Required(arg) or v.Required(arg) + callExpr, ok := node.(*ast.CallExpr) + if !ok { + return true + } + + // e.g. c.Validation.Required or v.Required + funcSelector, ok := callExpr.Fun.(*ast.SelectorExpr) + if !ok { + return true + } + + switch x := funcSelector.X.(type) { + case *ast.SelectorExpr: // e.g. c.Validation + if x.Sel.Name != "Validation" { + return true + } + + case *ast.Ident: // e.g. v + if validationParam == nil || x.Obj != validationParam { + return true + } + + default: + return true + } + + if len(callExpr.Args) == 0 { + return true + } + + // Given the validation expression, extract the key. + key := callExpr.Args[0] + switch expr := key.(type) { + case *ast.BinaryExpr: + // If the argument is a binary expression, take the first expression. + // (e.g. c.Validation.Required(myName != "")) + key = expr.X + case *ast.UnaryExpr: + // If the argument is a unary expression, drill in. + // (e.g. c.Validation.Required(!myBool) + key = expr.X + case *ast.BasicLit: + // If it's a literal, skip it. + return true + } + + if typeExpr := model.NewTypeExprFromAst("", key); typeExpr.Valid { + lineKeys[p.Fset.Position(callExpr.End()).Line] = typeExpr.TypeName("") + } else { + s.sourceProcessor.log.Error("Error: Failed to generate key for field validation. Make sure the field name is valid.", "file", p.PkgPath, + "line", p.Fset.Position(callExpr.End()).Line, "function", funcDecl.Name.String()) + } + return true + }) + + return lineKeys + +} +// Check to see if there is a *revel.Validation as an argument. +func (s *SourceInfoProcessor) getValidationParameter(funcDecl *ast.FuncDecl) *ast.Object { + for _, field := range funcDecl.Type.Params.List { + starExpr, ok := field.Type.(*ast.StarExpr) // e.g. *revel.Validation + if !ok { + continue + } + + selExpr, ok := starExpr.X.(*ast.SelectorExpr) // e.g. revel.Validation + if !ok { + continue + } + + xIdent, ok := selExpr.X.(*ast.Ident) // e.g. rev + if !ok { + continue + } + + if selExpr.Sel.Name == "Validation" && s.sourceProcessor.importMap[xIdent.Name] == model.RevelImportPath { + return field.Names[0].Obj + } + } + return nil +} +func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl,p *packages.Package) (method *model.MethodSpec, recvTypeName string) { + selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr) + if !ok { + return + } + if selExpr.Sel.Name != "Result" { + return + } + if pkgIdent, ok := selExpr.X.(*ast.Ident); !ok || s.sourceProcessor.importMap[pkgIdent.Name] != model.RevelImportPath { + return + } + method = &model.MethodSpec{ + Name: funcDecl.Name.Name, + } + + // Add a description of the arguments to the method. + for _, field := range funcDecl.Type.Params.List { + for _, name := range field.Names { + var importPath string + typeExpr := model.NewTypeExprFromAst(p.Name, field.Type) + if !typeExpr.Valid { + utils.Logger.Warn("Warn: Didn't understand argument '%s' of action %s. Ignoring.", name, s.getFuncName(funcDecl)) + return // We didn't understand one of the args. Ignore this action. + } + // Local object + if typeExpr.PkgName == p.Name { + importPath = p.PkgPath + } else if typeExpr.PkgName != "" { + var ok bool + if importPath, ok = s.sourceProcessor.importMap[typeExpr.PkgName]; !ok { + utils.Logger.Fatalf("Failed to find import for arg of type: %s , %s", typeExpr.PkgName, typeExpr.TypeName("")) + } + } + method.Args = append(method.Args, &model.MethodArg{ + Name: name.Name, + TypeExpr: typeExpr, + ImportPath: importPath, + }) + } + } + + // Add a description of the calls to Render from the method. + // Inspect every node (e.g. always return true). + method.RenderCalls = []*model.MethodCall{} + ast.Inspect(funcDecl.Body, func(node ast.Node) bool { + // Is it a function call? + callExpr, ok := node.(*ast.CallExpr) + if !ok { + return true + } + + // Is it calling (*Controller).Render? + selExpr, ok := callExpr.Fun.(*ast.SelectorExpr) + if !ok { + return true + } + + // The type of the receiver is not easily available, so just store every + // call to any method called Render. + if selExpr.Sel.Name != "Render" { + return true + } + + // Add this call's args to the renderArgs. + pos := p.Fset.Position(callExpr.Lparen) + methodCall := &model.MethodCall{ + Line: pos.Line, + Names: []string{}, + } + for _, arg := range callExpr.Args { + argIdent, ok := arg.(*ast.Ident) + if !ok { + continue + } + methodCall.Names = append(methodCall.Names, argIdent.Name) + } + method.RenderCalls = append(method.RenderCalls, methodCall) + return true + }) + + var recvType = funcDecl.Recv.List[0].Type + if recvStarType, ok := recvType.(*ast.StarExpr); ok { + recvTypeName = recvStarType.X.(*ast.Ident).Name + } else { + recvTypeName = recvType.(*ast.Ident).Name + } + return +} +func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec,p *packages.Package) (controllerSpec *model.TypeInfo) { + structType := spec.Type.(*ast.StructType) + + // At this point we know it's a type declaration for a struct. + // Fill in the rest of the info by diving into the fields. + // Add it provisionally to the Controller list -- it's later filtered using field info. + controllerSpec = &model.TypeInfo{ + StructName: spec.Name.Name, + ImportPath: p.PkgPath, + PackageName: p.Name, + } + for _, field := range structType.Fields.List { + // If field.Names is set, it's not an embedded type. + if field.Names != nil { + continue + } + + // A direct "sub-type" has an ast.Field as either: + // Ident { "AppController" } + // SelectorExpr { "rev", "Controller" } + // Additionally, that can be wrapped by StarExprs. + fieldType := field.Type + pkgName, typeName := func() (string, string) { + // Drill through any StarExprs. + for { + if starExpr, ok := fieldType.(*ast.StarExpr); ok { + fieldType = starExpr.X + continue + } + break + } + + // If the embedded type is in the same package, it's an Ident. + if ident, ok := fieldType.(*ast.Ident); ok { + return "", ident.Name + } + + if selectorExpr, ok := fieldType.(*ast.SelectorExpr); ok { + if pkgIdent, ok := selectorExpr.X.(*ast.Ident); ok { + return pkgIdent.Name, selectorExpr.Sel.Name + } + } + return "", "" + }() + + // If a typename wasn't found, skip it. + if typeName == "" { + continue + } + + // Find the import path for this type. + // If it was referenced without a package name, use the current package import path. + // Else, look up the package's import path by name. + var importPath string + if pkgName == "" { + importPath = p.PkgPath + } else { + var ok bool + if importPath, ok = s.sourceProcessor.importMap[pkgName]; !ok { + s.sourceProcessor.log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map",s.sourceProcessor.importMap) + continue + } + } + + controllerSpec.EmbeddedTypes = append(controllerSpec.EmbeddedTypes, &model.EmbeddedTypeName{ + ImportPath: importPath, + StructName: typeName, + }) + } + s.sourceProcessor.log.Info("Added controller spec", "name",controllerSpec.StructName,"package",controllerSpec.ImportPath) + return +} +func (s *SourceInfoProcessor) getStructTypeDecl(decl ast.Decl, fset *token.FileSet) (spec *ast.TypeSpec, found bool) { + genDecl, ok := decl.(*ast.GenDecl) + if !ok { + return + } + + if genDecl.Tok != token.TYPE { + return + } + + if len(genDecl.Specs) == 0 { + utils.Logger.Warn("Warn: Surprising: %s:%d Decl contains no specifications", fset.Position(decl.Pos()).Filename, fset.Position(decl.Pos()).Line) + return + } + + spec = genDecl.Specs[0].(*ast.TypeSpec) + _, found = spec.Type.(*ast.StructType) + + return + +} +func (s *SourceInfoProcessor) getFuncName(funcDecl *ast.FuncDecl) string { + prefix := "" + if funcDecl.Recv != nil { + recvType := funcDecl.Recv.List[0].Type + if recvStarType, ok := recvType.(*ast.StarExpr); ok { + prefix = "(*" + recvStarType.X.(*ast.Ident).Name + ")" + } else { + prefix = recvType.(*ast.Ident).Name + } + prefix += "." + } + return prefix + funcDecl.Name.Name +} \ No newline at end of file From f2b54f5a6932eb96c1f2cc9891f89025ecd75cf9 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sun, 26 Apr 2020 08:58:58 -0700 Subject: [PATCH 05/18] Updated sourceinfo Added packagepathmap to the SourceInfo, this in turn allows the RevelCLI app command to pass the source paths directly to Revel directly Added default to build to be "target" of the current folder Renamed source processor --- go.mod | 2 + harness/app.go | 5 +- harness/build.go | 13 +-- harness/harness.go | 14 ++- model/source_info.go | 2 + parser2/source_info_processor.go | 3 + parser2/{read.go => source_processor.go} | 119 +++++------------------ revel/build.go | 20 ++-- revel/clean.go | 3 + revel/package.go | 5 +- revel/run.go | 8 +- revel/test.go | 13 ++- utils/file.go | 8 +- 13 files changed, 90 insertions(+), 125 deletions(-) rename parser2/{read.go => source_processor.go} (61%) diff --git a/go.mod b/go.mod index a6e1c32..e6ee7ee 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/revel/config v0.21.0 github.com/revel/log15 v2.11.20+incompatible + github.com/revel/modules v0.21.0 // indirect github.com/revel/pathtree v0.0.0-20140121041023-41257a1839e9 // indirect github.com/revel/revel v0.21.0 github.com/stretchr/testify v1.4.0 @@ -21,6 +22,7 @@ require ( golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect golang.org/x/tools v0.0.0-20200219054238-753a1d49df85 gopkg.in/fsnotify/fsnotify.v1 v1.4.7 + gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0 gopkg.in/stretchr/testify.v1 v1.2.2 // indirect diff --git a/harness/app.go b/harness/app.go index 3b855b8..3b5475a 100644 --- a/harness/app.go +++ b/harness/app.go @@ -24,12 +24,13 @@ type App struct { BinaryPath string // Path to the app executable Port int // Port to pass as a command line argument. cmd AppCmd // The last cmd returned. + PackagePathMap map[string]string // Package to directory path map Paths *model.RevelContainer } // NewApp returns app instance with binary path in it -func NewApp(binPath string, paths *model.RevelContainer) *App { - return &App{BinaryPath: binPath, Paths: paths, Port: paths.HTTPPort} +func NewApp(binPath string, paths *model.RevelContainer, packagePathMap map[string]string) *App { + return &App{BinaryPath: binPath, Paths: paths, Port: paths.HTTPPort, PackagePathMap:packagePathMap} } // Cmd returns a command to run the app server using the current configuration. diff --git a/harness/build.go b/harness/build.go index 51adb64..729fd15 100644 --- a/harness/build.go +++ b/harness/build.go @@ -116,13 +116,8 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err } } - pkg, err := build.Default.Import(paths.ImportPath, "", build.FindOnly) - if err != nil { - return - } - - // Binary path is a combination of $GOBIN/revel.d directory, app's import path and its name. - binName := filepath.Join(pkg.BinDir, "revel.d", paths.ImportPath, filepath.Base(paths.BasePath)) + // Binary path is a combination of BasePath/target directory, app's import path and its name. + binName := filepath.Join(paths.BasePath, "target", paths.ImportPath, filepath.Base(paths.BasePath)) // Change binary path for Windows build goos := runtime.GOOS @@ -196,13 +191,13 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err "GOPATH="+gopath, ) utils.CmdInit(buildCmd, c.AppPath) - utils.Logger.Info("Exec:", "args", buildCmd.Args) + utils.Logger.Info("Exec:", "args", buildCmd.Args,"working dir", buildCmd.Dir) output, err := buildCmd.CombinedOutput() // If the build succeeded, we're done. if err == nil { utils.Logger.Info("Build successful continuing") - return NewApp(binName, paths), nil + return NewApp(binName, paths,sourceInfo.PackageMap), nil } // Since there was an error, capture the output in case we need to report it diff --git a/harness/harness.go b/harness/harness.go index bdf8002..fd6397c 100644 --- a/harness/harness.go +++ b/harness/harness.go @@ -34,6 +34,7 @@ import ( "html/template" "io/ioutil" "sync" + "encoding/json" ) var ( @@ -161,6 +162,7 @@ func NewHarness(c *model.CommandConfig, paths *model.RevelContainer, runMode str addr := paths.HTTPAddr port := paths.Config.IntDefault("harness.port", 0) scheme := "http" + if paths.HTTPSsl { scheme = "https" } @@ -229,7 +231,17 @@ func (h *Harness) Refresh() (err *utils.SourceError) { if h.useProxy { h.app.Port = h.port - if err2 := h.app.Cmd(h.runMode).Start(h.config); err2 != nil { + runMode := h.runMode + if !h.config.HistoricMode { + // Recalulate run mode based on the config + var paths []byte + if len(h.app.PackagePathMap)>0 { + paths, _ = json.Marshal(h.app.PackagePathMap) + } + runMode = fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, h.app.Paths.RunMode, h.config.Verbose, string(paths)) + + } + if err2 := h.app.Cmd(runMode).Start(h.config); err2 != nil { utils.Logger.Error("Could not start application", "error", err2) if err,k :=err2.(*utils.SourceError);k { return err diff --git a/model/source_info.go b/model/source_info.go index c7ca05f..88ed26f 100644 --- a/model/source_info.go +++ b/model/source_info.go @@ -29,6 +29,8 @@ type SourceInfo struct { controllerSpecs []*TypeInfo // testSuites list the types that constitute the set of application tests. testSuites []*TypeInfo + // packageMap a map of import to system directory (if available) + PackageMap map[string]string } // TypesThatEmbed returns all types that (directly or indirectly) embed the diff --git a/parser2/source_info_processor.go b/parser2/source_info_processor.go index 1aca9ca..6d8a1c0 100644 --- a/parser2/source_info_processor.go +++ b/parser2/source_info_processor.go @@ -7,6 +7,7 @@ import ( "go/ast" "go/token" "strings" + "path/filepath" ) type ( @@ -32,6 +33,8 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m ) for _,tree := range p.Syntax { for _, decl := range tree.Decls { + s.sourceProcessor.packageMap[p.PkgPath] = filepath.Dir(p.Fset.Position(decl.Pos()).Filename) + //println("*** checking", p.Fset.Position(decl.Pos()).Filename) spec, found := s.getStructTypeDecl(decl, p.Fset) if found { if isController || isTest { diff --git a/parser2/read.go b/parser2/source_processor.go similarity index 61% rename from parser2/read.go rename to parser2/source_processor.go index 48b35a1..2811da1 100644 --- a/parser2/read.go +++ b/parser2/source_processor.go @@ -3,13 +3,11 @@ package parser2 import ( "go/ast" "go/token" - "github.com/revel/cmd/model" "golang.org/x/tools/go/packages" "github.com/revel/cmd/utils" "errors" - "fmt" "strings" "github.com/revel/cmd/logger" ) @@ -20,6 +18,7 @@ type ( log logger.MultiLogger packageList []*packages.Package importMap map[string]string + packageMap map[string]string sourceInfoProcessor *SourceInfoProcessor sourceInfo *model.SourceInfo } @@ -30,97 +29,10 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour processor := NewSourceProcessor(revelContainer) compileError = processor.parse() sourceInfo = processor.sourceInfo - fmt.Printf("From parsers \n%v\n%v\n", sourceInfo, compileError) - //// Combine packages for modules and app and revel - //allPackages := []string{revelContainer.ImportPath+"/app/controllers/...",model.RevelImportPath} - //for _,module := range revelContainer.ModulePathMap { - // allPackages = append(allPackages,module.ImportPath+"/app/controllers/...") - //} - //allPackages = []string{revelContainer.ImportPath+"/app/controllers/..."} - // - //config := &packages.Config{ - // // ode: packages.NeedSyntax | packages.NeedCompiledGoFiles, - // Mode: packages.NeedTypes | packages.NeedSyntax , - // //Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | - // // packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | - // // packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | - // // packages.NeedTypesSizes, - // - // //Mode: packages.NeedName | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedFiles | - // // packages.NeedCompiledGoFiles | packages.NeedTypesSizes | - // // packages.NeedSyntax | packages.NeedCompiledGoFiles , - // //Mode: packages.NeedSyntax | packages.NeedCompiledGoFiles | packages.NeedName | packages.NeedFiles | - // // packages.LoadTypes | packages.NeedTypes | packages.NeedDeps, //, // | - // // packages.NeedTypes, // packages.LoadTypes | packages.NeedSyntax | packages.NeedTypesInfo, - // //packages.LoadSyntax | packages.NeedDeps, - // Dir:revelContainer.AppPath, - //} - //utils.Logger.Info("Before ","apppath", config.Dir,"paths",allPackages) - //pkgs, err := packages.Load(config, allPackages...) - //utils.Logger.Info("***Loaded packegs ", "len results", len(pkgs), "error",err) - //// Lets see if we can output all the path names - ////packages.Visit(pkgs,func(p *packages.Package) bool{ - //// println("Got pre",p.ID) - //// return true - ////}, func(p *packages.Package) { - ////}) - //counter := 0 - //for _, p := range pkgs { - // utils.Logger.Info("Errores","error",p.Errors, "id",p.ID) - // //for _,g := range p.GoFiles { - // // println("File", g) - // //} - // //for _, t:= range p.Syntax { - // // utils.Logger.Info("File","name",t.Name) - // //} - // //println("package typoe fouhnd ",p.Types.Name()) - // //imports := map[string]string{} - // - // for _,s := range p.Syntax { - // println("File ",s.Name.Name ) - // for _, decl := range s.Decls { - // genDecl, ok := decl.(*ast.GenDecl) - // if !ok { - // continue - // } - // - // if genDecl.Tok == token.IMPORT { - // for _, spec := range genDecl.Specs { - // importSpec := spec.(*ast.ImportSpec) - // fmt.Printf("*** import specification %#v\n", importSpec) - // var pkgAlias string - // if importSpec.Name != nil { - // pkgAlias = importSpec.Name.Name - // if pkgAlias == "_" { - // continue - // } - // } - // quotedPath := importSpec.Path.Value // e.g. "\"sample/app/models\"" - // fullPath := quotedPath[1 : len(quotedPath)-1] // Remove the quotes - // if pkgAlias == "" { - // pkgAlias = fullPath - // if index:=strings.LastIndex(pkgAlias,"/");index>0 { - // pkgAlias = pkgAlias[index+1:] - // } - // } - // //imports[pkgAlias] = fullPath - // println("Package ", pkgAlias, "fullpath", fullPath) - // } - // } - // } - // } - // } - // //p.Fset.Iterate(func(file *token.File) bool{ - // // - // // // utils.Logger.Info("Output","Found file", p.ID," AND NAME ", f.Name()) - // // // For each declaration in the source file... - // // //for _, decl := range file.Decls { - // // // addImports(imports, decl, pkgPath) - // // //} - // // counter ++ - // // return true - // //}) - ////} + if compileError==nil { + processor.log.Infof("From parsers : Structures:%d InitImports:%d ValidationKeys:%d %v", len(sourceInfo.StructSpecs), len(sourceInfo.InitImportPaths), len(sourceInfo.ValidationKeys),sourceInfo.PackageMap) + } + if false { compileError = errors.New("Incompleted") utils.Logger.Panic("Not implemented") @@ -143,15 +55,30 @@ func (s *SourceProcessor) parse() (compileError error) { if compileError = s.addSourceInfo(); compileError != nil { return } + s.sourceInfo.PackageMap = map[string]string{} + getImportFromMap := func(packagePath string) string { + for path := range s.packageMap { + if strings.Index(path,packagePath)==0 { + fullPath := s.packageMap[path] + return fullPath[:(len(fullPath) - len(path) + len(packagePath))] + } + } + return "" + } + s.sourceInfo.PackageMap[model.RevelImportPath] = getImportFromMap(model.RevelImportPath) + s.sourceInfo.PackageMap[s.revelContainer.ImportPath] = getImportFromMap(s.revelContainer.ImportPath) + for _, module := range s.revelContainer.ModulePathMap { + s.sourceInfo.PackageMap[module.ImportPath] = getImportFromMap(module.ImportPath) + } return } func (s *SourceProcessor) addPackages() (err error) { - allPackages := []string{s.revelContainer.ImportPath + "/..."} //,model.RevelImportPath} + allPackages := []string{s.revelContainer.ImportPath + "/...",model.RevelImportPath} for _, module := range s.revelContainer.ModulePathMap { allPackages = append(allPackages, module.ImportPath + "/...") // +"/app/controllers/...") } - allPackages = []string{s.revelContainer.ImportPath + "/..."} //+"/app/controllers/..."} + //allPackages = []string{s.revelContainer.ImportPath + "/..."} //+"/app/controllers/..."} config := &packages.Config{ // ode: packages.NeedSyntax | packages.NeedCompiledGoFiles, @@ -180,7 +107,9 @@ func (s *SourceProcessor) addPackages() (err error) { } func (s *SourceProcessor) addImportMap() (err error) { s.importMap = map[string]string{} + s.packageMap = map[string]string{} for _, p := range s.packageList { + if len(p.Errors) > 0 { // Generate a compile error for _, e := range p.Errors { diff --git a/revel/build.go b/revel/build.go index e929114..3bba537 100644 --- a/revel/build.go +++ b/revel/build.go @@ -37,6 +37,12 @@ func init() { // The update config updates the configuration command so that it can run func updateBuildConfig(c *model.CommandConfig, args []string) bool { c.Index = model.BUILD + if c.Build.TargetPath=="" { + c.Build.TargetPath="target" + } + if len(args)==0 && c.Build.ImportPath!="" { + return true + } // If arguments were passed in then there must be two if len(args) < 2 { fmt.Fprintf(os.Stderr, "%s\n%s", cmdBuild.UsageLine, cmdBuild.Long) @@ -63,7 +69,7 @@ func buildApp(c *model.CommandConfig) (err error) { c.Build.Mode = mode c.Build.ImportPath = appImportPath - revel_paths, err := model.NewRevelPaths(mode, appImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver)) + revel_paths, err := model.NewRevelPaths(mode, appImportPath, c.AppPath, model.NewWrappedRevelCallback(nil, c.PackageResolver)) if err != nil { return } @@ -88,7 +94,7 @@ func buildApp(c *model.CommandConfig) (err error) { if err != nil { return } - err = buildCopyModules(c, revel_paths, packageFolders) + err = buildCopyModules(c, revel_paths, packageFolders, app) if err != nil { return } @@ -148,7 +154,7 @@ func buildCopyFiles(c *model.CommandConfig, app *harness.App, revel_paths *model } // Based on the section copy over the build modules -func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, packageFolders []string) (err error) { +func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, packageFolders []string, app *harness.App) (err error) { destPath := filepath.Join(c.Build.TargetPath, "src") // Find all the modules used and copy them over. config := revel_paths.Config.Raw() @@ -174,14 +180,10 @@ func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, } } - modulePaths, err := utils.FindSrcPaths(c.AppPath, moduleImportList, c.PackageResolver) - - if err != nil { - utils.Logger.Fatalf("Failed to load modules ", "error", err) - } // Copy the the paths for each of the modules - for importPath, fsPath := range modulePaths { + for _,importPath := range moduleImportList { + fsPath := app.PackagePathMap[importPath] utils.Logger.Info("Copy files ", "to", filepath.Join(destPath, importPath), "from", fsPath) if c.Build.CopySource { err = utils.CopyDir(filepath.Join(destPath, importPath), fsPath, nil) diff --git a/revel/clean.go b/revel/clean.go index 6a210f3..6f428bd 100644 --- a/revel/clean.go +++ b/revel/clean.go @@ -37,6 +37,9 @@ func init() { // Update the clean command configuration, using old method func updateCleanConfig(c *model.CommandConfig, args []string) bool { c.Index = model.CLEAN + if len(args)==0 && c.Clean.ImportPath!="" { + return true + } if len(args) == 0 { fmt.Fprintf(os.Stderr, cmdClean.Long) return false diff --git a/revel/package.go b/revel/package.go index 8967258..723e7a9 100644 --- a/revel/package.go +++ b/revel/package.go @@ -40,6 +40,9 @@ func init() { // Called when unable to parse the command line automatically and assumes an old launch func updatePackageConfig(c *model.CommandConfig, args []string) bool { c.Index = model.PACKAGE + if len(args)==0 && c.Package.ImportPath!="" { + return true + } c.Package.ImportPath = args[0] if len(args) > 1 { c.Package.Mode = args[1] @@ -58,7 +61,7 @@ func packageApp(c *model.CommandConfig) (err error) { } appImportPath := c.ImportPath - revel_paths, err := model.NewRevelPaths(mode, appImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver)) + revel_paths, err := model.NewRevelPaths(mode, appImportPath, c.AppPath, model.NewWrappedRevelCallback(nil, c.PackageResolver)) if err != nil { return } diff --git a/revel/run.go b/revel/run.go index adce55c..85c9d3f 100644 --- a/revel/run.go +++ b/revel/run.go @@ -6,7 +6,7 @@ package main import ( "strconv" - + "encoding/json" "fmt" "github.com/revel/cmd/harness" "github.com/revel/cmd/model" @@ -159,7 +159,11 @@ func runApp(c *model.CommandConfig) (err error) { utils.Logger.Errorf("Failed to build app: %s", err) } app.Port = revel_path.HTTPPort - runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v}`, app.Paths.RunMode, c.Verbose) + var paths []byte + if len(app.PackagePathMap)>0 { + paths, _ = json.Marshal(app.PackagePathMap) + } + runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose, string(paths)) if c.HistoricMode { runMode = revel_path.RunMode } diff --git a/revel/test.go b/revel/test.go index 8465f6b..abeb35b 100644 --- a/revel/test.go +++ b/revel/test.go @@ -55,6 +55,10 @@ func init() { // Called to update the config command with from the older stype func updateTestConfig(c *model.CommandConfig, args []string) bool { c.Index = model.TEST + if len(args)==0 && c.Test.ImportPath!="" { + return true + } + // The full test runs // revel test (run mode) (suite(.function)) if len(args) < 1 { @@ -78,7 +82,7 @@ func testApp(c *model.CommandConfig) (err error) { } // Find and parse app.conf - revel_path, err := model.NewRevelPaths(mode, c.ImportPath, "", model.NewWrappedRevelCallback(nil, c.PackageResolver)) + revel_path, err := model.NewRevelPaths(mode, c.ImportPath, c.AppPath, model.NewWrappedRevelCallback(nil, c.PackageResolver)) if err != nil { return } @@ -104,11 +108,16 @@ func testApp(c *model.CommandConfig) (err error) { if reverr != nil { return utils.NewBuildIfError(reverr, "Error building: ") } - runMode := fmt.Sprintf(`{"mode":"%s","testModeFlag":true, "specialUseFlag":%v}`, app.Paths.RunMode, c.Verbose) + var paths []byte + if len(app.PackagePathMap)>0 { + paths, _ = json.Marshal(app.PackagePathMap) + } + runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose, string(paths)) if c.HistoricMode { runMode = app.Paths.RunMode } cmd := app.Cmd(runMode) + cmd.Dir=c.AppPath cmd.Stderr = io.MultiWriter(cmd.Stderr, file) cmd.Stdout = io.MultiWriter(cmd.Stderr, file) diff --git a/utils/file.go b/utils/file.go index 6272820..b48f9ff 100644 --- a/utils/file.go +++ b/utils/file.go @@ -4,8 +4,8 @@ import ( "archive/tar" "bytes" "compress/gzip" - "errors" "fmt" + "errors" "html/template" "io" "io/ioutil" @@ -352,7 +352,7 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str sourcePathsmap = map[string]string{} pkgs, err := packages.Load(config, packagesList...) - Logger.Info("Loaded packegs ", "len results", len(pkgs), "error",err) + Logger.Info("Loaded packegs ", "len results", len(pkgs), "error",err,"basedir",appPath) for _, packageName := range packagesList { found := false log:= Logger.New("seeking",packageName) @@ -360,11 +360,11 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str log.Info("Found package","package",pck.ID) if pck.ID == packageName { if pck.Errors!=nil && len(pck.Errors)>0 { - Logger.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID,"errors",pck.Errors) + log.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID,"errors",pck.Errors) } //a,_ := pck.MarshalJSON() - Logger.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID) + log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID,"apppath",appPath) sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0]) found = true } From c1aee244452d2bedd95bace5e01b5942565c8b26 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sun, 26 Apr 2020 09:57:35 -0700 Subject: [PATCH 06/18] Corrected version detection, so that equal versions match --- model/version.go | 4 +++- revel/version.go | 4 ++-- utils/file.go | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/model/version.go b/model/version.go index 60ee3b0..bc52654 100644 --- a/model/version.go +++ b/model/version.go @@ -21,6 +21,7 @@ type Version struct { var frameworkCompatibleRangeList = [][]string{ {"0.0.0", "0.20.0"}, // minimum Revel version to use with this version of the tool {"0.19.99", "0.30.0"}, // Compatible with Framework V 0.19.99 - 0.30.0 + {"1.0.0", "1.1.0"}, // Compatible with Framework V 1.0 - 1.1 } // Parses a version like v1.2.3a or 1.2 @@ -70,6 +71,7 @@ func (v *Version) CompatibleFramework(c *CommandConfig) error { if !v.Newer(start) || v.Newer(end) { continue } + // Framework is older then 0.20, turn on historic mode if i == 0 { c.HistoricMode = true @@ -109,7 +111,7 @@ func (v *Version) Newer(o *Version) bool { if v.Maintenance != o.Maintenance { return v.Maintenance > o.Maintenance } - return false + return true } // Convert the version to a string diff --git a/revel/version.go b/revel/version.go index af0a43e..3de97fb 100644 --- a/revel/version.go +++ b/revel/version.go @@ -239,8 +239,8 @@ func (v *VersionCommand) updateLocalVersions() { utils.Logger.Warn("Unable to extract version information from Revel library", "path",pathMap[model.RevelImportPath], "error",err) return } - utils.Logger.Info("Fullpath to revel", "dir", pathMap[model.RevelModulesImportPath]) - v.revelVersion, err = v.versionFromFilepath(pathMap[model.RevelModulesImportPath]) + utils.Logger.Info("Fullpath to revel modules", "dir", pathMap[model.RevelImportPath]) + v.revelVersion, err = v.versionFromFilepath(pathMap[model.RevelImportPath]) if err != nil { utils.Logger.Warn("Unable to extract version information from Revel", "error,err") } diff --git a/utils/file.go b/utils/file.go index b48f9ff..d661beb 100644 --- a/utils/file.go +++ b/utils/file.go @@ -352,7 +352,7 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str sourcePathsmap = map[string]string{} pkgs, err := packages.Load(config, packagesList...) - Logger.Info("Loaded packegs ", "len results", len(pkgs), "error",err,"basedir",appPath) + Logger.Info("Loaded packages ", "len results", len(pkgs), "error",err,"basedir",appPath) for _, packageName := range packagesList { found := false log:= Logger.New("seeking",packageName) From 07d67846c1a7ef1bbd664d6dbbeccb3597adbd59 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sun, 26 Apr 2020 11:07:06 -0700 Subject: [PATCH 07/18] Restructured command config Removed go/build reference in clean --- model/command/build.go | 10 +++++++ model/command/clean.go | 6 +++++ model/command/import_command.go | 7 +++++ model/command/new.go | 11 ++++++++ model/command/package.go | 9 +++++++ model/command/run.go | 9 +++++++ model/command/test_command.go | 9 +++++++ model/command/version.go | 7 +++++ model/command_config.go | 47 +++++++-------------------------- revel/clean.go | 10 +++---- 10 files changed, 80 insertions(+), 45 deletions(-) create mode 100644 model/command/build.go create mode 100644 model/command/clean.go create mode 100644 model/command/import_command.go create mode 100644 model/command/new.go create mode 100644 model/command/package.go create mode 100644 model/command/run.go create mode 100644 model/command/test_command.go create mode 100644 model/command/version.go diff --git a/model/command/build.go b/model/command/build.go new file mode 100644 index 0000000..61e3cbb --- /dev/null +++ b/model/command/build.go @@ -0,0 +1,10 @@ +package command +type ( + Build struct { + ImportCommand + TargetPath string `short:"t" long:"target-path" description:"Path to target folder. Folder will be completely deleted if it exists" required:"false"` + Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` + CopySource bool `short:"s" long:"include-source" description:"Copy the source code as well"` + } + +) diff --git a/model/command/clean.go b/model/command/clean.go new file mode 100644 index 0000000..644cca7 --- /dev/null +++ b/model/command/clean.go @@ -0,0 +1,6 @@ +package command +type ( + Clean struct { + ImportCommand + } +) diff --git a/model/command/import_command.go b/model/command/import_command.go new file mode 100644 index 0000000..8e86f29 --- /dev/null +++ b/model/command/import_command.go @@ -0,0 +1,7 @@ +package command + +type ( + ImportCommand struct { + ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` + } +) diff --git a/model/command/new.go b/model/command/new.go new file mode 100644 index 0000000..25f3de2 --- /dev/null +++ b/model/command/new.go @@ -0,0 +1,11 @@ +package command +type ( + New struct { + ImportCommand + SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` + Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` + NotVendored bool `short:"V" long:"vendor" description:"True if project should not be configured with a go.mod"` + Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` + } + +) \ No newline at end of file diff --git a/model/command/package.go b/model/command/package.go new file mode 100644 index 0000000..264ea12 --- /dev/null +++ b/model/command/package.go @@ -0,0 +1,9 @@ +package command +type ( + Package struct { + ImportCommand + TargetPath string `short:"t" long:"target-path" description:"Full path and filename of target package to deploy" required:"false"` + Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` + CopySource bool `short:"s" long:"include-source" description:"Copy the source code as well"` + } +) \ No newline at end of file diff --git a/model/command/run.go b/model/command/run.go new file mode 100644 index 0000000..1c745e6 --- /dev/null +++ b/model/command/run.go @@ -0,0 +1,9 @@ +package command +type ( + Run struct { + ImportCommand + Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` + Port int `short:"p" long:"port" default:"-1" description:"The port to listen" ` + NoProxy bool `short:"n" long:"no-proxy" description:"True if proxy server should not be started. This will only update the main and routes files on change"` + } +) \ No newline at end of file diff --git a/model/command/test_command.go b/model/command/test_command.go new file mode 100644 index 0000000..0822441 --- /dev/null +++ b/model/command/test_command.go @@ -0,0 +1,9 @@ +package command + +type ( + Test struct { + ImportCommand + Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` + Function string `short:"f" long:"suite-function" description:"The suite.function"` + } +) \ No newline at end of file diff --git a/model/command/version.go b/model/command/version.go new file mode 100644 index 0000000..627f505 --- /dev/null +++ b/model/command/version.go @@ -0,0 +1,7 @@ +package command +type ( + Version struct { + ImportCommand + Update bool `short:"u" long:"Update the framework and modules" required:"false"` + } +) diff --git a/model/command_config.go b/model/command_config.go index ef1fd9a..db248f3 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -14,6 +14,7 @@ import ( "os/exec" "path/filepath" "strings" + "github.com/revel/cmd/model/command" ) // The constants @@ -48,50 +49,20 @@ type ( Vendored bool // True if the application is vendored PackageResolver func(pkgName string) error // a packge resolver for the config BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` - // The new command - New struct { - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` - Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` - NotVendored bool `short:"V" long:"vendor" description:"True if project should not be configured with a go.mod"` - Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` - } `command:"new"` + + New command.New `command:"new"` // The new command // The build command - Build struct { - TargetPath string `short:"t" long:"target-path" description:"Path to target folder. Folder will be completely deleted if it exists" required:"false"` - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` - CopySource bool `short:"s" long:"include-source" description:"Copy the source code as well"` - } `command:"build"` + Build command.Build `command:"build"` // The run command - Run struct { - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` - Port int `short:"p" long:"port" default:"-1" description:"The port to listen" ` - NoProxy bool `short:"n" long:"no-proxy" description:"True if proxy server should not be started. This will only update the main and routes files on change"` - } `command:"run"` + Run command.Run `command:"run"` // The package command - Package struct { - TargetPath string `short:"t" long:"target-path" description:"Full path and filename of target package to deploy" required:"false"` - Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - CopySource bool `short:"s" long:"include-source" description:"Copy the source code as well"` - } `command:"package"` + Package command.Package `command:"package"` // The clean command - Clean struct { - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - } `command:"clean"` + Clean command.Clean `command:"clean"` // The test command - Test struct { - Mode string `short:"m" long:"run-mode" description:"The mode to run the application in"` - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - Function string `short:"f" long:"suite-function" description:"The suite.function"` - } `command:"test"` + Test command.Test `command:"test"` // The version command - Version struct { - ImportPath string `short:"a" long:"application-path" description:"Path to application folder" required:"false"` - Update bool `short:"u" long:"Update the framework and modules" required:"false"` - } `command:"version"` + Version command.Version `command:"version"` } ) diff --git a/revel/clean.go b/revel/clean.go index 6f428bd..285ea93 100644 --- a/revel/clean.go +++ b/revel/clean.go @@ -8,7 +8,7 @@ import ( "fmt" "github.com/revel/cmd/model" "github.com/revel/cmd/utils" - "go/build" + "os" "path/filepath" ) @@ -50,14 +50,10 @@ func updateCleanConfig(c *model.CommandConfig, args []string) bool { // Clean the source directory of generated files func cleanApp(c *model.CommandConfig) (err error) { - appPkg, err := build.Import(c.ImportPath, "", build.FindOnly) - if err != nil { - utils.Logger.Fatal("Abort: Failed to find import path:", "error", err) - } purgeDirs := []string{ - filepath.Join(appPkg.Dir, "app", "tmp"), - filepath.Join(appPkg.Dir, "app", "routes"), + filepath.Join(c.AppPath, "app", "tmp"), + filepath.Join(c.AppPath, "app", "routes"), } for _, dir := range purgeDirs { From 86736d6e4389243875ecb03a33bb645d80633aa1 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sun, 26 Apr 2020 22:24:00 -0700 Subject: [PATCH 08/18] Updated formating Ran through testing individually for vendored Revel applications --- .codebeatsettings | 8 +-- harness/app.go | 20 +++---- harness/build.go | 72 +++++++++++++------------ logger/revel_logger.go | 6 +-- model/command/new.go | 3 ++ model/command_config.go | 60 ++++++++------------- model/source_info.go | 18 +++---- model/version.go | 16 +++--- parser2/source_info_processor.go | 39 +++++++------- parser2/source_processor.go | 10 ++-- revel/build.go | 10 ++-- revel/clean.go | 2 +- revel/new.go | 48 +++++++++-------- revel/new_test.go | 90 +++++++------------------------- revel/revel.go | 14 ++--- revel/run.go | 6 +-- revel/test.go | 10 ++-- revel/version.go | 22 ++++---- utils/build_error.go | 10 ++-- utils/command.go | 22 ++++---- utils/error.go | 4 +- utils/file.go | 40 +++++++------- 22 files changed, 239 insertions(+), 291 deletions(-) diff --git a/.codebeatsettings b/.codebeatsettings index a99f39e..b8c65b2 100644 --- a/.codebeatsettings +++ b/.codebeatsettings @@ -1,13 +1,13 @@ { "GOLANG": { - "ABC":[25, 35, 50, 70], + "ABC":[33, 38, 50, 70], "ARITY":[5,6,7,8], - "BLOCK_NESTING":[7, 9, 11, 13], - "CYCLO":[20, 30, 45, 60], + "BLOCK_NESTING":[9, 10, 12, 13], + "CYCLO":[30, 35, 45, 60], "TOO_MANY_IVARS": [20, 25, 40, 45], "TOO_MANY_FUNCTIONS": [20, 30, 40, 50], "TOTAL_COMPLEXITY": [150, 250, 400, 500], "LOC": [100, 175, 250, 320], "TOTAL_LOC": [300, 400, 500, 600] } -} \ No newline at end of file +} diff --git a/harness/app.go b/harness/app.go index 3b5475a..8fa1105 100644 --- a/harness/app.go +++ b/harness/app.go @@ -21,11 +21,11 @@ import ( // App contains the configuration for running a Revel app. (Not for the app itself) // Its only purpose is constructing the command to execute. type App struct { - BinaryPath string // Path to the app executable - Port int // Port to pass as a command line argument. - cmd AppCmd // The last cmd returned. + BinaryPath string // Path to the app executable + Port int // Port to pass as a command line argument. + cmd AppCmd // The last cmd returned. PackagePathMap map[string]string // Package to directory path map - Paths *model.RevelContainer + Paths *model.RevelContainer } // NewApp returns app instance with binary path in it @@ -65,7 +65,7 @@ func (cmd AppCmd) Start(c *model.CommandConfig) error { listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool), c, &bytes.Buffer{}} cmd.Stdout = listeningWriter utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env) - utils.CmdInit(cmd.Cmd, c.AppPath) + utils.CmdInit(cmd.Cmd, !c.Vendored, c.AppPath) if err := cmd.Cmd.Start(); err != nil { utils.Logger.Fatal("Error running:", "error", err) } @@ -73,9 +73,9 @@ func (cmd AppCmd) Start(c *model.CommandConfig) error { select { case exitState := <-cmd.waitChan(): fmt.Println("Startup failure view previous messages, \n Proxy is listening :", c.Run.Port) - err := utils.NewError("","Revel Run Error", "starting your application there was an exception. See terminal output, " + exitState,"") - // TODO pretiffy command line output - // err.MetaError = listeningWriter.getLastOutput() + err := utils.NewError("", "Revel Run Error", "starting your application there was an exception. See terminal output, " + exitState, "") + // TODO pretiffy command line output + // err.MetaError = listeningWriter.getLastOutput() return err case <-time.After(60 * time.Second): @@ -150,7 +150,7 @@ func (cmd AppCmd) Kill() { case <-ch: return case <-time.After(60 * time.Second): - // Kill the process + // Kill the process utils.Logger.Error( "Revel app failed to exit in 60 seconds - killing.", "processid", cmd.Process.Pid, @@ -199,7 +199,7 @@ func (w *startupListeningWriter) Write(p []byte) (int, error) { w.notifyReady = nil } } - if w.notifyReady!=nil { + if w.notifyReady != nil { w.buffer.Write(p) } return w.dest.Write(p) diff --git a/harness/build.go b/harness/build.go index 729fd15..c92dde0 100644 --- a/harness/build.go +++ b/harness/build.go @@ -29,9 +29,15 @@ var importErrorPattern = regexp.MustCompile("cannot find package \"([^\"]+)\"") type ByString []*model.TypeInfo -func (c ByString) Len() int { return len(c) } -func (c ByString) Swap(i, j int) { c[i], c[j] = c[j], c[i] } -func (c ByString) Less(i, j int) bool { return c[i].String() < c[j].String() } +func (c ByString) Len() int { + return len(c) +} +func (c ByString) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} +func (c ByString) Less(i, j int) bool { + return c[i].String() < c[j].String() +} // Build the app: // 1. Generate the the main.go file. @@ -116,8 +122,8 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err } } - // Binary path is a combination of BasePath/target directory, app's import path and its name. - binName := filepath.Join(paths.BasePath, "target", paths.ImportPath, filepath.Base(paths.BasePath)) + // Binary path is a combination of BasePath/target/app directory, app's import path and its name. + binName := filepath.Join(paths.BasePath, "target", "app", paths.ImportPath, filepath.Base(paths.BasePath)) // Change binary path for Windows build goos := runtime.GOOS @@ -139,14 +145,10 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err } for { - appVersion := getAppVersion(paths) - if appVersion == "" { - appVersion = "noVersionProvided" - } buildTime := time.Now().UTC().Format(time.RFC3339) - versionLinkerFlags := fmt.Sprintf("-X '%s/app.AppVersion=%s' -X '%s/app.BuildTime=%s'", + versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s", paths.ImportPath, appVersion, paths.ImportPath, buildTime) // Append any build flags specified, they will override existing flags @@ -161,13 +163,9 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err if !contains(c.BuildFlags, "build") { flags = []string{"build"} } + flags = append(flags, c.BuildFlags...) if !contains(flags, "-ldflags") { - ldflags := "-ldflags= " + versionLinkerFlags - // Add in build flags - for i := range c.BuildFlags { - ldflags += "-X '" + c.BuildFlags[i] + "'" - } - flags = append(flags, ldflags) + flags = append(flags, "-ldflags", versionLinkerFlags) } if !contains(flags, "-tags") { flags = append(flags, "-tags", buildTags) @@ -177,31 +175,38 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err } } - // This is Go main path - gopath := c.GoPath - for _, o := range paths.ModulePathMap { - gopath += string(filepath.ListSeparator) + o.Path - } + // Add in build flags + flags = append(flags, c.BuildFlags...) // Note: It's not applicable for filepath.* usage flags = append(flags, path.Join(paths.ImportPath, "app", "tmp")) buildCmd := exec.Command(goPath, flags...) - buildCmd.Env = append(os.Environ(), - "GOPATH="+gopath, - ) - utils.CmdInit(buildCmd, c.AppPath) - utils.Logger.Info("Exec:", "args", buildCmd.Args,"working dir", buildCmd.Dir) + if !c.Vendored { + // This is Go main path + gopath := c.GoPath + for _, o := range paths.ModulePathMap { + gopath += string(filepath.ListSeparator) + o.Path + } + + buildCmd.Env = append(os.Environ(), + "GOPATH=" + gopath, + ) + } + utils.CmdInit(buildCmd, !c.Vendored, c.AppPath) + + utils.Logger.Info("Exec:", "args", buildCmd.Args, "working dir", buildCmd.Dir) output, err := buildCmd.CombinedOutput() // If the build succeeded, we're done. if err == nil { utils.Logger.Info("Build successful continuing") - return NewApp(binName, paths,sourceInfo.PackageMap), nil + return NewApp(binName, paths, sourceInfo.PackageMap), nil } // Since there was an error, capture the output in case we need to report it stOutput := string(output) + utils.Logger.Infof("Got error on build of app %s", stOutput) // See if it was an import error that we can go get. matches := importErrorPattern.FindAllStringSubmatch(stOutput, -1) @@ -253,7 +258,7 @@ func getAppVersion(paths *model.RevelContainer) string { if (err != nil && os.IsNotExist(err)) || !info.IsDir() { return "" } - gitCmd := exec.Command(gitPath, "--git-dir="+gitDir, "--work-tree="+paths.BasePath, "describe", "--always", "--dirty") + gitCmd := exec.Command(gitPath, "--git-dir=" + gitDir, "--work-tree=" + paths.BasePath, "describe", "--always", "--dirty") utils.Logger.Info("Exec:", "args", gitCmd.Args) output, err := gitCmd.Output() @@ -418,12 +423,13 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.SourceEr return newPath } + // Read the source for the offending file. var ( - relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go" - absFilename = findInPaths(relFilename) - line, _ = strconv.Atoi(string(errorMatch[2])) - description = string(errorMatch[4]) + relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go" + absFilename = findInPaths(relFilename) + line, _ = strconv.Atoi(string(errorMatch[2])) + description = string(errorMatch[4]) compileError = &utils.SourceError{ SourceType: "Go code", Title: "Go Compilation Error", @@ -442,7 +448,7 @@ func newCompileError(paths *model.RevelContainer, output []byte) *utils.SourceEr fileStr, err := utils.ReadLines(absFilename) if err != nil { compileError.MetaError = absFilename + ": " + err.Error() - utils.Logger.Info("Unable to readlines "+compileError.MetaError, "error", err) + utils.Logger.Info("Unable to readlines " + compileError.MetaError, "error", err) return compileError } diff --git a/logger/revel_logger.go b/logger/revel_logger.go index 3010d49..0097421 100644 --- a/logger/revel_logger.go +++ b/logger/revel_logger.go @@ -99,7 +99,7 @@ func (c callHandler) Log(log *log15.Record) error { ctx := log.Ctx var ctxMap ContextMap if len(ctx) > 0 { - ctxMap = make(ContextMap, len(ctx)/2) + ctxMap = make(ContextMap, len(ctx) / 2) for i := 0; i < len(ctx); i += 2 { v := ctx[i] @@ -108,8 +108,8 @@ func (c callHandler) Log(log *log15.Record) error { key = fmt.Sprintf("LOGGER_INVALID_KEY %v", v) } var value interface{} - if len(ctx) > i+1 { - value = ctx[i+1] + if len(ctx) > i + 1 { + value = ctx[i + 1] } else { value = "LOGGER_VALUE_MISSING" } diff --git a/model/command/new.go b/model/command/new.go index 25f3de2..66d88fb 100644 --- a/model/command/new.go +++ b/model/command/new.go @@ -1,4 +1,6 @@ package command + + type ( New struct { ImportCommand @@ -6,6 +8,7 @@ type ( Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` NotVendored bool `short:"V" long:"vendor" description:"True if project should not be configured with a go.mod"` Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` + Callback func() error } ) \ No newline at end of file diff --git a/model/command_config.go b/model/command_config.go index db248f3..db4ebc9 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -177,7 +177,7 @@ func (c *CommandConfig) initAppFolder() (err error) { appFolder = filepath.Join(wd,appFolder) } - utils.Logger.Info("Determined app folder to be", "folder",appFolder, "working",wd) + utils.Logger.Info("Determined app folder to be", "appfolder",appFolder, "working",wd,"importPath",c.ImportPath) // Use app folder to read the go.mod if it exists and extract the package information goModFile := filepath.Join(appFolder,"go.mod") @@ -214,24 +214,29 @@ func (c *CommandConfig) initAppFolder() (err error) { workingDir, _ := os.Getwd() goPathList := filepath.SplitList(c.GoPath) bestpath := "" - for _, path := range goPathList { - if c.Index == NEW { - // If the GOPATH is part of the working dir this is the most likely target - if strings.HasPrefix(workingDir, path) { - bestpath = path - } - } else { - if utils.Exists(filepath.Join(path, "src", c.ImportPath)) { - c.SrcRoot = path - break + if !c.Vendored { + for _, path := range goPathList { + if c.Index == NEW { + // If the GOPATH is part of the working dir this is the most likely target + if strings.HasPrefix(workingDir, path) { + bestpath = path + } + } else { + if utils.Exists(filepath.Join(path, "src", c.ImportPath)) { + c.SrcRoot = path + break + } } } + if len(c.SrcRoot) == 0 && len(bestpath) > 0 { + c.SrcRoot = bestpath + } + + } else { + c.SrcRoot = appFolder } utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath",bestpath) - if len(c.SrcRoot) == 0 && len(bestpath) > 0 { - c.SrcRoot = bestpath - } // If source root is empty and this isn't a version then skip it if len(c.SrcRoot) == 0 { @@ -270,32 +275,11 @@ func (c *CommandConfig) InitPackageResolver() { utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored) if c.Vendored { goModCmd := exec.Command("go", "mod", "tidy") - utils.CmdInit(goModCmd, c.AppPath) + utils.CmdInit(goModCmd,!c.Vendored, c.AppPath) + goModCmd.Run() return nil } - //utils.Logger.Info("Using dependency manager to import package", "package", pkgName) - // - //// Check to see if the package exists locally - //_, err := build.Import(pkgName, c.AppPath, build.FindOnly) - //if err != nil { - // getCmd = exec.Command(depPath, "ensure", "-add", pkgName) - //} else { - // getCmd = exec.Command(depPath, "ensure", "-update", pkgName) - //} - // - // - //} else { - // utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName) - // getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName) - //} - // - //utils.CmdInit(getCmd, c.AppPath) - //utils.Logger.Info("Go get command ", "exec", getCmd.Path, "dir", getCmd.Dir, "args", getCmd.Args, "env", getCmd.Env, "package", pkgName) - //output, err := getCmd.CombinedOutput() - //if err != nil { - // fmt.Printf("Error stack %v\n", logger.NewCallStack()) - // utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output)) - //} + return nil } } diff --git a/model/source_info.go b/model/source_info.go index 88ed26f..836f004 100644 --- a/model/source_info.go +++ b/model/source_info.go @@ -12,14 +12,14 @@ import ( type SourceInfo struct { // StructSpecs lists type info for all structs found under the code paths. // They may be queried to determine which ones (transitively) embed certain types. - StructSpecs []*TypeInfo + StructSpecs []*TypeInfo // ValidationKeys provides a two-level lookup. The keys are: // 1. The fully-qualified function name, // e.g. "github.com/revel/examples/chat/app/controllers.(*Application).Action" // 2. Within that func's file, the line number of the (overall) expression statement. // e.g. the line returned from runtime.Caller() // The result of the lookup the name of variable being validated. - ValidationKeys map[string]map[int]string + ValidationKeys map[string]map[int]string // A list of import paths. // Revel notices files with an init() function and imports that package. InitImportPaths []string @@ -28,9 +28,9 @@ type SourceInfo struct { // app/controllers/... that embed (directly or indirectly) revel.Controller controllerSpecs []*TypeInfo // testSuites list the types that constitute the set of application tests. - testSuites []*TypeInfo + testSuites []*TypeInfo // packageMap a map of import to system directory (if available) - PackageMap map[string]string + PackageMap map[string]string } // TypesThatEmbed returns all types that (directly or indirectly) embed the @@ -76,7 +76,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered utils.Logger.Info("Debug: Skipping adding spec for unexported type", "type", filteredItem.StructName, "package", filteredItem.ImportPath) - filtered = append(filtered[:i], filtered[i+1:]...) + filtered = append(filtered[:i], filtered[i + 1:]...) exit = false break } @@ -99,8 +99,8 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered // Report non controller structures in controller folder. if !found && !strings.HasPrefix(spec.StructName, "Test") { - utils.Logger.Warn("Type found in package: "+packageFilter+ - ", but did not embed from: "+filepath.Base(targetType), + utils.Logger.Warn("Type found in package: " + packageFilter + + ", but did not embed from: " + filepath.Base(targetType), "name", spec.StructName, "importpath", spec.ImportPath, "foundstructures", unfoundNames) } } @@ -112,7 +112,7 @@ func (s *SourceInfo) TypesThatEmbed(targetType, packageFilter string) (filtered // `revel.Controller` func (s *SourceInfo) ControllerSpecs() []*TypeInfo { if s.controllerSpecs == nil { - s.controllerSpecs = s.TypesThatEmbed(RevelImportPath+".Controller", "controllers") + s.controllerSpecs = s.TypesThatEmbed(RevelImportPath + ".Controller", "controllers") } return s.controllerSpecs } @@ -121,7 +121,7 @@ func (s *SourceInfo) ControllerSpecs() []*TypeInfo { // `testing.TestSuite` func (s *SourceInfo) TestSuites() []*TypeInfo { if s.testSuites == nil { - s.testSuites = s.TypesThatEmbed(RevelImportPath+"/testing.TestSuite", "testsuite") + s.testSuites = s.TypesThatEmbed(RevelImportPath + "/testing.TestSuite", "testsuite") } return s.testSuites } diff --git a/model/version.go b/model/version.go index bc52654..6016285 100644 --- a/model/version.go +++ b/model/version.go @@ -8,20 +8,20 @@ import ( ) type Version struct { - Prefix string - Major int - Minor int - Maintenance int - Suffix string - BuildDate string + Prefix string + Major int + Minor int + Maintenance int + Suffix string + BuildDate string MinGoVersion string } // The compatibility list var frameworkCompatibleRangeList = [][]string{ {"0.0.0", "0.20.0"}, // minimum Revel version to use with this version of the tool - {"0.19.99", "0.30.0"}, // Compatible with Framework V 0.19.99 - 0.30.0 - {"1.0.0", "1.1.0"}, // Compatible with Framework V 1.0 - 1.1 + {"0.19.99", "0.30.0"}, // Compatible with Framework V 0.19.99 - 0.30.0 + {"1.0.0", "1.1.0"}, // Compatible with Framework V 1.0 - 1.1 } // Parses a version like v1.2.3a or 1.2 diff --git a/parser2/source_info_processor.go b/parser2/source_info_processor.go index 6d8a1c0..e0e4141 100644 --- a/parser2/source_info_processor.go +++ b/parser2/source_info_processor.go @@ -15,23 +15,23 @@ type ( sourceProcessor *SourceProcessor } ) + func NewSourceInfoProcessor(sourceProcessor *SourceProcessor) *SourceInfoProcessor { return &SourceInfoProcessor{sourceProcessor:sourceProcessor} } - func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *model.SourceInfo) { sourceInfo = &model.SourceInfo{ ValidationKeys: map[string]map[int]string{}, } var ( - isController = strings.HasSuffix(p.PkgPath, "/controllers") || - strings.Contains(p.PkgPath, "/controllers/") - isTest = strings.HasSuffix(p.PkgPath, "/tests") || - strings.Contains(p.PkgPath, "/tests/") + isController = strings.HasSuffix(p.PkgPath, "/controllers") || + strings.Contains(p.PkgPath, "/controllers/") + isTest = strings.HasSuffix(p.PkgPath, "/tests") || + strings.Contains(p.PkgPath, "/tests/") methodMap = map[string][]*model.MethodSpec{} ) - for _,tree := range p.Syntax { + for _, tree := range p.Syntax { for _, decl := range tree.Decls { s.sourceProcessor.packageMap[p.PkgPath] = filepath.Dir(p.Fset.Position(decl.Pos()).Filename) //println("*** checking", p.Fset.Position(decl.Pos()).Filename) @@ -50,20 +50,21 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m } // This could be a controller action endpoint, check and add if needed if isController && - funcDecl.Recv!=nil && // Must have a receiver + funcDecl.Recv != nil && // Must have a receiver funcDecl.Name.IsExported() && // be public - funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) == 1 { // return one result - if m, receiver:=s.getControllerFunc(funcDecl,p);m!=nil { - methodMap[receiver]=append(methodMap[receiver],m) - s.sourceProcessor.log.Info("Added method map to ","receiver",receiver,"method",m.Name) + funcDecl.Type.Results != nil && len(funcDecl.Type.Results.List) == 1 { + // return one result + if m, receiver := s.getControllerFunc(funcDecl, p); m != nil { + methodMap[receiver] = append(methodMap[receiver], m) + s.sourceProcessor.log.Info("Added method map to ", "receiver", receiver, "method", m.Name) } } // Check for validation - if lineKeyMap := s.getValidation(funcDecl,p);len(lineKeyMap)>1 { - sourceInfo.ValidationKeys[p.PkgPath+"."+s.getFuncName(funcDecl)] = lineKeyMap + if lineKeyMap := s.getValidation(funcDecl, p); len(lineKeyMap) > 1 { + sourceInfo.ValidationKeys[p.PkgPath + "." + s.getFuncName(funcDecl)] = lineKeyMap } if funcDecl.Name.Name == "init" { - sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths,p.PkgPath) + sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths, p.PkgPath) } } } @@ -90,7 +91,7 @@ func (s *SourceInfoProcessor) processPackage(p *packages.Package) (sourceInfo *m // // The end result is that we can set the default validation key for each call to // be the same as the local variable. -func (s *SourceInfoProcessor) getValidation(funcDecl *ast.FuncDecl,p *packages.Package) (map[int]string) { +func (s *SourceInfoProcessor) getValidation(funcDecl *ast.FuncDecl, p *packages.Package) (map[int]string) { var ( lineKeys = make(map[int]string) @@ -182,7 +183,7 @@ func (s *SourceInfoProcessor) getValidationParameter(funcDecl *ast.FuncDecl) *a } return nil } -func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl,p *packages.Package) (method *model.MethodSpec, recvTypeName string) { +func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl, p *packages.Package) (method *model.MethodSpec, recvTypeName string) { selExpr, ok := funcDecl.Type.Results.List[0].Type.(*ast.SelectorExpr) if !ok { return @@ -270,7 +271,7 @@ func (s *SourceInfoProcessor) getControllerFunc(funcDecl *ast.FuncDecl,p *packag } return } -func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec,p *packages.Package) (controllerSpec *model.TypeInfo) { +func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec, p *packages.Package) (controllerSpec *model.TypeInfo) { structType := spec.Type.(*ast.StructType) // At this point we know it's a type declaration for a struct. @@ -329,7 +330,7 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec,p *packages.P } else { var ok bool if importPath, ok = s.sourceProcessor.importMap[pkgName]; !ok { - s.sourceProcessor.log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map",s.sourceProcessor.importMap) + s.sourceProcessor.log.Error("Error: Failed to find import path for ", "package", pkgName, "type", typeName, "map", s.sourceProcessor.importMap) continue } } @@ -339,7 +340,7 @@ func (s *SourceInfoProcessor) getControllerSpec(spec *ast.TypeSpec,p *packages.P StructName: typeName, }) } - s.sourceProcessor.log.Info("Added controller spec", "name",controllerSpec.StructName,"package",controllerSpec.ImportPath) + s.sourceProcessor.log.Info("Added controller spec", "name", controllerSpec.StructName, "package", controllerSpec.ImportPath) return } func (s *SourceInfoProcessor) getStructTypeDecl(decl ast.Decl, fset *token.FileSet) (spec *ast.TypeSpec, found bool) { diff --git a/parser2/source_processor.go b/parser2/source_processor.go index 2811da1..d7499ee 100644 --- a/parser2/source_processor.go +++ b/parser2/source_processor.go @@ -18,7 +18,7 @@ type ( log logger.MultiLogger packageList []*packages.Package importMap map[string]string - packageMap map[string]string + packageMap map[string]string sourceInfoProcessor *SourceInfoProcessor sourceInfo *model.SourceInfo } @@ -29,8 +29,8 @@ func ProcessSource(revelContainer *model.RevelContainer) (sourceInfo *model.Sour processor := NewSourceProcessor(revelContainer) compileError = processor.parse() sourceInfo = processor.sourceInfo - if compileError==nil { - processor.log.Infof("From parsers : Structures:%d InitImports:%d ValidationKeys:%d %v", len(sourceInfo.StructSpecs), len(sourceInfo.InitImportPaths), len(sourceInfo.ValidationKeys),sourceInfo.PackageMap) + if compileError == nil { + processor.log.Infof("From parsers : Structures:%d InitImports:%d ValidationKeys:%d %v", len(sourceInfo.StructSpecs), len(sourceInfo.InitImportPaths), len(sourceInfo.ValidationKeys), sourceInfo.PackageMap) } if false { @@ -58,7 +58,7 @@ func (s *SourceProcessor) parse() (compileError error) { s.sourceInfo.PackageMap = map[string]string{} getImportFromMap := func(packagePath string) string { for path := range s.packageMap { - if strings.Index(path,packagePath)==0 { + if strings.Index(path, packagePath) == 0 { fullPath := s.packageMap[path] return fullPath[:(len(fullPath) - len(path) + len(packagePath))] } @@ -74,7 +74,7 @@ func (s *SourceProcessor) parse() (compileError error) { return } func (s *SourceProcessor) addPackages() (err error) { - allPackages := []string{s.revelContainer.ImportPath + "/...",model.RevelImportPath} + allPackages := []string{s.revelContainer.ImportPath + "/...", model.RevelImportPath} for _, module := range s.revelContainer.ModulePathMap { allPackages = append(allPackages, module.ImportPath + "/...") // +"/app/controllers/...") } diff --git a/revel/build.go b/revel/build.go index 3bba537..9e43f69 100644 --- a/revel/build.go +++ b/revel/build.go @@ -37,10 +37,10 @@ func init() { // The update config updates the configuration command so that it can run func updateBuildConfig(c *model.CommandConfig, args []string) bool { c.Index = model.BUILD - if c.Build.TargetPath=="" { - c.Build.TargetPath="target" + if c.Build.TargetPath == "" { + c.Build.TargetPath = "target" } - if len(args)==0 && c.Build.ImportPath!="" { + if len(args) == 0 && c.Build.ImportPath != "" { return true } // If arguments were passed in then there must be two @@ -176,13 +176,13 @@ func buildCopyModules(c *model.CommandConfig, revel_paths *model.RevelContainer, if moduleImportPath == "" { continue } - moduleImportList =append(moduleImportList,moduleImportPath) + moduleImportList = append(moduleImportList, moduleImportPath) } } // Copy the the paths for each of the modules - for _,importPath := range moduleImportList { + for _, importPath := range moduleImportList { fsPath := app.PackagePathMap[importPath] utils.Logger.Info("Copy files ", "to", filepath.Join(destPath, importPath), "from", fsPath) if c.Build.CopySource { diff --git a/revel/clean.go b/revel/clean.go index 285ea93..ebbae09 100644 --- a/revel/clean.go +++ b/revel/clean.go @@ -37,7 +37,7 @@ func init() { // Update the clean command configuration, using old method func updateCleanConfig(c *model.CommandConfig, args []string) bool { c.Index = model.CLEAN - if len(args)==0 && c.Clean.ImportPath!="" { + if len(args) == 0 && c.Clean.ImportPath != "" { return true } if len(args) == 0 { diff --git a/revel/new.go b/revel/new.go index ae8941f..147d08a 100644 --- a/revel/new.go +++ b/revel/new.go @@ -46,13 +46,13 @@ func init() { // Called when unable to parse the command line automatically and assumes an old launch func updateNewConfig(c *model.CommandConfig, args []string) bool { c.Index = model.NEW - if len(c.New.Package)>0 { + if len(c.New.Package) > 0 { c.New.NotVendored = false } c.Vendored = !c.New.NotVendored if len(args) == 0 { - if len(c.New.ImportPath)==0 { + if len(c.New.ImportPath) == 0 { fmt.Fprintf(os.Stderr, cmdNew.Long) return false } @@ -76,7 +76,7 @@ func newApp(c *model.CommandConfig) (err error) { } // checking and setting skeleton - if err=setSkeletonPath(c);err!=nil { + if err = setSkeletonPath(c); err != nil { return } @@ -90,18 +90,20 @@ func newApp(c *model.CommandConfig) (err error) { return err } - // At this point the versions can be set - c.SetVersions() + // This kicked off the download of the revel app, not needed for vendor + if !c.Vendored { + // At this point the versions can be set + c.SetVersions() + } // copy files to new app directory - if err = copyNewAppFiles(c);err != nil { + if err = copyNewAppFiles(c); err != nil { return } // Run the vendor tool if needed - println("********** here",c.Vendored) if c.Vendored { - if err=createModVendor(c); err!=nil { + if err = createModVendor(c); err != nil { return } } @@ -120,13 +122,15 @@ func newApp(c *model.CommandConfig) (err error) { func createModVendor(c *model.CommandConfig) (err error) { utils.Logger.Info("Creating a new mod app") - goModCmd := exec.Command("go", "mod", "init", filepath.Join(c.New.Package,c.AppName)) + goModCmd := exec.Command("go", "mod", "init", filepath.Join(c.New.Package, c.AppName)) + utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) - utils.CmdInit(goModCmd, c.AppPath) - - utils.Logger.Info("Exec:", "args", goModCmd.Args, "env", goModCmd.Env, "workingdir",goModCmd.Dir) + utils.Logger.Info("Exec:", "args", goModCmd.Args, "env", goModCmd.Env, "workingdir", goModCmd.Dir) getOutput, err := goModCmd.CombinedOutput() + if c.New.Callback != nil { + err = c.New.Callback() + } if err != nil { return utils.NewBuildIfError(err, string(getOutput)) } @@ -141,7 +145,7 @@ func createDepVendor(c *model.CommandConfig) (err error) { if !utils.DirExists(vendorPath) { if err := os.MkdirAll(vendorPath, os.ModePerm); err != nil { - return utils.NewBuildError("Failed to create "+vendorPath, "error", err) + return utils.NewBuildError("Failed to create " + vendorPath, "error", err) } } @@ -150,11 +154,11 @@ func createDepVendor(c *model.CommandConfig) (err error) { utils.Logger.Info("Checking for temp folder for source code", "path", tempPath) if !utils.DirExists(tempPath) { if err := os.MkdirAll(tempPath, os.ModePerm); err != nil { - return utils.NewBuildIfError(err, "Failed to create "+vendorPath) + return utils.NewBuildIfError(err, "Failed to create " + vendorPath) } if err = utils.GenerateTemplate(filepath.Join(tempPath, "main.go"), NEW_MAIN_FILE, nil); err != nil { - return utils.NewBuildIfError(err, "Failed to create main file "+vendorPath) + return utils.NewBuildIfError(err, "Failed to create main file " + vendorPath) } } @@ -171,9 +175,9 @@ func createDepVendor(c *model.CommandConfig) (err error) { } getCmd := exec.Command("dep", "ensure", "-v") - utils.CmdInit(getCmd, c.AppPath) + utils.CmdInit(getCmd, !c.Vendored, c.AppPath) - utils.Logger.Info("Exec:", "args", getCmd.Args, "env", getCmd.Env, "workingdir",getCmd.Dir) + utils.Logger.Info("Exec:", "args", getCmd.Args, "env", getCmd.Env, "workingdir", getCmd.Dir) getOutput, err := getCmd.CombinedOutput() if err != nil { return utils.NewBuildIfError(err, string(getOutput)) @@ -211,7 +215,7 @@ func setApplicationPath(c *model.CommandConfig) (err error) { //// Go get the revel project err = c.PackageResolver(model.RevelImportPath) if err != nil { - return utils.NewBuildIfError(err, "Failed to fetch revel "+model.RevelImportPath) + return utils.NewBuildIfError(err, "Failed to fetch revel " + model.RevelImportPath) } } } @@ -235,13 +239,13 @@ func setSkeletonPath(c *model.CommandConfig) (err error) { switch strings.ToLower(sp.Scheme) { // TODO Add support for ftp, sftp, scp ?? case "" : - sp.Scheme="file" + sp.Scheme = "file" fallthrough case "file" : fullpath := sp.String()[7:] if !filepath.IsAbs(fullpath) { fullpath, err = filepath.Abs(fullpath) - if err!=nil { + if err != nil { return } } @@ -276,11 +280,11 @@ func newLoadFromGit(c *model.CommandConfig, sp *url.URL) (err error) { targetPath := filepath.Join(os.TempDir(), "revel", "skeleton") os.RemoveAll(targetPath) pathpart := strings.Split(sp.Path, ":") - getCmd := exec.Command("git", "clone", sp.Scheme+"://"+sp.Host+pathpart[0], targetPath) + getCmd := exec.Command("git", "clone", sp.Scheme + "://" + sp.Host + pathpart[0], targetPath) utils.Logger.Info("Exec:", "args", getCmd.Args) getOutput, err := getCmd.CombinedOutput() if err != nil { - utils.Logger.Fatal("Abort: could not clone the Skeleton source code: ","output", string(getOutput), "path", c.New.SkeletonPath) + utils.Logger.Fatal("Abort: could not clone the Skeleton source code: ", "output", string(getOutput), "path", c.New.SkeletonPath) } outputPath := targetPath if len(pathpart) > 1 { diff --git a/revel/new_test.go b/revel/new_test.go index 31aa2b4..f0cb757 100644 --- a/revel/new_test.go +++ b/revel/new_test.go @@ -3,95 +3,42 @@ package main_test import ( "github.com/revel/cmd/model" "github.com/revel/cmd/revel" - "github.com/revel/cmd/utils" "github.com/stretchr/testify/assert" - "io/ioutil" "os" - "path/filepath" "testing" ) // test the commands func TestNew(t *testing.T) { a := assert.New(t) - gopath := setup("revel-test-new", a) + gopath := setup("revel-test-new", a) - t.Run("New", func(t *testing.T) { - a := assert.New(t) - c := newApp("new-test", model.NEW, nil, a) - a.Nil(main.Commands[model.NEW].RunWith(c), "New failed") - }) - t.Run("Path", func(t *testing.T) { - a := assert.New(t) - c := newApp("new/test/a", model.NEW, nil, a) - a.Nil(main.Commands[model.NEW].RunWith(c), "New path failed") - }) - t.Run("Path-Duplicate", func(t *testing.T) { - a := assert.New(t) - c := newApp("new/test/b", model.NEW, nil, a) - a.Nil(main.Commands[model.NEW].RunWith(c), "New path failed") - c = newApp("new/test/b", model.NEW, nil, a) - a.NotNil(main.Commands[model.NEW].RunWith(c), "Duplicate path Did Not failed") - }) - t.Run("Skeleton-Git", func(t *testing.T) { - a := assert.New(t) - c := newApp("new/test/c/1", model.NEW, nil, a) - c.New.SkeletonPath = "git://github.com/revel/skeletons:basicnsadnsak" - a.NotNil(main.Commands[model.NEW].RunWith(c), "Expected Failed to run with new") - // We need to pick a different path - c = newApp("new/test/c/2", model.NEW, nil, a) - c.New.SkeletonPath = "git://github.com/revel/skeletons:basic/bootstrap4" - a.Nil(main.Commands[model.NEW].RunWith(c), "Failed to run with new skeleton git") - }) - if !t.Failed() { - if err := os.RemoveAll(gopath); err != nil { - a.Fail("Failed to remove test path") - } - } -} - -// test the commands -func TestNewVendor(t *testing.T) { - a := assert.New(t) - gopath := setup("revel-test-new-vendor", a) - precall := func(c *model.CommandConfig) { - c.New.DepVendored = true - } t.Run("New", func(t *testing.T) { a := assert.New(t) - c := newApp("onlyone/v/a", model.NEW, precall, a) - c.New.DepVendored = true + c := newApp("new-test", model.NEW, nil, a) a.Nil(main.Commands[model.NEW].RunWith(c), "New failed") }) - t.Run("Test", func(t *testing.T) { + t.Run("Path", func(t *testing.T) { a := assert.New(t) - c := newApp("onlyone/v/a", model.TEST, nil, a) - a.Nil(main.Commands[model.TEST].RunWith(c), "Test failed") + c := newApp("new/test/a", model.NEW, nil, a) + a.Nil(main.Commands[model.NEW].RunWith(c), "New path failed") }) - t.Run("Build", func(t *testing.T) { + t.Run("Path-Duplicate", func(t *testing.T) { a := assert.New(t) - c := newApp("onlyone/v/a", model.BUILD, nil, a) - c.Index = model.BUILD - c.Build.TargetPath = filepath.Join(gopath, "src/onlyone/v/a", "target") - a.Nil(main.Commands[model.BUILD].RunWith(c), " Build failed") - a.True(utils.DirExists(c.Build.TargetPath), "Target folder not made", c.Build.TargetPath) + c := newApp("new/test/b", model.NEW, nil, a) + a.Nil(main.Commands[model.NEW].RunWith(c), "New path failed") + c = newApp("new/test/b", model.NEW, nil, a) + a.NotNil(main.Commands[model.NEW].RunWith(c), "Duplicate path Did Not failed") }) - t.Run("Package", func(t *testing.T) { + t.Run("Skeleton-Git", func(t *testing.T) { a := assert.New(t) - c := newApp("onlyone/v/a", model.PACKAGE, nil, a) - c.Package.TargetPath = filepath.Join(gopath, "src/onlyone/v/a", "target.tar.gz") - a.Nil(main.Commands[model.PACKAGE].RunWith(c), "Package Failed") - a.True(utils.Exists(c.Package.TargetPath), "Target package not made", c.Package.TargetPath) - }) - t.Run("TestVendorDir", func(t *testing.T) { - // Check to see that no additional packages were downloaded outside the vendor folder - files, err := ioutil.ReadDir(gopath) - a.Nil(err, "Failed to read gopath folder") - // bin/ onlyone/ pkg/ src/ - a.Equal(3, len(files), "Expected single file in "+gopath) - files, err = ioutil.ReadDir(filepath.Join(gopath, "src")) - a.Nil(err, "Failed to read src folder") - a.Equal(1, len(files), "Expected single file in source folder", filepath.Join(gopath, "src")) + c := newApp("new/test/c/1", model.NEW, nil, a) + c.New.SkeletonPath = "git://github.com/revel/skeletons:basicnsadnsak" + a.NotNil(main.Commands[model.NEW].RunWith(c), "Expected Failed to run with new") + // We need to pick a different path + c = newApp("new/test/c/2", model.NEW, nil, a) + c.New.SkeletonPath = "git://github.com/revel/skeletons:basic/bootstrap4" + a.Nil(main.Commands[model.NEW].RunWith(c), "Failed to run with new skeleton git") }) if !t.Failed() { if err := os.RemoveAll(gopath); err != nil { @@ -99,3 +46,4 @@ func TestNewVendor(t *testing.T) { } } } + diff --git a/revel/revel.go b/revel/revel.go index c783e4e..2c32df5 100644 --- a/revel/revel.go +++ b/revel/revel.go @@ -71,27 +71,27 @@ func main() { wd, _ := os.Getwd() utils.InitLogger(wd, logger.LvlError) - parser := flags.NewParser(c, flags.HelpFlag|flags.PassDoubleDash) - if len(os.Args)<2 { + parser := flags.NewParser(c, flags.HelpFlag | flags.PassDoubleDash) + if len(os.Args) < 2 { parser.WriteHelp(os.Stdout) os.Exit(1) } if err := ParseArgs(c, parser, os.Args[1:]); err != nil { - fmt.Fprint(os.Stderr, err.Error() +"\n") + fmt.Fprint(os.Stderr, err.Error() + "\n") os.Exit(1) } // Switch based on the verbose flag - if len(c.Verbose)>1 { + if len(c.Verbose) > 1 { utils.InitLogger(wd, logger.LvlDebug) - } else if len(c.Verbose)>0 { + } else if len(c.Verbose) > 0 { utils.InitLogger(wd, logger.LvlInfo) } else { utils.InitLogger(wd, logger.LvlWarn) } - if err := c.UpdateImportPath();err!=nil { + if err := c.UpdateImportPath(); err != nil { utils.Logger.Error(err.Error()) parser.WriteHelp(os.Stdout) os.Exit(1) @@ -107,7 +107,7 @@ func main() { c.InitPackageResolver() if err := command.RunWith(c); err != nil { - utils.Logger.Error("Unable to execute","error",err) + utils.Logger.Error("Unable to execute", "error", err) os.Exit(1) } } diff --git a/revel/run.go b/revel/run.go index 85c9d3f..c996ae2 100644 --- a/revel/run.go +++ b/revel/run.go @@ -106,7 +106,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool { } case 0: // Attempt to set the import path to the current working director. - if c.Run.ImportPath=="" { + if c.Run.ImportPath == "" { c.Run.ImportPath, _ = os.Getwd() } } @@ -116,7 +116,7 @@ func updateRunConfig(c *model.CommandConfig, args []string) bool { // Returns true if this is an absolute path or a relative gopath func runIsImportPath(pathToCheck string) bool { - if _, err := build.Import(pathToCheck, "", build.FindOnly);err==nil { + if _, err := build.Import(pathToCheck, "", build.FindOnly); err == nil { return true } return filepath.IsAbs(pathToCheck) @@ -160,7 +160,7 @@ func runApp(c *model.CommandConfig) (err error) { } app.Port = revel_path.HTTPPort var paths []byte - if len(app.PackagePathMap)>0 { + if len(app.PackagePathMap) > 0 { paths, _ = json.Marshal(app.PackagePathMap) } runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose, string(paths)) diff --git a/revel/test.go b/revel/test.go index abeb35b..a82fb6b 100644 --- a/revel/test.go +++ b/revel/test.go @@ -55,7 +55,7 @@ func init() { // Called to update the config command with from the older stype func updateTestConfig(c *model.CommandConfig, args []string) bool { c.Index = model.TEST - if len(args)==0 && c.Test.ImportPath!="" { + if len(args) == 0 && c.Test.ImportPath != "" { return true } @@ -99,7 +99,7 @@ func testApp(c *model.CommandConfig) (err error) { } // Direct all the output into a file in the test-results directory. - file, err := os.OpenFile(filepath.Join(resultPath, "app.log"), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + file, err := os.OpenFile(filepath.Join(resultPath, "app.log"), os.O_CREATE | os.O_WRONLY | os.O_APPEND, 0666) if err != nil { return utils.NewBuildError("Failed to create test result log file: ", "error", err) } @@ -109,7 +109,7 @@ func testApp(c *model.CommandConfig) (err error) { return utils.NewBuildIfError(reverr, "Error building: ") } var paths []byte - if len(app.PackagePathMap)>0 { + if len(app.PackagePathMap) > 0 { paths, _ = json.Marshal(app.PackagePathMap) } runMode := fmt.Sprintf(`{"mode":"%s", "specialUseFlag":%v,"packagePathMap":%s}`, app.Paths.RunMode, c.Verbose, string(paths)) @@ -117,7 +117,7 @@ func testApp(c *model.CommandConfig) (err error) { runMode = app.Paths.RunMode } cmd := app.Cmd(runMode) - cmd.Dir=c.AppPath + cmd.Dir = c.AppPath cmd.Stderr = io.MultiWriter(cmd.Stderr, file) cmd.Stdout = io.MultiWriter(cmd.Stderr, file) @@ -234,7 +234,7 @@ func filterTestSuites(suites *[]tests.TestSuiteDesc, suiteArgument string) *[]te // in case it hasn't finished starting up yet. func getTestsList(baseURL string) (*[]tests.TestSuiteDesc, error) { var ( - err error + err error resp *http.Response testSuites []tests.TestSuiteDesc ) diff --git a/revel/version.go b/revel/version.go index 3de97fb..5dc6acf 100644 --- a/revel/version.go +++ b/revel/version.go @@ -29,10 +29,10 @@ import ( type ( // The version container VersionCommand struct { - Command *model.CommandConfig // The command - revelVersion *model.Version // The Revel framework version - modulesVersion *model.Version // The Revel modules version - cmdVersion *model.Version // The tool version + Command *model.CommandConfig // The command + revelVersion *model.Version // The Revel framework version + modulesVersion *model.Version // The Revel modules version + cmdVersion *model.Version // The tool version } ) @@ -74,10 +74,10 @@ func (v *VersionCommand) RunWith(c *model.CommandConfig) (err error) { versionInfo := "" for x := 0; x < 2 && needsUpdates; x++ { needsUpdates = false - versionInfo, needsUpdates = v.doRepoCheck(x==0) + versionInfo, needsUpdates = v.doRepoCheck(x == 0) } - fmt.Printf("%s\n\nGo Location:%s\n\n",versionInfo,c.GoCmd) + fmt.Printf("%s\n\nGo Location:%s\n\n", versionInfo, c.GoCmd) cmd := exec.Command(c.GoCmd, "version") cmd.Stdout = os.Stdout if e := cmd.Start(); e != nil { @@ -112,7 +112,7 @@ func (v *VersionCommand) doRepoCheck(updateLibs bool) (versionInfo string, needs // Only do an update on the first loop, and if specified to update shouldUpdate := updateLibs && v.Command.Version.Update if v.Command.Version.Update { - if localVersion == nil || (versonFromRepo != nil && versonFromRepo.Newer(localVersion)) { + if localVersion == nil || (versonFromRepo != nil && versonFromRepo.Newer(localVersion)) { needsUpdate = true if shouldUpdate { v.doUpdate(title, repo, localVersion, versonFromRepo) @@ -127,7 +127,7 @@ func (v *VersionCommand) doRepoCheck(updateLibs bool) (versionInfo string, needs // Checks for updates if needed func (v *VersionCommand) doUpdate(title, repo string, local, remote *model.Version) { - utils.Logger.Info("Updating package", "package", title, "repo",repo) + utils.Logger.Info("Updating package", "package", title, "repo", repo) fmt.Println("Attempting to update package", title) if err := v.Command.PackageResolver(repo); err != nil { utils.Logger.Error("Unable to update repo", "repo", repo, "error", err) @@ -228,15 +228,15 @@ func (v *VersionCommand) versionFromBytes(sourceStream []byte) (version *model.V } // Fetch the local version of revel from the file system -func (v *VersionCommand) updateLocalVersions() { +func (v *VersionCommand) updateLocalVersions() { v.cmdVersion = &model.Version{} v.cmdVersion.ParseVersion(cmd.Version) v.cmdVersion.BuildDate = cmd.BuildDate v.cmdVersion.MinGoVersion = cmd.MinimumGoVersion - pathMap, err := utils.FindSrcPaths(v.Command.AppPath,[]string{model.RevelImportPath,model.RevelModulesImportPath}, v.Command.PackageResolver) + pathMap, err := utils.FindSrcPaths(v.Command.AppPath, []string{model.RevelImportPath, model.RevelModulesImportPath}, v.Command.PackageResolver) if err != nil { - utils.Logger.Warn("Unable to extract version information from Revel library", "path",pathMap[model.RevelImportPath], "error",err) + utils.Logger.Warn("Unable to extract version information from Revel library", "path", pathMap[model.RevelImportPath], "error", err) return } utils.Logger.Info("Fullpath to revel modules", "dir", pathMap[model.RevelImportPath]) diff --git a/utils/build_error.go b/utils/build_error.go index 8655a96..faa8614 100644 --- a/utils/build_error.go +++ b/utils/build_error.go @@ -73,10 +73,10 @@ func NewCompileError(importPath, errorLink string, error error) *SourceError { // Read the source for the offending file. var ( - relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go" - absFilename = relFilename - line, _ = strconv.Atoi(string(errorMatch[2])) - description = string(errorMatch[4]) + relFilename = string(errorMatch[1]) // e.g. "src/revel/sample/app/controllers/app.go" + absFilename = relFilename + line, _ = strconv.Atoi(string(errorMatch[2])) + description = string(errorMatch[4]) compileError = &SourceError{ SourceType: "Go code", Title: "Go Compilation Error", @@ -95,7 +95,7 @@ func NewCompileError(importPath, errorLink string, error error) *SourceError { fileStr, err := ReadLines(absFilename) if err != nil { compileError.MetaError = absFilename + ": " + err.Error() - Logger.Info("Unable to readlines "+compileError.MetaError, "error", err) + Logger.Info("Unable to readlines " + compileError.MetaError, "error", err) return compileError } diff --git a/utils/command.go b/utils/command.go index 4a36592..e00b4e1 100644 --- a/utils/command.go +++ b/utils/command.go @@ -10,25 +10,27 @@ import ( ) // Initialize the command based on the GO environment -func CmdInit(c *exec.Cmd, basePath string) { +func CmdInit(c *exec.Cmd, addGoPath bool, basePath string) { c.Dir = basePath // Dep does not like paths that are not real, convert all paths in go to real paths realPath := &bytes.Buffer{} - for _, p := range filepath.SplitList(build.Default.GOPATH) { - rp,_ := filepath.EvalSymlinks(p) - if realPath.Len() > 0 { - realPath.WriteString(string(filepath.ListSeparator)) + if addGoPath { + for _, p := range filepath.SplitList(build.Default.GOPATH) { + rp, _ := filepath.EvalSymlinks(p) + if realPath.Len() > 0 { + realPath.WriteString(string(filepath.ListSeparator)) + } + realPath.WriteString(rp) } - realPath.WriteString(rp) + // Go 1.8 fails if we do not include the GOROOT + c.Env = []string{"GOPATH=" + realPath.String(), "GOROOT=" + os.Getenv("GOROOT")} } - // Go 1.8 fails if we do not include the GOROOT - c.Env = []string{"GOPATH=" + realPath.String(), "GOROOT="+ os.Getenv("GOROOT")} // Fetch the rest of the env variables for _, e := range os.Environ() { pair := strings.Split(e, "=") - if pair[0]=="GOPATH" || pair[0]=="GOROOT" { + if pair[0] == "GOPATH" || pair[0] == "GOROOT" { continue } - c.Env = append(c.Env,e) + c.Env = append(c.Env, e) } } \ No newline at end of file diff --git a/utils/error.go b/utils/error.go index 1146d72..93143d8 100644 --- a/utils/error.go +++ b/utils/error.go @@ -24,7 +24,7 @@ type ( } ) // Return a new error object -func NewError(source, title,path,description string) *SourceError { +func NewError(source, title, path, description string) *SourceError { return &SourceError{ SourceType:source, Title:title, @@ -82,7 +82,7 @@ func (e *SourceError) ContextSource() []SourceLine { end = len(e.SourceLines) } - lines := make([]SourceLine, end-start) + lines := make([]SourceLine, end - start) for i, src := range e.SourceLines[start:end] { fileLine := start + i + 1 lines[i] = SourceLine{src, fileLine, fileLine == e.Line} diff --git a/utils/file.go b/utils/file.go index d661beb..da8a177 100644 --- a/utils/file.go +++ b/utils/file.go @@ -109,7 +109,7 @@ func GenerateTemplate(filename, templateSource string, args map[string]interface func RenderTemplate(destPath, srcPath string, data interface{}) (err error) { tmpl, err := template.ParseFiles(srcPath) if err != nil { - return NewBuildIfError(err, "Failed to parse template "+srcPath) + return NewBuildIfError(err, "Failed to parse template " + srcPath) } f, err := os.Create(destPath) @@ -119,12 +119,12 @@ func RenderTemplate(destPath, srcPath string, data interface{}) (err error) { err = tmpl.Execute(f, data) if err != nil { - return NewBuildIfError(err, "Failed to Render template "+srcPath) + return NewBuildIfError(err, "Failed to Render template " + srcPath) } err = f.Close() if err != nil { - return NewBuildIfError(err, "Failed to close file stream "+destPath) + return NewBuildIfError(err, "Failed to close file stream " + destPath) } return } @@ -133,12 +133,12 @@ func RenderTemplate(destPath, srcPath string, data interface{}) (err error) { func RenderTemplateToStream(output io.Writer, srcPath []string, data interface{}) (err error) { tmpl, err := template.ParseFiles(srcPath...) if err != nil { - return NewBuildIfError(err, "Failed to parse template "+srcPath[0]) + return NewBuildIfError(err, "Failed to parse template " + srcPath[0]) } err = tmpl.Execute(output, data) if err != nil { - return NewBuildIfError(err, "Failed to render template "+srcPath[0]) + return NewBuildIfError(err, "Failed to render template " + srcPath[0]) } return } @@ -181,7 +181,7 @@ func CopyDir(destDir, srcDir string, data map[string]interface{}) error { if info.IsDir() { err := os.MkdirAll(filepath.Join(destDir, relSrcPath), 0777) if !os.IsExist(err) { - return NewBuildIfError(err, "Failed to create directory", "path", destDir+"/"+relSrcPath) + return NewBuildIfError(err, "Failed to create directory", "path", destDir + "/" + relSrcPath) } return nil } @@ -189,7 +189,7 @@ func CopyDir(destDir, srcDir string, data map[string]interface{}) error { // If this file ends in ".template", render it as a template. if strings.HasSuffix(relSrcPath, ".template") { - return RenderTemplate(destPath[:len(destPath)-len(".template")], srcPath, data) + return RenderTemplate(destPath[:len(destPath) - len(".template")], srcPath, data) } // Else, just copy it over. @@ -218,7 +218,7 @@ func fsWalk(fname string, linkName string, walkFn filepath.WalkFunc) error { path = filepath.Join(linkName, name) - if err == nil && info.Mode()&os.ModeSymlink == os.ModeSymlink { + if err == nil && info.Mode() & os.ModeSymlink == os.ModeSymlink { var symlinkPath string symlinkPath, err = filepath.EvalSymlinks(path) if err != nil { @@ -321,16 +321,16 @@ func Empty(dirname string) bool { // Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkgName string) error) (sourcePathsmap map[string]string, err error) { - sourcePathsmap, missingList,err := findSrcPaths(appPath,packageList) + sourcePathsmap, missingList, err := findSrcPaths(appPath, packageList) if err != nil && packageResolver != nil { for _, item := range missingList { if err = packageResolver(item); err != nil { return } } - sourcePathsmap,missingList,err = findSrcPaths(appPath,packageList) + sourcePathsmap, missingList, err = findSrcPaths(appPath, packageList) } - if err!=nil && len(missingList)>0 { + if err != nil && len(missingList) > 0 { for _, missing := range missingList { Logger.Error("Unable to import this package", "package", missing) } @@ -338,6 +338,7 @@ func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkg return } + var NO_APP_FOUND = errors.New("No app found") var NO_REVEL_FOUND = errors.New("No revel found") @@ -351,20 +352,19 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str } sourcePathsmap = map[string]string{} - pkgs, err := packages.Load(config, packagesList...) - Logger.Info("Loaded packages ", "len results", len(pkgs), "error",err,"basedir",appPath) + pkgs, err := packages.Load(config, packagesList...) + Logger.Info("Loaded packages ", "len results", len(pkgs), "error", err, "basedir", appPath) for _, packageName := range packagesList { found := false - log:= Logger.New("seeking",packageName) + log := Logger.New("seeking", packageName) for _, pck := range pkgs { - log.Info("Found package","package",pck.ID) + log.Info("Found package", "package", pck.ID) if pck.ID == packageName { - if pck.Errors!=nil && len(pck.Errors)>0 { - log.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID,"errors",pck.Errors) - + if pck.Errors != nil && len(pck.Errors) > 0 { + log.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID, "errors", pck.Errors) } //a,_ := pck.MarshalJSON() - log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID,"apppath",appPath) + log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID, "apppath", appPath) sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0]) found = true } @@ -375,7 +375,7 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str } else { err = NO_APP_FOUND } - missingList = append(missingList,packageName) + missingList = append(missingList, packageName) } } return From 33abc47c7ae7de7844ee997eb207495c31287a5c Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sun, 26 Apr 2020 23:00:51 -0700 Subject: [PATCH 09/18] Fixed remaining test --- .codebeatsettings | 2 +- harness/build.go | 10 +++- model/command/version.go | 3 +- model/command_config.go | 110 ++++++++++++++++++--------------------- revel/clean_test.go | 8 +-- 5 files changed, 67 insertions(+), 66 deletions(-) diff --git a/.codebeatsettings b/.codebeatsettings index b8c65b2..c5f22a4 100644 --- a/.codebeatsettings +++ b/.codebeatsettings @@ -4,7 +4,7 @@ "ARITY":[5,6,7,8], "BLOCK_NESTING":[9, 10, 12, 13], "CYCLO":[30, 35, 45, 60], - "TOO_MANY_IVARS": [20, 25, 40, 45], + "TOO_MANY_IVARS": [28, 30, 40, 45], "TOO_MANY_FUNCTIONS": [20, 30, 40, 50], "TOTAL_COMPLEXITY": [150, 250, 400, 500], "LOC": [100, 175, 250, 320], diff --git a/harness/build.go b/harness/build.go index c92dde0..808e1ec 100644 --- a/harness/build.go +++ b/harness/build.go @@ -146,6 +146,9 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err for { appVersion := getAppVersion(paths) + if appVersion == "" { + appVersion = "noVersionProvided" + } buildTime := time.Now().UTC().Format(time.RFC3339) versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s", @@ -165,7 +168,12 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err } flags = append(flags, c.BuildFlags...) if !contains(flags, "-ldflags") { - flags = append(flags, "-ldflags", versionLinkerFlags) + ldflags := "-ldflags= " + versionLinkerFlags + // Add in build flags + for i := range c.BuildFlags { + ldflags += "-X '" + c.BuildFlags[i] + "'" + } + flags = append(flags, ldflags) } if !contains(flags, "-tags") { flags = append(flags, "-tags", buildTags) diff --git a/model/command/version.go b/model/command/version.go index 627f505..45dca50 100644 --- a/model/command/version.go +++ b/model/command/version.go @@ -2,6 +2,7 @@ package command type ( Version struct { ImportCommand - Update bool `short:"u" long:"Update the framework and modules" required:"false"` + Update bool `short:"u" long:"update" description:"Update the framework and modules" required:"false"` + UpdateVersion string `long:"update-version" description:"Specify the version the revel and app will be switched to" required:"false"` } ) diff --git a/model/command_config.go b/model/command_config.go index db4ebc9..695a14b 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -3,7 +3,6 @@ package model import ( "fmt" "github.com/revel/cmd" -// "github.com/revel/cmd/logger" "github.com/revel/cmd/utils" "go/ast" "go/build" @@ -34,35 +33,28 @@ type ( // The Command config for the line input CommandConfig struct { - Index COMMAND // The index - Verbose []bool `short:"v" long:"debug" description:"If set the logger is set to verbose"` // True if debug is active - FrameworkVersion *Version // The framework version - CommandVersion *Version // The command version - HistoricMode bool `long:"historic-run-mode" description:"If set the runmode is passed a string not json"` // True if debug is active - ImportPath string // The import path (relative to a GOPATH) - GoPath string // The GoPath - GoCmd string // The full path to the go executable - SrcRoot string // The source root - AppPath string // The application path (absolute) - AppName string // The application name - HistoricBuildMode bool `long:"historic-build-mode" description:"If set the code is scanned using the original parsers, not the go.1.11+"` // True if debug is active - Vendored bool // True if the application is vendored - PackageResolver func(pkgName string) error // a packge resolver for the config - BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` - - New command.New `command:"new"` // The new command - // The build command - Build command.Build `command:"build"` - // The run command - Run command.Run `command:"run"` - // The package command - Package command.Package `command:"package"` - // The clean command - Clean command.Clean `command:"clean"` - // The test command - Test command.Test `command:"test"` - // The version command - Version command.Version `command:"version"` + Index COMMAND // The index + Verbose []bool `short:"v" long:"debug" description:"If set the logger is set to verbose"` // True if debug is active + FrameworkVersion *Version // The framework version + CommandVersion *Version // The command version + HistoricMode bool `long:"historic-run-mode" description:"If set the runmode is passed a string not json"` // True if debug is active + ImportPath string // The import path (relative to a GOPATH) + GoPath string // The GoPath + GoCmd string // The full path to the go executable + SrcRoot string // The source root + AppPath string // The application path (absolute) + AppName string // The application name + HistoricBuildMode bool `long:"historic-build-mode" description:"If set the code is scanned using the original parsers, not the go.1.11+"` // True if debug is active + Vendored bool // True if the application is vendored + PackageResolver func(pkgName string) error // a package resolver for the config + BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` + New command.New `command:"new"` + Build command.Build `command:"build"` + Run command.Run `command:"run"` + Package command.Package `command:"package"` + Clean command.Clean `command:"clean"` + Test command.Test `command:"test"` + Version command.Version `command:"version"` } ) @@ -75,19 +67,19 @@ func (c *CommandConfig) UpdateImportPath() error { importPath = c.New.ImportPath case RUN: importPath = c.Run.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath, "go.mod")) case BUILD: importPath = c.Build.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath, "go.mod")) case PACKAGE: importPath = c.Package.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath, "go.mod")) case CLEAN: importPath = c.Clean.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath, "go.mod")) case TEST: importPath = c.Test.ImportPath - c.Vendored = utils.Exists(filepath.Join(importPath,"go.mod")) + c.Vendored = utils.Exists(filepath.Join(importPath, "go.mod")) case VERSION: importPath = c.Version.ImportPath required = false @@ -109,10 +101,10 @@ func (c *CommandConfig) UpdateImportPath() error { if err == nil { for _, path := range strings.Split(build.Default.GOPATH, string(filepath.ListSeparator)) { utils.Logger.Infof("Checking import path %s with %s", currentPath, path) - if strings.HasPrefix(currentPath, path) && len(currentPath) > len(path)+1 { - importPath = currentPath[len(path)+1:] + if strings.HasPrefix(currentPath, path) && len(currentPath) > len(path) + 1 { + importPath = currentPath[len(path) + 1:] // Remove the source from the path if it is there - if len(importPath) > 4 && strings.ToLower(importPath[0:4]) == "src/" { + if len(importPath) > 4 && (strings.ToLower(importPath[0:4]) == "src/" || strings.ToLower(importPath[0:4]) == "src\\") { importPath = importPath[4:] } else if importPath == "src" { if c.Index != VERSION { @@ -134,7 +126,7 @@ func (c *CommandConfig) UpdateImportPath() error { if err := c.SetVersions(); err != nil { utils.Logger.Panic("Failed to fetch revel versions", "error", err) } - if err:=c.FrameworkVersion.CompatibleFramework(c);err!=nil { + if err := c.FrameworkVersion.CompatibleFramework(c); err != nil { utils.Logger.Fatal("Compatibility Error", "message", err, "Revel framework version", c.FrameworkVersion.String(), "Revel tool version", c.CommandVersion.String()) } @@ -143,14 +135,14 @@ func (c *CommandConfig) UpdateImportPath() error { if !required { return nil } - if len(importPath) == 0 { + if len(importPath) == 0 { return fmt.Errorf("Unable to determine import path from : %s", importPath) } return nil } func (c *CommandConfig) initAppFolder() (err error) { - utils.Logger.Info("initAppFolder","vendored", c.Vendored) + utils.Logger.Info("initAppFolder", "vendored", c.Vendored) // check for go executable c.GoCmd, err = exec.LookPath("go") @@ -160,36 +152,36 @@ func (c *CommandConfig) initAppFolder() (err error) { // First try to determine where the application is located - this should be the import value appFolder := c.ImportPath - wd,err := os.Getwd() + wd, err := os.Getwd() if len(appFolder) == 0 { // We will assume the working directory is the appFolder appFolder = wd - } else if strings.LastIndex(wd,appFolder)==len(wd)-len(appFolder) { + } else if strings.LastIndex(wd, appFolder) == len(wd) - len(appFolder) { // Check for existence of an /app folder - if utils.Exists(filepath.Join(wd,"app")) { + if utils.Exists(filepath.Join(wd, "app")) { appFolder = wd } else { - appFolder = filepath.Join(wd,appFolder) + appFolder = filepath.Join(wd, appFolder) } - } else if strings.Contains(appFolder,".") { - appFolder = filepath.Join(wd,filepath.Base(c.ImportPath)) + } else if strings.Contains(appFolder, ".") { + appFolder = filepath.Join(wd, filepath.Base(c.ImportPath)) } else if !filepath.IsAbs(appFolder) { - appFolder = filepath.Join(wd,appFolder) + appFolder = filepath.Join(wd, appFolder) } - utils.Logger.Info("Determined app folder to be", "appfolder",appFolder, "working",wd,"importPath",c.ImportPath) + utils.Logger.Info("Determined app folder to be", "appfolder", appFolder, "working", wd, "importPath", c.ImportPath) // Use app folder to read the go.mod if it exists and extract the package information - goModFile := filepath.Join(appFolder,"go.mod") + goModFile := filepath.Join(appFolder, "go.mod") if utils.Exists(goModFile) { c.Vendored = true - file,err:=ioutil.ReadFile(goModFile) - if err!=nil { + file, err := ioutil.ReadFile(goModFile) + if err != nil { return err } - for _,line := range strings.Split(string(file),"\n") { - if strings.Index(line,"module ")==0 { - c.ImportPath = strings.TrimSpace(strings.Split(line,"module")[1]) + for _, line := range strings.Split(string(file), "\n") { + if strings.Index(line, "module ") == 0 { + c.ImportPath = strings.TrimSpace(strings.Split(line, "module")[1]) c.AppPath = appFolder c.SrcRoot = appFolder utils.Logger.Info("Set application path and package based on go mod", "path", c.AppPath, "sourceroot", c.SrcRoot) @@ -236,7 +228,7 @@ func (c *CommandConfig) initAppFolder() (err error) { c.SrcRoot = appFolder } - utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath",bestpath) + utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) // If source root is empty and this isn't a version then skip it if len(c.SrcRoot) == 0 { @@ -275,7 +267,7 @@ func (c *CommandConfig) InitPackageResolver() { utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored) if c.Vendored { goModCmd := exec.Command("go", "mod", "tidy") - utils.CmdInit(goModCmd,!c.Vendored, c.AppPath) + utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) goModCmd.Run() return nil } @@ -323,7 +315,7 @@ func (c *CommandConfig) InitGoPathsOld() { } } - utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath",bestpath) + utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) if len(c.SrcRoot) == 0 && len(bestpath) > 0 { c.SrcRoot = bestpath } @@ -355,7 +347,7 @@ func (c *CommandConfig) SetVersions() (err error) { utils.Logger.Info("Fullpath to revel", "dir", pathMap[RevelImportPath]) fset := token.NewFileSet() // positions are relative to fset - versionData, err := ioutil.ReadFile(filepath.Join(pathMap[RevelImportPath], "version.go")) + versionData, err := ioutil.ReadFile(filepath.Join(pathMap[RevelImportPath], "version.go")) if err != nil { utils.Logger.Error("Failed to find Revel version:", "error", err, "path", pathMap[RevelImportPath]) } diff --git a/revel/clean_test.go b/revel/clean_test.go index 50dae6d..0b6c218 100644 --- a/revel/clean_test.go +++ b/revel/clean_test.go @@ -22,12 +22,12 @@ func TestClean(t *testing.T) { main.Commands[model.NEW].RunWith(c) c.Index = model.TEST main.Commands[model.TEST].RunWith(c) - a.True(utils.Exists(filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go")), - "Missing main from path "+filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go")) + a.True(utils.Exists(filepath.Join(gopath, "clean-test", "app", "tmp", "main.go")), + "Missing main from path "+filepath.Join(gopath, "clean-test", "app", "tmp", "main.go")) c.Clean.ImportPath = c.ImportPath a.Nil(main.Commands[model.CLEAN].RunWith(c), "Failed to run clean-test") - a.False(utils.Exists(filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go")), - "Did not remove main from path "+filepath.Join(gopath, "src", "clean-test", "app", "tmp", "main.go")) + a.False(utils.Exists(filepath.Join(gopath, "clean-test", "app", "tmp", "main.go")), + "Did not remove main from path "+filepath.Join(gopath, "clean-test", "app", "tmp", "main.go")) }) if !t.Failed() { if err := os.RemoveAll(gopath); err != nil { From 31cb64e496d098ce0b22ce076a6e096f00d7b968 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Mon, 27 Apr 2020 09:07:04 -0700 Subject: [PATCH 10/18] Check-in of command_test, remaps the go mod command to use the develop branch. --- revel/command_test.go | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/revel/command_test.go b/revel/command_test.go index 01e52f8..57e8306 100644 --- a/revel/command_test.go +++ b/revel/command_test.go @@ -7,7 +7,9 @@ import ( "github.com/stretchr/testify/assert" "go/build" "os" + "os/exec" "path/filepath" + "fmt" ) // Test that the event handler can be attached and it dispatches the event received @@ -43,10 +45,26 @@ func setup(suffix string, a *assert.Assertions) (string) { // Create a new app for the name func newApp(name string, command model.COMMAND, precall func(c *model.CommandConfig), a *assert.Assertions) *model.CommandConfig { - c := &model.CommandConfig{} + c := &model.CommandConfig{Vendored:true} switch command { case model.NEW: c.New.ImportPath = name + c.New.Callback=func() error { + // On callback we will invoke a specific branch of revel so that it works + + goModCmd := exec.Command("go", "mod", "tidy") + utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) + getOutput, _ := goModCmd.CombinedOutput() + fmt.Printf("Calling go mod tidy %s",string(getOutput)) + + goModCmd = exec.Command("go", "mod", "edit", "-replace=github.com/revel/revel=github.com/revel/revel@develop") + utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) + getOutput, _ = goModCmd.CombinedOutput() + fmt.Printf("Calling go mod edit %v",string(getOutput)) + + + return nil + } case model.BUILD: c.Build.ImportPath = name case model.TEST: @@ -68,7 +86,7 @@ func newApp(name string, command model.COMMAND, precall func(c *model.CommandCon if c.UpdateImportPath()!=nil { a.Fail("Unable to update import path") } - c.InitGoPaths() + c.InitPackageResolver() return c } From 0920905a0cadfe45d154b65debde2ed356b3e9f0 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Tue, 28 Apr 2020 11:48:55 -0700 Subject: [PATCH 11/18] Updated to build go 1.12 and up Modified to use fsnotify directlyUpdated travis to not use go deps --- .travis.yml | 8 +++----- watcher/watcher.go | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f191f77..e9d2b27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,9 @@ language: go go: - - "1.8.x" - - "1.9.x" - - "1.10.x" - - "1.11.x" + - "1.12.x" + - "1.13.x" + - "1.14.x" - "tip" os: @@ -29,7 +28,6 @@ install: - git clone -b $REVEL_BRANCH git://github.com/revel/revel ../revel/ - git clone -b $REVEL_BRANCH git://github.com/revel/modules ../modules/ - go get -t -v github.com/revel/cmd/revel - - go get -u github.com/golang/dep/cmd/dep - echo $GOPATH - echo $PATH - pwd diff --git a/watcher/watcher.go b/watcher/watcher.go index f4ee0be..b055e7e 100644 --- a/watcher/watcher.go +++ b/watcher/watcher.go @@ -12,7 +12,7 @@ import ( "github.com/revel/cmd/model" "github.com/revel/cmd/utils" - "gopkg.in/fsnotify/fsnotify.v1" + "github.com/fsnotify/fsnotify" "time" ) From 20d5766eb6868f659839aade52d4ae9fe586775a Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Wed, 29 Apr 2020 17:05:39 -0700 Subject: [PATCH 12/18] Added gomod-flags Added a gomod-flags parameter which allows you to run go mod commands on the go.mod file before the build is performed. This allows for development environments. --- .travis.yml | 44 ++++++++++++++++++++--------------------- go.mod | 2 +- harness/build.go | 14 +++++++++++++ model/command_config.go | 1 + 4 files changed, 38 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9d2b27..2451f34 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,31 +35,31 @@ script: - go test -v github.com/revel/cmd/revel/... # Ensure the new-app flow works (plus the other commands). - - revel version - - revel new my/testapp - - revel test my/testapp - - revel clean my/testapp - - revel build my/testapp build/testapp - - revel build my/testapp build/testapp prod - - revel package my/testapp - - revel package my/testapp prod + #- revel version + #- revel new my/testapp + #- revel test my/testapp + #- revel clean my/testapp + #- revel build my/testapp build/testapp + #- revel build my/testapp build/testapp prod + #- revel package my/testapp + #- revel package my/testapp prod # Ensure the new-app flow works (plus the other commands). - - revel new -a my/testapp2 - - revel test -a my/testapp2 - - revel clean -a my/testapp2 - - revel build -a my/testapp2 -t build/testapp2 - - revel build -a my/testapp2 -t build/testapp2 -m prod - - revel package -a my/testapp2 - - revel package -a my/testapp2 -m prod + - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 + - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 + - revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 + - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -t build/testapp2 + - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -t build/testapp2 -m prod + - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 + - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -m prod - - revel new -v -a my/testapp3 -V - - revel test -v -a my/testapp3 - - revel clean -v -a my/testapp3 - - revel build -a my/testapp3 -t build/testapp3 - - revel build -a my/testapp3 -t build/testapp3 -m prod - - revel package -a my/testapp3 - - revel package -a my/testapp3 -m prod + - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 -V + - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 + - revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 + - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -t build/testapp3 + - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -t build/testapp3 -m prod + - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 + - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -m prod matrix: allow_failures: diff --git a/go.mod b/go.mod index e6ee7ee..5e757e8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.13 require ( github.com/BurntSushi/toml v0.3.1 // indirect github.com/agtorre/gocolorize v1.0.0 - github.com/fsnotify/fsnotify v1.4.7 // indirect + github.com/fsnotify/fsnotify v1.4.7 github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect github.com/jessevdk/go-flags v1.4.0 github.com/mattn/go-colorable v0.1.4 diff --git a/harness/build.go b/harness/build.go index 808e1ec..ffb9f46 100644 --- a/harness/build.go +++ b/harness/build.go @@ -144,6 +144,20 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err return false } + if len(c.GoModFlags) > 0 { + for _, gomod := range c.GoModFlags { + goModCmd := exec.Command(goPath, append([]string{"mod"}, strings.Split(gomod, " ")...)...) + utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) + output, err := goModCmd.CombinedOutput() + utils.Logger.Infof("Gomod applied ", "output", string(output)) + + // If the build succeeded, we're done. + if err != nil { + utils.Logger.Error("Gomod Failed continuing ", "error", err, "output", string(output)) + } + } + } + for { appVersion := getAppVersion(paths) if appVersion == "" { diff --git a/model/command_config.go b/model/command_config.go index 695a14b..f850a63 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -48,6 +48,7 @@ type ( Vendored bool // True if the application is vendored PackageResolver func(pkgName string) error // a package resolver for the config BuildFlags []string `short:"X" long:"build-flags" description:"These flags will be used when building the application. May be specified multiple times, only applicable for Build, Run, Package, Test commands"` + GoModFlags []string `long:"gomod-flags" description:"These flags will execut go mod commands for each flag, this happens during the build process"` New command.New `command:"new"` Build command.Build `command:"build"` Run command.Run `command:"run"` From fb4b56513a6b5257b8107d7918c309b6b1a12cf0 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Wed, 29 Apr 2020 21:13:00 -0700 Subject: [PATCH 13/18] Debug travis Added verbose flag so we can see what is occurring, Removed checkout for revel, not needed anymore --- .travis.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2451f34..34db0d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,8 +25,9 @@ install: - export REVEL_BRANCH="develop" - 'if [[ "$TRAVIS_BRANCH" == "master" ]]; then export REVEL_BRANCH="master"; fi' - 'echo "Travis branch: $TRAVIS_BRANCH, Revel dependency branch: $REVEL_BRANCH"' - - git clone -b $REVEL_BRANCH git://github.com/revel/revel ../revel/ - - git clone -b $REVEL_BRANCH git://github.com/revel/modules ../modules/ + #- git clone -b $REVEL_BRANCH git://github.com/revel/revel ../revel/ + #- git clone -b $REVEL_BRANCH git://github.com/revel/modules ../modules/ + # Since travis already checks out go - go get -t -v github.com/revel/cmd/revel - echo $GOPATH - echo $PATH @@ -45,13 +46,13 @@ script: #- revel package my/testapp prod # Ensure the new-app flow works (plus the other commands). - - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 - - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 - - revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 - - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -t build/testapp2 - - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -t build/testapp2 -m prod - - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 - - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -m prod + - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v + - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v + - revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v + - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -t build/testapp2 + - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -t build/testapp2 -m prod + - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v + - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -m prod - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 -V - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 From ad694c0fb0bcba568ef7c1bce42e30e9b5ab1865 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Wed, 29 Apr 2020 21:28:09 -0700 Subject: [PATCH 14/18] Debug travis --- .travis.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 34db0d4..a1c151c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,14 @@ language: go go: - "1.12.x" - - "1.13.x" - - "1.14.x" - - "tip" +# - "1.13.x" +# - "1.14.x" +# - "tip" os: - - osx +# - osx - linux - - windows +# - windows sudo: false @@ -18,6 +18,8 @@ branches: - master - develop +env: + - GO111MODULE=on install: # Setting environments variables @@ -27,7 +29,7 @@ install: - 'echo "Travis branch: $TRAVIS_BRANCH, Revel dependency branch: $REVEL_BRANCH"' #- git clone -b $REVEL_BRANCH git://github.com/revel/revel ../revel/ #- git clone -b $REVEL_BRANCH git://github.com/revel/modules ../modules/ - # Since travis already checks out go + # Since travis already checks out go build the commandline tool (revel) - go get -t -v github.com/revel/cmd/revel - echo $GOPATH - echo $PATH From 1d9df256a04ad32ac0919261229641b6e2bce11c Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Wed, 29 Apr 2020 21:39:19 -0700 Subject: [PATCH 15/18] Moved test cases to run last --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a1c151c..91d9809 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,8 +35,6 @@ install: - echo $PATH - pwd script: - - go test -v github.com/revel/cmd/revel/... - # Ensure the new-app flow works (plus the other commands). #- revel version #- revel new my/testapp @@ -64,6 +62,8 @@ script: - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -m prod + - go test -v github.com/revel/cmd/revel/... + matrix: allow_failures: - go: tip From 36bd6b944a1f19dfae6dbf19307e8a47fb3b409e Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Wed, 29 Apr 2020 21:48:11 -0700 Subject: [PATCH 16/18] Corrected flags --- harness/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/harness/build.go b/harness/build.go index ffb9f46..0184fa3 100644 --- a/harness/build.go +++ b/harness/build.go @@ -165,7 +165,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err } buildTime := time.Now().UTC().Format(time.RFC3339) - versionLinkerFlags := fmt.Sprintf("-X %s/app.AppVersion=%s -X %s/app.BuildTime=%s", + versionLinkerFlags := fmt.Sprintf("-X '%s/app.AppVersion=%s' -X '%s/app.BuildTime=%s'", paths.ImportPath, appVersion, paths.ImportPath, buildTime) // Append any build flags specified, they will override existing flags From 9d3a554becdb67925d8d911d0678f0288b0fb03b Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Wed, 29 Apr 2020 22:01:28 -0700 Subject: [PATCH 17/18] Updates Updated NotVendored flag Updated travis matrix Updated build log --- .travis.yml | 28 +++++++++------------------- harness/build.go | 2 +- model/command/new.go | 2 +- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 91d9809..86430d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,14 @@ language: go go: - "1.12.x" -# - "1.13.x" -# - "1.14.x" -# - "tip" + - "1.13.x" + - "1.14.x" + - "tip" os: -# - osx + - osx - linux -# - windows + - windows sudo: false @@ -19,22 +19,22 @@ branches: - develop env: + # Setting environments variables - GO111MODULE=on install: - # Setting environments variables - export PATH=$PATH:$HOME/gopath/bin - export REVEL_BRANCH="develop" - 'if [[ "$TRAVIS_BRANCH" == "master" ]]; then export REVEL_BRANCH="master"; fi' - 'echo "Travis branch: $TRAVIS_BRANCH, Revel dependency branch: $REVEL_BRANCH"' - #- git clone -b $REVEL_BRANCH git://github.com/revel/revel ../revel/ - #- git clone -b $REVEL_BRANCH git://github.com/revel/modules ../modules/ # Since travis already checks out go build the commandline tool (revel) - - go get -t -v github.com/revel/cmd/revel + - go get -v github.com/revel/cmd/revel - echo $GOPATH - echo $PATH - pwd script: + - go test -v github.com/revel/cmd/revel/... + # Ensure the new-app flow works (plus the other commands). #- revel version #- revel new my/testapp @@ -54,16 +54,6 @@ script: - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -m prod - - revel new --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 -V - - revel test --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 - - revel clean --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -v -a my/testapp3 - - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -t build/testapp3 - - revel build --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -t build/testapp3 -m prod - - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 - - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp3 -m prod - - - go test -v github.com/revel/cmd/revel/... - matrix: allow_failures: - go: tip diff --git a/harness/build.go b/harness/build.go index 0184fa3..c271b9e 100644 --- a/harness/build.go +++ b/harness/build.go @@ -149,7 +149,7 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err goModCmd := exec.Command(goPath, append([]string{"mod"}, strings.Split(gomod, " ")...)...) utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) output, err := goModCmd.CombinedOutput() - utils.Logger.Infof("Gomod applied ", "output", string(output)) + utils.Logger.Info("Gomod applied ", "output", string(output)) // If the build succeeded, we're done. if err != nil { diff --git a/model/command/new.go b/model/command/new.go index 66d88fb..51e2c5e 100644 --- a/model/command/new.go +++ b/model/command/new.go @@ -6,7 +6,7 @@ type ( ImportCommand SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` - NotVendored bool `short:"V" long:"vendor" description:"True if project should not be configured with a go.mod"` + NotVendored bool `long:"not-vendor" description:"True if project should not be configured with a go.mod, this requires you to have the project on the GOPATH"` Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` Callback func() error } From 49eef29bb553bd2243735a59d3523f77fa5bbff0 Mon Sep 17 00:00:00 2001 From: "notzippy@gmail.com" Date: Sat, 2 May 2020 12:03:17 -0700 Subject: [PATCH 18/18] Build and Historic build updates Modified GOPATH to not modify build with go.mod Updated go.mod to version 1.12 Updated harness to setup listener before killing process Updated notvendored flag to --no-vendor Updated command_config to ensure no-vendor can be build Added additional checks in source path lookup --- .travis.yml | 13 +++- go.mod | 7 +- harness/app.go | 39 ++++++---- harness/build.go | 24 +----- model/command/new.go | 2 +- model/command_config.go | 161 ++++++++++++++++------------------------ revel/build.go | 3 +- revel/new_test.go | 6 ++ revel/revel.go | 9 +-- utils/file.go | 16 +++- 10 files changed, 125 insertions(+), 155 deletions(-) diff --git a/.travis.yml b/.travis.yml index 86430d8..530d6ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,10 +28,11 @@ install: - 'if [[ "$TRAVIS_BRANCH" == "master" ]]; then export REVEL_BRANCH="master"; fi' - 'echo "Travis branch: $TRAVIS_BRANCH, Revel dependency branch: $REVEL_BRANCH"' # Since travis already checks out go build the commandline tool (revel) - - go get -v github.com/revel/cmd/revel - - echo $GOPATH - - echo $PATH + - mkdir $HOME/GOPATH_PROTECTED + - export GOPATH=$HOME/GOPATH_PROTECTED + - go build -o $HOME/gopath/bin/revel github.com/revel/cmd/revel - pwd + - env script: - go test -v github.com/revel/cmd/revel/... @@ -54,6 +55,12 @@ script: - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v - revel package --gomod-flags "edit -replace=github.com/revel/revel=github.com/revel/revel@develop" -a my/testapp2 -v -m prod + # Check build works with no-vendor flag + - cd $GOPATH + - export GO111MODULE=auto + - revel new -a my/testapp2 --no-vendor + - revel test -a my/testapp2 + matrix: allow_failures: - go: tip diff --git a/go.mod b/go.mod index 5e757e8..268f752 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/revel/cmd -go 1.13 +go 1.12 require ( github.com/BurntSushi/toml v0.3.1 // indirect @@ -8,7 +8,7 @@ require ( github.com/fsnotify/fsnotify v1.4.7 github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 // indirect github.com/jessevdk/go-flags v1.4.0 - github.com/mattn/go-colorable v0.1.4 + github.com/mattn/go-colorable v0.1.6 github.com/myesui/uuid v1.0.0 // indirect github.com/pkg/errors v0.9.1 github.com/revel/config v0.21.0 @@ -19,7 +19,8 @@ require ( github.com/stretchr/testify v1.4.0 github.com/twinj/uuid v1.0.0 // indirect github.com/xeonx/timeago v1.0.0-rc4 // indirect - golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect + golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 // indirect + golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect golang.org/x/tools v0.0.0-20200219054238-753a1d49df85 gopkg.in/fsnotify/fsnotify.v1 v1.4.7 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 diff --git a/harness/app.go b/harness/app.go index 8fa1105..5538bd3 100644 --- a/harness/app.go +++ b/harness/app.go @@ -12,6 +12,7 @@ import ( "os" "os/exec" "time" + "sync" "github.com/revel/cmd/model" "github.com/revel/cmd/utils" @@ -64,8 +65,8 @@ func NewAppCmd(binPath string, port int, runMode string, paths *model.RevelConta func (cmd AppCmd) Start(c *model.CommandConfig) error { listeningWriter := &startupListeningWriter{os.Stdout, make(chan bool), c, &bytes.Buffer{}} cmd.Stdout = listeningWriter - utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env) utils.CmdInit(cmd.Cmd, !c.Vendored, c.AppPath) + utils.Logger.Info("Exec app:", "path", cmd.Path, "args", cmd.Args, "dir", cmd.Dir, "env", cmd.Env) if err := cmd.Cmd.Start(); err != nil { utils.Logger.Fatal("Error running:", "error", err) } @@ -107,10 +108,30 @@ func (cmd AppCmd) Kill() { // server before this can, this check will ensure the process is still running if _, err := os.FindProcess(int(cmd.Process.Pid));err!=nil { // Server has already exited - utils.Logger.Info("Killing revel server pid", "pid", cmd.Process.Pid) + utils.Logger.Info("Server not running revel server pid", "pid", cmd.Process.Pid) return } + // Wait for the shutdown channel + waitMutex := &sync.WaitGroup{} + waitMutex.Add(1) + ch := make(chan bool, 1) + go func() { + waitMutex.Done() + s, err := cmd.Process.Wait() + defer func() { + ch <- true + }() + if err != nil { + utils.Logger.Info("Wait failed for process ", "error", err) + } + if s != nil { + utils.Logger.Info("Revel App exited", "state", s.String()) + } + }() + // Wait for the channel to begin waiting + waitMutex.Wait() + // Send an interrupt signal to allow for a graceful shutdown utils.Logger.Info("Killing revel server pid", "pid", cmd.Process.Pid) var err error @@ -129,20 +150,6 @@ func (cmd AppCmd) Kill() { return } - // Wait for the shutdown - ch := make(chan bool, 1) - go func() { - s, err := cmd.Process.Wait() - defer func() { - ch <- true - }() - if err != nil { - utils.Logger.Info("Wait failed for process ", "error", err) - } - if s != nil { - utils.Logger.Info("Revel App exited", "state", s.String()) - } - }() // Use a timer to ensure that the process exits utils.Logger.Info("Waiting to exit") diff --git a/harness/build.go b/harness/build.go index c271b9e..f3a45de 100644 --- a/harness/build.go +++ b/harness/build.go @@ -102,28 +102,8 @@ func Build(c *model.CommandConfig, paths *model.RevelContainer) (_ *App, err err utils.Logger.Fatal("Go executable not found in PATH.") } - // Detect if deps tool should be used (is there a vendor folder ?) - useVendor := utils.DirExists(filepath.Join(paths.BasePath, "vendor")) - basePath := paths.BasePath - for !useVendor { - basePath = filepath.Dir(basePath) - found := false - // Check to see if we are still in the GOPATH - for _, gopath := range filepath.SplitList(build.Default.GOPATH) { - if strings.HasPrefix(basePath, gopath) { - found = true - break - } - } - if !found { - break - } else { - useVendor = utils.DirExists(filepath.Join(basePath, "vendor")) - } - } - - // Binary path is a combination of BasePath/target/app directory, app's import path and its name. - binName := filepath.Join(paths.BasePath, "target", "app", paths.ImportPath, filepath.Base(paths.BasePath)) + // Binary path is a combination of target/app directory, app's import path and its name. + binName := filepath.Join("target", "app", paths.ImportPath, filepath.Base(paths.BasePath)) // Change binary path for Windows build goos := runtime.GOOS diff --git a/model/command/new.go b/model/command/new.go index 51e2c5e..5ff685f 100644 --- a/model/command/new.go +++ b/model/command/new.go @@ -6,7 +6,7 @@ type ( ImportCommand SkeletonPath string `short:"s" long:"skeleton" description:"Path to skeleton folder (Must exist on GO PATH)" required:"false"` Package string `short:"p" long:"package" description:"The package name, this becomes the repfix to the app name, if defined vendored is set to true" required:"false"` - NotVendored bool `long:"not-vendor" description:"True if project should not be configured with a go.mod, this requires you to have the project on the GOPATH"` + NotVendored bool `long:"no-vendor" description:"True if project should not be configured with a go.mod, this requires you to have the project on the GOPATH, this is only compatible with go versions v1.12 or older"` Run bool `short:"r" long:"run" description:"True if you want to run the application right away"` Callback func() error } diff --git a/model/command_config.go b/model/command_config.go index f850a63..08f0b90 100644 --- a/model/command_config.go +++ b/model/command_config.go @@ -41,7 +41,7 @@ type ( ImportPath string // The import path (relative to a GOPATH) GoPath string // The GoPath GoCmd string // The full path to the go executable - SrcRoot string // The source root + //SrcRoot string // The source root AppPath string // The application path (absolute) AppName string // The application name HistoricBuildMode bool `long:"historic-build-mode" description:"If set the code is scanned using the original parsers, not the go.1.11+"` // True if debug is active @@ -143,7 +143,7 @@ func (c *CommandConfig) UpdateImportPath() error { } func (c *CommandConfig) initAppFolder() (err error) { - utils.Logger.Info("initAppFolder", "vendored", c.Vendored) + utils.Logger.Info("initAppFolder", "vendored", c.Vendored, "build-gopath", build.Default.GOPATH, "gopath-env", os.Getenv("GOPATH")) // check for go executable c.GoCmd, err = exec.LookPath("go") @@ -184,30 +184,17 @@ func (c *CommandConfig) initAppFolder() (err error) { if strings.Index(line, "module ") == 0 { c.ImportPath = strings.TrimSpace(strings.Split(line, "module")[1]) c.AppPath = appFolder - c.SrcRoot = appFolder - utils.Logger.Info("Set application path and package based on go mod", "path", c.AppPath, "sourceroot", c.SrcRoot) + //c.SrcRoot = appFolder + utils.Logger.Info("Set application path and package based on go mod", "path", c.AppPath) return nil } } - } - - utils.Logger.Debug("Trying to set path based on gopath") - // lookup go path - c.GoPath = build.Default.GOPATH - if c.GoPath == "" { - utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " + - "Please refer to http://golang.org/doc/code.html to configure your Go environment.") - } - - // revel/revel#1004 choose go path relative to current working directory - - // What we want to do is to add the import to the end of the - // gopath, and discover which import exists - If none exist this is an error except in the case - // where we are dealing with new which is a special case where we will attempt to target the working directory first - workingDir, _ := os.Getwd() - goPathList := filepath.SplitList(c.GoPath) - bestpath := "" - if !c.Vendored { + // c.SrcRoot = appFolder + c.AppPath = appFolder + } else if c.Index != NEW || (c.Index == NEW && c.New.NotVendored) { + workingDir, _ := os.Getwd() + goPathList := filepath.SplitList(c.GoPath) + bestpath := "" for _, path := range goPathList { if c.Index == NEW { // If the GOPATH is part of the working dir this is the most likely target @@ -216,61 +203,48 @@ func (c *CommandConfig) initAppFolder() (err error) { } } else { if utils.Exists(filepath.Join(path, "src", c.ImportPath)) { - c.SrcRoot = path + bestpath = path break } } } - if len(c.SrcRoot) == 0 && len(bestpath) > 0 { - c.SrcRoot = bestpath + + utils.Logger.Info("Source root", "cwd", workingDir, "gopath", c.GoPath, "c.ImportPath", c.ImportPath, "bestpath", bestpath) + if len(bestpath) > 0 { + c.AppPath = filepath.Join(bestpath, "src", c.ImportPath) } + // Recalculate the appFolder because we are using a GOPATH } else { - c.SrcRoot = appFolder + // This is new and not vendored, so the app path is the appFolder + c.AppPath = appFolder } - utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) - - // If source root is empty and this isn't a version then skip it - if len(c.SrcRoot) == 0 { - if c.Index == NEW { - c.SrcRoot = c.New.ImportPath - } else { - if c.Index != VERSION { - utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.") - } - return nil - } - } - - // set go src path - if c.Vendored { - c.AppPath = c.SrcRoot - - } else { - c.SrcRoot = filepath.Join(c.SrcRoot, "src") - - c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath)) - } utils.Logger.Info("Set application path", "path", c.AppPath) return nil } // Used to initialize the package resolver func (c *CommandConfig) InitPackageResolver() { + c.initGoPaths() utils.Logger.Info("InitPackageResolver", "useVendor", c.Vendored, "path", c.AppPath) // This should get called when needed c.PackageResolver = func(pkgName string) error { - //useVendor := utils.DirExists(filepath.Join(c.AppPath, "vendor")) - - //var getCmd *exec.Cmd utils.Logger.Info("Request for package ", "package", pkgName, "use vendor", c.Vendored) + var getCmd *exec.Cmd if c.Vendored { - goModCmd := exec.Command("go", "mod", "tidy") - utils.CmdInit(goModCmd, !c.Vendored, c.AppPath) - goModCmd.Run() - return nil + getCmd = exec.Command(c.GoCmd, "mod", "tidy") + } else { + utils.Logger.Info("No vendor folder detected, not using dependency manager to import package", "package", pkgName) + getCmd = exec.Command(c.GoCmd, "get", "-u", pkgName) + } + + utils.CmdInit(getCmd, !c.Vendored, c.AppPath) + utils.Logger.Info("Go get command ", "exec", getCmd.Path, "dir", getCmd.Dir, "args", getCmd.Args, "env", getCmd.Env, "package", pkgName) + output, err := getCmd.CombinedOutput() + if err != nil { + utils.Logger.Error("Failed to import package", "error", err, "gopath", build.Default.GOPATH, "GO-ROOT", build.Default.GOROOT, "output", string(output)) } return nil @@ -278,15 +252,8 @@ func (c *CommandConfig) InitPackageResolver() { } // lookup and set Go related variables -func (c *CommandConfig) InitGoPathsOld() { - utils.Logger.Info("InitGoPaths") - // lookup go path - c.GoPath = build.Default.GOPATH - if c.GoPath == "" { - utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " + - "Please refer to http://golang.org/doc/code.html to configure your Go environment.") - } - +func (c *CommandConfig) initGoPaths() { + utils.Logger.Info("InitGoPaths", "vendored", c.Vendored) // check for go executable var err error c.GoCmd, err = exec.LookPath("go") @@ -294,50 +261,46 @@ func (c *CommandConfig) InitGoPathsOld() { utils.Logger.Fatal("Go executable not found in PATH.") } + if c.Vendored { + return + } + + // lookup go path + c.GoPath = build.Default.GOPATH + if c.GoPath == "" { + utils.Logger.Fatal("Abort: GOPATH environment variable is not set. " + + "Please refer to http://golang.org/doc/code.html to configure your Go environment.") + } + return + //todo determine if the rest needs to happen + + // revel/revel#1004 choose go path relative to current working directory // What we want to do is to add the import to the end of the // gopath, and discover which import exists - If none exist this is an error except in the case // where we are dealing with new which is a special case where we will attempt to target the working directory first - workingDir, _ := os.Getwd() - goPathList := filepath.SplitList(c.GoPath) - bestpath := "" - for _, path := range goPathList { - if c.Index == NEW { - // If the GOPATH is part of the working dir this is the most likely target - if strings.HasPrefix(workingDir, path) { - bestpath = path - } - } else { - if utils.Exists(filepath.Join(path, "src", c.ImportPath)) { - c.SrcRoot = path - break + /* + // If source root is empty and this isn't a version then skip it + if len(c.SrcRoot) == 0 { + if c.Index == NEW { + c.SrcRoot = c.New.ImportPath + } else { + if c.Index != VERSION { + utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.") + } + return } } - } - utils.Logger.Info("Source root", "path", c.SrcRoot, "cwd", workingDir, "gopath", c.GoPath, "bestpath", bestpath) - if len(c.SrcRoot) == 0 && len(bestpath) > 0 { - c.SrcRoot = bestpath - } + // set go src path + c.SrcRoot = filepath.Join(c.SrcRoot, "src") - // If source root is empty and this isn't a version then skip it - if len(c.SrcRoot) == 0 { - if c.Index == NEW { - c.SrcRoot = c.New.ImportPath - } else { - if c.Index != VERSION { - utils.Logger.Fatal("Abort: could not create a Revel application outside of GOPATH.") - } - return - } - } + c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath)) + utils.Logger.Info("Set application path", "path", c.AppPath) - // set go src path - c.SrcRoot = filepath.Join(c.SrcRoot, "src") + */ - c.AppPath = filepath.Join(c.SrcRoot, filepath.FromSlash(c.ImportPath)) - utils.Logger.Info("Set application path", "path", c.AppPath) } // Sets the versions on the command config diff --git a/revel/build.go b/revel/build.go index 9e43f69..1106cc5 100644 --- a/revel/build.go +++ b/revel/build.go @@ -59,6 +59,7 @@ func updateBuildConfig(c *model.CommandConfig, args []string) bool { // The main entry point to build application from command line func buildApp(c *model.CommandConfig) (err error) { + appImportPath, destPath, mode := c.ImportPath, c.Build.TargetPath, DefaultRunMode if len(c.Build.Mode) > 0 { mode = c.Build.Mode @@ -113,7 +114,7 @@ func buildCopyFiles(c *model.CommandConfig, app *harness.App, revel_paths *model srcPath := filepath.Join(destPath, "src") destBinaryPath := filepath.Join(destPath, filepath.Base(app.BinaryPath)) tmpRevelPath := filepath.Join(srcPath, filepath.FromSlash(model.RevelImportPath)) - if err = utils.CopyFile(destBinaryPath, app.BinaryPath); err != nil { + if err = utils.CopyFile(destBinaryPath, filepath.Join(revel_paths.BasePath, app.BinaryPath)); err != nil { return } utils.MustChmod(destBinaryPath, 0755) diff --git a/revel/new_test.go b/revel/new_test.go index f0cb757..2deac86 100644 --- a/revel/new_test.go +++ b/revel/new_test.go @@ -18,6 +18,12 @@ func TestNew(t *testing.T) { c := newApp("new-test", model.NEW, nil, a) a.Nil(main.Commands[model.NEW].RunWith(c), "New failed") }) + t.Run("New-NotVendoredmode", func(t *testing.T) { + a := assert.New(t) + c := newApp("new-notvendored", model.NEW, nil, a) + c.New.NotVendored = true + a.Nil(main.Commands[model.NEW].RunWith(c), "New failed") + }) t.Run("Path", func(t *testing.T) { a := assert.New(t) c := newApp("new/test/a", model.NEW, nil, a) diff --git a/revel/revel.go b/revel/revel.go index 2c32df5..06be182 100644 --- a/revel/revel.go +++ b/revel/revel.go @@ -91,6 +91,9 @@ func main() { utils.InitLogger(wd, logger.LvlWarn) } + // Setup package resolver + c.InitPackageResolver() + if err := c.UpdateImportPath(); err != nil { utils.Logger.Error(err.Error()) parser.WriteHelp(os.Stdout) @@ -100,12 +103,6 @@ func main() { command := Commands[c.Index] println("Revel executing:", command.Short) - // Setting go paths - // c.InitGoPaths() - - // Setup package resolver - c.InitPackageResolver() - if err := command.RunWith(c); err != nil { utils.Logger.Error("Unable to execute", "error", err) os.Exit(1) diff --git a/utils/file.go b/utils/file.go index da8a177..ab915bd 100644 --- a/utils/file.go +++ b/utils/file.go @@ -322,7 +322,8 @@ func Empty(dirname string) bool { // Find the full source dir for the import path, uses the build.Default.GOPATH to search for the directory func FindSrcPaths(appPath string, packageList []string, packageResolver func(pkgName string) error) (sourcePathsmap map[string]string, err error) { sourcePathsmap, missingList, err := findSrcPaths(appPath, packageList) - if err != nil && packageResolver != nil { + if err != nil && packageResolver != nil || len(missingList)>0 { + Logger.Info("Failed to find package, attempting to call resolver for missing packages","missing packages",missingList) for _, item := range missingList { if err = packageResolver(item); err != nil { return @@ -351,22 +352,28 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str Dir:appPath, } sourcePathsmap = map[string]string{} + Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"),config.Env) pkgs, err := packages.Load(config, packagesList...) + Logger.Infof("Environment path %s root %s config env %s", os.Getenv("GOPATH"), os.Getenv("GOROOT"),config.Env) Logger.Info("Loaded packages ", "len results", len(pkgs), "error", err, "basedir", appPath) for _, packageName := range packagesList { - found := false + found := false log := Logger.New("seeking", packageName) for _, pck := range pkgs { log.Info("Found package", "package", pck.ID) if pck.ID == packageName { if pck.Errors != nil && len(pck.Errors) > 0 { log.Info("Error ", "count", len(pck.Errors), "App Import Path", pck.ID, "errors", pck.Errors) + continue + } //a,_ := pck.MarshalJSON() log.Info("Found ", "count", len(pck.GoFiles), "App Import Path", pck.ID, "apppath", appPath) - sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0]) - found = true + if len(pck.GoFiles)>0 { + sourcePathsmap[packageName] = filepath.Dir(pck.GoFiles[0]) + found = true + } } } if !found { @@ -378,5 +385,6 @@ func findSrcPaths(appPath string, packagesList []string) (sourcePathsmap map[str missingList = append(missingList, packageName) } } + return }