diff options
author | ale <ale@incal.net> | 2019-11-13 19:55:27 +0000 |
---|---|---|
committer | ale <ale@incal.net> | 2019-11-13 19:55:27 +0000 |
commit | f4455ea67f8d669702b91b19b2b6afbdaa828b39 (patch) | |
tree | af5d20926ccbc1515a2c6c3bd87abd019da87761 /vendor/github.com | |
parent | a67708b7af20483dafc126ea85e6a7eeec965776 (diff) | |
download | crawl-f4455ea67f8d669702b91b19b2b6afbdaa828b39.tar.gz crawl-f4455ea67f8d669702b91b19b2b6afbdaa828b39.zip |
Update dependencies (legacy and go.mod)
Diffstat (limited to 'vendor/github.com')
37 files changed, 1946 insertions, 754 deletions
diff --git a/vendor/github.com/PuerkitoBio/goquery/README.md b/vendor/github.com/PuerkitoBio/goquery/README.md index 84f9af3..c9db736 100644 --- a/vendor/github.com/PuerkitoBio/goquery/README.md +++ b/vendor/github.com/PuerkitoBio/goquery/README.md @@ -138,9 +138,11 @@ func main() { - [Goq][goq], an HTML deserialization and scraping library based on goquery and struct tags. - [andybalholm/cascadia][cascadia], the CSS selector library used by goquery. - [suntong/cascadia][cascadiacli], a command-line interface to the cascadia CSS selector library, useful to test selectors. -- [asciimoo/colly](https://github.com/asciimoo/colly), a lightning fast and elegant Scraping Framework +- [gocolly/colly](https://github.com/gocolly/colly), a lightning fast and elegant Scraping Framework - [gnulnx/goperf](https://github.com/gnulnx/goperf), a website performance test tool that also fetches static assets. - [MontFerret/ferret](https://github.com/MontFerret/ferret), declarative web scraping. +- [tacusci/berrycms](https://github.com/tacusci/berrycms), a modern simple to use CMS with easy to write plugins +- [Dataflow kit](https://github.com/slotix/dataflowkit), Web Scraping framework for Gophers. ## Support diff --git a/vendor/github.com/andybalholm/cascadia/parser.go b/vendor/github.com/andybalholm/cascadia/parser.go index 495db9c..bebf0af 100644 --- a/vendor/github.com/andybalholm/cascadia/parser.go +++ b/vendor/github.com/andybalholm/cascadia/parser.go @@ -7,14 +7,16 @@ import ( "regexp" "strconv" "strings" - - "golang.org/x/net/html" ) // a parser for CSS selectors type parser struct { s string // the source text i int // the current position + + // if `false`, parsing a pseudo-element + // returns an error. + acceptPseudoElements bool } // parseEscape parses a backslash escape. @@ -56,6 +58,26 @@ func (p *parser) parseEscape() (result string, err error) { return result, nil } +// toLowerASCII returns s with all ASCII capital letters lowercased. +func toLowerASCII(s string) string { + var b []byte + for i := 0; i < len(s); i++ { + if c := s[i]; 'A' <= c && c <= 'Z' { + if b == nil { + b = make([]byte, len(s)) + copy(b, s) + } + b[i] = s[i] + ('a' - 'A') + } + } + + if b == nil { + return s + } + + return string(b) +} + func hexDigit(c byte) bool { return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' } @@ -280,92 +302,92 @@ func (p *parser) consumeClosingParenthesis() bool { } // parseTypeSelector parses a type selector (one that matches by tag name). -func (p *parser) parseTypeSelector() (result Selector, err error) { +func (p *parser) parseTypeSelector() (result tagSelector, err error) { tag, err := p.parseIdentifier() if err != nil { - return nil, err + return } - - return typeSelector(tag), nil + return tagSelector{tag: toLowerASCII(tag)}, nil } // parseIDSelector parses a selector that matches by id attribute. -func (p *parser) parseIDSelector() (Selector, error) { +func (p *parser) parseIDSelector() (idSelector, error) { if p.i >= len(p.s) { - return nil, fmt.Errorf("expected id selector (#id), found EOF instead") + return idSelector{}, fmt.Errorf("expected id selector (#id), found EOF instead") } if p.s[p.i] != '#' { - return nil, fmt.Errorf("expected id selector (#id), found '%c' instead", p.s[p.i]) + return idSelector{}, fmt.Errorf("expected id selector (#id), found '%c' instead", p.s[p.i]) } p.i++ id, err := p.parseName() if err != nil { - return nil, err + return idSelector{}, err } - return attributeEqualsSelector("id", id), nil + return idSelector{id: id}, nil } // parseClassSelector parses a selector that matches by class attribute. -func (p *parser) parseClassSelector() (Selector, error) { +func (p *parser) parseClassSelector() (classSelector, error) { if p.i >= len(p.s) { - return nil, fmt.Errorf("expected class selector (.class), found EOF instead") + return classSelector{}, fmt.Errorf("expected class selector (.class), found EOF instead") } if p.s[p.i] != '.' { - return nil, fmt.Errorf("expected class selector (.class), found '%c' instead", p.s[p.i]) + return classSelector{}, fmt.Errorf("expected class selector (.class), found '%c' instead", p.s[p.i]) } p.i++ class, err := p.parseIdentifier() if err != nil { - return nil, err + return classSelector{}, err } - return attributeIncludesSelector("class", class), nil + return classSelector{class: class}, nil } // parseAttributeSelector parses a selector that matches by attribute value. -func (p *parser) parseAttributeSelector() (Selector, error) { +func (p *parser) parseAttributeSelector() (attrSelector, error) { if p.i >= len(p.s) { - return nil, fmt.Errorf("expected attribute selector ([attribute]), found EOF instead") + return attrSelector{}, fmt.Errorf("expected attribute selector ([attribute]), found EOF instead") } if p.s[p.i] != '[' { - return nil, fmt.Errorf("expected attribute selector ([attribute]), found '%c' instead", p.s[p.i]) + return attrSelector{}, fmt.Errorf("expected attribute selector ([attribute]), found '%c' instead", p.s[p.i]) } p.i++ p.skipWhitespace() key, err := p.parseIdentifier() if err != nil { - return nil, err + return attrSelector{}, err } + key = toLowerASCII(key) p.skipWhitespace() if p.i >= len(p.s) { - return nil, errors.New("unexpected EOF in attribute selector") + return attrSelector{}, errors.New("unexpected EOF in attribute selector") } if p.s[p.i] == ']' { p.i++ - return attributeExistsSelector(key), nil + return attrSelector{key: key, operation: ""}, nil } if p.i+2 >= len(p.s) { - return nil, errors.New("unexpected EOF in attribute selector") + return attrSelector{}, errors.New("unexpected EOF in attribute selector") } op := p.s[p.i : p.i+2] if op[0] == '=' { op = "=" } else if op[1] != '=' { - return nil, fmt.Errorf(`expected equality operator, found "%s" instead`, op) + return attrSelector{}, fmt.Errorf(`expected equality operator, found "%s" instead`, op) } p.i += len(op) p.skipWhitespace() if p.i >= len(p.s) { - return nil, errors.New("unexpected EOF in attribute selector") + return attrSelector{}, errors.New("unexpected EOF in attribute selector") } var val string var rx *regexp.Regexp @@ -380,88 +402,84 @@ func (p *parser) parseAttributeSelector() (Selector, error) { } } if err != nil { - return nil, err + return attrSelector{}, err } p.skipWhitespace() if p.i >= len(p.s) { - return nil, errors.New("unexpected EOF in attribute selector") + return attrSelector{}, errors.New("unexpected EOF in attribute selector") } if p.s[p.i] != ']' { - return nil, fmt.Errorf("expected ']', found '%c' instead", p.s[p.i]) + return attrSelector{}, fmt.Errorf("expected ']', found '%c' instead", p.s[p.i]) } p.i++ switch op { - case "=": - return attributeEqualsSelector(key, val), nil - case "!=": - return attributeNotEqualSelector(key, val), nil - case "~=": - return attributeIncludesSelector(key, val), nil - case "|=": - return attributeDashmatchSelector(key, val), nil - case "^=": - return attributePrefixSelector(key, val), nil - case "$=": - return attributeSuffixSelector(key, val), nil - case "*=": - return attributeSubstringSelector(key, val), nil - case "#=": - return attributeRegexSelector(key, rx), nil - } - - return nil, fmt.Errorf("attribute operator %q is not supported", op) + case "=", "!=", "~=", "|=", "^=", "$=", "*=", "#=": + return attrSelector{key: key, val: val, operation: op, regexp: rx}, nil + default: + return attrSelector{}, fmt.Errorf("attribute operator %q is not supported", op) + } } var errExpectedParenthesis = errors.New("expected '(' but didn't find it") var errExpectedClosingParenthesis = errors.New("expected ')' but didn't find it") var errUnmatchedParenthesis = errors.New("unmatched '('") -// parsePseudoclassSelector parses a pseudoclass selector like :not(p). -func (p *parser) parsePseudoclassSelector() (Selector, error) { +// parsePseudoclassSelector parses a pseudoclass selector like :not(p) or a pseudo-element +// For backwards compatibility, both ':' and '::' prefix are allowed for pseudo-elements. +// https://drafts.csswg.org/selectors-3/#pseudo-elements +// Returning a nil `Sel` (and a nil `error`) means we found a pseudo-element. +func (p *parser) parsePseudoclassSelector() (out Sel, pseudoElement string, err error) { if p.i >= len(p.s) { - return nil, fmt.Errorf("expected pseudoclass selector (:pseudoclass), found EOF instead") + return nil, "", fmt.Errorf("expected pseudoclass selector (:pseudoclass), found EOF instead") } if p.s[p.i] != ':' { - return nil, fmt.Errorf("expected attribute selector (:pseudoclass), found '%c' instead", p.s[p.i]) + return nil, "", fmt.Errorf("expected attribute selector (:pseudoclass), found '%c' instead", p.s[p.i]) } p.i++ + var mustBePseudoElement bool + if p.i >= len(p.s) { + return nil, "", fmt.Errorf("got empty pseudoclass (or pseudoelement)") + } + if p.s[p.i] == ':' { // we found a pseudo-element + mustBePseudoElement = true + p.i++ + } + name, err := p.parseIdentifier() if err != nil { - return nil, err + return } name = toLowerASCII(name) + if mustBePseudoElement && (name != "after" && name != "backdrop" && name != "before" && + name != "cue" && name != "first-letter" && name != "first-line" && name != "grammar-error" && + name != "marker" && name != "placeholder" && name != "selection" && name != "spelling-error") { + return out, "", fmt.Errorf("unknown pseudoelement :%s", name) + } switch name { case "not", "has", "haschild": if !p.consumeParenthesis() { - return nil, errExpectedParenthesis + return out, "", errExpectedParenthesis } sel, parseErr := p.parseSelectorGroup() if parseErr != nil { - return nil, parseErr + return out, "", parseErr } if !p.consumeClosingParenthesis() { - return nil, errExpectedClosingParenthesis + return out, "", errExpectedClosingParenthesis } - switch name { - case "not": - return negatedSelector(sel), nil - case "has": - return hasDescendantSelector(sel), nil - case "haschild": - return hasChildSelector(sel), nil - } + out = relativePseudoClassSelector{name: name, match: sel} case "contains", "containsown": if !p.consumeParenthesis() { - return nil, errExpectedParenthesis + return out, "", errExpectedParenthesis } if p.i == len(p.s) { - return nil, errUnmatchedParenthesis + return out, "", errUnmatchedParenthesis } var val string switch p.s[p.i] { @@ -471,95 +489,75 @@ func (p *parser) parsePseudoclassSelector() (Selector, error) { val, err = p.parseIdentifier() } if err != nil { - return nil, err + return out, "", err } val = strings.ToLower(val) p.skipWhitespace() if p.i >= len(p.s) { - return nil, errors.New("unexpected EOF in pseudo selector") + return out, "", errors.New("unexpected EOF in pseudo selector") } if !p.consumeClosingParenthesis() { - return nil, errExpectedClosingParenthesis + return out, "", errExpectedClosingParenthesis } - switch name { - case "contains": - return textSubstrSelector(val), nil - case "containsown": - return ownTextSubstrSelector(val), nil - } + out = containsPseudoClassSelector{own: name == "containsown", value: val} case "matches", "matchesown": if !p.consumeParenthesis() { - return nil, errExpectedParenthesis + return out, "", errExpectedParenthesis } rx, err := p.parseRegex() if err != nil { - return nil, err + return out, "", err } if p.i >= len(p.s) { - return nil, errors.New("unexpected EOF in pseudo selector") + return out, "", errors.New("unexpected EOF in pseudo selector") } if !p.consumeClosingParenthesis() { - return nil, errExpectedClosingParenthesis + return out, "", errExpectedClosingParenthesis } - switch name { - case "matches": - return textRegexSelector(rx), nil - case "matchesown": - return ownTextRegexSelector(rx), nil - } + out = regexpPseudoClassSelector{own: name == "matchesown", regexp: rx} case "nth-child", "nth-last-child", "nth-of-type", "nth-last-of-type": if !p.consumeParenthesis() { - return nil, errExpectedParenthesis + return out, "", errExpectedParenthesis } a, b, err := p.parseNth() if err != nil { - return nil, err + return out, "", err } if !p.consumeClosingParenthesis() { - return nil, errExpectedClosingParenthesis - } - if a == 0 { - switch name { - case "nth-child": - return simpleNthChildSelector(b, false), nil - case "nth-of-type": - return simpleNthChildSelector(b, true), nil - case "nth-last-child": - return simpleNthLastChildSelector(b, false), nil - case "nth-last-of-type": - return simpleNthLastChildSelector(b, true), nil - } + return out, "", errExpectedClosingParenthesis } - return nthChildSelector(a, b, - name == "nth-last-child" || name == "nth-last-of-type", - name == "nth-of-type" || name == "nth-last-of-type"), - nil + last := name == "nth-last-child" || name == "nth-last-of-type" + ofType := name == "nth-of-type" || name == "nth-last-of-type" + out = nthPseudoClassSelector{a: a, b: b, last: last, ofType: ofType} case "first-child": - return simpleNthChildSelector(1, false), nil + out = nthPseudoClassSelector{a: 0, b: 1, ofType: false, last: false} case "last-child": - return simpleNthLastChildSelector(1, false), nil + out = nthPseudoClassSelector{a: 0, b: 1, ofType: false, last: true} case "first-of-type": - return simpleNthChildSelector(1, true), nil + out = nthPseudoClassSelector{a: 0, b: 1, ofType: true, last: false} case "last-of-type": - return simpleNthLastChildSelector(1, true), nil + out = nthPseudoClassSelector{a: 0, b: 1, ofType: true, last: true} case "only-child": - return onlyChildSelector(false), nil + out = onlyChildPseudoClassSelector{ofType: false} case "only-of-type": - return onlyChildSelector(true), nil + out = onlyChildPseudoClassSelector{ofType: true} case "input": - return inputSelector, nil + out = inputPseudoClassSelector{} case "empty": - return emptyElementSelector, nil + out = emptyElementPseudoClassSelector{} case "root": - return rootSelector, nil + out = rootPseudoClassSelector{} + case "after", "backdrop", "before", "cue", "first-letter", "first-line", "grammar-error", "marker", "placeholder", "selection", "spelling-error": + return nil, name, nil + default: + return out, "", fmt.Errorf("unknown pseudoclass or pseudoelement :%s", name) } - - return nil, fmt.Errorf("unknown pseudoclass :%s", name) + return } // parseInteger parses a decimal integer. @@ -705,8 +703,8 @@ invalid: // parseSimpleSelectorSequence parses a selector sequence that applies to // a single element. -func (p *parser) parseSimpleSelectorSequence() (Selector, error) { - var result Selector +func (p *parser) parseSimpleSelectorSequence() (Sel, error) { + var selectors []Sel if p.i >= len(p.s) { return nil, errors.New("expected selector, found EOF instead") @@ -723,13 +721,17 @@ func (p *parser) parseSimpleSelectorSequence() (Selector, error) { if err != nil { return nil, err } - result = r + selectors = append(selectors, r) } + var pseudoElement string loop: for p.i < len(p.s) { - var ns Selector - var err error + var ( + ns Sel + newPseudoElement string + err error + ) switch p.s[p.i] { case '#': ns, err = p.parseIDSelector() @@ -738,44 +740,57 @@ loop: case '[': ns, err = p.parseAttributeSelector() case ':': - ns, err = p.parsePseudoclassSelector() + ns, newPseudoElement, err = p.parsePseudoclassSelector() default: break loop } if err != nil { return nil, err } - if result == nil { - result = ns + // From https://drafts.csswg.org/selectors-3/#pseudo-elements : + // "Only one pseudo-element may appear per selector, and if present + // it must appear after the sequence of simple selectors that + // represents the subjects of the selector."" + if ns == nil { // we found a pseudo-element + if pseudoElement != "" { + return nil, fmt.Errorf("only one pseudo-element is accepted per selector, got %s and %s", pseudoElement, newPseudoElement) + } + if !p.acceptPseudoElements { + return nil, fmt.Errorf("pseudo-element %s found, but pseudo-elements support is disabled", newPseudoElement) + } + pseudoElement = newPseudoElement } else { - result = intersectionSelector(result, ns) + if pseudoElement != "" { + return nil, fmt.Errorf("pseudo-element %s must be at the end of selector", pseudoElement) + } + selectors = append(selectors, ns) } - } - if result == nil { - result = func(n *html.Node) bool { - return n.Type == html.ElementNode - } } - - return result, nil + if len(selectors) == 1 && pseudoElement == "" { // no need wrap the selectors in compoundSelector + return selectors[0], nil + } + return compoundSelector{selectors: selectors, pseudoElement: pseudoElement}, nil } // parseSelector parses a selector that may include combinators. -func (p *parser) parseSelector() (result Selector, err error) { +func (p *parser) parseSelector() (Sel, error) { p.skipWhitespace() - result, err = p.parseSimpleSelectorSequence() + result, err := p.parseSimpleSelectorSequence() if err != nil { - return + return nil, err } for { - var combinator byte + var ( + combinator byte + c Sel + ) if p.skipWhitespace() { combinator = ' ' } if p.i >= len(p.s) { - return + return result, nil } switch p.s[p.i] { @@ -785,51 +800,39 @@ func (p *parser) parseSelector() (result Selector, err error) { p.skipWhitespace() case ',', ')': // These characters can't begin a selector, but they can legally occur after one. - return + return result, nil } if combinator == 0 { - return + return result, nil } - c, err := p.parseSimpleSelectorSequence() + c, err = p.parseSimpleSelectorSequence() if err != nil { return nil, err } - - switch combinator { - case ' ': - result = descendantSelector(result, c) - case '>': - result = childSelector(result, c) - case '+': - result = siblingSelector(result, c, true) - case '~': - result = siblingSelector(result, c, false) - } + result = combinedSelector{first: result, combinator: combinator, second: c} } - - panic("unreachable") } // parseSelectorGroup parses a group of selectors, separated by commas. -func (p *parser) parseSelectorGroup() (result Selector, err error) { - result, err = p.parseSelector() +func (p *parser) parseSelectorGroup() (SelectorGroup, error) { + current, err := p.parseSelector() if err != nil { - return + return nil, err } + result := SelectorGroup{current} for p.i < len(p.s) { if p.s[p.i] != ',' { - return result, nil + break } p.i++ c, err := p.parseSelector() if err != nil { return nil, err } - result = unionSelector(result, c) + result = append(result, c) } - - return + return result, nil } diff --git a/vendor/github.com/andybalholm/cascadia/selector.go b/vendor/github.com/andybalholm/cascadia/selector.go index 9fb05cc..e2a6dc4 100644 --- a/vendor/github.com/andybalholm/cascadia/selector.go +++ b/vendor/github.com/andybalholm/cascadia/selector.go @@ -9,36 +9,60 @@ import ( "golang.org/x/net/html" ) -// the Selector type, and functions for creating them +// Matcher is the interface for basic selector functionality. +// Match returns whether a selector matches n. +type Matcher interface { + Match(n *html.Node) bool +} -// A Selector is a function which tells whether a node matches or not. -type Selector func(*html.Node) bool +// Sel is the interface for all the functionality provided by selectors. +type Sel interface { + Matcher + Specificity() Specificity -// hasChildMatch returns whether n has any child that matches a. -func hasChildMatch(n *html.Node, a Selector) bool { - for c := n.FirstChild; c != nil; c = c.NextSibling { - if a(c) { - return true - } + // Returns a CSS input compiling to this selector. + String() string + + // Returns a pseudo-element, or an empty string. + PseudoElement() string +} + +// Parse parses a selector. Use `ParseWithPseudoElement` +// if you need support for pseudo-elements. +func Parse(sel string) (Sel, error) { + p := &parser{s: sel} + compiled, err := p.parseSelector() + if err != nil { + return nil, err } - return false + + if p.i < len(sel) { + return nil, fmt.Errorf("parsing %q: %d bytes left over", sel, len(sel)-p.i) + } + + return compiled, nil } -// hasDescendantMatch performs a depth-first search of n's descendants, -// testing whether any of them match a. It returns true as soon as a match is -// found, or false if no match is found. -func hasDescendantMatch(n *html.Node, a Selector) bool { - for c := n.FirstChild; c != nil; c = c.NextSibling { - if a(c) || (c.Type == html.ElementNode && hasDescendantMatch(c, a)) { - return true - } +// ParseWithPseudoElement parses a single selector, +// with support for pseudo-element. +func ParseWithPseudoElement(sel string) (Sel, error) { + p := &parser{s: sel, acceptPseudoElements: true} + compiled, err := p.parseSelector() + if err != nil { + return nil, err } - return false + + if p.i < len(sel) { + return nil, fmt.Errorf("parsing %q: %d bytes left over", sel, len(sel)-p.i) + } + + return compiled, nil } -// Compile parses a selector and returns, if successful, a Selector object -// that can be used to match against html.Node objects. -func Compile(sel string) (Selector, error) { +// ParseGroup parses a selector, or a group of selectors separated by commas. +// Use `ParseGroupWithPseudoElements` +// if you need support for pseudo-elements. +func ParseGroup(sel string) (SelectorGroup, error) { p := &parser{s: sel} compiled, err := p.parseSelectorGroup() if err != nil { @@ -52,6 +76,39 @@ func Compile(sel string) (Selector, error) { return compiled, nil } +// ParseGroupWithPseudoElements parses a selector, or a group of selectors separated by commas. +// It supports pseudo-elements. +func ParseGroupWithPseudoElements(sel string) (SelectorGroup, error) { + p := &parser{s: sel, acceptPseudoElements: true} + compiled, err := p.parseSelectorGroup() + if err != nil { + return nil, err + } + + if p.i < len(sel) { + return nil, fmt.Errorf("parsing %q: %d bytes left over", sel, len(sel)-p.i) + } + + return compiled, nil +} + +// A Selector is a function which tells whether a node matches or not. +// +// This type is maintained for compatibility; I recommend using the newer and +// more idiomatic interfaces Sel and Matcher. +type Selector func(*html.Node) bool + +// Compile parses a selector and returns, if successful, a Selector object +// that can be used to match against html.Node objects. +func Compile(sel string) (Selector, error) { + compiled, err := ParseGroup(sel) + if err != nil { + return nil, err + } + + return Selector(compiled.Match), nil +} + // MustCompile is like Compile, but panics instead of returning an error. func MustCompile(sel string) Selector { compiled, err := Compile(sel) @@ -79,6 +136,23 @@ func (s Selector) matchAllInto(n *html.Node, storage []*html.Node) []*html.Node return storage } +func queryInto(n *html.Node, m Matcher, storage []*html.Node) []*html.Node { + for child := n.FirstChild; child != nil; child = child.NextSibling { + if m.Match(child) { + storage = append(storage, child) + } + storage = queryInto(child, m, storage) + } + + return storage +} + +// QueryAll returns a slice of all the nodes that match m, from the descendants +// of n. +func QueryAll(n *html.Node, m Matcher) []*html.Node { + return queryInto(n, m, nil) +} + // Match returns true if the node matches the selector. func (s Selector) Match(n *html.Node) bool { return s(n) @@ -99,6 +173,21 @@ func (s Selector) MatchFirst(n *html.Node) *html.Node { return nil } +// Query returns the first node that matches m, from the descendants of n. +// If none matches, it returns nil. +func Query(n *html.Node, m Matcher) *html.Node { + for c := n.FirstChild; c != nil; c = c.NextSibling { + if m.Match(c) { + return c + } + if matched := Query(c, m); matched != nil { + return matched + } + } + + return nil +} + // Filter returns the nodes in nodes that match the selector. func (s Selector) Filter(nodes []*html.Node) (result []*html.Node) { for _, n := range nodes { @@ -109,106 +198,148 @@ func (s Selector) Filter(nodes []*html.Node) (result []*html.Node) { return result } -// typeSelector returns a Selector that matches elements with a given tag name. -func typeSelector(tag string) Selector { - tag = toLowerASCII(tag) - return func(n *html.Node) bool { - return n.Type == html.ElementNode && n.Data == tag +// Filter returns the nodes that match m. +func Filter(nodes []*html.Node, m Matcher) (result []*html.Node) { + for _, n := range nodes { + if m.Match(n) { + result = append(result, n) + } } + return result } -// toLowerASCII returns s with all ASCII capital letters lowercased. -func toLowerASCII(s string) string { - var b []byte - for i := 0; i < len(s); i++ { - if c := s[i]; 'A' <= c && c <= 'Z' { - if b == nil { - b = make([]byte, len(s)) - copy(b, s) - } - b[i] = s[i] + ('a' - 'A') - } - } +type tagSelector struct { + tag string +} - if b == nil { - return s - } +// Matches elements with a given tag name. +func (t tagSelector) Match(n *html.Node) bool { + return n.Type == html.ElementNode && n.Data == t.tag +} - return string(b) +func (c tagSelector) Specificity() Specificity { + return Specificity{0, 0, 1} } -// attributeSelector returns a Selector that matches elements -// where the attribute named key satisifes the function f. -func attributeSelector(key string, f func(string) bool) Selector { - key = toLowerASCII(key) - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false - } - for _, a := range n.Attr { - if a.Key == key && f(a.Val) { - return true - } - } - return false - } +func (c tagSelector) PseudoElement() string { + return "" } -// attributeExistsSelector returns a Selector that matches elements that have -// an attribute named key. -func attributeExistsSelector(key string) Selector { - return attributeSelector(key, func(string) bool { return true }) +type classSelector struct { + class string } -// attributeEqualsSelector returns a Selector that matches elements where -// the attribute named key has the value val. -func attributeEqualsSelector(key, val string) Selector { - return attributeSelector(key, - func(s string) bool { - return s == val - }) +// Matches elements by class attribute. +func (t classSelector) Match(n *html.Node) bool { + return matchAttribute(n, "class", func(s string) bool { + return matchInclude(t.class, s) + }) +} + +func (c classSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c classSelector) PseudoElement() string { + return "" +} + +type idSelector struct { + id string +} + +// Matches elements by id attribute. +func (t idSelector) Match(n *html.Node) bool { + return matchAttribute(n, "id", func(s string) bool { + return s == t.id + }) +} + +func (c idSelector) Specificity() Specificity { + return Specificity{1, 0, 0} +} + +func (c idSelector) PseudoElement() string { + return "" +} + +type attrSelector struct { + key, val, operation string + regexp *regexp.Regexp +} + +// Matches elements by attribute value. +func (t attrSelector) Match(n *html.Node) bool { + switch t.operation { + case "": + return matchAttribute(n, t.key, func(string) bool { return true }) + case "=": + return matchAttribute(n, t.key, func(s string) bool { return s == t.val }) + case "!=": + return attributeNotEqualMatch(t.key, t.val, n) + case "~=": + // matches elements where the attribute named key is a whitespace-separated list that includes val. + return matchAttribute(n, t.key, func(s string) bool { return matchInclude(t.val, s) }) + case "|=": + return attributeDashMatch(t.key, t.val, n) + case "^=": + return attributePrefixMatch(t.key, t.val, n) + case "$=": + return attributeSuffixMatch(t.key, t.val, n) + case "*=": + return attributeSubstringMatch(t.key, t.val, n) + case "#=": + return attributeRegexMatch(t.key, t.regexp, n) + default: + panic(fmt.Sprintf("unsuported operation : %s", t.operation)) + } } -// attributeNotEqualSelector returns a Selector that matches elements where +// matches elements where the attribute named key satisifes the function f. +func matchAttribute(n *html.Node, key string, f func(string) bool) bool { + if n.Type != html.ElementNode { + return false + } + for _, a := range n.Attr { + if a.Key == key && f(a.Val) { + return true + } + } + return false +} + +// attributeNotEqualMatch matches elements where // the attribute named key does not have the value val. -func attributeNotEqualSelector(key, val string) Selector { - key = toLowerASCII(key) - return func(n *html.Node) bool { - if n.Type != html.ElementNode { +func attributeNotEqualMatch(key, val string, n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + for _, a := range n.Attr { + if a.Key == key && a.Val == val { return false } - for _, a := range n.Attr { - if a.Key == key && a.Val == val { - return false - } - } - return true } + return true } -// attributeIncludesSelector returns a Selector that matches elements where -// the attribute named key is a whitespace-separated list that includes val. -func attributeIncludesSelector(key, val string) Selector { - return attributeSelector(key, - func(s string) bool { - for s != "" { - i := strings.IndexAny(s, " \t\r\n\f") - if i == -1 { - return s == val - } - if s[:i] == val { - return true - } - s = s[i+1:] - } - return false - }) +// returns true if s is a whitespace-separated list that includes val. +func matchInclude(val, s string) bool { + for s != "" { + i := strings.IndexAny(s, " \t\r\n\f") + if i == -1 { + return s == val + } + if s[:i] == val { + return true + } + s = s[i+1:] + } + return false } -// attributeDashmatchSelector returns a Selector that matches elements where -// the attribute named key equals val or starts with val plus a hyphen. -func attributeDashmatchSelector(key, val string) Selector { - return attributeSelector(key, +// matches elements where the attribute named key equals val or starts with val plus a hyphen. +func attributeDashMatch(key, val string, n *html.Node) bool { + return matchAttribute(n, key, func(s string) bool { if s == val { return true @@ -223,10 +354,10 @@ func attributeDashmatchSelector(key, val string) Selector { }) } -// attributePrefixSelector returns a Selector that matches elements where +// attributePrefixMatch returns a Selector that matches elements where // the attribute named key starts with val. -func attributePrefixSelector(key, val string) Selector { - return attributeSelector(key, +func attributePrefixMatch(key, val string, n *html.Node) bool { + return matchAttribute(n, key, func(s string) bool { if strings.TrimSpace(s) == "" { return false @@ -235,10 +366,10 @@ func attributePrefixSelector(key, val string) Selector { }) } -// attributeSuffixSelector returns a Selector that matches elements where +// attributeSuffixMatch matches elements where // the attribute named key ends with val. -func attributeSuffixSelector(key, val string) Selector { - return attributeSelector(key, +func attributeSuffixMatch(key, val string, n *html.Node) bool { + return matchAttribute(n, key, func(s string) bool { if strings.TrimSpace(s) == "" { return false @@ -247,10 +378,10 @@ func attributeSuffixSelector(key, val string) Selector { }) } -// attributeSubstringSelector returns a Selector that matches nodes where +// attributeSubstringMatch matches nodes where // the attribute named key contains val. -func attributeSubstringSelector(key, val string) Selector { - return attributeSelector(key, +func attributeSubstringMatch(key, val string, n *html.Node) bool { + return matchAttribute(n, key, func(s string) bool { if strings.TrimSpace(s) == "" { return false @@ -259,39 +390,130 @@ func attributeSubstringSelector(key, val string) Selector { }) } -// attributeRegexSelector returns a Selector that matches nodes where +// attributeRegexMatch matches nodes where // the attribute named key matches the regular expression rx -func attributeRegexSelector(key string, rx *regexp.Regexp) Selector { - return attributeSelector(key, +func attributeRegexMatch(key string, rx *regexp.Regexp, n *html.Node) bool { + return matchAttribute(n, key, func(s string) bool { return rx.MatchString(s) }) } -// intersectionSelector returns a selector that matches nodes that match -// both a and b. -func intersectionSelector(a, b Selector) Selector { - return func(n *html.Node) bool { - return a(n) && b(n) +func (c attrSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c attrSelector) PseudoElement() string { + return "" +} + +// ---------------- Pseudo class selectors ---------------- +// we use severals concrete types of pseudo-class selectors + +type relativePseudoClassSelector struct { + name string // one of "not", "has", "haschild" + match SelectorGroup +} + +func (s relativePseudoClassSelector) Match(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + switch s.name { + case "not": + // matches elements that do not match a. + return !s.match.Match(n) + case "has": + // matches elements with any descendant that matches a. + return hasDescendantMatch(n, s.match) + case "haschild": + // matches elements with a child that matches a. + return hasChildMatch(n, s.match) + default: + panic(fmt.Sprintf("unsupported relative pseudo class selector : %s", s.name)) } } -// unionSelector returns a selector that matches elements that match -// either a or b. -func unionSelector(a, b Selector) Selector { - return func(n *html.Node) bool { - return a(n) || b(n) +// hasChildMatch returns whether n has any child that matches a. +func hasChildMatch(n *html.Node, a Matcher) bool { + for c := n.FirstChild; c != nil; c = c.NextSibling { + if a.Match(c) { + return true + } } + return false } -// negatedSelector returns a selector that matches elements that do not match a. -func negatedSelector(a Selector) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false +// hasDescendantMatch performs a depth-first search of n's descendants, +// testing whether any of them match a. It returns true as soon as a match is +// found, or false if no match is found. +func hasDescendantMatch(n *html.Node, a Matcher) bool { + for c := n.FirstChild; c != nil; c = c.NextSibling { + if a.Match(c) || (c.Type == html.ElementNode && hasDescendantMatch(c, a)) { + return true } - return !a(n) } + return false +} + +// Specificity returns the specificity of the most specific selectors +// in the pseudo-class arguments. +// See https://www.w3.org/TR/selectors/#specificity-rules +func (s relativePseudoClassSelector) Specificity() Specificity { + var max Specificity + for _, sel := range s.match { + newSpe := sel.Specificity() + if max.Less(newSpe) { + max = newSpe + } + } + return max +} + +func (c relativePseudoClassSelector) PseudoElement() string { + return "" +} + +type containsPseudoClassSelector struct { + own bool + value string +} + +func (s containsPseudoClassSelector) Match(n *html.Node) bool { + var text string + if s.own { + // matches nodes that directly contain the given text + text = strings.ToLower(nodeOwnText(n)) + } else { + // matches nodes that contain the given text. + text = strings.ToLower(nodeText(n)) + } + return strings.Contains(text, s.value) +} + +func (s containsPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c containsPseudoClassSelector) PseudoElement() string { + return "" +} + +type regexpPseudoClassSelector struct { + own bool + regexp *regexp.Regexp +} + +func (s regexpPseudoClassSelector) Match(n *html.Node) bool { + var text string + if s.own { + // matches nodes whose text directly matches the specified regular expression + text = nodeOwnText(n) + } else { + // matches nodes whose text matches the specified regular expression + text = nodeText(n) + } + return s.regexp.MatchString(text) } // writeNodeText writes the text contained in n and its descendants to b. @@ -325,221 +547,214 @@ func nodeOwnText(n *html.Node) string { return b.String() } -// textSubstrSelector returns a selector that matches nodes that -// contain the given text. -func textSubstrSelector(val string) Selector { - return func(n *html.Node) bool { - text := strings.ToLower(nodeText(n)) - return strings.Contains(text, val) - } -} - -// ownTextSubstrSelector returns a selector that matches nodes that -// directly contain the given text -func ownTextSubstrSelector(val string) Selector { - return func(n *html.Node) bool { - text := strings.ToLower(nodeOwnText(n)) - return strings.Contains(text, val) - } -} - -// textRegexSelector returns a selector that matches nodes whose text matches -// the specified regular expression -func textRegexSelector(rx *regexp.Regexp) Selector { - return func(n *html.Node) bool { - return rx.MatchString(nodeText(n)) - } +func (s regexpPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} } -// ownTextRegexSelector returns a selector that matches nodes whose text -// directly matches the specified regular expression -func ownTextRegexSelector(rx *regexp.Regexp) Selector { - return func(n *html.Node) bool { - return rx.MatchString(nodeOwnText(n)) - } +func (c regexpPseudoClassSelector) PseudoElement() string { + return "" } -// hasChildSelector returns a selector that matches elements -// with a child that matches a. -func hasChildSelector(a Selector) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false - } - return hasChildMatch(n, a) - } +type nthPseudoClassSelector struct { + a, b int + last, ofType bool } -// hasDescendantSelector returns a selector that matches elements -// with any descendant that matches a. -func hasDescendantSelector(a Selector) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false +func (s nthPseudoClassSelector) Match(n *html.Node) bool { + if s.a == 0 { + if s.last { + return simpleNthLastChildMatch(s.b, s.ofType, n) + } else { + return simpleNthChildMatch(s.b, s.ofType, n) } - return hasDescendantMatch(n, a) } + return nthChildMatch(s.a, s.b, s.last, s.ofType, n) } -// nthChildSelector returns a selector that implements :nth-child(an+b). +// nthChildMatch implements :nth-child(an+b). // If last is true, implements :nth-last-child instead. // If ofType is true, implements :nth-of-type instead. -func nthChildSelector(a, b int, last, ofType bool) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false - } +func nthChildMatch(a, b int, last, ofType bool, n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } - parent := n.Parent - if parent == nil { - return false - } + parent := n.Parent + if parent == nil { + return false + } - if parent.Type == html.DocumentNode { - return false - } + if parent.Type == html.DocumentNode { + return false + } - i := -1 - count := 0 - for c := parent.FirstChild; c != nil; c = c.NextSibling { - if (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) { - continue - } - count++ - if c == n { - i = count - if !last { - break - } - } + i := -1 + count := 0 + for c := parent.FirstChild; c != nil; c = c.NextSibling { + if (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) { + continue } - - if i == -1 { - // This shouldn't happen, since n should always be one of its parent's children. - return false + count++ + if c == n { + i = count + if !last { + break + } } + } - if last { - i = count - i + 1 - } + if i == -1 { + // This shouldn't happen, since n should always be one of its parent's children. + return false + } - i -= b - if a == 0 { - return i == 0 - } + if last { + i = count - i + 1 + } - return i%a == 0 && i/a >= 0 + i -= b + if a == 0 { + return i == 0 } + + return i%a == 0 && i/a >= 0 } -// simpleNthChildSelector returns a selector that implements :nth-child(b). +// simpleNthChildMatch implements :nth-child(b). // If ofType is true, implements :nth-of-type instead. -func simpleNthChildSelector(b int, ofType bool) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false - } +func simpleNthChildMatch(b int, ofType bool, n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } - parent := n.Parent - if parent == nil { - return false - } + parent := n.Parent + if parent == nil { + return false + } + + if parent.Type == html.DocumentNode { + return false + } - if parent.Type == html.DocumentNode { + count := 0 + for c := parent.FirstChild; c != nil; c = c.NextSibling { + if c.Type != html.ElementNode || (ofType && c.Data != n.Data) { + continue + } + count++ + if c == n { + return count == b + } + if count >= b { return false } + } + return false +} - count := 0 - for c := parent.FirstChild; c != nil; c = c.NextSibling { - if c.Type != html.ElementNode || (ofType && c.Data != n.Data) { - continue - } - count++ - if c == n { - return count == b - } - if count >= b { - return false - } - } +// simpleNthLastChildMatch implements :nth-last-child(b). +// If ofType is true, implements :nth-last-of-type instead. +func simpleNthLastChildMatch(b int, ofType bool, n *html.Node) bool { + if n.Type != html.ElementNode { return false } -} -// simpleNthLastChildSelector returns a selector that implements -// :nth-last-child(b). If ofType is true, implements :nth-last-of-type -// instead. -func simpleNthLastChildSelector(b int, ofType bool) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false - } + parent := n.Parent + if parent == nil { + return false + } - parent := n.Parent - if parent == nil { - return false - } + if parent.Type == html.DocumentNode { + return false + } - if parent.Type == html.DocumentNode { + count := 0 + for c := parent.LastChild; c != nil; c = c.PrevSibling { + if c.Type != html.ElementNode || (ofType && c.Data != n.Data) { + continue + } + count++ + if c == n { + return count == b + } + if count >= b { return false } + } + return false +} - count := 0 - for c := parent.LastChild; c != nil; c = c.PrevSibling { - if c.Type != html.ElementNode || (ofType && c.Data != n.Data) { - continue - } - count++ - if c == n { - return count == b - } - if count >= b { - return false - } - } +// Specificity for nth-child pseudo-class. +// Does not support a list of selectors +func (s nthPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c nthPseudoClassSelector) PseudoElement() string { + return "" +} + +type onlyChildPseudoClassSelector struct { + ofType bool +} + +// Match implements :only-child. +// If `ofType` is true, it implements :only-of-type instead. +func (s onlyChildPseudoClassSelector) Match(n *html.Node) bool { + if n.Type != html.ElementNode { return false } -} -// onlyChildSelector returns a selector that implements :only-child. -// If ofType is true, it implements :only-of-type instead. -func onlyChildSelector(ofType bool) Selector { - return func(n *html.Node) bool { - if n.Type != html.ElementNode { - return false - } + parent := n.Parent + if parent == nil { + return false + } - parent := n.Parent - if parent == nil { - return false - } + if parent.Type == html.DocumentNode { + return false + } - if parent.Type == html.DocumentNode { + count := 0 + for c := parent.FirstChild; c != nil; c = c.NextSibling { + if (c.Type != html.ElementNode) || (s.ofType && c.Data != n.Data) { + continue + } + count++ + if count > 1 { return false } + } - count := 0 - for c := parent.FirstChild; c != nil; c = c.NextSibling { - if (c.Type != html.ElementNode) || (ofType && c.Data != n.Data) { - continue - } - count++ - if count > 1 { - return false - } - } + return count == 1 +} - return count == 1 - } +func (s onlyChildPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} } -// inputSelector is a Selector that matches input, select, textarea and button elements. -func inputSelector(n *html.Node) bool { +func (c onlyChildPseudoClassSelector) PseudoElement() string { + return "" +} + +type inputPseudoClassSelector struct{} + +// Matches input, select, textarea and button elements. +func (s inputPseudoClassSelector) Match(n *html.Node) bool { return n.Type == html.ElementNode && (n.Data == "input" || n.Data == "select" || n.Data == "textarea" || n.Data == "button") } -// emptyElementSelector is a Selector that matches empty elements. -func emptyElementSelector(n *html.Node) bool { +func (s inputPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c inputPseudoClassSelector) PseudoElement() string { + return "" +} + +type emptyElementPseudoClassSelector struct{} + +// Matches empty elements. +func (s emptyElementPseudoClassSelector) Match(n *html.Node) bool { if n.Type != html.ElementNode { return false } @@ -554,69 +769,170 @@ func emptyElementSelector(n *html.Node) bool { return true } -// descendantSelector returns a Selector that matches an element if -// it matches d and has an ancestor that matches a. -func descendantSelector(a, d Selector) Selector { - return func(n *html.Node) bool { - if !d(n) { +func (s emptyElementPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c emptyElementPseudoClassSelector) PseudoElement() string { + return "" +} + +type rootPseudoClassSelector struct{} + +// Match implements :root +func (s rootPseudoClassSelector) Match(n *html.Node) bool { + if n.Type != html.ElementNode { + return false + } + if n.Parent == nil { + return false + } + return n.Parent.Type == html.DocumentNode +} + +func (s rootPseudoClassSelector) Specificity() Specificity { + return Specificity{0, 1, 0} +} + +func (c rootPseudoClassSelector) PseudoElement() string { + return "" +} + +type compoundSelector struct { + selectors []Sel + pseudoElement string +} + +// Matches elements if each sub-selectors matches. +func (t compoundSelector) Match(n *html.Node) bool { + if len(t.selectors) == 0 { + return n.Type == html.ElementNode + } + + for _, sel := range t.selectors { + if !sel.Match(n) { return false } + } + return true +} - for p := n.Parent; p != nil; p = p.Parent { - if a(p) { - return true - } - } +func (s compoundSelector) Specificity() Specificity { + var out Specificity + for _, sel := range s.selectors { + out = out.Add(sel.Specificity()) + } + if s.pseudoElement != "" { + // https://drafts.csswg.org/selectors-3/#specificity + out = out.Add(Specificity{0, 0, 1}) + } + return out +} - return false +func (c compoundSelector) PseudoElement() string { + return c.pseudoElement +} + +type combinedSelector struct { + first Sel + combinator byte + second Sel +} + +func (t combinedSelector) Match(n *html.Node) bool { + if t.first == nil { + return false // maybe we should panic + } + switch t.combinator { + case 0: + return t.first.Match(n) + case ' ': + return descendantMatch(t.first, t.second, n) + case '>': + return childMatch(t.first, t.second, n) + case '+': + return siblingMatch(t.first, t.second, true, n) + case '~': + return siblingMatch(t.first, t.second, false, n) + default: + panic("unknown combinator") } } -// childSelector returns a Selector that matches an element if -// it matches d and its parent matches a. -func childSelector(a, d Selector) Selector { - return func(n *html.Node) bool { - return d(n) && n.Parent != nil && a(n.Parent) +// matches an element if it matches d and has an ancestor that matches a. +func descendantMatch(a, d Matcher, n *html.Node) bool { + if !d.Match(n) { + return false } + + for p := n.Parent; p != nil; p = p.Parent { + if a.Match(p) { + return true + } + } + + return false } -// siblingSelector returns a Selector that matches an element -// if it matches s2 and in is preceded by an element that matches s1. +// matches an element if it matches d and its parent matches a. +func childMatch(a, d Matcher, n *html.Node) bool { + return d.Match(n) && n.Parent != nil && a.Match(n.Parent) +} + +// matches an element if it matches s2 and is preceded by an element that matches s1. // If adjacent is true, the sibling must be immediately before the element. -func siblingSelector(s1, s2 Selector, adjacent bool) Selector { - return func(n *html.Node) bool { - if !s2(n) { - return false - } +func siblingMatch(s1, s2 Matcher, adjacent bool, n *html.Node) bool { + if !s2.Match(n) { + return false + } - if adjacent { - for n = n.PrevSibling; n != nil; n = n.PrevSibling { - if n.Type == html.TextNode || n.Type == html.CommentNode { - continue - } - return s1(n) + if adjacent { + for n = n.PrevSibling; n != nil; n = n.PrevSibling { + if n.Type == html.TextNode || n.Type == html.CommentNode { + continue } - return false + return s1.Match(n) } + return false + } - // Walk backwards looking for element that matches s1 - for c := n.PrevSibling; c != nil; c = c.PrevSibling { - if s1(c) { - return true - } + // Walk backwards looking for element that matches s1 + for c := n.PrevSibling; c != nil; c = c.PrevSibling { + if s1.Match(c) { + return true } + } - return false + return false +} + +func (s combinedSelector) Specificity() Specificity { + spec := s.first.Specificity() + if s.second != nil { + spec = spec.Add(s.second.Specificity()) } + return spec } -// rootSelector implements :root -func rootSelector(n *html.Node) bool { - if n.Type != html.ElementNode { - return false +// on combinedSelector, a pseudo-element only makes sens on the last +// selector, although others increase specificity. +func (c combinedSelector) PseudoElement() string { + if c.second == nil { + return "" } - if n.Parent == nil { - return false + return c.second.PseudoElement() +} + +// A SelectorGroup is a list of selectors, which matches if any of the +// individual selectors matches. +type SelectorGroup []Sel + +// Match returns true if the node matches one of the single selectors. +func (s SelectorGroup) Match(n *html.Node) bool { + for _, sel := range s { + if sel.Match(n) { + return true + } } - return n.Parent.Type == html.DocumentNode + return false } diff --git a/vendor/github.com/andybalholm/cascadia/serialize.go b/vendor/github.com/andybalholm/cascadia/serialize.go new file mode 100644 index 0000000..f15b079 --- /dev/null +++ b/vendor/github.com/andybalholm/cascadia/serialize.go @@ -0,0 +1,120 @@ +package cascadia + +import ( + "fmt" + "strings" +) + +// implements the reverse operation Sel -> string + +func (c tagSelector) String() string { + return c.tag +} + +func (c idSelector) String() string { + return "#" + c.id +} + +func (c classSelector) String() string { + return "." + c.class +} + +func (c attrSelector) String() string { + val := c.val + if c.operation == "#=" { + val = c.regexp.String() + } else if c.operation != "" { + val = fmt.Sprintf(`"%s"`, val) + } + return fmt.Sprintf(`[%s%s%s]`, c.key, c.operation, val) +} + +func (c relativePseudoClassSelector) String() string { + return fmt.Sprintf(":%s(%s)", c.name, c.match.String()) +} +func (c containsPseudoClassSelector) String() string { + s := "contains" + if c.own { + s += "Own" + } + return fmt.Sprintf(`:%s("%s")`, s, c.value) +} +func (c regexpPseudoClassSelector) String() string { + s := "matches" + if c.own { + s += "Own" + } + return fmt.Sprintf(":%s(%s)", s, c.regexp.String()) +} +func (c nthPseudoClassSelector) String() string { + if c.a == 0 && c.b == 1 { // special cases + s := ":first-" + if c.last { + s = ":last-" + } + if c.ofType { + s += "of-type" + } else { + s += "child" + } + return s + } + var name string + switch [2]bool{c.last, c.ofType} { + case [2]bool{true, true}: + name = "nth-last-of-type" + case [2]bool{true, false}: + name = "nth-last-child" + case [2]bool{false, true}: + name = "nth-of-type" + case [2]bool{false, false}: + name = "nth-child" + } + return fmt.Sprintf(":%s(%dn+%d)", name, c.a, c.b) +} +func (c onlyChildPseudoClassSelector) String() string { + if c.ofType { + return ":only-of-type" + } + return ":only-child" +} +func (c inputPseudoClassSelector) String() string { + return ":input" +} +func (c emptyElementPseudoClassSelector) String() string { + return ":empty" +} +func (c rootPseudoClassSelector) String() string { + return ":root" +} + +func (c compoundSelector) String() string { + if len(c.selectors) == 0 && c.pseudoElement == "" { + return "*" + } + chunks := make([]string, len(c.selectors)) + for i, sel := range c.selectors { + chunks[i] = sel.String() + } + s := strings.Join(chunks, "") + if c.pseudoElement != "" { + s += "::" + c.pseudoElement + } + return s +} + +func (c combinedSelector) String() string { + start := c.first.String() + if c.second != nil { + start += fmt.Sprintf(" %s %s", string(c.combinator), c.second.String()) + } + return start +} + +func (c SelectorGroup) String() string { + ck := make([]string, len(c)) + for i, s := range c { + ck[i] = s.String() + } + return strings.Join(ck, ", ") +} diff --git a/vendor/github.com/andybalholm/cascadia/specificity.go b/vendor/github.com/andybalholm/cascadia/specificity.go new file mode 100644 index 0000000..8db864f --- /dev/null +++ b/vendor/github.com/andybalholm/cascadia/specificity.go @@ -0,0 +1,26 @@ +package cascadia + +// Specificity is the CSS specificity as defined in +// https://www.w3.org/TR/selectors/#specificity-rules +// with the convention Specificity = [A,B,C]. +type Specificity [3]int + +// returns `true` if s < other (strictly), false otherwise +func (s Specificity) Less(other Specificity) bool { + for i := range s { + if s[i] < other[i] { + return true + } + if s[i] > other[i] { + return false + } + } + return false +} + +func (s Specificity) Add(other Specificity) Specificity { + for i, sp := range other { + s[i] += sp + } + return s +} diff --git a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go index 59d4ee9..5f6ed93 100644 --- a/vendor/github.com/google/go-cmp/cmp/export_unsafe.go +++ b/vendor/github.com/google/go-cmp/cmp/export_unsafe.go @@ -19,5 +19,7 @@ const supportAllowUnexported = true // The parent struct, v, must be addressable, while f must be a StructField // describing the field to retrieve. func retrieveUnexportedField(v reflect.Value, f reflect.StructField) reflect.Value { - return reflect.NewAt(f.Type, unsafe.Pointer(v.UnsafeAddr()+f.Offset)).Elem() + // See https://github.com/google/go-cmp/issues/167 for discussion of the + // following expression. + return reflect.NewAt(f.Type, unsafe.Pointer(uintptr(unsafe.Pointer(v.UnsafeAddr()))+f.Offset)).Elem() } diff --git a/vendor/github.com/google/go-cmp/cmp/options.go b/vendor/github.com/google/go-cmp/cmp/options.go index 7934481..a20390d 100644 --- a/vendor/github.com/google/go-cmp/cmp/options.go +++ b/vendor/github.com/google/go-cmp/cmp/options.go @@ -226,7 +226,19 @@ func (validator) apply(s *state, vx, vy reflect.Value) { // Unable to Interface implies unexported field without visibility access. if !vx.CanInterface() || !vy.CanInterface() { const help = "consider using a custom Comparer; if you control the implementation of type, you can also consider AllowUnexported or cmpopts.IgnoreUnexported" - panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help)) + var name string + if t := s.curPath.Index(-2).Type(); t.Name() != "" { + // Named type with unexported fields. + name = fmt.Sprintf("%q.%v", t.PkgPath(), t.Name()) // e.g., "path/to/package".MyType + } else { + // Unnamed type with unexported fields. Derive PkgPath from field. + var pkgPath string + for i := 0; i < t.NumField() && pkgPath == ""; i++ { + pkgPath = t.Field(i).PkgPath + } + name = fmt.Sprintf("%q.(%v)", pkgPath, t.String()) // e.g., "path/to/package".(struct { a int }) + } + panic(fmt.Sprintf("cannot handle unexported field at %#v:\n\t%v\n%s", s.curPath, name, help)) } panic("not reachable") diff --git a/vendor/github.com/google/uuid/CONTRIBUTING.md b/vendor/github.com/google/uuid/CONTRIBUTING.md new file mode 100644 index 0000000..04fdf09 --- /dev/null +++ b/vendor/github.com/google/uuid/CONTRIBUTING.md @@ -0,0 +1,10 @@ +# How to contribute + +We definitely welcome patches and contribution to this project! + +### Legal requirements + +In order to protect both you and ourselves, you will need to sign the +[Contributor License Agreement](https://cla.developers.google.com/clas). + +You may have already signed it for other Google projects. diff --git a/vendor/github.com/google/uuid/CONTRIBUTORS b/vendor/github.com/google/uuid/CONTRIBUTORS new file mode 100644 index 0000000..b4bb97f --- /dev/null +++ b/vendor/github.com/google/uuid/CONTRIBUTORS @@ -0,0 +1,9 @@ +Paul Borman <borman@google.com> +bmatsuo +shawnps +theory +jboverfelt +dsymonds +cd1 +wallclockbuilder +dansouza diff --git a/vendor/github.com/google/uuid/LICENSE b/vendor/github.com/google/uuid/LICENSE new file mode 100644 index 0000000..5dc6826 --- /dev/null +++ b/vendor/github.com/google/uuid/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009,2014 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/google/uuid/README.md b/vendor/github.com/google/uuid/README.md new file mode 100644 index 0000000..9d92c11 --- /dev/null +++ b/vendor/github.com/google/uuid/README.md @@ -0,0 +1,19 @@ +# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master) +The uuid package generates and inspects UUIDs based on +[RFC 4122](http://tools.ietf.org/html/rfc4122) +and DCE 1.1: Authentication and Security Services. + +This package is based on the github.com/pborman/uuid package (previously named +code.google.com/p/go-uuid). It differs from these earlier packages in that +a UUID is a 16 byte array rather than a byte slice. One loss due to this +change is the ability to represent an invalid UUID (vs a NIL UUID). + +###### Install +`go get github.com/google/uuid` + +###### Documentation +[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid) + +Full `go doc` style documentation for the package can be viewed online without +installing this package by using the GoDoc site here: +http://godoc.org/github.com/google/uuid diff --git a/vendor/github.com/google/uuid/dce.go b/vendor/github.com/google/uuid/dce.go new file mode 100644 index 0000000..fa820b9 --- /dev/null +++ b/vendor/github.com/google/uuid/dce.go @@ -0,0 +1,80 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "fmt" + "os" +) + +// A Domain represents a Version 2 domain +type Domain byte + +// Domain constants for DCE Security (Version 2) UUIDs. +const ( + Person = Domain(0) + Group = Domain(1) + Org = Domain(2) +) + +// NewDCESecurity returns a DCE Security (Version 2) UUID. +// +// The domain should be one of Person, Group or Org. +// On a POSIX system the id should be the users UID for the Person +// domain and the users GID for the Group. The meaning of id for +// the domain Org or on non-POSIX systems is site defined. +// +// For a given domain/id pair the same token may be returned for up to +// 7 minutes and 10 seconds. +func NewDCESecurity(domain Domain, id uint32) (UUID, error) { + uuid, err := NewUUID() + if err == nil { + uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2 + uuid[9] = byte(domain) + binary.BigEndian.PutUint32(uuid[0:], id) + } + return uuid, err +} + +// NewDCEPerson returns a DCE Security (Version 2) UUID in the person +// domain with the id returned by os.Getuid. +// +// NewDCESecurity(Person, uint32(os.Getuid())) +func NewDCEPerson() (UUID, error) { + return NewDCESecurity(Person, uint32(os.Getuid())) +} + +// NewDCEGroup returns a DCE Security (Version 2) UUID in the group +// domain with the id returned by os.Getgid. +// +// NewDCESecurity(Group, uint32(os.Getgid())) +func NewDCEGroup() (UUID, error) { + return NewDCESecurity(Group, uint32(os.Getgid())) +} + +// Domain returns the domain for a Version 2 UUID. Domains are only defined +// for Version 2 UUIDs. +func (uuid UUID) Domain() Domain { + return Domain(uuid[9]) +} + +// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2 +// UUIDs. +func (uuid UUID) ID() uint32 { + return binary.BigEndian.Uint32(uuid[0:4]) +} + +func (d Domain) String() string { + switch d { + case Person: + return "Person" + case Group: + return "Group" + case Org: + return "Org" + } + return fmt.Sprintf("Domain%d", int(d)) +} diff --git a/vendor/github.com/google/uuid/doc.go b/vendor/github.com/google/uuid/doc.go new file mode 100644 index 0000000..5b8a4b9 --- /dev/null +++ b/vendor/github.com/google/uuid/doc.go @@ -0,0 +1,12 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package uuid generates and inspects UUIDs. +// +// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security +// Services. +// +// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to +// maps or compared directly. +package uuid diff --git a/vendor/github.com/google/uuid/go.mod b/vendor/github.com/google/uuid/go.mod new file mode 100644 index 0000000..fc84cd7 --- /dev/null +++ b/vendor/github.com/google/uuid/go.mod @@ -0,0 +1 @@ +module github.com/google/uuid diff --git a/vendor/github.com/google/uuid/hash.go b/vendor/github.com/google/uuid/hash.go new file mode 100644 index 0000000..b174616 --- /dev/null +++ b/vendor/github.com/google/uuid/hash.go @@ -0,0 +1,53 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "crypto/md5" + "crypto/sha1" + "hash" +) + +// Well known namespace IDs and UUIDs +var ( + NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) + NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) + Nil UUID // empty UUID, all zeros +) + +// NewHash returns a new UUID derived from the hash of space concatenated with +// data generated by h. The hash should be at least 16 byte in length. The +// first 16 bytes of the hash are used to form the UUID. The version of the +// UUID will be the lower 4 bits of version. NewHash is used to implement +// NewMD5 and NewSHA1. +func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID { + h.Reset() + h.Write(space[:]) + h.Write(data) + s := h.Sum(nil) + var uuid UUID + copy(uuid[:], s) + uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4) + uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant + return uuid +} + +// NewMD5 returns a new MD5 (Version 3) UUID based on the +// supplied name space and data. It is the same as calling: +// +// NewHash(md5.New(), space, data, 3) +func NewMD5(space UUID, data []byte) UUID { + return NewHash(md5.New(), space, data, 3) +} + +// NewSHA1 returns a new SHA1 (Version 5) UUID based on the +// supplied name space and data. It is the same as calling: +// +// NewHash(sha1.New(), space, data, 5) +func NewSHA1(space UUID, data []byte) UUID { + return NewHash(sha1.New(), space, data, 5) +} diff --git a/vendor/github.com/google/uuid/marshal.go b/vendor/github.com/google/uuid/marshal.go new file mode 100644 index 0000000..7f9e0c6 --- /dev/null +++ b/vendor/github.com/google/uuid/marshal.go @@ -0,0 +1,37 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "fmt" + +// MarshalText implements encoding.TextMarshaler. +func (uuid UUID) MarshalText() ([]byte, error) { + var js [36]byte + encodeHex(js[:], uuid) + return js[:], nil +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (uuid *UUID) UnmarshalText(data []byte) error { + id, err := ParseBytes(data) + if err == nil { + *uuid = id + } + return err +} + +// MarshalBinary implements encoding.BinaryMarshaler. +func (uuid UUID) MarshalBinary() ([]byte, error) { + return uuid[:], nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler. +func (uuid *UUID) UnmarshalBinary(data []byte) error { + if len(data) != 16 { + return fmt.Errorf("invalid UUID (got %d bytes)", len(data)) + } + copy(uuid[:], data) + return nil +} diff --git a/vendor/github.com/google/uuid/node.go b/vendor/github.com/google/uuid/node.go new file mode 100644 index 0000000..d651a2b --- /dev/null +++ b/vendor/github.com/google/uuid/node.go @@ -0,0 +1,90 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "sync" +) + +var ( + nodeMu sync.Mutex + ifname string // name of interface being used + nodeID [6]byte // hardware for version 1 UUIDs + zeroID [6]byte // nodeID with only 0's +) + +// NodeInterface returns the name of the interface from which the NodeID was +// derived. The interface "user" is returned if the NodeID was set by +// SetNodeID. +func NodeInterface() string { + defer nodeMu.Unlock() + nodeMu.Lock() + return ifname +} + +// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. +// If name is "" then the first usable interface found will be used or a random +// Node ID will be generated. If a named interface cannot be found then false +// is returned. +// +// SetNodeInterface never fails when name is "". +func SetNodeInterface(name string) bool { + defer nodeMu.Unlock() + nodeMu.Lock() + return setNodeInterface(name) +} + +func setNodeInterface(name string) bool { + iname, addr := getHardwareInterface(name) // null implementation for js + if iname != "" && addr != nil { + ifname = iname + copy(nodeID[:], addr) + return true + } + + // We found no interfaces with a valid hardware address. If name + // does not specify a specific interface generate a random Node ID + // (section 4.1.6) + if name == "" { + ifname = "random" + randomBits(nodeID[:]) + return true + } + return false +} + +// NodeID returns a slice of a copy of the current Node ID, setting the Node ID +// if not already set. +func NodeID() []byte { + defer nodeMu.Unlock() + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + nid := nodeID + return nid[:] +} + +// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes +// of id are used. If id is less than 6 bytes then false is returned and the +// Node ID is not set. +func SetNodeID(id []byte) bool { + if len(id) < 6 { + return false + } + defer nodeMu.Unlock() + nodeMu.Lock() + copy(nodeID[:], id) + ifname = "user" + return true +} + +// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is +// not valid. The NodeID is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) NodeID() []byte { + var node [6]byte + copy(node[:], uuid[10:]) + return node[:] +} diff --git a/vendor/github.com/pborman/uuid/node_js.go b/vendor/github.com/google/uuid/node_js.go index 24b78ed..24b78ed 100644 --- a/vendor/github.com/pborman/uuid/node_js.go +++ b/vendor/github.com/google/uuid/node_js.go diff --git a/vendor/github.com/pborman/uuid/node_net.go b/vendor/github.com/google/uuid/node_net.go index 330b544..0cbbcdd 100644 --- a/vendor/github.com/pborman/uuid/node_net.go +++ b/vendor/github.com/google/uuid/node_net.go @@ -26,10 +26,7 @@ func getHardwareInterface(name string) (string, []byte) { } for _, ifs := range interfaces { if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) { - if setNodeID(ifs.HardwareAddr) { - ifname = ifs.Name - return ifname, nodeID - } + return ifs.Name, ifs.HardwareAddr } } return "", nil diff --git a/vendor/github.com/google/uuid/sql.go b/vendor/github.com/google/uuid/sql.go new file mode 100644 index 0000000..f326b54 --- /dev/null +++ b/vendor/github.com/google/uuid/sql.go @@ -0,0 +1,59 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "database/sql/driver" + "fmt" +) + +// Scan implements sql.Scanner so UUIDs can be read from databases transparently +// Currently, database types that map to string and []byte are supported. Please +// consult database-specific driver documentation for matching types. +func (uuid *UUID) Scan(src interface{}) error { + switch src := src.(type) { + case nil: + return nil + + case string: + // if an empty UUID comes from a table, we return a null UUID + if src == "" { + return nil + } + + // see Parse for required string format + u, err := Parse(src) + if err != nil { + return fmt.Errorf("Scan: %v", err) + } + + *uuid = u + + case []byte: + // if an empty UUID comes from a table, we return a null UUID + if len(src) == 0 { + return nil + } + + // assumes a simple slice of bytes if 16 bytes + // otherwise attempts to parse + if len(src) != 16 { + return uuid.Scan(string(src)) + } + copy((*uuid)[:], src) + + default: + return fmt.Errorf("Scan: unable to scan type %T into UUID", src) + } + + return nil +} + +// Value implements sql.Valuer so that UUIDs can be written to databases +// transparently. Currently, UUIDs map to strings. Please consult +// database-specific driver documentation for matching types. +func (uuid UUID) Value() (driver.Value, error) { + return uuid.String(), nil +} diff --git a/vendor/github.com/google/uuid/time.go b/vendor/github.com/google/uuid/time.go new file mode 100644 index 0000000..e6ef06c --- /dev/null +++ b/vendor/github.com/google/uuid/time.go @@ -0,0 +1,123 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" + "sync" + "time" +) + +// A Time represents a time as the number of 100's of nanoseconds since 15 Oct +// 1582. +type Time int64 + +const ( + lillian = 2299160 // Julian day of 15 Oct 1582 + unix = 2440587 // Julian day of 1 Jan 1970 + epoch = unix - lillian // Days between epochs + g1582 = epoch * 86400 // seconds between epochs + g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs +) + +var ( + timeMu sync.Mutex + lasttime uint64 // last time we returned + clockSeq uint16 // clock sequence for this run + + timeNow = time.Now // for testing +) + +// UnixTime converts t the number of seconds and nanoseconds using the Unix +// epoch of 1 Jan 1970. +func (t Time) UnixTime() (sec, nsec int64) { + sec = int64(t - g1582ns100) + nsec = (sec % 10000000) * 100 + sec /= 10000000 + return sec, nsec +} + +// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and +// clock sequence as well as adjusting the clock sequence as needed. An error +// is returned if the current time cannot be determined. +func GetTime() (Time, uint16, error) { + defer timeMu.Unlock() + timeMu.Lock() + return getTime() +} + +func getTime() (Time, uint16, error) { + t := timeNow() + + // If we don't have a clock sequence already, set one. + if clockSeq == 0 { + setClockSequence(-1) + } + now := uint64(t.UnixNano()/100) + g1582ns100 + + // If time has gone backwards with this clock sequence then we + // increment the clock sequence + if now <= lasttime { + clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000 + } + lasttime = now + return Time(now), clockSeq, nil +} + +// ClockSequence returns the current clock sequence, generating one if not +// already set. The clock sequence is only used for Version 1 UUIDs. +// +// The uuid package does not use global static storage for the clock sequence or +// the last time a UUID was generated. Unless SetClockSequence is used, a new +// random clock sequence is generated the first time a clock sequence is +// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) +func ClockSequence() int { + defer timeMu.Unlock() + timeMu.Lock() + return clockSequence() +} + +func clockSequence() int { + if clockSeq == 0 { + setClockSequence(-1) + } + return int(clockSeq & 0x3fff) +} + +// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to +// -1 causes a new sequence to be generated. +func SetClockSequence(seq int) { + defer timeMu.Unlock() + timeMu.Lock() + setClockSequence(seq) +} + +func setClockSequence(seq int) { + if seq == -1 { + var b [2]byte + randomBits(b[:]) // clock sequence + seq = int(b[0])<<8 | int(b[1]) + } + oldSeq := clockSeq + clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant + if oldSeq != clockSeq { + lasttime = 0 + } +} + +// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in +// uuid. The time is only defined for version 1 and 2 UUIDs. +func (uuid UUID) Time() Time { + time := int64(binary.BigEndian.Uint32(uuid[0:4])) + time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32 + time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48 + return Time(time) +} + +// ClockSequence returns the clock sequence encoded in uuid. +// The clock sequence is only well defined for version 1 and 2 UUIDs. +func (uuid UUID) ClockSequence() int { + return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff +} diff --git a/vendor/github.com/google/uuid/util.go b/vendor/github.com/google/uuid/util.go new file mode 100644 index 0000000..5ea6c73 --- /dev/null +++ b/vendor/github.com/google/uuid/util.go @@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "io" +) + +// randomBits completely fills slice b with random data. +func randomBits(b []byte) { + if _, err := io.ReadFull(rander, b); err != nil { + panic(err.Error()) // rand should never fail + } +} + +// xvalues returns the value of a byte as a hexadecimal digit or 255. +var xvalues = [256]byte{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +} + +// xtob converts hex characters x1 and x2 into a byte. +func xtob(x1, x2 byte) (byte, bool) { + b1 := xvalues[x1] + b2 := xvalues[x2] + return (b1 << 4) | b2, b1 != 255 && b2 != 255 +} diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go new file mode 100644 index 0000000..524404c --- /dev/null +++ b/vendor/github.com/google/uuid/uuid.go @@ -0,0 +1,245 @@ +// Copyright 2018 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "errors" + "fmt" + "io" + "strings" +) + +// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC +// 4122. +type UUID [16]byte + +// A Version represents a UUID's version. +type Version byte + +// A Variant represents a UUID's variant. +type Variant byte + +// Constants returned by Variant. +const ( + Invalid = Variant(iota) // Invalid UUID + RFC4122 // The variant specified in RFC4122 + Reserved // Reserved, NCS backward compatibility. + Microsoft // Reserved, Microsoft Corporation backward compatibility. + Future // Reserved for future definition. +) + +var rander = rand.Reader // random function + +// Parse decodes s into a UUID or returns an error. Both the standard UUID +// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the +// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex +// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. +func Parse(s string) (UUID, error) { + var uuid UUID + switch len(s) { + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36: + + // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36 + 9: + if strings.ToLower(s[:9]) != "urn:uuid:" { + return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) + } + s = s[9:] + + // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + case 36 + 2: + s = s[1:] + + // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + case 32: + var ok bool + for i := range uuid { + uuid[i], ok = xtob(s[i*2], s[i*2+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + } + return uuid, nil + default: + return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) + } + // s is now at least 36 bytes long + // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { + return uuid, errors.New("invalid UUID format") + } + for i, x := range [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34} { + v, ok := xtob(s[x], s[x+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + uuid[i] = v + } + return uuid, nil +} + +// ParseBytes is like Parse, except it parses a byte slice instead of a string. +func ParseBytes(b []byte) (UUID, error) { + var uuid UUID + switch len(b) { + case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { + return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) + } + b = b[9:] + case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} + b = b[1:] + case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + var ok bool + for i := 0; i < 32; i += 2 { + uuid[i/2], ok = xtob(b[i], b[i+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + } + return uuid, nil + default: + return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) + } + // s is now at least 36 bytes long + // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { + return uuid, errors.New("invalid UUID format") + } + for i, x := range [16]int{ + 0, 2, 4, 6, + 9, 11, + 14, 16, + 19, 21, + 24, 26, 28, 30, 32, 34} { + v, ok := xtob(b[x], b[x+1]) + if !ok { + return uuid, errors.New("invalid UUID format") + } + uuid[i] = v + } + return uuid, nil +} + +// MustParse is like Parse but panics if the string cannot be parsed. +// It simplifies safe initialization of global variables holding compiled UUIDs. +func MustParse(s string) UUID { + uuid, err := Parse(s) + if err != nil { + panic(`uuid: Parse(` + s + `): ` + err.Error()) + } + return uuid +} + +// FromBytes creates a new UUID from a byte slice. Returns an error if the slice +// does not have a length of 16. The bytes are copied from the slice. +func FromBytes(b []byte) (uuid UUID, err error) { + err = uuid.UnmarshalBinary(b) + return uuid, err +} + +// Must returns uuid if err is nil and panics otherwise. +func Must(uuid UUID, err error) UUID { + if err != nil { + panic(err) + } + return uuid +} + +// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +// , or "" if uuid is invalid. +func (uuid UUID) String() string { + var buf [36]byte + encodeHex(buf[:], uuid) + return string(buf[:]) +} + +// URN returns the RFC 2141 URN form of uuid, +// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid. +func (uuid UUID) URN() string { + var buf [36 + 9]byte + copy(buf[:], "urn:uuid:") + encodeHex(buf[9:], uuid) + return string(buf[:]) +} + +func encodeHex(dst []byte, uuid UUID) { + hex.Encode(dst, uuid[:4]) + dst[8] = '-' + hex.Encode(dst[9:13], uuid[4:6]) + dst[13] = '-' + hex.Encode(dst[14:18], uuid[6:8]) + dst[18] = '-' + hex.Encode(dst[19:23], uuid[8:10]) + dst[23] = '-' + hex.Encode(dst[24:], uuid[10:]) +} + +// Variant returns the variant encoded in uuid. +func (uuid UUID) Variant() Variant { + switch { + case (uuid[8] & 0xc0) == 0x80: + return RFC4122 + case (uuid[8] & 0xe0) == 0xc0: + return Microsoft + case (uuid[8] & 0xe0) == 0xe0: + return Future + default: + return Reserved + } +} + +// Version returns the version of uuid. +func (uuid UUID) Version() Version { + return Version(uuid[6] >> 4) +} + +func (v Version) String() string { + if v > 15 { + return fmt.Sprintf("BAD_VERSION_%d", v) + } + return fmt.Sprintf("VERSION_%d", v) +} + +func (v Variant) String() string { + switch v { + case RFC4122: + return "RFC4122" + case Reserved: + return "Reserved" + case Microsoft: + return "Microsoft" + case Future: + return "Future" + case Invalid: + return "Invalid" + } + return fmt.Sprintf("BadVariant%d", int(v)) +} + +// SetRand sets the random number generator to r, which implements io.Reader. +// If r.Read returns an error when the package requests random data then +// a panic will be issued. +// +// Calling SetRand with nil sets the random number generator to the default +// generator. +func SetRand(r io.Reader) { + if r == nil { + rander = rand.Reader + return + } + rander = r +} diff --git a/vendor/github.com/google/uuid/version1.go b/vendor/github.com/google/uuid/version1.go new file mode 100644 index 0000000..199a1ac --- /dev/null +++ b/vendor/github.com/google/uuid/version1.go @@ -0,0 +1,44 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import ( + "encoding/binary" +) + +// NewUUID returns a Version 1 UUID based on the current NodeID and clock +// sequence, and the current time. If the NodeID has not been set by SetNodeID +// or SetNodeInterface then it will be set automatically. If the NodeID cannot +// be set NewUUID returns nil. If clock sequence has not been set by +// SetClockSequence then it will be set automatically. If GetTime fails to +// return the current NewUUID returns nil and an error. +// +// In most cases, New should be used. +func NewUUID() (UUID, error) { + nodeMu.Lock() + if nodeID == zeroID { + setNodeInterface("") + } + nodeMu.Unlock() + + var uuid UUID + now, seq, err := GetTime() + if err != nil { + return uuid, err + } + + timeLow := uint32(now & 0xffffffff) + timeMid := uint16((now >> 32) & 0xffff) + timeHi := uint16((now >> 48) & 0x0fff) + timeHi |= 0x1000 // Version 1 + + binary.BigEndian.PutUint32(uuid[0:], timeLow) + binary.BigEndian.PutUint16(uuid[4:], timeMid) + binary.BigEndian.PutUint16(uuid[6:], timeHi) + binary.BigEndian.PutUint16(uuid[8:], seq) + copy(uuid[10:], nodeID[:]) + + return uuid, nil +} diff --git a/vendor/github.com/google/uuid/version4.go b/vendor/github.com/google/uuid/version4.go new file mode 100644 index 0000000..9ad1aba --- /dev/null +++ b/vendor/github.com/google/uuid/version4.go @@ -0,0 +1,43 @@ +// Copyright 2016 Google Inc. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package uuid + +import "io" + +// New creates a new random UUID or panics. New is equivalent to +// the expression +// +// uuid.Must(uuid.NewRandom()) +func New() UUID { + return Must(NewRandom()) +} + +// NewRandom returns a Random (Version 4) UUID. +// +// The strength of the UUIDs is based on the strength of the crypto/rand +// package. +// +// A note about uniqueness derived from the UUID Wikipedia entry: +// +// Randomly generated UUIDs have 122 random bits. One's annual risk of being +// hit by a meteorite is estimated to be one chance in 17 billion, that +// means the probability is about 0.00000000006 (6 × 10−11), +// equivalent to the odds of creating a few tens of trillions of UUIDs in a +// year and having one duplicate. +func NewRandom() (UUID, error) { + return NewRandomFromReader(rander) +} + +func NewRandomFromReader(r io.Reader) (UUID, error) { + var uuid UUID + _, err := io.ReadFull(r, uuid[:]) + if err != nil { + return Nil, err + } + uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 + uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 + return uuid, nil +} + diff --git a/vendor/github.com/pborman/uuid/README.md b/vendor/github.com/pborman/uuid/README.md index b0396b2..810ad40 100644 --- a/vendor/github.com/pborman/uuid/README.md +++ b/vendor/github.com/pborman/uuid/README.md @@ -3,6 +3,8 @@ This project was automatically exported from code.google.com/p/go-uuid # uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master) The uuid package generates and inspects UUIDs based on [RFC 4122](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services. +This package now leverages the github.com/google/uuid package (which is based off an earlier version of this package). + ###### Install `go get github.com/pborman/uuid` diff --git a/vendor/github.com/pborman/uuid/doc.go b/vendor/github.com/pborman/uuid/doc.go index d8bd013..727d761 100644 --- a/vendor/github.com/pborman/uuid/doc.go +++ b/vendor/github.com/pborman/uuid/doc.go @@ -4,5 +4,10 @@ // The uuid package generates and inspects UUIDs. // -// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security Services. +// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security +// Services. +// +// This package is a partial wrapper around the github.com/google/uuid package. +// This package represents a UUID as []byte while github.com/google/uuid +// represents a UUID as [16]byte. package uuid diff --git a/vendor/github.com/pborman/uuid/go.mod b/vendor/github.com/pborman/uuid/go.mod new file mode 100644 index 0000000..099fc7d --- /dev/null +++ b/vendor/github.com/pborman/uuid/go.mod @@ -0,0 +1,3 @@ +module github.com/pborman/uuid + +require github.com/google/uuid v1.0.0 diff --git a/vendor/github.com/pborman/uuid/go.sum b/vendor/github.com/pborman/uuid/go.sum new file mode 100644 index 0000000..db2574a --- /dev/null +++ b/vendor/github.com/pborman/uuid/go.sum @@ -0,0 +1,2 @@ +github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= diff --git a/vendor/github.com/pborman/uuid/marshal.go b/vendor/github.com/pborman/uuid/marshal.go index 6621dd5..35b8935 100644 --- a/vendor/github.com/pborman/uuid/marshal.go +++ b/vendor/github.com/pborman/uuid/marshal.go @@ -7,6 +7,8 @@ package uuid import ( "errors" "fmt" + + guuid "github.com/google/uuid" ) // MarshalText implements encoding.TextMarshaler. @@ -60,11 +62,11 @@ func (u Array) MarshalText() ([]byte, error) { // UnmarshalText implements encoding.TextUnmarshaler. func (u *Array) UnmarshalText(data []byte) error { - id := Parse(string(data)) - if id == nil { - return errors.New("invalid UUID") + id, err := guuid.ParseBytes(data) + if err != nil { + return err } - *u = id.Array() + *u = Array(id) return nil } diff --git a/vendor/github.com/pborman/uuid/node.go b/vendor/github.com/pborman/uuid/node.go index f522385..e524e01 100644 --- a/vendor/github.com/pborman/uuid/node.go +++ b/vendor/github.com/pborman/uuid/node.go @@ -5,22 +5,14 @@ package uuid import ( - "sync" -) - -var ( - nodeMu sync.Mutex - ifname string // name of interface being used - nodeID []byte // hardware for version 1 UUIDs + guuid "github.com/google/uuid" ) // NodeInterface returns the name of the interface from which the NodeID was // derived. The interface "user" is returned if the NodeID was set by // SetNodeID. func NodeInterface() string { - defer nodeMu.Unlock() - nodeMu.Lock() - return ifname + return guuid.NodeInterface() } // SetNodeInterface selects the hardware address to be used for Version 1 UUIDs. @@ -30,67 +22,20 @@ func NodeInterface() string { // // SetNodeInterface never fails when name is "". func SetNodeInterface(name string) bool { - defer nodeMu.Unlock() - nodeMu.Lock() - return setNodeInterface(name) -} - -func setNodeInterface(name string) bool { - - iname, addr := getHardwareInterface(name) // null implementation for js - if iname != "" && setNodeID(addr) { - ifname = iname - return true - } - - // We found no interfaces with a valid hardware address. If name - // does not specify a specific interface generate a random Node ID - // (section 4.1.6) - if name == "" { - if nodeID == nil { - nodeID = make([]byte, 6) - } - randomBits(nodeID) - return true - } - return false + return guuid.SetNodeInterface(name) } // NodeID returns a slice of a copy of the current Node ID, setting the Node ID // if not already set. func NodeID() []byte { - defer nodeMu.Unlock() - nodeMu.Lock() - if nodeID == nil { - setNodeInterface("") - } - nid := make([]byte, 6) - copy(nid, nodeID) - return nid + return guuid.NodeID() } // SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes // of id are used. If id is less than 6 bytes then false is returned and the // Node ID is not set. func SetNodeID(id []byte) bool { - defer nodeMu.Unlock() - nodeMu.Lock() - if setNodeID(id) { - ifname = "user" - return true - } - return false -} - -func setNodeID(id []byte) bool { - if len(id) < 6 { - return false - } - if nodeID == nil { - nodeID = make([]byte, 6) - } - copy(nodeID, id) - return true + return guuid.SetNodeID(id) } // NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is diff --git a/vendor/github.com/pborman/uuid/sql.go b/vendor/github.com/pborman/uuid/sql.go index d015bfd..929c384 100644 --- a/vendor/github.com/pborman/uuid/sql.go +++ b/vendor/github.com/pborman/uuid/sql.go @@ -40,7 +40,9 @@ func (uuid *UUID) Scan(src interface{}) error { // assumes a simple slice of bytes if 16 bytes // otherwise attempts to parse if len(b) == 16 { - *uuid = UUID(b) + parsed := make([]byte, 16) + copy(parsed, b) + *uuid = UUID(parsed) } else { u := Parse(string(b)) diff --git a/vendor/github.com/pborman/uuid/time.go b/vendor/github.com/pborman/uuid/time.go index eedf242..7286824 100644 --- a/vendor/github.com/pborman/uuid/time.go +++ b/vendor/github.com/pborman/uuid/time.go @@ -6,65 +6,18 @@ package uuid import ( "encoding/binary" - "sync" - "time" + + guuid "github.com/google/uuid" ) // A Time represents a time as the number of 100's of nanoseconds since 15 Oct // 1582. -type Time int64 - -const ( - lillian = 2299160 // Julian day of 15 Oct 1582 - unix = 2440587 // Julian day of 1 Jan 1970 - epoch = unix - lillian // Days between epochs - g1582 = epoch * 86400 // seconds between epochs - g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs -) - -var ( - timeMu sync.Mutex - lasttime uint64 // last time we returned - clock_seq uint16 // clock sequence for this run - - timeNow = time.Now // for testing -) - -// UnixTime converts t the number of seconds and nanoseconds using the Unix -// epoch of 1 Jan 1970. -func (t Time) UnixTime() (sec, nsec int64) { - sec = int64(t - g1582ns100) - nsec = (sec % 10000000) * 100 - sec /= 10000000 - return sec, nsec -} +type Time = guuid.Time // GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and // clock sequence as well as adjusting the clock sequence as needed. An error // is returned if the current time cannot be determined. -func GetTime() (Time, uint16, error) { - defer timeMu.Unlock() - timeMu.Lock() - return getTime() -} - -func getTime() (Time, uint16, error) { - t := timeNow() - - // If we don't have a clock sequence already, set one. - if clock_seq == 0 { - setClockSequence(-1) - } - now := uint64(t.UnixNano()/100) + g1582ns100 - - // If time has gone backwards with this clock sequence then we - // increment the clock sequence - if now <= lasttime { - clock_seq = ((clock_seq + 1) & 0x3fff) | 0x8000 - } - lasttime = now - return Time(now), clock_seq, nil -} +func GetTime() (Time, uint16, error) { return guuid.GetTime() } // ClockSequence returns the current clock sequence, generating one if not // already set. The clock sequence is only used for Version 1 UUIDs. @@ -74,39 +27,11 @@ func getTime() (Time, uint16, error) { // clock sequence is generated the first time a clock sequence is requested by // ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated // for -func ClockSequence() int { - defer timeMu.Unlock() - timeMu.Lock() - return clockSequence() -} - -func clockSequence() int { - if clock_seq == 0 { - setClockSequence(-1) - } - return int(clock_seq & 0x3fff) -} +func ClockSequence() int { return guuid.ClockSequence() } -// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to +// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to // -1 causes a new sequence to be generated. -func SetClockSequence(seq int) { - defer timeMu.Unlock() - timeMu.Lock() - setClockSequence(seq) -} - -func setClockSequence(seq int) { - if seq == -1 { - var b [2]byte - randomBits(b[:]) // clock sequence - seq = int(b[0])<<8 | int(b[1]) - } - old_seq := clock_seq - clock_seq = uint16(seq&0x3fff) | 0x8000 // Set our variant - if old_seq != clock_seq { - lasttime = 0 - } -} +func SetClockSequence(seq int) { guuid.SetClockSequence(seq) } // Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in // uuid. It returns false if uuid is not valid. The time is only well defined diff --git a/vendor/github.com/pborman/uuid/util.go b/vendor/github.com/pborman/uuid/util.go index fc8e052..255b5e2 100644 --- a/vendor/github.com/pborman/uuid/util.go +++ b/vendor/github.com/pborman/uuid/util.go @@ -4,17 +4,6 @@ package uuid -import ( - "io" -) - -// randomBits completely fills slice b with random data. -func randomBits(b []byte) { - if _, err := io.ReadFull(rander, b); err != nil { - panic(err.Error()) // rand should never fail - } -} - // xvalues returns the value of a byte as a hexadecimal digit or 255. var xvalues = [256]byte{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, diff --git a/vendor/github.com/pborman/uuid/uuid.go b/vendor/github.com/pborman/uuid/uuid.go index 7c643cf..3370004 100644 --- a/vendor/github.com/pborman/uuid/uuid.go +++ b/vendor/github.com/pborman/uuid/uuid.go @@ -8,9 +8,9 @@ import ( "bytes" "crypto/rand" "encoding/hex" - "fmt" "io" - "strings" + + guuid "github.com/google/uuid" ) // Array is a pass-by-value UUID that can be used as an effecient key in a map. @@ -24,7 +24,7 @@ func (uuid Array) UUID() UUID { // String returns the string representation of uuid, // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. func (uuid Array) String() string { - return uuid.UUID().String() + return guuid.UUID(uuid).String() } // A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC @@ -32,18 +32,18 @@ func (uuid Array) String() string { type UUID []byte // A Version represents a UUIDs version. -type Version byte +type Version = guuid.Version // A Variant represents a UUIDs variant. -type Variant byte +type Variant = guuid.Variant // Constants returned by Variant. const ( - Invalid = Variant(iota) // Invalid UUID - RFC4122 // The variant specified in RFC4122 - Reserved // Reserved, NCS backward compatibility. - Microsoft // Reserved, Microsoft Corporation backward compatibility. - Future // Reserved for future definition. + Invalid = guuid.Invalid // Invalid UUID + RFC4122 = guuid.RFC4122 // The variant specified in RFC4122 + Reserved = guuid.Reserved // Reserved, NCS backward compatibility. + Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility. + Future = guuid.Future // Reserved for future definition. ) var rander = rand.Reader // random function @@ -54,35 +54,23 @@ func New() string { return NewRandom().String() } -// Parse decodes s into a UUID or returns nil. Both the UUID form of -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and -// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. +// Parse decodes s into a UUID or returns nil. See github.com/google/uuid for +// the formats parsed. func Parse(s string) UUID { - if len(s) == 36+9 { - if strings.ToLower(s[:9]) != "urn:uuid:" { - return nil - } - s = s[9:] - } else if len(s) != 36 { - return nil - } - if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return nil + gu, err := guuid.Parse(s) + if err == nil { + return gu[:] } - var uuid [16]byte - for i, x := range [16]int{ - 0, 2, 4, 6, - 9, 11, - 14, 16, - 19, 21, - 24, 26, 28, 30, 32, 34} { - if v, ok := xtob(s[x:]); !ok { - return nil - } else { - uuid[i] = v - } + return nil +} + +// ParseBytes is like Parse, except it parses a byte slice instead of a string. +func ParseBytes(b []byte) (UUID, error) { + gu, err := guuid.ParseBytes(b) + if err == nil { + return gu[:], nil } - return uuid[:] + return nil, err } // Equal returns true if uuid1 and uuid2 are equal. @@ -163,29 +151,6 @@ func (uuid UUID) Version() (Version, bool) { return Version(uuid[6] >> 4), true } -func (v Version) String() string { - if v > 15 { - return fmt.Sprintf("BAD_VERSION_%d", v) - } - return fmt.Sprintf("VERSION_%d", v) -} - -func (v Variant) String() string { - switch v { - case RFC4122: - return "RFC4122" - case Reserved: - return "Reserved" - case Microsoft: - return "Microsoft" - case Future: - return "Future" - case Invalid: - return "Invalid" - } - return fmt.Sprintf("BadVariant%d", int(v)) -} - // SetRand sets the random number generator to r, which implements io.Reader. // If r.Read returns an error when the package requests random data then // a panic will be issued. @@ -193,9 +158,5 @@ func (v Variant) String() string { // Calling SetRand with nil sets the random number generator to the default // generator. func SetRand(r io.Reader) { - if r == nil { - rander = rand.Reader - return - } - rander = r + guuid.SetRand(r) } diff --git a/vendor/github.com/pborman/uuid/version1.go b/vendor/github.com/pborman/uuid/version1.go index 0127eac..7af948d 100644 --- a/vendor/github.com/pborman/uuid/version1.go +++ b/vendor/github.com/pborman/uuid/version1.go @@ -5,7 +5,7 @@ package uuid import ( - "encoding/binary" + guuid "github.com/google/uuid" ) // NewUUID returns a Version 1 UUID based on the current NodeID and clock @@ -15,27 +15,9 @@ import ( // SetClockSequence then it will be set automatically. If GetTime fails to // return the current NewUUID returns nil. func NewUUID() UUID { - if nodeID == nil { - SetNodeInterface("") + gu, err := guuid.NewUUID() + if err == nil { + return UUID(gu[:]) } - - now, seq, err := GetTime() - if err != nil { - return nil - } - - uuid := make([]byte, 16) - - time_low := uint32(now & 0xffffffff) - time_mid := uint16((now >> 32) & 0xffff) - time_hi := uint16((now >> 48) & 0x0fff) - time_hi |= 0x1000 // Version 1 - - binary.BigEndian.PutUint32(uuid[0:], time_low) - binary.BigEndian.PutUint16(uuid[4:], time_mid) - binary.BigEndian.PutUint16(uuid[6:], time_hi) - binary.BigEndian.PutUint16(uuid[8:], seq) - copy(uuid[10:], nodeID) - - return uuid + return nil } diff --git a/vendor/github.com/pborman/uuid/version4.go b/vendor/github.com/pborman/uuid/version4.go index b3d4a36..767dd0c 100644 --- a/vendor/github.com/pborman/uuid/version4.go +++ b/vendor/github.com/pborman/uuid/version4.go @@ -4,12 +4,14 @@ package uuid -// Random returns a Random (Version 4) UUID or panics. +import guuid "github.com/google/uuid" + +// NewRandom returns a Random (Version 4) UUID or panics. // // The strength of the UUIDs is based on the strength of the crypto/rand // package. // -// A note about uniqueness derived from from the UUID Wikipedia entry: +// A note about uniqueness derived from the UUID Wikipedia entry: // // Randomly generated UUIDs have 122 random bits. One's annual risk of being // hit by a meteorite is estimated to be one chance in 17 billion, that @@ -17,9 +19,8 @@ package uuid // equivalent to the odds of creating a few tens of trillions of UUIDs in a // year and having one duplicate. func NewRandom() UUID { - uuid := make([]byte, 16) - randomBits([]byte(uuid)) - uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4 - uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10 - return uuid + if gu, err := guuid.NewRandom(); err == nil { + return UUID(gu[:]) + } + return nil } |