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)?\s?([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_PACKAGES_BEGIN
= re
.compile(r
"^packages$")
71 LEXER_PACKAGES_LINE
= LEXER_BLOCK_LINE
72 LEXER_PACKAGES_END
= LEXER_BLOCK_END
74 LEXER_PACKAGE2_BEGIN
= re
.compile(r
"^package$")
75 LEXER_PACKAGE2_LINE
= LEXER_BLOCK_LINE
76 LEXER_PACKAGE2_END
= LEXER_BLOCK_END
79 LEXER_EXPORT
= re
.compile(r
"^export ([A-Za-z0-9_\-])\s*(\+)?=\s*(.+)$")
80 LEXER_UNEXPORT
= re
.compile(r
"^unexport ([A-Za-z0-9_\-]+)$")
81 LEXER_INCLUDE
= re
.compile(r
"^include (.+)$")
83 LEXER_VARIABLE
= re
.compile(r
"\%\{([A-Za-z0-9_\-]+)\}")
84 LEXER_SHELL
= re
.compile(r
"\%\(.*\)")
88 def __init__(self
, lines
=[], parent
=None, environ
=None):
94 # A place to store all definitions.
95 self
._definitions
= {}
97 # Init function that can be overwritten by child classes.
103 def inherit(self
, other
):
104 self
._definitions
.update(other
._definitions
)
107 def definitions(self
):
108 return self
._definitions
111 def open(cls
, filename
, *args
, **kwargs
):
113 lines
= f
.readlines()
116 return cls(lines
, *args
, **kwargs
)
120 return self
._lineno
+ 1
125 return self
.parent
.root
129 def get_line(self
, no
, raw
=False):
131 line
= self
.lines
[no
]
136 line
= line
.rstrip("\n")
144 # strip comments - caution: quotations
146 if line
.startswith(LEXER_COMMENT_CHAR
):
149 # XXX fix removing of comments in lines
154 #for i in range(length):
157 # if s in LEXER_QUOTES:
163 # if s == LEXER_COMMENT_CHAR:
168 def line_is_empty(self
):
169 line
= self
.get_line(self
._lineno
)
171 m
= re
.match(LEXER_EMPTY_LINE
, line
)
177 def expand_string(self
, s
):
182 m
= re
.search(LEXER_VARIABLE
, s
)
187 s
= s
.replace("%%{%s}" % var
, self
.get_var(var
))
191 def get_var(self
, key
, default
=None):
193 definitions
.update(self
.root
.definitions
)
194 definitions
.update(self
.definitions
)
198 val
= definitions
[key
]
200 logging
.warning("Undefined variable: %s" % key
)
202 # logging.warning("Undefined variable: %s" % key)
203 # raise LexerUndefinedVariableError, key
208 return self
.expand_string(val
)
210 def init(self
, environ
):
213 def get_default_parsers(self
):
215 (LEXER_COMMENT
, self
.parse_comment
),
216 (LEXER_DEFINITION
, self
.parse_definition
),
217 (LEXER_DEFINE_BEGIN
, self
.parse_define
),
219 #(LEXER_EXPORT, self.parse_export),
220 #(LEXER_UNEXPORT, self.parse_unexport),
223 def get_parsers(self
):
226 def parse_line(self
):
228 if self
.line_is_empty():
232 line
= self
.get_line(self
._lineno
)
234 parsers
= self
.get_parsers() + self
.get_default_parsers()
237 for pattern
, func
in parsers
:
238 m
= re
.match(pattern
, line
)
240 # Hey, I found a match, we parse it with the subparser function.
247 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
249 def read_block(self
, pattern_start
=None, pattern_line
=None, pattern_end
=None,
255 line
= self
.get_line(self
._lineno
)
257 m
= re
.match(pattern_start
, line
)
261 # Go in to next line.
268 line
= self
.get_line(self
._lineno
, raw
=raw
)
270 m
= re
.match(pattern_end
, line
)
275 m
= re
.match(pattern_line
, line
)
277 lines
.append(m
.group(1))
281 m
= re
.match(LEXER_EMPTY_LINE
, line
)
287 if not line
.startswith(LEXER_BLOCK_LINE_INDENT
):
288 raise LexerError
, "Line has not the right indentation: %d: %s" \
289 % (self
.lineno
, line
)
291 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
293 return (groups
, lines
)
296 while self
._lineno
< len(self
.lines
):
299 def parse_comment(self
):
300 line
= self
.get_line(self
._lineno
)
305 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
307 def parse_definition(self
, pattern
=LEXER_DEFINITION
):
308 line
= self
.get_line(self
._lineno
)
310 m
= re
.match(pattern
, line
)
312 raise LexerError
, "Not a definition: %s" % line
314 # Line was correctly parsed, can go on.
320 prev
= self
.definitions
.get(k
, None)
321 if prev
is None and self
.parent
:
322 prev
= self
.parent
.definitions
.get(k
, None)
324 v
= " ".join((prev
or "", v
))
327 while v
and v
.endswith("\\"):
328 line
= self
.get_line(self
._lineno
)
333 self
._definitions
[k
] = v
337 def parse_define(self
):
338 line
= self
.get_line(self
._lineno
)
340 m
= re
.match(LEXER_DEFINE_BEGIN
, line
)
342 raise Exception, "XXX not a define"
344 # Check content of next line.
348 line
= self
.get_line(self
._lineno
+ i
)
351 empty
= re
.match(LEXER_EMPTY_LINE
, line
)
356 for pattern
in (LEXER_DEFINE_LINE
, LEXER_DEFINE_END
):
357 found
= re
.match(pattern
, line
)
365 line
= self
.get_line(self
._lineno
)
366 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
368 # Go in to next line.
376 line
= self
.get_line(self
._lineno
)
378 m
= re
.match(LEXER_DEFINE_END
, line
)
383 m
= re
.match(LEXER_DEFINE_LINE
, line
)
386 value
.append(m
.group(1))
389 m
= re
.match(LEXER_EMPTY_LINE
, line
)
395 raise LexerError
, "Unhandled line: %s" % line
397 self
._definitions
[key
] = "\n".join(value
)
400 class DefaultLexer(Lexer
):
402 A lexer which only knows about about simple definitions and def.
407 class TemplateLexer(DefaultLexer
):
408 def init(self
, environ
):
409 # A place to store the scriptlets.
413 def definitions(self
):
417 definitions
.update(self
.parent
.definitions
)
418 definitions
.update(self
._definitions
)
422 def get_parsers(self
):
424 (LEXER_SCRIPTLET_BEGIN
, self
.parse_scriptlet
),
427 def parse_scriptlet(self
):
428 line
= self
.get_line(self
._lineno
)
430 m
= re
.match(LEXER_SCRIPTLET_BEGIN
, line
)
432 raise Exception, "Not a scriptlet"
438 # check if scriptlet was already defined.
439 if self
.scriptlets
.has_key(name
):
440 raise Exception, "Scriptlet %s is already defined" % name
444 self
.scriptlets
[name
] = {
446 "path" : self
.expand_string(path
),
452 line
= self
.get_line(self
._lineno
, raw
=True)
454 m
= re
.match(LEXER_SCRIPTLET_END
, line
)
459 m
= re
.match(LEXER_SCRIPTLET_LINE
, line
)
461 lines
.append(m
.group(1))
465 m
= re
.match(LEXER_EMPTY_LINE
, line
)
471 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
473 self
.scriptlets
[name
] = {
475 "scriptlet" : "\n".join(lines
),
479 class PackageLexer(TemplateLexer
):
480 def init(self
, environ
):
481 TemplateLexer
.init(self
, environ
)
483 self
._template
= "MAIN"
485 assert isinstance(self
.parent
, PackagesLexer
)
488 def definitions(self
):
492 definitions
.update(self
.template
.definitions
)
494 definitions
.update(self
._definitions
)
500 if not self
._template
:
503 # Get template from parent.
505 return self
.root
.templates
[self
._template
]
507 raise LexerError
, "Template does not exist: %s" % self
._template
509 def get_parsers(self
):
511 (LEXER_PACKAGE_INHERIT
, self
.parse_inherit
),
512 ] + TemplateLexer
.get_parsers(self
)
516 def parse_inherit(self
):
517 line
= self
.get_line(self
._lineno
)
519 m
= re
.match(LEXER_PACKAGE_INHERIT
, line
)
521 raise LexerError
, "Not a template inheritance: %s" % line
525 self
._template
= m
.group(1)
527 # Check if template exists.
531 class BuildLexer(DefaultLexer
):
533 def definitions(self
):
534 return self
._definitions
538 return self
.definitions
540 def inherit(self
, other
):
542 Inherit everything from other lexer.
544 self
._definitions
.update(other
._definitions
)
547 class RootLexer(DefaultLexer
):
548 def init(self
, environ
):
549 # A list of variables that should be exported in the build
553 # A place to store all packages and templates.
554 self
.packages
= PackagesLexer([], parent
=self
)
556 # Import all environment variables.
558 for k
, v
in environ
.items():
559 self
._definitions
[k
] = v
561 self
.exports
.append(k
)
563 # Place for build instructions
564 self
.build
= BuildLexer([], parent
=self
)
566 # Include all macros.
568 for macro
in MACRO_FILES
:
571 def include(self
, file):
572 # Create a new lexer, and parse the whole file.
573 include
= RootLexer
.open(file, parent
=self
)
575 # Copy all data from the included file.
576 self
.inherit(include
)
578 def inherit(self
, other
):
580 Inherit everything from other lexer.
582 self
._definitions
.update(other
._definitions
)
584 self
.build
.inherit(other
.build
)
585 self
.packages
.inherit(other
.packages
)
587 for export
in other
.exports
:
588 if not export
in self
.exports
:
589 self
.exports
.append(export
)
593 return self
.packages
.templates
595 def get_parsers(self
):
597 (LEXER_INCLUDE
, self
.parse_include
),
598 (LEXER_PACKAGES_BEGIN
, self
.parse_packages
),
599 (LEXER_BUILD_BEGIN
, self
.parse_build
),
602 def parse_build(self
):
603 line
= self
.get_line(self
._lineno
)
605 m
= re
.match(LEXER_BUILD_BEGIN
, line
)
607 raise LexerError
, "Not a build statement: %s" % line
614 line
= self
.get_line(self
._lineno
)
616 m
= re
.match(LEXER_BUILD_END
, line
)
621 m
= re
.match(LEXER_BUILD_LINE
, line
)
623 lines
.append(m
.group(1))
626 # Accept empty lines.
627 m
= re
.match(LEXER_EMPTY_LINE
, line
)
633 build
= BuildLexer(lines
, parent
=self
)
634 self
.build
.inherit(build
)
636 def parse_include(self
):
637 line
= self
.get_line(self
._lineno
)
639 m
= re
.match(LEXER_INCLUDE
, line
)
641 raise LexerError
, "Not an include statement: %s" % line
643 # Get the filename from the line.
645 file = self
.expand_string(file)
647 # Include the content of the file.
650 # Go on to next line.
653 def parse_export(self
):
654 k
, v
= self
.parse_definition(pattern
, LEXER_EXPORT
)
656 if k
and not k
in self
.exports
:
657 self
.exports
.append(k
)
659 def parse_unexport(self
):
660 line
= self
.get_line(self
._lineno
)
663 m
= re
.match(LEXER_UNEXPORT
, line
)
666 if k
and k
in self
.exports
:
667 self
.exports
.remove(k
)
669 def parse_packages(self
):
670 keys
, lines
= self
.read_block(
671 pattern_start
=LEXER_PACKAGES_BEGIN
,
672 pattern_line
=LEXER_PACKAGES_LINE
,
673 pattern_end
=LEXER_PACKAGES_END
,
677 pkgs
= PackagesLexer(lines
, parent
=self
)
678 self
.packages
.inherit(pkgs
)
681 class PackagesLexer(DefaultLexer
):
682 def init(self
, environ
):
683 # A place to store all templates.
686 # A place to store all packages.
689 def inherit(self
, other
):
690 # Copy all templates and packages but make sure
691 # to update the parent lexer (for accessing each other).
692 for name
, template
in other
.templates
.items():
693 template
.parent
= self
694 self
.templates
[name
] = template
696 for pkg
in other
.packages
:
698 self
.packages
.append(pkg
)
701 return iter(self
.packages
)
703 def get_parsers(self
):
705 (LEXER_TEMPLATE_BEGIN
, self
.parse_template
),
706 (LEXER_PACKAGE_BEGIN
, self
.parse_package
),
709 def parse_template(self
):
710 line
= self
.get_line(self
._lineno
)
712 m
= re
.match(LEXER_TEMPLATE_BEGIN
, line
)
714 raise Exception, "Not a template"
716 # Line was correctly parsed, can go on.
723 line
= self
.get_line(self
._lineno
)
725 m
= re
.match(LEXER_TEMPLATE_END
, line
)
730 m
= re
.match(LEXER_TEMPLATE_LINE
, line
)
732 lines
.append(m
.group(1))
735 # Accept empty lines.
736 m
= re
.match(LEXER_EMPTY_LINE
, line
)
742 template
= TemplateLexer(lines
, parent
=self
)
743 self
.templates
[name
] = template
745 def parse_package(self
):
746 line
= self
.get_line(self
._lineno
)
748 m
= re
.match(LEXER_PACKAGE_BEGIN
, line
)
750 raise Exception, "Not a package: %s" %line
755 name
= self
.expand_string(name
)
757 m
= re
.match(LEXER_VALID_PACKAGE_NAME
, name
)
759 raise LexerError
, "Invalid package name: %s" % name
761 lines
= ["_name = %s" % name
]
764 while len(self
.lines
) > self
._lineno
:
765 line
= self
.get_line(self
._lineno
)
767 m
= re
.match(LEXER_PACKAGE_END
, line
)
773 m
= re
.match(LEXER_PACKAGE_LINE
, line
)
776 lines
.append(m
.group(1))
780 # Accept empty lines.
781 m
= re
.match(LEXER_EMPTY_LINE
, line
)
787 # If there is an unhandled line in a block, we raise an error.
789 raise Exception, "XXX unhandled line in package block: %s" % line
791 # If the block was never opened, we just go on.
796 raise LexerError
, "Unclosed package block '%s'." % name
798 package
= PackageLexer(lines
, parent
=self
)
799 self
.packages
.append(package
)
802 class FileLexer(DefaultLexer
):
803 def init(self
, environ
):
804 self
.build
= DefaultLexer()
805 self
.deps
= DefaultLexer()
806 self
.distro
= DefaultLexer()
807 self
.package
= DefaultLexer()
809 def get_parsers(self
):
811 (LEXER_BUILD_BEGIN
, self
.parse_build
),
812 (LEXER_DISTRO_BEGIN
, self
.parse_distro
),
813 (LEXER_PACKAGE2_BEGIN
, self
.parse_package
),
814 (LEXER_DEPS_BEGIN
, self
.parse_deps
),
817 def parse_build(self
):
818 keys
, lines
= self
.read_block(
819 pattern_start
=LEXER_BUILD_BEGIN
,
820 pattern_line
=LEXER_BUILD_LINE
,
821 pattern_end
=LEXER_BUILD_END
,
825 build
= DefaultLexer(lines
)
826 self
.build
.inherit(build
)
828 def parse_distro(self
):
829 keys
, lines
= self
.read_block(
830 pattern_start
=LEXER_DISTRO_BEGIN
,
831 pattern_line
=LEXER_DISTRO_LINE
,
832 pattern_end
=LEXER_DISTRO_END
,
836 distro
= DefaultLexer(lines
)
837 self
.distro
.inherit(distro
)
839 def parse_package(self
):
840 keys
, lines
= self
.read_block(
841 pattern_start
=LEXER_PACKAGE2_BEGIN
,
842 pattern_line
=LEXER_PACKAGE2_LINE
,
843 pattern_end
=LEXER_PACKAGE2_END
,
847 pkg
= DefaultLexer(lines
)
848 self
.package
.inherit(pkg
)
850 def parse_deps(self
):
851 keys
, lines
= self
.read_block(
852 pattern_start
=LEXER_DEPS_BEGIN
,
853 pattern_line
=LEXER_DEPS_LINE
,
854 pattern_end
=LEXER_DEPS_END
,
858 deps
= DefaultLexer(lines
)
859 self
.deps
.inherit(deps
)