mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-15 07:00:52 +00:00
Imported Upstream version 1.0.1
This commit is contained in:
+247
@@ -0,0 +1,247 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// itemType identifies the type of lex items.
|
||||
type itemType int
|
||||
|
||||
const eof = -1
|
||||
|
||||
const (
|
||||
itemNull itemType = iota
|
||||
itemError // error occurred;
|
||||
// value is text of error
|
||||
itemEOF
|
||||
itemLeftParen // (
|
||||
itemRightParen // )
|
||||
itemOr // |
|
||||
itemAnd // ,
|
||||
itemNot // !
|
||||
itemLt // <<
|
||||
itemLtEq // <=, <
|
||||
itemGt // >>
|
||||
itemGtEq // >=, >
|
||||
itemEq // =
|
||||
itemPatMatch // %
|
||||
itemRegexp // ~
|
||||
itemLeftCurly // {
|
||||
itemRightCurly // }
|
||||
itemString
|
||||
)
|
||||
|
||||
// item represents a token returned from the scanner.
|
||||
type item struct {
|
||||
typ itemType // Type, such as itemNumber.
|
||||
val string // Value, such as "23.2".
|
||||
}
|
||||
|
||||
func (i item) String() string {
|
||||
if i.typ == itemString {
|
||||
return fmt.Sprintf("%#v", i.val)
|
||||
}
|
||||
if i.typ == itemEOF {
|
||||
return "<EOL>"
|
||||
}
|
||||
if i.typ == itemError {
|
||||
return fmt.Sprintf("error: %s", i.val)
|
||||
}
|
||||
if i.typ == itemNull {
|
||||
return "<NULL>"
|
||||
}
|
||||
return i.val
|
||||
}
|
||||
|
||||
// stateFn represents the state of the scanner
|
||||
// as a function that returns the next state.
|
||||
type stateFn func(*lexer) stateFn
|
||||
|
||||
// lexer holds the state of the scanner.
|
||||
type lexer struct {
|
||||
name string // used only for error reports.
|
||||
input string // the string being scanned.
|
||||
start int // start position of this item.
|
||||
pos int // current position in the input.
|
||||
width int // width of last rune read from input.
|
||||
items chan item // channel of scanned items.
|
||||
last item
|
||||
}
|
||||
|
||||
func lex(name, input string) (*lexer, chan item) {
|
||||
l := &lexer{
|
||||
name: name,
|
||||
input: input,
|
||||
items: make(chan item),
|
||||
}
|
||||
go l.run() // Concurrently run state machine.
|
||||
return l, l.items
|
||||
}
|
||||
|
||||
// emit passes an item back to the client.
|
||||
func (l *lexer) emit(t itemType) {
|
||||
l.items <- item{t, l.input[l.start:l.pos]}
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
// run lexes the input by executing state functions until
|
||||
// the state is nil.
|
||||
func (l *lexer) run() {
|
||||
for state := lexMain; state != nil; {
|
||||
state = state(l)
|
||||
}
|
||||
close(l.items) // No more tokens will be delivered.
|
||||
}
|
||||
|
||||
// next returns the next rune in the input.
|
||||
func (l *lexer) next() (r rune) {
|
||||
if l.pos >= len(l.input) {
|
||||
l.width = 0
|
||||
return eof
|
||||
}
|
||||
r, l.width =
|
||||
utf8.DecodeRuneInString(l.input[l.pos:])
|
||||
l.pos += l.width
|
||||
return r
|
||||
}
|
||||
|
||||
// ignore skips over the pending input before this point.
|
||||
func (l *lexer) ignore() {
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
// backup steps back one rune.
|
||||
// Can be called only once per call of next.
|
||||
func (l *lexer) backup() {
|
||||
l.pos -= l.width
|
||||
}
|
||||
|
||||
// peek returns but does not consume
|
||||
// the next rune in the input.
|
||||
func (l *lexer) peek() rune {
|
||||
r := l.next()
|
||||
l.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
func (l *lexer) Current() item {
|
||||
if l.last.typ == 0 {
|
||||
l.last = <-l.items
|
||||
}
|
||||
|
||||
return l.last
|
||||
}
|
||||
|
||||
func (l *lexer) Consume() {
|
||||
l.last = <-l.items
|
||||
}
|
||||
|
||||
// error returns an error token and terminates the scan
|
||||
// by passing back a nil pointer that will be the next
|
||||
// state, terminating l.run.
|
||||
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
|
||||
l.items <- item{
|
||||
itemError,
|
||||
fmt.Sprintf(format, args...),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lexMain(l *lexer) stateFn {
|
||||
switch r := l.next(); {
|
||||
case r == eof:
|
||||
l.emit(itemEOF)
|
||||
return nil
|
||||
case unicode.IsSpace(r):
|
||||
l.ignore()
|
||||
case r == '(':
|
||||
l.emit(itemLeftParen)
|
||||
case r == ')':
|
||||
l.emit(itemRightParen)
|
||||
case r == '{':
|
||||
l.emit(itemLeftCurly)
|
||||
case r == '}':
|
||||
l.emit(itemRightCurly)
|
||||
case r == '|':
|
||||
l.emit(itemOr)
|
||||
case r == ',':
|
||||
l.emit(itemAnd)
|
||||
case r == '!':
|
||||
l.emit(itemNot)
|
||||
case r == '<':
|
||||
r2 := l.next()
|
||||
if r2 == '<' {
|
||||
l.emit(itemLt)
|
||||
} else if r2 == '=' {
|
||||
l.emit(itemLtEq)
|
||||
} else {
|
||||
l.backup()
|
||||
l.emit(itemLtEq)
|
||||
}
|
||||
case r == '>':
|
||||
r2 := l.next()
|
||||
if r2 == '>' {
|
||||
l.emit(itemGt)
|
||||
} else if r2 == '=' {
|
||||
l.emit(itemGtEq)
|
||||
} else {
|
||||
l.backup()
|
||||
l.emit(itemGtEq)
|
||||
}
|
||||
case r == '=':
|
||||
l.emit(itemEq)
|
||||
case r == '%':
|
||||
l.emit(itemPatMatch)
|
||||
case r == '~':
|
||||
l.emit(itemRegexp)
|
||||
default:
|
||||
l.backup()
|
||||
return lexString
|
||||
}
|
||||
|
||||
return lexMain
|
||||
}
|
||||
|
||||
func lexString(l *lexer) stateFn {
|
||||
r := l.next()
|
||||
// quoted string
|
||||
if r == '"' || r == '\'' {
|
||||
quote := r
|
||||
result := ""
|
||||
l.ignore()
|
||||
for {
|
||||
r = l.next()
|
||||
if r == quote {
|
||||
l.ignore()
|
||||
l.items <- item{itemString, result}
|
||||
return lexMain
|
||||
}
|
||||
if r == '\\' {
|
||||
r = l.next()
|
||||
}
|
||||
if r == eof {
|
||||
return l.errorf("unexpected eof in quoted string")
|
||||
}
|
||||
result = result + string(r)
|
||||
}
|
||||
} else {
|
||||
// unquoted string
|
||||
for {
|
||||
if unicode.IsSpace(r) || strings.IndexRune("()|,!{}", r) > 0 {
|
||||
l.backup()
|
||||
l.emit(itemString)
|
||||
return lexMain
|
||||
}
|
||||
|
||||
if r == eof {
|
||||
l.emit(itemString)
|
||||
l.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
r = l.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type LexerSuite struct {
|
||||
}
|
||||
|
||||
var _ = Suite(&LexerSuite{})
|
||||
|
||||
func (s *LexerSuite) TestLexing(c *C) {
|
||||
_, ch := lex("query", "package (<< 1.3), $Source | !\"app\", 'd\"\\a\\'ta' {i386}")
|
||||
|
||||
c.Check(<-ch, Equals, item{typ: itemString, val: "package"})
|
||||
c.Check(<-ch, Equals, item{typ: itemLeftParen, val: "("})
|
||||
c.Check(<-ch, Equals, item{typ: itemLt, val: "<<"})
|
||||
c.Check(<-ch, Equals, item{typ: itemString, val: "1.3"})
|
||||
c.Check(<-ch, Equals, item{typ: itemRightParen, val: ")"})
|
||||
c.Check(<-ch, Equals, item{typ: itemAnd, val: ","})
|
||||
c.Check(<-ch, Equals, item{typ: itemString, val: "$Source"})
|
||||
c.Check(<-ch, Equals, item{typ: itemOr, val: "|"})
|
||||
c.Check(<-ch, Equals, item{typ: itemNot, val: "!"})
|
||||
c.Check(<-ch, Equals, item{typ: itemString, val: "app"})
|
||||
c.Check(<-ch, Equals, item{typ: itemAnd, val: ","})
|
||||
c.Check(<-ch, Equals, item{typ: itemString, val: "d\"a'ta"})
|
||||
c.Check(<-ch, Equals, item{typ: itemLeftCurly, val: "{"})
|
||||
c.Check(<-ch, Equals, item{typ: itemString, val: "i386"})
|
||||
c.Check(<-ch, Equals, item{typ: itemRightCurly, val: "}"})
|
||||
c.Check(<-ch, Equals, item{typ: itemEOF, val: ""})
|
||||
}
|
||||
|
||||
func (s *LexerSuite) TestConsume(c *C) {
|
||||
l, _ := lex("query", "package (<< 1.3)")
|
||||
|
||||
c.Check(l.Current(), Equals, item{typ: itemString, val: "package"})
|
||||
c.Check(l.Current(), Equals, item{typ: itemString, val: "package"})
|
||||
l.Consume()
|
||||
c.Check(l.Current(), Equals, item{typ: itemLeftParen, val: "("})
|
||||
l.Consume()
|
||||
c.Check(l.Current(), Equals, item{typ: itemLt, val: "<<"})
|
||||
}
|
||||
|
||||
func (s *LexerSuite) TestString(c *C) {
|
||||
l, _ := lex("query", "package (<< 1.3)")
|
||||
|
||||
c.Check(fmt.Sprintf("%s", l.Current()), Equals, "\"package\"")
|
||||
l.Consume()
|
||||
c.Check(fmt.Sprintf("%s", l.Current()), Equals, "(")
|
||||
}
|
||||
|
||||
func (s *LexerSuite) TestError(c *C) {
|
||||
l, _ := lex("query", "'package")
|
||||
|
||||
c.Check(fmt.Sprintf("%s", l.Current()), Equals, "error: unexpected eof in quoted string")
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Package query implements query language for
|
||||
package query
|
||||
|
||||
import (
|
||||
"github.com/smira/aptly/deb"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
Query language resembling Debian dependencies and reprepro
|
||||
queries: http://mirrorer.alioth.debian.org/reprepro.1.html
|
||||
|
||||
Query := A | A '|' Query
|
||||
A := B | B ',' A
|
||||
B := C | '!' B
|
||||
C := '(' Query ')' | D
|
||||
D := <field> <condition> <arch_condition> | <pkg>_<version>_<arch>
|
||||
field := <package-name> | <field> | $special_field
|
||||
condition := '(' <operator> value ')' |
|
||||
arch_condition := '{' arch '}' |
|
||||
operator := | << | < | <= | > | >> | >= | = | % | ~
|
||||
*/
|
||||
|
||||
// Parse parses input package query into PackageQuery tree ready for evaluation
|
||||
func Parse(query string) (result deb.PackageQuery, err error) {
|
||||
l, _ := lex("", query)
|
||||
result, err = parse(l)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
// Launch gocheck tests
|
||||
func Test(t *testing.T) {
|
||||
TestingT(t)
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/smira/aptly/deb"
|
||||
)
|
||||
|
||||
type parser struct {
|
||||
name string // used only for error reports.
|
||||
input *lexer // the input lexer
|
||||
err error // error stored while parsing
|
||||
}
|
||||
|
||||
func parse(input *lexer) (deb.PackageQuery, error) {
|
||||
p := &parser{
|
||||
name: input.name,
|
||||
input: input,
|
||||
}
|
||||
query := p.parse()
|
||||
if p.err != nil {
|
||||
return nil, p.err
|
||||
}
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// Entry into parser
|
||||
func (p *parser) parse() deb.PackageQuery {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
p.err = fmt.Errorf("parsing failed: %s", r)
|
||||
}
|
||||
}()
|
||||
|
||||
q := p.Query()
|
||||
if p.input.Current().typ != itemEOF {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting end of query", p.input.Current()))
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// Query := A | A '|' Query
|
||||
func (p *parser) Query() deb.PackageQuery {
|
||||
q := p.A()
|
||||
if p.input.Current().typ == itemOr {
|
||||
p.input.Consume()
|
||||
return &deb.OrQuery{L: q, R: p.Query()}
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// A := B | B ',' A
|
||||
func (p *parser) A() deb.PackageQuery {
|
||||
q := p.B()
|
||||
if p.input.Current().typ == itemAnd {
|
||||
p.input.Consume()
|
||||
return &deb.AndQuery{L: q, R: p.A()}
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// B := C | '!' B
|
||||
func (p *parser) B() deb.PackageQuery {
|
||||
if p.input.Current().typ == itemNot {
|
||||
p.input.Consume()
|
||||
return &deb.NotQuery{Q: p.B()}
|
||||
}
|
||||
return p.C()
|
||||
}
|
||||
|
||||
// C := '(' Query ')' | D
|
||||
func (p *parser) C() deb.PackageQuery {
|
||||
if p.input.Current().typ == itemLeftParen {
|
||||
p.input.Consume()
|
||||
q := p.Query()
|
||||
if p.input.Current().typ != itemRightParen {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting ')'", p.input.Current()))
|
||||
}
|
||||
p.input.Consume()
|
||||
return q
|
||||
}
|
||||
return p.D()
|
||||
}
|
||||
|
||||
func operatorToRelation(operator itemType) int {
|
||||
switch operator {
|
||||
case 0:
|
||||
return deb.VersionDontCare
|
||||
case itemLt:
|
||||
return deb.VersionLess
|
||||
case itemLtEq:
|
||||
return deb.VersionLessOrEqual
|
||||
case itemGt:
|
||||
return deb.VersionGreater
|
||||
case itemGtEq:
|
||||
return deb.VersionGreaterOrEqual
|
||||
case itemEq:
|
||||
return deb.VersionEqual
|
||||
case itemPatMatch:
|
||||
return deb.VersionPatternMatch
|
||||
case itemRegexp:
|
||||
return deb.VersionRegexp
|
||||
}
|
||||
panic("unable to map token to relation")
|
||||
}
|
||||
|
||||
// isPackageRef returns ok true if field has format pkg_version_arch
|
||||
func parsePackageRef(query string) (pkg, version, arch string, ok bool) {
|
||||
i := strings.Index(query, "_")
|
||||
if i != -1 {
|
||||
pkg, query = query[:i], query[i+1:]
|
||||
j := strings.LastIndex(query, "_")
|
||||
if j != -1 {
|
||||
version, arch = query[:j], query[j+1:]
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// D := <field> <condition> <arch_condition> | <package>_<version>_<arch>
|
||||
// field := <package-name> | <field> | $special_field
|
||||
func (p *parser) D() deb.PackageQuery {
|
||||
if p.input.Current().typ != itemString {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting field or package name", p.input.Current()))
|
||||
}
|
||||
|
||||
field := p.input.Current().val
|
||||
p.input.Consume()
|
||||
|
||||
operator, value := p.Condition()
|
||||
|
||||
r, _ := utf8.DecodeRuneInString(field)
|
||||
if strings.HasPrefix(field, "$") || unicode.IsUpper(r) {
|
||||
// special field or regular field
|
||||
q := &deb.FieldQuery{Field: field, Relation: operatorToRelation(operator), Value: value}
|
||||
if q.Relation == deb.VersionRegexp {
|
||||
var err error
|
||||
q.Regexp, err = regexp.Compile(q.Value)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("regexp compile failed: %s", err))
|
||||
}
|
||||
}
|
||||
return q
|
||||
} else if operator == 0 && value == "" {
|
||||
if pkg, version, arch, ok := parsePackageRef(field); ok {
|
||||
// query for specific package
|
||||
return &deb.PkgQuery{Pkg: pkg, Version: version, Arch: arch}
|
||||
}
|
||||
}
|
||||
|
||||
// regular dependency-like query
|
||||
q := &deb.DependencyQuery{Dep: deb.Dependency{
|
||||
Pkg: field,
|
||||
Relation: operatorToRelation(operator),
|
||||
Version: value,
|
||||
Architecture: p.ArchCondition()}}
|
||||
if q.Dep.Relation == deb.VersionRegexp {
|
||||
var err error
|
||||
q.Dep.Regexp, err = regexp.Compile(q.Dep.Version)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("regexp compile failed: %s", err))
|
||||
}
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// condition := '(' <operator> value ')' |
|
||||
// operator := | << | < | <= | > | >> | >= | = | % | ~
|
||||
func (p *parser) Condition() (operator itemType, value string) {
|
||||
if p.input.Current().typ != itemLeftParen {
|
||||
return
|
||||
}
|
||||
p.input.Consume()
|
||||
|
||||
if p.input.Current().typ == itemLt ||
|
||||
p.input.Current().typ == itemGt ||
|
||||
p.input.Current().typ == itemLtEq ||
|
||||
p.input.Current().typ == itemGtEq ||
|
||||
p.input.Current().typ == itemEq ||
|
||||
p.input.Current().typ == itemPatMatch ||
|
||||
p.input.Current().typ == itemRegexp {
|
||||
operator = p.input.Current().typ
|
||||
p.input.Consume()
|
||||
} else {
|
||||
operator = itemEq
|
||||
}
|
||||
|
||||
if p.input.Current().typ != itemString {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting value", p.input.Current()))
|
||||
}
|
||||
value = p.input.Current().val
|
||||
p.input.Consume()
|
||||
|
||||
if p.input.Current().typ != itemRightParen {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting ')'", p.input.Current()))
|
||||
}
|
||||
p.input.Consume()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// arch_condition := '{' arch '}' |
|
||||
func (p *parser) ArchCondition() (arch string) {
|
||||
if p.input.Current().typ != itemLeftCurly {
|
||||
return
|
||||
}
|
||||
p.input.Consume()
|
||||
|
||||
if p.input.Current().typ != itemString {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting architecture", p.input.Current()))
|
||||
}
|
||||
arch = p.input.Current().val
|
||||
p.input.Consume()
|
||||
|
||||
if p.input.Current().typ != itemRightCurly {
|
||||
panic(fmt.Sprintf("unexpected token %s: expecting '}'", p.input.Current()))
|
||||
}
|
||||
p.input.Consume()
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/smira/aptly/deb"
|
||||
|
||||
. "gopkg.in/check.v1"
|
||||
)
|
||||
|
||||
type SyntaxSuite struct {
|
||||
}
|
||||
|
||||
var _ = Suite(&SyntaxSuite{})
|
||||
|
||||
func (s *SyntaxSuite) TestParsing(c *C) {
|
||||
l, _ := lex("query", "package (<< 1.3~dev), $Source")
|
||||
q, err := parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q.(*deb.AndQuery).L, DeepEquals, &deb.DependencyQuery{Dep: deb.Dependency{Pkg: "package", Relation: deb.VersionLess, Version: "1.3~dev"}})
|
||||
c.Check(q.(*deb.AndQuery).R, DeepEquals, &deb.FieldQuery{Field: "$Source"})
|
||||
|
||||
l, _ = lex("query", "package (1.3), Name (lala) | !$Source")
|
||||
q, err = parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q.(*deb.OrQuery).L.(*deb.AndQuery).L, DeepEquals, &deb.DependencyQuery{Dep: deb.Dependency{Pkg: "package", Relation: deb.VersionEqual, Version: "1.3"}})
|
||||
c.Check(q.(*deb.OrQuery).L.(*deb.AndQuery).R, DeepEquals, &deb.FieldQuery{Field: "Name", Relation: deb.VersionEqual, Value: "lala"})
|
||||
c.Check(q.(*deb.OrQuery).R.(*deb.NotQuery).Q, DeepEquals, &deb.FieldQuery{Field: "$Source"})
|
||||
|
||||
l, _ = lex("query", "package, ((!(Name | $Source (~ a.*))))")
|
||||
q, err = parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q.(*deb.AndQuery).L, DeepEquals, &deb.DependencyQuery{Dep: deb.Dependency{Pkg: "package", Relation: deb.VersionDontCare}})
|
||||
c.Check(q.(*deb.AndQuery).R.(*deb.NotQuery).Q.(*deb.OrQuery).L, DeepEquals, &deb.FieldQuery{Field: "Name", Relation: deb.VersionDontCare})
|
||||
c.Check(q.(*deb.AndQuery).R.(*deb.NotQuery).Q.(*deb.OrQuery).R, DeepEquals, &deb.FieldQuery{Field: "$Source", Relation: deb.VersionRegexp, Value: "a.*",
|
||||
Regexp: regexp.MustCompile("a.*")})
|
||||
|
||||
l, _ = lex("query", "package (> 5.3.7)")
|
||||
q, err = parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q, DeepEquals, &deb.DependencyQuery{Dep: deb.Dependency{Pkg: "package", Relation: deb.VersionGreaterOrEqual, Version: "5.3.7"}})
|
||||
|
||||
l, _ = lex("query", "package (~ 5\\.3.*~dev)")
|
||||
q, err = parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q, DeepEquals, &deb.DependencyQuery{Dep: deb.Dependency{Pkg: "package", Relation: deb.VersionRegexp, Version: "5\\.3.*~dev",
|
||||
Regexp: regexp.MustCompile("5\\.3.*~dev")}})
|
||||
|
||||
l, _ = lex("query", "alien-data_1.3.4~dev_i386")
|
||||
q, err = parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q, DeepEquals, &deb.PkgQuery{Pkg: "alien-data", Version: "1.3.4~dev", Arch: "i386"})
|
||||
|
||||
l, _ = lex("query", "package (> 5.3.7) {amd64}")
|
||||
q, err = parse(l)
|
||||
|
||||
c.Assert(err, IsNil)
|
||||
c.Check(q, DeepEquals, &deb.DependencyQuery{
|
||||
Dep: deb.Dependency{Pkg: "package", Relation: deb.VersionGreaterOrEqual, Version: "5.3.7", Architecture: "amd64"}})
|
||||
}
|
||||
|
||||
func (s *SyntaxSuite) TestParsingErrors(c *C) {
|
||||
l, _ := lex("query", "package (> 5.3.7), ")
|
||||
_, err := parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: unexpected token <EOL>: expecting field or package name")
|
||||
|
||||
l, _ = lex("query", "package>5.3.7)")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: unexpected token \\): expecting end of query")
|
||||
|
||||
l, _ = lex("query", "package | !|")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: unexpected token |: expecting field or package name")
|
||||
|
||||
l, _ = lex("query", "((package )")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: unexpected token <EOL>: expecting '\\)'")
|
||||
|
||||
l, _ = lex("query", "!package )")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: unexpected token \\): expecting end of query")
|
||||
|
||||
l, _ = lex("query", "'package )")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: unexpected token error: unexpected eof in quoted string: expecting field or package name")
|
||||
|
||||
l, _ = lex("query", "package (~ 1.2[34)")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: regexp compile failed: error parsing regexp: missing closing \\]: `\\[34`")
|
||||
|
||||
l, _ = lex("query", "$Name (~ 1.2[34)")
|
||||
_, err = parse(l)
|
||||
c.Check(err, ErrorMatches, "parsing failed: regexp compile failed: error parsing regexp: missing closing \\]: `\\[34`")
|
||||
}
|
||||
Reference in New Issue
Block a user