From 2bcb748cf0ec6b27df5ae3b7deae8ce94be86809 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 15 Apr 2011 22:22:30 -0700 Subject: [PATCH] Make jsonconfig into its own library Will move away from camli/blobserver in future commit. --- build.pl | 1 + lib/go/camli/jsonconfig/jsonconfig.go | 137 ++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 lib/go/camli/jsonconfig/jsonconfig.go diff --git a/build.pl b/build.pl index 6f78daa24..0ad04ec21 100755 --- a/build.pl +++ b/build.pl @@ -404,6 +404,7 @@ TARGET: lib/go/camli/blobserver/s3 TARGET: lib/go/camli/client TARGET: lib/go/camli/errorutil TARGET: lib/go/camli/httputil +TARGET: lib/go/camli/jsonconfig TARGET: lib/go/camli/jsonsign TARGET: lib/go/camli/lru TARGET: lib/go/camli/magic diff --git a/lib/go/camli/jsonconfig/jsonconfig.go b/lib/go/camli/jsonconfig/jsonconfig.go new file mode 100644 index 000000000..2500a38d1 --- /dev/null +++ b/lib/go/camli/jsonconfig/jsonconfig.go @@ -0,0 +1,137 @@ +/* +Copyright 2011 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package jsonconfig + +import ( + "fmt" + "os" + "strings" +) + +type Obj map[string]interface{} + +func (jc Obj) RequiredString(key string) string { + jc.noteKnownKey(key) + ei, ok := jc[key] + if !ok { + jc.appendError(fmt.Errorf("Missing required config key %q (string)", key)) + return "" + } + s, ok := ei.(string) + if !ok { + jc.appendError(fmt.Errorf("Expected config key %q to be a string", key)) + return "" + } + return s +} + +func (jc Obj) OptionalString(key, def string) string { + jc.noteKnownKey(key) + ei, ok := jc[key] + if !ok { + return def + } + s, ok := ei.(string) + if !ok { + jc.appendError(fmt.Errorf("Expected config key %q to be a string", key)) + return "" + } + return s +} + +func (jc Obj) RequiredBool(key string) bool { + jc.noteKnownKey(key) + ei, ok := jc[key] + if !ok { + jc.appendError(fmt.Errorf("Missing required config key %q (boolean)", key)) + return false + } + b, ok := ei.(bool) + if !ok { + jc.appendError(fmt.Errorf("Expected config key %q to be a boolean", key)) + return false + } + return b +} + +func (jc Obj) OptionalBool(key string, def bool) bool { + jc.noteKnownKey(key) + ei, ok := jc[key] + if !ok { + return def + } + b, ok := ei.(bool) + if !ok { + jc.appendError(fmt.Errorf("Expected config key %q to be a boolean", key)) + return def + } + return b +} + +func (jc Obj) noteKnownKey(key string) { + _, ok := jc["_knownkeys"] + if !ok { + jc["_knownkeys"] = make(map[string]bool) + } + jc["_knownkeys"].(map[string]bool)[key] = true +} + +func (jc Obj) appendError(err os.Error) { + ei, ok := jc["_errors"] + if ok { + jc["_errors"] = append(ei.([]os.Error), err) + } else { + jc["_errors"] = []os.Error{err} + } +} + +func (jc Obj) lookForUnknownKeys() { + ei, ok := jc["_knownkeys"] + var known map[string]bool + if ok { + known = ei.(map[string]bool) + } + for k, _ := range jc { + if ok && known[k] { + continue + } + if strings.HasPrefix(k, "_") { + // Permit keys with a leading underscore as a + // form of comments. + continue + } + jc.appendError(fmt.Errorf("Unknown key %q", k)) + } +} + +func (jc Obj) Validate() os.Error { + jc.lookForUnknownKeys() + + ei, ok := jc["_errors"] + if !ok { + return nil + } + errList := ei.([]os.Error) + if len(errList) == 1 { + return errList[0] + } + strs := make([]string, 0) + for _, v := range errList { + strs = append(strs, v.String()) + } + return fmt.Errorf("Multiple errors: " + strings.Join(strs, ", ")) +}