Пример #1
0
// 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)
}
Пример #2
0
func TestStart(t *testing.T) {
	dst := "./testdata/project"
	main(handlers, 0, tool.Data{dst})

	rs1, fn1 := walkFunc(dst)
	filepath.Walk(dst, fn1)

	p, err := path.ImportToAbsolute("github.com/colegion/goal/internal/skeleton")
	if err != nil {
		t.Error(err)
		t.FailNow()
	}
	rs2, err := walk(p)
	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	if len(rs1.dirs) != len(rs2.dirs) ||
		len(rs1.files) != len(rs2.files) ||
		len(rs1.srcs) != len(rs2.srcs) {

		t.Error("Looks like not all go files, static files, and/or directories are copied.")
	}

	// Remove the directory we have created.
	os.RemoveAll(dst)
}
Пример #3
0
// Context returns mappings between types that can be parsed using
// strconv package and functions for that conversions.
// All conversion functions meet the following criteria:
// 1. They are exported.
// 2. They expect 3 arguments: url.Values, string, ...int.
// 3. They return 1 argument.
// This is useful for code generation.
func Context() FnMap {
	p, _ := path.ImportToAbsolute("github.com/colegion/goal/strconv")
	fs := FnMap{}
	pkg := reflect.ParseDir(p, false)
	for i := range pkg.Funcs {
		if !strconvFunc(pkg.Funcs[i]) {
			continue
		}
		fs[pkg.Funcs[i].Results[0].Type.String()] = pkg.Funcs[i]
	}
	return fs
}
Пример #4
0
// processPackage gets an import path of a package, processes it, and
// extracts controllers + actions.
func (ps packages) processPackage(importPath string) {
	log.Trace.Printf(`Parsing "%s"...`, importPath)
	dir, err := path.ImportToAbsolute(importPath)
	log.AssertNil(err)
	p := reflect.ParseDir(dir, false)
	cs := ps.extractControllers(p)
	if len(cs.data) > 0 {
		ps[importPath] = controllers{
			data: cs.data,
			init: ps.extractInitFunc(p),
		}
	}
}
Пример #5
0
func createConfig(t *testing.T) []byte {
	p, _ := path.ImportToAbsolute("github.com/colegion/goal/tools/run")

	bs, err := ioutil.ReadFile(
		filepath.Join(p, "./testdata/configs/goal.src.yml"),
	)
	if err != nil {
		t.Error(err)
	}
	err = ioutil.WriteFile(
		filepath.Join(p, "./testdata/configs/goal.yml"), bs, 0666,
	)
	if err != nil {
		t.Error(err)
	}
	return bs
}
Пример #6
0
// 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
}
Пример #7
0
// start is an entry point of the generate handlers command.
func start() {
	// Clean the out directory.
	log.Trace.Printf(`Removing "%s" directory if already exists...`, *output)
	err := os.RemoveAll(*output)
	log.AssertNil(err)

	// Start processing of controllers.
	ps := packages{}
	absInput, err := path.ImportToAbsolute(*input)
	log.AssertNil(err)
	absImport, err := path.AbsoluteToImport(absInput)
	log.AssertNil(err)
	absOutput, err := path.ImportToAbsolute(*output)
	log.AssertNil(err)
	absImportOut, err := path.AbsoluteToImport(absOutput)
	log.AssertNil(err)
	log.Trace.Printf(`Processing "%s" package...`, absImport)
	ps.processPackage(absImport)

	// Start generation of handler packages.
	tpl, err := path.ImportToAbsolute("github.com/colegion/goal/tools/generate/handlers/handlers.go.template")
	log.AssertNil(err)
	t := generation.NewType("", tpl)
	t.Extension = ".go" // Save generated files as a .go source.

	// Iterate through all available packages and generate handlers for them.
	log.Trace.Printf(`Starting generation of "%s" package...`, *pkg)
	for imp := range ps {
		// Check whether current package is the main one
		// and should be stored at the root directory or it is a subpackage.
		//
		// I.e. if --input is "./controllers" and --output is "./assets/handlers",
		// we are saving processed "./controllers" package to "./assets/handlers"
		// and some "github.com/colegion/smth" to "./assets/handlers/github.com/colegion/smth".
		out := *output
		if imp != absImport {
			out = filepath.Join(out, imp)
		}
		t.CreateDir(out)

		// Iterate over all available controllers, generate handlers package on
		// every of them.
		n := 0
		for name := range ps[imp].data {
			// Find parent controllers of this controller.
			cs := []parent{}
			for i, p := range ps[imp].data[name].Parents {
				// Make sure it is a controller rather than just some embedded struct.
				check := p.Import
				if check == "" { // Embedded parent is a local structure.
					check = absImport
				}
				if _, ok := ps[check]; !ok { // Such package is not in the list of scanned ones.
					continue
				}
				if _, ok := ps[check].data[p.Name]; !ok { // There is no such controller.
					continue
				}

				// It is a valid parent controller, add it to the list.
				cs = append(cs, parent{
					ID:     i,
					Import: p.Import,
					Name:   p.Name,
				})
			}

			// Initialize parameters and generate a package.
			t.Package = strings.ToLower(name)
			t.Context = map[string]interface{}{
				"after":     action.MethodAfter,
				"before":    action.MethodBefore,
				"initially": method.InitiallyName,
				"finally":   method.FinallyName,

				"controller":   ps[imp].data[name],
				"controllers":  ps[imp].data,
				"import":       imp,
				"input":        input,
				"name":         name,
				"outputImport": absImportOut,
				"output":       output,
				"package":      pkg,
				"parents":      cs,
				"initFunc":     ps[imp].init,
				"num":          n,

				"actionImport":    action.InterfaceImport,
				"actionInterface": action.Interface,
				"strconv":         action.StrconvContext,
			}
			t.Generate()
			n++
		}
	}
}