Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into add-plugin-config…
Browse files Browse the repository at this point in the history
…-loading
  • Loading branch information
henworth committed Feb 25, 2023
2 parents 6dd426d + da928a4 commit 442b848
Show file tree
Hide file tree
Showing 101 changed files with 2,716 additions and 2,401 deletions.
3 changes: 0 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,3 @@ indent_size = 4

[*.yml]
indent_size = 2

[*.md]
trim_trailing_whitespace = false
41 changes: 34 additions & 7 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,44 @@ on:
schedule:
- cron: '0 8 * * 6'
jobs:
build:
runs-on: ubuntu-latest
test:
env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
strategy:
fail-fast: false
matrix:
python: [2.7, pypy2, 3.5, 3.6, 3.7, 3.8, 3.9, pypy3]
name: Python ${{ matrix.python }}
os: ["ubuntu-20.04", "macos-latest"]
python: ["2.7", "pypy-2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.9"]
include:
- os: "windows-latest"
python: "3.8"
- os: "windows-latest"
python: "3.9"
- os: "windows-latest"
python: "3.10"
runs-on: ${{ matrix.os }}
name: "Test: Python ${{ matrix.python }} on ${{ matrix.os }}"
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/setup-python@v2
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- run: ./test/test
- name: "Install dependencies"
run: |
python -m pip install --upgrade pip setuptools
python -m pip install tox tox-gh-actions
- name: "Run tests"
run: |
python -m tox
python -m tox -e coverage_report
- uses: codecov/codecov-action@v3

fmt:
name: Format
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: psf/black@stable
- uses: isort/isort-action@v1
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
*.egg-info
*.pyc
.coverage*
.eggs/
.idea/
.tox/
.venv/
build/
coverage.xml
dist/
htmlcov/
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ touch install.conf.yaml
```

If you are using PowerShell instead of a POSIX shell, you can use the provided
`install.ps1` script instead of `install`.
`install.ps1` script instead of `install`. On Windows, Dotbot only supports
Python 3.8+, and it requires that your account is [allowed to create symbolic
links][windows-symlinks].

To get started, you just need to fill in the `install.conf.yaml` and Dotbot
will take care of the rest. To help you get started we have [an
Expand Down Expand Up @@ -481,7 +483,7 @@ Copyright (c) 2014-2021 Anish Athalye. Released under the MIT License. See
[init-dotfiles]: https://github.com/Vaelatern/init-dotfiles
[dotfiles-template]: https://github.com/anishathalye/dotfiles_template
[inspiration]: https://github.com/anishathalye/dotbot/wiki/Users
[managing-dotfiles-post]: http://www.anishathalye.com/2014/08/03/managing-your-dotfiles/
[windows-symlinks]: https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-symbolic-links
[json2yaml]: https://www.json2yaml.com/
[plugins]: https://github.com/anishathalye/dotbot/wiki/Plugins
[wiki]: https://github.com/anishathalye/dotbot/wiki
Expand Down
2 changes: 1 addition & 1 deletion dotbot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .cli import main
from .plugin import Plugin

__version__ = '1.19.0'
__version__ = "1.19.1"
155 changes: 99 additions & 56 deletions dotbot/cli.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,87 @@
import os, glob
import glob
import os
import subprocess
import sys

from argparse import ArgumentParser, RawTextHelpFormatter

import dotbot

from .config import ConfigReader, ReadingError
from .dispatcher import Dispatcher, DispatchError
from .messenger import Messenger
from .messenger import Level
from .messenger import Level, Messenger
from .plugins import Clean, Create, Link, Plugins, Shell
from .util import module

import dotbot
import os
import subprocess

def add_options(parser):
parser.add_argument('-Q', '--super-quiet', action='store_true',
help='suppress almost all output')
parser.add_argument('-q', '--quiet', action='store_true',
help='suppress most output')
parser.add_argument('-v', '--verbose', action='count', default=0,
help='enable verbose output\n'
'-v: typical verbose\n'
'-vv: also, set shell commands stderr/stdout to true')
parser.add_argument('-d', '--base-directory',
help='execute commands from within BASEDIR',
metavar='BASEDIR')
parser.add_argument('-c', '--config-file',
help='run commands given in CONFIGFILE', metavar='CONFIGFILE')
parser.add_argument('-p', '--plugin', action='append', dest='plugins', default=[],
help='load PLUGIN as a plugin', metavar='PLUGIN')
parser.add_argument('--disable-built-in-plugins',
action='store_true', help='disable built-in plugins')
parser.add_argument('--plugin-dir', action='append', dest='plugin_dirs', default=[],
metavar='PLUGIN_DIR', help='load all plugins in PLUGIN_DIR')
parser.add_argument('--only', nargs='+',
help='only run specified directives', metavar='DIRECTIVE')
parser.add_argument('--except', nargs='+', dest='skip',
help='skip specified directives', metavar='DIRECTIVE')
parser.add_argument('--force-color', dest='force_color', action='store_true',
help='force color output')
parser.add_argument('--no-color', dest='no_color', action='store_true',
help='disable color output')
parser.add_argument('--version', action='store_true',
help='show program\'s version number and exit')
parser.add_argument('-x', '--exit-on-failure', dest='exit_on_failure', action='store_true',
help='exit after first failed directive')
parser.add_argument(
"-Q", "--super-quiet", action="store_true", help="suppress almost all output"
)
parser.add_argument("-q", "--quiet", action="store_true", help="suppress most output")
parser.add_argument(
"-v",
"--verbose",
action="count",
default=0,
help="enable verbose output\n"
"-v: typical verbose\n"
"-vv: also, set shell commands stderr/stdout to true",
)
parser.add_argument(
"-d", "--base-directory", help="execute commands from within BASEDIR", metavar="BASEDIR"
)
parser.add_argument(
"-c", "--config-file", help="run commands given in CONFIGFILE", metavar="CONFIGFILE"
)
parser.add_argument(
"-p",
"--plugin",
action="append",
dest="plugins",
default=[],
help="load PLUGIN as a plugin",
metavar="PLUGIN",
)
parser.add_argument(
"--disable-built-in-plugins", action="store_true", help="disable built-in plugins"
)
parser.add_argument(
"--plugin-dir",
action="append",
dest="plugin_dirs",
default=[],
metavar="PLUGIN_DIR",
help="load all plugins in PLUGIN_DIR",
)
parser.add_argument(
"--only", nargs="+", help="only run specified directives", metavar="DIRECTIVE"
)
parser.add_argument(
"--except", nargs="+", dest="skip", help="skip specified directives", metavar="DIRECTIVE"
)
parser.add_argument(
"--force-color", dest="force_color", action="store_true", help="force color output"
)
parser.add_argument(
"--no-color", dest="no_color", action="store_true", help="disable color output"
)
parser.add_argument(
"--version", action="store_true", help="show program's version number and exit"
)
parser.add_argument(
"-x",
"--exit-on-failure",
dest="exit_on_failure",
action="store_true",
help="exit after first failed directive",
)


def read_config(config_file):
reader = ConfigReader(config_file)
return reader.get_config()


def main():
log = Messenger()
try:
Expand All @@ -58,12 +91,15 @@ def main():
if options.version:
try:
with open(os.devnull) as devnull:
git_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
cwd=os.path.dirname(os.path.abspath(__file__)), stderr=devnull)
hash_msg = ' (git %s)' % git_hash[:10]
git_hash = subprocess.check_output(
["git", "rev-parse", "HEAD"],
cwd=os.path.dirname(os.path.abspath(__file__)),
stderr=devnull,
)
hash_msg = " (git %s)" % git_hash[:10]
except (OSError, subprocess.CalledProcessError):
hash_msg = ''
print('Dotbot version %s%s' % (dotbot.__version__, hash_msg))
hash_msg = ""
print("Dotbot version %s%s" % (dotbot.__version__, hash_msg))
exit(0)
if options.super_quiet:
log.set_level(Level.WARNING)
Expand All @@ -82,43 +118,50 @@ def main():
else:
log.use_color(sys.stdout.isatty())

plugins = []
plugin_directories = list(options.plugin_dirs)
if not options.disable_built_in_plugins:
from .plugins import Clean, Create, Link, Shell, Plugins
plugins.extend([Clean, Create, Link, Plugins, Shell])
plugin_paths = []
for directory in plugin_directories:
for plugin_path in glob.glob(os.path.join(directory, '*.py')):
plugin_paths.append(plugin_path)
for plugin_path in glob.glob(os.path.join(directory, "*.py")):
plugin_paths.append(plugin_path)
for plugin_path in options.plugins:
plugin_paths.append(plugin_path)
for plugin_path in plugin_paths:
abspath = os.path.abspath(plugin_path)
module.load(abspath)
plugins.extend(module.load(abspath))
if not options.config_file:
log.error('No configuration file specified')
log.error("No configuration file specified")
exit(1)
tasks = read_config(options.config_file)
if tasks is None:
log.warning('Configuration file is empty, no work to do')
log.warning("Configuration file is empty, no work to do")
tasks = []
if not isinstance(tasks, list):
raise ReadingError('Configuration file must be a list of tasks')
raise ReadingError("Configuration file must be a list of tasks")
if options.base_directory:
base_directory = os.path.abspath(options.base_directory)
else:
# default to directory of config file
base_directory = os.path.dirname(os.path.abspath(options.config_file))
os.chdir(base_directory)
dispatcher = Dispatcher(base_directory, only=options.only, skip=options.skip,
exit_on_failure=options.exit_on_failure, options=options)
dispatcher = Dispatcher(
base_directory,
only=options.only,
skip=options.skip,
exit_on_failure=options.exit_on_failure,
options=options,
plugins=plugins,
)
success = dispatcher.dispatch(tasks)
if success:
log.info('\n==> All tasks executed successfully')
log.info("\n==> All tasks executed successfully")
else:
raise DispatchError('\n==> Some tasks were not executed successfully')
raise DispatchError("\n==> Some tasks were not executed successfully")
except (ReadingError, DispatchError) as e:
log.error('%s' % e)
log.error("%s" % e)
exit(1)
except KeyboardInterrupt:
log.error('\n==> Operation aborted')
log.error("\n==> Operation aborted")
exit(1)
10 changes: 7 additions & 3 deletions dotbot/config.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import yaml
import json
import os.path

import yaml

from .util import string


class ConfigReader(object):
def __init__(self, config_file_path):
self._config = self._read(config_file_path)
Expand All @@ -11,17 +14,18 @@ def _read(self, config_file_path):
try:
_, ext = os.path.splitext(config_file_path)
with open(config_file_path) as fin:
if ext == '.json':
if ext == ".json":
data = json.load(fin)
else:
data = yaml.safe_load(fin)
return data
except Exception as e:
msg = string.indent_lines(str(e))
raise ReadingError('Could not read config file:\n%s' % msg)
raise ReadingError("Could not read config file:\n%s" % msg)

def get_config(self):
return self._config


class ReadingError(Exception):
pass
5 changes: 3 additions & 2 deletions dotbot/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import os
from argparse import Namespace


class Context(object):
'''
"""
Contextual data and information for plugins.
'''
"""

def __init__(self, base_directory, options=Namespace()):
self._base_directory = base_directory
Expand Down
Loading

0 comments on commit 442b848

Please sign in to comment.