aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/python/qmk/keymap.py52
-rw-r--r--lib/python/qmk/makefile.py94
2 files changed, 67 insertions, 79 deletions
diff --git a/lib/python/qmk/keymap.py b/lib/python/qmk/keymap.py
index 1024f8fc6..113b885de 100644
--- a/lib/python/qmk/keymap.py
+++ b/lib/python/qmk/keymap.py
@@ -2,8 +2,6 @@
2""" 2"""
3import os 3import os
4from traceback import format_exc 4from traceback import format_exc
5import re
6import glob
7 5
8import qmk.path 6import qmk.path
9import qmk.makefile 7import qmk.makefile
@@ -100,27 +98,6 @@ def write(keyboard, keymap, layout, layers):
100 98
101 return keymap_file 99 return keymap_file
102 100
103def find_keymaps(base_path, revision = "", community = False):
104 """ Find the available keymaps for a keyboard and revision pair.
105
106 Args:
107 base_path: The base path of the keyboard.
108
109 revision: The keyboard's revision.
110
111 community: Set to True for the layouts under layouts/community.
112
113 Returns:
114 a set with the keymaps's names
115 """
116 path_wildcard = os.path.join(base_path, "**", "keymap.c")
117 if community:
118 path_regex = re.compile(r"^" + re.escape(base_path) + "(\S+)" + os.path.sep + "keymap\.c")
119 else:
120 path_regex = re.compile(r"^" + re.escape(base_path) + "(?:" + re.escape(revision) + os.path.sep + ")?keymaps" + os.path.sep + "(\S+)" + os.path.sep + "keymap\.c")
121 names = [path_regex.sub(lambda name: name.group(1), path) for path in glob.iglob(path_wildcard, recursive = True) if path_regex.search(path)]
122 return set(names)
123
124def list_keymaps(keyboard_name): 101def list_keymaps(keyboard_name):
125 """ List the available keymaps for a keyboard. 102 """ List the available keymaps for a keyboard.
126 103
@@ -130,25 +107,28 @@ def list_keymaps(keyboard_name):
130 Returns: 107 Returns:
131 a set with the names of the available keymaps 108 a set with the names of the available keymaps
132 """ 109 """
133 if os.path.sep in keyboard_name:
134 keyboard, revision = os.path.split(os.path.normpath(keyboard_name))
135 else:
136 keyboard = keyboard_name
137 revision = ""
138
139 # parse all the rules.mk files for the keyboard 110 # parse all the rules.mk files for the keyboard
140 rules_mk = qmk.makefile.get_rules_mk(keyboard, revision) 111 rules_mk = qmk.makefile.get_rules_mk(keyboard_name)
141 names = set() 112 names = set()
142 113
143 if rules_mk: 114 if rules_mk:
144 # get the keymaps from the keyboard's directory 115 # qmk_firmware/keyboards
145 kb_base_path = os.path.join(os.getcwd(), "keyboards", keyboard) + os.path.sep 116 keyboards_dir = os.path.join(os.getcwd(), "keyboards")
146 names = find_keymaps(kb_base_path, revision) 117 # path to the keyboard's directory
118 kb_path = os.path.join(keyboards_dir, keyboard_name)
119 # walk up the directory tree until keyboards_dir
120 # and collect all directories' name with keymap.c file in it
121 while kb_path != keyboards_dir:
122 keymaps_dir = os.path.join(kb_path, "keymaps")
123 if os.path.exists(keymaps_dir):
124 names = names.union([keymap for keymap in os.listdir(keymaps_dir) if os.path.isfile(os.path.join(keymaps_dir, keymap, "keymap.c"))])
125 kb_path = os.path.dirname(kb_path)
147 126
148 # if community layouts are supported, get them 127 # if community layouts are supported, get them
149 if "LAYOUTS" in rules_mk: 128 if "LAYOUTS" in rules_mk:
150 for layout in rules_mk["LAYOUTS"]["value"].split(): 129 for layout in rules_mk["LAYOUTS"].split():
151 cl_base_path = os.path.join(os.getcwd(), "layouts", "community", layout) + os.path.sep 130 cl_path = os.path.join(os.getcwd(), "layouts", "community", layout)
152 names = names.union(find_keymaps(cl_base_path, revision, community = True)) 131 if os.path.exists(cl_path):
132 names = names.union([keymap for keymap in os.listdir(cl_path) if os.path.isfile(os.path.join(cl_path, keymap, "keymap.c"))])
153 133
154 return sorted(names) 134 return sorted(names)
diff --git a/lib/python/qmk/makefile.py b/lib/python/qmk/makefile.py
index 6ed6b4b70..c53f12ac7 100644
--- a/lib/python/qmk/makefile.py
+++ b/lib/python/qmk/makefile.py
@@ -1,72 +1,80 @@
1""" Functions for working with Makefiles 1""" Functions for working with Makefiles
2""" 2"""
3import os 3import os
4import glob
5import re
6 4
7import qmk.path 5import qmk.path
8from qmk.errors import NoSuchKeyboardError 6from qmk.errors import NoSuchKeyboardError
9 7
10def parse_rules_mk(file_path): 8def parse_rules_mk_file(file, rules_mk=None):
11 """ Parse a rules.mk file 9 """Turn a rules.mk file into a dictionary.
12 10
13 Args: 11 Args:
14 file_path: path to the rules.mk file 12 file: path to the rules.mk file
13 rules_mk: already parsed rules.mk the new file should be merged with
15 14
16 Returns: 15 Returns:
17 a dictionary with the file's content 16 a dictionary with the file's content
18 """ 17 """
19 # regex to match lines uncommented lines and get the data 18 if not rules_mk:
20 # group(1) = option's name 19 rules_mk = {}
21 # group(2) = operator (eg.: '=', '+=')
22 # group(3) = value(s)
23 rules_mk_regex = re.compile(r"^\s*(\w+)\s*([\?\:\+\-]?=)\s*(\S.*?)(?=\s*(\#|$))")
24 parsed_file = dict()
25 mk_content = qmk.path.file_lines(file_path)
26 for line in mk_content:
27 found = rules_mk_regex.search(line)
28 if found:
29 parsed_file[found.group(1)] = dict(operator = found.group(2), value = found.group(3))
30 return parsed_file
31 20
32def merge_rules_mk_files(base, revision): 21 if os.path.exists(file):
33 """ Merge a keyboard revision's rules.mk file with 22 rules_mk_lines = qmk.path.file_lines(file)
34 the 'base' rules.mk file
35 23
36 Args: 24 for line in rules_mk_lines:
37 base: the base rules.mk file's content as dictionary 25 # Filter out comments
38 revision: the revision's rules.mk file's content as dictionary 26 if line.strip().startswith("#"):
27 continue
39 28
40 Returns: 29 # Strip in-line comments
41 a dictionary with the merged content 30 if '#' in line:
42 """ 31 line = line[:line.index('#')].strip()
43 return {**base, **revision} 32
33 if '=' in line:
34 # Append
35 if '+=' in line:
36 key, value = line.split('+=', 1)
37 if key.strip() not in rules_mk:
38 rules_mk[key.strip()] = value.strip()
39 else:
40 rules_mk[key.strip()] += ' ' + value.strip()
41 # Set if absent
42 elif "?=" in line:
43 key, value = line.split('?=', 1)
44 if key.strip() not in rules_mk:
45 rules_mk[key.strip()] = value.strip()
46 else:
47 if ":=" in line:
48 line.replace(":","")
49 key, value = line.split('=', 1)
50 rules_mk[key.strip()] = value.strip()
44 51
45def get_rules_mk(keyboard, revision = ""): 52 return rules_mk
53
54def get_rules_mk(keyboard):
46 """ Get a rules.mk for a keyboard 55 """ Get a rules.mk for a keyboard
47 56
48 Args: 57 Args:
49 keyboard: name of the keyboard 58 keyboard: name of the keyboard
50 revision: revision of the keyboard 59
60 Raises:
61 NoSuchKeyboardError: when the keyboard does not exists
51 62
52 Returns: 63 Returns:
53 a dictionary with the content of the rules.mk file 64 a dictionary with the content of the rules.mk file
54 """ 65 """
55 base_path = os.path.join(os.getcwd(), "keyboards", keyboard) + os.path.sep 66 # Start with qmk_firmware/keyboards
56 rules_mk = dict() 67 kb_path = os.path.join(os.getcwd(), "keyboards")
57 if os.path.exists(base_path + os.path.sep + revision): 68 # walk down the directory tree
58 rules_mk_path_wildcard = os.path.join(base_path, "**", "rules.mk") 69 # and collect all rules.mk files
59 rules_mk_regex = re.compile(r"^" + base_path + "(?:" + revision + os.path.sep + ")?rules.mk") 70 if os.path.exists(os.path.join(kb_path, keyboard)):
60 paths = [path for path in glob.iglob(rules_mk_path_wildcard, recursive = True) if rules_mk_regex.search(path)] 71 rules_mk = dict()
61 for file_path in paths: 72 for directory in keyboard.split(os.path.sep):
62 rules_mk[revision if revision in file_path else "base"] = parse_rules_mk(file_path) 73 kb_path = os.path.join(kb_path, directory)
74 rules_mk_path = os.path.join(kb_path, "rules.mk")
75 if os.path.exists(rules_mk_path):
76 rules_mk = parse_rules_mk_file(rules_mk_path, rules_mk)
63 else: 77 else:
64 raise NoSuchKeyboardError("The requested keyboard and/or revision does not exist.") 78 raise NoSuchKeyboardError("The requested keyboard and/or revision does not exist.")
65 79
66 # if the base or the revision directory does not contain a rules.mk
67 if len(rules_mk) == 1:
68 rules_mk = rules_mk[revision]
69 # if both directories contain rules.mk files
70 elif len(rules_mk) == 2:
71 rules_mk = merge_rules_mk_files(rules_mk["base"], rules_mk[revision])
72 return rules_mk 80 return rules_mk