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\s+([A-Za-z0-9_\-]+)\s*(\+)?=\s*(.+)?$")
80 LEXER_EXPORT2
= re
.compile(r
"^export\s+([A-Za-z0-9_\-]+)$")
81 LEXER_UNEXPORT
= re
.compile(r
"^unexport\s+([A-Za-z0-9_\-]+)$")
82 LEXER_INCLUDE
= re
.compile(r
"^include\s+(.+)$")
84 LEXER_VARIABLE
= re
.compile(r
"\%\{([A-Za-z0-9_\-]+)\}")
85 LEXER_SHELL
= re
.compile(r
"\%\(.*\)")
87 LEXER_IF_IF
= re
.compile(r
"^if\s+(.*)\s+(==|!=)\s+(.*)\s*")
88 LEXER_IF_ELIF
= re
.compile(r
"^elif\s+(.*)\s*(==|!=)\s*(.*)\s*")
89 LEXER_IF_ELSE
= re
.compile(r
"^else")
90 LEXER_IF_LINE
= LEXER_BLOCK_LINE
91 LEXER_IF_END
= LEXER_BLOCK_END
94 def __init__(self
, lines
=[], parent
=None, environ
=None):
100 # A place to store all definitions.
101 self
._definitions
= {}
103 # Init function that can be overwritten by child classes.
109 def inherit(self
, other
):
111 Inherit everything from other lexer.
113 self
._definitions
.update(other
._definitions
)
116 def definitions(self
):
117 return self
._definitions
120 def open(cls
, filename
, *args
, **kwargs
):
122 lines
= f
.readlines()
125 return cls(lines
, *args
, **kwargs
)
129 return self
._lineno
+ 1
134 return self
.parent
.root
138 def get_line(self
, no
, raw
=False):
140 line
= self
.lines
[no
]
145 line
= line
.rstrip("\n")
153 # strip comments - caution: quotations
155 if line
.startswith(LEXER_COMMENT_CHAR
):
158 # XXX fix removing of comments in lines
163 #for i in range(length):
166 # if s in LEXER_QUOTES:
172 # if s == LEXER_COMMENT_CHAR:
177 def line_is_empty(self
):
178 line
= self
.get_line(self
._lineno
)
180 m
= re
.match(LEXER_EMPTY_LINE
, line
)
186 def expand_string(self
, s
):
191 m
= re
.search(LEXER_VARIABLE
, s
)
196 s
= s
.replace("%%{%s}" % var
, self
.get_var(var
))
200 def get_var(self
, key
, default
=None):
202 definitions
.update(self
.root
.definitions
)
203 definitions
.update(self
.definitions
)
207 val
= definitions
[key
]
214 return self
.expand_string(val
)
216 def init(self
, environ
):
219 def get_default_parsers(self
):
221 (LEXER_COMMENT
, self
.parse_comment
),
222 (LEXER_DEFINITION
, self
.parse_definition
),
223 (LEXER_DEFINE_BEGIN
, self
.parse_define
),
224 (LEXER_IF_IF
, self
.parse_if
),
227 def get_parsers(self
):
230 def parse_line(self
):
232 if self
.line_is_empty():
236 line
= self
.get_line(self
._lineno
)
238 parsers
= self
.get_parsers() + self
.get_default_parsers()
241 for pattern
, func
in parsers
:
242 m
= re
.match(pattern
, line
)
244 # Hey, I found a match, we parse it with the subparser function.
251 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
253 def read_block(self
, pattern_start
=None, pattern_line
=None, pattern_end
=None,
259 line
= self
.get_line(self
._lineno
)
261 m
= re
.match(pattern_start
, line
)
265 # Go in to next line.
272 line
= self
.get_line(self
._lineno
, raw
=raw
)
274 m
= re
.match(pattern_end
, line
)
279 m
= re
.match(pattern_line
, line
)
281 lines
.append(m
.group(1))
285 m
= re
.match(LEXER_EMPTY_LINE
, line
)
291 if not line
.startswith(LEXER_BLOCK_LINE_INDENT
):
292 raise LexerError
, "Line has not the right indentation: %d: %s" \
293 % (self
.lineno
, line
)
295 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
297 return (groups
, lines
)
300 while self
._lineno
< len(self
.lines
):
303 def parse_comment(self
):
304 line
= self
.get_line(self
._lineno
)
309 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
311 def parse_definition(self
, pattern
=LEXER_DEFINITION
):
312 line
= self
.get_line(self
._lineno
)
314 m
= re
.match(pattern
, line
)
316 raise LexerError
, "Not a definition: %s" % line
318 # Line was correctly parsed, can go on.
324 prev
= self
.definitions
.get(k
, None)
325 if prev
is None and self
.parent
:
326 prev
= self
.parent
.definitions
.get(k
, None)
328 v
= " ".join((prev
or "", v
))
331 while v
and v
.endswith("\\"):
332 line
= self
.get_line(self
._lineno
)
337 self
._definitions
[k
] = v
341 def parse_define(self
):
342 line
= self
.get_line(self
._lineno
)
344 m
= re
.match(LEXER_DEFINE_BEGIN
, line
)
346 raise Exception, "XXX not a define"
348 # Check content of next line.
352 line
= self
.get_line(self
._lineno
+ i
)
355 empty
= re
.match(LEXER_EMPTY_LINE
, line
)
360 for pattern
in (LEXER_DEFINE_LINE
, LEXER_DEFINE_END
):
361 found
= re
.match(pattern
, line
)
369 line
= self
.get_line(self
._lineno
)
370 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
372 # Go in to next line.
380 line
= self
.get_line(self
._lineno
)
382 m
= re
.match(LEXER_DEFINE_END
, line
)
387 m
= re
.match(LEXER_DEFINE_LINE
, line
)
390 value
.append(m
.group(1))
393 m
= re
.match(LEXER_EMPTY_LINE
, line
)
399 raise LexerError
, "Unhandled line: %s" % line
401 self
._definitions
[key
] = "\n".join(value
)
403 def _parse_if_block(self
, first
=True):
404 line
= self
.get_line(self
._lineno
)
409 m
= re
.match(LEXER_IF_IF
, line
)
413 m
= re
.match(LEXER_IF_ELIF
, line
)
417 m
= re
.match(LEXER_IF_ELSE
, line
)
422 raise LexerError
, "No valid begin of if statement: %d: %s" \
423 % (self
.lineno
, line
)
430 while len(self
.lines
) >= self
._lineno
:
431 line
= self
.get_line(self
._lineno
)
433 for pattern
in (LEXER_IF_END
, LEXER_IF_ELIF
, LEXER_IF_ELSE
):
434 m
= re
.match(pattern
, line
)
442 m
= re
.match(LEXER_IF_LINE
, line
)
445 lines
.append("%s" % m
.groups())
448 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
451 raise LexerError
, "Unclosed if block"
453 return (clause
, lines
)
457 blocks
.append(self
._parse
_if
_block
(first
=True))
459 while len(self
.lines
) >= self
._lineno
:
460 line
= self
.get_line(self
._lineno
)
463 for pattern
in (LEXER_IF_ELIF
, LEXER_IF_ELSE
,):
464 m
= re
.match(pattern
, line
)
466 # Found another block.
468 blocks
.append(self
._parse
_if
_block
(first
=False))
475 line
= self
.get_line(self
._lineno
)
476 m
= re
.match(LEXER_IF_END
, line
)
478 raise LexerError
, "Unclosed if clause"
482 # Read in all blocks, now we evaluate each clause.
483 for clause
, lines
in blocks
:
489 # Remove leading and trailing "s and 's.
490 a
= a
.lstrip("\"'").rstrip("\"'")
491 b
= b
.lstrip("\"'").rstrip("\"'")
493 a
= self
.expand_string(a
)
494 b
= self
.expand_string(b
)
501 raise LexerError
, "Unknown operator: %s" % op
504 # Else is always true.
507 # If any clause is true, we can parse the block.
509 lexer
= self
.__class
__(lines
, parent
=self
)
514 class DefaultLexer(Lexer
):
516 A lexer which only knows about simple definitions.
521 class TemplateLexer(DefaultLexer
):
522 def init(self
, environ
):
523 # A place to store the scriptlets.
527 def definitions(self
):
531 definitions
.update(self
.parent
.definitions
)
532 definitions
.update(self
._definitions
)
536 def get_parsers(self
):
538 (LEXER_SCRIPTLET_BEGIN
, self
.parse_scriptlet
),
541 def parse_scriptlet(self
):
542 line
= self
.get_line(self
._lineno
)
544 m
= re
.match(LEXER_SCRIPTLET_BEGIN
, line
)
546 raise Exception, "Not a scriptlet"
552 # check if scriptlet was already defined.
553 if self
.scriptlets
.has_key(name
):
554 raise Exception, "Scriptlet %s is already defined" % name
558 self
.scriptlets
[name
] = {
560 "path" : self
.expand_string(path
),
566 line
= self
.get_line(self
._lineno
, raw
=True)
568 m
= re
.match(LEXER_SCRIPTLET_END
, line
)
573 m
= re
.match(LEXER_SCRIPTLET_LINE
, line
)
575 lines
.append(m
.group(1))
579 m
= re
.match(LEXER_EMPTY_LINE
, line
)
585 raise LexerUnhandledLine
, "%d: %s" % (self
.lineno
, line
)
587 self
.scriptlets
[name
] = {
589 "scriptlet" : "\n".join(lines
),
593 class PackageLexer(TemplateLexer
):
594 def init(self
, environ
):
595 TemplateLexer
.init(self
, environ
)
597 self
._template
= "MAIN"
599 assert isinstance(self
.parent
, PackagesLexer
) or \
600 isinstance(self
.parent
, PackageLexer
), self
.parent
603 def definitions(self
):
607 definitions
.update(self
.template
.definitions
)
609 definitions
.update(self
._definitions
)
615 if not self
._template
:
618 # Get template from parent.
620 return self
.root
.templates
[self
._template
]
622 raise LexerError
, "Template does not exist: %s" % self
._template
624 def get_parsers(self
):
626 (LEXER_PACKAGE_INHERIT
, self
.parse_inherit
),
627 ] + TemplateLexer
.get_parsers(self
)
631 def parse_inherit(self
):
632 line
= self
.get_line(self
._lineno
)
634 m
= re
.match(LEXER_PACKAGE_INHERIT
, line
)
636 raise LexerError
, "Not a template inheritance: %s" % line
640 self
._template
= m
.group(1)
642 # Check if template exists.
646 class ExportLexer(DefaultLexer
):
649 if not hasattr(self
.parent
, "exports"):
653 for export
in self
._exports
+ self
.parent
.exports
:
654 exports
.append(export
)
658 def init(self
, environ
):
659 # A list of variables that should be exported in the build
664 def get_parsers(self
):
666 (LEXER_EXPORT
, self
.parse_export
),
667 (LEXER_EXPORT2
, self
.parse_export2
),
668 (LEXER_UNEXPORT
, self
.parse_unexport
),
671 def inherit(self
, other
):
672 DefaultLexer
.inherit(self
, other
)
674 # Try to remove all unexported variables.
675 for unexport
in other
._unexports
:
677 self
._exports
.remove(unexport
)
681 for export
in other
._exports
:
682 if not export
in self
._exports
:
683 self
._exports
.append(export
)
685 def parse_export(self
):
686 k
, v
= self
.parse_definition(pattern
=LEXER_EXPORT
)
688 if k
and not k
in self
.exports
:
689 self
._exports
.append(k
)
691 def parse_export2(self
):
692 line
= self
.get_line(self
._lineno
)
695 m
= re
.match(LEXER_EXPORT2
, line
)
698 if k
and k
in self
.exports
:
699 self
._exports
.append(k
)
701 def parse_unexport(self
):
702 line
= self
.get_line(self
._lineno
)
705 m
= re
.match(LEXER_UNEXPORT
, line
)
708 if k
and k
in self
.exports
:
709 self
._exports
.remove(k
)
710 self
._unexports
.append(k
)
713 class BuildLexer(ExportLexer
):
716 return self
.definitions
719 class RootLexer(ExportLexer
):
720 def init(self
, environ
):
721 ExportLexer
.init(self
, environ
)
723 # A place to store all packages and templates.
724 self
.packages
= PackagesLexer([], parent
=self
)
726 # Import all environment variables.
728 for k
, v
in environ
.items():
729 self
._definitions
[k
] = v
731 self
.exports
.append(k
)
733 # Place for build instructions
734 self
.build
= BuildLexer([], parent
=self
)
736 # Include all macros.
738 for macro
in MACRO_FILES
:
741 def include(self
, file):
742 # Create a new lexer, and parse the whole file.
743 include
= RootLexer
.open(file, parent
=self
)
745 # Copy all data from the included file.
746 self
.inherit(include
)
748 def inherit(self
, other
):
750 Inherit everything from other lexer.
752 ExportLexer
.inherit(self
, other
)
754 self
._definitions
.update(other
._definitions
)
756 self
.build
.inherit(other
.build
)
757 self
.packages
.inherit(other
.packages
)
761 return self
.packages
.templates
763 def get_parsers(self
):
764 parsers
= ExportLexer
.get_parsers(self
)
766 (LEXER_INCLUDE
, self
.parse_include
),
767 (LEXER_PACKAGES_BEGIN
, self
.parse_packages
),
768 (LEXER_BUILD_BEGIN
, self
.parse_build
),
773 def parse_build(self
):
774 line
= self
.get_line(self
._lineno
)
776 m
= re
.match(LEXER_BUILD_BEGIN
, line
)
778 raise LexerError
, "Not a build statement: %s" % line
785 line
= self
.get_line(self
._lineno
)
787 m
= re
.match(LEXER_BUILD_END
, line
)
792 m
= re
.match(LEXER_BUILD_LINE
, line
)
794 lines
.append(m
.group(1))
797 # Accept empty lines.
798 m
= re
.match(LEXER_EMPTY_LINE
, line
)
804 build
= BuildLexer(lines
, parent
=self
)
805 self
.build
.inherit(build
)
807 def parse_include(self
):
808 line
= self
.get_line(self
._lineno
)
810 m
= re
.match(LEXER_INCLUDE
, line
)
812 raise LexerError
, "Not an include statement: %s" % line
814 # Get the filename from the line.
816 file = self
.expand_string(file)
818 # Include the content of the file.
821 # Go on to next line.
824 def parse_packages(self
):
825 keys
, lines
= self
.read_block(
826 pattern_start
=LEXER_PACKAGES_BEGIN
,
827 pattern_line
=LEXER_PACKAGES_LINE
,
828 pattern_end
=LEXER_PACKAGES_END
,
832 pkgs
= PackagesLexer(lines
, parent
=self
)
833 self
.packages
.inherit(pkgs
)
836 class PackagesLexer(DefaultLexer
):
837 def init(self
, environ
):
838 # A place to store all templates.
841 # A place to store all packages.
844 def inherit(self
, other
):
845 # Copy all templates and packages but make sure
846 # to update the parent lexer (for accessing each other).
847 for name
, template
in other
.templates
.items():
848 template
.parent
= self
849 self
.templates
[name
] = template
851 for pkg
in other
.packages
:
853 self
.packages
.append(pkg
)
856 return iter(self
.packages
)
858 def get_parsers(self
):
860 (LEXER_TEMPLATE_BEGIN
, self
.parse_template
),
861 (LEXER_PACKAGE_BEGIN
, self
.parse_package
),
864 def parse_template(self
):
865 line
= self
.get_line(self
._lineno
)
867 m
= re
.match(LEXER_TEMPLATE_BEGIN
, line
)
869 raise Exception, "Not a template"
871 # Line was correctly parsed, can go on.
878 line
= self
.get_line(self
._lineno
)
880 m
= re
.match(LEXER_TEMPLATE_END
, line
)
885 m
= re
.match(LEXER_TEMPLATE_LINE
, line
)
887 lines
.append(m
.group(1))
890 # Accept empty lines.
891 m
= re
.match(LEXER_EMPTY_LINE
, line
)
897 template
= TemplateLexer(lines
, parent
=self
)
898 self
.templates
[name
] = template
900 def parse_package(self
):
901 line
= self
.get_line(self
._lineno
)
903 m
= re
.match(LEXER_PACKAGE_BEGIN
, line
)
905 raise Exception, "Not a package: %s" %line
910 name
= self
.expand_string(name
)
912 m
= re
.match(LEXER_VALID_PACKAGE_NAME
, name
)
914 raise LexerError
, "Invalid package name: %s" % name
916 lines
= ["_name = %s" % name
]
919 while len(self
.lines
) > self
._lineno
:
920 line
= self
.get_line(self
._lineno
)
922 m
= re
.match(LEXER_PACKAGE_END
, line
)
928 m
= re
.match(LEXER_PACKAGE_LINE
, line
)
931 lines
.append(m
.group(1))
935 # Accept empty lines.
936 m
= re
.match(LEXER_EMPTY_LINE
, line
)
942 # If there is an unhandled line in a block, we raise an error.
944 raise Exception, "XXX unhandled line in package block: %s" % line
946 # If the block was never opened, we just go on.
951 raise LexerError
, "Unclosed package block '%s'." % name
953 package
= PackageLexer(lines
, parent
=self
)
954 self
.packages
.append(package
)
957 class FileLexer(DefaultLexer
):
958 def init(self
, environ
):
959 self
.build
= DefaultLexer()
960 self
.deps
= DefaultLexer()
961 self
.distro
= DefaultLexer()
962 self
.package
= DefaultLexer()
964 def get_parsers(self
):
966 (LEXER_BUILD_BEGIN
, self
.parse_build
),
967 (LEXER_DISTRO_BEGIN
, self
.parse_distro
),
968 (LEXER_PACKAGE2_BEGIN
, self
.parse_package
),
969 (LEXER_DEPS_BEGIN
, self
.parse_deps
),
972 def parse_build(self
):
973 keys
, lines
= self
.read_block(
974 pattern_start
=LEXER_BUILD_BEGIN
,
975 pattern_line
=LEXER_BUILD_LINE
,
976 pattern_end
=LEXER_BUILD_END
,
980 build
= DefaultLexer(lines
)
981 self
.build
.inherit(build
)
983 def parse_distro(self
):
984 keys
, lines
= self
.read_block(
985 pattern_start
=LEXER_DISTRO_BEGIN
,
986 pattern_line
=LEXER_DISTRO_LINE
,
987 pattern_end
=LEXER_DISTRO_END
,
991 distro
= DefaultLexer(lines
)
992 self
.distro
.inherit(distro
)
994 def parse_package(self
):
995 keys
, lines
= self
.read_block(
996 pattern_start
=LEXER_PACKAGE2_BEGIN
,
997 pattern_line
=LEXER_PACKAGE2_LINE
,
998 pattern_end
=LEXER_PACKAGE2_END
,
1002 pkg
= DefaultLexer(lines
)
1003 self
.package
.inherit(pkg
)
1005 def parse_deps(self
):
1006 keys
, lines
= self
.read_block(
1007 pattern_start
=LEXER_DEPS_BEGIN
,
1008 pattern_line
=LEXER_DEPS_LINE
,
1009 pattern_end
=LEXER_DEPS_END
,
1013 deps
= DefaultLexer(lines
)
1014 self
.deps
.inherit(deps
)