|
# babby's first real python code |
|
# this should be ran from within the qmk_firmware directory - where ever it is. |
|
|
|
from distutils.command.build import build |
|
import subprocess |
|
import os |
|
import argparse |
|
import shutil |
|
from datetime import datetime |
|
from argparse import RawDescriptionHelpFormatter |
|
|
|
helpString = """Script to aid in building multiple QMK firmware files based on input args. |
|
|
|
Run from within the /qmk_firmware/ directory. |
|
|
|
---Examples--- |
|
|
|
Basic |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py -h |
|
|
|
Compile all keyboard default keymaps within a keyboard directory |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush gh60 |
|
|
|
Compile all keyboards with specific keymap(s) within a keyboard directory |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush -km via |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush -km via default |
|
|
|
Compile specific keyboards with/without specific keymaps within a keyboard directory |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush -kb h87a h88 -km via |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush -kb h87a h88 h60 |
|
|
|
Compile and copy firmware files to specified folder |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush -km via -o ../firmware-files |
|
|
|
Test mode - only shows you which keyboard firmware files would have been compiled |
|
you@pc: ~/qmk_firmware$ python ../scripts/qmk_build.py hineybush -km via -t |
|
""" |
|
|
|
# input argument parser |
|
inputParser = argparse.ArgumentParser( |
|
description=helpString, formatter_class=RawDescriptionHelpFormatter) |
|
inputParser.add_argument('path', type=str, nargs='+', |
|
help="Directory of keyboard(s) to build. ex. \'hineybush\', \'gh60\'. Can run multiple keyboard directories at once") |
|
inputParser.add_argument('-km', '--keymap', type=str, nargs='*', |
|
help="Which keymap(s) to build. ex. \'default\', \'via\'. default = \'default\'", default=["default"]) |
|
inputParser.add_argument('-kb', '--keyboards', nargs="*", type=str, |
|
help="List of specific keyboards within the directory to build. ex. \'h87a\'. Default (blank) will build all within the specified path", default=["all"]) |
|
inputParser.add_argument('-o', '--outputdir', type=str, default='.', |
|
help="Directory to copy files to. ex. \'../firmware\'. Default will leave firmware files within the default QMK directory. Works for .hex and .bin', default='.'") |
|
inputParser.add_argument('-t', '--test', default=False, action='store_true', |
|
help="Enable test mode, will only show which keyboards would have been compiled") |
|
inputParser.add_argument('--no-test', dest='test', action='store_false', |
|
help="Normal operation mode, not needed") |
|
inputArgs = inputParser.parse_args() |
|
|
|
# board/user directory to look for |
|
inputPath = getattr(inputArgs, 'path') |
|
# keymap file(s) to build (default, via, etc) |
|
inputKeymap = getattr(inputArgs, 'keymap') |
|
# keyboards to build (blank or all, or specific ones) |
|
inputBoardList = getattr(inputArgs, 'keyboards') |
|
outputDir = getattr(inputArgs, 'outputdir') |
|
testStatus = getattr(inputArgs, 'test') |
|
|
|
buildList = [] # init empty list to fill with found keyboard files |
|
extensionList = ['.hex', '.bin'] |
|
|
|
# function to build the buildlist |
|
|
|
|
|
def listdirs(rootdir, kbPath): |
|
for a in rootdir: |
|
# get keyboard subdirectories from /keyboards/arg1 |
|
kbDir = os.path.join(kbPath, a) |
|
if os.path.isdir(kbDir): |
|
# go into each subdir, check for keymap files: |
|
for b in os.listdir(kbDir): |
|
dirInKbDir = os.path.join(kbDir, b) |
|
for c in inputKeymap: |
|
hopefulKeymapDir = f'{dirInKbDir}/{c}' |
|
# check if needed keymap dir exists |
|
if os.path.isdir(hopefulKeymapDir): |
|
# get path of needed keymap |
|
kbPathSplit = hopefulKeymapDir.split('/') |
|
# pull out keyboard and keymap name from path, add to overall name list |
|
buildList.append( |
|
f"{kbPathSplit[1]}/{kbPathSplit[2]}/{kbPathSplit[4]}") |
|
if buildList != []: |
|
print( |
|
f"-----\nFound the following keyboards to compile in {kbPath}: {os.linesep}{os.linesep.join(map(str, buildList))}") |
|
else: |
|
print( |
|
f"-----\nWarning! Did not find any keyboards in {kbPath} with keyboard(s) {', '.join(map(str,inputBoardList))} or keymap(s) {', '.join(map(str,inputKeymap))}") |
|
return buildList |
|
|
|
# function to build the buildlist per keymap folder |
|
|
|
|
|
def kmListDirs(rootdir): |
|
kbPath = f"keyboards/{rootdir}" |
|
if inputBoardList == ['all']: |
|
q = os.listdir(kbPath) |
|
else: |
|
q = inputBoardList |
|
listdirs(q, kbPath) |
|
return buildList |
|
|
|
# function to run qmk compile |
|
|
|
|
|
def qmkBuild(buildlist): |
|
for b in buildlist: # concat the qmk compile command with buildList info |
|
kbDir = b.split('/')[0] |
|
kb = b.split('/')[1] |
|
km = b.split('/')[2] |
|
fullCmd = f"qmk compile -j 0 -kb {kbDir}/{kb} -km {km}" |
|
# run fullCmd in bash, quietly |
|
subprocess.run(fullCmd, shell=True, check=True, |
|
text=True, stdout=subprocess.DEVNULL) |
|
|
|
# copies newly compiled firmware files to specified output folder |
|
|
|
|
|
def copyToOutput(buildlist, outputDir): |
|
filesToCopy = [] |
|
for b in buildlist: # concat the filenames with buildList info |
|
kbDir = b.split('/')[0] |
|
kb = b.split('/')[1] |
|
km = b.split('/')[2] |
|
for c in extensionList: |
|
fwfilename = f"{kbDir}_{kb}_{km}{c}" |
|
for d in os.listdir('.'): |
|
if (os.path.isfile(fwfilename) and (d == fwfilename)): |
|
filesToCopy.append(d) |
|
for e in filesToCopy: |
|
print(f"Copying {e} to: {outputDir}") |
|
shutil.copy(e, outputDir) |
|
|
|
def mainCycle(input): |
|
for a in input: |
|
# empty buildlist from previous runs, if any (needed for multi keyboard/dir use) |
|
buildList = [] |
|
kmListDirs(a) |
|
return buildList |
|
|
|
# main code |
|
|
|
|
|
# get time of exec start (unused tbh) |
|
exectime = datetime.now() |
|
dt_string = exectime.strftime("%d/%m/%Y %H:%M:%S") |
|
|
|
if testStatus == False: |
|
mainCycle(inputPath) |
|
print("-----") |
|
qmkBuild(buildList) |
|
if outputDir != '.': |
|
copyToOutput(buildList, outputDir) |
|
else: |
|
print("Firmware files saved in default QMK directory.") |
|
else: |
|
mainCycle(inputPath) |
|
print("-----\nTest run only, did not compile!") |
|
if outputDir != '.': |
|
print(f"Output firmware files would have been copied to {outputDir}") |
|
else: |
|
print(f"Output firmware files would have been copied to default QMK directory") |
|
print("-----\nDone!") |