diff --git a/.gitignore b/.gitignore index 0d20b64..bf45d22 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ +*.egg-info *.pyc +build/ +dist/ diff --git a/.gitmodules b/.gitmodules index 111c39c..ffb9af9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "lib/pyyaml"] path = lib/pyyaml - url = https://github.com/anishathalye/pyyaml + url = https://github.com/yaml/pyyaml ignore = dirty diff --git a/LICENSE.md b/LICENSE.md index 432fcc0..1af799f 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,7 +1,7 @@ The MIT License (MIT) ===================== -**Copyright (c) 2014-2017 Anish Athalye (me@anishathalye.com)** +**Copyright (c) 2014-2018 Anish Athalye (me@anishathalye.com)** Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index 06d073b..1e5a5fe 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,17 @@ submodule; be sure to commit your changes before running `./install`, otherwise the old version of Dotbot will be checked out by the install script. If using a subrepo, run `git fetch && git checkout origin/master` in the Dotbot directory. +If you prefer, you can install Dotbot from [PyPI] and call it as a command-line +program: + +```bash +pip install dotbot +touch install.conf.yaml +``` + +In this case, rather than running `./install`, you can invoke Dotbot with +`dotbot -c `. + ### Full Example Here's an example of a complete configuration. @@ -366,12 +377,22 @@ Contributing Do you have a feature request, bug report, or patch? Great! See [CONTRIBUTING.md][contributing] for information on what you can do about that. +Packaging +--------- + +1. Update version information. + +2. Build the package using ``python setup.py sdist bdist_wheel``. + +3. Sign and upload the package using ``twine upload -s dist/*``. + License ------- -Copyright (c) 2014-2017 Anish Athalye. Released under the MIT License. See +Copyright (c) 2014-2018 Anish Athalye. Released under the MIT License. See [LICENSE.md][license] for details. +[PyPI]: https://pypi.org/project/dotbot/ [init-dotfiles]: https://github.com/Vaelatern/init-dotfiles [dotfiles-template]: https://github.com/anishathalye/dotfiles_template [inspiration]: https://github.com/anishathalye/dotbot/wiki/Users diff --git a/bin/dotbot b/bin/dotbot index 78a0725..123fc93 100755 --- a/bin/dotbot +++ b/bin/dotbot @@ -11,7 +11,7 @@ which python3 >/dev/null 2>&1 && exec python3 "$0" "$@" which python >/dev/null 2>&1 && exec python "$0" "$@" which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" >&2 echo "error: cannot find python" -return 1 +exit 1 ''' # python code diff --git a/dotbot/__init__.py b/dotbot/__init__.py index 1d03464..dbb3f38 100644 --- a/dotbot/__init__.py +++ b/dotbot/__init__.py @@ -1,2 +1,4 @@ from .cli import main from .plugin import Plugin + +__version__ = '1.12.3' diff --git a/dotbot/cli.py b/dotbot/cli.py index d77ab42..0674cbe 100644 --- a/dotbot/cli.py +++ b/dotbot/cli.py @@ -7,25 +7,29 @@ from .messenger import Messenger from .messenger import Level from .util import module +import dotbot +import yaml + def add_options(parser): - parser.add_argument('-Q', '--super-quiet', dest='super_quiet', action='store_true', + parser.add_argument('-Q', '--super-quiet', action='store_true', help='suppress almost all output') - parser.add_argument('-q', '--quiet', dest='quiet', action='store_true', + parser.add_argument('-q', '--quiet', action='store_true', help='suppress most output') - parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', + parser.add_argument('-v', '--verbose', action='store_true', help='enable verbose output') - parser.add_argument('-d', '--base-directory', nargs=1, - dest='base_directory', help='execute commands from within BASEDIR', - metavar='BASEDIR', required=True) - parser.add_argument('-c', '--config-file', nargs=1, dest='config_file', - help='run commands given in CONFIGFILE', metavar='CONFIGFILE', - required=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', dest='disable_built_in_plugins', + 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('--version', action='store_true', + help='show program\'s version number and exit') def read_config(config_file): reader = ConfigReader(config_file) @@ -37,6 +41,9 @@ def main(): parser = ArgumentParser() add_options(parser) options = parser.parse_args() + if options.version: + print('Dotbot version %s (yaml: %s)' % (dotbot.__version__, yaml.__version__)) + exit(0) if options.super_quiet: log.set_level(Level.WARNING) if options.quiet: @@ -55,10 +62,19 @@ def main(): for plugin_path in plugin_paths: abspath = os.path.abspath(plugin_path) module.load(abspath) - tasks = read_config(options.config_file[0]) + if not options.config_file: + log.error('No configuration file specified') + exit(1) + tasks = read_config(options.config_file) if not isinstance(tasks, list): raise ReadingError('Configuration file must be a list of tasks') - dispatcher = Dispatcher(options.base_directory[0]) + if options.base_directory: + base_directory = options.base_directory + else: + # default to directory of config file + base_directory = os.path.dirname(os.path.realpath(options.config_file)) + os.chdir(base_directory) + dispatcher = Dispatcher(base_directory) success = dispatcher.dispatch(tasks) if success: log.info('\n==> All tasks executed successfully') diff --git a/lib/pyyaml b/lib/pyyaml index f30c956..7e026bf 160000 --- a/lib/pyyaml +++ b/lib/pyyaml @@ -1 +1 @@ -Subproject commit f30c956c11aa6b5e7827fe5840cc9ed40b938d17 +Subproject commit 7e026bfee9cc0bddeb1bbca0c4a0bcd826c2bfdf diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..3c6e79c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..975deb3 --- /dev/null +++ b/setup.py @@ -0,0 +1,87 @@ +from setuptools import setup, find_packages +from codecs import open # For a consistent encoding +from os import path +import re + + +here = path.dirname(__file__) + + +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + + +def read(*names, **kwargs): + with open( + path.join(here, *names), + encoding=kwargs.get("encoding", "utf8") + ) as fp: + return fp.read() + + +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + + +setup( + name='dotbot', + + version=find_version('dotbot', '__init__.py'), + + description='A tool that bootstraps your dotfiles', + long_description=long_description, + long_description_content_type='text/markdown', + + url='https://github.com/anishathalye/dotbot', + + author='Anish Athalye', + author_email='me@anishathalye.com', + + license='MIT', + + classifiers=[ + 'Development Status :: 5 - Production/Stable', + + 'Intended Audience :: Developers', + + 'License :: OSI Approved :: MIT License', + + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + + 'Topic :: Utilities', + ], + + keywords='dotfiles', + + packages=find_packages(), + + setup_requires=[ + 'setuptools>=38.6.0', + 'wheel>=0.31.0', + ], + + install_requires=[ + 'PyYAML>=3.12,<4', + ], + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + entry_points={ + 'console_scripts': [ + 'dotbot=dotbot:main', + ], + }, +) diff --git a/test/Vagrantfile b/test/Vagrantfile index 8ce1739..05d6747 100644 --- a/test/Vagrantfile +++ b/test/Vagrantfile @@ -2,8 +2,7 @@ Vagrant.configure(2) do |config| config.vm.box = 'debian/stretch64' # sync by copying for isolation - config.vm.synced_folder "..", "/dotbot", type: "rsync", - rsync__exclude: ".git/" + config.vm.synced_folder "..", "/dotbot", type: "rsync" # disable default synced folder config.vm.synced_folder ".", "/vagrant", disabled: true diff --git a/test/test-lib.bash b/test/test-lib.bash index 008c2f8..e4d9a4e 100644 --- a/test/test-lib.bash +++ b/test/test-lib.bash @@ -1,10 +1,6 @@ DEBUG=${DEBUG:-false} USE_VAGRANT=${USE_VAGRANT:-true} -if ${USE_VAGRANT}; then - DOTBOT_EXEC=${DOTBOT_EXEC:-"python /dotbot/bin/dotbot"} -else - DOTBOT_EXEC=${DOTBOT_EXEC:-"/dotbot/bin/dotbot"} -fi +DOTBOT_EXEC=${DOTBOT_EXEC:-"python /dotbot/bin/dotbot"} DOTFILES="/home/$(whoami)/dotfiles" INSTALL_CONF='install.conf.yaml' INSTALL_CONF_JSON='install.conf.json' @@ -51,17 +47,15 @@ initialize() { run_dotbot() { ( - cd "${DOTFILES}" - cat > "${INSTALL_CONF}" - ${DOTBOT_EXEC} -d . -c "${INSTALL_CONF}" "${@}" + cat > "${DOTFILES}/${INSTALL_CONF}" + ${DOTBOT_EXEC} -c "${DOTFILES}/${INSTALL_CONF}" "${@}" ) } run_dotbot_json() { ( - cd "${DOTFILES}" - cat > "${INSTALL_CONF_JSON}" - ${DOTBOT_EXEC} -d . -c "${INSTALL_CONF_JSON}" "${@}" + cat > "${DOTFILES}/${INSTALL_CONF_JSON}" + ${DOTBOT_EXEC} -c "${DOTFILES}/${INSTALL_CONF_JSON}" "${@}" ) } diff --git a/test/test_travis b/test/test_travis index 20ec1ae..79439e1 100755 --- a/test/test_travis +++ b/test/test_travis @@ -6,7 +6,7 @@ set -e # set -x # set -v -BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +export BASEDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" # Prevent execution outside of Travis CI builds if [[ "${TRAVIS}" != true || "${CI}" != true ]]; then diff --git a/test/tests/plugin-dir.bash b/test/tests/plugin-dir.bash index 299f144..f3a5e94 100644 --- a/test/tests/plugin-dir.bash +++ b/test/tests/plugin-dir.bash @@ -19,7 +19,7 @@ EOF ' test_expect_success 'run' ' -run_dotbot --plugin-dir plugins < ${DOTFILES}/foo +' + +test_expect_success 'run' ' +cat > ${DOTFILES}/install.conf.yaml <