Example #1
0
// Load a single message file
func loadMessageFile(path string, info os.FileInfo, osError error) error {
	if osError != nil {
		return osError
	}
	if info.IsDir() {
		return nil
	}

	if matched, _ := regexp.MatchString(messageFilePattern, info.Name()); matched {
		if config, error := parseMessagesFile(path); error != nil {
			return error
		} else {
			locale := parseLocaleFromFileName(info.Name())

			// If we have already parsed a message file for this locale, merge both
			if _, exists := messages[locale]; exists {
				messages[locale].Merge(config)
				glog.V(1).Infof("Successfully merged messages for locale '%s'", locale)
			} else {
				messages[locale] = config
			}

			glog.V(1).Infoln("Successfully loaded messages from file", info.Name())
		}
	} else {
		glog.V(1).Infof("Ignoring file %s because it did not have a valid extension", info.Name())
	}

	return nil
}
Example #2
0
func I18nFilter(c *Controller, fc []Filter) {
	if foundCookie, cookieValue := hasLocaleCookie(c.Request); foundCookie {
		glog.V(1).Infof("Found locale cookie value: %s", cookieValue)
		setCurrentLocaleControllerArguments(c, cookieValue)
	} else if foundHeader, headerValue := hasAcceptLanguageHeader(c.Request); foundHeader {
		glog.V(1).Infof("Found Accept-Language header value: %s", headerValue)
		setCurrentLocaleControllerArguments(c, headerValue)
	} else {
		glog.V(1).Info("Unable to find locale in cookie or header, using empty string")
		setCurrentLocaleControllerArguments(c, "")
	}
	fc[0](c, fc[1:])
}
Example #3
0
func ActionInvoker(c *Controller, _ []Filter) {
	// Instantiate the method.
	methodValue := reflect.ValueOf(c.AppController).MethodByName(c.MethodType.Name)

	// Collect the values for the method's arguments.
	var methodArgs []reflect.Value
	for _, arg := range c.MethodType.Args {
		// If they accept a websocket connection, treat that arg specially.
		var boundArg reflect.Value
		if arg.Type == websocketType {
			boundArg = reflect.ValueOf(c.Websocket)
		} else {
			glog.V(1).Infoln("Binding:", arg.Name, "as", arg.Type)
			boundArg = Bind(c.Params, arg.Name, arg.Type)
		}
		methodArgs = append(methodArgs, boundArg)
	}

	var resultValue reflect.Value
	if methodValue.Type().IsVariadic() {
		resultValue = methodValue.CallSlice(methodArgs)[0]
	} else {
		resultValue = methodValue.Call(methodArgs)[0]
	}
	if resultValue.Kind() == reflect.Interface && !resultValue.IsNil() {
		c.Result = resultValue.Interface().(Result)
	}
}
Example #4
0
// Perform a message look-up for the given locale and message using the given arguments.
//
// When either an unknown locale or message is detected, a specially formatted string is returned.
func Message(locale, message string, args ...interface{}) string {
	language, region := parseLocale(locale)
	glog.V(1).Infof("Resolving message '%s' for language '%s' and region '%s'", message, language, region)

	var value string
	var err error
	messageConfig, knownLanguage := messages[language]
	if knownLanguage {
		// This works because unlike the goconfig documentation suggests it will actually
		// try to resolve message in DEFAULT if it did not find it in the given section.
		value, err = messageConfig.String(region, message)
		if err != nil {
			glog.V(1).Infof("Unknown message '%s' for locale '%s', trying default language", message, locale)
			// Continue to try default language
		}
	} else {
		glog.V(1).Infof("Unsupported language for locale '%s' and message '%s', trying default language", locale, message)
	}

	if value == "" {
		if defaultLanguage, found := Config.String(defaultLanguageOption); found {
			glog.V(1).Infof("Using default language '%s'", defaultLanguage)

			messageConfig, knownLanguage = messages[defaultLanguage]
			if !knownLanguage {
				glog.Warningf("Unsupported default language for locale '%s' and message '%s'", defaultLanguage, message)
				return fmt.Sprintf(unknownValueFormat, message)
			}

			value, err = messageConfig.String(region, message)
			if err != nil {
				glog.Warningf("Unknown message '%s' for default locale '%s'", message, locale)
				return fmt.Sprintf(unknownValueFormat, message)
			}
		} else {
			glog.Warningf("Unable to find default language option (%s); messages for unsupported locales will never be translated", defaultLanguageOption)
			return fmt.Sprintf(unknownValueFormat, message)
		}
	}

	if len(args) > 0 {
		glog.V(1).Infof("Arguments detected, formatting '%s' with %v", value, args)
		value = fmt.Sprintf(value, args...)
	}

	return value
}
Example #5
0
// Terminate the app server if it's running.
func (cmd AppCmd) Kill() {
	if cmd.Cmd != nil && (cmd.ProcessState == nil || !cmd.ProcessState.Exited()) {
		glog.V(1).Infoln("Killing revel server pid", cmd.Process.Pid)
		err := cmd.Process.Kill()
		if err != nil {
			glog.Fatalln("Failed to kill revel server:", err)
		}
	}
}
Example #6
0
// Determine whether the given request has a valid language cookie value.
func hasLocaleCookie(request *Request) (bool, string) {
	if request != nil && request.Cookies() != nil {
		name := Config.StringDefault(localeCookieConfigKey, CookiePrefix+"_LANG")
		if cookie, error := request.Cookie(name); error == nil {
			return true, cookie.Value
		} else {
			glog.V(1).Infof("Unable to read locale cookie with name '%s': %s", name, error.Error())
		}
	}

	return false, ""
}
Example #7
0
func runApp(args []string) {
	if len(args) == 0 {
		errorf("No import path given.\nRun 'revel help run' for usage.\n")
	}

	// Determine the run mode.
	mode := "dev"
	if len(args) >= 2 {
		mode = args[1]
	}

	// Find and parse app.conf
	revel.Init(mode, args[0], "")
	revel.LoadModules()
	revel.LoadMimeConfig()

	// Set working directory to BasePath, to make relative paths convenient and
	// dependable.
	if err := os.Chdir(revel.BasePath); err != nil {
		log.Fatalln("Failed to change directory into app path: ", err)
	}

	// Determine the override port, if any.
	port := revel.HttpPort
	if len(args) == 3 {
		var err error
		if port, err = strconv.Atoi(args[2]); err != nil {
			errorf("Failed to parse port as integer: %s", args[2])
		}
	}

	glog.Infof("Running %s (%s) in %s mode", revel.AppName, revel.ImportPath, mode)
	glog.V(1).Info("Base path: ", revel.BasePath)

	// If the app is run in "watched" mode, use the harness to run it.
	if revel.Config.BoolDefault("watch", true) && revel.Config.BoolDefault("watch.code", true) {
		revel.HttpPort = port
		harness.NewHarness().Run() // Never returns.
	}

	// Else, just build and run the app.
	app, err := harness.Build()
	if err != nil {
		errorf("Failed to build app: %s", err)
	}
	app.Port = port
	app.Cmd().Run()
}
Example #8
0
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 == "" {
			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") {
					glog.V(1).Info("Could not find import: ", fullPath)
				}
				continue
			}
			pkgAlias = pkg.Name
		}

		imports[pkgAlias] = fullPath
	}
}
Example #9
0
// Rebuild the Revel application and run it on the given port.
func (h *Harness) Refresh() (err *revel.Error) {
	if h.app != nil {
		h.app.Kill()
	}

	glog.V(1).Info("Rebuild")
	h.app, err = Build()
	if err != nil {
		return
	}

	h.app.Port = h.port
	if err2 := h.app.Cmd().Start(); err2 != nil {
		return &revel.Error{
			Title:       "App failed to start up",
			Description: err2.Error(),
		}
	}

	return
}
Example #10
0
// Start the app server, and wait until it is ready to serve requests.
func (cmd AppCmd) Start() error {
	listeningWriter := startupListeningWriter{os.Stdout, make(chan bool)}
	cmd.Stdout = listeningWriter
	glog.V(1).Infoln("Exec app:", cmd.Path, cmd.Args)
	if err := cmd.Cmd.Start(); err != nil {
		glog.Fatalln("Error running:", err)
	}

	select {
	case <-cmd.waitChan():
		return errors.New("revel/harness: app died")

	case <-time.After(30 * time.Second):
		cmd.Kill()
		return errors.New("revel/harness: app timed out")

	case <-listeningWriter.notifyReady:
		return nil
	}
	panic("Impossible")
}
Example #11
0
// Register a Controller and its Methods with Revel.
func RegisterController(c interface{}, methods []*MethodType) {
	// De-star the controller type
	// (e.g. given TypeOf((*Application)(nil)), want TypeOf(Application))
	var t reflect.Type = reflect.TypeOf(c)
	var elem reflect.Type = t.Elem()

	// De-star all of the method arg types too.
	for _, m := range methods {
		m.lowerName = strings.ToLower(m.Name)
		for _, arg := range m.Args {
			arg.Type = arg.Type.Elem()
		}
	}

	controllers[strings.ToLower(elem.Name())] = &ControllerType{
		Type:              elem,
		Methods:           methods,
		ControllerIndexes: findControllers(elem),
	}
	glog.V(1).Infof("Registered controller: %s", elem.Name())
}
Example #12
0
// getStructTypeDecl checks if the given decl is a type declaration for a
// struct.  If so, the TypeSpec is returned.
func getStructTypeDecl(decl ast.Decl) (spec *ast.TypeSpec, found bool) {
	genDecl, ok := decl.(*ast.GenDecl)
	if !ok {
		return
	}

	if genDecl.Tok != token.TYPE {
		return
	}

	if len(genDecl.Specs) != 1 {
		glog.V(1).Infof("Surprising: Decl does not have 1 Spec: %v", genDecl)
		return
	}

	spec = genDecl.Specs[0].(*ast.TypeSpec)
	if _, ok := spec.Type.(*ast.StructType); ok {
		found = true
	}

	return
}
Example #13
0
// Refresh scans the views directory and parses all templates using the
// configured TemplateEngines.  If a template fails to parse, the error is set
// on the loader (and returned).
func (loader *TemplateLoader) Refresh() *Error {
	glog.V(1).Infof("Refreshing templates from %s", loader.paths)
	loader.compileError = nil
	loader.templatePaths = map[string]string{}

	// Set the template delimiters for the project if present, then split into left
	// and right delimiters around a space character
	var splitDelims []string
	if delims := Config.StringDefault("template.delimiters", ""); delims != "" {
		splitDelims = strings.Split(delims, " ")
		if len(splitDelims) != 2 {
			glog.Fatalln("app.conf: Incorrect format for template.delimiters")
		}
	}

	loader.defaultEngine = NewTextTemplateEngine()
	loader.engines = map[string]TemplateEngine{
		".html": NewHtmlTemplateEngine(),
		".xml":  NewHtmlTemplateEngine(),
		".json": NewTextTemplateEngine(),
		".txt":  NewTextTemplateEngine(),
	}

	// Walk through the template loader's paths and pass each template to the
	// appropriate engine.
	for _, basePath := range loader.paths {

		// Walk only returns an error if the template loader is completely unusable
		// (namely, if one of the TemplateFuncs does not have an acceptable signature).
		funcErr := filepath.Walk(basePath, func(path string, info os.FileInfo, err error) (walkErr error) {
			defer func() {
				if err := recover(); err != nil {
					walkErr = &Error{
						Title:       "Panic (Template Loader)",
						Description: fmt.Sprintln(err),
					}
				}
			}()

			if err != nil {
				glog.Errorln("error walking templates:", err)
				return nil
			}

			// Walk into directories.
			if info.IsDir() {
				if !loader.WatchDir(info.Name()) {
					return filepath.SkipDir
				}
				return nil
			}

			if !loader.WatchFile(info.Name()) {
				return nil
			}

			// Convert template names to use forward slashes, even on Windows.
			templateName := path[len(basePath)+1:]
			if os.PathSeparator == '\\' {
				templateName = strings.Replace(templateName, "\\", "/", -1)
			}

			// If we already loaded a template of this name, skip it.
			if _, ok := loader.templatePaths[templateName]; ok {
				return nil
			}
			loader.templatePaths[templateName] = path

			fileBytes, err := ioutil.ReadFile(path)
			if err != nil {
				glog.Errorln("Failed reading file:", path)
				return nil
			}

			ext := filepath.Ext(templateName)
			engine, ok := loader.engines[ext]
			if !ok {
				engine = loader.defaultEngine
			}

			// If alternate delimiters set for the project, change them for this template.
			if splitDelims != nil {
				if strings.HasPrefix(path, ViewsPath) {
					engine.Delims(splitDelims[0], splitDelims[1])
				} else {
					engine.Delims("", "")
				}
			}

			err = engine.Parse(templateName, string(fileBytes))

			// Store / report the first error encountered.
			if err != nil && loader.compileError == nil {
				_, line, description := parseTemplateError(err)
				loader.compileError = &Error{
					Title:       "Template Compilation Error",
					Path:        templateName,
					Description: description,
					Line:        line,
					SourceLines: strings.Split(string(fileBytes), "\n"),
				}
				glog.Errorf("Template compilation error (In %s around line %d):\n%s",
					templateName, line, description)
			}

			return nil
		})

		// If there was an error with the Funcs, set it and return immediately.
		if funcErr != nil {
			loader.compileError = funcErr.(*Error)
			return loader.compileError
		}
	}
	return loader.compileError
}
Example #14
0
// Run the app server inline.  Never returns.
func (cmd AppCmd) Run() {
	glog.V(1).Infoln("Exec app:", cmd.Path, cmd.Args)
	if err := cmd.Cmd.Run(); err != nil {
		glog.Fatalln("Error running:", err)
	}
}
Example #15
0
// Build the app:
// 1. Generate the the main.go file.
// 2. Run the appropriate "go build" command.
// Requires that revel.Init has been called previously.
// Returns the path to the built binary, and an error if there was a problem building it.
func Build() (app *App, compileError *revel.Error) {
	start := time.Now()

	// First, clear the generated files (to avoid them messing with ProcessSource).
	cleanSource("tmp", "routes")

	sourceInfo, compileError := ProcessSource(revel.CodePaths)
	if compileError != nil {
		return nil, compileError
	}

	// Add the db.import to the import paths.
	if dbImportPath, found := revel.Config.String("db.import"); found {
		sourceInfo.InitImportPaths = append(sourceInfo.InitImportPaths, dbImportPath)
	}

	// Generate two source files.
	templateArgs := map[string]interface{}{
		"Controllers":    sourceInfo.ControllerSpecs(),
		"ValidationKeys": sourceInfo.ValidationKeys,
		"ImportPaths":    calcImportAliases(sourceInfo),
		"TestSuites":     sourceInfo.TestSuites(),
	}
	genSource("tmp", "main.go", MAIN, templateArgs)
	genSource("routes", "routes.go", ROUTES, templateArgs)

	// Read build config.
	buildTags := revel.Config.StringDefault("build.tags", "")

	// Build the user program (all code under app).
	// It relies on the user having "go" installed.
	goPath, err := exec.LookPath("go")
	if err != nil {
		glog.Fatalf("Go executable not found in PATH.")
	}

	pkg, err := build.Default.Import(revel.ImportPath, "", build.FindOnly)
	if err != nil {
		glog.Fatalln("Failure importing", revel.ImportPath)
	}
	binName := filepath.Join(pkg.BinDir, filepath.Base(revel.BasePath))
	if runtime.GOOS == "windows" {
		binName += ".exe"
	}

	gotten := make(map[string]struct{})
	for {
		buildCmd := exec.Command(goPath, "build",
			"-i",
			"-tags", buildTags,
			"-o", binName, path.Join(revel.ImportPath, "app", "tmp"))
		glog.V(1).Infoln("Exec:", buildCmd.Args)
		output, err := buildCmd.CombinedOutput()

		// If the build succeeded, we're done.
		if err == nil {
			glog.Infof("Build took %s", time.Since(start))
			return NewApp(binName), nil
		}
		glog.Error(string(output))

		// See if it was an import error that we can go get.
		matches := importErrorPattern.FindStringSubmatch(string(output))
		if matches == nil {
			return nil, newCompileError(output)
		}

		// Ensure we haven't already tried to go get it.
		pkgName := matches[1]
		if _, alreadyTried := gotten[pkgName]; alreadyTried {
			return nil, newCompileError(output)
		}
		gotten[pkgName] = struct{}{}

		// Execute "go get <pkg>"
		getCmd := exec.Command(goPath, "get", pkgName)
		glog.V(1).Infoln("Exec:", getCmd.Args)
		getOutput, err := getCmd.CombinedOutput()
		if err != nil {
			glog.Error(string(getOutput))
			return nil, newCompileError(output)
		}

		// Success getting the import, attempt to build again.
	}
	glog.Fatal("Not reachable")
	return nil, nil
}