// scanAnonEmbStructs expects a package and an index of structure in that package. // It scans the structure looking for fields that are anonymously embedded types. // If those types are from other packages, they are processed as well. // As a result a list of all found types in a form of []parent is returned. func (ps packages) scanAnonEmbStructs(pkg *reflect.Package, i int) (prs []parent) { // Iterating over fields of the structure. for j := range pkg.Structs[i].Fields { // Make sure current field is embedded anonymously, // i.e. there is no arg name. if pkg.Structs[i].Fields[j].Name != "" { continue } // Ensure the struct is embedded as a pointer. if !pkg.Structs[i].Fields[j].Type.Star { continue } // Add the field to the list of results. imp, _ := pkg.Imports.Value(pkg.Structs[i].File, pkg.Structs[i].Fields[j].Type.Package) p, _ := path.CleanImport(imp) prs = append(prs, parent{ Import: p, Name: pkg.Structs[i].Fields[j].Type.Name, }) // Check whether this import has already been processed. // If not, do it now. if _, ok := ps[imp]; imp != "" && !ok { ps.processPackage(p) } } return }
// Main is an entry point of the subcommand (tool). func main(hs []tool.Handler, i int, args tool.Data) { // The first argument in the list is a path. // If it's missing use an empty string instead. p := args.GetDefault(0, "") // Prepare source and destination directory paths. src, err := path.ImportToAbsolute("github.com/colegion/goal/internal/skeleton") log.AssertNil(err) destImp, err := path.CleanImport(p) log.AssertNil(err) dest, err := path.ImportToAbsolute(destImp) log.AssertNil(err) // Make sure the requested import path (dest) does not exist yet. if _, err := os.Stat(dest); !os.IsNotExist(err) { log.Error.Panicf(`Cannot use "%s", such import path already exists.`, destImp) } // Scan the skeleton directory and get a list of directories / files // to be copied / processed. res, err := walk(src) log.AssertNil(err) // Create the directories in destination path. for i := 0; i < len(res.dirs); i++ { err = os.MkdirAll(filepath.Join(dest, res.dirs[i]), 0755) log.AssertNil(err) } // Copy static files to the destination directories. for i := 0; i < len(res.files); i++ { copyFile(res.files[i].absolute, filepath.Join(dest, res.files[i].relative)) } // Process source files and copy to the destination directories. for i := 0; i < len(res.srcs); i++ { copyModifiedFile( res.srcs[i].absolute, filepath.Join(dest, res.srcs[i].relative), [][][]byte{ { []byte("github.com/colegion/goal/internal/skeleton"), []byte(destImp), }, }, ) } log.Info.Printf(info, destImp) }
// main is an entry point of the "run" subcommand (tool). func main(hs []tool.Handler, i int, args tool.Data) { // The first argument in the list is a path. // If it's missing use an empty string instead. p := args.GetDefault(0, "") // Determine import path and absolute path of the project to run. imp, err := path.CleanImport(p) log.AssertNil(err) dir, err := path.ImportToAbsolute(imp) log.AssertNil(err) // Prepare a path of configuration file. cf := filepath.Join(dir, ConfigFile) // Start a user tasks runner and instances controller. go instanceController() // Start a configuration file watcher. go configDaemon(imp, cf) // Show user friendly errors and terminate subprograms // in case of panics. defer func() { channel <- message{ action: "exit", } <-stopped log.Trace.Panicln("Application has been terminated.") }() // Execute all commands from the requested directory. curr, _ := os.Getwd() os.Chdir(dir) // pushd defer func() { // Going back to the initial directory. os.Chdir(curr) // popd }() // Load the configuration. reloadConfig() // Cleaning up after we are done. signal.Notify(notify, os.Interrupt, syscall.SIGTERM) <-notify }