From b6b39a669f54628ce90bc3ce01779afb073f59a6 Mon Sep 17 00:00:00 2001
From: whosonfirst
-
+
+
+
get json values quickly
@@ -14,6 +16,10 @@ It has features such as [one line retrieval](#get-a-value), [dot notation paths] Also check out [SJSON](https://github.com/tidwall/sjson) for modifying json, and the [JJ](https://github.com/tidwall/jj) command line tool. +This README is a quick overview of how to use GJSON, for more information check out [GJSON Syntax](SYNTAX.md). + +GJSON is also available for [Python](https://github.com/volans-/gjson-py) and [Rust](https://github.com/tidwall/gjson.rs) + Getting Started =============== @@ -200,6 +206,11 @@ There are currently the following built-in modifiers: - `@valid`: Ensure the json document is valid. - `@flatten`: Flattens an array. - `@join`: Joins multiple objects into a single object. +- `@keys`: Returns an array of keys for an object. +- `@values`: Returns an array of values for an object. +- `@tostr`: Converts json to a string. Wraps a json string. +- `@fromstr`: Converts a string from json. Unwraps a json string. +- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db). ### Modifier arguments @@ -434,14 +445,15 @@ Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/js and [json-iterator](https://github.com/json-iterator/go) ``` -BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op -BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op -BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op -BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op -BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op -BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op -BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op -BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op +BenchmarkGJSONGet-16 11644512 311 ns/op 0 B/op 0 allocs/op +BenchmarkGJSONUnmarshalMap-16 1122678 3094 ns/op 1920 B/op 26 allocs/op +BenchmarkJSONUnmarshalMap-16 516681 6810 ns/op 2944 B/op 69 allocs/op +BenchmarkJSONUnmarshalStruct-16 697053 5400 ns/op 928 B/op 13 allocs/op +BenchmarkJSONDecoder-16 330450 10217 ns/op 3845 B/op 160 allocs/op +BenchmarkFFJSONLexer-16 1424979 2585 ns/op 880 B/op 8 allocs/op +BenchmarkEasyJSONLexer-16 3000000 729 ns/op 501 B/op 5 allocs/op +BenchmarkJSONParserGet-16 3000000 366 ns/op 21 B/op 0 allocs/op +BenchmarkJSONIterator-16 3000000 869 ns/op 693 B/op 14 allocs/op ``` JSON document used: @@ -482,4 +494,4 @@ widget.image.hOffset widget.text.onMouseUp ``` -*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be found [here](https://github.com/tidwall/gjson-benchmarks).* +*These benchmarks were run on a MacBook Pro 16" 2.4 GHz Intel Core i9 using Go 1.17 and can be found [here](https://github.com/tidwall/gjson-benchmarks).* diff --git a/vendor/github.com/tidwall/gjson/SYNTAX.md b/vendor/github.com/tidwall/gjson/SYNTAX.md index 34fdccf..7a9b6a2 100644 --- a/vendor/github.com/tidwall/gjson/SYNTAX.md +++ b/vendor/github.com/tidwall/gjson/SYNTAX.md @@ -13,16 +13,16 @@ This document is designed to explain the structure of a GJSON Path through examp - [Dot vs Pipe](#dot-vs-pipe) - [Modifiers](#modifiers) - [Multipaths](#multipaths) +- [Literals](#literals) The definitive implemenation is [github.com/tidwall/gjson](https://github.com/tidwall/gjson). Use the [GJSON Playground](https://gjson.dev) to experiment with the syntax online. - ## Path structure A GJSON Path is intended to be easily expressed as a series of components seperated by a `.` character. -Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, and `?`. +Along with `.` character, there are a few more that have special meaning, including `|`, `#`, `@`, `\`, `*`, `!`, and `?`. ## Example @@ -77,7 +77,7 @@ Special purpose characters, such as `.`, `*`, and `?` can be escaped with `\`. fav\.movie "Deer Hunter" ``` -You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in you source code. +You'll also need to make sure that the `\` character is correctly escaped when hardcoding a path in your source code. ```go // Go @@ -236,6 +236,11 @@ There are currently the following built-in modifiers: - `@valid`: Ensure the json document is valid. - `@flatten`: Flattens an array. - `@join`: Joins multiple objects into a single object. +- `@keys`: Returns an array of keys for an object. +- `@values`: Returns an array of values for an object. +- `@tostr`: Converts json to a string. Wraps a json string. +- `@fromstr`: Converts a string from json. Unwraps a json string. +- `@group`: Groups arrays of objects. See [e4fc67c](https://github.com/tidwall/gjson/commit/e4fc67c92aeebf2089fabc7872f010e340d105db). #### Modifier arguments @@ -294,7 +299,7 @@ Starting with v1.3.0, GJSON added the ability to join multiple paths together to form new documents. Wrapping comma-separated paths between `[...]` or `{...}` will result in a new array or object, respectively. -For example, using the given multipath +For example, using the given multipath: ``` {name.first,age,"the_murphys":friends.#(last="Murphy")#.first} @@ -310,8 +315,28 @@ determined, then "_" is used. This results in -``` +```json {"first":"Tom","age":37,"the_murphys":["Dale","Jane"]} ``` +### Literals + +Starting with v1.12.0, GJSON added support of json literals, which provides a way for constructing static blocks of json. This is can be particularly useful when constructing a new json document using [multipaths](#multipaths). + +A json literal begins with the '!' declaration character. + +For example, using the given multipath: + +``` +{name.first,age,"company":!"Happysoft","employed":!true} +``` + +Here we selected the first name and age. Then add two new fields, "company" and "employed". + +This results in + +```json +{"first":"Tom","age":37,"company":"Happysoft","employed":true} +``` +*See issue [#249](https://github.com/tidwall/gjson/issues/249) for additional context on JSON Literals.* diff --git a/vendor/github.com/tidwall/gjson/gjson.go b/vendor/github.com/tidwall/gjson/gjson.go index 973c8af..9b0db4e 100644 --- a/vendor/github.com/tidwall/gjson/gjson.go +++ b/vendor/github.com/tidwall/gjson/gjson.go @@ -2,7 +2,6 @@ package gjson import ( - "encoding/json" "strconv" "strings" "time" @@ -189,14 +188,15 @@ func (t Result) Time() time.Time { } // Array returns back an array of values. -// If the result represents a non-existent value, then an empty array will be -// returned. If the result is not a JSON array, the return value will be an +// If the result represents a null value or is non-existent, then an empty +// array will be returned. +// If the result is not a JSON array, the return value will be an // array containing one result. func (t Result) Array() []Result { if t.Type == Null { return []Result{} } - if t.Type != JSON { + if !t.IsArray() { return []Result{t} } r := t.arrayOrMap('[', false) @@ -213,6 +213,11 @@ func (t Result) IsArray() bool { return t.Type == JSON && len(t.Raw) > 0 && t.Raw[0] == '[' } +// IsBool returns true if the result value is a JSON boolean. +func (t Result) IsBool() bool { + return t.Type == True || t.Type == False +} + // ForEach iterates through values. // If the result represents a non-existent value, then no values will be // iterated. If the result is an Object, the iterator will pass the key and @@ -228,17 +233,19 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { return } json := t.Raw - var keys bool + var obj bool var i int var key, value Result for ; i < len(json); i++ { if json[i] == '{' { i++ key.Type = String - keys = true + obj = true break } else if json[i] == '[' { i++ + key.Type = Number + key.Num = -1 break } if json[i] > ' ' { @@ -248,8 +255,9 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { var str string var vesc bool var ok bool + var idx int for ; i < len(json); i++ { - if keys { + if obj { if json[i] != '"' { continue } @@ -264,7 +272,9 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { key.Str = str[1 : len(str)-1] } key.Raw = str - key.Index = s + key.Index = s + t.Index + } else { + key.Num += 1 } for ; i < len(json); i++ { if json[i] <= ' ' || json[i] == ',' || json[i] == ':' { @@ -277,10 +287,17 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { if !ok { return } - value.Index = s + if t.Indexes != nil { + if idx < len(t.Indexes) { + value.Index = t.Indexes[idx] + } + } else { + value.Index = s + t.Index + } if !iterator(key, value) { return } + idx++ } } @@ -297,7 +314,15 @@ func (t Result) Map() map[string]Result { // Get searches result for the specified path. // The result should be a JSON array or object. func (t Result) Get(path string) Result { - return Get(t.Raw, path) + r := Get(t.Raw, path) + if r.Indexes != nil { + for i := 0; i < len(r.Indexes); i++ { + r.Indexes[i] += t.Index + } + } else { + r.Index += t.Index + } + return r } type arrayOrMapResult struct { @@ -388,6 +413,8 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { value.Raw, value.Str = tostr(json[i:]) value.Num = 0 } + value.Index = i + t.Index + i += len(value.Raw) - 1 if r.vc == '{' { @@ -414,6 +441,17 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { } } end: + if t.Indexes != nil { + if len(t.Indexes) != len(r.a) { + for i := 0; i < len(r.a); i++ { + r.a[i].Index = 0 + } + } else { + for i := 0; i < len(r.a); i++ { + r.a[i].Index = t.Indexes[i] + } + } + } return } @@ -425,7 +463,8 @@ end: // use the Valid function first. func Parse(json string) Result { var value Result - for i := 0; i < len(json); i++ { + i := 0 + for ; i < len(json); i++ { if json[i] == '{' || json[i] == '[' { value.Type = JSON value.Raw = json[i:] // just take the entire raw @@ -435,16 +474,20 @@ func Parse(json string) Result { continue } switch json[i] { - default: - if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' { + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + value.Type = Number + value.Raw, value.Num = tonum(json[i:]) + case 'n': + if i+1 < len(json) && json[i+1] != 'u' { + // nan value.Type = Number value.Raw, value.Num = tonum(json[i:]) } else { - return Result{} + // null + value.Type = Null + value.Raw = tolit(json[i:]) } - case 'n': - value.Type = Null - value.Raw = tolit(json[i:]) case 't': value.Type = True value.Raw = tolit(json[i:]) @@ -454,9 +497,14 @@ func Parse(json string) Result { case '"': value.Type = String value.Raw, value.Str = tostr(json[i:]) + default: + return Result{} } break } + if value.Exists() { + value.Index = i + } return value } @@ -530,20 +578,12 @@ func tonum(json string) (raw string, num float64) { return } // could be a '+' or '-'. let's assume so. - continue - } - if json[i] < ']' { - // probably a valid number - continue - } - if json[i] == 'e' || json[i] == 'E' { - // allow for exponential numbers - continue + } else if json[i] == ']' || json[i] == '}' { + // break on ']' or '}' + raw = json[:i] + num, _ = strconv.ParseFloat(raw, 64) + return } - // likely a ']' or '}' - raw = json[:i] - num, _ = strconv.ParseFloat(raw, 64) - return } raw = json num, _ = strconv.ParseFloat(raw, 64) @@ -735,7 +775,7 @@ func parseArrayPath(path string) (r arrayPathResult) { } if path[i] == '.' { r.part = path[:i] - if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1]) { + if !r.arrch && i < len(path)-1 && isDotPiperChar(path[i+1:]) { r.pipe = path[i+1:] r.piped = true } else { @@ -760,7 +800,7 @@ func parseArrayPath(path string) (r arrayPathResult) { // bad query, end now break } - if len(value) > 2 && value[0] == '"' && + if len(value) >= 2 && value[0] == '"' && value[len(value)-1] == '"' { value = value[1 : len(value)-1] if vesc { @@ -896,8 +936,23 @@ right: } // peek at the next byte and see if it's a '@', '[', or '{'. -func isDotPiperChar(c byte) bool { - return !DisableModifiers && (c == '@' || c == '[' || c == '{') +func isDotPiperChar(s string) bool { + if DisableModifiers { + return false + } + c := s[0] + if c == '@' { + // check that the next component is *not* a modifier. + i := 1 + for ; i < len(s); i++ { + if s[i] == '.' || s[i] == '|' { + break + } + } + _, ok := modifiers[s[1:i]] + return ok + } + return c == '[' || c == '{' } type objectPathResult struct { @@ -919,7 +974,7 @@ func parseObjectPath(path string) (r objectPathResult) { } if path[i] == '.' { r.part = path[:i] - if i < len(path)-1 && isDotPiperChar(path[i+1]) { + if i < len(path)-1 && isDotPiperChar(path[i+1:]) { r.pipe = path[i+1:] r.piped = true } else { @@ -949,7 +1004,7 @@ func parseObjectPath(path string) (r objectPathResult) { continue } else if path[i] == '.' { r.part = string(epart) - if i < len(path)-1 && isDotPiperChar(path[i+1]) { + if i < len(path)-1 && isDotPiperChar(path[i+1:]) { r.pipe = path[i+1:] r.piped = true } else { @@ -1089,9 +1144,9 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } if rp.wild { if kesc { - pmatch = match.Match(unescape(key), rp.part) + pmatch = matchLimit(unescape(key), rp.part) } else { - pmatch = match.Match(key, rp.part) + pmatch = matchLimit(key, rp.part) } } else { if kesc { @@ -1102,6 +1157,7 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } hit = pmatch && !rp.more for ; i < len(c.json); i++ { + var num bool switch c.json[i] { default: continue @@ -1149,15 +1205,13 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { return i, true } } - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(c.json, i) - if hit { - c.value.Raw = val - c.value.Type = Number - c.value.Num, _ = strconv.ParseFloat(val, 64) - return i, true + case 'n': + if i+1 < len(c.json) && c.json[i+1] != 'u' { + num = true + break } - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := c.json[i] i, val = parseLiteral(c.json, i) if hit { @@ -1170,12 +1224,33 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } return i, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true + } + if num { + i, val = parseNumber(c.json, i) + if hit { + c.value.Raw = val + c.value.Type = Number + c.value.Num, _ = strconv.ParseFloat(val, 64) + return i, true + } } break } } return i, false } + +// matchLimit will limit the complexity of the match operation to avoid ReDos +// attacks from arbritary inputs. +// See the github.com/tidwall/match.MatchLimit function for more information. +func matchLimit(str, pattern string) bool { + matched, _ := match.MatchLimit(str, pattern, 10000) + return matched +} + func queryMatches(rp *arrayPathResult, value Result) bool { rpv := rp.query.value if len(rpv) > 0 && rpv[0] == '~' { @@ -1213,9 +1288,9 @@ func queryMatches(rp *arrayPathResult, value Result) bool { case ">=": return value.Str >= rpv case "%": - return match.Match(value.Str, rpv) + return matchLimit(value.Str, rpv) case "!%": - return !match.Match(value.Str, rpv) + return !matchLimit(value.Str, rpv) } case Number: rpvn, _ := strconv.ParseFloat(rpv, 64) @@ -1348,6 +1423,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } else { ch = c.json[i] } + var num bool switch ch { default: continue @@ -1430,26 +1506,13 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { return i, true } } - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(c.json, i) - if rp.query.on { - var qval Result - qval.Raw = val - qval.Type = Number - qval.Num, _ = strconv.ParseFloat(val, 64) - if procQuery(qval) { - return i, true - } - } else if hit { - if rp.alogok { - break - } - c.value.Raw = val - c.value.Type = Number - c.value.Num, _ = strconv.ParseFloat(val, 64) - return i, true + case 'n': + if i+1 < len(c.json) && c.json[i+1] != 'u' { + num = true + break } - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := c.json[i] i, val = parseLiteral(c.json, i) if rp.query.on { @@ -1477,6 +1540,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } return i, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true case ']': if rp.arrch && rp.part == "#" { if rp.alogok { @@ -1501,7 +1567,6 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } if idx < len(c.json) && c.json[idx] != ']' { _, res, ok := parseAny(c.json, idx, true) - parentIndex := res.Index if ok { res := res.Get(rp.alogkey) if res.Exists() { @@ -1513,8 +1578,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { raw = res.String() } jsons = append(jsons, []byte(raw)...) - indexes = append(indexes, - res.Index+parentIndex) + indexes = append(indexes, res.Index) k++ } } @@ -1552,6 +1616,26 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } return i + 1, false } + if num { + i, val = parseNumber(c.json, i) + if rp.query.on { + var qval Result + qval.Raw = val + qval.Type = Number + qval.Num, _ = strconv.ParseFloat(val, 64) + if procQuery(qval) { + return i, true + } + } else if hit { + if rp.alogok { + break + } + c.value.Raw = val + c.value.Type = Number + c.value.Num, _ = strconv.ParseFloat(val, 64) + return i, true + } + } break } } @@ -1667,7 +1751,7 @@ type subSelector struct { // first character in path is either '[' or '{', and has already been checked // prior to calling this function. func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) { - modifer := 0 + modifier := 0 depth := 1 colon := 0 start := 1 @@ -1682,6 +1766,7 @@ func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) { } sels = append(sels, sel) colon = 0 + modifier = 0 start = i + 1 } for ; i < len(path); i++ { @@ -1689,11 +1774,11 @@ func parseSubSelectors(path string) (sels []subSelector, out string, ok bool) { case '\\': i++ case '@': - if modifer == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') { - modifer = i + if modifier == 0 && i > 0 && (path[i-1] == '.' || path[i-1] == '|') { + modifier = i } case ':': - if modifer == 0 && colon == 0 && depth == 1 { + if modifier == 0 && colon == 0 && depth == 1 { colon = i } case ',': @@ -1746,24 +1831,71 @@ func isSimpleName(component string) bool { return false } switch component[i] { - case '[', ']', '{', '}', '(', ')', '#', '|': + case '[', ']', '{', '}', '(', ')', '#', '|', '!': return false } } return true } -func appendJSONString(dst []byte, s string) []byte { +var hexchars = [...]byte{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', +} + +func appendHex16(dst []byte, x uint16) []byte { + return append(dst, + hexchars[x>>12&0xF], hexchars[x>>8&0xF], + hexchars[x>>4&0xF], hexchars[x>>0&0xF], + ) +} + +// AppendJSONString is a convenience function that converts the provided string +// to a valid JSON string and appends it to dst. +func AppendJSONString(dst []byte, s string) []byte { + dst = append(dst, make([]byte, len(s)+2)...) + dst = append(dst[:len(dst)-len(s)-2], '"') for i := 0; i < len(s); i++ { - if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 { - d, _ := json.Marshal(s) - return append(dst, string(d)...) + if s[i] < ' ' { + dst = append(dst, '\\') + switch s[i] { + case '\n': + dst = append(dst, 'n') + case '\r': + dst = append(dst, 'r') + case '\t': + dst = append(dst, 't') + default: + dst = append(dst, 'u') + dst = appendHex16(dst, uint16(s[i])) + } + } else if s[i] == '>' || s[i] == '<' || s[i] == '&' { + dst = append(dst, '\\', 'u') + dst = appendHex16(dst, uint16(s[i])) + } else if s[i] == '\\' { + dst = append(dst, '\\', '\\') + } else if s[i] == '"' { + dst = append(dst, '\\', '"') + } else if s[i] > 127 { + // read utf8 character + r, n := utf8.DecodeRuneInString(s[i:]) + if n == 0 { + break + } + if r == utf8.RuneError && n == 1 { + dst = append(dst, `\ufffd`...) + } else if r == '\u2028' || r == '\u2029' { + dst = append(dst, `\u202`...) + dst = append(dst, hexchars[r&0xF]) + } else { + dst = append(dst, s[i:i+n]...) + } + i = i + n - 1 + } else { + dst = append(dst, s[i]) } } - dst = append(dst, '"') - dst = append(dst, s...) - dst = append(dst, '"') - return dst + return append(dst, '"') } type parseContext struct { @@ -1810,23 +1942,25 @@ type parseContext struct { // use the Valid function first. func Get(json, path string) Result { if len(path) > 1 { - if !DisableModifiers { - if path[0] == '@' { - // possible modifier - var ok bool - var npath string - var rjson string + if (path[0] == '@' && !DisableModifiers) || path[0] == '!' { + // possible modifier + var ok bool + var npath string + var rjson string + if path[0] == '@' && !DisableModifiers { npath, rjson, ok = execModifier(json, path) - if ok { - path = npath - if len(path) > 0 && (path[0] == '|' || path[0] == '.') { - res := Get(rjson, path[1:]) - res.Index = 0 - res.Indexes = nil - return res - } - return Parse(rjson) + } else if path[0] == '!' { + npath, rjson, ok = execStatic(json, path) + } + if ok { + path = npath + if len(path) > 0 && (path[0] == '|' || path[0] == '.') { + res := Get(rjson, path[1:]) + res.Index = 0 + res.Indexes = nil + return res } + return Parse(rjson) } } if path[0] == '[' || path[0] == '{' { @@ -1851,14 +1985,14 @@ func Get(json, path string) Result { if sub.name[0] == '"' && Valid(sub.name) { b = append(b, sub.name...) } else { - b = appendJSONString(b, sub.name) + b = AppendJSONString(b, sub.name) } } else { last := nameOfLast(sub.path) if isSimpleName(last) { - b = appendJSONString(b, last) + b = AppendJSONString(b, last) } else { - b = appendJSONString(b, "_") + b = AppendJSONString(b, "_") } } b = append(b, ':') @@ -2071,6 +2205,7 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { if json[i] <= ' ' { continue } + var num bool switch json[i] { case '"': i++ @@ -2090,15 +2225,13 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { } } return i, res, true - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(json, i) - if hit { - res.Raw = val - res.Type = Number - res.Num, _ = strconv.ParseFloat(val, 64) + case 'n': + if i+1 < len(json) && json[i+1] != 'u' { + num = true + break } - return i, res, true - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := json[i] i, val = parseLiteral(json, i) if hit { @@ -2111,7 +2244,20 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { } return i, res, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true + } + if num { + i, val = parseNumber(json, i) + if hit { + res.Raw = val + res.Type = Number + res.Num, _ = strconv.ParseFloat(val, 64) + } + return i, res, true } + } return i, res, false } @@ -2483,8 +2629,40 @@ func safeInt(f float64) (n int64, ok bool) { return int64(f), true } +// execStatic parses the path to find a static value. +// The input expects that the path already starts with a '!' +func execStatic(json, path string) (pathOut, res string, ok bool) { + name := path[1:] + if len(name) > 0 { + switch name[0] { + case '{', '[', '"', '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9': + _, res = parseSquash(name, 0) + pathOut = name[len(res):] + return pathOut, res, true + } + } + for i := 1; i < len(path); i++ { + if path[i] == '|' { + pathOut = path[i:] + name = path[1:i] + break + } + if path[i] == '.' { + pathOut = path[i:] + name = path[1:i] + break + } + } + switch strings.ToLower(name) { + case "true", "false", "null", "nan", "inf": + return pathOut, name, true + } + return pathOut, res, false +} + // execModifier parses the path to find a matching modifier function. -// then input expects that the path already starts with a '@' +// The input expects that the path already starts with a '@' func execModifier(json, path string) (pathOut, res string, ok bool) { name := path[1:] var hasArgs bool @@ -2555,6 +2733,11 @@ var modifiers = map[string]func(json, arg string) string{ "flatten": modFlatten, "join": modJoin, "valid": modValid, + "keys": modKeys, + "values": modValues, + "tostr": modToStr, + "fromstr": modFromStr, + "group": modGroup, } // AddModifier binds a custom modifier command to the GJSON syntax. @@ -2711,6 +2894,58 @@ func modFlatten(json, arg string) string { return bytesString(out) } +// @keys extracts the keys from an object. +// {"first":"Tom","last":"Smith"} -> ["first","last"] +func modKeys(json, arg string) string { + v := Parse(json) + if !v.Exists() { + return "[]" + } + obj := v.IsObject() + var out strings.Builder + out.WriteByte('[') + var i int + v.ForEach(func(key, _ Result) bool { + if i > 0 { + out.WriteByte(',') + } + if obj { + out.WriteString(key.Raw) + } else { + out.WriteString("null") + } + i++ + return true + }) + out.WriteByte(']') + return out.String() +} + +// @values extracts the values from an object. +// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"] +func modValues(json, arg string) string { + v := Parse(json) + if !v.Exists() { + return "[]" + } + if v.IsArray() { + return json + } + var out strings.Builder + out.WriteByte('[') + var i int + v.ForEach(func(_, value Result) bool { + if i > 0 { + out.WriteByte(',') + } + out.WriteString(value.Raw) + i++ + return true + }) + out.WriteByte(']') + return out.String() +} + // @join multiple objects into a single object. // [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"} // The arg can be "true" to specify that duplicate keys should be preserved. @@ -2788,6 +3023,56 @@ func modValid(json, arg string) string { return json } +// @fromstr converts a string to json +// "{\"id\":1023,\"name\":\"alert\"}" -> {"id":1023,"name":"alert"} +func modFromStr(json, arg string) string { + if !Valid(json) { + return "" + } + return Parse(json).String() +} + +// @tostr converts a string to json +// {"id":1023,"name":"alert"} -> "{\"id\":1023,\"name\":\"alert\"}" +func modToStr(str, arg string) string { + return string(AppendJSONString(nil, str)) +} + +func modGroup(json, arg string) string { + res := Parse(json) + if !res.IsObject() { + return "" + } + var all [][]byte + res.ForEach(func(key, value Result) bool { + if !value.IsArray() { + return true + } + var idx int + value.ForEach(func(_, value Result) bool { + if idx == len(all) { + all = append(all, []byte{}) + } + all[idx] = append(all[idx], ("," + key.Raw + ":" + value.Raw)...) + idx++ + return true + }) + return true + }) + var data []byte + data = append(data, '[') + for i, item := range all { + if i > 0 { + data = append(data, ',') + } + data = append(data, '{') + data = append(data, item[1:]...) + data = append(data, '}') + } + data = append(data, ']') + return string(data) +} + // stringHeader instead of reflect.StringHeader type stringHeader struct { data unsafe.Pointer @@ -2873,3 +3158,202 @@ func stringBytes(s string) []byte { func bytesString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } + +func revSquash(json string) string { + // reverse squash + // expects that the tail character is a ']' or '}' or ')' or '"' + // squash the value, ignoring all nested arrays and objects. + i := len(json) - 1 + var depth int + if json[i] != '"' { + depth++ + } + if json[i] == '}' || json[i] == ']' || json[i] == ')' { + i-- + } + for ; i >= 0; i-- { + switch json[i] { + case '"': + i-- + for ; i >= 0; i-- { + if json[i] == '"' { + esc := 0 + for i > 0 && json[i-1] == '\\' { + i-- + esc++ + } + if esc%2 == 1 { + continue + } + i += esc + break + } + } + if depth == 0 { + if i < 0 { + i = 0 + } + return json[i:] + } + case '}', ']', ')': + depth++ + case '{', '[', '(': + depth-- + if depth == 0 { + return json[i:] + } + } + } + return json +} + +// Paths returns the original GJSON paths for a Result where the Result came +// from a simple query path that returns an array, like: +// +// gjson.Get(json, "friends.#.first") +// +// The returned value will be in the form of a JSON array: +// +// ["friends.0.first","friends.1.first","friends.2.first"] +// +// The param 'json' must be the original JSON used when calling Get. +// +// Returns an empty string if the paths cannot be determined, which can happen +// when the Result came from a path that contained a multipath, modifier, +// or a nested query. +func (t Result) Paths(json string) []string { + if t.Indexes == nil { + return nil + } + paths := make([]string, 0, len(t.Indexes)) + t.ForEach(func(_, value Result) bool { + paths = append(paths, value.Path(json)) + return true + }) + if len(paths) != len(t.Indexes) { + return nil + } + return paths +} + +// Path returns the original GJSON path for a Result where the Result came +// from a simple path that returns a single value, like: +// +// gjson.Get(json, "friends.#(last=Murphy)") +// +// The returned value will be in the form of a JSON string: +// +// "friends.0" +// +// The param 'json' must be the original JSON used when calling Get. +// +// Returns an empty string if the paths cannot be determined, which can happen +// when the Result came from a path that contained a multipath, modifier, +// or a nested query. +func (t Result) Path(json string) string { + var path []byte + var comps []string // raw components + i := t.Index - 1 + if t.Index+len(t.Raw) > len(json) { + // JSON cannot safely contain Result. + goto fail + } + if !strings.HasPrefix(json[t.Index:], t.Raw) { + // Result is not at the JSON index as exepcted. + goto fail + } + for ; i >= 0; i-- { + if json[i] <= ' ' { + continue + } + if json[i] == ':' { + // inside of object, get the key + for ; i >= 0; i-- { + if json[i] != '"' { + continue + } + break + } + raw := revSquash(json[:i+1]) + i = i - len(raw) + comps = append(comps, raw) + // key gotten, now squash the rest + raw = revSquash(json[:i+1]) + i = i - len(raw) + i++ // increment the index for next loop step + } else if json[i] == '{' { + // Encountered an open object. The original result was probably an + // object key. + goto fail + } else if json[i] == ',' || json[i] == '[' { + // inside of an array, count the position + var arrIdx int + if json[i] == ',' { + arrIdx++ + i-- + } + for ; i >= 0; i-- { + if json[i] == ':' { + // Encountered an unexpected colon. The original result was + // probably an object key. + goto fail + } else if json[i] == ',' { + arrIdx++ + } else if json[i] == '[' { + comps = append(comps, strconv.Itoa(arrIdx)) + break + } else if json[i] == ']' || json[i] == '}' || json[i] == '"' { + raw := revSquash(json[:i+1]) + i = i - len(raw) + 1 + } + } + } + } + if len(comps) == 0 { + if DisableModifiers { + goto fail + } + return "@this" + } + for i := len(comps) - 1; i >= 0; i-- { + rcomp := Parse(comps[i]) + if !rcomp.Exists() { + goto fail + } + comp := escapeComp(rcomp.String()) + path = append(path, '.') + path = append(path, comp...) + } + if len(path) > 0 { + path = path[1:] + } + return string(path) +fail: + return "" +} + +// isSafePathKeyChar returns true if the input character is safe for not +// needing escaping. +func isSafePathKeyChar(c byte) bool { + return c <= ' ' || c > '~' || c == '_' || c == '-' || c == ':' || + (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') +} + +// escapeComp escaped a path compontent, making it safe for generating a +// path for later use. +func escapeComp(comp string) string { + for i := 0; i < len(comp); i++ { + if !isSafePathKeyChar(comp[i]) { + ncomp := []byte(comp[:i]) + for ; i < len(comp); i++ { + if !isSafePathKeyChar(comp[i]) { + ncomp = append(ncomp, '\\') + } + ncomp = append(ncomp, comp[i]) + } + return string(ncomp) + } + } + return comp +} diff --git a/vendor/github.com/tidwall/gjson/go.mod b/vendor/github.com/tidwall/gjson/go.mod index 30ed7f0..6f64083 100644 --- a/vendor/github.com/tidwall/gjson/go.mod +++ b/vendor/github.com/tidwall/gjson/go.mod @@ -3,6 +3,6 @@ module github.com/tidwall/gjson go 1.12 require ( - github.com/tidwall/match v1.1.0 + github.com/tidwall/match v1.1.1 github.com/tidwall/pretty v1.2.0 ) diff --git a/vendor/github.com/tidwall/gjson/go.sum b/vendor/github.com/tidwall/gjson/go.sum index f4dcaab..be39c8c 100644 --- a/vendor/github.com/tidwall/gjson/go.sum +++ b/vendor/github.com/tidwall/gjson/go.sum @@ -1,4 +1,4 @@ -github.com/tidwall/match v1.1.0 h1:VfI2e2aXLvytih7WUVyO9uvRC+RcXlaTrMbHuQWnFmk= -github.com/tidwall/match v1.1.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= diff --git a/vendor/github.com/tidwall/match/match.go b/vendor/github.com/tidwall/match/match.go index 499321d..11da28f 100644 --- a/vendor/github.com/tidwall/match/match.go +++ b/vendor/github.com/tidwall/match/match.go @@ -21,10 +21,47 @@ func Match(str, pattern string) bool { if pattern == "*" { return true } - return match(str, pattern) + return match(str, pattern, 0, nil, -1) == rMatch } -func match(str, pat string) bool { +// MatchLimit is the same as Match but will limit the complexity of the match +// operation. This is to avoid long running matches, specifically to avoid ReDos +// attacks from arbritary inputs. +// +// How it works: +// The underlying match routine is recursive and may call itself when it +// encounters a sandwiched wildcard pattern, such as: `user:*:name`. +// Everytime it calls itself a counter is incremented. +// The operation is stopped when counter > maxcomp*len(str). +func MatchLimit(str, pattern string, maxcomp int) (matched, stopped bool) { + if pattern == "*" { + return true, false + } + counter := 0 + r := match(str, pattern, len(str), &counter, maxcomp) + if r == rStop { + return false, true + } + return r == rMatch, false +} + +type result int + +const ( + rNoMatch result = iota + rMatch + rStop +) + +func match(str, pat string, slen int, counter *int, maxcomp int) result { + // check complexity limit + if maxcomp > -1 { + if *counter > slen*maxcomp { + return rStop + } + *counter++ + } + for len(pat) > 0 { var wild bool pc, ps := rune(pat[0]), 1 @@ -42,7 +79,7 @@ func match(str, pat string) bool { switch pc { case '?': if ss == 0 { - return false + return rNoMatch } case '*': // Ignore repeating stars. @@ -50,39 +87,45 @@ func match(str, pat string) bool { pat = pat[1:] } - // If this is the last character then it must be a match. + // If this star is the last character then it must be a match. if len(pat) == 1 { - return true + return rMatch } // Match and trim any non-wildcard suffix characters. var ok bool str, pat, ok = matchTrimSuffix(str, pat) if !ok { - return false + return rNoMatch } - // perform recursive wildcard search - if match(str, pat[1:]) { - return true + // Check for single star again. + if len(pat) == 1 { + return rMatch + } + + // Perform recursive wildcard search. + r := match(str, pat[1:], slen, counter, maxcomp) + if r != rNoMatch { + return r } if len(str) == 0 { - return false + return rNoMatch } wild = true default: if ss == 0 { - return false + return rNoMatch } if pc == '\\' { pat = pat[ps:] pc, ps = utf8.DecodeRuneInString(pat) if ps == 0 { - return false + return rNoMatch } } if sc != pc { - return false + return rNoMatch } } str = str[ss:] @@ -90,7 +133,10 @@ func match(str, pat string) bool { pat = pat[ps:] } } - return len(str) == 0 + if len(str) == 0 { + return rMatch + } + return rNoMatch } // matchTrimSuffix matches and trims any non-wildcard suffix characters. diff --git a/vendor/github.com/tidwall/sjson/go.mod b/vendor/github.com/tidwall/sjson/go.mod index 2a72f85..fa6b7e8 100644 --- a/vendor/github.com/tidwall/sjson/go.mod +++ b/vendor/github.com/tidwall/sjson/go.mod @@ -3,6 +3,6 @@ module github.com/tidwall/sjson go 1.14 require ( - github.com/tidwall/gjson v1.9.1 + github.com/tidwall/gjson v1.14.2 github.com/tidwall/pretty v1.2.0 ) diff --git a/vendor/github.com/tidwall/sjson/go.sum b/vendor/github.com/tidwall/sjson/go.sum index f041fa3..ec6ee0a 100644 --- a/vendor/github.com/tidwall/sjson/go.sum +++ b/vendor/github.com/tidwall/sjson/go.sum @@ -1,6 +1,6 @@ -github.com/tidwall/gjson v1.9.1 h1:wrrRk7TyL7MmKanNRck/Mcr3VU1sdMvJHvJXzqBIUNo= -github.com/tidwall/gjson v1.9.1/go.mod h1:jydLKE7s8J0+1/5jC4eXcuFlzKizGrCKvLmBVX/5oXc= -github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= diff --git a/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go b/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go index 18bb37e..f9700b8 100644 --- a/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go +++ b/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go @@ -26,21 +26,25 @@ type ReadSeekCloser struct { // Create a new NewReadSeekCloser instance conforming to the Go 1.16 `io.ReadSeekCloser` interface. This method accepts the following types: io.ReadSeekCloser, io.Reader, io.ReadCloser and io.ReadSeeker. func NewReadSeekCloser(fh interface{}) (io.ReadSeekCloser, error) { - reader := true + reader := false seeker := false closer := false switch fh.(type) { case io.ReadSeekCloser: return fh.(io.ReadSeekCloser), nil - case io.Reader: - // pass + case io.Closer: + closer = true case io.ReadCloser: + reader = true closer = true case io.ReadSeeker: + reader = true seeker = true + case io.Reader: + reader = true default: - return nil, fmt.Errorf("Invalid or unsupported type") + return nil, fmt.Errorf("Invalid or unsupported type: %T", fh) } mu := new(sync.RWMutex) diff --git a/vendor/github.com/whosonfirst/go-reader/README.md b/vendor/github.com/whosonfirst/go-reader/README.md index 1141902..c94ebdb 100644 --- a/vendor/github.com/whosonfirst/go-reader/README.md +++ b/vendor/github.com/whosonfirst/go-reader/README.md @@ -2,8 +2,6 @@ There are many interfaces for reading files. This one is ours. It returns `io.ReadSeekCloser` instances. -_This package supersedes the [go-whosonfirst-readwrite](https://github.com/whosonfirst/go-whosonfirst-readwrite) package._ - ## Documentation [![Go Reference](https://pkg.go.dev/badge/github.com/whosonfirst/go-reader.svg)](https://pkg.go.dev/github.com/whosonfirst/go-reader) @@ -227,7 +225,7 @@ func main() { r, _ := reader.NewReader(ctx, "github://{GITHUB_OWNER}/{GITHUB_REPO}") // to specify a specific branch you would do this: - // r, _ := reader.NewReader(ctx, "github://{GITHUB_OWNER}/{GITHUB_REPO}/{GITHUB_BRANCH}") + // r, _ := reader.NewReader(ctx, "github://{GITHUB_OWNER}/{GITHUB_REPO}?branch={GITHUB_BRANCH}") } ``` @@ -314,9 +312,23 @@ func main() { } ``` -## See also +### repo:// -* https://github.com/whosonfirst/go-writer +This is a convenience scheme for working with Who's On First data repositories. + +It will update a URI by appending a `data` directory to its path and changing its scheme to `fs://` before invoking `reader.NewReader` with the updated URI. + +``` +import ( + "context" + "github.com/whosonfirst/go-reader" +) + +func main() { + ctx := context.Background() + r, _ := reader.NewReader(ctx, "repo:///usr/local/data/whosonfirst-data-admin-ca") +} +``` ### stdin:// diff --git a/vendor/github.com/whosonfirst/go-reader/fs.go b/vendor/github.com/whosonfirst/go-reader/fs.go index e735571..9a832a3 100644 --- a/vendor/github.com/whosonfirst/go-reader/fs.go +++ b/vendor/github.com/whosonfirst/go-reader/fs.go @@ -1,17 +1,22 @@ package reader import ( + "compress/bzip2" "context" - "errors" + "fmt" + "github.com/whosonfirst/go-ioutil" "io" "net/url" "os" "path/filepath" + "strconv" ) +// FileReader is a struct that implements the `Reader` interface for reading documents from files on a local disk. type FileReader struct { Reader - root string + root string + allow_bz2 bool } func init() { @@ -26,32 +31,54 @@ func init() { } +// NewFileReader returns a new `FileReader` instance for reading documents from local files on +// disk, configured by 'uri' in the form of: +// +// fs://{PATH} +// +// Where {PATH} is an absolute path to an existing directory where files will be read from. func NewFileReader(ctx context.Context, uri string) (Reader, error) { u, err := url.Parse(uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse URI, %w", err) } root := u.Path info, err := os.Stat(root) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to stat %s, %w", root, err) } if !info.IsDir() { - return nil, errors.New("root is not a directory") + return nil, fmt.Errorf("Root (%s) is not a directory", root) } r := &FileReader{ root: root, } + q := u.Query() + + allow_bz2 := q.Get("allow_bz2") + + if allow_bz2 != "" { + + allow, err := strconv.ParseBool(allow_bz2) + + if err != nil { + return nil, fmt.Errorf("Unable to parse '%s' parameter, %w", allow_bz2, err) + } + + r.allow_bz2 = allow + } + return r, nil } +// Read will open an `io.ReadSeekCloser` for a file matching 'path'. func (r *FileReader) Read(ctx context.Context, path string) (io.ReadSeekCloser, error) { abs_path := r.ReaderURI(ctx, path) @@ -59,12 +86,34 @@ func (r *FileReader) Read(ctx context.Context, path string) (io.ReadSeekCloser, _, err := os.Stat(abs_path) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to stat %s, %v", abs_path, err) + } + + var fh io.ReadSeekCloser + + fh, err = os.Open(abs_path) + + if err != nil { + return nil, fmt.Errorf("Failed to open %s, %w", abs_path, err) + } + + if filepath.Ext(abs_path) == ".bz2" && r.allow_bz2 { + + bz_r := bzip2.NewReader(fh) + + rsc, err := ioutil.NewReadSeekCloser(bz_r) + + if err != nil { + return nil, fmt.Errorf("Failed create ReadSeekCloser for bzip2 reader for %s, %w", path, err) + } + + fh = rsc } - return os.Open(abs_path) + return fh, nil } +// ReaderURI returns the absolute URL for 'path'. func (r *FileReader) ReaderURI(ctx context.Context, path string) string { return filepath.Join(r.root, path) } diff --git a/vendor/github.com/whosonfirst/go-reader/go.mod b/vendor/github.com/whosonfirst/go-reader/go.mod index 310b1e6..000e68e 100644 --- a/vendor/github.com/whosonfirst/go-reader/go.mod +++ b/vendor/github.com/whosonfirst/go-reader/go.mod @@ -3,6 +3,6 @@ module github.com/whosonfirst/go-reader go 1.16 require ( - github.com/aaronland/go-roster v0.0.2 - github.com/whosonfirst/go-ioutil v1.0.0 + github.com/aaronland/go-roster v1.0.0 + github.com/whosonfirst/go-ioutil v1.0.2 ) diff --git a/vendor/github.com/whosonfirst/go-reader/go.sum b/vendor/github.com/whosonfirst/go-reader/go.sum index 52e1991..bf73c7d 100644 --- a/vendor/github.com/whosonfirst/go-reader/go.sum +++ b/vendor/github.com/whosonfirst/go-reader/go.sum @@ -1,36 +1,4 @@ -github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= -github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= -github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= -github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= -github.com/facebookgo/atomicfile v0.0.0-20151019000000-2de1f203e7d5e386a6833233882782932729f27e h1:bYAD+4OJX4+LUrmLhpNFiicL4B0mnswQe5QaI6rxJ4A= -github.com/facebookgo/atomicfile v0.0.0-20151019000000-2de1f203e7d5e386a6833233882782932729f27e/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= -github.com/go-ini/ini v1.42.0 h1:TWr1wGj35+UiWHlBA8er89seFXxzwFn11spilrrj+38= -github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/whosonfirst/go-ioutil v0.0.1 h1:cCrEYen6NDvHfjzV2q4u/VB21u2kTOwDnUGRlMI8Z9o= -github.com/whosonfirst/go-ioutil v0.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= -github.com/whosonfirst/go-ioutil v1.0.0 h1:sYpgJx7Wsp76e7PFGa8KKQBvWQW3+HMCWSJbKdD5m14= -github.com/whosonfirst/go-ioutil v1.0.0/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= -github.com/whosonfirst/go-whosonfirst-cache v0.1.0 h1:ryWTsHj7gAEjwHC/WjsjROpFflsz3SCa7W9Qnk4EU7k= -github.com/whosonfirst/go-whosonfirst-cache v0.1.0/go.mod h1:P5Tx34j2M50qX/kTfXY516apwGzJGkFSBYQI7TGArKw= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0 h1:Wwj9z0R/ryHmPmpVm5jCbXdG4agJzKMWXDtPVReN/KA= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= -github.com/whosonfirst/go-whosonfirst-reader v0.0.0-20191122203133-047f20452865 h1:1GYjmjunRhDm1E4/aM/AIhjBij8C9kMqufjS1G2P0fs= -github.com/whosonfirst/go-whosonfirst-reader v0.0.0-20191122203133-047f20452865/go.mod h1:xYzBn6llLD/uS6Zhh0H4LAqddEJHXdQSUIxywTnhpOU= -github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= -github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= -github.com/whosonfirst/go-whosonfirst-uri v0.1.0 h1:JMlpam0x1hVrFBMTAPY3edIHz7azfMK8lLI2kM9BgbI= -github.com/whosonfirst/go-whosonfirst-uri v0.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -github.com/whosonfirst/go-whosonfirst-uri v1.0.1 h1:hVEDRuW9WhqvTksDi092OO9UecX7PAMDrD47KPEqAg0= -github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +github.com/aaronland/go-roster v1.0.0 h1:FRDGrTqsYySKjWnAhbBGXyeGlI/o5/t9FZYCbUmyQtI= +github.com/aaronland/go-roster v1.0.0/go.mod h1:KIsYZgrJlAsyb9LsXSCvlqvbcCBVjCSqcQiZx42i9ro= +github.com/whosonfirst/go-ioutil v1.0.2 h1:+GJPfa42OFn5A+5yJSc5jQTQIkNV3/MhYyg4pavdrC8= +github.com/whosonfirst/go-ioutil v1.0.2/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= diff --git a/vendor/github.com/whosonfirst/go-reader/multi.go b/vendor/github.com/whosonfirst/go-reader/multi.go index a72111b..0b09d31 100644 --- a/vendor/github.com/whosonfirst/go-reader/multi.go +++ b/vendor/github.com/whosonfirst/go-reader/multi.go @@ -9,6 +9,7 @@ import ( "sync" ) +// MultiReader is a struct that implements the `Reader` interface for reading documents from one or more `Reader` instances. type MultiReader struct { Reader readers []Reader @@ -16,6 +17,8 @@ type MultiReader struct { mu *sync.RWMutex } +// NewMultiReaderFromURIs returns a new `Reader` instance for reading documents from one or more `Reader` instances. +// 'uris' is assumed to be a list of URIs each of which will be used to invoke the `NewReader` method. func NewMultiReaderFromURIs(ctx context.Context, uris ...string) (Reader, error) { readers := make([]Reader, 0) @@ -34,6 +37,7 @@ func NewMultiReaderFromURIs(ctx context.Context, uris ...string) (Reader, error) return NewMultiReader(ctx, readers...) } +// NewMultiReaderFromURIs returns a new `Reader` instance for reading documents from one or more `Reader` instances. func NewMultiReader(ctx context.Context, readers ...Reader) (Reader, error) { lookup := make(map[string]int) @@ -49,26 +53,28 @@ func NewMultiReader(ctx context.Context, readers ...Reader) (Reader, error) { return &mr, nil } -func (mr *MultiReader) Read(ctx context.Context, uri string) (io.ReadSeekCloser, error) { +// Read will open an `io.ReadSeekCloser` for a file matching 'path'. In the case of multiple underlying +// `Reader` instances the first instance to successfully load 'path' will be returned. +func (mr *MultiReader) Read(ctx context.Context, path string) (io.ReadSeekCloser, error) { missing := errors.New("Unable to read URI") mr.mu.RLock() - idx, ok := mr.lookup[uri] + idx, ok := mr.lookup[path] mr.mu.RUnlock() if ok { - // log.Printf("READ MULTIREADER LOOKUP INDEX FOR %s AS %d\n", uri, idx) + // log.Printf("READ MULTIREADER LOOKUP INDEX FOR %s AS %d\n", path, idx) if idx == -1 { return nil, missing } r := mr.readers[idx] - return r.Read(ctx, uri) + return r.Read(ctx, path) } var fh io.ReadSeekCloser @@ -76,7 +82,7 @@ func (mr *MultiReader) Read(ctx context.Context, uri string) (io.ReadSeekCloser, for i, r := range mr.readers { - rsp, err := r.Read(ctx, uri) + rsp, err := r.Read(ctx, path) if err == nil { @@ -87,10 +93,10 @@ func (mr *MultiReader) Read(ctx context.Context, uri string) (io.ReadSeekCloser, } } - // log.Printf("SET MULTIREADER LOOKUP INDEX FOR %s AS %d\n", uri, idx) + // log.Printf("SET MULTIREADER LOOKUP INDEX FOR %s AS %d\n", path, idx) mr.mu.Lock() - mr.lookup[uri] = idx + mr.lookup[path] = idx mr.mu.Unlock() if fh == nil { @@ -100,23 +106,27 @@ func (mr *MultiReader) Read(ctx context.Context, uri string) (io.ReadSeekCloser, return fh, nil } -func (mr *MultiReader) ReaderURI(ctx context.Context, uri string) string { +// ReaderURI returns the absolute URL for 'path'. In the case of multiple underlying +// `Reader` instances the first instance to successfully load 'path' will be returned. +func (mr *MultiReader) ReaderURI(ctx context.Context, path string) string { mr.mu.RLock() - idx, ok := mr.lookup[uri] + idx, ok := mr.lookup[path] mr.mu.RUnlock() if ok { - return mr.readers[idx].ReaderURI(ctx, uri) + return mr.readers[idx].ReaderURI(ctx, path) } - _, err := mr.Read(ctx, uri) + r, err := mr.Read(ctx, path) if err != nil { - return fmt.Sprintf("x-urn:go-reader:multi#%s", uri) + return fmt.Sprintf("x-urn:go-reader:multi#%s", path) } - return mr.ReaderURI(ctx, uri) + defer r.Close() + + return mr.ReaderURI(ctx, path) } diff --git a/vendor/github.com/whosonfirst/go-reader/null.go b/vendor/github.com/whosonfirst/go-reader/null.go index c1e4151..9818f85 100644 --- a/vendor/github.com/whosonfirst/go-reader/null.go +++ b/vendor/github.com/whosonfirst/go-reader/null.go @@ -7,6 +7,7 @@ import ( "io" ) +// NullReader is a struct that implements the `Reader` interface for reading documents from nowhere. type NullReader struct { Reader } @@ -21,17 +22,25 @@ func init() { } } +// NewNullReader returns a new `FileReader` instance for reading documents from nowhere, +// configured by 'uri' in the form of: +// +// null:// +// +// Technically 'uri' can also be an empty string. func NewNullReader(ctx context.Context, uri string) (Reader, error) { r := &NullReader{} return r, nil } -func (r *NullReader) Read(ctx context.Context, uri string) (io.ReadSeekCloser, error) { - br := bytes.NewReader([]byte(uri)) +// Read will open and return an empty `io.ReadSeekCloser` for any value of 'path'. +func (r *NullReader) Read(ctx context.Context, path string) (io.ReadSeekCloser, error) { + br := bytes.NewReader([]byte("")) return ioutil.NewReadSeekCloser(br) } -func (r *NullReader) ReaderURI(ctx context.Context, uri string) string { - return uri +// ReaderURI returns the value of 'path'. +func (r *NullReader) ReaderURI(ctx context.Context, path string) string { + return path } diff --git a/vendor/github.com/whosonfirst/go-reader/reader.go b/vendor/github.com/whosonfirst/go-reader/reader.go index cffd6a5..a79616a 100644 --- a/vendor/github.com/whosonfirst/go-reader/reader.go +++ b/vendor/github.com/whosonfirst/go-reader/reader.go @@ -12,13 +12,20 @@ import ( var reader_roster roster.Roster +// ReaderInitializationFunc is a function defined by individual reader package and used to create +// an instance of that reader type ReaderInitializationFunc func(ctx context.Context, uri string) (Reader, error) +// Reader is an interface for reading data from multiple sources or targets. type Reader interface { + // Reader returns a `io.ReadSeekCloser` instance for a URI resolved by the instance implementing the `Reader` interface. Read(context.Context, string) (io.ReadSeekCloser, error) + // The absolute path for the file is determined by the instance implementing the `Reader` interface. ReaderURI(context.Context, string) string } +// RegisterReader registers 'scheme' as a key pointing to 'init_func' in an internal lookup table +// used to create new `Reader` instances by the `NewReader` method. func RegisterReader(ctx context.Context, scheme string, init_func ReaderInitializationFunc) error { err := ensureReaderRoster() @@ -46,6 +53,10 @@ func ensureReaderRoster() error { return nil } +// NewReader returns a new `Reader` instance configured by 'uri'. The value of 'uri' is parsed +// as a `url.URL` and its scheme is used as the key for a corresponding `ReaderInitializationFunc` +// function used to instantiate the new `Reader`. It is assumed that the scheme (and initialization +// function) have been registered by the `RegisterReader` method. func NewReader(ctx context.Context, uri string) (Reader, error) { u, err := url.Parse(uri) @@ -66,11 +77,7 @@ func NewReader(ctx context.Context, uri string) (Reader, error) { return init_func(ctx, uri) } -func Readers() []string { - ctx := context.Background() - return reader_roster.Drivers(ctx) -} - +// Schemes returns the list of schemes that have been registered. func Schemes() []string { ctx := context.Background() diff --git a/vendor/github.com/whosonfirst/go-reader/repo.go b/vendor/github.com/whosonfirst/go-reader/repo.go new file mode 100644 index 0000000..ed9f02e --- /dev/null +++ b/vendor/github.com/whosonfirst/go-reader/repo.go @@ -0,0 +1,37 @@ +package reader + +import ( + "context" + "fmt" + "net/url" + "path/filepath" +) + +func init() { + + ctx := context.Background() + + err := RegisterReader(ctx, "repo", NewRepoReader) + + if err != nil { + panic(err) + } + +} + +// NewRepoReader is a convenience method to update 'uri' by appending a `data` +// directory to its path and changing its scheme to `fs://` before invoking +// NewReader with the updated URI. +func NewRepoReader(ctx context.Context, uri string) (Reader, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + root := filepath.Join(u.Path, "data") + + uri = fmt.Sprintf("fs://%s", root) + return NewReader(ctx, uri) +} diff --git a/vendor/github.com/whosonfirst/go-reader/stdin.go b/vendor/github.com/whosonfirst/go-reader/stdin.go index 9c673a2..3846177 100644 --- a/vendor/github.com/whosonfirst/go-reader/stdin.go +++ b/vendor/github.com/whosonfirst/go-reader/stdin.go @@ -2,12 +2,15 @@ package reader import ( "context" + "github.com/whosonfirst/go-ioutil" "io" "os" - - "github.com/whosonfirst/go-ioutil" ) +// Constant string value representing STDIN. +const STDIN string = "-" + +// StdinReader is a struct that implements the `Reader` interface for reading documents from STDIN. type StdinReader struct { Reader } @@ -22,16 +25,24 @@ func init() { } } +// NewStdinReader returns a new `FileReader` instance for reading documents from STDIN, +// configured by 'uri' in the form of: +// +// stdin:// +// +// Technically 'uri' can also be an empty string. func NewStdinReader(ctx context.Context, uri string) (Reader, error) { r := &StdinReader{} return r, nil } +// Read will open a `io.ReadSeekCloser` instance wrapping `os.Stdin`. func (r *StdinReader) Read(ctx context.Context, uri string) (io.ReadSeekCloser, error) { return ioutil.NewReadSeekCloser(os.Stdin) } +// ReaderURI will return the value of the `STDIN` constant. func (r *StdinReader) ReaderURI(ctx context.Context, uri string) string { - return "-" + return STDIN } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/geometry.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/geometry.go index 7426ecd..7f3e089 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/geometry.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/geometry.go @@ -7,6 +7,7 @@ import ( "github.com/tidwall/gjson" ) +// Geometry() will return a `paulmach/orb/geojson.Geometry` instance derived from 'body'. func Geometry(body []byte) (*geojson.Geometry, error) { rsp := gjson.GetBytes(body, "geometry") diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/type.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/type.go index 5b6f240..80decff 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/type.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/geometry/type.go @@ -5,6 +5,7 @@ import ( "github.com/tidwall/gjson" ) +// Type() returns the `geometry.type` property for 'body'. func Type(body []byte) (string, error) { rsp := gjson.GetBytes(body, "geometry.type") diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_geoms.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_geoms.go new file mode 100644 index 0000000..b13efa7 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_geoms.go @@ -0,0 +1,20 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func AltGeometries(body []byte) ([]string, error) { + + rsp := gjson.GetBytes(body, "properties.src:geom_alt") + possible := rsp.Array() + + count := len(possible) + geoms := make([]string, count) + + for idx, r := range possible { + geoms[idx] = r.String() + } + + return geoms, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/belongsto.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/belongsto.go new file mode 100644 index 0000000..c4553d2 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/belongsto.go @@ -0,0 +1,18 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func BelongsTo(body []byte) []int64 { + + by := make([]int64, 0) + + rsp := gjson.GetBytes(body, "properties.wof:belongsto") + + for _, r := range rsp.Array() { + by = append(by, r.Int()) + } + + return by +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go index 6f73e6b..1fb16d3 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go @@ -4,13 +4,68 @@ import ( "github.com/tidwall/gjson" ) +/* + +https://github.com/whosonfirst/whosonfirst-placetypes#iso-country-codes + +Per the ISO 3166 spec which states: + +User-assigned code elements are codes at the disposal of users who need to add further names of countries, territories, or other geographical entities to their in-house application of ISO 3166-1, and the ISO 3166/MA will never use these codes in the updating process of the standard. The following codes can be user-assigned:[19] + + Alpha-2: AA, QM to QZ, XA to XZ, and ZZ + Alpha-3: AAA to AAZ, QMA to QZZ, XAA to XZZ, and ZZA to ZZZ + Numeric: 900 to 999 + +We use the following ISO country codes: + +XK We just followed Geonames' lead and have assigned XK to be the ISO country code for Kosovo. +XN For Null Island. +XS We use XS to indicate Somaliland. +XX XX denotes a place disputed by two or more (ISO) countries. +XY XY denotes an ISO country that has yet to be determined (by us). You might typically see this is a record for a freshly created place that hasn't been fully vetted or editorialized yet. +XZ XZ is the ISO country code equivalent of wof:parent_id=-2 or :shrug: the world is a complicated place. + +*/ + +const COUNTRY_KOSOVO string = "XK" +const COUNTRY_NULLISLAND string = "XN" +const COUNTRY_SOMALILAND string = "XS" +const COUNTRY_DISPUTED string = "XX" +const COUNTRY_UNKNOWN string = "XY" +const COUNTRY_COMPLICATED string = "XZ" + func Country(body []byte) string { rsp := gjson.GetBytes(body, "properties.wof:country") if !rsp.Exists() { - return "XY" + return COUNTRY_UNKNOWN } return rsp.String() } + +func MergeCountries(features ...[]byte) string { + + tmp := make(map[string]bool) + + for _, body := range features { + c := Country(body) + tmp[c] = true + } + + codes := make([]string, 0) + + for c, _ := range tmp { + codes = append(codes, c) + } + + switch len(codes) { + case 0: + return COUNTRY_UNKNOWN + case 1: + return codes[0] + default: + return COUNTRY_COMPLICATED + } +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go new file mode 100644 index 0000000..6c884b2 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go @@ -0,0 +1,16 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func Created(body []byte) int64 { + + rsp := gjson.GetBytes(body, "properties.wof:created") + + if !rsp.Exists() { + return -1 + } + + return rsp.Int() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go new file mode 100644 index 0000000..90a17f1 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go @@ -0,0 +1,34 @@ +package properties + +import ( + "github.com/sfomuseum/go-edtf" + "github.com/tidwall/gjson" +) + +func Inception(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.edtf:inception") + + if !rsp.Exists() { + return edtf.UNKNOWN + } + + return rsp.String() +} + +func Cessation(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.edtf:cessation") + + if !rsp.Exists() { + return edtf.UNKNOWN + } + + return rsp.String() +} + +func Deprecated(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.edtf:deprecated") + return rsp.String() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go index c2c4690..bd018b0 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go @@ -1,6 +1,9 @@ package properties import ( + "crypto/sha256" + "encoding/json" + "fmt" "github.com/tidwall/gjson" ) @@ -27,3 +30,52 @@ func Hierarchies(body []byte) []map[string]int64 { return hierarchies } + +// MergeHierarchies returns the unique set of hierarchies defined in 'features'. +func MergeHierarchies(features ...[]byte) ([]map[string]int64, error) { + + tmp := make(map[string]map[string]int64) + + for i, body := range features { + + hierarchies := Hierarchies(body) + + if hierarchies == nil { + continue + } + + for j, h := range hierarchies { + + hash, err := hash_interface(h) + + if err != nil { + return nil, fmt.Errorf("Failed to hash hierarchy at index %d for feature at index %d, %w", j, i, err) + } + + tmp[hash] = h + } + } + + hierarchies := make([]map[string]int64, 0) + + for _, h := range tmp { + hierarchies = append(hierarchies, h) + } + + return hierarchies, nil +} + +// hash_interface will return the SHA-256 hash for the JSON-encoding of 'i'. +func hash_interface(i interface{}) (string, error) { + + enc_i, err := json.Marshal(i) + + if err != nil { + return "", fmt.Errorf("Failed to marshal interface, %w", err) + } + + h := sha256.New() + h.Write(enc_i) + + return fmt.Sprintf("%x", h.Sum(nil)), nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go new file mode 100644 index 0000000..5beb0e4 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go @@ -0,0 +1,16 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func LastModified(body []byte) int64 { + + rsp := gjson.GetBytes(body, "properties.wof:lastmodified") + + if !rsp.Exists() { + return -1 + } + + return rsp.Int() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go index 7b24702..73ed477 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go @@ -14,6 +14,5 @@ func Name(body []byte) (string, error) { } name := rsp.String() - return name, nil } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/names.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/names.go new file mode 100644 index 0000000..cd21f5b --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/names.go @@ -0,0 +1,39 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "strings" +) + +func Names(body []byte) map[string][]string { + + names_map := make(map[string][]string) + + r := gjson.GetBytes(body, "properties") + + if !r.Exists() { + return names_map + } + + for k, v := range r.Map() { + + if !strings.HasPrefix(k, "name:") { + continue + } + + if !v.Exists() { + continue + } + + name := strings.Replace(k, "name:", "", 1) + names := make([]string, 0) + + for _, n := range v.Array() { + names = append(names, n.String()) + } + + names_map[name] = names + } + + return names_map +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go new file mode 100644 index 0000000..6e205b6 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go @@ -0,0 +1,18 @@ +package properties + +import ( + "fmt" + "github.com/tidwall/gjson" +) + +func Repo(body []byte) (string, error) { + + rsp := gjson.GetBytes(body, "properties.wof:repo") + + if !rsp.Exists() { + return "", fmt.Errorf("Missing wof:repo property") + } + + repo := rsp.String() + return repo, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/source.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/source.go new file mode 100644 index 0000000..2fac88c --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/source.go @@ -0,0 +1,32 @@ +package properties + +import ( + "fmt" + "github.com/tidwall/gjson" +) + +func Source(body []byte) (string, error) { + + var source string + + possible := []string{ + "properties.src:alt_label", + "properties.src:geom", + } + + for _, path := range possible { + + rsp := gjson.GetBytes(body, path) + + if rsp.Exists() { + source = rsp.String() + break + } + } + + if source == "" { + return "", fmt.Errorf("Missing src:geom or src:alt_label property") + } + + return source, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go new file mode 100644 index 0000000..85b2909 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go @@ -0,0 +1,18 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func SupersededBy(body []byte) []int64 { + + by := make([]int64, 0) + + rsp := gjson.GetBytes(body, "properties.wof:superseded_by") + + for _, r := range rsp.Array() { + by = append(by, r.Int()) + } + + return by +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go new file mode 100644 index 0000000..4c8fb71 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go @@ -0,0 +1,18 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func Supersedes(body []byte) []int64 { + + by := make([]int64, 0) + + rsp := gjson.GetBytes(body, "properties.wof:supersedes") + + for _, r := range rsp.Array() { + by = append(by, r.Int()) + } + + return by +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/Makefile b/vendor/github.com/whosonfirst/go-whosonfirst-flags/Makefile index 53c7aaf..e69de29 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-flags/Makefile +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/Makefile @@ -1,7 +0,0 @@ -vendor-deps: - go mod vendor - -fmt: - go fmt *.go - go fmt existential/*.go - go fmt placetypes/*.go diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/README.md b/vendor/github.com/whosonfirst/go-whosonfirst-flags/README.md index 4cd847c..e5592a5 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-flags/README.md +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/README.md @@ -1,7 +1,11 @@ # go-whosonfirst-flags -Go tools for working Who's On First flags. +Go package defining interfaces for different classes of "flags" (or well-defined arguments) for querying or filtering Who's On First records. + +## Documentation + +[![Go Reference](https://pkg.go.dev/badge/github.com/whosonfirst/go-whosonfirst-flags.svg)](https://pkg.go.dev/github.com/whosonfirst/go-whosonfirst-flags) ## Important -Work in progress. Documentation to follow. \ No newline at end of file +Work in progress. Documentation is incomplete. \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/date/date.go b/vendor/github.com/whosonfirst/go-whosonfirst-flags/date/date.go new file mode 100644 index 0000000..db4cd79 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/date/date.go @@ -0,0 +1,2 @@ +// package date defines date-based flags for querying and filtering Who's On First records. +package date diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/doc.go b/vendor/github.com/whosonfirst/go-whosonfirst-flags/doc.go new file mode 100644 index 0000000..611e63e --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/doc.go @@ -0,0 +1,2 @@ +// package flags defines interfaces for different classes of "flags" (or well-defined arguments) for querying or filtering Who's On First records. +package flags diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/existential/existential.go b/vendor/github.com/whosonfirst/go-whosonfirst-flags/existential/existential.go new file mode 100644 index 0000000..4c8897a --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/existential/existential.go @@ -0,0 +1,2 @@ +// package existential defines "existential" flags for querying and filtering Who's On First records. +package existential diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/flags.go b/vendor/github.com/whosonfirst/go-whosonfirst-flags/flags.go index 8095b96..e31bb26 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-flags/flags.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/flags.go @@ -1,41 +1,60 @@ package flags +// type ExistentialFlag provides a common interface for Who's On First -style "existential" flags where 1 represents true, 0 represents false and -1 represents unknown or to be determined. type ExistentialFlag interface { StringFlag() string Flag() int64 + // Return a boolean value indicating whether the flag is true. IsTrue() bool + // Return a boolean value indicating whether the flag is false. IsFalse() bool + // Return a boolean value indicating whether the flag is true or false (not -1). IsKnown() bool + // Return a boolean value indicating whether the flag matches any record in a set of ExistentialFlag instances. MatchesAny(...ExistentialFlag) bool + // Return a boolean value indicating whether the flag matches all records in a set of ExistentialFlag instances. MatchesAll(...ExistentialFlag) bool String() string } type AlternateGeometryFlag interface { + // Return a boolean value indicating whether the flag matches any record in a set of AlternateGeometryFlag instances. MatchesAny(...AlternateGeometryFlag) bool + // Return a boolean value indicating whether the flag matches all records in a set of AlternateGeometryFlag instances. MatchesAll(...AlternateGeometryFlag) bool IsAlternateGeometry() bool Label() string String() string } +// type DateFlags provides a common interface for querying Who's On First records using date ranges. type DateFlag interface { + // Return a boolean value indicating whether the flag matches any record in a set of DateFlag instances. MatchesAll(...DateFlag) bool + // Return a boolean value indicating whether the flag matches all records in a set of DateFlag instances. MatchesAny(...DateFlag) bool + // Returns min, max numeric values representing to inner range of allowable dates for a DateFlag instance. InnerRange() (*int64, *int64) + // Returns min, max numeric values representing to outer range of allowable dates for a DateFlag instance. OuterRange() (*int64, *int64) String() string } +// type PlaceFlag provides a common interface for querying Who's On First records using well-defined placetypes. type PlacetypeFlag interface { + // Return a boolean value indicating whether the flag matches any record in a set of PlacetypeFlag instances. MatchesAny(...PlacetypeFlag) bool + // Return a boolean value indicating whether the flag matches all records in a set of PlacetypeFlag instances. MatchesAll(...PlacetypeFlag) bool Placetype() string String() string } +// type CustomFlag provides a common interface for querying Who's On First records with non-standard (custom) flag types. type CustomFlag interface { + // Return a boolean value indicating whether the flag matches any record in a set of CustomFlag instances. MatchesAny(...CustomFlag) bool + // Return a boolean value indicating whether the flag matches all records in a set of CustomFlag instances. MatchesAll(...CustomFlag) bool String() string } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/geometry/geometry.go b/vendor/github.com/whosonfirst/go-whosonfirst-flags/geometry/geometry.go new file mode 100644 index 0000000..73d2f87 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/geometry/geometry.go @@ -0,0 +1,2 @@ +// package geometry defines flags for querying and filtering Who's On First records by one or more geometry-related properties. +package geometry diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.mod index ad58280..d7cf11f 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.mod +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.mod @@ -1,9 +1,9 @@ module github.com/whosonfirst/go-whosonfirst-flags -go 1.12 +go 1.16 require ( - github.com/sfomuseum/go-edtf v0.2.3 + github.com/sfomuseum/go-edtf v1.1.1 github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 - github.com/whosonfirst/go-whosonfirst-uri v1.0.1 + github.com/whosonfirst/go-whosonfirst-uri v1.2.0 ) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.sum index 6e3d765..0983f0d 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.sum +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/go.sum @@ -1,34 +1,13 @@ -github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/sfomuseum/go-edtf v0.2.2 h1:8n1UekTCU6fkgAf3bWqG5RyQxOd9hRhy4lg91aQ3kMk= -github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= -github.com/sfomuseum/go-edtf v0.2.3 h1:wpcpwl1RD9W/sXFDi4zpoIpQcIwIk8em9CGwa7YWv4g= -github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v1.1.1 h1:R5gElndHGDaK/rGSh2X+ulaLtlcHCdQA1cTzB8e9wv8= +github.com/sfomuseum/go-edtf v1.1.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= -github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0 h1:zuSk8eqeEkg42sIZ4EF71IMtphdTbG80qJsXhuZXXbM= -github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0/go.mod h1:Jdmug2QQLbrmg+UcYGz8k575GnrOEg63vZVS46e5fMs= -github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4 h1:hl6BgQ6ozmrCAbw0if0EtGDBn2x7vqgXv6ucWE0lOJ0= -github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 h1:68kuizK8FXjfEIOKlqWemhs7gyMBIgpLJDbCZF8+8Ok= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0/go.mod h1:ez0VFkGFbgT2/z2oi3PIuW6FewsZ2+5glyfDD79XEHk= github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= -github.com/whosonfirst/go-whosonfirst-uri v0.2.0 h1:iODHdyvW+8IXqHZTixZ/9GEZy1dVKGj6dMRg7fn0d2M= -github.com/whosonfirst/go-whosonfirst-uri v0.2.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -github.com/whosonfirst/go-whosonfirst-uri v1.0.1 h1:hVEDRuW9WhqvTksDi092OO9UecX7PAMDrD47KPEqAg0= -github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -github.com/whosonfirst/warning v0.1.0/go.mod h1:cAez7FpC/UEUrbiOXZO15v2JM8eijtFHQlN93AGFy1k= +github.com/whosonfirst/go-whosonfirst-uri v1.2.0 h1:lhmRsIhcpTr5HAo+kXKRGsSt76HTh3Ko/oTR2jpCm/o= +github.com/whosonfirst/go-whosonfirst-uri v1.2.0/go.mod h1:CuVygTCUpMG945MMvqHyqxvc/L5YkDaMrrVpRFr7ZxY= github.com/whosonfirst/warning v0.1.1/go.mod h1:/unEMzhB9YaMeEwTJpzLN3kM5LiSxdJhKEsf/OQhn6s= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-flags/placetypes/placetypes.go b/vendor/github.com/whosonfirst/go-whosonfirst-flags/placetypes/placetypes.go new file mode 100644 index 0000000..f02d723 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-flags/placetypes/placetypes.go @@ -0,0 +1,2 @@ +// package placetypes defines flags for querying and filtering Who's On First records according to their placetype. +package placetypes diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/README.md b/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/README.md index 25e2751..349f497 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/README.md +++ b/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/README.md @@ -12,13 +12,21 @@ make tools All of this package's dependencies are bundled with the code in the `vendor` directory. -## Important +## Notice -This is work in progress. It may change (and break your code) still. This package aims to replace the existing [go-whosonfirst-geojson](https://github.com/whosonfirst/go-whosonfirst-geojson) package. If you want to follow along, please consult: +This package is stuck in that awkward in-between place where it is basically deprecated but still being included as a dependency to a lot of other packages. -https://github.com/whosonfirst/go-whosonfirst-geojson-v2/issues/1 +Which is to say: While this package is not officially deprecated yet it is on its way to being deprecated. Bug fixes will be applied when necessary but otherwise all work is being applied to the [whosonfirst/go-whosonfirst-feature](https://github.com/whosonfirst/go-whosonfirst-feature) package. -## geojson-v2? +Basically this package tries to do too many things, specifically around defining GeoJSON-related structs and interfaces. It's not really worth the effort and better to use [paulmach/orb/geojson](https://github.com/paulmach/orb) for geometry and GeoJSON-related operations and [tidwall/gjson](https://github.com/tidwall/gjson] for query-related operations using plain-vanilla `[]byte` elements. This is the approach taken by the `go-whosonfirst-feature` package. + +If you are using _this package_ in your code it would be best to migrate it to use equivalent functionality defined in the `go-whosonfirst-feature` package. + +## History + +The goal of this package was to replace the existing [go-whosonfirst-geojson](https://github.com/whosonfirst/go-whosonfirst-geojson) package. + +### geojson-v2? Yeah, I don't really like it either but this package is basically 100% backwards incompatible with `github.com/whosonfirst/go-whosonfirst-geojson` and while I don't _really_ think anyone else is using it I don't like the idea of suddenly breaking everyone's code. diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.mod index 989e5b6..6a0176c 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.mod +++ b/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.mod @@ -5,13 +5,13 @@ go 1.12 require ( github.com/mmcloughlin/geohash v0.10.0 github.com/paulmach/go.geojson v1.4.0 - github.com/sfomuseum/go-edtf v0.2.3 + github.com/sfomuseum/go-edtf v0.3.1 github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 - github.com/tidwall/gjson v1.6.8 - github.com/whosonfirst/go-whosonfirst-flags v0.4.2 + github.com/tidwall/gjson v1.14.0 + github.com/whosonfirst/go-whosonfirst-flags v0.4.3 github.com/whosonfirst/go-whosonfirst-hash v0.1.0 github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 - github.com/whosonfirst/go-whosonfirst-uri v0.2.0 + github.com/whosonfirst/go-whosonfirst-uri v1.1.0 github.com/whosonfirst/warning v0.1.1 ) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.sum index 66aa561..c15f66a 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.sum +++ b/vendor/github.com/whosonfirst/go-whosonfirst-geojson-v2/go.sum @@ -22,6 +22,8 @@ github.com/sfomuseum/go-edtf v0.2.2 h1:8n1UekTCU6fkgAf3bWqG5RyQxOd9hRhy4lg91aQ3k github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-edtf v0.2.3 h1:wpcpwl1RD9W/sXFDi4zpoIpQcIwIk8em9CGwa7YWv4g= github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.3.1 h1:22DEXVvGhnpF7PD4dvpgKH0/oD8u9I+a4cXCwy1x2f4= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= github.com/skelterjohn/geom v0.0.0-20180103000000-96f3e8a219c5f4276b0dda3568d80c4e02a50116 h1:3viuBF2tRGd2HlEs/uL4LLmdjOj8kAO6Y2c8Ii4H0oI= github.com/skelterjohn/geom v0.0.0-20180103000000-96f3e8a219c5f4276b0dda3568d80c4e02a50116/go.mod h1:w8cQIijHlvvZM7afYlixPThHAdD+AkRFw3Mb9yQ2Y+I= @@ -42,16 +44,22 @@ github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w= github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g= github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/whosonfirst/go-whosonfirst-cli v0.1.0 h1:Wwj9z0R/ryHmPmpVm5jCbXdG4agJzKMWXDtPVReN/KA= github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= github.com/whosonfirst/go-whosonfirst-flags v0.1.0 h1:llb2wtsI2y+gHZCmWaamMCx4YDRE8ZXQRRYqC7qB4so= @@ -61,6 +69,8 @@ github.com/whosonfirst/go-whosonfirst-flags v0.4.0 h1:3qEz1v7rALk+TqVstW9DKQOWrM github.com/whosonfirst/go-whosonfirst-flags v0.4.0/go.mod h1:kewFjxBiE00SqjjIanm5DPI81SYvx93wVb3ogwV/PMk= github.com/whosonfirst/go-whosonfirst-flags v0.4.2 h1:HWjy/0MfAQMdCj4M9hi3LAITgK/D+cuDWGHP37mFeZo= github.com/whosonfirst/go-whosonfirst-flags v0.4.2/go.mod h1:kewFjxBiE00SqjjIanm5DPI81SYvx93wVb3ogwV/PMk= +github.com/whosonfirst/go-whosonfirst-flags v0.4.3 h1:ef6IkgvYADL4kc750sl6i5hkReNq0Z6upLcqpK2CHLY= +github.com/whosonfirst/go-whosonfirst-flags v0.4.3/go.mod h1:pL17Ryo60FH8RYaQRgfu5XnxhrNRK3x+rn03TYD6Gc8= github.com/whosonfirst/go-whosonfirst-hash v0.1.0 h1:FpnclPIb+8M1uhSXfl3z8nYcG/3O59vgfkdV+m0hQpA= github.com/whosonfirst/go-whosonfirst-hash v0.1.0/go.mod h1:1ZdCFZTnQt5bwnsj2daB9yHilKOKToVh+Tyj/Z8TbUk= github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0 h1:zuSk8eqeEkg42sIZ4EF71IMtphdTbG80qJsXhuZXXbM= @@ -78,6 +88,9 @@ github.com/whosonfirst/go-whosonfirst-uri v0.1.0 h1:JMlpam0x1hVrFBMTAPY3edIHz7az github.com/whosonfirst/go-whosonfirst-uri v0.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= github.com/whosonfirst/go-whosonfirst-uri v0.2.0 h1:iODHdyvW+8IXqHZTixZ/9GEZy1dVKGj6dMRg7fn0d2M= github.com/whosonfirst/go-whosonfirst-uri v0.2.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-uri v1.1.0 h1:kNYOmKSm3u2asUOeq7yXL1Q8gFKkPIl8A0qinKrGV/8= +github.com/whosonfirst/go-whosonfirst-uri v1.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= github.com/whosonfirst/warning v0.1.0 h1:NgMa6a6Xv7FdDNgpqK5j/FDo6qrcFzFtidAExDqPfC0= github.com/whosonfirst/warning v0.1.0/go.mod h1:cAez7FpC/UEUrbiOXZO15v2JM8eijtFHQlN93AGFy1k= github.com/whosonfirst/warning v0.1.1 h1:h29zL3VNL9VUHztkAAndzblhrDHyik9z47OuUR2Vovw= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go index 0cf09ec..fed1e7c 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/directory.go @@ -2,6 +2,7 @@ package emitter import ( "context" + "fmt" "github.com/whosonfirst/go-whosonfirst-crawl" "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" "os" @@ -13,17 +14,28 @@ func init() { RegisterEmitter(ctx, "directory", NewDirectoryEmitter) } +// DirectoryEmitter implements the `Emitter` interface for crawling records in a directory. type DirectoryEmitter struct { Emitter + // filters is a `filters.Filters` instance used to include or exclude specific records from being crawled. filters filters.Filters } +// NewDirectoryEmitter() returns a new `DirectoryEmitter` instance configured by 'uri' in the form of: +// +// directory://?{PARAMETERS} +// +// Where {PARAMETERS} may be: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewDirectoryEmitter(ctx context.Context, uri string) (Emitter, error) { f, err := filters.NewQueryFiltersFromURI(ctx, uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create filters from query, %w", err) } idx := &DirectoryEmitter{ @@ -33,12 +45,14 @@ func NewDirectoryEmitter(ctx context.Context, uri string) (Emitter, error) { return idx, nil } +// WalkURI() walks (crawls) the directory named 'uri' and for each file (not excluded by any filters specified +// when `idx` was created) invokes 'index_cb'. func (idx *DirectoryEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { abs_path, err := filepath.Abs(uri) if err != nil { - return err + return fmt.Errorf("Failed to derive absolute path for '%s', %w", uri, err) } crawl_cb := func(path string, info os.FileInfo) error { @@ -57,7 +71,7 @@ func (idx *DirectoryEmitter) WalkURI(ctx context.Context, index_cb EmitterCallba fh, err := ReaderWithPath(ctx, path) if err != nil { - return err + return fmt.Errorf("Failed to create reader for '%s', %w", abs_path, err) } defer fh.Close() @@ -67,7 +81,7 @@ func (idx *DirectoryEmitter) WalkURI(ctx context.Context, index_cb EmitterCallba ok, err := idx.filters.Apply(ctx, fh) if err != nil { - return err + return fmt.Errorf("Failed to apply filters for '%s', %w", abs_path, err) } if !ok { @@ -77,13 +91,25 @@ func (idx *DirectoryEmitter) WalkURI(ctx context.Context, index_cb EmitterCallba _, err = fh.Seek(0, 0) if err != nil { - return err + return fmt.Errorf("Failed to seek(0, 0) on reader for '%s', %w", abs_path, err) } } - return index_cb(ctx, path, fh) + err = index_cb(ctx, path, fh) + + if err != nil { + return fmt.Errorf("Failed to invoke callback fir '%s', %w", abs_path, err) + } + + return nil } c := crawl.NewCrawler(abs_path) - return c.Crawl(crawl_cb) + err = c.Crawl(crawl_cb) + + if err != nil { + return fmt.Errorf("Failed to crawl '%s', %w", abs_path, err) + } + + return nil } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/emitter.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/emitter.go index 491834b..4489bc6 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/emitter.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/emitter.go @@ -1,3 +1,4 @@ +// Package emitter provides an interface for crawling data sources and "emitting" records. package emitter import ( @@ -11,47 +12,58 @@ import ( "strings" ) +// STDIN is a constant value signaling that a record was read from `STDIN` and has no URI (path). const STDIN string = "STDIN" -type IndexerContextKey string - +// type EmitterInitializeFunc is a function used to initialize an implementation of the `Emitter` interface. type EmitterInitializeFunc func(context.Context, string) (Emitter, error) +// EmitterCallbackFunc is a custom function used to process individual records as they are crawled by an instance of the `Emitter` interface. type EmitterCallbackFunc func(context.Context, string, io.ReadSeeker, ...interface{}) error +// type Emitter is an interface for crawling data sources and "emitting" records. Data sources are assumed to be Who's On First records. type Emitter interface { WalkURI(context.Context, EmitterCallbackFunc, string) error } +// emitters is a `aaronland/go-roster.Roster` instance used to maintain a list of registered `EmitterInitializeFunc` initialization functions. var emitters roster.Roster -func ensureSpatialRoster() error { - - if emitters == nil { - - r, err := roster.NewDefaultRoster() +// RegisterEmitter() associates 'scheme' with 'init_func' in an internal list of avilable `Emitter` implementations. +func RegisterEmitter(ctx context.Context, scheme string, f EmitterInitializeFunc) error { - if err != nil { - return err - } + err := ensureSpatialRoster() - emitters = r + if err != nil { + return fmt.Errorf("Failed to register %s scheme, %w", scheme, err) } - return nil + return emitters.Register(ctx, scheme, f) } -func RegisterEmitter(ctx context.Context, scheme string, f EmitterInitializeFunc) error { +// NewEmitter() returns a new `Emitter` instance derived from 'uri'. The semantics of and requirements for +// 'uri' as specific to the package implementing the interface. +func NewEmitter(ctx context.Context, uri string) (Emitter, error) { - err := ensureSpatialRoster() + u, err := url.Parse(uri) if err != nil { - return err + return nil, fmt.Errorf("Failed to parse URI, %w", err) } - return emitters.Register(ctx, scheme, f) + scheme := u.Scheme + + i, err := emitters.Driver(ctx, scheme) + + if err != nil { + return nil, fmt.Errorf("Failed to retrieve driver for %s scheme, %w", scheme, err) + } + + fn := i.(EmitterInitializeFunc) + return fn(ctx, uri) } +// Schemes() returns the list of schemes that have been "registered". func Schemes() []string { ctx := context.Background() @@ -72,39 +84,36 @@ func Schemes() []string { return schemes } -func NewEmitter(ctx context.Context, uri string) (Emitter, error) { - - u, err := url.Parse(uri) +// ReaderWithPath returns a new `io.ReadSeekCloser` instance derived from 'abs_path'. +func ReaderWithPath(ctx context.Context, abs_path string) (io.ReadSeekCloser, error) { - if err != nil { - return nil, err + if abs_path == STDIN { + return os.Stdin, nil } - scheme := u.Scheme - - i, err := emitters.Driver(ctx, scheme) + fh, err := os.Open(abs_path) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to open %s, %w", abs_path, err) } - fn := i.(EmitterInitializeFunc) - return fn(ctx, uri) + return fh, nil } -// +// ensureDispatcherRoster() ensures that a `aaronland/go-roster.Roster` instance used to maintain a list of registered `EmitterInitializeFunc` +// initialization functions is present +func ensureSpatialRoster() error { -func ReaderWithPath(ctx context.Context, abs_path string) (io.ReadSeekCloser, error) { + if emitters == nil { - if abs_path == STDIN { - return os.Stdin, nil - } + r, err := roster.NewDefaultRoster() - fh, err := os.Open(abs_path) + if err != nil { + return fmt.Errorf("Failed to create new roster, %w", err) + } - if err != nil { - return nil, err + emitters = r } - return fh, nil + return nil } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go index cb42f5b..18a1542 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/featurecollection.go @@ -15,17 +15,28 @@ func init() { RegisterEmitter(ctx, "featurecollection", NewFeatureCollectionEmitter) } +// FeatureCollectionEmitter implements the `Emitter` interface for crawling features in a GeoJSON FeatureCollection record. type FeatureCollectionEmitter struct { Emitter + // filters is a `filters.Filters` instance used to include or exclude specific records from being crawled. filters filters.Filters } +// NewFeatureCollectionEmitter() returns a new `FeatureCollectionEmitter` instance configured by 'uri' in the form of: +// +// featurecollection://?{PARAMETERS} +// +// Where {PARAMETERS} may be: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewFeatureCollectionEmitter(ctx context.Context, uri string) (Emitter, error) { f, err := filters.NewQueryFiltersFromURI(ctx, uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create filters from query, %w", err) } i := &FeatureCollectionEmitter{ @@ -35,12 +46,14 @@ func NewFeatureCollectionEmitter(ctx context.Context, uri string) (Emitter, erro return i, nil } +// WalkURI() walks (crawls) each feature in the GeoJSON FeatureCollection found in the file identified by 'uri' and for +// each file (not excluded by any filters specified when `idx` was created) invokes 'index_cb'. func (idx *FeatureCollectionEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { fh, err := ReaderWithPath(ctx, uri) if err != nil { - return err + return fmt.Errorf("Failed to create reader for '%s', %w", uri, err) } defer fh.Close() @@ -48,7 +61,7 @@ func (idx *FeatureCollectionEmitter) WalkURI(ctx context.Context, index_cb Emitt body, err := io.ReadAll(fh) if err != nil { - return err + return fmt.Errorf("Failed to read body for '%s', %w", uri, err) } type FC struct { @@ -61,7 +74,7 @@ func (idx *FeatureCollectionEmitter) WalkURI(ctx context.Context, index_cb Emitt err = json.Unmarshal(body, &collection) if err != nil { - return err + return fmt.Errorf("Failed to unmarshal '%s' as a feature collection, %w", uri, err) } for i, f := range collection.Features { @@ -73,17 +86,19 @@ func (idx *FeatureCollectionEmitter) WalkURI(ctx context.Context, index_cb Emitt // pass } + path := fmt.Sprintf("%s#%d", uri, i) + feature, err := json.Marshal(f) if err != nil { - return err + return fmt.Errorf("Failed to marshal feature for '%s', %w", path, err) } br := bytes.NewReader(feature) fh, err := ioutil.NewReadSeekCloser(br) if err != nil { - return err + return fmt.Errorf("Failed to create new ReadSeekCloser for '%s', %w", path, err) } if idx.filters != nil { @@ -91,7 +106,7 @@ func (idx *FeatureCollectionEmitter) WalkURI(ctx context.Context, index_cb Emitt ok, err := idx.filters.Apply(ctx, fh) if err != nil { - return err + return fmt.Errorf("Failed to apply filters for '%s', %w", path, err) } if !ok { @@ -101,15 +116,14 @@ func (idx *FeatureCollectionEmitter) WalkURI(ctx context.Context, index_cb Emitt _, err = fh.Seek(0, 0) if err != nil { - return err + return fmt.Errorf("Failed to seek(0, 0) for '%s', %w", path, err) } } - path := fmt.Sprintf("%s#%d", uri, i) err = index_cb(ctx, path, fh) if err != nil { - return err + return fmt.Errorf("Index callback failed for '%s', %w", path, err) } } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go index 1750b55..d9c3f82 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/file.go @@ -2,6 +2,7 @@ package emitter import ( "context" + "fmt" "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" ) @@ -10,17 +11,28 @@ func init() { RegisterEmitter(ctx, "file", NewFileEmitter) } +// FileEmitter implements the `Emitter` interface for crawling individual file records. type FileEmitter struct { Emitter + // filters is a `filters.Filters` instance used to include or exclude specific records from being crawled. filters filters.Filters } +// NewFileEmitter() returns a new `FileEmitter` instance configured by 'uri' in the form of: +// +// file://?{PARAMETERS} +// +// Where {PARAMETERS} may be: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewFileEmitter(ctx context.Context, uri string) (Emitter, error) { f, err := filters.NewQueryFiltersFromURI(ctx, uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create filters from query, %w", err) } idx := &FileEmitter{ @@ -30,12 +42,13 @@ func NewFileEmitter(ctx context.Context, uri string) (Emitter, error) { return idx, nil } +// WalkURI() applies 'index_cb' to the file named 'uri'. func (idx *FileEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { fh, err := ReaderWithPath(ctx, uri) if err != nil { - return err + return fmt.Errorf("Failed to create reader for '%s', %w", uri, err) } defer fh.Close() @@ -45,7 +58,7 @@ func (idx *FileEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFun ok, err := idx.filters.Apply(ctx, fh) if err != nil { - return err + return fmt.Errorf("Failed to apply filters for '%s', %w", uri, err) } if !ok { @@ -55,9 +68,15 @@ func (idx *FileEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFun _, err = fh.Seek(0, 0) if err != nil { - return err + return fmt.Errorf("Failed to seek(0,) for '%s', %w", uri, err) } } - return index_cb(ctx, uri, fh) + err = index_cb(ctx, uri, fh) + + if err != nil { + return fmt.Errorf("Index callback failed for '%s', %w", uri, err) + } + + return nil } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go index 58a4eb3..bc91299 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/filelist.go @@ -3,7 +3,9 @@ package emitter import ( "bufio" "context" + "fmt" "github.com/whosonfirst/go-whosonfirst-iterate/v2/filters" + "path/filepath" ) func init() { @@ -11,17 +13,28 @@ func init() { RegisterEmitter(ctx, "filelist", NewFileListEmitter) } +// FileListEmitter implements the `Emitter` interface for crawling records listed in a "file list" (a plain text newline-delimted list of files). type FileListEmitter struct { Emitter + // filters is a `filters.Filters` instance used to include or exclude specific records from being crawled. filters filters.Filters } +// NewFileListEmitter() returns a new `FileListEmitter` instance configured by 'uri' in the form of: +// +// file://?{PARAMETERS} +// +// Where {PARAMETERS} may be: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewFileListEmitter(ctx context.Context, uri string) (Emitter, error) { f, err := filters.NewQueryFiltersFromURI(ctx, uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create filters from query, %w", err) } idx := &FileListEmitter{ @@ -31,12 +44,20 @@ func NewFileListEmitter(ctx context.Context, uri string) (Emitter, error) { return idx, nil } +// WalkURI() walks (crawls) the list of files found in 'uri' and for each file (not excluded by any filters specified +// when `idx` was created) invokes 'index_cb'. func (idx *FileListEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { - fh, err := ReaderWithPath(ctx, uri) + abs_path, err := filepath.Abs(uri) if err != nil { - return err + return fmt.Errorf("Failed to derive absolute path for '%s', %w", uri, err) + } + + fh, err := ReaderWithPath(ctx, abs_path) + + if err != nil { + return fmt.Errorf("Failed to create reader for '%s', %w", abs_path, err) } defer fh.Close() @@ -57,7 +78,7 @@ func (idx *FileListEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac fh, err := ReaderWithPath(ctx, path) if err != nil { - return err + return fmt.Errorf("Failed to create reader for '%s', %w", path, err) } if idx.filters != nil { @@ -65,7 +86,7 @@ func (idx *FileListEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac ok, err := idx.filters.Apply(ctx, fh) if err != nil { - return err + return fmt.Errorf("Failed to apply filters to '%s', %w", path, err) } if !ok { @@ -75,21 +96,21 @@ func (idx *FileListEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac _, err = fh.Seek(0, 0) if err != nil { - return err + return fmt.Errorf("Failed to reset file handle for '%s', %w", path, err) } } err = index_cb(ctx, path, fh) if err != nil { - return err + return fmt.Errorf("Index callback failed for '%s', %w", path, err) } } err = scanner.Err() if err != nil { - return err + return fmt.Errorf("Scanner error reported, %w", err) } return nil diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go index 1301fe5..11886b1 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/geojsonls.go @@ -15,17 +15,28 @@ func init() { RegisterEmitter(ctx, "geojsonl", NewGeoJSONLEmitter) } +// GeojsonLEmitter implements the `Emitter` interface for crawling features in a line-separated GeoJSON record. type GeojsonLEmitter struct { Emitter + // filters is a `filters.Filters` instance used to include or exclude specific records from being crawled. filters filters.Filters } +// NewGeojsonLEmitter() returns a new `GeojsonLEmitter` instance configured by 'uri' in the form of: +// +// geojsonl://?{PARAMETERS} +// +// Where {PARAMETERS} may be: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewGeoJSONLEmitter(ctx context.Context, uri string) (Emitter, error) { f, err := filters.NewQueryFiltersFromURI(ctx, uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create filters from query, %w", err) } idx := &GeojsonLEmitter{ @@ -35,12 +46,14 @@ func NewGeoJSONLEmitter(ctx context.Context, uri string) (Emitter, error) { return idx, nil } +// WalkURI() walks (crawls) each GeoJSON feature found in the file identified by 'uri' and for +// each file (not excluded by any filters specified when `idx` was created) invokes 'index_cb'. func (idx *GeojsonLEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { fh, err := ReaderWithPath(ctx, uri) if err != nil { - return err + return fmt.Errorf("Failed to create reader for '%s', %w", uri, err) } defer fh.Close() @@ -74,7 +87,7 @@ func (idx *GeojsonLEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac } if err != nil { - return err + return fmt.Errorf("Failed to read line at '%s', %w", path, err) } raw.Write(fragment) @@ -87,7 +100,7 @@ func (idx *GeojsonLEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac fh, err := ioutil.NewReadSeekCloser(br) if err != nil { - return err + return fmt.Errorf("Failed to create new ReadSeekCloser for '%s', %w", path, err) } defer fh.Close() @@ -97,7 +110,7 @@ func (idx *GeojsonLEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac ok, err := idx.filters.Apply(ctx, fh) if err != nil { - return err + return fmt.Errorf("Failed to apply filters for '%s', %w", path, err) } if !ok { @@ -107,14 +120,14 @@ func (idx *GeojsonLEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbac _, err = fh.Seek(0, 0) if err != nil { - return err + return fmt.Errorf("Failed to reset file handle for '%s', %w", path, err) } } err = index_cb(ctx, path, fh) if err != nil { - return err + return fmt.Errorf("Index callback failed for '%s', %w", path, err) } raw.Reset() diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/null.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/null.go index 36ab35a..acb4b32 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/null.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/null.go @@ -9,16 +9,21 @@ func init() { RegisterEmitter(ctx, "null", NewNullEmitter) } +// NullEmitter implements the `Emitter` interface for appearing to crawl records but not doing anything. type NullEmitter struct { Emitter } +// NewNullEmitter() returns a new `NullEmitter` instance configured by 'uri' in the form of: +// +// null:// func NewNullEmitter(ctx context.Context, uri string) (Emitter, error) { idx := &NullEmitter{} return idx, nil } +// WalkURI() does nothing. func (idx *NullEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { return nil } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/repo.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/repo.go index c591c36..25a9c9d 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/repo.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter/repo.go @@ -2,6 +2,7 @@ package emitter import ( "context" + "fmt" "path/filepath" ) @@ -10,17 +11,28 @@ func init() { RegisterEmitter(ctx, "repo", NewRepoEmitter) } +// RepoEmitter implements the `Emitter` interface for crawling records in a Who's On First style data directory. type RepoEmitter struct { Emitter + // emitter is the underlying `DirectoryEmitter` instance for crawling records. emitter Emitter } +// NewDirectoryEmitter() returns a new `RepoEmitter` instance configured by 'uri' in the form of: +// +// repo://?{PARAMETERS} +// +// Where {PARAMETERS} may be: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewRepoEmitter(ctx context.Context, uri string) (Emitter, error) { directory_idx, err := NewDirectoryEmitter(ctx, uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create new directory emitter, %w", err) } idx := &RepoEmitter{ @@ -30,12 +42,14 @@ func NewRepoEmitter(ctx context.Context, uri string) (Emitter, error) { return idx, nil } +// WalkURI() appends 'uri' with "data" and then walks that directory and for each file (not excluded by any +// filters specified when `idx` was created) invokes 'index_cb'. func (idx *RepoEmitter) WalkURI(ctx context.Context, index_cb EmitterCallbackFunc, uri string) error { abs_path, err := filepath.Abs(uri) if err != nil { - return err + return fmt.Errorf("Failed to derive absolute path for '%s', %w", uri, err) } data_path := filepath.Join(abs_path, "data") diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/filters.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/filters.go index e702615..e9379ef 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/filters.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/filters.go @@ -1,3 +1,4 @@ +// Packge filters defines interfaces for filtering documents which should be processed during an iteration. package filters import ( @@ -5,6 +6,8 @@ import ( "io" ) +// type Filters defines an interface for filtering documents which should be processed during an iteration. type Filters interface { - Apply(context.Context, io.ReadSeekCloser) (bool, error) + // Apply() performs any filtering operations defined by the interface implementation to an `io.ReadSeekCloser` instance and returns a boolean value indicating whether the record should be considered for further processing. + Apply(context.Context, io.ReadSeeker) (bool, error) } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go index f576c2b..1d4aac5 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/filters/query.go @@ -2,29 +2,50 @@ package filters import ( "context" + "fmt" "github.com/aaronland/go-json-query" "io" "net/url" ) +// type QueryFilters implements the `Filters` interface for filtering documents using `aaronland/go-json-query` query strings. type QueryFilters struct { Filters + // Include is a `aaronland/go-json-query.QuerySet` instance containing rules that must match for a document to be considered for further processing. Include *query.QuerySet + // Exclude is a `aaronland/go-json-query.QuerySet` instance containing rules that if matched will prevent a document from being considered for further processing. Exclude *query.QuerySet } +// NewQueryFiltersFromURI() will return a `QueryFilters` instance derived from 'uri' which is expected +// to take the form of: +// +// {SCHEME}://{HOST}?{PARAMETERS} +// +// Where {SCHEME} and {HOST} can be any value so long as they conform to the URI standard. {PARAMETERS} is expected to be +// zero or more of the following parameters: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewQueryFiltersFromURI(ctx context.Context, uri string) (Filters, error) { u, err := url.Parse(uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse URI, %w", err) } q := u.Query() return NewQueryFiltersFromQuery(ctx, q) } +// NewQueryFiltersFromQuery() will return a `QueryFilters` instance derived from 'q' which is expected +// to contain zero or more of the following parameters: +// * `?include=` Zero or more `aaronland/go-json-query` query strings containing rules that must match for a document to be considered for further processing. +// * `?exclude=` Zero or more `aaronland/go-json-query` query strings containing rules that if matched will prevent a document from being considered for further processing. +// * `?include_mode=` A valid `aaronland/go-json-query` query mode string for testing inclusion rules. +// * `?exclude_mode=` A valid `aaronland/go-json-query` query mode string for testing exclusion rules. func NewQueryFiltersFromQuery(ctx context.Context, q url.Values) (Filters, error) { f := &QueryFilters{} @@ -38,7 +59,7 @@ func NewQueryFiltersFromQuery(ctx context.Context, q url.Values) (Filters, error includes_qs, err := querySetFromStrings(ctx, includes_mode, includes...) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to construct include query set, %w", err) } f.Include = includes_qs @@ -50,7 +71,7 @@ func NewQueryFiltersFromQuery(ctx context.Context, q url.Values) (Filters, error excludes_qs, err := querySetFromStrings(ctx, excludes_mode, excludes...) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to construct exclude query set, %w", err) } f.Exclude = excludes_qs @@ -59,6 +80,7 @@ func NewQueryFiltersFromQuery(ctx context.Context, q url.Values) (Filters, error return f, nil } +// querySetFromStrings() will return a `query.QuerySet` instance derive from 'mode' and 'flags'. func querySetFromStrings(ctx context.Context, mode string, flags ...string) (*query.QuerySet, error) { var query_flags query.QueryFlags @@ -69,7 +91,7 @@ func querySetFromStrings(ctx context.Context, mode string, flags ...string) (*qu err := query_flags.Set(fl) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to assign '%s' to query flags, %w", fl, err) } } @@ -88,12 +110,13 @@ func querySetFromStrings(ctx context.Context, mode string, flags ...string) (*qu return qs, nil } -func (f *QueryFilters) Apply(ctx context.Context, fh io.ReadSeekCloser) (bool, error) { +// Apply() performs filtering operations against 'fh' and returns a boolean value indicating whether the record should be considered for further processing. +func (f *QueryFilters) Apply(ctx context.Context, fh io.ReadSeeker) (bool, error) { body, err := io.ReadAll(fh) if err != nil { - return false, err + return false, fmt.Errorf("Failed to read document, %w", err) } includes_qs := f.Include @@ -104,7 +127,7 @@ func (f *QueryFilters) Apply(ctx context.Context, fh io.ReadSeekCloser) (bool, e matches, err := query.Matches(ctx, includes_qs, body) if err != nil { - return false, err + return false, fmt.Errorf("Failed to perform includes matching, %w", err) } if !matches { @@ -118,7 +141,7 @@ func (f *QueryFilters) Apply(ctx context.Context, fh io.ReadSeekCloser) (bool, e matches, err := query.Matches(ctx, excludes_qs, body) if err != nil { - return false, err + return false, fmt.Errorf("Failed to perform excludes matching, %w", err) } if matches { diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go index 8fa5a6e..9291f6f 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator/iterator.go @@ -1,7 +1,11 @@ +// Package iterator provides methods and utilities for iterating over a collection of records +// (presumed but not required to be Who's On First records) from a variety of sources and dispatching +// processing to user-defined callback functions. package iterator import ( "context" + "fmt" "github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter" "io" "log" @@ -13,28 +17,45 @@ import ( "time" ) +// type Iterator provides a struct that can be used for iterating over a collection of records +// (presumed but not required to be Who's On First records) from a variety of sources and dispatching +// processing to user-defined callback functions. type Iterator struct { - Emitter emitter.Emitter + // Emitter is a `emitter.Emitter` instance used to crawl and emit records. + Emitter emitter.Emitter + // EmitterCallbackFunc is a `emitter.EmitterCallbackFunc` callback function to be applied to each record emitted by `Emitter`. EmitterCallbackFunc emitter.EmitterCallbackFunc - Logger *log.Logger - Seen int64 - count int64 - max_procs int - exclude_paths *regexp.Regexp + // Logger is a `log.Logger` instance used to provide feedback. + Logger *log.Logger + // Seen is the count of documents that have been seen (or emitted). + Seen int64 + // count is the current number of documents being processed used to signal where an `Iterator` instance is still indexing (processing) documents. + count int64 + // max_procs is the number maximum (CPU) processes to used to process documents simultaneously. + max_procs int + // exclude_paths is a `regexp.Regexp` instance used to test and exclude (if matching) the paths of documents as they are iterated through. + exclude_paths *regexp.Regexp } +// NewIterator() returns a new `Iterator` instance derived from 'emitter_uri' and 'emitter_cb'. The former is expected +// to be a valid `whosonfirst/go-whosonfirst-iterate/v2/emitter.Emitter` URI whose semantics are defined by the underlying +// implementation of the `emitter.Emitter` interface. The following iterator-specific query parameters are also accepted: +// * `?_max_procs=` Explicitly set the number maximum processes to use for iterating documents simultaneously. (Default is the value of `runtime.NumCPU()`.) +// * `?_exclude=` A valid regular expresion used to test and exclude (if matching) the paths of documents as they are iterated through. func NewIterator(ctx context.Context, emitter_uri string, emitter_cb emitter.EmitterCallbackFunc) (*Iterator, error) { idx, err := emitter.NewEmitter(ctx, emitter_uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to create new emitter, %w", err) } + // Technically a no-op since we'll have parse 'emitter_uri' in NewEmitter but best not to assume + u, err := url.Parse(emitter_uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse URI, %w", err) } q := u.Query() @@ -46,7 +67,7 @@ func NewIterator(ctx context.Context, emitter_uri string, emitter_cb emitter.Emi max, err := strconv.ParseInt(q.Get("_max_procs"), 10, 64) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse '_max_procs' parameter, %w", err) } max_procs = int(max) @@ -68,7 +89,7 @@ func NewIterator(ctx context.Context, emitter_uri string, emitter_cb emitter.Emi re_exclude, err := regexp.Compile(q.Get("_exclude")) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse '_exclude' parameter, %w", err) } i.exclude_paths = re_exclude @@ -77,6 +98,8 @@ func NewIterator(ctx context.Context, emitter_uri string, emitter_cb emitter.Emi return &i, nil } +// IterateURIs processes 'uris' concurrent dispatching each URI to the iterator's underlying `Emitter.WalkURI` +// method and `EmitterCallbackFunc` callback function. func (idx *Iterator) IterateURIs(ctx context.Context, uris ...string) error { t1 := time.Now() @@ -139,7 +162,7 @@ func (idx *Iterator) IterateURIs(ctx context.Context, uris ...string) error { err := idx.Emitter.WalkURI(ctx, local_callback, uri) if err != nil { - err_ch <- err + err_ch <- fmt.Errorf("Failed to walk '%s', %w", uri, err) } }(uri) } @@ -158,6 +181,7 @@ func (idx *Iterator) IterateURIs(ctx context.Context, uris ...string) error { return nil } +// IsIndexing() returns a boolean value indicating whether 'idx' is still processing documents. func (idx *Iterator) IsIndexing() bool { if atomic.LoadInt64(&idx.count) > 0 { @@ -167,10 +191,12 @@ func (idx *Iterator) IsIndexing() bool { return false } +// increment() increments the count of documents being processed. func (idx *Iterator) increment() { atomic.AddInt64(&idx.count, 1) } +// decrement() decrements the count of documents being processed. func (idx *Iterator) decrement() { atomic.AddInt64(&idx.count, -1) } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.mod index 573c3a5..ad1315f 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.mod +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.mod @@ -3,18 +3,18 @@ module github.com/whosonfirst/go-whosonfirst-spatial go 1.16 require ( - github.com/aaronland/go-roster v0.0.2 - github.com/paulmach/orb v0.2.2 - github.com/sfomuseum/go-flags v0.8.2 - github.com/tidwall/gjson v1.9.2 - github.com/tidwall/sjson v1.2.2 - github.com/whosonfirst/go-reader v0.9.0 + github.com/aaronland/go-roster v1.0.0 + github.com/paulmach/orb v0.7.1 + github.com/sfomuseum/go-flags v0.8.3 + github.com/tidwall/gjson v1.14.2 + github.com/tidwall/sjson v1.2.5 + github.com/whosonfirst/go-reader v1.0.1 github.com/whosonfirst/go-sanitize v0.1.0 - github.com/whosonfirst/go-whosonfirst-feature v0.0.12 - github.com/whosonfirst/go-whosonfirst-flags v0.4.3 - github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0 + github.com/whosonfirst/go-whosonfirst-feature v0.0.24 + github.com/whosonfirst/go-whosonfirst-flags v0.4.4 + github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.1.0 github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 - github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 - github.com/whosonfirst/go-writer v0.6.0 + github.com/whosonfirst/go-whosonfirst-spr/v2 v2.2.1 + github.com/whosonfirst/go-writer v1.0.1 github.com/whosonfirst/warning v0.1.1 ) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.sum index 2f32886..1f16c26 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.sum +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spatial/go.sum @@ -1,131 +1,70 @@ -github.com/aaronland/go-json-query v0.0.2 h1:cKw/DnxtGaPsClb78ONgmXPOJkqHhaBMU2RTBbPoXos= -github.com/aaronland/go-json-query v0.0.2/go.mod h1:dGc7y824R93ugQMTldL7PFD/SPVGPwKdqrUJFLE/ILU= -github.com/aaronland/go-json-query v0.1.0 h1:ZHtbpW8jiGYuOXKDEscWDrDjyVXZhU9Qqfi3nkyI9Ho= -github.com/aaronland/go-json-query v0.1.0/go.mod h1:Mj1i+9hS3cd2Nj7qlnahcUeRC5uydPuJ/3xZGlIgBFU= -github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= -github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-json-query v0.1.2 h1:+yJBCJk9kcRAzbErhh+zOqK3DHSs/GmuSqXcCn5yH/c= +github.com/aaronland/go-json-query v0.1.2/go.mod h1:kkCl5KrO+fVSL2M8b/i3qO5PsnCpmajGXkbJHpEQPY8= +github.com/aaronland/go-roster v1.0.0 h1:FRDGrTqsYySKjWnAhbBGXyeGlI/o5/t9FZYCbUmyQtI= +github.com/aaronland/go-roster v1.0.0/go.mod h1:KIsYZgrJlAsyb9LsXSCvlqvbcCBVjCSqcQiZx42i9ro= github.com/g8rswimmer/error-chain v1.0.0 h1:WnwnunlvqtGPHVHmBfbmUyAgrtag8Y6nNpwLWmtSYOQ= github.com/g8rswimmer/error-chain v1.0.0/go.mod h1:XPJ/brUsL7yzc5VRlIxtf9GvoUqnOKVI9fg2MB5DWx8= -github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 h1:em+tTnzgU7N22woTBMcSJAOW7tRHAkK597W+MD/CpK8= github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/mmcloughlin/geohash v0.9.0 h1:FihR004p/aE1Sju6gcVq5OLDqGcMnpBY+8moBqIsVOs= -github.com/mmcloughlin/geohash v0.9.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= -github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE= -github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= -github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09 h1:DXR0VtCesBD2ss3toN9OEeXszpQmW9dc3SvUbUfiBC0= -github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= -github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY= -github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs= -github.com/paulmach/orb v0.2.2 h1:PblToKAbU0xHVypex/GdZfibA1CeCfN5s0UjxyWExdo= -github.com/paulmach/orb v0.2.2/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= -github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI= +github.com/paulmach/orb v0.6.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= +github.com/paulmach/orb v0.7.1 h1:Zha++Z5OX/l168sqHK3k4z18LDvr+YAO/VjK0ReQ9rU= +github.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/sfomuseum/go-edtf v0.2.2 h1:8n1UekTCU6fkgAf3bWqG5RyQxOd9hRhy4lg91aQ3kMk= -github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= -github.com/sfomuseum/go-edtf v0.2.3 h1:wpcpwl1RD9W/sXFDi4zpoIpQcIwIk8em9CGwa7YWv4g= github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= -github.com/sfomuseum/go-edtf v0.3.0 h1:D9YI8FUR9mGge2aVFLIJE1IF+6KDKZddXCftPjUPnSo= -github.com/sfomuseum/go-edtf v0.3.0/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= -github.com/sfomuseum/go-flags v0.7.0 h1:tj0BhAEhc7enIA0kuLjVNrVkqiUelX5jQkyL/A0cNAo= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v1.0.0/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v1.1.1 h1:R5gElndHGDaK/rGSh2X+ulaLtlcHCdQA1cTzB8e9wv8= +github.com/sfomuseum/go-edtf v1.1.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= -github.com/sfomuseum/go-flags v0.8.0 h1:gRmrsoWJ/KTNLxitnc+UZBL7nAghi2Vd/Xh45dZTF2s= -github.com/sfomuseum/go-flags v0.8.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= -github.com/sfomuseum/go-flags v0.8.1 h1:xiytUeZKoVHLf7lvICwUMHrGJxVRmR7C1s/3ozm/oLg= -github.com/sfomuseum/go-flags v0.8.1/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= -github.com/sfomuseum/go-flags v0.8.2 h1:elSU3KWMo442d1YjXu5Y/bokxvkGV+OrgAHshHZaeIo= -github.com/sfomuseum/go-flags v0.8.2/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= -github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 h1:qQF/q/+xaKD4CAVz3zfuvpij8U4ihSGIhHfOROI4NFc= -github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5/go.mod h1:w8cQIijHlvvZM7afYlixPThHAdD+AkRFw3Mb9yQ2Y+I= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= -github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w= -github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= -github.com/tidwall/gjson v1.7.1 h1:hwkZ6V1/EF8FxNhKJrIXQwSscyl2yWCZ1SkOCQYHSHA= -github.com/tidwall/gjson v1.7.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/gjson v1.7.4/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc= -github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= -github.com/tidwall/gjson v1.9.1 h1:wrrRk7TyL7MmKanNRck/Mcr3VU1sdMvJHvJXzqBIUNo= -github.com/tidwall/gjson v1.9.1/go.mod h1:jydLKE7s8J0+1/5jC4eXcuFlzKizGrCKvLmBVX/5oXc= -github.com/tidwall/gjson v1.9.2 h1:SJQc2IgWWKL5V+YGJrr95hjNXFeZzHT2L9Wv1aAb51Q= -github.com/tidwall/gjson v1.9.2/go.mod h1:2tcKM/KQ/GjiTN7mfTL/HdNmef9Q6AZLaSK2RdfvSjw= -github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= -github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/match v1.1.0 h1:VfI2e2aXLvytih7WUVyO9uvRC+RcXlaTrMbHuQWnFmk= -github.com/tidwall/match v1.1.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= -github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= -github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/sfomuseum/go-flags v0.8.3 h1:rclKNzfBgN8nfS5qKjMUo8ymQ4mrH4KaEMFQRAT98m8= +github.com/sfomuseum/go-flags v0.8.3/go.mod h1:VXOnnX1/yxQpX2yiwHaBV6aCmhtszQOL5bL1/nNo3co= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.2 h1:6BBkirS0rAHjumnjHF6qgy5d2YAJ1TLIaFE2lzfOLqo= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.1.6 h1:8fDdlahON04OZBlTQCIatW8FstSFJz8oxidj5h0rmSQ= -github.com/tidwall/sjson v1.1.6/go.mod h1:KN3FZ7odvXIHPbJdhNorK/M9lWweVUbXsXXhrJ/kGOA= -github.com/tidwall/sjson v1.2.2 h1:H1Llj/C9G+BoUN2DsybLHjWvr9dx4Uazavf0sXQ+rOs= -github.com/tidwall/sjson v1.2.2/go.mod h1:jmW2RZpbKuExPFUHeFSBMiovT9ZyOziEHDRkbsdp0B0= -github.com/whosonfirst/go-ioutil v0.0.1 h1:cCrEYen6NDvHfjzV2q4u/VB21u2kTOwDnUGRlMI8Z9o= -github.com/whosonfirst/go-ioutil v0.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= -github.com/whosonfirst/go-ioutil v1.0.0 h1:sYpgJx7Wsp76e7PFGa8KKQBvWQW3+HMCWSJbKdD5m14= -github.com/whosonfirst/go-ioutil v1.0.0/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= -github.com/whosonfirst/go-reader v0.5.0 h1:nx+ai0F6JXouw+7Dln34dmYglw+3sQ6sG4JZGOJ/sqA= -github.com/whosonfirst/go-reader v0.5.0/go.mod h1:4ou/wZUss2CDZp27QK5ySDc8p98GVWvUiqqmwEprjgk= -github.com/whosonfirst/go-reader v0.9.0 h1:u5PITZiAkPrpmZQHlkASdBEzF1pwby5vtgAmCEESWu4= -github.com/whosonfirst/go-reader v0.9.0/go.mod h1:6byB+UfZFNLYFqgsC/EKxTnKY8ahNgGHhUJsTrv1Jig= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/whosonfirst/go-ioutil v1.0.2 h1:+GJPfa42OFn5A+5yJSc5jQTQIkNV3/MhYyg4pavdrC8= +github.com/whosonfirst/go-ioutil v1.0.2/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= +github.com/whosonfirst/go-reader v1.0.1 h1:mvEqObVuzJyZkI37SDmuvCpTJ2iEG5GUgD2Z3mT2e7s= +github.com/whosonfirst/go-reader v1.0.1/go.mod h1:3RXON51sbyPw8Ca7sxxwOItVfx8SM+KFPR+l2azGxJA= github.com/whosonfirst/go-sanitize v0.1.0 h1:ygSqCnakwdzH/m8UEa15zXGDsoo5/JJeRkgmAjXZrBU= github.com/whosonfirst/go-sanitize v0.1.0/go.mod h1:p/emgbafMM0p5iVAz2XWwecYPl06Tw4Jos9rhTKIrt8= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= github.com/whosonfirst/go-whosonfirst-crawl v0.2.1 h1:nNG7r7/4MaII/NM8Df2oqgfgVNBDoIKlseleoX1vw1Q= github.com/whosonfirst/go-whosonfirst-crawl v0.2.1/go.mod h1:MTD1TCgAkXlAtysPU98ylrz9Y5+ZCfRrsrBnRyiH/t8= -github.com/whosonfirst/go-whosonfirst-feature v0.0.7 h1:KweSqcJenzI01zCgbVUzjAlzFmXJMDRVX68mpHRSRUg= -github.com/whosonfirst/go-whosonfirst-feature v0.0.7/go.mod h1:NhUZ9XDyqQiOipFIBvbmixwfM6jtSzP2lX5dxcWX5uw= -github.com/whosonfirst/go-whosonfirst-feature v0.0.12 h1:SNZdeOhQ4XXid4g4iJ5/H6y0tU4rOGn/41M/knVgFMM= -github.com/whosonfirst/go-whosonfirst-feature v0.0.12/go.mod h1:NhUZ9XDyqQiOipFIBvbmixwfM6jtSzP2lX5dxcWX5uw= -github.com/whosonfirst/go-whosonfirst-flags v0.2.0/go.mod h1:ECd0AJJZIlybmjTGB9z+CPz9pSiMTwxur7fPKmDnoqI= -github.com/whosonfirst/go-whosonfirst-flags v0.4.2 h1:HWjy/0MfAQMdCj4M9hi3LAITgK/D+cuDWGHP37mFeZo= -github.com/whosonfirst/go-whosonfirst-flags v0.4.2/go.mod h1:kewFjxBiE00SqjjIanm5DPI81SYvx93wVb3ogwV/PMk= -github.com/whosonfirst/go-whosonfirst-flags v0.4.3 h1:ef6IkgvYADL4kc750sl6i5hkReNq0Z6upLcqpK2CHLY= +github.com/whosonfirst/go-whosonfirst-feature v0.0.23/go.mod h1:3cvRigFFG2a99M64lZzfy5amHacWu8Os5fXZdGjPnLM= +github.com/whosonfirst/go-whosonfirst-feature v0.0.24 h1:YR3Qm0oFDc9FM4z6VXsTZ4tSBRdi/hKKQUOj9fYy/Yw= +github.com/whosonfirst/go-whosonfirst-feature v0.0.24/go.mod h1:bdRPXMN+i82aVJSVMEaO306wDITCijdSIcmgUbSp04E= github.com/whosonfirst/go-whosonfirst-flags v0.4.3/go.mod h1:pL17Ryo60FH8RYaQRgfu5XnxhrNRK3x+rn03TYD6Gc8= -github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3 h1:EaLfTJqWj7q3bVCNil+F9QtVylxiyWNlo09ZEUDtf+E= -github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3/go.mod h1:R3GximAGJWLCITU2eh3I5Vtyze/usjOl5LTGQCDI89Y= -github.com/whosonfirst/go-whosonfirst-hash v0.1.0 h1:FpnclPIb+8M1uhSXfl3z8nYcG/3O59vgfkdV+m0hQpA= -github.com/whosonfirst/go-whosonfirst-hash v0.1.0/go.mod h1:1ZdCFZTnQt5bwnsj2daB9yHilKOKToVh+Tyj/Z8TbUk= -github.com/whosonfirst/go-whosonfirst-iterate v1.1.1 h1:7J8kq86bZgO2uUEJcSW7ciWTaoMC9k5obFQ90lp7ZpQ= -github.com/whosonfirst/go-whosonfirst-iterate v1.1.1/go.mod h1:ceLMHQ9s3naZLFcKeUvokP0Sw7/BmwuZJiaQt/mVO0I= -github.com/whosonfirst/go-whosonfirst-iterate v1.2.0 h1:+wouZy6JPIrmLBZdFDqI1UJWthbpwGc1JRdnLbW6hIc= -github.com/whosonfirst/go-whosonfirst-iterate v1.2.0/go.mod h1:MOA6QCBONVG98p8kA8HaoBEAmv83jW4SNTfNhHpP9+o= -github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0 h1:w2N2TfsaGcONmQzR4MMxuDvVpt8DuJnlVeS9Eh5Sffk= -github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0/go.mod h1:NeChKAgakom3sWjPfTnxauSykSzmkfqnEbtuy6nSF6s= -github.com/whosonfirst/go-whosonfirst-log v0.1.0 h1:mWYI5hn16uyeLxBmPsLSvYV4rQKK/cxGVhM+bC2ZoGc= -github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= -github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= +github.com/whosonfirst/go-whosonfirst-flags v0.4.4 h1:pwUnE8btx4Po6N5+uq0IrKVF0WraY5YW3tc3saIDg3A= +github.com/whosonfirst/go-whosonfirst-flags v0.4.4/go.mod h1:C9X7vQvNR/u55AfOHYUT8o7dRACWV++ZV4B0kylnIaY= +github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.1.0 h1:/+BjiA045nnk/kVtxvwxAxPuRHF0zN1+zcedynCvlbY= +github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.1.0/go.mod h1:aWeWB3DYX7bVtnNNRjCpMNZSsRgohX+FM7ukQ0cXXTY= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 h1:68kuizK8FXjfEIOKlqWemhs7gyMBIgpLJDbCZF8+8Ok= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0/go.mod h1:ez0VFkGFbgT2/z2oi3PIuW6FewsZ2+5glyfDD79XEHk= github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= -github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 h1:UQ1n/uODS50mckZpXYe5GKm8XwoUUC1jRcNN8oiW2uc= -github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0/go.mod h1:tveSSFDn8XoiCeAMarSCn769lA6e3Y0/Qi8S19Jz7Gw= -github.com/whosonfirst/go-whosonfirst-uri v0.2.0 h1:iODHdyvW+8IXqHZTixZ/9GEZy1dVKGj6dMRg7fn0d2M= -github.com/whosonfirst/go-whosonfirst-uri v0.2.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -github.com/whosonfirst/go-whosonfirst-uri v1.0.1 h1:hVEDRuW9WhqvTksDi092OO9UecX7PAMDrD47KPEqAg0= +github.com/whosonfirst/go-whosonfirst-spr/v2 v2.2.1 h1:WRL/a9KPyA+MC6/ChIWlRqa/1BtV94Ak9Fh4cZB0yjs= +github.com/whosonfirst/go-whosonfirst-spr/v2 v2.2.1/go.mod h1:3P6fiSVGtIbM3UcyaVMs4i1N6Hi88GmTsdouuXzlr78= github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -github.com/whosonfirst/go-writer v0.4.1 h1:pAZ/cwaCM129PfwYy28ggCIRfL98OkrYxNnAxz2dksg= -github.com/whosonfirst/go-writer v0.4.1/go.mod h1:kFzhremCFtnkJdmviwJEPLFYKQ5+vq6ocJPxt1bHPFY= -github.com/whosonfirst/go-writer v0.6.0 h1:rlr8xGaUrSfUC4ogDHKj6F/bEkA1inbw95FEgCHbSAs= -github.com/whosonfirst/go-writer v0.6.0/go.mod h1:Qj0rZgdoFagSJ1xwhm60KyTgMU4DK5C6q5n8zKpgnj8= +github.com/whosonfirst/go-whosonfirst-uri v1.2.0 h1:lhmRsIhcpTr5HAo+kXKRGsSt76HTh3Ko/oTR2jpCm/o= +github.com/whosonfirst/go-whosonfirst-uri v1.2.0/go.mod h1:CuVygTCUpMG945MMvqHyqxvc/L5YkDaMrrVpRFr7ZxY= +github.com/whosonfirst/go-writer v1.0.1 h1:Ew9tkA/rTgF8w7yNc9CrdioVBLltDwWfMM0kDSA6jvc= +github.com/whosonfirst/go-writer v1.0.1/go.mod h1:pVM562YU8Mu2IHqgT+Rk4o4ITAHM6d5dxeJL5G/r3UU= github.com/whosonfirst/walk v0.0.1 h1:t0QrqGwOdPMSeovFZSXfiS0GIGHrRXK3Wb9z5Uhs2bg= github.com/whosonfirst/walk v0.0.1/go.mod h1:1KtP/VeooSlFOI61p+THc/C16Ra8Z5MjpjI0tsd3c1M= github.com/whosonfirst/warning v0.1.1 h1:h29zL3VNL9VUHztkAAndzblhrDHyik9z47OuUR2Vovw= @@ -137,7 +76,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -151,7 +89,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -160,5 +97,4 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/Makefile b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/Makefile deleted file mode 100644 index 734934f..0000000 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -vendor-deps: - go mod vendor - -fmt: - go fmt *.go - go fmt util/*.go diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/README.md b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/README.md index 0b4a354..819eddb 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/README.md +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/README.md @@ -2,6 +2,10 @@ Go package for the Who's On First "standard places responses" (SPR) interface. +## Documentation + +[![Go Reference](https://pkg.go.dev/badge/github.com/whosonfirst/go-whosonfirst-spr.svg)](https://pkg.go.dev/github.com/whosonfirst/go-whosonfirst-spr) + ## Description The `StandardPlacesResult` (SPR) interface defines the _minimum_ set of methods that a system working with a collection of Who's On First (WOF) must implement for any given record. Not all records are the same so the SPR interface is meant to serve as a baseline for common data that describes every record. @@ -12,44 +16,6 @@ Being a [Go language interface type](https://www.alexedwards.net/blog/interfaces For a concrete example of a package that implements the `SPR` have a look at the [go-whosonfirst-sqlite-spr](https://github.com/whosonfirst/go-whosonfirst-sqlite-spr) package. -## Usage - -``` -import "github.com/whosonfirst/go-whosonfirst-spr/v2" -``` - -## Interface - -``` -type StandardPlacesResult interface { - Id() string - ParentId() string - Name() string - Placetype() string - Country() string - Repo() string - Path() string - URI() string - Inception() *edtf.EDTFDate - Cessation() *edtf.EDTFDate - Latitude() float64 - Longitude() float64 - MinLatitude() float64 - MinLongitude() float64 - MaxLatitude() float64 - MaxLongitude() float64 - IsCurrent() flags.ExistentialFlag - IsCeased() flags.ExistentialFlag - IsDeprecated() flags.ExistentialFlag - IsSuperseded() flags.ExistentialFlag - IsSuperseding() flags.ExistentialFlag - SupersededBy() []int64 - Supersedes() []int64 - BelongsTo() []int64 - LastModified() int64 -} -``` - ### Notes * The `Id()` and `ParentId()` methods return `string` (rather than `int64`) values to account for non-WOF GeoJSON documents that are consumed by the `whosonfirst/go-whosonfirst-geojson-v2` package. diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/doc.go b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/doc.go new file mode 100644 index 0000000..e340fce --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/doc.go @@ -0,0 +1,11 @@ +// package spr provides an interface which defines the minimum set of methods that a system working with a collection of Who's On First (WOF) must implement for any given record. Not all records are the same so the SPR interface is meant to serve as a baseline for common data that describes every record. +// +// The `StandardPlacesResult` (SPR) interface defines the _minimum_ set of methods that a system working with a collection of Who's On First (WOF) must implement for any given record. Not all records are the same so the SPR interface is meant to serve as a baseline for common data that describes every record. +// +// The `StandardPlacesResults` takes the Flickr [standard photo response](https://code.flickr.net/2008/08/19/standard-photos-response-apis-for-civilized-age) as its inspiration which was designed to be the minimum amount of information about a Flickr photo necessary to display that photo with proper attribution and a link back to the photo page itself. The `StandardPlacesResults` aims to achieve the same thing for WOF records. +// +// Being a [Go language interface type](https://www.alexedwards.net/blog/interfaces-explained) the SPR is _not_ designed as a data exchange method. Any given implementation of the SPR _may_ allow its internal data to be exported or serialized (for example, as JSON) but this is not a requirement. +// +// For a concrete example of a package that implements the `SPR` have a look at the [go-whosonfirst-sqlite-spr](https://github.com/whosonfirst/go-whosonfirst-sqlite-spr) package. +package spr + diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.mod index e8aad89..f1ff344 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.mod +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.mod @@ -1,8 +1,10 @@ module github.com/whosonfirst/go-whosonfirst-spr/v2 -go 1.12 +go 1.16 require ( - github.com/sfomuseum/go-edtf v0.2.2 - github.com/whosonfirst/go-whosonfirst-flags v0.2.0 + github.com/sfomuseum/go-edtf v1.0.0 + github.com/whosonfirst/go-whosonfirst-feature v0.0.23 + github.com/whosonfirst/go-whosonfirst-flags v0.4.3 + github.com/whosonfirst/go-whosonfirst-uri v1.0.1 ) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.sum index 5fa5d1c..07e1ebc 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.sum +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/go.sum @@ -1,29 +1,61 @@ -github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/paulmach/orb v0.6.0 h1:QqsQkeYM3zzr3ANUHWBoo8zvK1CATO4G9pYmKoCAgnM= +github.com/paulmach/orb v0.6.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= +github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/sfomuseum/go-edtf v0.2.2 h1:8n1UekTCU6fkgAf3bWqG5RyQxOd9hRhy4lg91aQ3kMk= -github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= -github.com/whosonfirst/go-whosonfirst-flags v0.1.0 h1:llb2wtsI2y+gHZCmWaamMCx4YDRE8ZXQRRYqC7qB4so= -github.com/whosonfirst/go-whosonfirst-flags v0.1.0/go.mod h1:bovMiQphaVhqemXFmNVf9Ts0tqnWtzHRFMUSKX+zTE8= -github.com/whosonfirst/go-whosonfirst-flags v0.2.0 h1:zia/L+rhKSQ5iruITPnwU9lqsd1SavvF+HYRubEARSs= -github.com/whosonfirst/go-whosonfirst-flags v0.2.0/go.mod h1:ECd0AJJZIlybmjTGB9z+CPz9pSiMTwxur7fPKmDnoqI= -github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0/go.mod h1:Jdmug2QQLbrmg+UcYGz8k575GnrOEg63vZVS46e5fMs= -github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= +github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v1.0.0 h1:pU76aSrBgRTaKK/RzEESYDU+YcGNbBk/XKwEMr4qXmE= +github.com/sfomuseum/go-edtf v1.0.0/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= +github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/whosonfirst/go-whosonfirst-feature v0.0.23 h1:/oklJJRMF5a75D7tYKueh1nQRBcejqZ2cnr0CdakYiQ= +github.com/whosonfirst/go-whosonfirst-feature v0.0.23/go.mod h1:3cvRigFFG2a99M64lZzfy5amHacWu8Os5fXZdGjPnLM= +github.com/whosonfirst/go-whosonfirst-flags v0.4.3 h1:ef6IkgvYADL4kc750sl6i5hkReNq0Z6upLcqpK2CHLY= +github.com/whosonfirst/go-whosonfirst-flags v0.4.3/go.mod h1:pL17Ryo60FH8RYaQRgfu5XnxhrNRK3x+rn03TYD6Gc8= +github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0/go.mod h1:ez0VFkGFbgT2/z2oi3PIuW6FewsZ2+5glyfDD79XEHk= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= -github.com/whosonfirst/go-whosonfirst-spr v0.1.0 h1:5qE629nCiucF2upy5NjPOEl9cFatsljykYY0l2JKgAk= -github.com/whosonfirst/go-whosonfirst-spr v0.1.0/go.mod h1:R8GtEVz1GVSnwwOjzcoVUd172ZK26Q7hQSLI6SGG7lM= -github.com/whosonfirst/go-whosonfirst-uri v0.2.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -github.com/whosonfirst/warning v0.1.0/go.mod h1:cAez7FpC/UEUrbiOXZO15v2JM8eijtFHQlN93AGFy1k= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1 h1:hVEDRuW9WhqvTksDi092OO9UecX7PAMDrD47KPEqAg0= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= github.com/whosonfirst/warning v0.1.1/go.mod h1:/unEMzhB9YaMeEwTJpzLN3kM5LiSxdJhKEsf/OQhn6s= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/spr.go b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/spr.go index a675bed..1d89c28 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/spr.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/spr.go @@ -1,47 +1,66 @@ package spr import ( + "github.com/sfomuseum/go-edtf" "github.com/whosonfirst/go-whosonfirst-flags" - "github.com/sfomuseum/go-edtf" ) +// StandardPlacesResult is an interface which defines the minimum set of methods that a system working with a collection of Who's On First (WOF) must implement for any given record. Not all records are the same so the SPR interface is meant to serve as a baseline for common data that describes every record. type StandardPlacesResult interface { + // The unique ID of the place result Id() string + // The unique parent ID of the place result ParentId() string + // The name of the place result Name() string + // The Who's On First placetype of the place result Placetype() string + // The two-letter country code of the place result Country() string + // The (Git) repository name where the source record for the place result is stored. Repo() string + // The relative path for the Who's On First record associated with the place result Path() string + // The fully-qualified URI (URL) for the Who's On First record associated with the place result URI() string + // The EDTF inception date of the place result Inception() *edtf.EDTFDate - Cessation() *edtf.EDTFDate + // The EDTF cessation date of the place result + Cessation() *edtf.EDTFDate + // The latitude for the principal centroid (typically "label") of the place result Latitude() float64 + // The longitude for the principal centroid (typically "label") of the place result Longitude() float64 + // The minimum latitude of the bounding box of the place result MinLatitude() float64 + // The minimum longitude of the bounding box of the place result MinLongitude() float64 + // The maximum latitude of the bounding box of the place result MaxLatitude() float64 + // The maximum longitude of the bounding box of the place result MaxLongitude() float64 + // The Who's On First "existential" flag denoting whether the place result is "current" or not IsCurrent() flags.ExistentialFlag + // The Who's On First "existential" flag denoting whether the place result is "ceased" or not IsCeased() flags.ExistentialFlag + // The Who's On First "existential" flag denoting whether the place result is superseded or not IsDeprecated() flags.ExistentialFlag + // The Who's On First "existential" flag denoting whether the place result has been superseded IsSuperseded() flags.ExistentialFlag + // The Who's On First "existential" flag denoting whether the place result supersedes other records IsSuperseding() flags.ExistentialFlag + // The list of Who's On First IDs that supersede the place result SupersededBy() []int64 + // The list of Who's On First IDs that are superseded by the place result Supersedes() []int64 + // The list of Who's On First IDs that are ancestors of the place result BelongsTo() []int64 + // The Unix timestamp indicating when the place result was last modified LastModified() int64 } -type Pagination interface { - Pages() int - Page() int - PerPage() int - Total() int - Cursor() string - NextQuery() string -} - +// StandardPlacesResults provides an interface for returning a list of `StandardPlacesResult` results type StandardPlacesResults interface { + // Results is a list of `StandardPlacesResult` instances. Results() []StandardPlacesResult } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/whosonfirst.go b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/whosonfirst.go new file mode 100644 index 0000000..cdd0756 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/whosonfirst.go @@ -0,0 +1,343 @@ +package spr + +import ( + "fmt" + "github.com/sfomuseum/go-edtf" + "github.com/sfomuseum/go-edtf/parser" + "github.com/whosonfirst/go-whosonfirst-feature/alt" + "github.com/whosonfirst/go-whosonfirst-feature/geometry" + "github.com/whosonfirst/go-whosonfirst-feature/properties" + "github.com/whosonfirst/go-whosonfirst-flags" + "github.com/whosonfirst/go-whosonfirst-flags/existential" + "github.com/whosonfirst/go-whosonfirst-uri" + "strconv" +) + +// WOFStandardPlacesResult is a struct that implements the `StandardPlacesResult` for +// Who's On First GeoJSON Feature records. +type WOFStandardPlacesResult struct { + StandardPlacesResult `json:",omitempty"` + EDTFInception string `json:"edtf:inception"` + EDTFCessation string `json:"edtf:cessation"` + WOFId int64 `json:"wof:id"` + WOFParentId int64 `json:"wof:parent_id"` + WOFName string `json:"wof:name"` + WOFPlacetype string `json:"wof:placetype"` + WOFCountry string `json:"wof:country"` + WOFRepo string `json:"wof:repo"` + WOFPath string `json:"wof:path"` + WOFSupersededBy []int64 `json:"wof:superseded_by"` + WOFSupersedes []int64 `json:"wof:supersedes"` + WOFBelongsTo []int64 `json:"wof:belongsto"` + MZURI string `json:"mz:uri"` + MZLatitude float64 `json:"mz:latitude"` + MZLongitude float64 `json:"mz:longitude"` + MZMinLatitude float64 `json:"mz:min_latitude"` + MZMinLongitude float64 `json:"mz:min_longitude"` + MZMaxLatitude float64 `json:"mz:max_latitude"` + MZMaxLongitude float64 `json:"mz:max_longitude"` + MZIsCurrent int64 `json:"mz:is_current"` + MZIsCeased int64 `json:"mz:is_ceased"` + MZIsDeprecated int64 `json:"mz:is_deprecated"` + MZIsSuperseded int64 `json:"mz:is_superseded"` + MZIsSuperseding int64 `json:"mz:is_superseding"` + WOFLastModified int64 `json:"wof:lastmodified"` +} + +// WhosOnFirstSPR will derive a new `WOFStandardPlacesResult` instance from 'f'. +func WhosOnFirstSPR(f []byte) (StandardPlacesResult, error) { + + if alt.IsAlt(f) { + return nil, fmt.Errorf("Can not create SPR for alternate geometry") + } + + id, err := properties.Id(f) + + if err != nil { + return nil, err + } + + parent_id, err := properties.ParentId(f) + + if err != nil { + return nil, err + } + + name, err := properties.Name(f) + + if err != nil { + return nil, err + } + + placetype, err := properties.Placetype(f) + + if err != nil { + return nil, err + } + + country := properties.Country(f) + + repo, err := properties.Repo(f) + + if err != nil { + return nil, err + } + + inception := properties.Inception(f) + cessation := properties.Cessation(f) + + // See this: We're accounting for all the pre-2019 EDTF spec + // inception but mostly cessation strings by silently swapping + // them out (20210321/straup) + + _, err = parser.ParseString(inception) + + if err != nil { + + if !edtf.IsDeprecated(inception) { + return nil, err + } + + replacement, err := edtf.ReplaceDeprecated(inception) + + if err != nil { + return nil, err + } + + inception = replacement + } + + _, err = parser.ParseString(cessation) + + if err != nil { + + if !edtf.IsDeprecated(cessation) { + return nil, err + } + + replacement, err := edtf.ReplaceDeprecated(cessation) + + if err != nil { + return nil, err + } + + cessation = replacement + } + + path, err := uri.Id2RelPath(id) + + if err != nil { + return nil, err + } + + uri, err := uri.Id2AbsPath("https://data.whosonfirst.org", id) + + if err != nil { + return nil, err + } + + is_current, err := properties.IsCurrent(f) + + if err != nil { + return nil, err + } + + is_ceased, err := properties.IsCeased(f) + + if err != nil { + return nil, err + } + + is_deprecated, err := properties.IsDeprecated(f) + + if err != nil { + return nil, err + } + + is_superseded, err := properties.IsSuperseded(f) + + if err != nil { + return nil, err + } + + is_superseding, err := properties.IsSuperseding(f) + + if err != nil { + return nil, err + } + + centroid, _, err := properties.Centroid(f) + + if err != nil { + return nil, err + } + + geojson_geom, err := geometry.Geometry(f) + + if err != nil { + return nil, err + } + + orb_geom := geojson_geom.Geometry() + mbr := orb_geom.Bound() + + superseded_by := properties.SupersededBy(f) + supersedes := properties.Supersedes(f) + + belongsto := properties.BelongsTo(f) + + lastmod := properties.LastModified(f) + + spr := WOFStandardPlacesResult{ + WOFId: id, + WOFParentId: parent_id, + WOFPlacetype: placetype, + WOFName: name, + WOFCountry: country, + WOFRepo: repo, + WOFPath: path, + WOFSupersedes: supersedes, + WOFSupersededBy: superseded_by, + WOFBelongsTo: belongsto, + EDTFInception: inception, + EDTFCessation: cessation, + MZURI: uri, + MZLatitude: centroid.Y(), + MZLongitude: centroid.X(), + MZMinLatitude: mbr.Min.Y(), + MZMinLongitude: mbr.Min.X(), + MZMaxLatitude: mbr.Max.Y(), + MZMaxLongitude: mbr.Max.X(), + MZIsCurrent: is_current.Flag(), + MZIsCeased: is_ceased.Flag(), + MZIsDeprecated: is_deprecated.Flag(), + MZIsSuperseded: is_superseded.Flag(), + MZIsSuperseding: is_superseding.Flag(), + WOFLastModified: lastmod, + } + + return &spr, nil + +} + +func (spr *WOFStandardPlacesResult) Id() string { + return strconv.FormatInt(spr.WOFId, 10) +} + +func (spr *WOFStandardPlacesResult) ParentId() string { + return strconv.FormatInt(spr.WOFParentId, 10) +} + +func (spr *WOFStandardPlacesResult) Name() string { + return spr.WOFName +} + +func (spr *WOFStandardPlacesResult) Inception() *edtf.EDTFDate { + return spr.edtfDate(spr.EDTFInception) +} + +func (spr *WOFStandardPlacesResult) Cessation() *edtf.EDTFDate { + return spr.edtfDate(spr.EDTFCessation) +} + +func (spr *WOFStandardPlacesResult) edtfDate(edtf_str string) *edtf.EDTFDate { + + d, err := parser.ParseString(edtf_str) + + if err != nil { + return nil + } + + return d +} + +func (spr *WOFStandardPlacesResult) Placetype() string { + return spr.WOFPlacetype +} + +func (spr *WOFStandardPlacesResult) Country() string { + return spr.WOFCountry +} + +func (spr *WOFStandardPlacesResult) Repo() string { + return spr.WOFRepo +} + +func (spr *WOFStandardPlacesResult) Path() string { + return spr.WOFPath +} + +func (spr *WOFStandardPlacesResult) URI() string { + return spr.MZURI +} + +func (spr *WOFStandardPlacesResult) Latitude() float64 { + return spr.MZLatitude +} + +func (spr *WOFStandardPlacesResult) Longitude() float64 { + return spr.MZLongitude +} + +func (spr *WOFStandardPlacesResult) MinLatitude() float64 { + return spr.MZMinLatitude +} + +func (spr *WOFStandardPlacesResult) MinLongitude() float64 { + return spr.MZMinLongitude +} + +func (spr *WOFStandardPlacesResult) MaxLatitude() float64 { + return spr.MZLatitude +} + +func (spr *WOFStandardPlacesResult) MaxLongitude() float64 { + return spr.MZMaxLongitude +} + +func (spr *WOFStandardPlacesResult) IsCurrent() flags.ExistentialFlag { + return existentialFlag(spr.MZIsCurrent) +} + +func (spr *WOFStandardPlacesResult) IsCeased() flags.ExistentialFlag { + return existentialFlag(spr.MZIsCeased) +} + +func (spr *WOFStandardPlacesResult) IsDeprecated() flags.ExistentialFlag { + return existentialFlag(spr.MZIsDeprecated) +} + +func (spr *WOFStandardPlacesResult) IsSuperseded() flags.ExistentialFlag { + return existentialFlag(spr.MZIsSuperseded) +} + +func (spr *WOFStandardPlacesResult) IsSuperseding() flags.ExistentialFlag { + return existentialFlag(spr.MZIsSuperseding) +} + +func (spr *WOFStandardPlacesResult) SupersededBy() []int64 { + return spr.WOFSupersededBy +} + +func (spr *WOFStandardPlacesResult) Supersedes() []int64 { + return spr.WOFSupersedes +} + +func (spr *WOFStandardPlacesResult) BelongsTo() []int64 { + return spr.WOFBelongsTo +} + +func (spr *WOFStandardPlacesResult) LastModified() int64 { + return spr.WOFLastModified +} + +// we're going to assume that this won't fail since we already go through +// the process of instantiating `flags.ExistentialFlag` thingies in SPR() +// if we need to we'll just cache those instances in the `spr *WOFStandardPlacesResult` +// thingy (and omit them from the JSON output) but today that is unnecessary +// (20170816/thisisaaronland) + +func existentialFlag(i int64) flags.ExistentialFlag { + fl, _ := existential.NewKnownUnknownFlag(i) + return fl +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/whosonfirst_alt.go b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/whosonfirst_alt.go new file mode 100644 index 0000000..cd1817b --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-spr/v2/whosonfirst_alt.go @@ -0,0 +1,218 @@ +package spr + +import ( + "fmt" + "github.com/sfomuseum/go-edtf" + "github.com/whosonfirst/go-whosonfirst-feature/geometry" + "github.com/whosonfirst/go-whosonfirst-feature/properties" + "github.com/whosonfirst/go-whosonfirst-flags" + "github.com/whosonfirst/go-whosonfirst-uri" + "strconv" + "strings" +) + +// WOFStandardPlacesResult is a struct that implements the `StandardPlacesResult` for +// Who's On First GeoJSON Feature alternate geometry records. +type WOFAltStandardPlacesResult struct { + StandardPlacesResult `json:",omitempty"` + WOFId string `json:"wof:id"` + WOFName string `json:"wof:name"` + WOFPlacetype string `json:"wof:placetype"` + MZLatitude float64 `json:"mz:latitude"` + MZLongitude float64 `json:"mz:longitude"` + MZMinLatitude float64 `json:"mz:min_latitude"` + MZMinLongitude float64 `json:"mz:min_longitude"` + MZMaxLatitude float64 `json:"mz:max_latitude"` + MZMaxLongitude float64 `json:"mz:max_longitude"` + WOFPath string `json:"wof:path"` + WOFRepo string `json:"wof:repo"` +} + +// WhosOnFirstAltSPR will derive a new `WOFStandardPlacesResult` instance from 'f'. +func WhosOnFirstAltSPR(f []byte) (StandardPlacesResult, error) { + + id, err := properties.Id(f) + + if err != nil { + return nil, fmt.Errorf("Failed to derive ID, %w", err) + } + + source, err := properties.Source(f) + + if err != nil { + return nil, fmt.Errorf("Failed to derive source, %w", err) + } + + name := fmt.Sprintf("%d alt geometry (%s)", id, source) + + alt_label, err := properties.AltLabel(f) + + if err != nil { + return nil, fmt.Errorf("Failed to derive alt label, %w", err) + } + + label_parts := strings.Split(alt_label, "-") + + if len(label_parts) == 0 { + return nil, fmt.Errorf("Invalid src:alt_label property") + } + + alt_geom := &uri.AltGeom{ + Source: label_parts[0], + } + + if len(label_parts) >= 2 { + alt_geom.Function = label_parts[1] + } + + if len(label_parts) >= 3 { + alt_geom.Extras = label_parts[2:] + } + + uri_args := &uri.URIArgs{ + IsAlternate: true, + AltGeom: alt_geom, + } + + rel_path, err := uri.Id2RelPath(id, uri_args) + + if err != nil { + return nil, fmt.Errorf("Failed to derive path for %d, %w", id, err) + } + + repo, err := properties.Repo(f) + + if err != nil { + return nil, fmt.Errorf("Failed to derive repo, %w", err) + } + + geojson_geom, err := geometry.Geometry(f) + + if err != nil { + return nil, err + } + + orb_geom := geojson_geom.Geometry() + mbr := orb_geom.Bound() + + lat := mbr.Min.Y() + ((mbr.Max.Y() - mbr.Min.Y()) / 2.0) + lon := mbr.Min.X() + ((mbr.Max.X() - mbr.Min.X()) / 2.0) + + str_id := strconv.FormatInt(id, 10) + + spr := WOFAltStandardPlacesResult{ + WOFId: str_id, + WOFPlacetype: "alt", + WOFName: name, + MZLatitude: lat, + MZLongitude: lon, + MZMinLatitude: mbr.Min.Y(), + MZMinLongitude: mbr.Min.X(), + MZMaxLatitude: mbr.Max.Y(), + MZMaxLongitude: mbr.Max.X(), + WOFPath: rel_path, + WOFRepo: repo, + } + + return &spr, nil +} + +func (spr *WOFAltStandardPlacesResult) Id() string { + return spr.WOFId +} + +func (spr *WOFAltStandardPlacesResult) ParentId() string { + return "-1" +} + +func (spr *WOFAltStandardPlacesResult) Name() string { + return spr.WOFName +} + +func (spr *WOFAltStandardPlacesResult) Placetype() string { + return spr.WOFPlacetype +} + +func (spr *WOFAltStandardPlacesResult) Country() string { + return "XX" +} + +func (spr *WOFAltStandardPlacesResult) Repo() string { + return spr.WOFRepo +} + +func (spr *WOFAltStandardPlacesResult) Path() string { + return spr.WOFPath +} + +func (spr *WOFAltStandardPlacesResult) URI() string { + return "" +} + +func (spr *WOFAltStandardPlacesResult) Latitude() float64 { + return spr.MZLatitude +} + +func (spr *WOFAltStandardPlacesResult) Longitude() float64 { + return spr.MZLongitude +} + +func (spr *WOFAltStandardPlacesResult) MinLatitude() float64 { + return spr.MZMinLatitude +} + +func (spr *WOFAltStandardPlacesResult) MinLongitude() float64 { + return spr.MZMinLongitude +} + +func (spr *WOFAltStandardPlacesResult) MaxLatitude() float64 { + return spr.MZLatitude +} + +func (spr *WOFAltStandardPlacesResult) MaxLongitude() float64 { + return spr.MZMaxLongitude +} + +func (spr *WOFAltStandardPlacesResult) Inception() *edtf.EDTFDate { + return nil +} + +func (spr *WOFAltStandardPlacesResult) Cessation() *edtf.EDTFDate { + return nil +} + +func (spr *WOFAltStandardPlacesResult) IsCurrent() flags.ExistentialFlag { + return existentialFlag(-1) +} + +func (spr *WOFAltStandardPlacesResult) IsCeased() flags.ExistentialFlag { + return existentialFlag(-1) +} + +func (spr *WOFAltStandardPlacesResult) IsDeprecated() flags.ExistentialFlag { + return existentialFlag(-1) +} + +func (spr *WOFAltStandardPlacesResult) IsSuperseded() flags.ExistentialFlag { + return existentialFlag(-1) +} + +func (spr *WOFAltStandardPlacesResult) IsSuperseding() flags.ExistentialFlag { + return existentialFlag(-1) +} + +func (spr *WOFAltStandardPlacesResult) SupersededBy() []int64 { + return []int64{} +} + +func (spr *WOFAltStandardPlacesResult) Supersedes() []int64 { + return []int64{} +} + +func (spr *WOFAltStandardPlacesResult) BelongsTo() []int64 { + return []int64{} +} + +func (spr *WOFAltStandardPlacesResult) LastModified() int64 { + return -1 +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-uri/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-uri/go.mod index 506e405..dfcc30a 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-uri/go.mod +++ b/vendor/github.com/whosonfirst/go-whosonfirst-uri/go.mod @@ -1,5 +1,5 @@ module github.com/whosonfirst/go-whosonfirst-uri -require github.com/whosonfirst/go-whosonfirst-sources v0.1.0 +go 1.13 -go 1.12 +require github.com/whosonfirst/go-whosonfirst-sources v0.1.0 diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-uri/parse.go b/vendor/github.com/whosonfirst/go-whosonfirst-uri/parse.go index baaddfc..6b2303d 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-uri/parse.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-uri/parse.go @@ -1,7 +1,7 @@ package uri import ( - "errors" + "fmt" _ "log" "path/filepath" "regexp" @@ -19,13 +19,25 @@ func init() { re_uri = regexp.MustCompile(URI_REGEXP) } +// IsAlternateGeometry returns a boolean value indicating whether 'path' is considered by an alternate geometry URI. +func IsAlternateGeometry(path string) (bool, error) { + + _, uri_args, err := ParseURI(path) + + if err != nil { + return false, fmt.Errorf("Failed to parse '%s', %w", path, err) + } + + return uri_args.IsAlternate, nil +} + // ParseURI will parse a Who's On First URI into its unique ID and any optional "alternate" geometry information. func ParseURI(path string) (int64, *URIArgs, error) { abs_path, err := filepath.Abs(path) if err != nil { - return -1, nil, err + return -1, nil, fmt.Errorf("Failed to derive absolute path for %s, %w", path, err) } fname := filepath.Base(abs_path) @@ -35,11 +47,11 @@ func ParseURI(path string) (int64, *URIArgs, error) { // log.Println(fname, match) if len(match) == 0 { - return -1, nil, errors.New("Unable to parse WOF ID") + return -1, nil, fmt.Errorf("Unable to parse WOF ID for %s", path) } if len(match) < 2 { - return -1, nil, errors.New("Unable to parse WOF ID") + return -1, nil, fmt.Errorf("Unable to parse WOF ID for %s", path) } str_id := match[1] @@ -48,7 +60,7 @@ func ParseURI(path string) (int64, *URIArgs, error) { wofid, err := strconv.ParseInt(str_id, 10, 64) if err != nil { - return -1, nil, err + return -1, nil, fmt.Errorf("Failed to parse %s, %w", str_id, err) } args := &URIArgs{ @@ -117,11 +129,11 @@ func AltGeomFromPath(path string) (*AltGeom, error) { _, uri_args, err := ParseURI(path) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse URI, %w", err) } if !uri_args.IsAlternate { - return nil, errors.New("Not an alternate geometry") + return nil, fmt.Errorf("%s is not an alternate geometry", path) } return uri_args.AltGeom, nil @@ -131,7 +143,12 @@ func AltGeomFromPath(path string) (*AltGeom, error) { func IdFromPath(path string) (int64, error) { id, _, err := ParseURI(path) - return id, err + + if err != nil { + return 0, fmt.Errorf("Failed to parse URI, %w", err) + } + + return id, nil } // RepoFromPath parses a path and if it is a valid whosonfirst-data Who's On First URI returns a GitHub repository name. @@ -140,7 +157,7 @@ func WhosOnFirstDataRepoFromPath(path string) (string, error) { abs_path, err := filepath.Abs(path) if err != nil { - return "", err + return "", fmt.Errorf("Failed to derive absolute path for %s, %w", path, err) } wofid, err := IdFromPath(abs_path) @@ -180,7 +197,7 @@ func WhosOnFirstDataRepoFromPath(path string) (string, error) { } if repo == "" { - return "", errors.New("Unable to determine repo from path") + return "", fmt.Errorf("Unable to determine repo from %s", path) } return repo, nil diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-uri/uri.go b/vendor/github.com/whosonfirst/go-whosonfirst-uri/uri.go index 9343688..e457941 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-uri/uri.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-uri/uri.go @@ -1,7 +1,7 @@ package uri import ( - "errors" + "fmt" "github.com/whosonfirst/go-whosonfirst-sources" _ "log" "net/url" @@ -36,7 +36,7 @@ func (a *AltGeom) String() (string, error) { source := a.Source if a.Strict && source == "" { - return "", errors.New("Missing source argument for alternate geometry") + return "", fmt.Errorf("Missing source argument for alternate geometry") } if source == "" { @@ -45,7 +45,7 @@ func (a *AltGeom) String() (string, error) { } if a.Strict && !sources.IsValidSource(source) { - return "", errors.New("Invalid or unknown source argument for alternate geometry") + return "", fmt.Errorf("Invalid or unknown source argument for alternate geometry") } parts := []string{ diff --git a/vendor/github.com/whosonfirst/go-writer/README.md b/vendor/github.com/whosonfirst/go-writer/README.md index 3b5dd6f..c6afbb6 100644 --- a/vendor/github.com/whosonfirst/go-writer/README.md +++ b/vendor/github.com/whosonfirst/go-writer/README.md @@ -1,27 +1,68 @@ # go-whosonfirst-writer -## Important +Go package that provides a common interface for writing data to multiple sources. -Work in progress. Documentation to follow +## Documentation -## Interfaces +[![Go Reference](https://pkg.go.dev/badge/github.com/whosonfirst/go-writer.svg)](https://pkg.go.dev/github.com/whosonfirst/go-writer) -### WriterInitializationFunc +## Example + +Writers are instantiated with the `writer.NewWriter` method which takes as its arguments a `context.Context` instance and a URI string. The URI's scheme represents the type of writer it implements and the remaining (URI) properties are used by that writer type to instantiate itself. For example: ``` -type WriterInitializationFunc func(ctx context.Context, uri string) (Writer, error) -``` +import ( + "context" + "github.com/whosonfirst/go-writer" + "strings" +) -### Writer +func main() { -``` -type Writer interface { - Write(context.Context, string, io.ReadSeeker) (int64, error) - Close() error - WriterURI(string) string + ctx := context.Background() + + r := strings.NewReader("Hello world") + + wr, _ := writer.NewWriter(ctx, "fs:///usr/local/example") + wr.Write(ctx, wr, "hello/world.txt", r) } ``` +_Error handling omitted for the sake of brevity._ + +## Writers + +The following writers are exported by this package. Additional writers are defined in separate [go-writer-*](https://github.com/whosonfirst/?q=go-writer-&type=all&language=&sort=) packages. + +### cwd:// + +Implements the `Writer` interface for writing documents to the current working directory. + +### fs:// + +Implements the `Writer` interface for writing documents as files on a local disk. + +### io:// + +Implements the `Writer` interface for writing documents to an `io.Writer` instance. + +### multi:// + +Implements the `Writer` interface for writing documents to multiple `Writer` instances. + +### null:// + +Implements the `Writer` interface for writing documents to nowhere. + +### repo:// + +Implements the `Writer` interface for writing documents to a Who's On First "data" directory. + +### stdout:// + +Implements the `Writer` interface for writing documents to STDOUT. + ## See also +* https://github.com/whosonfirst/?q=go-writer-&type=all&language=&sort= * https://github.com/whosonfirst/go-reader diff --git a/vendor/github.com/whosonfirst/go-writer/cwd.go b/vendor/github.com/whosonfirst/go-writer/cwd.go new file mode 100644 index 0000000..103fb30 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/cwd.go @@ -0,0 +1,76 @@ +package writer + +import ( + "context" + "fmt" + "io" + "os" +) + +// CwdWriter is a struct that implements the `Writer` interface for writing documents to the current working directory. +type CwdWriter struct { + Writer + writer Writer +} + +func init() { + + ctx := context.Background() + + schemes := []string{ + "cwd", + } + + for _, scheme := range schemes { + + err := RegisterWriter(ctx, scheme, NewCwdWriter) + + if err != nil { + panic(err) + } + } +} + +// NewCwdWriter returns a new `CwdWriter` instance for writing documents to the current working directory +// configured by 'uri' in the form of: +// +// cwd:// +// +// Technically 'uri' can also be an empty string. +func NewCwdWriter(ctx context.Context, uri string) (Writer, error) { + + cwd, err := os.Getwd() + + if err != nil { + return nil, fmt.Errorf("Failed to derive current working directory, %w", err) + } + + uri = fmt.Sprintf("fs://%s", cwd) + fs_wr, err := NewFileWriter(ctx, uri) + + if err != nil { + return nil, fmt.Errorf("Failed to create new FS writer, %w", err) + } + + wr := &CwdWriter{ + writer: fs_wr, + } + + return wr, nil +} + +// Write copies the content of 'fh' to 'path'. +func (wr *CwdWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { + + return wr.writer.Write(ctx, path, fh) +} + +// WriterURI returns the final URI for 'path' +func (wr *CwdWriter) WriterURI(ctx context.Context, path string) string { + return wr.writer.WriterURI(ctx, path) +} + +// Close closes the underlying writer mechanism. +func (wr *CwdWriter) Close(ctx context.Context) error { + return wr.writer.Close(ctx) +} diff --git a/vendor/github.com/whosonfirst/go-writer/fs.go b/vendor/github.com/whosonfirst/go-writer/fs.go index 256aedd..85cea4d 100644 --- a/vendor/github.com/whosonfirst/go-writer/fs.go +++ b/vendor/github.com/whosonfirst/go-writer/fs.go @@ -2,14 +2,16 @@ package writer import ( "context" - "errors" + "fmt" "github.com/natefinch/atomic" "io" + "math/rand" "net/url" "os" "path/filepath" ) +// FileWriter is a struct that implements the `Writer` interface for writing documents as files on a local disk. type FileWriter struct { Writer root string @@ -35,23 +37,29 @@ func init() { } } +// NewFileWriter returns a new `FileWriter` instance for writing documents as files on a local disk, +// configured by 'uri' in the form of: +// +// fs://{PATH} +// +// Where {PATH} is an absolute path to an existing directory where files will be written. func NewFileWriter(ctx context.Context, uri string) (Writer, error) { u, err := url.Parse(uri) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to parse uri, %w", err) } root := u.Path info, err := os.Stat(root) if err != nil { - return nil, err + return nil, fmt.Errorf("Failed to stat '%s', %w", root, err) } if !info.IsDir() { - return nil, errors.New("root is not a directory") + return nil, fmt.Errorf("root (%s) is not a directory", root) } // check for dir/file mode query parameters here @@ -65,62 +73,74 @@ func NewFileWriter(ctx context.Context, uri string) (Writer, error) { return wr, nil } +// Write copies the content of 'fh' to 'path', where 'path' is assumed to be relative to the root +// path defined in the constuctor. If the root directory for 'path' does not exist it will be created. func (wr *FileWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { abs_path := wr.WriterURI(ctx, path) abs_root := filepath.Dir(abs_path) - tmp_file, err := os.CreateTemp("", filepath.Base(abs_path)) + _, err := os.Stat(abs_root) + + if os.IsNotExist(err) { + + err = os.MkdirAll(abs_root, wr.dir_mode) + + if err != nil { + return 0, fmt.Errorf("Failed to create %s, %w", abs_root, err) + } + } + + // So this... we can't do this because of cross-device (filesystem) limitations + // under Unix. That is /tmp may be on a different filesystem than abs_path + // tmp_file, err := os.CreateTemp("", filepath.Base(abs_path)) + // tmp_path := tmp_file.Name() + + tmp_suffix := fmt.Sprintf("tmp%d", rand.Int63()) + tmp_path := fmt.Sprintf("%s.%s", abs_path, tmp_suffix) + + tmp_file, err := os.OpenFile(tmp_path, os.O_RDWR|os.O_CREATE, 0600) if err != nil { - return 0, err + return 0, fmt.Errorf("Failed to open temp file (%s), %w", tmp_path, err) } - tmp_path := tmp_file.Name() defer os.Remove(tmp_path) b, err := io.Copy(tmp_file, fh) if err != nil { - return 0, err + return 0, fmt.Errorf("Failed to copy data to temp file (%s), %w", tmp_path, err) } err = tmp_file.Close() if err != nil { - return 0, err + return 0, fmt.Errorf("Failed to close temp file (%s), %w", tmp_path, err) } err = os.Chmod(tmp_path, wr.file_mode) if err != nil { - return 0, err - } - - _, err = os.Stat(abs_root) - - if os.IsNotExist(err) { - - err = os.MkdirAll(abs_root, wr.dir_mode) - - if err != nil { - return 0, err - } + return 0, fmt.Errorf("Failed to assign permissions for temp file (%s), %w", tmp_path, err) } err = atomic.ReplaceFile(tmp_path, abs_path) if err != nil { - return 0, err + return 0, fmt.Errorf("Failed to install final file (%s) from temp file (%s), %w", abs_path, tmp_path, err) } return b, nil } +// WriterURI returns the absolute URL for 'path' relative to the root directory defined +// in the `FileWriter` constuctor. func (wr *FileWriter) WriterURI(ctx context.Context, path string) string { return filepath.Join(wr.root, path) } +// Close closes the underlying writer mechanism. func (wr *FileWriter) Close(ctx context.Context) error { return nil } diff --git a/vendor/github.com/whosonfirst/go-writer/go.mod b/vendor/github.com/whosonfirst/go-writer/go.mod index b66e549..5ef8178 100644 --- a/vendor/github.com/whosonfirst/go-writer/go.mod +++ b/vendor/github.com/whosonfirst/go-writer/go.mod @@ -3,7 +3,7 @@ module github.com/whosonfirst/go-writer go 1.16 require ( - github.com/aaronland/go-roster v0.0.2 + github.com/aaronland/go-roster v1.0.0 github.com/g8rswimmer/error-chain v1.0.0 github.com/natefinch/atomic v1.0.1 ) diff --git a/vendor/github.com/whosonfirst/go-writer/go.sum b/vendor/github.com/whosonfirst/go-writer/go.sum index 7d0f513..c02258f 100644 --- a/vendor/github.com/whosonfirst/go-writer/go.sum +++ b/vendor/github.com/whosonfirst/go-writer/go.sum @@ -1,38 +1,6 @@ -github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= -github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= -github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= -github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= -github.com/facebookgo/atomicfile v0.0.0-20151019000000-2de1f203e7d5e386a6833233882782932729f27e h1:bYAD+4OJX4+LUrmLhpNFiicL4B0mnswQe5QaI6rxJ4A= -github.com/facebookgo/atomicfile v0.0.0-20151019000000-2de1f203e7d5e386a6833233882782932729f27e/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= +github.com/aaronland/go-roster v1.0.0 h1:FRDGrTqsYySKjWnAhbBGXyeGlI/o5/t9FZYCbUmyQtI= +github.com/aaronland/go-roster v1.0.0/go.mod h1:KIsYZgrJlAsyb9LsXSCvlqvbcCBVjCSqcQiZx42i9ro= github.com/g8rswimmer/error-chain v1.0.0 h1:WnwnunlvqtGPHVHmBfbmUyAgrtag8Y6nNpwLWmtSYOQ= github.com/g8rswimmer/error-chain v1.0.0/go.mod h1:XPJ/brUsL7yzc5VRlIxtf9GvoUqnOKVI9fg2MB5DWx8= -github.com/go-ini/ini v1.42.0 h1:TWr1wGj35+UiWHlBA8er89seFXxzwFn11spilrrj+38= -github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc h1:7xGrl4tTpBQu5Zjll08WupHyq+Sp0Z/adtyf1cfk3Q8= -github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= -github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09 h1:DXR0VtCesBD2ss3toN9OEeXszpQmW9dc3SvUbUfiBC0= -github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= -github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/whosonfirst/go-whosonfirst-cache v0.1.0 h1:ryWTsHj7gAEjwHC/WjsjROpFflsz3SCa7W9Qnk4EU7k= -github.com/whosonfirst/go-whosonfirst-cache v0.1.0/go.mod h1:P5Tx34j2M50qX/kTfXY516apwGzJGkFSBYQI7TGArKw= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0 h1:Wwj9z0R/ryHmPmpVm5jCbXdG4agJzKMWXDtPVReN/KA= -github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= -github.com/whosonfirst/go-whosonfirst-reader v0.0.0-20191122203133-047f20452865 h1:1GYjmjunRhDm1E4/aM/AIhjBij8C9kMqufjS1G2P0fs= -github.com/whosonfirst/go-whosonfirst-reader v0.0.0-20191122203133-047f20452865/go.mod h1:xYzBn6llLD/uS6Zhh0H4LAqddEJHXdQSUIxywTnhpOU= -github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= -github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= -github.com/whosonfirst/go-whosonfirst-uri v0.1.0 h1:JMlpam0x1hVrFBMTAPY3edIHz7azfMK8lLI2kM9BgbI= -github.com/whosonfirst/go-whosonfirst-uri v0.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/vendor/github.com/whosonfirst/go-writer/io.go b/vendor/github.com/whosonfirst/go-writer/io.go index 5ce1a2f..98823ff 100644 --- a/vendor/github.com/whosonfirst/go-writer/io.go +++ b/vendor/github.com/whosonfirst/go-writer/io.go @@ -3,11 +3,14 @@ package writer import ( "context" "errors" + "fmt" "io" ) +// IOWRITER_TARGET_KEY is the key used to store an `io.Writer` instance in a `context.Context` instance. const IOWRITER_TARGET_KEY string = "github.com/whosonfirst/go-writer#io_writer" +// IOWriter is a struct that implements the `Writer` interface for writing documents to an `io.Writer` instance. type IOWriter struct { Writer } @@ -22,37 +25,51 @@ func init() { } } +// NewIOWriter returns a new `IOWriter` instance for writing documents to the current working directory +// configured by 'uri' in the form of: +// +// io:// +// +// In order to assign the actual `io.Writer` instance to use you will need to call the `SetIOWriterWithContext` +// method and pass the resultant `context.Context` instance to the `Write` method. func NewIOWriter(ctx context.Context, uri string) (Writer, error) { - wr := &IOWriter{} return wr, nil } -func (wr *IOWriter) Write(ctx context.Context, uri string, fh io.ReadSeeker) (int64, error) { +// Write copies the content of 'fh' to 'path'. It is assumed that 'ctx' contains a valid `io.Writer` instance +// that has been assigned by the `SetIOWriterWithContext` method. +func (wr *IOWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { target, err := GetIOWriterFromContext(ctx) if err != nil { - return 0, err + return 0, fmt.Errorf("Failed to get io.Writer instance from context, %w", err) } return io.Copy(target, fh) } -func (wr *IOWriter) WriterURI(ctx context.Context, uri string) string { - return uri +// WriterURI returns the final URI for path. +func (wr *IOWriter) WriterURI(ctx context.Context, path string) string { + return path } +// Close closes the underlying writer mechanism. func (wr *IOWriter) Close(ctx context.Context) error { return nil } +// SetIOWriterWithContext returns a new `context.Context` instance with 'wr' assigned to the +// `IOWRITER_TARGET_KEY` value. func SetIOWriterWithContext(ctx context.Context, wr io.Writer) (context.Context, error) { ctx = context.WithValue(ctx, IOWRITER_TARGET_KEY, wr) return ctx, nil } +// GetIOWriterFromContext returns the `io.Writer` instance associated with the `IOWRITER_TARGET_KEY` +// value in 'ctx'. func GetIOWriterFromContext(ctx context.Context) (io.Writer, error) { v := ctx.Value(IOWRITER_TARGET_KEY) diff --git a/vendor/github.com/whosonfirst/go-writer/multi.go b/vendor/github.com/whosonfirst/go-writer/multi.go index 4217ce4..ebd63b4 100644 --- a/vendor/github.com/whosonfirst/go-writer/multi.go +++ b/vendor/github.com/whosonfirst/go-writer/multi.go @@ -7,7 +7,7 @@ import ( "io" ) -// Type MultiWriter holds mutltiple Writer instances. +// Type MultiWriter implements the `Writer` interface for writing documents to multiple `Writer` instances. type MultiWriter struct { Writer writers []Writer @@ -24,6 +24,8 @@ func NewMultiWriter(writers ...Writer) Writer { return wr } +// Write copies the contents of 'fh' to each of the writers contained by 'mw' in the order they +// were specified. func (mw *MultiWriter) Write(ctx context.Context, key string, fh io.ReadSeeker) (int64, error) { errors := make([]error, 0) @@ -57,10 +59,16 @@ func (mw *MultiWriter) Write(ctx context.Context, key string, fh io.ReadSeeker) return count, nil } +// WriteURI returns an empty string. Because 'mw' has multiple underlying `Writer` instances +// each of which specifies their own `WriteURI` methods it's either a choice of returning a +// concatenated string (with all the values) or an empty string. The decision was made to opt +// for the latter. func (mw *MultiWriter) WriterURI(ctx context.Context, key string) string { return "" } +// Closes closes each of the underlying `Writer` instances (in the order they were specified +// to the 'mw' instance). func (mw *MultiWriter) Close(ctx context.Context) error { errors := make([]error, 0) diff --git a/vendor/github.com/whosonfirst/go-writer/null.go b/vendor/github.com/whosonfirst/go-writer/null.go index cd45a45..a70fd6e 100644 --- a/vendor/github.com/whosonfirst/go-writer/null.go +++ b/vendor/github.com/whosonfirst/go-writer/null.go @@ -5,6 +5,7 @@ import ( "io" ) +// NullWriter is a struct that implements the `Writer` interface for writing documents to nowhere. type NullWriter struct { Writer } @@ -19,20 +20,29 @@ func init() { } } +// NewNullWriter returns a new `CwdWriter` instance for writing documents to nowhere configured by +// 'uri' in the form of: +// +// null:// +// +// Technically 'uri' can also be an empty string. func NewNullWriter(ctx context.Context, uri string) (Writer, error) { wr := &NullWriter{} return wr, nil } -func (wr *NullWriter) Write(ctx context.Context, uri string, fh io.ReadSeeker) (int64, error) { +// Write copies the content of 'fh' to 'path' using an `io.Discard` writer. +func (wr *NullWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { return io.Copy(io.Discard, fh) } -func (wr *NullWriter) WriterURI(ctx context.Context, uri string) string { - return uri +// WriterURI returns the value of 'path' +func (wr *NullWriter) WriterURI(ctx context.Context, path string) string { + return path } +// Close is a no-op to conform to the `Writer` instance and returns nil. func (wr *NullWriter) Close(ctx context.Context) error { return nil } diff --git a/vendor/github.com/whosonfirst/go-writer/repo.go b/vendor/github.com/whosonfirst/go-writer/repo.go new file mode 100644 index 0000000..e99617f --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/repo.go @@ -0,0 +1,37 @@ +package writer + +import ( + "context" + "fmt" + "net/url" + "path/filepath" +) + +func init() { + + ctx := context.Background() + + err := RegisterWriter(ctx, "repo", NewRepoWriter) + + if err != nil { + panic(err) + } + +} + +// NewRepoWriter is a convenience method to update 'uri' by appending a `data` +// directory to its path and changing its scheme to `fs://` before invoking +// NewWriter with the updated URI. +func NewRepoWriter(ctx context.Context, uri string) (Writer, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + root := filepath.Join(u.Path, "data") + + uri = fmt.Sprintf("fs://%s", root) + return NewWriter(ctx, uri) +} diff --git a/vendor/github.com/whosonfirst/go-writer/stdout.go b/vendor/github.com/whosonfirst/go-writer/stdout.go index 8922a4c..6f5c937 100644 --- a/vendor/github.com/whosonfirst/go-writer/stdout.go +++ b/vendor/github.com/whosonfirst/go-writer/stdout.go @@ -6,6 +6,7 @@ import ( "os" ) +// StdoutWriter is a struct that implements the `Writer` interface for writing documents to STDOUT. type StdoutWriter struct { Writer } @@ -20,20 +21,29 @@ func init() { } } +// NewStdoutWriter returns a new `CwdWriter` instance for writing documents to STDOUT configured by +// 'uri' in the form of: +// +// stdout:// +// +// Technically 'uri' can also be an empty string. func NewStdoutWriter(ctx context.Context, uri string) (Writer, error) { wr := &StdoutWriter{} return wr, nil } -func (wr *StdoutWriter) Write(ctx context.Context, uri string, fh io.ReadSeeker) (int64, error) { +// Write copies the content of 'fh' to 'path' using an `os.Stdout` writer. +func (wr *StdoutWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { return io.Copy(os.Stdout, fh) } -func (wr *StdoutWriter) WriterURI(ctx context.Context, uri string) string { - return uri +// WriterURI returns the value of 'path' +func (wr *StdoutWriter) WriterURI(ctx context.Context, path string) string { + return path } +// Close is a no-op to conform to the `Writer` instance and returns nil. func (wr *StdoutWriter) Close(ctx context.Context) error { return nil } diff --git a/vendor/github.com/whosonfirst/go-writer/writer.go b/vendor/github.com/whosonfirst/go-writer/writer.go index 9826f58..9c13938 100644 --- a/vendor/github.com/whosonfirst/go-writer/writer.go +++ b/vendor/github.com/whosonfirst/go-writer/writer.go @@ -12,40 +12,23 @@ import ( var writer_roster roster.Roster +// WriterInitializationFunc is a function defined by individual writer package and used to create +// an instance of that writer type WriterInitializationFunc func(ctx context.Context, uri string) (Writer, error) +// Writer is an interface for writing data to multiple sources or targets. type Writer interface { + // Writer copies the contents of an `io.ReadSeeker` instance to a relative path. + // The absolute path for the file is determined by the instance implementing the `Writer` interface. Write(context.Context, string, io.ReadSeeker) (int64, error) + // WriterURI returns the absolute URI for an instance implementing the `Writer` interface. WriterURI(context.Context, string) string + // Close closes any underlying writing mechnisms for an instance implementing the `Writer` interface. Close(context.Context) error } -func NewService(ctx context.Context, uri string) (Writer, error) { - - err := ensureWriterRoster() - - if err != nil { - return nil, err - } - - parsed, err := url.Parse(uri) - - if err != nil { - return nil, err - } - - scheme := parsed.Scheme - - i, err := writer_roster.Driver(ctx, scheme) - - if err != nil { - return nil, err - } - - init_func := i.(WriterInitializationFunc) - return init_func(ctx, uri) -} - +// RegisterWriter registers 'scheme' as a key pointing to 'init_func' in an internal lookup table +// used to create new `Writer` instances by the `NewWriter` method. func RegisterWriter(ctx context.Context, scheme string, init_func WriterInitializationFunc) error { err := ensureWriterRoster() @@ -73,6 +56,10 @@ func ensureWriterRoster() error { return nil } +// NewWriter returns a new `Writer` instance configured by 'uri'. The value of 'uri' is parsed +// as a `url.URL` and its scheme is used as the key for a corresponding `WriterInitializationFunc` +// function used to instantiate the new `Writer`. It is assumed that the scheme (and initialization +// function) have been registered by the `RegisterWriter` method. func NewWriter(ctx context.Context, uri string) (Writer, error) { u, err := url.Parse(uri) @@ -93,11 +80,7 @@ func NewWriter(ctx context.Context, uri string) (Writer, error) { return init_func(ctx, uri) } -func Writers() []string { - ctx := context.Background() - return writer_roster.Drivers(ctx) -} - +// Schemes returns the list of schemes that have been registered. func Schemes() []string { ctx := context.Background() diff --git a/vendor/modules.txt b/vendor/modules.txt index 49c6b0a..641dd88 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,6 +1,6 @@ -# github.com/aaronland/go-json-query v0.1.0 +# github.com/aaronland/go-json-query v0.1.2 github.com/aaronland/go-json-query -# github.com/aaronland/go-roster v0.0.2 +# github.com/aaronland/go-roster v1.0.0 github.com/aaronland/go-roster # github.com/dhconnelly/rtreego v1.1.0 ## explicit @@ -20,13 +20,13 @@ github.com/natefinch/atomic github.com/patrickmn/go-cache # github.com/paulmach/go.geojson v1.4.0 github.com/paulmach/go.geojson -# github.com/paulmach/orb v0.2.2 +# github.com/paulmach/orb v0.7.1 ## explicit github.com/paulmach/orb github.com/paulmach/orb/geojson github.com/paulmach/orb/internal/length github.com/paulmach/orb/planar -# github.com/sfomuseum/go-edtf v0.3.0 +# github.com/sfomuseum/go-edtf v1.1.1 github.com/sfomuseum/go-edtf github.com/sfomuseum/go-edtf/calendar github.com/sfomuseum/go-edtf/common @@ -36,42 +36,42 @@ github.com/sfomuseum/go-edtf/level2 github.com/sfomuseum/go-edtf/parser github.com/sfomuseum/go-edtf/re github.com/sfomuseum/go-edtf/tests -# github.com/sfomuseum/go-flags v0.8.2 +# github.com/sfomuseum/go-flags v0.8.3 ## explicit github.com/sfomuseum/go-flags/flagset github.com/sfomuseum/go-flags/lookup github.com/sfomuseum/go-flags/multi # github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 github.com/skelterjohn/geom -# github.com/tidwall/gjson v1.9.2 +# github.com/tidwall/gjson v1.14.2 github.com/tidwall/gjson -# github.com/tidwall/match v1.1.0 +# github.com/tidwall/match v1.1.1 github.com/tidwall/match # github.com/tidwall/pretty v1.2.0 github.com/tidwall/pretty -# github.com/tidwall/sjson v1.2.2 +# github.com/tidwall/sjson v1.2.5 github.com/tidwall/sjson -# github.com/whosonfirst/go-ioutil v1.0.0 +# github.com/whosonfirst/go-ioutil v1.0.2 ## explicit github.com/whosonfirst/go-ioutil -# github.com/whosonfirst/go-reader v0.9.0 +# github.com/whosonfirst/go-reader v1.0.1 github.com/whosonfirst/go-reader # github.com/whosonfirst/go-sanitize v0.1.0 github.com/whosonfirst/go-sanitize # github.com/whosonfirst/go-whosonfirst-crawl v0.2.1 github.com/whosonfirst/go-whosonfirst-crawl -# github.com/whosonfirst/go-whosonfirst-feature v0.0.12 +# github.com/whosonfirst/go-whosonfirst-feature v0.0.24 ## explicit github.com/whosonfirst/go-whosonfirst-feature/alt github.com/whosonfirst/go-whosonfirst-feature/geometry github.com/whosonfirst/go-whosonfirst-feature/properties -# github.com/whosonfirst/go-whosonfirst-flags v0.4.3 +# github.com/whosonfirst/go-whosonfirst-flags v0.4.4 github.com/whosonfirst/go-whosonfirst-flags github.com/whosonfirst/go-whosonfirst-flags/date github.com/whosonfirst/go-whosonfirst-flags/existential github.com/whosonfirst/go-whosonfirst-flags/geometry github.com/whosonfirst/go-whosonfirst-flags/placetypes -# github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3 +# github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.4 ## explicit github.com/whosonfirst/go-whosonfirst-geojson-v2 github.com/whosonfirst/go-whosonfirst-geojson-v2/feature @@ -81,7 +81,7 @@ github.com/whosonfirst/go-whosonfirst-geojson-v2/properties/whosonfirst github.com/whosonfirst/go-whosonfirst-geojson-v2/utils # github.com/whosonfirst/go-whosonfirst-hash v0.1.0 github.com/whosonfirst/go-whosonfirst-hash -# github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0 +# github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.1.0 github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter github.com/whosonfirst/go-whosonfirst-iterate/v2/filters github.com/whosonfirst/go-whosonfirst-iterate/v2/iterator @@ -91,7 +91,7 @@ github.com/whosonfirst/go-whosonfirst-placetypes/placetypes # github.com/whosonfirst/go-whosonfirst-sources v0.1.0 github.com/whosonfirst/go-whosonfirst-sources github.com/whosonfirst/go-whosonfirst-sources/sources -# github.com/whosonfirst/go-whosonfirst-spatial v0.3.1 +# github.com/whosonfirst/go-whosonfirst-spatial v0.3.5 ## explicit github.com/whosonfirst/go-whosonfirst-spatial github.com/whosonfirst/go-whosonfirst-spatial/database @@ -99,13 +99,13 @@ github.com/whosonfirst/go-whosonfirst-spatial/filter github.com/whosonfirst/go-whosonfirst-spatial/flags github.com/whosonfirst/go-whosonfirst-spatial/geo github.com/whosonfirst/go-whosonfirst-spatial/timer -# github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 +# github.com/whosonfirst/go-whosonfirst-spr/v2 v2.2.1 ## explicit github.com/whosonfirst/go-whosonfirst-spr/v2 -# github.com/whosonfirst/go-whosonfirst-uri v1.1.0 +# github.com/whosonfirst/go-whosonfirst-uri v1.2.0 ## explicit github.com/whosonfirst/go-whosonfirst-uri -# github.com/whosonfirst/go-writer v0.6.0 +# github.com/whosonfirst/go-writer v1.0.1 github.com/whosonfirst/go-writer # github.com/whosonfirst/walk v0.0.1 github.com/whosonfirst/walk