7 from pakfire
.constants
import *
9 class LexerError(Exception):
13 class LexerUnhandledLine(LexerError
):
17 class EndOfFileError(LexerError
):
21 class LexerUndefinedVariableError(LexerError
):
25 LEXER_VALID_PACKAGE_NAME
= re
.compile(r
"[A-Za-z][A-Za-z0-9\_\-\+]")
27 # XXX need to build check
28 LEXER_VALID_SCRIPTLET_NAME
= re
.compile(r
"((pre|post|posttrans)(in|un|up))")
30 LEXER_COMMENT_CHAR
= "#"
31 LEXER_COMMENT
= re
.compile(r
"^\s*#")
33 LEXER_EMPTY_LINE
= re
.compile(r
"^\s*$")
35 LEXER_DEFINITION
= re
.compile(r
"^([A-Za-z0-9_\-]+)\s*(\+)?=\s*(.+)?")
37 LEXER_BLOCK_LINE_INDENT
= "\t"
38 LEXER_BLOCK_LINE
= re
.compile(r
"^\t(.*)$")
39 LEXER_BLOCK_END
= re
.compile(r
"^end$")
41 LEXER_DEFINE_BEGIN
= re
.compile(r
"^def ([A-Za-z0-9_\-]+)$")
42 LEXER_DEFINE_LINE
= LEXER_BLOCK_LINE
43 LEXER_DEFINE_END
= LEXER_BLOCK_END
45 LEXER_PACKAGE_BEGIN
= re
.compile(r
"^package ([A-Za-z0-9_\-\+\%\{\}]+)$")
46 LEXER_PACKAGE_LINE
= LEXER_BLOCK_LINE
47 LEXER_PACKAGE_END
= LEXER_BLOCK_END
48 LEXER_PACKAGE_INHERIT
= re
.compile(r
"^template ([A-Z]+)$")
50 LEXER_SCRIPTLET_BEGIN
= re
.compile(r
"^script ([a-z]+)\s?(/[A-Za-z0-9\-\_/]+)?$")
51 LEXER_SCRIPTLET_LINE
= LEXER_BLOCK_LINE
52 LEXER_SCRIPTLET_END
= LEXER_BLOCK_END
54 LEXER_TEMPLATE_BEGIN
= re
.compile(r
"^template ([A-Z]+)$")
55 LEXER_TEMPLATE_LINE
= LEXER_BLOCK_LINE
56 LEXER_TEMPLATE_END
= LEXER_BLOCK_END
58 LEXER_BUILD_BEGIN
= re
.compile(r
"^build$")
59 LEXER_BUILD_LINE
= LEXER_BLOCK_LINE
60 LEXER_BUILD_END
= LEXER_BLOCK_END
62 LEXER_DEPS_BEGIN
= re
.compile(r
"^dependencies$")
63 LEXER_DEPS_LINE
= LEXER_BLOCK_LINE
64 LEXER_DEPS_END
= LEXER_BLOCK_END
66 LEXER_DISTRO_BEGIN
= re
.compile(r
"^distribution$")
67 LEXER_DISTRO_LINE
= LEXER_BLOCK_LINE
68 LEXER_DISTRO_END
= LEXER_BLOCK_END
70 LEXER_PACKAGE2_BEGIN
= re
.compile(r
"^package$")
71 LEXER_PACKAGE2_LINE
= LEXER_BLOCK_LINE
72 LEXER_PACKAGE2_END
= LEXER_BLOCK_END
75 LEXER_EXPORT
= re
.compile(r
"^export ([A-Za-z0-9_\-])\s*(\+)?=\s*(.+)$")
76 LEXER_UNEXPORT
= re
.compile(r
"^unexport ([A-Za-z0-9_\-]+)$")
77 LEXER_INCLUDE
= re
.compile(r
"^include (.+)$")
79 LEXER_VARIABLE
= re
.compile(r
"\%\{([A-Za-z0-9_\-]+)\}")
83 def __init__(self
, lines
=[], parent
=None, environ
=None):
89 # A place to store all definitions.
90 self
._definitions
= {}
92 # Init function that can be overwritten by child classes.
98 def inherit(self
, other
):
99 self
._definitions
.update(other
._definitions
)
102 def definitions(self
):
103 return self
._definitions
106 def open(cls
, filename
, *args
, **kwargs
):
108 lines
= f
.readlines()
111 return cls(lines
, *args
, **kwargs
)
115 return self
._lineno
+ 1
120 return self
.parent
.root
124 def get_line(self
, no
, raw
=False):
126 line
= self
.lines
[no
]
131 line
= line
.rstrip("\n")
139 # strip comments - caution: quotations
141 if line
.startswith(LEXER_COMMENT_CHAR
):
144 # XXX fix removing of comments in lines
149 #for i in range(length):
152 # if s in LEXER_QUOTES:
158 # if s == LEXER_COMMENT_CHAR:
163 def line_is_empty(self
):
164 line
= self
.get_line(self
._lineno
)
166 m
= re
.match(LEXER_EMPTY_LINE
, line
)
172 def expand_string(self
, s
):
177 m
= re
.search(LEXER_VARIABLE
, s
)
182 s
= s
.replace("%%{%s}" % var
, self
.get_var(var
))
186 def get_var(self
, key
, default
=None):
188 definitions
.update(self
.root
.definitions
)
189 definitions
.update(self
.definitions
)
193 val
= definitions
[key
]
195 logging
.warning("Undefined variable: %s" % key
)
197 # logging.warning("Undefined variable: %s" % key)
198 # raise LexerUndefinedVariableError, key
203 return self
.expand_string(val
)
205 def init(self
, environ
):
208 def get_default_parsers(self
):
210 (LEXER_COMMENT
, self
.parse_comment
),
211 (LEXER_DEFINITION
, self
.parse_definition
),
212 (LEXER_DEFINE_BEGIN
, self
.parse_define
),
215 def get_parsers(self
):
218 def parse_line(self
):
220 if self
.line_is_empty():
224 line
= self
.get_line(self
._lineno
)
226 parsers
= self
.get_default_parsers() + self
.get_parsers()
229 for pattern
, func
in parsers
:
230 m
= re
.match(pattern
, line
)
232 # Hey, I found a match, we parse it with the subparser function.
239 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
241 def read_block(self
, pattern_start
=None, pattern_line
=None, pattern_end
=None,
247 line
= self
.get_line(self
._lineno
)
249 m
= re
.match(pattern_start
, line
)
253 # Go in to next line.
260 line
= self
.get_line(self
._lineno
, raw
=raw
)
262 m
= re
.match(pattern_end
, line
)
267 m
= re
.match(pattern_line
, line
)
269 lines
.append(m
.group(1))
273 m
= re
.match(LEXER_EMPTY_LINE
, line
)
279 if not line
.startswith(LEXER_BLOCK_LINE_INDENT
):
280 raise LexerError
, "Line has not the right indentation: %d: %s" \
281 % (self
.lineno
, line
)
283 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
285 return (groups
, lines
)
288 while self
._lineno
< len(self
.lines
):
291 def parse_comment(self
):
292 line
= self
.get_line(self
._lineno
)
297 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
299 def parse_definition(self
, pattern
=LEXER_DEFINITION
):
300 line
= self
.get_line(self
._lineno
)
302 m
= re
.match(pattern
, line
)
304 raise LexerError
, "Not a definition: %s" % line
306 # Line was correctly parsed, can go on.
312 prev
= self
.definitions
.get(k
, None)
314 v
= " ".join((prev
, v
))
317 while v
and v
.endswith("\\"):
318 line
= self
.get_line(self
._lineno
)
323 self
._definitions
[k
] = v
327 def parse_define(self
):
328 line
= self
.get_line(self
._lineno
)
330 m
= re
.match(LEXER_DEFINE_BEGIN
, line
)
332 raise Exception, "XXX not a define"
334 # Go in to next line.
342 line
= self
.get_line(self
._lineno
)
344 m
= re
.match(LEXER_DEFINE_END
, line
)
349 m
= re
.match(LEXER_DEFINE_LINE
, line
)
352 value
.append(m
.group(1))
355 m
= re
.match(LEXER_EMPTY_LINE
, line
)
361 raise LexerError
, "Unhandled line: %s" % line
363 self
._definitions
[key
] = "\n".join(value
)
366 class DefaultLexer(Lexer
):
368 A lexer which only knows about about simple definitions and def.
373 class TemplateLexer(DefaultLexer
):
374 def init(self
, environ
):
375 # A place to store the scriptlets.
379 def definitions(self
):
383 definitions
.update(self
.parent
.definitions
)
384 definitions
.update(self
._definitions
)
388 def get_parsers(self
):
390 (LEXER_SCRIPTLET_BEGIN
, self
.parse_scriptlet
),
393 def parse_scriptlet(self
):
394 line
= self
.get_line(self
._lineno
)
396 m
= re
.match(LEXER_SCRIPTLET_BEGIN
, line
)
398 raise Exception, "Not a scriptlet"
404 # check if scriptlet was already defined.
405 if self
.scriptlets
.has_key(name
):
406 raise Exception, "Scriptlet %s is already defined" % name
410 self
.scriptlets
[name
] = {
412 "path" : self
.expand_string(path
),
418 line
= self
.get_line(self
._lineno
, raw
=True)
420 m
= re
.match(LEXER_SCRIPTLET_END
, line
)
425 m
= re
.match(LEXER_SCRIPTLET_LINE
, line
)
427 lines
.append(m
.group(1))
431 m
= re
.match(LEXER_EMPTY_LINE
, line
)
437 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
439 self
.scriptlets
[name
] = {
441 "scriptlet" : "\n".join(lines
),
445 class PackageLexer(TemplateLexer
):
446 def init(self
, environ
):
447 TemplateLexer
.init(self
, environ
)
449 self
._template
= "MAIN"
452 def definitions(self
):
456 definitions
.update(self
.template
.definitions
)
458 definitions
.update(self
._definitions
)
464 if not self
._template
:
467 # Get templates from root.
469 templates
= self
.root
.templates
472 return templates
[self
._template
]
474 raise LexerError
, "Template does not exist: %s" % self
._template
476 def get_parsers(self
):
477 parsers
= TemplateLexer
.get_parsers(self
)
480 (LEXER_PACKAGE_INHERIT
, self
.parse_inherit
),
485 def parse_inherit(self
):
486 line
= self
.get_line(self
._lineno
)
488 m
= re
.match(LEXER_PACKAGE_INHERIT
, line
)
490 raise LexerError
, "Not a template inheritance: %s" % line
494 self
._template
= m
.group(1)
496 # Check if template exists.
500 class BuildLexer(DefaultLexer
):
502 def definitions(self
):
503 return self
._definitions
507 return self
.definitions
509 def inherit(self
, other
):
511 Inherit everything from other lexer.
513 self
._definitions
.update(other
._definitions
)
516 class RootLexer(DefaultLexer
):
517 def init(self
, environ
):
518 # A list of variables that should be exported in the build
522 # Import all environment variables.
524 for k
, v
in environ
.items():
525 self
._definitions
[k
] = v
527 self
.exports
.append(k
)
529 # A place to store all packages.
532 # A place to store all templates.
535 # Place for build instructions
536 self
.build
= BuildLexer([], parent
=self
)
538 # Include all macros.
540 for macro
in MACRO_FILES
:
543 def include(self
, file):
544 # Create a new lexer, and parse the whole file.
545 include
= RootLexer
.open(file, parent
=self
)
547 # Copy all data from the included file.
548 self
.inherit(include
)
550 def inherit(self
, other
):
552 Inherit everything from other lexer.
554 self
._definitions
.update(other
._definitions
)
556 self
.build
.inherit(other
.build
)
557 self
.templates
.update(other
.templates
)
558 self
.packages
+= other
.packages
560 for export
in other
.exports
:
561 if not export
in self
.exports
:
562 self
.exports
.append(export
)
564 def get_parsers(self
):
566 (LEXER_INCLUDE
, self
.parse_include
),
567 (LEXER_TEMPLATE_BEGIN
, self
.parse_template
),
568 (LEXER_PACKAGE_BEGIN
, self
.parse_package
),
569 (LEXER_BUILD_BEGIN
, self
.parse_build
),
572 def parse_build(self
):
573 line
= self
.get_line(self
._lineno
)
575 m
= re
.match(LEXER_BUILD_BEGIN
, line
)
577 raise LexerError
, "Not a build statement: %s" % line
584 line
= self
.get_line(self
._lineno
)
586 m
= re
.match(LEXER_BUILD_END
, line
)
591 m
= re
.match(LEXER_BUILD_LINE
, line
)
593 lines
.append(m
.group(1))
596 # Accept empty lines.
597 m
= re
.match(LEXER_EMPTY_LINE
, line
)
603 build
= BuildLexer(lines
, parent
=self
)
604 self
.build
.inherit(build
)
606 def parse_include(self
):
607 line
= self
.get_line(self
._lineno
)
609 m
= re
.match(LEXER_INCLUDE
, line
)
611 raise LexerError
, "Not an include statement: %s" % line
613 # Get the filename from the line.
615 file = self
.expand_string(file)
617 # Include the content of the file.
620 # Go on to next line.
623 def parse_export(self
):
624 k
, v
= self
.parse_definition(pattern
, LEXER_EXPORT
)
626 if k
and not k
in self
.exports
:
627 self
.exports
.append(k
)
629 def parse_unexport(self
):
630 line
= self
.get_line(self
._lineno
)
633 m
= re
.match(LEXER_UNEXPORT
, line
)
636 if k
and k
in self
.exports
:
637 self
.exports
.remove(k
)
639 def parse_template(self
):
640 line
= self
.get_line(self
._lineno
)
642 m
= re
.match(LEXER_TEMPLATE_BEGIN
, line
)
644 raise Exception, "Not a template"
646 # Line was correctly parsed, can go on.
653 line
= self
.get_line(self
._lineno
)
655 m
= re
.match(LEXER_TEMPLATE_END
, line
)
660 m
= re
.match(LEXER_TEMPLATE_LINE
, line
)
662 lines
.append(m
.group(1))
665 # Accept empty lines.
666 m
= re
.match(LEXER_EMPTY_LINE
, line
)
672 template
= TemplateLexer(lines
, parent
=self
)
673 self
.templates
[name
] = template
675 def parse_package(self
):
676 line
= self
.get_line(self
._lineno
)
678 m
= re
.match(LEXER_PACKAGE_BEGIN
, line
)
680 raise Exception, "Not a package: %s" %line
685 name
= self
.expand_string(name
)
687 m
= re
.match(LEXER_VALID_PACKAGE_NAME
, name
)
689 raise LexerError
, "Invalid package name: %s" % name
691 lines
= ["name = %s" % name
]
694 line
= self
.get_line(self
._lineno
)
696 m
= re
.match(LEXER_PACKAGE_END
, line
)
701 m
= re
.match(LEXER_PACKAGE_LINE
, line
)
704 lines
.append(m
.group(1))
707 # Accept empty lines.
708 m
= re
.match(LEXER_EMPTY_LINE
, line
)
714 raise Exception, "XXX unhandled line in package block: %s" % line
716 package
= PackageLexer(lines
, parent
=self
)
717 self
.packages
.append(package
)
720 class FileLexer(DefaultLexer
):
721 def init(self
, environ
):
722 self
.build
= DefaultLexer()
723 self
.deps
= DefaultLexer()
724 self
.distro
= DefaultLexer()
725 self
.package
= DefaultLexer()
727 def get_parsers(self
):
729 (LEXER_BUILD_BEGIN
, self
.parse_build
),
730 (LEXER_DISTRO_BEGIN
, self
.parse_distro
),
731 (LEXER_PACKAGE2_BEGIN
, self
.parse_package
),
732 (LEXER_DEPS_BEGIN
, self
.parse_deps
),
735 def parse_build(self
):
736 keys
, lines
= self
.read_block(
737 pattern_start
=LEXER_BUILD_BEGIN
,
738 pattern_line
=LEXER_BUILD_LINE
,
739 pattern_end
=LEXER_BUILD_END
,
743 build
= DefaultLexer(lines
)
744 self
.build
.inherit(build
)
746 def parse_distro(self
):
747 keys
, lines
= self
.read_block(
748 pattern_start
=LEXER_DISTRO_BEGIN
,
749 pattern_line
=LEXER_DISTRO_LINE
,
750 pattern_end
=LEXER_DISTRO_END
,
754 distro
= DefaultLexer(lines
)
755 self
.distro
.inherit(distro
)
757 def parse_package(self
):
758 keys
, lines
= self
.read_block(
759 pattern_start
=LEXER_PACKAGE2_BEGIN
,
760 pattern_line
=LEXER_PACKAGE2_LINE
,
761 pattern_end
=LEXER_PACKAGE2_END
,
765 pkg
= DefaultLexer(lines
)
766 self
.package
.inherit(pkg
)
768 def parse_deps(self
):
769 keys
, lines
= self
.read_block(
770 pattern_start
=LEXER_DEPS_BEGIN
,
771 pattern_line
=LEXER_DEPS_LINE
,
772 pattern_end
=LEXER_DEPS_END
,
776 deps
= DefaultLexer(lines
)
777 self
.deps
.inherit(deps
)