qmk-cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Makefile +8 -0
- data/README.md +22 -1
- data/lib/cli.rb +33 -10
- data/lib/firmware.rb +37 -20
- data/lib/makefile.rb +12 -11
- data/lib/programmer.rb +5 -5
- data/qmk_cli.gemspec +2 -2
- data/test/rules.mk +78 -0
- data/test/test_makefile.rb +23 -0
- data/test/test_programmer.rb +36 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5e5a93c0d7e2f5455b441ab6856220e0d433695
|
4
|
+
data.tar.gz: 1580ecbbbb8f93abce2c79b1332fe8ed130e1b7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fee8427995c73f2abec6c245cd6749de414a23c8823360e7fb07f0d26976169a24bfd6a002265cbb1538307bd60e9359125c0dfb77b5a7b41d14e95af38371b
|
7
|
+
data.tar.gz: 2830b17e5ad2e3fc2567b1bec4c5fffe85b2486cf8dd0e2dcd3ef6d2a0007622d00497cf8838051e7fc660912a73121c503e1ab70f1fd56b20134408704628e8
|
data/Makefile
CHANGED
@@ -6,6 +6,10 @@ build: clean
|
|
6
6
|
install:
|
7
7
|
@gem install *.gem
|
8
8
|
|
9
|
+
.PHONY: uninstall
|
10
|
+
uninstall:
|
11
|
+
@gem install qmk-cli
|
12
|
+
|
9
13
|
.PHONY: publish
|
10
14
|
publish: build
|
11
15
|
@gem push *.gem
|
@@ -13,3 +17,7 @@ publish: build
|
|
13
17
|
.PHONY: clean
|
14
18
|
clean:
|
15
19
|
@rm -f *.gem
|
20
|
+
|
21
|
+
.PHONY: test
|
22
|
+
test:
|
23
|
+
@ruby -Ilib -e 'ARGV.each { |f| require f }' ./test/test*.rb
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# qmk-cli
|
2
2
|
|
3
|
-
A
|
3
|
+
A wrapper around QMK's `make` to make common tasks easier. **This is a proof of concept and should be considered unstable.**
|
4
4
|
|
5
5
|
## Why use this?
|
6
6
|
|
@@ -31,6 +31,27 @@ A thin wrapper around QMK's `make` to make common tasks easier.
|
|
31
31
|
|
32
32
|
View [nicinabox/keymaps](https://github.com/nicinabox/keymaps) for a complete example on how standalone keymaps should be organized.
|
33
33
|
|
34
|
+
### .qmk
|
35
|
+
|
36
|
+
This file tells qmk-cli that the directory contains keymaps only, with the directory named after the keyboard it supports. This works well for common cases, but there are a number of cases in which you may want to organize differently and supply a configuration.
|
37
|
+
|
38
|
+
Here is an example configuration. All fields are optional.
|
39
|
+
|
40
|
+
```yaml
|
41
|
+
# Specify your keymap name. Uses `whoami` by default.
|
42
|
+
keymap: nic
|
43
|
+
|
44
|
+
# Map local keyboard directories to qmk keyboard directories if needed.
|
45
|
+
keyboards:
|
46
|
+
bananasplit_blocked: bananasplit
|
47
|
+
clueboard: clueboard/66
|
48
|
+
nh60: handwired/nh60
|
49
|
+
|
50
|
+
keymaps:
|
51
|
+
# Override keymap names that differ from your keymap setting above.
|
52
|
+
nh60: default
|
53
|
+
```
|
54
|
+
|
34
55
|
## Platforms
|
35
56
|
|
36
57
|
- [x] macOS
|
data/lib/cli.rb
CHANGED
@@ -21,9 +21,9 @@ module QMK
|
|
21
21
|
def initialize(args)
|
22
22
|
@options = parser(args)
|
23
23
|
command, keyboard = args
|
24
|
-
@firmware = Firmware.new(keyboard, @options[:keymap],
|
24
|
+
@firmware = Firmware.new(keyboard, @options[:keymap], config)
|
25
25
|
|
26
|
-
self.send(parse_command(command
|
26
|
+
command and self.send(parse_command(command))
|
27
27
|
end
|
28
28
|
|
29
29
|
def setup
|
@@ -51,10 +51,6 @@ module QMK
|
|
51
51
|
puts @firmware.keyboards
|
52
52
|
end
|
53
53
|
|
54
|
-
def help
|
55
|
-
puts @options[:help]
|
56
|
-
end
|
57
|
-
|
58
54
|
private
|
59
55
|
def parser(args)
|
60
56
|
options = {}
|
@@ -62,13 +58,20 @@ module QMK
|
|
62
58
|
OptionParser.new do |parser|
|
63
59
|
parser.banner = USAGE
|
64
60
|
|
65
|
-
options[:keymap] =
|
61
|
+
options[:keymap] = config[:keymap]
|
66
62
|
parser.on("-k", "--keymap KEYMAP", "Your keymap name (default: #{options[:keymap]})") do |v|
|
67
63
|
options[:keymap] = v
|
68
64
|
end
|
69
65
|
|
66
|
+
parser.on("-v", "--version", "Show qmk-cli version") do
|
67
|
+
spec = Gem::Specification::load("qmk_cli.gemspec")
|
68
|
+
puts spec.version
|
69
|
+
end
|
70
|
+
|
70
71
|
options[:help] = parser
|
71
|
-
parser.on("-h", "--help", "Show this help message")
|
72
|
+
parser.on("-h", "--help", "Show this help message") do
|
73
|
+
puts parser
|
74
|
+
end
|
72
75
|
end.parse!
|
73
76
|
|
74
77
|
options
|
@@ -78,12 +81,32 @@ module QMK
|
|
78
81
|
cmd.gsub(/\-/, '_').downcase
|
79
82
|
end
|
80
83
|
|
81
|
-
def
|
84
|
+
def config
|
85
|
+
defaults = {
|
86
|
+
standalone_keymaps: standalone_keymaps?,
|
87
|
+
keyboards: [],
|
88
|
+
keymaps: [],
|
89
|
+
keymap: `whoami`.strip
|
90
|
+
}
|
91
|
+
|
92
|
+
if standalone_keymaps?
|
93
|
+
c = YAML.load_file('.qmk')
|
94
|
+
.each_with_object({}) do |(k,v), memo|
|
95
|
+
memo[k.to_sym] = v
|
96
|
+
end
|
97
|
+
|
98
|
+
return defaults.merge c
|
99
|
+
end
|
100
|
+
|
101
|
+
return defaults
|
102
|
+
end
|
103
|
+
|
104
|
+
def standalone_keymaps?
|
82
105
|
File.exists? '.qmk'
|
83
106
|
end
|
84
107
|
|
85
108
|
def method_missing(*args)
|
86
|
-
help
|
109
|
+
puts @options[:help]
|
87
110
|
end
|
88
111
|
end
|
89
112
|
end
|
data/lib/firmware.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'open3'
|
3
|
+
require 'yaml'
|
3
4
|
require 'programmer'
|
4
5
|
require 'git'
|
5
6
|
|
@@ -7,15 +8,18 @@ LIB_PATH = "/usr/local/lib/qmk_firmware"
|
|
7
8
|
|
8
9
|
module QMK
|
9
10
|
class Firmware
|
10
|
-
def initialize(keyboard, keymap,
|
11
|
+
def initialize(keyboard, keymap, config)
|
12
|
+
@config = config
|
13
|
+
|
11
14
|
@keyboard = keyboard
|
12
|
-
@
|
15
|
+
@qmk_keyboard = get_keyboard keyboard
|
16
|
+
@keymap = get_keymap(keyboard) || keymap
|
17
|
+
|
13
18
|
@repo = Git.new(LIB_PATH)
|
14
|
-
@keymaps_only = keymaps_only
|
15
19
|
end
|
16
20
|
|
17
21
|
def make(target = nil)
|
18
|
-
if @
|
22
|
+
if @config[:standalone_keymaps]
|
19
23
|
prepare_firmware
|
20
24
|
end
|
21
25
|
|
@@ -53,7 +57,7 @@ module QMK
|
|
53
57
|
end
|
54
58
|
|
55
59
|
def keyboards
|
56
|
-
if @
|
60
|
+
if @config[:standalone_keymaps]
|
57
61
|
standalone_keyboards
|
58
62
|
else
|
59
63
|
qmk_keyboards @keymap
|
@@ -66,7 +70,7 @@ module QMK
|
|
66
70
|
.sort
|
67
71
|
end
|
68
72
|
|
69
|
-
def qmk_keyboards(keymap=nil)
|
73
|
+
def qmk_keyboards(keymap = nil)
|
70
74
|
Dir["#{keyboards_path}/**/#{keymap}/keymap.c"]
|
71
75
|
.map {|path|
|
72
76
|
File.dirname(path)
|
@@ -79,15 +83,19 @@ module QMK
|
|
79
83
|
.sort
|
80
84
|
end
|
81
85
|
|
82
|
-
def keyboard_name
|
83
|
-
@keyboard.gsub(/\/rev.*/, '')
|
84
|
-
end
|
85
|
-
|
86
86
|
def programmer
|
87
87
|
Programmer.new(keyboard_path).flasher
|
88
88
|
end
|
89
89
|
|
90
90
|
private
|
91
|
+
def get_keyboard(local_keyboard)
|
92
|
+
@config[:keyboards][local_keyboard] || local_keyboard
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_keymap(keyboard)
|
96
|
+
@config[:keymaps][keyboard]
|
97
|
+
end
|
98
|
+
|
91
99
|
def in_repo(&block)
|
92
100
|
@repo.in_repo &block
|
93
101
|
end
|
@@ -97,12 +105,16 @@ module QMK
|
|
97
105
|
while line = stdout.gets
|
98
106
|
puts line
|
99
107
|
end
|
108
|
+
|
109
|
+
while line = stderr.gets
|
110
|
+
puts line
|
111
|
+
end
|
100
112
|
end
|
101
113
|
end
|
102
114
|
|
103
115
|
def prepare_firmware
|
104
|
-
|
105
|
-
files = Dir.glob "#{
|
116
|
+
local_keyboard_path = File.expand_path "./#{@keyboard}"
|
117
|
+
files = Dir.glob "#{local_keyboard_path}/*"
|
106
118
|
|
107
119
|
FileUtils.mkdir_p keymap_path
|
108
120
|
FileUtils.cp_r files, keymap_path
|
@@ -110,7 +122,8 @@ module QMK
|
|
110
122
|
|
111
123
|
def make_target(target = nil)
|
112
124
|
return target unless @keyboard
|
113
|
-
|
125
|
+
|
126
|
+
[@qmk_keyboard, @keymap, target].compact.join(':')
|
114
127
|
end
|
115
128
|
|
116
129
|
def keyboards_path
|
@@ -118,19 +131,23 @@ module QMK
|
|
118
131
|
end
|
119
132
|
|
120
133
|
def keyboard_path
|
121
|
-
"#{keyboards_path}/#{
|
134
|
+
"#{keyboards_path}/#{@qmk_keyboard}"
|
122
135
|
end
|
123
136
|
|
124
137
|
def keymap_path
|
125
|
-
if handwired
|
126
|
-
|
127
|
-
else
|
128
|
-
"#{keyboard_path}/keymaps/#{@keymap}"
|
138
|
+
if /handwired/ =~ @qmk_keyboard
|
139
|
+
return handwired_keymap_path
|
129
140
|
end
|
141
|
+
|
142
|
+
standard_keymap_path
|
143
|
+
end
|
144
|
+
|
145
|
+
def standard_keymap_path
|
146
|
+
"#{keyboard_path}/keymaps/#{@keymap}"
|
130
147
|
end
|
131
148
|
|
132
|
-
def
|
133
|
-
|
149
|
+
def handwired_keymap_path
|
150
|
+
keyboard_path
|
134
151
|
end
|
135
152
|
end
|
136
153
|
end
|
data/lib/makefile.rb
CHANGED
@@ -3,24 +3,25 @@ require 'tempfile'
|
|
3
3
|
class Makefile
|
4
4
|
def initialize(include_makefile)
|
5
5
|
@include_makefile = include_makefile
|
6
|
-
@file =
|
6
|
+
@file = write
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
+
def get(variable)
|
10
|
+
output = run variable
|
11
|
+
_, value = parse output
|
12
|
+
value
|
9
13
|
end
|
10
14
|
|
15
|
+
private
|
11
16
|
def write
|
12
|
-
|
13
|
-
|
17
|
+
file = Tempfile.new('makefile')
|
18
|
+
file.write contents
|
19
|
+
file.close
|
20
|
+
file
|
14
21
|
end
|
15
22
|
|
16
23
|
def run(variable)
|
17
|
-
`make -f #{@file.path} -f #{@include_makefile} print-#{variable.upcase}`
|
18
|
-
end
|
19
|
-
|
20
|
-
def value(variable)
|
21
|
-
output = run variable
|
22
|
-
_, value = parse output
|
23
|
-
value
|
24
|
+
`make -f #{@file.path} -f #{@include_makefile} print-#{variable.to_s.upcase}`
|
24
25
|
end
|
25
26
|
|
26
27
|
def parse(output)
|
data/lib/programmer.rb
CHANGED
@@ -24,26 +24,26 @@ class Programmer
|
|
24
24
|
|
25
25
|
def flasher
|
26
26
|
bootloader and FLASHERS.each do |k, v|
|
27
|
-
break k if v.include? bootloader.downcase
|
27
|
+
break k.to_s if v.include? bootloader.downcase
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
32
32
|
def bootloader_from_size(size)
|
33
33
|
size and BOOTLOADERS.each do |k, v|
|
34
|
-
break k.to_s if v.include? size
|
34
|
+
break k.to_s if v.include? size.to_s
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
def parse_bootloader_name(filename)
|
39
39
|
make = Makefile.new(filename)
|
40
|
-
name = make.
|
40
|
+
name = make.get :bootloader
|
41
41
|
return name if name
|
42
42
|
|
43
|
-
size = make.
|
43
|
+
size = make.get :bootloader_size
|
44
44
|
return bootloader_from_size(size) if size
|
45
45
|
|
46
|
-
opt_defs = make.
|
46
|
+
opt_defs = make.get :opt_defs
|
47
47
|
match = opt_defs.match /BOOTLOADER_SIZE=(\w+)/
|
48
48
|
return bootloader_from_size(match[1]) if match
|
49
49
|
end
|
data/qmk_cli.gemspec
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "qmk-cli"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.3.0"
|
4
4
|
s.date = "2018-02-27"
|
5
5
|
s.summary = "A cli wrapper for QMK Firmware"
|
6
6
|
s.authors = ["Nic Haynes"]
|
7
7
|
s.email = "nic@nicinabox.com"
|
8
8
|
s.files = `git ls-files -z`.split("\x0")
|
9
9
|
s.homepage = "https://github.com/nicinabox/qmk-cli"
|
10
|
-
s.license = "
|
10
|
+
s.license = "ISC"
|
11
11
|
|
12
12
|
s.executables << "qmk"
|
13
13
|
end
|
data/test/rules.mk
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
ifdef TEENSY2
|
4
|
+
OPT_DEFS += -DATREUS_TEENSY2
|
5
|
+
ATREUS_UPLOAD_COMMAND = teensy_loader_cli -w -mmcu=$(MCU) $(TARGET).hex
|
6
|
+
else
|
7
|
+
OPT_DEFS += -DATREUS_ASTAR
|
8
|
+
ATREUS_UPLOAD_COMMAND = while [ ! -r $(USB) ]; do sleep 1; done; \
|
9
|
+
avrdude -p $(MCU) -c avr109 -U flash:w:$(TARGET).hex -P $(USB)
|
10
|
+
endif
|
11
|
+
|
12
|
+
# MCU name
|
13
|
+
#MCU = at90usb1287
|
14
|
+
MCU = atmega32u4
|
15
|
+
|
16
|
+
# Processor frequency.
|
17
|
+
# This will define a symbol, F_CPU, in all source code files equal to the
|
18
|
+
# processor frequency in Hz. You can then use this symbol in your source code to
|
19
|
+
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
|
20
|
+
# automatically to create a 32-bit value in your source code.
|
21
|
+
#
|
22
|
+
# This will be an integer division of F_USB below, as it is sourced by
|
23
|
+
# F_USB after it has run through any CPU prescalers. Note that this value
|
24
|
+
# does not *change* the processor frequency - it should merely be updated to
|
25
|
+
# reflect the processor speed set externally so that the code can use accurate
|
26
|
+
# software delays.
|
27
|
+
F_CPU = 16000000
|
28
|
+
|
29
|
+
#
|
30
|
+
# LUFA specific
|
31
|
+
#
|
32
|
+
# Target architecture (see library "Board Types" documentation).
|
33
|
+
ARCH = AVR8
|
34
|
+
|
35
|
+
# Input clock frequency.
|
36
|
+
# This will define a symbol, F_USB, in all source code files equal to the
|
37
|
+
# input clock frequency (before any prescaling is performed) in Hz. This value may
|
38
|
+
# differ from F_CPU if prescaling is used on the latter, and is required as the
|
39
|
+
# raw input clock is fed directly to the PLL sections of the AVR for high speed
|
40
|
+
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
|
41
|
+
# at the end, this will be done automatically to create a 32-bit value in your
|
42
|
+
# source code.
|
43
|
+
#
|
44
|
+
# If no clock division is performed on the input clock inside the AVR (via the
|
45
|
+
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
|
46
|
+
F_USB = $(F_CPU)
|
47
|
+
|
48
|
+
# Bootloader
|
49
|
+
# This definition is optional, and if your keyboard supports multiple bootloaders of
|
50
|
+
# different sizes, comment this out, and the correct address will be loaded
|
51
|
+
# automatically (+60). See bootloader.mk for all options.
|
52
|
+
ifdef TEENSY2
|
53
|
+
BOOTLOADER = halfkay
|
54
|
+
else
|
55
|
+
BOOTLOADER = caterina
|
56
|
+
endif
|
57
|
+
|
58
|
+
# Interrupt driven control endpoint task(+60)
|
59
|
+
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
|
60
|
+
|
61
|
+
|
62
|
+
# Build Options
|
63
|
+
# comment out to disable the options.
|
64
|
+
#
|
65
|
+
#BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
|
66
|
+
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
|
67
|
+
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
|
68
|
+
CONSOLE_ENABLE = yes # Console for debug(+400)
|
69
|
+
COMMAND_ENABLE = yes # Commands for debug and configuration
|
70
|
+
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
|
71
|
+
# SLEEP_LED_ENABLE = yes # Breathing sleep LED during USB suspend
|
72
|
+
NKRO_ENABLE = yes # USB Nkey Rollover - not yet supported in LUFA
|
73
|
+
# BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
|
74
|
+
# MIDI_ENABLE = YES # MIDI controls
|
75
|
+
UNICODE_ENABLE = YES # Unicode
|
76
|
+
# BLUETOOTH_ENABLE = yes # Enable Bluetooth with the Adafruit EZ-Key HID
|
77
|
+
|
78
|
+
USB = /dev/cu.usbmodem1411
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'makefile'
|
3
|
+
|
4
|
+
class MakefileTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@make = Makefile.new 'test/rules.mk'
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_basic_value
|
10
|
+
value = @make.get :mcu
|
11
|
+
assert_equal value, 'atmega32u4'
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_complex_value
|
15
|
+
value = @make.get :opt_defs
|
16
|
+
assert_equal value, '-DATREUS_ASTAR -DINTERRUPT_CONTROL_ENDPOINT'
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_logical_value
|
20
|
+
value = @make.get :bootloader
|
21
|
+
assert_equal value, 'caterina'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'programmer'
|
3
|
+
|
4
|
+
class ProgrammerTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@protected_methods = Programmer.private_instance_methods
|
7
|
+
Programmer.send(:public, *@protected_methods)
|
8
|
+
|
9
|
+
@prog = Programmer.new 'test'
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_bootloader
|
13
|
+
assert_equal @prog.bootloader, 'caterina'
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_bootloader_not_found
|
17
|
+
prog = Programmer.new ''
|
18
|
+
assert_nil prog.bootloader
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_flasher
|
22
|
+
assert_equal @prog.flasher, 'avrdude'
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_flasher_not_found
|
26
|
+
prog = Programmer.new ''
|
27
|
+
assert_nil prog.flasher
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_bootloader_mapping
|
31
|
+
assert_equal @prog.bootloader_from_size(512), 'halfkay'
|
32
|
+
assert_equal @prog.bootloader_from_size(1024), 'halfkay'
|
33
|
+
assert_equal @prog.bootloader_from_size(2048), 'usbasploader'
|
34
|
+
assert_equal @prog.bootloader_from_size(4096), 'atmel-dfu'
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qmk-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nic Haynes
|
@@ -28,9 +28,12 @@ files:
|
|
28
28
|
- lib/makefile.rb
|
29
29
|
- lib/programmer.rb
|
30
30
|
- qmk_cli.gemspec
|
31
|
+
- test/rules.mk
|
32
|
+
- test/test_makefile.rb
|
33
|
+
- test/test_programmer.rb
|
31
34
|
homepage: https://github.com/nicinabox/qmk-cli
|
32
35
|
licenses:
|
33
|
-
-
|
36
|
+
- ISC
|
34
37
|
metadata: {}
|
35
38
|
post_install_message:
|
36
39
|
rdoc_options: []
|