func parseConfig() { configPath := ConfigFilePath() f, err := os.Open(configPath) switch { case err != nil && err.(*os.PathError).Error.(os.Errno) == syscall.ENOENT: // TODO: write empty file? return case err != nil: log.Printf("Error opening config file %q: %v", ConfigFilePath(), err) return } defer f.Close() dj := json.NewDecoder(f) if err := dj.Decode(&config); err != nil { extra := "" if serr, ok := err.(*json.SyntaxError); ok { if _, serr := f.Seek(0, os.SEEK_SET); serr != nil { log.Fatalf("seek error: %v", serr) } line, col, highlight := errorutil.HighlightBytePosition(f, serr.Offset) extra = fmt.Sprintf(":\nError at line %d, column %d (file offset %d):\n%s", line, col, serr.Offset, highlight) } log.Fatalf("error parsing JSON object in config file %s%s\n%v", ConfigFilePath(), extra, err) } if err := jsonconfig.EvaluateExpressions(config); err != nil { log.Fatalf("error expanding JSON config expressions in %s: %v", configPath, err) } }
// Decodes and evaluates a json config file, watching for include cycles. func (c *configParser) recursiveReadJson(configPath string) (decodedObject map[string]interface{}, err os.Error) { configPath, err = filepath.Abs(configPath) if err != nil { return nil, fmt.Errorf("Failed to expand absolute path for %s", configPath) } if c.touchedFiles[configPath] { return nil, fmt.Errorf("configParser include cycle detected reading config: %v", configPath) } c.touchedFiles[configPath] = true c.includeStack.Push(configPath) defer c.includeStack.Pop() var f *os.File if f, err = os.Open(configPath); err != nil { return nil, fmt.Errorf("Failed to open config: %s, %v", configPath, err) } defer f.Close() decodedObject = make(map[string]interface{}) dj := json.NewDecoder(f) if err = dj.Decode(&decodedObject); err != nil { extra := "" if serr, ok := err.(*json.SyntaxError); ok { if _, serr := f.Seek(0, os.SEEK_SET); serr != nil { log.Fatalf("seek error: %v", serr) } line, col, highlight := errorutil.HighlightBytePosition(f, serr.Offset) extra = fmt.Sprintf(":\nError at line %d, column %d (file offset %d):\n%s", line, col, serr.Offset, highlight) } return nil, fmt.Errorf("error parsing JSON object in config file %s%s\n%v", f.Name(), extra, err) } if err = c.evaluateExpressions(decodedObject); err != nil { return nil, fmt.Errorf("error expanding JSON config expressions in %s:\n%v", f.Name(), err) } return decodedObject, nil }
func main() { flag.Parse() configPath := *flagConfigFile if !filepath.IsAbs(configPath) { configPath = filepath.Join(osutil.CamliConfigDir(), configPath) } f, err := os.Open(configPath) if err != nil { exitFailure("error opening %s: %v", configPath, err) } defer f.Close() dj := json.NewDecoder(f) rootjson := make(map[string]interface{}) if err = dj.Decode(&rootjson); err != nil { extra := "" if serr, ok := err.(*json.SyntaxError); ok { if _, serr := f.Seek(0, os.SEEK_SET); serr != nil { log.Fatalf("seek error: %v", serr) } line, col, highlight := errorutil.HighlightBytePosition(f, serr.Offset) extra = fmt.Sprintf(":\nError at line %d, column %d (file offset %d):\n%s", line, col, serr.Offset, highlight) } exitFailure("error parsing JSON object in config file %s%s\n%v", osutil.UserServerConfigPath(), extra, err) } if err := jsonconfig.EvaluateExpressions(rootjson); err != nil { exitFailure("error expanding JSON config expressions in %s: %v", configPath, err) } ws := webserver.New() baseURL := ws.BaseURL() // Root configuration config := jsonconfig.Obj(rootjson) { cert, key := config.OptionalString("TLSCertFile", ""), config.OptionalString("TLSKeyFile", "") if (cert != "") != (key != "") { exitFailure("TLSCertFile and TLSKeyFile must both be either present or absent") } if cert != "" { ws.SetTLS(cert, key) } } auth.AccessPassword = config.OptionalString("password", "") if url := config.OptionalString("baseURL", ""); url != "" { baseURL = url } prefixes := config.RequiredObject("prefixes") if err := config.Validate(); err != nil { exitFailure("configuration error in root object's keys in %s: %v", configPath, err) } hl := &handlerLoader{ ws: ws, baseURL: baseURL, config: make(map[string]*handlerConfig), handler: make(map[string]interface{}), } for prefix, vei := range prefixes { if !strings.HasPrefix(prefix, "/") { exitFailure("prefix %q doesn't start with /", prefix) } if !strings.HasSuffix(prefix, "/") { exitFailure("prefix %q doesn't end with /", prefix) } pmap, ok := vei.(map[string]interface{}) if !ok { exitFailure("prefix %q value isn't an object", prefix) } pconf := jsonconfig.Obj(pmap) handlerType := pconf.RequiredString("handler") handlerArgs := pconf.OptionalObject("handlerArgs") if err := pconf.Validate(); err != nil { exitFailure("configuration error in prefix %s: %v", prefix, err) } h := &handlerConfig{ prefix: prefix, htype: handlerType, conf: handlerArgs, } hl.config[prefix] = h } hl.setupAll() ws.Serve() }