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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 915b0f8e03509b8c776660b1a9f335441707e1b4
4
- data.tar.gz: f4541bde947171682ffa95db7b2d92084d458a5a
3
+ metadata.gz: a5e5a93c0d7e2f5455b441ab6856220e0d433695
4
+ data.tar.gz: 1580ecbbbb8f93abce2c79b1332fe8ed130e1b7e
5
5
  SHA512:
6
- metadata.gz: 9aa6510c0fbad4586d251fab54ae968ee74542c83c596b87cf32e9480d54e3b68a44a017531a878afa19e0efa866b4ce6a57f8308ae679b2e86bf0dbb0229567
7
- data.tar.gz: 1d0050383637fc83085fd80fd91a7e9f32049695df559abc0e14d5bed3e7a0d42dcc2f3269e3dc78891dc712e07436b8ae33b63e56917b4e380ae007fef31e35
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 thin wrapper around QMK's `make` to make common tasks easier.
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], keymaps_only?)
24
+ @firmware = Firmware.new(keyboard, @options[:keymap], config)
25
25
 
26
- self.send(parse_command(command || 'help'))
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] = keymaps_only? ? `whoami`.strip : nil
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 keymaps_only?
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
@@ -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, keymaps_only)
11
+ def initialize(keyboard, keymap, config)
12
+ @config = config
13
+
11
14
  @keyboard = keyboard
12
- @keymap = keymap
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 @keymaps_only
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 @keymaps_only
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
- keyboard_path = File.expand_path "./#{keyboard_name}"
105
- files = Dir.glob "#{keyboard_path}/*"
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
- [@keyboard, @keymap, target].compact.join(':')
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}/#{keyboard_name}"
134
+ "#{keyboards_path}/#{@qmk_keyboard}"
122
135
  end
123
136
 
124
137
  def keymap_path
125
- if handwired?
126
- keyboard_path
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 handwired?
133
- @keyboard =~ /handwired/
149
+ def handwired_keymap_path
150
+ keyboard_path
134
151
  end
135
152
  end
136
153
  end
@@ -3,24 +3,25 @@ require 'tempfile'
3
3
  class Makefile
4
4
  def initialize(include_makefile)
5
5
  @include_makefile = include_makefile
6
- @file = Tempfile.new('makefile')
6
+ @file = write
7
+ end
7
8
 
8
- write
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
- @file.write contents
13
- @file.close
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)
@@ -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.value 'BOOTLOADER'
40
+ name = make.get :bootloader
41
41
  return name if name
42
42
 
43
- size = make.value 'BOOTLOADER_SIZE'
43
+ size = make.get :bootloader_size
44
44
  return bootloader_from_size(size) if size
45
45
 
46
- opt_defs = make.value 'OPT_DEFS'
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
@@ -1,13 +1,13 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "qmk-cli"
3
- s.version = "0.2.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 = "MIT"
10
+ s.license = "ISC"
11
11
 
12
12
  s.executables << "qmk"
13
13
  end
@@ -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.2.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
- - MIT
36
+ - ISC
34
37
  metadata: {}
35
38
  post_install_message:
36
39
  rdoc_options: []