Skip to content

Commit

Permalink
Add a globbing source statement
Browse files Browse the repository at this point in the history
'gsource' works like 'source', but takes a glob pattern and sources all
matching files. Works as a no-op if no files match, and hence doubles as
an include-if-exists function, similar to '-include' in 'make'.

Add a 'grsource' statement as well, mirroring 'rsource'.

Came up in #40.
  • Loading branch information
ulfalizer committed Mar 13, 2018
1 parent af29359 commit daac69d
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 6 deletions.
72 changes: 68 additions & 4 deletions kconfiglib.py
Expand Up @@ -313,8 +313,13 @@
functions just avoid printing 'if y' conditions to give cleaner output.
Kconfig extensions
==================
Kconfiglib implements two Kconfig extensions related to 'source':
'source' with relative path
===========================
---------------------------
The library implements a custom 'rsource' statement that allows to import
Kconfig file by specifying path relative to directory of the currently parsed
Expand Down Expand Up @@ -347,13 +352,34 @@
If absolute path is given to 'rsource' then it follows behavior of 'source'.
Globbed sourcing with 'gsource' and 'grsource'
----------------------------------------------
The 'gsource' statement works like 'source', but takes a glob pattern and
sources all matching Kconfig files. For example, the following statement might
source 'sub1/foofoofoo' and 'sub2/foobarfoo':
gsource "sub[12]/foo*foo"
The glob patterns accepted are the same as for the standard glob.glob()
function.
If no file matches the pattern, gsource is a no-op, and hence doubles as an
include-if-exists function when given a plain filename (similar to '-include'
in 'make'). It might help to think of the 'g' as "generalized" in that case.
'grsource' is the 'rsource' version of 'gsource' and globs relative to the
directory of the current Kconfig file.
Feedback
========
Send bug reports, suggestions, and questions to ulfalizer a.t Google's email
service, or open a ticket on the GitHub page.
"""
import errno
import glob
import os
import platform
import re
Expand Down Expand Up @@ -1822,7 +1848,7 @@ def _parse_block(self, end_token, parent, visible_if_deps, prev_node):

elif t0 == _T_SOURCE:
self._enter_file(self._expand_syms(self._expect_str_and_eol()))
prev_node = self._parse_block(None, # end_token
prev_node = self._parse_block(None, # end_token
parent,
visible_if_deps,
prev_node)
Expand All @@ -1833,12 +1859,44 @@ def _parse_block(self, end_token, parent, visible_if_deps, prev_node):
os.path.dirname(self._filename),
self._expand_syms(self._expect_str_and_eol())
))
prev_node = self._parse_block(None, # end_token
prev_node = self._parse_block(None, # end_token
parent,
visible_if_deps,
prev_node)
self._leave_file()

elif t0 in (_T_GSOURCE, _T_GRSOURCE):
pattern = self._expand_syms(self._expect_str_and_eol())
if t0 == _T_GRSOURCE:
# Relative gsource
pattern = os.path.join(os.path.dirname(self._filename),
pattern)

# If $srctree is set, glob relative to it
if self.srctree is not None:
pattern = os.path.join(self.srctree, pattern)

# Sort the glob results to ensure a consistent ordering of
# Kconfig symbols, which indirectly ensures a consistent
# ordering in e.g. .config files
for filename in sorted(glob.glob(pattern)):
if self.srctree is not None and not os.path.isabs(filename):
# Strip the $srctree prefix from the filename and let
# the normal $srctree logic find the file. This makes
# the globbed filenames appear without a $srctree
# prefix in MenuNode.filename, which is consistent with
# how 'source' and 'rsource' work. We get the same
# behavior as if the files had been 'source'd one by
# one.
filename = os.path.relpath(filename, self.srctree)

self._enter_file(filename)
prev_node = self._parse_block(None, # end_token
parent,
visible_if_deps,
prev_node)
self._leave_file()

elif t0 == end_token:
# We have reached the end of the block. Terminate the final
# node and return it.
Expand Down Expand Up @@ -4699,6 +4757,8 @@ def _check_choice_sanity(choice):
_T_EQUAL,
_T_GREATER,
_T_GREATER_EQUAL,
_T_GRSOURCE,
_T_GSOURCE,
_T_HELP,
_T_HEX,
_T_IF,
Expand All @@ -4725,7 +4785,7 @@ def _check_choice_sanity(choice):
_T_TRISTATE,
_T_UNEQUAL,
_T_VISIBLE,
) = range(45)
) = range(47)

# Public integers representing expression types
#
Expand Down Expand Up @@ -4759,6 +4819,8 @@ def _check_choice_sanity(choice):
"endif": _T_ENDIF,
"endmenu": _T_ENDMENU,
"env": _T_ENV,
"grsource": _T_GRSOURCE,
"gsource": _T_GSOURCE,
"help": _T_HELP,
"hex": _T_HEX,
"if": _T_IF,
Expand Down Expand Up @@ -4792,6 +4854,8 @@ def _check_choice_sanity(choice):
_T_BOOL,
_T_CHOICE,
_T_COMMENT,
_T_GRSOURCE,
_T_GSOURCE,
_T_HEX,
_T_INT,
_T_MAINMENU,
Expand Down
20 changes: 20 additions & 0 deletions tests/Klocation
Expand Up @@ -49,9 +49,29 @@ config _RSOURCED
string
default "_rsourced"

config _GSOURCED
string
default "_gsourced"

config _GRSOURCED
string
default "_grsourced"

# Expands to "tests/Klocation_sourced"
source "$TESTS_DIR_FROM_ENV/Klocation$_SOURCED"

# Expands to "sub/Klocation_rsourced"
rsource "$SUB_DIR_FROM_ENV/Klocation$_RSOURCED"

# Expands to "tests/*ub/Klocation_gsourced[12]", matching
# tests/sub/Klocation_gsourced{1,2}
gsource "$TESTS_DIR_FROM_ENV/*ub/Klocation$_GSOURCED[12]"

# Expands to "sub/Klocation_grsourced[12]", matching
# tests/sub/Klocation_grsourced{1,2}
grsource "$SUB_DIR_FROM_ENV/Klocation$_GRSOURCED[12]"

# No-op
gsource "nonexisting file"

config MULTI_DEF
1 change: 1 addition & 0 deletions tests/sub/Klocation_grsourced1
@@ -0,0 +1 @@
config MULTI_DEF
1 change: 1 addition & 0 deletions tests/sub/Klocation_grsourced2
@@ -0,0 +1 @@
config MULTI_DEF
1 change: 1 addition & 0 deletions tests/sub/Klocation_gsourced1
@@ -0,0 +1 @@
config MULTI_DEF
1 change: 1 addition & 0 deletions tests/sub/Klocation_gsourced2
@@ -0,0 +1 @@
config MULTI_DEF
8 changes: 6 additions & 2 deletions testsuite.py
Expand Up @@ -792,7 +792,7 @@ def verify_help(node, s):
""")


print("Testing locations and 'source', 'rsource'")
print("Testing locations and source/rsource/gsource/grsource")

def verify_locations(nodes, *expected_locs):
verify(len(nodes) == len(expected_locs),
Expand Down Expand Up @@ -823,7 +823,11 @@ def verify_locations(nodes, *expected_locs):
"tests/Klocation:31",
"tests/Klocation_sourced:3",
"tests/sub/Klocation_rsourced:2",
"tests/Klocation:57")
"tests/sub/Klocation_gsourced1:1",
"tests/sub/Klocation_gsourced2:1",
"tests/sub/Klocation_grsourced1:1",
"tests/sub/Klocation_grsourced2:1",
"tests/Klocation:77")

verify_locations(c.named_choices["CHOICE"].nodes,
"tests/Klocation_sourced:5")
Expand Down

0 comments on commit daac69d

Please sign in to comment.