keyboard stuff
1"""Helper functions for commands.
2"""
3import os
4import sys
5import shutil
6from pathlib import Path
7
8from milc import cli
9import jsonschema
10
11from qmk.constants import QMK_USERSPACE, HAS_QMK_USERSPACE
12from qmk.json_schema import json_load, validate
13from qmk.keyboard import keyboard_alias_definitions
14from qmk.util import maybe_exit
15from qmk.path import unix_style_path
16
17
18def find_make():
19 """Returns the correct make command for this environment.
20 """
21 make_cmd = os.environ.get('MAKE')
22
23 if not make_cmd:
24 make_cmd = 'gmake' if shutil.which('gmake') else 'make'
25
26 return make_cmd
27
28
29def get_make_parallel_args(parallel=1):
30 """Returns the arguments for running the specified number of parallel jobs.
31 """
32 parallel_args = []
33
34 if int(parallel) <= 0:
35 # 0 or -1 means -j without argument (unlimited jobs)
36 parallel_args.append('--jobs')
37 elif int(parallel) > 1:
38 parallel_args.append('--jobs=' + str(parallel))
39
40 if int(parallel) != 1:
41 # If more than 1 job is used, synchronize parallel output by target
42 parallel_args.append('--output-sync=target')
43
44 return parallel_args
45
46
47def parse_configurator_json(configurator_file):
48 """Open and parse a configurator json export
49 """
50 user_keymap = json_load(configurator_file)
51 # Validate against the jsonschema
52 try:
53 validate(user_keymap, 'qmk.keymap.v1')
54
55 except jsonschema.ValidationError as e:
56 cli.log.error(f'Invalid JSON keymap: {configurator_file} : {e.message}')
57 maybe_exit(1)
58
59 keyboard = user_keymap.get('keyboard', None)
60 aliases = keyboard_alias_definitions()
61
62 while keyboard in aliases:
63 last_keyboard = keyboard
64 keyboard = aliases[keyboard].get('target', keyboard)
65 if keyboard == last_keyboard:
66 break
67
68 user_keymap['keyboard'] = keyboard
69 return user_keymap
70
71
72def parse_env_vars(args):
73 """Common processing for cli.args.env
74 """
75 envs = {}
76 for env in args:
77 if '=' in env:
78 key, value = env.split('=', 1)
79 envs[key] = value
80 else:
81 cli.log.warning('Invalid environment variable: %s', env)
82 return envs
83
84
85def build_environment(args):
86 envs = parse_env_vars(args)
87
88 if HAS_QMK_USERSPACE:
89 envs['QMK_USERSPACE'] = unix_style_path(Path(QMK_USERSPACE).resolve())
90
91 return envs
92
93
94def in_virtualenv():
95 """Check if running inside a virtualenv.
96 Based on https://stackoverflow.com/a/1883251
97 """
98 active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
99 return active_prefix != sys.prefix
100
101
102def dump_lines(output_file, lines, quiet=True, remove_repeated_newlines=False):
103 """Handle dumping to stdout or file
104 Creates parent folders if required
105 """
106 generated = '\n'.join(lines) + '\n'
107 if remove_repeated_newlines:
108 while '\n\n\n' in generated:
109 generated = generated.replace('\n\n\n', '\n\n')
110 if output_file and output_file.name != '-':
111 output_file.parent.mkdir(parents=True, exist_ok=True)
112 if output_file.exists():
113 with open(output_file, 'r', encoding='utf-8', newline='\n') as f:
114 existing = f.read()
115 if existing == generated:
116 if not quiet:
117 cli.log.info(f'No changes to {output_file.name}.')
118 return
119 output_file.replace(output_file.parent / (output_file.name + '.bak'))
120 with open(output_file, 'w', encoding='utf-8', newline='\n') as f:
121 f.write(generated)
122 # output_file.write_text(generated, encoding='utf-8', newline='\n') # `newline` needs Python 3.10
123
124 if not quiet:
125 cli.log.info(f'Wrote {output_file.name} to {output_file}.')
126 else:
127 print(generated)