aboutsummaryrefslogtreecommitdiff
path: root/lib/python/qmk/commands.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python/qmk/commands.py')
-rw-r--r--lib/python/qmk/commands.py165
1 files changed, 137 insertions, 28 deletions
diff --git a/lib/python/qmk/commands.py b/lib/python/qmk/commands.py
index 3a35c1103..421453d83 100644
--- a/lib/python/qmk/commands.py
+++ b/lib/python/qmk/commands.py
@@ -2,6 +2,7 @@
2""" 2"""
3import json 3import json
4import os 4import os
5import sys
5import shutil 6import shutil
6from pathlib import Path 7from pathlib import Path
7from subprocess import DEVNULL 8from subprocess import DEVNULL
@@ -10,7 +11,7 @@ from time import strftime
10from milc import cli 11from milc import cli
11 12
12import qmk.keymap 13import qmk.keymap
13from qmk.constants import KEYBOARD_OUTPUT_PREFIX 14from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX
14from qmk.json_schema import json_load 15from qmk.json_schema import json_load
15 16
16time_fmt = '%Y-%m-%d-%H:%M:%S' 17time_fmt = '%Y-%m-%d-%H:%M:%S'
@@ -51,7 +52,7 @@ def create_make_target(target, parallel=1, **env_vars):
51 for key, value in env_vars.items(): 52 for key, value in env_vars.items():
52 env.append(f'{key}={value}') 53 env.append(f'{key}={value}')
53 54
54 return [make_cmd, '-j', str(parallel), *env, target] 55 return [make_cmd, *get_make_parallel_args(parallel), *env, target]
55 56
56 57
57def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars): 58def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars):
@@ -86,11 +87,17 @@ def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars):
86 return create_make_target(':'.join(make_args), parallel, **env_vars) 87 return create_make_target(':'.join(make_args), parallel, **env_vars)
87 88
88 89
89def get_git_version(repo_dir='.', check_dir='.'): 90def get_git_version(current_time, repo_dir='.', check_dir='.'):
90 """Returns the current git version for a repo, or the current time. 91 """Returns the current git version for a repo, or the current time.
91 """ 92 """
92 git_describe_cmd = ['git', 'describe', '--abbrev=6', '--dirty', '--always', '--tags'] 93 git_describe_cmd = ['git', 'describe', '--abbrev=6', '--dirty', '--always', '--tags']
93 94
95 if repo_dir != '.':
96 repo_dir = Path('lib') / repo_dir
97
98 if check_dir != '.':
99 check_dir = repo_dir / check_dir
100
94 if Path(check_dir).exists(): 101 if Path(check_dir).exists():
95 git_describe = cli.run(git_describe_cmd, stdin=DEVNULL, cwd=repo_dir) 102 git_describe = cli.run(git_describe_cmd, stdin=DEVNULL, cwd=repo_dir)
96 103
@@ -100,23 +107,58 @@ def get_git_version(repo_dir='.', check_dir='.'):
100 else: 107 else:
101 cli.log.warn(f'"{" ".join(git_describe_cmd)}" returned error code {git_describe.returncode}') 108 cli.log.warn(f'"{" ".join(git_describe_cmd)}" returned error code {git_describe.returncode}')
102 print(git_describe.stderr) 109 print(git_describe.stderr)
103 return strftime(time_fmt) 110 return current_time
111
112 return current_time
113
114
115def get_make_parallel_args(parallel=1):
116 """Returns the arguments for running the specified number of parallel jobs.
117 """
118 parallel_args = []
119
120 if int(parallel) <= 0:
121 # 0 or -1 means -j without argument (unlimited jobs)
122 parallel_args.append('--jobs')
123 else:
124 parallel_args.append('--jobs=' + str(parallel))
125
126 if int(parallel) != 1:
127 # If more than 1 job is used, synchronize parallel output by target
128 parallel_args.append('--output-sync=target')
104 129
105 return strftime(time_fmt) 130 return parallel_args
106 131
107 132
108def write_version_h(git_version, build_date, chibios_version, chibios_contrib_version): 133def create_version_h(skip_git=False, skip_all=False):
109 """Generate and write quantum/version.h 134 """Generate version.h contents
110 """ 135 """
111 version_h = [ 136 if skip_all:
112 f'#define QMK_VERSION "{git_version}"', 137 current_time = "1970-01-01-00:00:00"
113 f'#define QMK_BUILDDATE "{build_date}"', 138 else:
114 f'#define CHIBIOS_VERSION "{chibios_version}"', 139 current_time = strftime(time_fmt)
115 f'#define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"', 140
116 ] 141 if skip_git:
142 git_version = "NA"
143 chibios_version = "NA"
144 chibios_contrib_version = "NA"
145 else:
146 git_version = get_git_version(current_time)
147 chibios_version = get_git_version(current_time, "chibios", "os")
148 chibios_contrib_version = get_git_version(current_time, "chibios-contrib", "os")
149
150 version_h_lines = f"""/* This file was automatically generated. Do not edit or copy.
151 */
152
153#pragma once
154
155#define QMK_VERSION "{git_version}"
156#define QMK_BUILDDATE "{current_time}"
157#define CHIBIOS_VERSION "{chibios_version}"
158#define CHIBIOS_CONTRIB_VERSION "{chibios_contrib_version}"
159"""
117 160
118 version_h_file = Path('quantum/version.h') 161 return version_h_lines
119 version_h_file.write_text('\n'.join(version_h))
120 162
121 163
122def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_vars): 164def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_vars):
@@ -149,13 +191,8 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va
149 keymap_dir.mkdir(exist_ok=True, parents=True) 191 keymap_dir.mkdir(exist_ok=True, parents=True)
150 keymap_c.write_text(c_text) 192 keymap_c.write_text(c_text)
151 193
152 # Write the version.h file 194 version_h = Path('quantum/version.h')
153 git_version = get_git_version() 195 version_h.write_text(create_version_h())
154 build_date = strftime('%Y-%m-%d-%H:%M:%S')
155 chibios_version = get_git_version("lib/chibios", "lib/chibios/os")
156 chibios_contrib_version = get_git_version("lib/chibios-contrib", "lib/chibios-contrib/os")
157
158 write_version_h(git_version, build_date, chibios_version, chibios_contrib_version)
159 196
160 # Return a command that can be run to make the keymap and flash if given 197 # Return a command that can be run to make the keymap and flash if given
161 verbose = 'true' if cli.config.general.verbose else 'false' 198 verbose = 'true' if cli.config.general.verbose else 'false'
@@ -166,8 +203,7 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va
166 make_command.append('-s') 203 make_command.append('-s')
167 204
168 make_command.extend([ 205 make_command.extend([
169 '-j', 206 *get_make_parallel_args(parallel),
170 str(parallel),
171 '-r', 207 '-r',
172 '-R', 208 '-R',
173 '-f', 209 '-f',
@@ -181,10 +217,6 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va
181 make_command.append(f'{key}={value}') 217 make_command.append(f'{key}={value}')
182 218
183 make_command.extend([ 219 make_command.extend([
184 f'GIT_VERSION={git_version}',
185 f'BUILD_DATE={build_date}',
186 f'CHIBIOS_VERSION={chibios_version}',
187 f'CHIBIOS_CONTRIB_VERSION={chibios_contrib_version}',
188 f'KEYBOARD={user_keymap["keyboard"]}', 220 f'KEYBOARD={user_keymap["keyboard"]}',
189 f'KEYMAP={user_keymap["keymap"]}', 221 f'KEYMAP={user_keymap["keymap"]}',
190 f'KEYBOARD_FILESAFE={keyboard_filesafe}', 222 f'KEYBOARD_FILESAFE={keyboard_filesafe}',
@@ -223,3 +255,80 @@ def parse_configurator_json(configurator_file):
223 user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']] 255 user_keymap['layout'] = aliases[orig_keyboard]['layouts'][user_keymap['layout']]
224 256
225 return user_keymap 257 return user_keymap
258
259
260def git_get_username():
261 """Retrieves user's username from Git config, if set.
262 """
263 git_username = cli.run(['git', 'config', '--get', 'user.name'])
264
265 if git_username.returncode == 0 and git_username.stdout:
266 return git_username.stdout.strip()
267
268
269def git_check_repo():
270 """Checks that the .git directory exists inside QMK_HOME.
271
272 This is a decent enough indicator that the qmk_firmware directory is a
273 proper Git repository, rather than a .zip download from GitHub.
274 """
275 dot_git_dir = QMK_FIRMWARE / '.git'
276
277 return dot_git_dir.is_dir()
278
279
280def git_get_branch():
281 """Returns the current branch for a repo, or None.
282 """
283 git_branch = cli.run(['git', 'branch', '--show-current'])
284 if not git_branch.returncode != 0 or not git_branch.stdout:
285 # Workaround for Git pre-2.22
286 git_branch = cli.run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
287
288 if git_branch.returncode == 0:
289 return git_branch.stdout.strip()
290
291
292def git_is_dirty():
293 """Returns 1 if repo is dirty, or 0 if clean
294 """
295 git_diff_staged_cmd = ['git', 'diff', '--quiet']
296 git_diff_unstaged_cmd = [*git_diff_staged_cmd, '--cached']
297
298 unstaged = cli.run(git_diff_staged_cmd)
299 staged = cli.run(git_diff_unstaged_cmd)
300
301 return unstaged.returncode != 0 or staged.returncode != 0
302
303
304def git_get_remotes():
305 """Returns the current remotes for a repo.
306 """
307 remotes = {}
308
309 git_remote_show_cmd = ['git', 'remote', 'show']
310 git_remote_get_cmd = ['git', 'remote', 'get-url']
311
312 git_remote_show = cli.run(git_remote_show_cmd)
313 if git_remote_show.returncode == 0:
314 for name in git_remote_show.stdout.splitlines():
315 git_remote_name = cli.run([*git_remote_get_cmd, name])
316 remotes[name.strip()] = {"url": git_remote_name.stdout.strip()}
317
318 return remotes
319
320
321def git_check_deviation(active_branch):
322 """Return True if branch has custom commits
323 """
324 cli.run(['git', 'fetch', 'upstream', active_branch])
325 deviations = cli.run(['git', '--no-pager', 'log', f'upstream/{active_branch}...{active_branch}'])
326 return bool(deviations.returncode)
327
328
329def in_virtualenv():
330 """Check if running inside a virtualenv.
331 Based on https://stackoverflow.com/a/1883251
332 """
333 active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
334 return active_prefix != sys.prefix