Compare commits

..

15 Commits

Author SHA1 Message Date
QMK Bot 6a928e9322 New release: 0.3.4 → 0.3.5 2021-08-13 18:26:21 +00:00
QMK Bot 5315431058 New release: 0.3.3 → 0.3.4 2021-08-13 18:07:41 +00:00
Zach White aa11928c03 remove extraneous backticks 2021-08-12 11:38:48 -07:00
Zach White 369c3e150a document building and packages in the readme 2021-08-12 11:18:15 -07:00
Zach White c4e82e0740 only trigger fedora32 2021-08-12 10:40:51 -07:00
QMK Bot 95152b6f7f New release: 0.3.2 → 0.3.3 2021-08-12 17:27:08 +00:00
Zach White 3bd1a79bfa fix ref for trigger 2021-08-12 10:25:27 -07:00
QMK Bot 42fcfc3930 New release: 0.3.1 → 0.3.2 2021-08-12 17:22:35 +00:00
Zach White 60f2bb743d Move bumpversion config to .bumpversion.cfg
It seems that bumpversion only bumps the first match in a file,
with no way I can find to get around that. This works around the
problem so that bumpversion works in our setup.py-less world.
2021-08-12 10:18:13 -07:00
Zach White f8902bd258 fix setup.cfg version 2021-08-12 10:12:58 -07:00
QMK Bot f7125127f1 New release: 0.3.0 → 0.3.1 2021-08-12 17:05:55 +00:00
Zach White f8fe363999 Modernize the qmk_cli package (#91)
* bring our package into the future

* trigger the OS packages upon a successful build

* fix windows

* trim deps

* remove the qmk_cli module from setup
2021-08-12 09:53:28 -07:00
QMK Bot bbd667e30c New release: 0.2.2 → 0.3.0 2021-08-11 02:54:39 +00:00
dependabot[bot] 32506bf1bb Bump milc from 1.4.2 to 1.5.0 (#90)
Bumps [milc](https://github.com/clueboard/milc) from 1.4.2 to 1.5.0.
- [Release notes](https://github.com/clueboard/milc/releases)
- [Commits](https://github.com/clueboard/milc/compare/1.4.2...1.5.0)

---
updated-dependencies:
- dependency-name: milc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-10 19:46:28 -07:00
Zach White 45a231af0c Add qmk console to the global cli (#84)
* add qmk console to the global cli

* lazy load hid and usb.core

* lazy load hid and usb.core
2021-08-10 11:25:00 -07:00
16 changed files with 512 additions and 314 deletions
+12
View File
@@ -0,0 +1,12 @@
[bumpversion]
current_version = 0.3.5
commit = True
tag = True
tag_name = {new_version}
message = New release: {current_version} → {new_version}
[bumpversion:file:.bumpversion.cfg]
[bumpversion:file:qmk_cli/__init__.py]
[bumpversion:file:setup.cfg]
+4 -5
View File
@@ -44,14 +44,13 @@ jobs:
- name: (MSYS2) Install Python dependencies
shell: msys2 {0}
run: |
python3 -m pip install wheel
python3 -m pip install -U setuptools wheel
- name: (MSYS2) Install QMK CLI from source
shell: msys2 {0}
run: |
python3 -m pip install -r requirements.txt
python3 setup.py sdist bdist_wheel
cd ..
python3 -m pip install --force-reinstall --no-index --no-deps --find-links qmk_cli/dist qmk
python3 -m pip install -U build
python3 -m build
python3 -m pip install dist/qmk-*.tar.gz
- name: (MSYS2) Run qmk setup -y
shell: msys2 {0}
run: qmk setup -y
+12 -72
View File
@@ -13,112 +13,52 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
# Environment Setup
- name: Set up Python
uses: actions/setup-python@v2.2.2
with:
python-version: '3.7'
- name: Run ci_tests
run: ./ci_tests
- name: Install system dependencies
- name: Install dependencies
run: |
apt-get update
apt-get install devscripts equivs sphinx-common sphinx-rtd-theme-common # dh-virtualenv deps
apt-get install debhelper dh-python python3-all # stdeb deps
apt-get install dpkg-sig # signing deps
- name: Install dh-virtualenv
run: |
git clone https://github.com/spotify/dh-virtualenv.git
cd dh-virtualenv
mk-build-deps -ri
dpkg-buildpackage -us -uc -b
cd ..
dpkg -i dh-virtualenv_*.deb
- name: Install GPG secret key
run: |
echo -e "${{ secrets.QMK_GPG_SECRET_KEY }}" | gpg --batch --import
gpg --list-secret-keys --keyid-format LONG
- name: Install python dependencies
run: |
python -m pip install --upgrade pip
python3 -m pip install --upgrade pip
pip install setuptools wheel
pip install -r requirements-dev.txt
- name: Log in to Docker Hub
uses: docker/login-action@v1.10.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
# Build and upload new Python package
- name: Bump version
run: |
git config --local user.email "hello@qmk.fm"
git config --local user.name "QMK Bot"
bumpversion ${{ github.event.inputs.version_part }}
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: master
tags: true
- name: Build and publish
env:
TWINE_USERNAME: qmk
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
python3 -m build
twine upload dist/*
# Build and upload new Docker container
- name: Log in to Docker Hub
uses: docker/login-action@v1.10.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Build and Push to Docker Hub
uses: docker/build-push-action@v2.6.1
with:
context: .
push: true
tags: qmkfm/qmk_cli:latest
# Build Debian package
- name: Build debian package
run: |
python3 setup.py bdist_deb
dpkg-sig -s builder -k F464DFD46C4DA3FD4D06234691B06358D2CAE8AE deb_dist/*.deb
# Create Debian repo
- name: Build debian package repository
run: |
mkdir -p deb_repo/deb deb_repo/dsc
cp gpg_pubkey.txt deb_repo
cp deb_dist/*.deb deb_repo/deb
cp deb_dist/*.dsc deb_dist/*.orig.tar.gz deb_dist/*.debian.tar.xz deb_repo/dsc
cd deb_repo
apt-ftparchive packages deb > Packages
apt-ftparchive sources dsc > Sources
gzip -k {Packages,Sources}
apt-ftparchive release . > Release
gpg --default-key F464DFD46C4DA3FD4D06234691B06358D2CAE8AE -abs -o Release.gpg Release
gpg --default-key F464DFD46C4DA3FD4D06234691B06358D2CAE8AE --clearsign -o InRelease Release
# Upload the Debian repo to S3
- name: Upload Debian Repo
uses: jakejarvis/s3-sync-action@0.5.1
with:
args: --acl public-read --follow-symlinks --delete
- name: Trigger OS package builds
run: ./trigger_packages
env:
AWS_S3_BUCKET: qmk-debian
AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_KEY }}
AWS_S3_ENDPOINT: https://nyc3.digitaloceanspaces.com
SOURCE_DIR: 'deb_repo'
QMK_BOT_TOKEN: ${{ secrets.QMK_BOT_TOKEN }}
-5
View File
@@ -106,8 +106,3 @@ venv.bak/
# QMK
qmk_firmware
# Debian packages
deb_dist
deb_repo
qmk-*.tar.gz
+36 -1
View File
@@ -8,17 +8,52 @@ A program to help users work with [QMK Firmware](https://qmk.fm/).
* Interact with your qmk_firmware tree from any location
* Use `qmk clone` to pull down anyone's `qmk_firmware` fork
* Setup your build environment with `qmk setup`
* Use `qmk console` to get debugging information from your keyboard(s)
* Check that your environment is correctly setup with `qmk doctor`
* Integrates with qmk_firmware for additional functionality:
* `qmk compile`
* `qmk console`
* `qmk info`
* `qmk flash`
* `qmk lint`
* ...and many more!
# Packages
We provide "install and go" packages for many Operating Systems.
## Linux
Packages for several distributions available here: https://github.com/qmk/qmk_fpm
## macOS
Using [Homebrew](https://brew.sh):
brew install qmk/qmk/qmk
## Windows
Download our custom MSYS2 installer here: https://msys.qmk.fm/
# Quickstart
* `python3 -m pip install qmk`
* `qmk setup`
# Building
We follow PEP517, you can install using [build](https://pypi.org/project/build/):
Setup:
python3 -m pip install build
Build:
python3 -m build
You can read more about working with PEP517 packages in the [Python Packaging User Guide](https://packaging.python.org/guides/distributing-packages-using-setuptools/#packaging-your-project).
# Documentation
Full documentation: <https://docs.qmk.fm/#/tutorial>
-65
View File
@@ -1,65 +0,0 @@
# Atmel DFU
### ATmega16U2
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2fef", TAG+="uaccess"
### ATmega32U2
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff0", TAG+="uaccess"
### ATmega16U4
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff3", TAG+="uaccess"
### ATmega32U4
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff4", TAG+="uaccess"
### AT90USB64
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ff9", TAG+="uaccess"
### AT90USB162
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffa", TAG+="uaccess"
### AT90USB128
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2ffb", TAG+="uaccess"
# Input Club
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1c11", ATTRS{idProduct}=="b007", TAG+="uaccess"
# STM32duino
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="0003", TAG+="uaccess"
# STM32 DFU
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", TAG+="uaccess"
# BootloadHID
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", TAG+="uaccess"
# USBAspLoader
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", TAG+="uaccess"
# ModemManager should ignore the following devices
# Atmel SAM-BA (Massdrop)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
# Caterina (Pro Micro)
## Spark Fun Electronics
### Pro Micro 3V3/8MHz
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9203", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
### Pro Micro 5V/16MHz
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9205", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
### LilyPad 3V3/8MHz (and some Pro Micro clones)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b4f", ATTRS{idProduct}=="9207", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
## Pololu Electronics
### A-Star 32U4
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1ffb", ATTRS{idProduct}=="0101", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
## Arduino SA
### Leonardo
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
### Micro
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
## Adafruit Industries LLC
### Feather 32U4
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000c", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
### ItsyBitsy 32U4 3V3/8MHz
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000d", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
### ItsyBitsy 32U4 5V/16MHz
SUBSYSTEMS=="usb", ATTRS{idVendor}=="239a", ATTRS{idProduct}=="000e", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
## dog hunter AG
### Leonardo
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0036", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
### Micro
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="0037", TAG+="uaccess", ENV{ID_MM_DEVICE_IGNORE}="1"
# hid_listen
KERNEL=="hidraw*", MODE="0660", GROUP="plugdev", TAG+="uaccess", TAG+="udev-acl"
-3
View File
@@ -1,3 +0,0 @@
Files: *
Copyright: 2019-2021 Zach White, et al
License: expat
-52
View File
@@ -1,52 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=t1lg
-----END PGP PUBLIC KEY BLOCK-----
+6
View File
@@ -0,0 +1,6 @@
[build-system]
requires = [
"setuptools>=42",
"wheel"
]
build-backend = "setuptools.build_meta"
+1 -1
View File
@@ -1,3 +1,3 @@
"""A program to help you work with qmk_firmware."""
__version__ = '0.2.2'
__version__ = '0.3.5'
+1
View File
@@ -3,5 +3,6 @@
We list each subcommand here explicitly because all the reliable ways of searching for modules are slow and delay startup.
"""
from . import clone # noqa
from . import console # noqa
from . import env # noqa
from . import setup # noqa
+358
View File
@@ -0,0 +1,358 @@
"""Acquire debugging information from usb hid devices
cli implementation of https://www.pjrc.com/teensy/hid_listen.html
"""
from functools import lru_cache
from pathlib import Path
from platform import platform
from threading import Thread
from time import sleep, strftime
from milc import cli
from milc.questions import yesno
LOG_COLOR = {
'next': 0,
'colors': [
'{fg_blue}',
'{fg_cyan}',
'{fg_green}',
'{fg_magenta}',
'{fg_red}',
'{fg_yellow}',
],
}
KNOWN_BOOTLOADERS = {
# VID , PID
('03EB', '2FEF'): 'atmel-dfu: ATmega16U2',
('03EB', '2FF0'): 'atmel-dfu: ATmega32U2',
('03EB', '2FF3'): 'atmel-dfu: ATmega16U4',
('03EB', '2FF4'): 'atmel-dfu: ATmega32U4',
('03EB', '2FF9'): 'atmel-dfu: AT90USB64',
('03EB', '2FFA'): 'atmel-dfu: AT90USB162',
('03EB', '2FFB'): 'atmel-dfu: AT90USB128',
('03EB', '6124'): 'Microchip SAM-BA',
('0483', 'DF11'): 'stm32-dfu: STM32 BOOTLOADER',
('16C0', '05DC'): 'USBasp: USBaspLoader',
('16C0', '05DF'): 'bootloadHID: HIDBoot',
('16C0', '0478'): 'halfkay: Teensy Halfkay',
('1B4F', '9203'): 'caterina: Pro Micro 3.3V',
('1B4F', '9205'): 'caterina: Pro Micro 5V',
('1B4F', '9207'): 'caterina: LilyPadUSB',
('1C11', 'B007'): 'kiibohd: Kiibohd DFU Bootloader',
('1EAF', '0003'): 'stm32duino: Maple 003',
('1FFB', '0101'): 'caterina: Polou A-Star 32U4 Bootloader',
('2341', '0036'): 'caterina: Arduino Leonardo',
('2341', '0037'): 'caterina: Arduino Micro',
('239A', '000C'): 'caterina: Adafruit Feather 32U4',
('239A', '000D'): 'caterina: Adafruit ItsyBitsy 32U4 3v',
('239A', '000E'): 'caterina: Adafruit ItsyBitsy 32U4 5v',
('239A', '000E'): 'caterina: Adafruit ItsyBitsy 32U4 5v',
('2A03', '0036'): 'caterina: Arduino Leonardo',
('2A03', '0037'): 'caterina: Arduino Micro',
('314B', '0106'): 'apm32-dfu: APM32 DFU ISP Mode'
}
def install_deps():
"""Install the necessary dependencies for qmk console.
"""
this_platform = platform().lower()
if 'darwin' in this_platform or 'macos' in this_platform:
command = ['brew', 'install', 'hidapi']
elif 'linux' in this_platform:
command = ['sudo', 'apt', 'install', '-y', 'libhidapi-hidraw0', 'libusb-dev']
elif 'windows' in this_platform:
command = ['pacboy', 'sync', '--needed', '--noconfirm', '--disable-download-timeout', 'hidapi:x']
else:
cli.log.error('Unsupported platform: %s', this_platform)
if yesno("Would you like to run `%s` to install the necessary package?", ' '.join(command)):
cli.run(command, capture_output=False)
return True
@lru_cache(maxsize=0)
def import_usb_core():
"""Attempts to import the usb.core module.
"""
try:
import usb.core
return usb.core
except ImportError as e:
cli.log.error('Could not import usb.core: %s', e)
if install_deps():
return import_usb_core()
raise
def import_hid():
"""Attempts to import the hid module.
"""
try:
import hid
return hid
except ImportError as e:
cli.log.error('Could not import hid: %s', e)
if install_deps():
return import_hid()
raise
class MonitorDevice(object):
def __init__(self, hid_device, numeric):
self.hid = import_hid()
self.hid_device = hid_device
self.numeric = numeric
self.device = self.hid.Device(path=hid_device['path'])
self.current_line = ''
cli.log.info('Console Connected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', hid_device)
def read(self, size, encoding='ascii', timeout=1):
"""Read size bytes from the device.
"""
return self.device.read(size, timeout).decode(encoding)
def read_line(self):
"""Read from the device's console until we get a \n.
"""
while '\n' not in self.current_line:
self.current_line += self.read(32).replace('\x00', '')
lines = self.current_line.split('\n', 1)
self.current_line = lines[1]
return lines[0]
def run_forever(self):
while True:
try:
message = {**self.hid_device, 'text': self.read_line()}
identifier = (int2hex(message['vendor_id']), int2hex(message['product_id'])) if self.numeric else (message['manufacturer_string'], message['product_string'])
message['identifier'] = ':'.join(identifier)
message['ts'] = '{style_dim}{fg_green}%s{style_reset_all} ' % (strftime(cli.config.general.datetime_fmt),) if cli.args.timestamp else ''
cli.echo('%(ts)s%(color)s%(identifier)s:%(index)d{style_reset_all}: %(text)s' % message)
except self.hid.HIDException:
break
class FindDevices(object):
def __init__(self, vid, pid, index, numeric):
self.hid = import_hid()
self.vid = vid
self.pid = pid
self.index = index
self.numeric = numeric
def run_forever(self):
"""Process messages from our queue in a loop.
"""
live_devices = {}
live_bootloaders = {}
while True:
try:
for device in list(live_devices):
if not live_devices[device]['thread'].is_alive():
cli.log.info('Console Disconnected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', live_devices[device])
del live_devices[device]
for device in self.find_devices():
if device['path'] not in live_devices:
device['color'] = LOG_COLOR['colors'][LOG_COLOR['next']]
LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors'])
live_devices[device['path']] = device
try:
monitor = MonitorDevice(device, self.numeric)
device['thread'] = Thread(target=monitor.run_forever, daemon=True)
device['thread'].start()
except Exception as e:
device['e'] = e
device['e_name'] = e.__class__.__name__
cli.log.error("Could not connect to %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s:%(vendor_id)04X:%(product_id)04X:%(index)d): %(e_name)s: %(e)s", device)
if cli.config.general.verbose:
cli.log.exception(e)
del live_devices[device['path']]
if cli.args.bootloaders:
for device in self.find_bootloaders():
if device.address in live_bootloaders:
live_bootloaders[device.address]._qmk_found = True
else:
name = KNOWN_BOOTLOADERS[(int2hex(device.idVendor), int2hex(device.idProduct))]
cli.log.info('Bootloader Connected: {style_bright}{fg_magenta}%s', name)
device._qmk_found = True
live_bootloaders[device.address] = device
for device in list(live_bootloaders):
if live_bootloaders[device]._qmk_found:
live_bootloaders[device]._qmk_found = False
else:
name = KNOWN_BOOTLOADERS[(int2hex(live_bootloaders[device].idVendor), int2hex(live_bootloaders[device].idProduct))]
cli.log.info('Bootloader Disconnected: {style_bright}{fg_magenta}%s', name)
del live_bootloaders[device]
sleep(.1)
except KeyboardInterrupt:
break
def is_bootloader(self, hid_device):
"""Returns true if the device in question matches a known bootloader vid/pid.
"""
return (int2hex(hid_device.idVendor), int2hex(hid_device.idProduct)) in KNOWN_BOOTLOADERS
def is_console_hid(self, hid_device):
"""Returns true when the usage page indicates it's a teensy-style console.
"""
return hid_device['usage_page'] == 0xFF31 and hid_device['usage'] == 0x0074
def is_filtered_device(self, hid_device):
"""Returns True if the device should be included in the list of available consoles.
"""
return int2hex(hid_device['vendor_id']) == self.vid and int2hex(hid_device['product_id']) == self.pid
def find_devices_by_report(self, hid_devices):
"""Returns a list of available teensy-style consoles by doing a brute-force search.
Some versions of linux don't report usage and usage_page. In that case we fallback to reading the report (possibly inaccurately) ourselves.
"""
devices = []
for device in hid_devices:
path = device['path'].decode('utf-8')
if path.startswith('/dev/hidraw'):
number = path[11:]
report = Path(f'/sys/class/hidraw/hidraw{number}/device/report_descriptor')
if report.exists():
rp = report.read_bytes()
if rp[1] == 0x31 and rp[3] == 0x09:
devices.append(device)
return devices
def find_bootloaders(self):
"""Returns a list of available bootloader devices.
"""
import usb.core
return list(filter(self.is_bootloader, usb.core.find(find_all=True)))
def find_devices(self):
"""Returns a list of available teensy-style consoles.
"""
hid_devices = self.hid.enumerate()
devices = list(filter(self.is_console_hid, hid_devices))
if not devices:
devices = self.find_devices_by_report(hid_devices)
if self.vid and self.pid:
devices = list(filter(self.is_filtered_device, devices))
# Add index numbers
device_index = {}
for device in devices:
id = ':'.join((int2hex(device['vendor_id']), int2hex(device['product_id'])))
if id not in device_index:
device_index[id] = 0
device_index[id] += 1
device['index'] = device_index[id]
return devices
def int2hex(number):
"""Returns a string representation of the number as hex.
"""
return "%04X" % number
def list_devices(device_finder):
"""Show the user a nicely formatted list of devices.
"""
devices = device_finder.find_devices()
if devices:
cli.log.info('Available devices:')
for dev in devices:
color = LOG_COLOR['colors'][LOG_COLOR['next']]
LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors'])
cli.log.info("\t%s%s:%s:%d{style_reset_all}\t%s %s", color, int2hex(dev['vendor_id']), int2hex(dev['product_id']), dev['index'], dev['manufacturer_string'], dev['product_string'])
if cli.args.bootloaders:
bootloaders = device_finder.find_bootloaders()
if bootloaders:
cli.log.info('Available Bootloaders:')
for dev in bootloaders:
cli.log.info("\t%s:%s\t%s", int2hex(dev.idVendor), int2hex(dev.idProduct), KNOWN_BOOTLOADERS[(int2hex(dev.idVendor), int2hex(dev.idProduct))])
@cli.argument('--bootloaders', arg_only=True, default=True, action='store_boolean', help='displaying bootloaders.')
@cli.argument('-d', '--device', help='Device to select - uses format <pid>:<vid>[:<index>].')
@cli.argument('-l', '--list', arg_only=True, action='store_true', help='List available hid_listen devices.')
@cli.argument('-n', '--numeric', arg_only=True, action='store_true', help='Show VID/PID instead of names.')
@cli.argument('-t', '--timestamp', arg_only=True, action='store_true', help='Print the timestamp for received messages as well.')
@cli.argument('-w', '--wait', type=int, default=1, help="How many seconds to wait between checks (Default: 1)")
@cli.subcommand('Acquire debugging information from usb hid devices.')
def console(cli):
"""Acquire debugging information from usb hid devices
"""
vid = None
pid = None
index = 1
if cli.config.console.device:
device = cli.config.console.device.split(':')
if len(device) == 2:
vid, pid = device
elif len(device) == 3:
vid, pid, index = device
if not index.isdigit():
cli.log.error('Device index must be a number! Got "%s" instead.', index)
exit(1)
index = int(index)
if index < 1:
cli.log.error('Device index must be greater than 0! Got %s', index)
exit(1)
else:
cli.log.error('Invalid format for device, expected "<pid>:<vid>[:<index>]" but got "%s".', cli.config.console.device)
cli.print_help()
exit(1)
vid = vid.upper()
pid = pid.upper()
device_finder = FindDevices(vid, pid, index, cli.args.numeric)
if cli.args.list:
return list_devices(device_finder)
print('Looking for devices...', flush=True)
device_finder.run_forever()
+1 -3
View File
@@ -1,10 +1,10 @@
bleach==4.0.0
build==0.6.0.post1
bump2version==1.0.1
bumpversion==0.6.0
certifi==2021.5.30
cffi==1.14.6
chardet==4.0.0
colorama==0.4.4
cryptography==3.4.7
docutils==0.17.1
idna==2.10
@@ -14,7 +14,6 @@ keyring==23.0.1
packaging==21.0
pkginfo==1.7.1
pycparser==2.20
Pygments==2.9.0
pyparsing==2.4.7
readme-renderer==29.0
requests==2.26.0
@@ -22,7 +21,6 @@ requests-toolbelt==0.9.1
rfc3986==1.5.0
SecretStorage==3.3.1
six==1.16.0
stdeb==0.10.0
tqdm==4.62.0
twine==3.4.2
urllib3==1.26.6
+52 -38
View File
@@ -1,51 +1,65 @@
[global]
command-packages: stdeb.command
[bumpversion]
current_version = 0.2.2
commit = True
tag = True
tag_name = {new_version}
message = New release: {current_version} → {new_version}
[bumpversion:file:qmk_cli/__init__.py]
[bumpversion:file:setup.cfg]
#[bumpversion]
# Bumpversion config has been moved to .bumpversion.cfg
[bdist_wheel]
universal = 1
[entry_points]
qmk = qmk_cli.script_qmk:main
[flake8]
ignore = E501,E226
[metadata]
name = qmk
version = 0.3.5
author = skullydazed
author-email = skullydazed@gmail.com
description-file = README.md
dist-name = qmk
license_file = LICENSE
module = qmk_cli
home-page = https://qmk.fm/
requires-python = >=3.7
author_email = skullydazed@gmail.com
description = A program to help users work with QMK Firmware.
long_description = file: README.md
long_description_content_type = text/markdown
license = MIT License
project_urls =
Bug Tracker = https://github.com/qmk/qmk_cli/issues
Documentation = https://docs.qmk.fm/#/cli
Homepage = https://qmk.fm/
Source = https://github.com/qmk/qmk_cli/
classifiers =
Development Status :: 3 - Alpha
Environment :: Console
Intended Audience :: Developers
Intended Audience :: System Administrators
Intended Audience :: End Users/Desktop
License :: OSI Approved :: MIT License
Natural Language :: English
Programming Language :: Python :: 3 :: Only
Topic :: Scientific/Engineering
Topic :: Software Development
Topic :: Utilities
[sdist_dsc]
# Configuration for the Debian package
with-python2: False
with-python3: True
with-dh-virtualenv: True
sign-results: True
compat: 10
suite3: stable
package3: qmk
maintainer: QMK Firmware (Official QMK GPG Signing Key) <hello@qmk.fm>
section: devel
depends3: build-essential, clang-format, diffutils, gcc, git, unzip, wget, zip, python3-pip, binutils-avr, gcc-avr, avr-libc, binutils-arm-none-eabi, gcc-arm-none-eabi, libnewlib-arm-none-eabi, avrdude, dfu-programmer, dfu-util, teensy-loader-cli, libhidapi-hidraw0, libusb-dev
depends: build-essential, clang-format, diffutils, gcc, git, unzip, wget, zip, python3-pip, binutils-avr, gcc-avr, avr-libc, binutils-arm-none-eabi, gcc-arm-none-eabi, libnewlib-arm-none-eabi, avrdude, dfu-programmer, dfu-util, teensy-loader-cli, libhidapi-hidraw0, libusb-dev
x-python3-version: >= 3.7
udev-rules: debian/50-qmk.rules
[options]
install_requires =
appdirs==1.4.4
argcomplete==1.12.3
attrs==21.2.0
colorama==0.4.4
coverage==5.5
halo==0.0.31
hid==1.0.4
log-symbols==0.0.14
mccabe==0.6.1
milc==1.5.0
pycodestyle==2.7.0
pyflakes==2.3.1
pyrsistent==0.18.0
pyusb==1.2.1
setuptools>=45
six==1.16.0
spinners==0.0.24
termcolor==1.1.0
packages = find:
python_requiures = >=3.7
[options.entry_points]
console_scripts =
qmk = qmk_cli.script_qmk:main
[yapf]
align_closing_bracket_with_visual_indent = True
-69
View File
@@ -1,69 +0,0 @@
from configparser import ConfigParser
from setuptools import setup, find_packages
setup_cfg = ConfigParser()
setup_cfg.read('setup.cfg')
metadata = setup_cfg['metadata']
if __name__ == "__main__":
with open('README.md', encoding='utf-8') as readme_file:
long_description = readme_file.read()
setup(
name=metadata['dist-name'],
description='A program to help users work with QMK Firmware.',
entry_points={
'console_scripts': ['%s = %s' % i for i in setup_cfg['entry_points'].items()],
},
license='MIT License',
url=metadata['home-page'],
version=setup_cfg['bumpversion']['current_version'],
author=metadata['author'],
author_email=metadata['author-email'],
maintainer=metadata['author'],
maintainer_email=metadata['author-email'],
long_description=long_description,
long_description_content_type="text/markdown",
packages=find_packages(),
py_modules=['qmk_cli'],
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'Intended Audience :: End Users/Desktop',
'License :: OSI Approved :: MIT License',
'Natural Language :: English',
'Programming Language :: Python :: 3 :: Only',
'Topic :: Scientific/Engineering',
'Topic :: Software Development',
'Topic :: Utilities',
],
python_requires=metadata['requires-python'],
install_requires=[
"appdirs==1.4.4",
"argcomplete==1.12.3",
"attrs==21.2.0",
"colorama==0.4.4",
"coverage==5.5",
"qmk-dotty-dict==1.3.0.post1",
"flake8==3.9.2",
"halo==0.0.31",
"hid==1.0.4",
"hjson==3.0.2",
"jsonschema==3.2.0",
"log-symbols==0.0.14",
"mccabe==0.6.1",
"milc==1.4.2",
"nose2==0.10.0",
"pycodestyle==2.7.0",
"pyflakes==2.3.1",
"Pygments==2.9.0",
"pyrsistent==0.18.0",
"pyusb==1.2.1",
"setuptools>=45",
"six==1.16.0",
"spinners==0.0.24",
"termcolor==1.1.0",
"yapf==0.31.0"
]
)
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
"""Trigger workflows that build QMK packages.
"""
from os import environ
from pathlib import Path
import requests
# Pull in environment vars
gh_user = environ.get('GH_USERNAME', 'qmk-bot')
gh_pat = environ.get('QMK_BOT_TOKEN', '')
gh_repo_owner = environ.get('REPO_OWNER', 'qmk')
gh_repo_name = environ.get('REPO_NAME', 'qmk_fpm')
gh_ref = environ.get('BRANCH_NAME', 'main')
gh_workflow_ids = environ.get('WORKFLOW_IDS', 'debian-buster-publish.yml,fedora-32-publish.yml,ubuntu-focal-publish.yml').split(',')
gh_api_url = environ.get('GITHUB_API_URL', 'https://api.github.com')
gh_workflow_args = {'ref': gh_ref}
gh_workflow_headers = {'Accept': 'application/vnd.github.v3+json'}
for gh_workflow_id in gh_workflow_ids:
gh_workflow_endpoint = f'{gh_api_url}/repos/{gh_repo_owner}/{gh_repo_name}/actions/workflows/{gh_workflow_id}/dispatches'
print(f'Triggering {gh_workflow_id} workflow at: {gh_workflow_endpoint}')
workflow_dispatch = requests.post(gh_workflow_endpoint, headers=gh_workflow_headers, json=gh_workflow_args, auth=(gh_user, gh_pat))
if workflow_dispatch.status_code != 204:
print(f'Error from GitHub API, status_code {workflow_dispatch.status_code}!')
print(workflow_dispatch.text)
exit(1)
exit(0)