Example #1
0
// genSource renders the given template to produce source code, which it writes
// to the given directory and file.
func genSource(dir, filename, templateSource string, args map[string]interface{}) {
	sourceCode := revel.ExecuteTemplate(
		template.Must(template.New("").Parse(templateSource)),
		args)

	// Create a fresh dir.
	tmpPath := filepath.Join(revel.AppPath, dir)
	err := os.RemoveAll(tmpPath)
	if err != nil {
		glog.Errorln("Failed to remove dir:", err)
	}
	err = os.Mkdir(tmpPath, 0777)
	if err != nil {
		glog.Fatalln("Failed to make tmp directory:", err)
	}

	// Create the file
	file, err := os.Create(filepath.Join(tmpPath, filename))
	defer file.Close()
	if err != nil {
		glog.Fatalln("Failed to create file:", err)
	}
	_, err = file.WriteString(sourceCode)
	if err != nil {
		glog.Fatalln("Failed to write to file:", err)
	}
}
Example #2
0
// Recursively read and cache all available messages from all message files on the given path.
func loadMessages(path string) {
	messages = make(map[string]*config.Config)

	if error := filepath.Walk(path, loadMessageFile); error != nil && !os.IsNotExist(error) {
		glog.Errorln("Error reading messages files:", error)
	}
}
Example #3
0
// Render a template corresponding to the calling Controller method.
// Arguments will be added to c.RenderArgs prior to rendering the template.
// They are keyed on their local identifier.
//
// For example:
//
//     func (c Users) ShowUser(id int) revel.Result {
//     	 user := loadUser(id)
//     	 return c.Render(user)
//     }
//
// This action will render views/Users/ShowUser.html, passing in an extra
// key-value "user": (User).
//
// Content negotiation
//
// The template selected depends on the request's format (html, json, xml, txt),
// (which is derived from the Accepts header).  For example, if Request.Format
// was "json", then the above example would look for the
// views/Users/ShowUser.json template instead.
//
// If no template is found and the format is one of "json" or "xml",
// then Render will instead serialize the first argument into that format.
func (c *Controller) Render(extraRenderArgs ...interface{}) Result {
	templatePath := c.Name + "/" + c.MethodType.Name + "." + c.Request.Format

	// Get the calling function name.
	_, _, line, ok := runtime.Caller(1)
	if !ok {
		glog.Error("Failed to get Caller information")
	}

	// If not HTML, first check if the template is present.
	template, err := MainTemplateLoader.Template(templatePath)

	// If not, and there is an arg, serialize that if it's xml or json.
	if template == nil {
		if len(extraRenderArgs) > 0 {
			switch c.Request.Format {
			case "xml":
				return c.RenderXml(extraRenderArgs[0])
			case "json":
				return c.RenderJson(extraRenderArgs[0])
			}
		}
		// Else, render a 404 error saying we couldn't find the template.
		return c.NotFound(err.Error())
	}

	// Get the extra RenderArgs passed in.
	if renderArgNames, ok := c.MethodType.RenderArgNames[line]; ok {
		if len(renderArgNames) == len(extraRenderArgs) {
			for i, extraRenderArg := range extraRenderArgs {
				c.RenderArgs[renderArgNames[i]] = extraRenderArg
			}
		} else {
			glog.Errorln(len(renderArgNames), "RenderArg names found for",
				len(extraRenderArgs), "extra RenderArgs")
		}
	} else {
		glog.Errorln("No RenderArg names found for Render call on line", line,
			"(Method", c.MethodType.Name, ")")
	}

	return &RenderTemplateResult{
		Template:   template,
		RenderArgs: c.RenderArgs,
	}
}
Example #4
0
func cleanSource(dirs ...string) {
	for _, dir := range dirs {
		tmpPath := filepath.Join(revel.AppPath, dir)
		err := os.RemoveAll(tmpPath)
		if err != nil {
			glog.Errorln("Failed to remove dir:", err)
		}
	}
}
Example #5
0
func (r *RedirectToActionResult) Apply(req *Request, resp *Response) {
	url, err := getRedirectUrl(r.val)
	if err != nil {
		glog.Errorln("Couldn't resolve redirect:", err.Error())
		ErrorResult{Error: err}.Apply(req, resp)
		return
	}
	resp.Out.Header().Set("Location", url)
	resp.WriteHeader(http.StatusFound, "")
}
Example #6
0
func (c *MergedConfig) Bool(option string) (result, found bool) {
	result, err := c.config.Bool(c.section, option)
	if err == nil {
		return result, true
	}
	if _, ok := err.(config.OptionError); ok {
		return false, false
	}

	// If it wasn't an OptionError, it must have failed to parse.
	glog.Errorln("Failed to parse config option", option, "as bool:", err)
	return false, false
}
Example #7
0
// Listen registers for events within the given root directories (recursively).
func (w *Watcher) Listen(listener Listener, roots ...string) {
	eventCh := make(chan notify.EventInfo, 100)

	// Walk through all files / directories under the root, adding each to watcher.
	for _, p := range roots {
		// is the directory / file a symlink?
		f, err := os.Lstat(p)
		if err == nil && f.Mode()&os.ModeSymlink == os.ModeSymlink {
			realPath, err := filepath.EvalSymlinks(p)
			if err != nil {
				panic(err)
			}
			p = realPath
		}

		fi, err := os.Stat(p)
		if err != nil {
			glog.Errorln("Failed to stat watched path", p, ":", err)
			continue
		}

		if fi.IsDir() {
			err = notify.Watch(p+string(filepath.Separator)+"...", eventCh, notify.All)
		} else {
			err = notify.Watch(p, eventCh, notify.All)
		}
		if err != nil {
			glog.Errorln("Failed to watch", p, ":", err)
		}
	}

	if w.eagerRebuildEnabled() {
		// Create goroutine to notify file changes in real time
		go w.NotifyWhenUpdated(listener, eventCh)
	}

	w.events = append(w.events, eventCh)
	w.listeners = append(w.listeners, listener)
}
Example #8
0
// SourceLines returns the template's source code.
// A template of the given name must exist, or a panic results.
func (loader *TemplateLoader) SourceLines(templateName string) []string {
	path, ok := loader.templatePaths[templateName]
	if !ok {
		panic("template not found: " + templateName)
	}

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

	// TODO: Better way to split into lines?
	return strings.Split(string(fileBytes), "\n")
}
Example #9
0
// Parse the line, and description from an error message like:
// html/template:Application/Register.html:36: no such template "footer.html"
func parseTemplateError(err error) (templateName string, line int, description string) {
	description = err.Error()
	i := regexp.MustCompile(`:\d+:`).FindStringIndex(description)
	if i != nil {
		line, err = strconv.Atoi(description[i[0]+1 : i[1]-1])
		if err != nil {
			glog.Errorln("Failed to parse line number from error message:", err)
		}
		templateName = description[:i[0]]
		if colon := strings.Index(templateName, ":"); colon != -1 {
			templateName = templateName[colon+1:]
		}
		templateName = strings.TrimSpace(templateName)
		description = description[i[1]+1:]
	}
	return templateName, line, description
}
Example #10
0
// Pluralize, a helper for pluralizing words to correspond to data of dynamic length.
// items - a slice of items, or an integer indicating how many items there are.
// pluralOverrides - optional arguments specifying the output in the
//     singular and plural cases.  by default "" and "s"
func Pluralize(items interface{}, pluralOverrides ...string) string {
	singular, plural := "", "s"
	if len(pluralOverrides) >= 1 {
		singular = pluralOverrides[0]
		if len(pluralOverrides) == 2 {
			plural = pluralOverrides[1]
		}
	}

	switch v := reflect.ValueOf(items); v.Kind() {
	case reflect.Int:
		if items.(int) != 1 {
			return plural
		}
	case reflect.Slice:
		if v.Len() != 1 {
			return plural
		}
	default:
		glog.Errorln("pluralize: unexpected type: ", v)
	}
	return singular
}
Example #11
0
func (router *Router) Reverse(action string, argValues map[string]string) *ActionDefinition {

NEXT_ROUTE:
	// Loop through the routes.
	for _, route := range router.Routes {
		if route.actionPattern == nil {
			continue
		}

		var matches []string = route.actionPattern.FindStringSubmatch(action)
		if len(matches) == 0 {
			continue
		}

		for i, match := range matches[1:] {
			argValues[route.actionPattern.SubexpNames()[i+1]] = match
		}

		// Create a lookup for the route args.
		routeArgs := make(map[string]*arg)
		for _, arg := range route.args {
			routeArgs[arg.name] = arg
		}

		// Enforce the constraints on the arg values.
		for argKey, argValue := range argValues {
			arg, ok := routeArgs[argKey]
			if ok && !arg.constraint.MatchString(argValue) {
				continue NEXT_ROUTE
			}
		}

		// Build up the URL.
		var queryValues url.Values = make(url.Values)
		// Handle optional trailing slashes (e.g. "/?") by removing the question mark.
		path := strings.Replace(route.Path, "?", "", -1)
		for argKey, argValue := range argValues {
			if _, ok := routeArgs[argKey]; ok {
				// If this arg goes into the path, put it in.
				path = regexp.MustCompile(`\{(<[^>]+>)?`+regexp.QuoteMeta(argKey)+`\}`).
					ReplaceAllString(path, url.QueryEscape(string(argValue)))
			} else {
				// Else, add it to the query string.
				queryValues.Set(argKey, argValue)
			}
		}

		// Calculate the final URL and Method
		url := path
		if len(queryValues) > 0 {
			url += "?" + queryValues.Encode()
		}

		method := route.Method
		star := false
		if route.Method == "*" {
			method = "GET"
			star = true
		}

		return &ActionDefinition{
			Url:    url,
			Method: method,
			Star:   star,
			Action: action,
			Args:   argValues,
			Host:   "TODO",
		}
	}
	glog.Errorln("Failed to find reverse route:", action, argValues)
	return nil
}
Example #12
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
}