Compare commits

...

2 Commits

Author SHA1 Message Date
skullY 30c89ec8e0 New release: 0.0.33 → 0.0.34 2020-04-29 10:39:57 -07:00
Zach White a7a7bd9f08 improve the qmk setup flow (#20)
* improve the qmk setup flow

* Apply suggestions from code review

Co-Authored-By: Erovia <Erovia@users.noreply.github.com>

* Update qmk_cli/subcommands/setup.py

* explicity set encoding to utf-8

* polishing

Co-authored-by: Erovia <Erovia@users.noreply.github.com>
2020-04-29 10:38:56 -07:00
7 changed files with 113 additions and 83 deletions
+73 -46
View File
@@ -295,7 +295,7 @@ class MILC(object):
self.prog_name = self.prog_name.split('/')[-1] self.prog_name = self.prog_name.split('/')[-1]
# Initialize all the things # Initialize all the things
self.read_config_file() self.initialize_config()
self.initialize_argparse() self.initialize_argparse()
self.initialize_logging() self.initialize_logging()
@@ -482,22 +482,20 @@ class MILC(object):
self.release_lock() self.release_lock()
def read_config_file(self): def read_config_file(self, config_file):
"""Read in the configuration file and store it in self.config. """Read in the configuration file and return Configuration objects for it and the config_source.
""" """
self.acquire_lock() config = Configuration()
self.config = Configuration() config_source = Configuration()
self.config_source = Configuration()
self.config_file = self.find_config_file()
if self.config_file and self.config_file.exists(): if config_file.exists():
config = RawConfigParser(self.config) raw_config = RawConfigParser()
config.read(str(self.config_file)) raw_config.read(str(config_file))
# Iterate over the config file options and write them into self.config # Iterate over the config file options and write them into config
for section in config.sections(): for section in raw_config.sections():
for option in config.options(section): for option in raw_config.options(section):
value = config.get(section, option) value = raw_config.get(section, option)
# Coerce values into useful datatypes # Coerce values into useful datatypes
if value.lower() in ['1', 'yes', 'true', 'on']: if value.lower() in ['1', 'yes', 'true', 'on']:
@@ -512,9 +510,17 @@ class MILC(object):
else: else:
value = int(value) value = int(value)
self.config[section][option] = value config[section][option] = value
self.config_source[section][option] = 'config_file' config_source[section][option] = 'config_file'
return config, config_source
def initialize_config(self):
"""Read in the configuration file and store it in self.config.
"""
self.acquire_lock()
self.config_file = self.find_config_file()
self.config, self.config_source = self.read_config_file(self.config_file)
self.release_lock() self.release_lock()
def merge_args_into_config(self): def merge_args_into_config(self):
@@ -559,6 +565,54 @@ class MILC(object):
self.release_lock() self.release_lock()
def _save_config_file(self, config):
"""Write config to disk.
"""
# Generate a sanitized version of our running configuration
sane_config = RawConfigParser()
for section_name, section in config._config.items():
sane_config.add_section(section_name)
for option_name, value in section.items():
if section_name == 'general':
if option_name in ['config_file']:
continue
if value is not None:
sane_config.set(section_name, option_name, str(value))
config_dir = self.config_file.parent
if not config_dir.exists():
config_dir.mkdir(parents=True, exist_ok=True)
# Write the config file atomically.
self.acquire_lock()
with NamedTemporaryFile(mode='w', dir=str(config_dir), delete=False) as tmpfile:
sane_config.write(tmpfile)
if os.path.getsize(tmpfile.name) > 0:
os.replace(tmpfile.name, str(self.config_file))
else:
self.log.warning('Config file saving failed, not replacing %s with %s.', str(self.config_file), tmpfile.name)
self.release_lock()
def write_config_option(self, section, option):
"""Save a single config option to the config file.
"""
if not self.config_file:
self.log.warning('%s.config_file not set, not saving config!', self.__class__.__name__)
return
config, config_source = self.read_config_file(self.config_file)
if section in config and option in config[section] and config[section][option] is None:
del(config[section][option])
else:
config[section][option] = str(self.config[section][option])
self._save_config_file(config)
# Housekeeping
self.log.info('Wrote configuration to %s', shlex.quote(str(self.config_file)))
def save_config(self): def save_config(self):
"""Save the current configuration to the config file. """Save the current configuration to the config file.
""" """
@@ -568,36 +622,9 @@ class MILC(object):
self.log.warning('%s.config_file file not set, not saving config!', self.__class__.__name__) self.log.warning('%s.config_file file not set, not saving config!', self.__class__.__name__)
return return
self.acquire_lock() # Write config to disk
self._save_config_file(self.config)
# Generate a sanitized version of our running configuration self.log.info('Wrote configuration to %s', shlex.quote(str(self.config_file)))
config = RawConfigParser()
for section_name, section in self.config._config.items():
config.add_section(section_name)
for option_name, value in section.items():
if section_name == 'general':
if option_name in ['config_file']:
continue
if value is not None:
config.set(section_name, option_name, str(value))
# Write out the config file
config_dir = self.config_file.parent
if not config_dir.exists():
config_dir.mkdir(parents=True, exist_ok=True)
with NamedTemporaryFile(mode='w', dir=str(config_dir), delete=False) as tmpfile:
config.write(tmpfile)
# Move the new config file into place atomically
if os.path.getsize(tmpfile.name) > 0:
os.replace(tmpfile.name, str(self.config_file))
else:
self.log.warning('Config file saving failed, not replacing %s with %s.', str(self.config_file), tmpfile.name)
# Housekeeping
self.release_lock()
cli.log.info('Wrote configuration to %s', shlex.quote(str(self.config_file)))
def __call__(self): def __call__(self):
"""Execute the entrypoint function. """Execute the entrypoint function.
+1 -1
View File
@@ -1,3 +1,3 @@
"""A program to help you work with qmk_firmware.""" """A program to help you work with qmk_firmware."""
__version__ = '0.0.33' __version__ = '0.0.34'
+5 -5
View File
@@ -9,7 +9,7 @@ default_fork = 'qmk/' + default_repo
default_branch = 'master' default_branch = 'master'
def clone(url, destination, branch): def git_clone(url, destination, branch):
git_clone = [ git_clone = [
'git', 'git',
'clone', 'clone',
@@ -20,13 +20,13 @@ def clone(url, destination, branch):
] ]
cli.log.debug('Git clone command: %s', git_clone) cli.log.debug('Git clone command: %s', git_clone)
with subprocess.Popen(git_clone, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True) as p: with subprocess.Popen(git_clone, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, bufsize=1, universal_newlines=True, encoding='utf-8') as p:
for line in p.stdout: for line in p.stdout:
print(line, end='') print(line, end='')
if p.returncode != 0: if p.returncode != 0:
cli.log.error('git clone exited %d', p.returncode) cli.log.error('git clone exited %d', p.returncode)
return False
else: else:
cli.log.info('Successfully cloned %s to %s!', cli.args.fork, cli.args.destination) cli.log.info('Successfully cloned %s to %s!', url, destination)
return True
return p.returncode
+3 -2
View File
@@ -1,6 +1,6 @@
"""Useful helper functions. """Useful helper functions.
""" """
from milc import cli from milc import cli, format_ansi
def question(question, boolean=True, default=''): def question(question, boolean=True, default=''):
@@ -18,10 +18,11 @@ def question(question, boolean=True, default=''):
else: else:
answer_key = 'y/n' answer_key = 'y/n'
prompt = '*** %s [%s] ' % (question, answer_key) prompt = format_ansi('\n*** %s [%s] ' % (question, answer_key))
while True: while True:
answer = input(prompt) answer = input(prompt)
print()
if answer == '' and default.lower() == 'y': if answer == '' and default.lower() == 'y':
answer = 'y' answer = 'y'
elif answer == '' and default.lower() == 'n': elif answer == '' and default.lower() == 'n':
+2 -3
View File
@@ -4,7 +4,7 @@ import os
from pathlib import Path from pathlib import Path
from milc import cli from milc import cli
from qmk_cli.git import clone as git_clone from qmk_cli.git import git_clone
default_repo = 'qmk_firmware' default_repo = 'qmk_firmware'
default_fork = 'qmk/' + default_repo default_fork = 'qmk/' + default_repo
@@ -27,5 +27,4 @@ def clone(cli):
cli.log.error('Destination already exists: %s', cli.args.destination) cli.log.error('Destination already exists: %s', cli.args.destination)
exit(1) exit(1)
success = git_clone(git_url, cli.args.destination, cli.config.clone.branch) return git_clone(git_url, cli.args.destination, cli.config.clone.branch)
exit(0 if success else 1)
+28 -25
View File
@@ -1,12 +1,13 @@
"""Setup qmk_firmware on your computer. """Setup qmk_firmware on your computer.
""" """
import os import os
import shlex
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
from milc import cli from milc import cli
from qmk_cli.git import clone from qmk_cli.git import git_clone
from qmk_cli.helpers import question from qmk_cli.helpers import question
default_repo = 'qmk_firmware' default_repo = 'qmk_firmware'
@@ -18,11 +19,14 @@ default_branch = 'master'
@cli.argument('-y', '--yes', arg_only=True, action='store_true', help='Answer yes to all questions') @cli.argument('-y', '--yes', arg_only=True, action='store_true', help='Answer yes to all questions')
@cli.argument('--baseurl', default='https://github.com', help='The URL all git operations start from') @cli.argument('--baseurl', default='https://github.com', help='The URL all git operations start from')
@cli.argument('-b', '--branch', default=default_branch, help='The branch to clone') @cli.argument('-b', '--branch', default=default_branch, help='The branch to clone')
@cli.argument('destination', default=os.environ['QMK_HOME'], nargs='?', help='The directory to clone to') @cli.argument('-H', '--home', default=Path(os.environ['QMK_HOME']), type=Path, help='The location for QMK Firmware. Defaults to %s' % (os.environ['QMK_HOME'],))
@cli.argument('fork', default=default_fork, nargs='?', help='The qmk_firmware fork to clone') @cli.argument('fork', default=default_fork, nargs='?', help='The qmk_firmware fork to clone')
@cli.subcommand('Setup your computer for qmk_firmware.') @cli.subcommand('Setup your computer for qmk_firmware.')
def setup(cli): def setup(cli):
qmk_firmware = Path(cli.args.destination) """Guide the user through setting up their QMK environment.
"""
clone_prompt = 'Would you like to clone {fg_cyan}%s{fg_reset} to {fg_cyan}%s{fg_reset}?' % (cli.args.fork, shlex.quote(str(cli.args.home)))
home_prompt = 'Would you like to set {fg_cyan}%s{fg_reset} as your QMK home?' % (shlex.quote(str(cli.args.home)),)
# Sanity checks # Sanity checks
if cli.args.yes and cli.args.no: if cli.args.yes and cli.args.no:
@@ -30,30 +34,29 @@ def setup(cli):
exit(1) exit(1)
# Check on qmk_firmware, and if it doesn't exist offer to check it out. # Check on qmk_firmware, and if it doesn't exist offer to check it out.
if (qmk_firmware / 'Makefile').exists(): if (cli.args.home / 'Makefile').exists():
cli.log.info('Found qmk_firmware at %s.', str(qmk_firmware)) cli.log.info('Found qmk_firmware at %s.', str(cli.args.home))
else: else:
cli.log.error('qmk_firmware not found!') cli.log.error('Could not find qmk_firmware!')
if question('Would you like to clone %s?' % cli.args.fork): if question(clone_prompt):
git_url = '/'.join((cli.config.setup.baseurl, cli.args.fork)) git_url = '/'.join((cli.config.setup.baseurl, cli.args.fork))
clone(git_url, cli.args.destination, cli.config.setup.branch) result = git_clone(git_url, cli.args.home, cli.config.setup.branch)
if result != 0:
exit(1)
# Offer to set `user.qmk_home` for them.
if cli.args.home != os.environ['QMK_HOME'] and question(home_prompt):
cli.config['user']['qmk_home'] = str(cli.args.home.absolute())
cli.write_config_option('user', 'qmk_home')
# Run `qmk_firmware/bin/qmk doctor` to check the rest of the environment out # Run `qmk_firmware/bin/qmk doctor` to check the rest of the environment out
if qmk_firmware.exists(): qmk_bin = cli.args.home / 'bin/qmk'
qmk_bin = qmk_firmware / 'bin' / 'qmk' doctor_cmd = [sys.executable, qmk_bin, 'doctor']
doctor_cmd = [sys.executable, str(qmk_bin), 'doctor']
if cli.args.yes:
doctor_cmd.append('--yes')
if cli.args.no:
doctor_cmd.append('--no')
doctor = subprocess.run(doctor_cmd)
if doctor.returncode != 0:
cli.log.error('Your build environment is not setup completely.')
if question('Would you like to run util/qmk_install?'): if cli.args.yes:
curdir = os.getcwd() doctor_cmd.append('--yes')
os.chdir(str(qmk_firmware))
process = subprocess.run(['util/qmk_install.sh']) if cli.args.no:
os.chdir(curdir) doctor_cmd.append('--no')
if process.returncode == 0:
cli.log.info('QMK setup complete!') subprocess.run(doctor_cmd)
+1 -1
View File
@@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.0.33 current_version = 0.0.34
commit = True commit = True
tag = True tag = True
tag_name = {new_version} tag_name = {new_version}