In progress...
- When running the
remote
command with eithersudo
orrun_as
and captured stdout, hide the remote sudo prompt and show a local prompt so that the remote prompt doesn't get included in the captured stdout. - Drop support for Python 3.7 and 3.8 since these versions have been EOL for a while.
- Switch from poetry to uv.
- Switch from black to ruff for formatting.
- Added support for Python 3.10 and 3.11. Initially, this just means testing against these versions when creating a new release.
- Dropped official support for Python 3.6 since it has been end-of-life for about a year now. Note that RunCommands can still be installed on 3.6, but 3.6 is no longer tested against when creating a new release.
- Relaxed dependency constraints to
>=x
rather>=x.y,<x+1
. This allows compatibility with more projects. - Fixed a bug in the printer utility that would throw an exception if
no args were passed to any of the print functions (e.g., using
printer.print()
to print a blank line). - Updated the styling of headers printed via
printer.header()
in order to make headers more visually prominent.
-
Allow default arg values to be specified via environment variables like so:
some_arg: arg(envvar="SOME_ENV_VAR") = None
. If no value is passed forsome_arg
on the command line, the value ofSOME_ENV_VAR
will be used, if it's defined.This is an alternative to using a config file to define default arg values. It's probably more useful for standalone console scripts versus collections of commands. Both types of defaults can be used at the same time, although this isn't recommended (env var defaults take precedence over config file defaults).
- Make some printer methods print to stderr by default:
debug
,error
,warning
. In the switch to Rich in 1.0a67, these methods were changed inadvertently to print to stdout. - Fixed potential infinite loop when finding project root.
- Fixed infinite recursion when attempting to find a commands module in a directory that didn't contain one (or any of its parents).
- Fix a couple small issues with the switch to Rich in 1.0a67.
- Use Rich for color printing and other terminal formatting. Rich is cross platform and opens up some new options for better formatting.
NOTE: This release contains a breaking change. See below for details.
- Added simplistic make-like functionality. Commands can now specify
sources
(as glob patterns) andcreates
. Commands that specify the latter will only be run if all the targets are newer than all the sources. - Improved
bool_or
so it can be used without specifying a type. This supports the common case ofbool_or(str)
with less typing. - Added support for using
bool_or
with container args. - BREAKING: Switched to TOML for config. TOML is nicer than YAML. This
also allows config to be specified in
pyproject.toml
without having to use a different config language. - Added option to specify config in
pyproject.toml
. This should be the preferred location for RunCommands config IMO.commands.toml
orruncommands.toml
can also be used for projects that don't usepyproject.toml
. - Added the option to define commands in
runcommands.py
instead ofcommands.py
. - Improved discovery of commands module and config, primarily so that commands can be run from project subdirectories. Discovery starts in the current directory and precedes upward until a project root or the file system root is reached. Care has to be taken in commands to ensure they're operating in/on the correct path, especially commands that assume they're being run from the project root.
- Made a handful of internal improvements.
- Fixed color setup for printer utility when
TERM
isn't set.
- Switched to
make_release
package for making releases (make_release
is based on the RunCommandrelease
command) - Removed
release
command - Switched to
cached_property
package for@cached_property
- Removed
@cached_property
- Fixed some things relating to poetry and new package layout
- Made
argv
required when callingCommand.run()
- Added a mechanism for specifying default args in either
pyproject.toml
orsetup.cfg
; this is mainly intended for use with standalone console scripts, providing an easy way for end users to configure such scripts without needing to know anything about RunCommands - When creating subcommand's use the base command's class by default
rather than
Command
- BREAKING:
Command.console_script()
nowsys.exit()
s at the end rather than returning the exit code so standalone console scripts will exit with the correct return code; this can be "disabled" by wrapping calls toconsole_script
in a try/except that catchesSystemExit
Fixed project configuration with regard to README file. Poetry requires
the README file to be specified as the readme
or it won't render it as
the long description in the package or on PyPI.
- Switched to poetry for package setup
- Moved package into
src/
- Moved tests into
tests/
- Added
format-code
command; reformatted all code - Improved
release
command; in particular, it now looks forpyproject.toml
and updates the version there if found - Improved color printer utility
- Disabled color printing on non-posix platforms (instead of printing gibberish)
- Improved "string meaning inversion" logic for automatically inverting boolean option help strings
- Wrapped arg type constructors so that when empty strings are passed
via the command they'll be converted to
None
- Drop support for Python 3.5 since it's no longer supported.
- Add support for Python 3.9. For now, this just means adding Python 3.9 to the list of supported version and the list of versions tested via tox.
- When possible, set type from default value for container args that don't specifiy a type.
-
Improved/fixed/standardized how command results are processed. A
Result
object is now created in most cases, except when a command returns something that's notNone
, anint
, or aResult
.When a command returns
None
or anint
, 0 or theint
is now returned fromCommand.console_script
instead of 1 (not sure what the rationale behind returning 1 was in these cases).Callbacks will now receive
Result
objects in most cases, which gives them access to commands' stdout, etc.
- Fixed/improved callback handling. See 58be7ab86a26 for details.
- In
Printer
, moved default stream assignments for the various print methods from keyword args into the method body. This allowssys.stdout
andsys.stderr
to be redirected usingcontextlib.redirect_stdout
in tests.
- Made
data
property ofCommand
instances read only. - More args are now passed to command callbacks:
Command
instance (as before)- result of running command
aborted
flag, which will be the same for all callbacks; this is intended for use in base command callbacks for deciding how to do cleanup
-
Added 1.0a57 change log.
-
Added
is_type()
utility function and used it to tidy up code in a couple places. -
Added
Parameter
class to wrapinspect.Parameter
. It has some convenience functions that allows some code to be tidied. -
Fixed
Command.find_parameter()
so that it does what it says it does. In particular, it now tries to find a parameter with the passed-in name before normalizing the name and trying to find an arg with that name (and then retrieving the parameter from that arg). This allows parameters that don't have a corresponding arg to be retrieved. -
Improved how args are passed down from base commands to subcommands.
The main change is that a given base arg will now be passed down to a subcommand when it has a corresponding function parameter rather than a corresponding arg as before (parameter = function parameter; arg = command line arg).
This allows subcommands to have required keyword-only parameters that can receive args from a base command. Since required keyword-only parameters don't correspond to command line args, this forces these args to be passed to the base command while still giving subcommands a way to get access to them when needed.
The use case for this is args that need to be handled consistently at a higher level. The specific use case that motivated this was handling "dry run" functionality (esp. pertaining to database transactions).
-
Constrained flake8 to <3.8 for now, since 3.8 is finding "errors" that aren't errors--it's calling out quoted strings as undefined names in function arg annotations 🤔
- Fixed
Data
class used for attaching arbitrary data to commands viadata
attribute onCommand
instances (added in 1.0a55). Accessing the internal data dict was causing infinite recursion. - Improved
Data
so that when adict
is added it will be converted to aData
object. This is for convenience and consistent access to nested data. - Modified
Printer
to flush by default when the console is a TTY. This aligns with what I assume is usually the desired behavior when running commands interactively.
- Default inverse short and long options are now only set for boolean args. Previously, these would always be set up, which would cause two short options to be consumed for every non-bool arg, which would in turn keep the second short option from being used by another arg. This regression was introduced in 1.0a52.
- Set the
base_name
attribute inCommand
's constructor rather than using a cached property. The cached property isn't needed, since the base name is known in the constructor.
- Added ability to attach arbitrary data to commands via
data
attribute onCommand
instances. Data items can be accessed via dot (attribute) or bracket (item) notation. - Added command callbacks. These are called after the last command runs, starting with the callbacks for the last command. Callbacks allow for cleanup, post-run messages, etc.
- Fixed/improved subcommand arg passdown logic.
- Added
fill_char
arg toPrinter.hr()
so a fill char other than=
can be used.
- Added
module
andqualname
attributes toCommand
instances. These correspond to the built in__module__
and__qualname__
attributes of classes and can be used for introspection of a command. E.g.,module
can be used to order commands by module in a command listing. - Added support for command line completion for base commands used as console scripts.
- Improve inverse options.
- Commonly-used utilities are now exported from the top level package. This is
intended to reduce tedium when creating lots of commands spread across many
modules. Includes
abort
,confirm
, andprinter
. - Made it somewhat easier to specify subcommands by allowing
@base_command.subcommand
to be used as a decorator. This reduces the number of imports needed when creating subcommands. It also looks nicer than@subcommand(base_command)
IMO. - Changed the default color of
printer.hr()
from info (blue) to header (magenta) since that's the color I usually want HRs to be. - Made it a little easier to specify colors in
printer
by allowing colors in the color map to be accessed as attributes (in addition to item access).
- Common base command args are now passed down to subcommands.
- Fixed normalization of default args read from config file. Command and arg names are now normalized immediately as they're read from config instead of merging them all together and then normalizing them. This ensures all the default args are consistently and correctly merged.
- Fixed an issue with positional args that have a default value and
nargs=N
. Previously,nargs
would be set to*
or?
(depending on whether the arg is a container type or not), but that doesn't work whennargs=N
. Such args are now converted to options and must be passed via--arg ...
from the command line.
- Fixed/improved handling of args in
Command.__call__()
andCommand.run()
. In particular, handle args as much as possible as they would be when doing a normal call, with the primary difference being that positionals can have default values. - Improved normalization of command names. In particular, it was previously
possible to call a command named
xyz
asXYZ
on the command line since command-line args were always lower-cased when checking to see if they were command names. - Added the option to specify a default value for a command's var args.
- Added
background
flag tolocal
command. This provides an easy way to run a command as a background process (e.g., a file watcher).
- Fixed an issue with default args being added to globals breaking interpolation. Instead of adding the default to globals so that they can be added to commands' default args (if requested), they're now added directly to commands' default args (when requested). When they're added to globals, that can cause circularity issues when interpolating.
- Fixed handling of default args for var args (
*args
). - Added
default_args
to globals so commands can request their own and other commands' default args by adding adefault_args
arg. This allows, for example, setting a default arg for a command that another command can then access viadefault_args
instead of duplicating the arg for both commands or adding the arg to globals.
- Fixed a couple regressions regarding default args introduced in 1.0a40:
- Add globals to keyword args for commands that have
**kwargs
. - Track args that came from defaults.
- Add globals to keyword args for commands that have
- Fixed/improved handling of args in
Command.__call__()
introduced in 1.0a40:- Ensure positional args can be passed via keyword args.
- Ensure optional args can be passed positionally.
- Fixed
complete
command so it doesn't show command usage when parsing args. - Added
make-dist
andupload-dists
commands. - Revamped
Printer
utility.
- Fixed some issues with parsing short option group, especially during the
initial partitioning of
argv
:- Made sure the last option in a short option group gets a value.
- Stopped reparsing
run
args for short option groups since they're parsed when partitioningargv
. - Moved parsing of short option groups for commands to an earlier point in the process so it's possible to tell if help was requested if the help option was passed as part of a multi short option group.
- Improved
release
command.
- The
run
console script alias is now installed by default along with theruncommand
andruncommands
aliases. TheRUNCOMMANDS_CONSOLE_SCRIPTS
environment variable can be used to specify different aliases or to disable installation of the RunCommands console script altogether. - The
RUNCOMMANDS_INSTALL_COMPLETE_CONSOLE_SCRIPT
environment variable can be used to disable the installation of theruncommands-complete
console script. - The
RUNCOMMANDS_INSTALL_RELEASE_CONSOLE_SCRIPT
environment variable can be used to enable installation of themake-release
console script. - Fixed regular expression used to check long options (again). This time, add
support for
--multiple-words
. - Improved parsing of multi short options. In particular, added support for
specifying a value for the last option in the group:
-xyzValue
. - Improved partitioning of initial
argv
:argv
is now partitioned intorun
args versus commands and their args by finding the first non-option word. This allows for better, more intuitive feedback when bad args are passed torun
(allowingargparse
to do its validation instead of aborting with an unhelpful error).- In addition, don't attempt to parse every arg in
argv
as a multi short option. Only attempt to parse those that appear to berun
args (i.e., those before the first non-option word).
- Added option to pass a minimum hash length via the
git-version
command's--short
option.--short
by itself, as a flag, means let git determine the minimum has length.--short=N
means useN
as the minimum.
- Added support for commands with subcommands (like
git log
). - Added support for mutually exclusive command args. Corresponds to
argparse.ArgumentParser.add_mutually_exclusive_group()
. - Added support for positional args that have a default value. These are args that you want to pass positionally but that are optional.
- Added
release
command to built-in commands. - Removed
collect_commands()
utility function. It was too magical without providing much benefity. - The
run
console script is now only installed when an active virtualenv is detected (indicated by the presence of theVIRTUAL_ENV
environment variable). "Run" is pretty generic and only installingrun
in virtualenvs is intended to reduce the possibility of conflicts. - The
runcmd
console script is no longer installed. It was a not-very-useful alias. - Improved internals, esp. wrt. handling of positional args.
- Added support for positional args that have a default value. Includes
handling of
choices
args when no choice is passed. - Fixed conversion of list-arg-to-tuple for cases where arg doesn't exist on
command. This can happen when, for example, a command is run with
run --debug
and the command doesn't have adebug
arg. - Added check to ensure long options are valid. Short options were already being checked.
- Added the option to pass enum choices via
choices
rather than viatype
. Usingchoices
is more natural. The reasontype
was used initially is because such enums are passed toargparse.add_argument()
as the type converter.
- Support Python 3.8.
- Don't attempt to parse command args after
--
as multi short options. Args after--
should be passed verbatim. - When determining if help was requested for a command, ignore args after
--
. Args after--
aren't command options.
- Allow env-specific default args, which take precedence over top level default args (the default default args).
- Default args read from config are now checked and a useful exception is raised if an unknown arg is encountered.
- Fixed/improved handling of container args. This deconflates the type of
a container from the type of values it contains. It also allows commands to
use
*args
to collect an arbitrary number of positional args. - Fixed handling of
--
on the command line. Now, each command can make use of--
to specify the end of options and that the remaining args are positional. - The command to run via the
local
orremote
commands no longer needs to be quoted on the command line. - Improved parsing and expansion of grouped short options like
-xyz
.
- Upgraded PyYAML 3.13 => 5.1. Depending on your setup, this may require
upgrading PyYAML to 5.1 first before upgrading to this version of
RunCommands (e.g., if you have a command that wraps
pip install
).
- Arg values are now collected into tuples when appropriate--when an arg's
default value is a tuple or its type is explicitly set to
tuple
. - Positional args can now be specified with a type of
dict
,list
, ortuple
. Previously, specifying one of these types didn't work as expected because only one value would be read from the command line and that value would be converted to alist
ortuple
of characters (and usingdict
would cause an error). - Multiple short options can now be grouped on the command line like
abc
. - The inverse option for
bool
args can now be disabled. - Fixed some issues related to linting.
- Fixed precedence of globals in
run
command. In particular, globals passed via the command line have higher precedence than globals specified in theenvs
section of the config file. - Fixed a logic bug in
util.misc._merge_dicts()
.
- Convert
cd
arg passed tolocal
command to an absolute path via theabs_path
utility function. This is mainly so that asset paths like'package.module:file'
will be handled correctly. - Normalize default arg names read from config file. E.g., if a command has
an arg named
dir_
with a trailing slash to avoid clashing with the builtindir
function, allow the arg to specified asdir
in the config file.
- Reworked new config system introduced in 1.0a28. Removed
defaults
. Addedenvs
and support environment-specific globals.
- Fixed handling of
**kwargs
. When collecting the args/options for a command,kwargs
is skipped instead of inadvertantly being added to the command's options.
- Added
keep_slash
flag to path utility functions, because sometimes slashes need to be preserved (e.g., withrsync
). - Fixed
sync
command so that it preserves trailing slashes on thesource
anddestination
paths its passed. - Tweaked version regex in
release
task (don't require dev marker). - Fixed some
local
git commands in release task.
Big rewrite. See the git log for tag 1.0a28 to see all the details. Here's a summary:
- Focus is more on console scripts and collections of commands rather than
being a Farbric-esque deployment tool, although simplified versions of the
local
andremote
commands are still available for simple deployment scenarios. - Config files are YAML now instead of custom INI/JSON format.
- Global config is no longer passed to commands as first positional arg.
- Fixed reading of stdin by unbuffering it. The approach used here is derived from Fabric.
- Added
copy_file
command. - Added
get_all_list
utility function.
- Fixed a bug in
util.confirm()
relating to its abort-on-unconfirmed logic. The abort logic was being triggered in practically all cases when something wasn't confirmed (notably, in the default case whereabort_on_unconfirmed=False
).
- Changed mapping operations on
Config
so that__contains__()
no longer looks in therun
config and__iter__()
no longer yieldsrun
config keys. I'm not sure why I thought would be useful in the first place, but it was tricky to get right and confusing (and causing duplicates in the output of theshow-config
command). - Added
--python
option toinstall
command so the Python version for the virtualenv can be specified. - All extras are no installed when the
install
command is run. This is so testing dependencies will be installed. - Fixed a bootstrapping issue in
commands.py
: importcoverage.Coverage
in thetest
command instead of globally because coverage might not be installed yet.
- Fixed/simplified iteration in
Config
. The previous implementation worked on Python 3.5 and 3.6 but not 3.3 and 3.4, causing infinite recursion on those versions. The new implementation is simpler because it only defines__iter__()
instead of both__iter__()
andkeys()
.
- Replacement commands are now called automatically when commands are called
directly. A "replacement command" is a command with the same name as an
already-defined command. When the original command is called, it will check
to see if it has been replaced and call the replacement command if it has
been. The original command implementation can always be called via
Command.implementation()
. This is intended to mirror CLI behavior (where only replacement commands are available) and to make it easy to swap command implementations in wrapper commands. [NOTE: This probably needs a bit more thought put into it and perhaps a less-magical API]. - Command default options can now be specified via a shorter config path:
defaults.{command-name}.xyz
. The old method of using the full module path is still supported, which may be useful when commands are replaced and the original defaults shouldn't be applied to the replacement command. Defaults specified via the short path are merged over defaults specified using the module path. - Added
Command.get_default()
to make getting at individual default options easy.
- Added
use_pty
flag toremote
command. It's passed through to the remote runner strategy (strategies already had ause_pty
flag). - Added
RawConfig.update()
so thatRawConfig.__getitem__()
will be used when updating (likeget()
andpop()
). - A
RawConfig
object is now always returned fromCommand.get_defaults()
instead of returning a plaindict
when there are no defaults. This is for consistency; not sure it has any practical/noticeable effect. - Added
commands
to defaultRunConfig
options.commands
is populated inRunner
with the commands it loads and inCommand.console_script()
with the command being wrapped.
- When loading JSON values tolerantly (i.e., treating bad values as strings),
values are now explicitly cast to
str
to avoid returning non-string values (inJSONValue.loads()
).
- When running a subprocess via the
local
command, onCtrl-C
SIGINT
is now sent to the subprocess for handling and thelocal
command is aborted only after/if the subprocess exits. The idea is to allow interactive commands likeless
to exit cleanly and to obviate the need for thestty sane
hack added in the 1.0a20 release. - When a
local
subprocess times out,Popen.terminate()
is now used to shut down the subprocess instead of.kill()
..terminate()
gives subprocesses a chance to exit cleanly. remote
commands are now allocated a pseudo-terminal (usingssh -t
) when run interactively (whenstdout
is detected to be a TTY). This is to allow interaction with remote commands that prompt for input. TODO: Investigate downsides.
- Made
Config.__contains__()
look inrun
config like.__getitem__()
does. - Made
Config.keys()
and.__iter__()
yieldrun
config keys. - Made
Config.values()
yieldrun
config values. - Made
Config.items()
yieldrun
config items. - Changed all
str.format(**x)
tostr.format_map(x)
for consistency.
- Started adding tests.
stty sane
is now run when a local process exits. This feels pretty hacky and probably won't work on Windows.
-
Re-revamped config stuff
Interpolation-related changes:
- Interpolation is now done when config values are retrieved instead of interpolating all values up front. This allows a value to be changed and any dependent values to be updated automatically. - Interpolation now works with any value type, not just strings. - It's now possible to do things like this in config files: x = [1, 2, 3] ; y will be a list y = ${y} ; z will be a string z = "${y}"
Breaking changes:
- Renamed `RawConfig._clone()` to `copy()`. - Removed `RawConfig._overrides()` context manager because it didn't seem all that useful (just copy instead). - `${...}` is now used instead of `{...}` for interpolation. Config values are now parsed instead of using `str.format()`. - When a `dict` or other mapping type is added to a config object, it will no longer be converted to a `RawConfig` object.
Other changes:
- Added `RawConfig._iter_dotted()`; this was added to make `RawConfig._to_string()` simpler, but it may have other uses.
-
Added
util
package and moved the utilities from theutil
module into various modules in that package.
- Made
Config._get_default_version()
refer directly toconfig.version_getter()
instead of loading it from a string so it works in subclasses. - Made
config.version_getter()
work if it's run from anywhere within a git work tree and not just at the root. - The
cd
arg passed tolocal
command is converted to an absolute path. This is mainly to support asset paths (which was supported before). - Added support for
flush
toPrinter.print()
(by not passing it through toPrinter.colorize()
).
RawConfig._overrides()
RawConfig._clone()
(renamed tocopy()
)util.as_list()
andutil.as_tuple()
; these were holdovers from before list-type options were supported.
- When getting the default version in
Config
, if a tag is checked out, use the tag name instead of the short hash.
- Renamed
runners.commands.get_default_prepend_path
utility function toget_default_local_prepend_path
. - Fixed some issues with creating & copying config objects. On Python 3.3
& 3.4,
OrderedDict.__init__
needs to be called. - Made some internal improvements to local & remote runners.
- When the
--debug
flag is passed to the main script,RunCommandsError
exceptions are now raised instead of being caught. Raising these exceptions actually facilitates debugging. ;) - Default command options specified via config are now validated. Previously,
nonexistent default options would be silently ignored. Now a
CommandError
will be raised. - When reading streams (e.g., when the
local
command is run),EIO
errors are now caught and ignored. We already do this when writing, so it makes sense to do it also when reading. TODO: Review which OS/IO errors can be caught and safely ignored. - Revamped config handling. Mainly, this is internal facing. Creation and handling of config objects is simpler and more consistent.
- Added more documentation.
configure()
is now "officially" exported from the top level package (by adding it to__all__
).- The
env
anddebug
config keys are now both copied from theRunConfig
to the top levelConfig
so you can doconfig.env
instead ofconfig.run.env
in commands. This is somewhat for backward compatibility and somewhat just for convenience. - Improved
util.confirms()
'sabort_on_unconfirmed
option. - Fixed a little glitch in the output of
show-config
.
- Default run options can now be specified for individual commands in
setup.cfg
orruncommands.cfg
(in sections like[runcommands:local]
). - Default
list
anddict
run options read fromsetup.cfg
are now handled correctly. - Added support for environment variables corresponding to various run options
(
RUNCOMMANDS_ECHO
,RUNCOMMANDS_HIDE
, etc). They can be set directly or via theruncommands.configure()
function. Environment variables take precedence over run options read fromsetup.cfg
. - Made it easy to export console scripts for individual commands (by adding
something like
deploy = my.package:deploy.console_script
to a project'sconsole_scripts
entry point). list
options are now processed the same waydict
options are: attempt to parse them as JSON and fall back to str if that fails.- Empty command line options are now converted to
None
. Empty values can be passed using--opt=
or--opt ''
. - Revamped env handling.
- Added handling of keyword-only command function args. Keyword-only args can only be passed in direct/programmatic calls to a command; they aren't included in the command line options.
- Made the project bootstrappable. It should be possible now to
git clone
the project and then run./commands.py install
to create a virtualenv for development. - Reorganized and cleaned up a bunch of stuff.
- Started writing Sphinx/RTD docs.
- Added tox configuration.
- Fixed the
@command
decorator's first arg: renamed it fromname_or_wrapped
toname
. - When getting the default version via get in
Config
, returnNone
if the current directory isn't a git repo.
- Default args for the main script will now be read from
runcommands.cfg
orsetup.cfg
if one of those is present and contains a[runcommands]
section. - Added ability to list available envs to main script (
--list-envs
). - Added support for bool-or-type options. This is used with
hide
options. - Added support for args that specify choices. Added
choices
arg toCommand
. - Added support for
Enum
args. These args will be limited to the choices specified by the enum. commands_module
is now included in config.
- Command line option names for
dict
andlist
args are now made singular when they end with ans
. From the command line, dicts and lists are created by using a given option multiple times. Using a singular name makes this more clear. - Improved
show-config
command. Added--flat
flag (don't nest config). Added--values
flag (show values only without keys. Added ability to specify multiple items. Added--exclude
option. - Made default type of
hide
args for all commandsbool_or(Hide)
. - Improved handling of arg types in general.
- Removed fill/wrap code; use
textwrap.fill()
from the stdlib instead. - Wrapped entire body of main script in try block.
RunCommandsError
is now raised in some places. These keep the main script from blowing up with a stack trace in cases where it's better to abort with a nice error message.
- Fixed a one-off bug with
--
in the main script. Skip over it so it's not treated as a command arg. - Fixed an issue in
Printer.print()
where thefile
arg wasn't being passed down toprint()
, which was causing warning, error, and debug messages to be sent to stdout instead of stderr. - Fixed
RawConfig
so it doesn't read files when adding items or cloning.
- Improved command env handling and options.
- Fixed a bug when raising
TimeoutExpired
exception inLocalRunner
. The captured output data is bytes and needs to be decoded. - Improved handling of non-existent commands module or config file. Catch
exceptions and raise an appropriate
RunCommandsError
instead. The main script catches these errors and aborts with a useful message instead of spewing a traceback. - Improved
release
command's automatic next version detection. In particular, it can now derive1.0aN
from1.0aM
.
- Fixed potential decoding errors when capturing subprocess data. Captured data
is no longer decoded eagerly, which avoids decoding errors when the data read
ends with an incomplete Unicode byte sequence. This was an issue for commands
that output a lot of data, like
npm install
.
- Improved input/output mirroring/capture in
LocalRunner
.- Fixed input mirroring issue with subprocesses that accept single character
input (like
less
). - Added loop to read until no more data is available after subprocess exits.
- Added
COLUMNS
andLINES
to subprocess environment when using PTY so output isn't constrained to the default terminal size. - Made more robust by checking for closed streams when reading, closing PTY file descriptors, etc.
- Moved read/mirror/capture code into its own module for potential reuse.
- Fixed input mirroring issue with subprocesses that accept single character
input (like
- Made an attempt to fix the Paramiko remote runner strategy using the
select
-based reader, but it didn't work because the file handles returned bySSHClient.exec_command()
aren't "real" files (they don't have afileno()
method).
- Simplified handling of input/output in
LocalRunner
. Instead of firing up reader threads, this version usesselect
. This seems to actually work in all cases now (PTY vs non-PTY), but it won't work on Windows. It also breaks the Paramiko remote runner strategy (sinceNonBlockingStreamReader
was removed). It might be possible to create a thread-based version of the same logic... - In
get_default_prepend_path
, bad asset paths are now skipped over and a warning is printed. This fits with how non-existent path directories are skipped. Previously, a bad asset path would cause a nastyImportError
. - Improved
util.asset_path
:- Inject
config
into path at top instead of at bottom. - Raise a better error when a path contains an unimportable package.
- Inject
- Added
clean
command.
- Underscores in command names are now replaced with dashes. This is just an aesthetic preference.
- Fixed an issue with completion where it would always provide options for the last command on the command line even if the cursor was moved before the last command.
- Removed distinction between
-l
and--list
main script options.-l
used to show a short listing of commands (i.e., just their names) and--list
would show a long listing with usage strings. Both now show the short listing. The output of--list
was long and cluttered and with completion working it no longer seems necessary. - When printing help for a command, the command function's entire docstring is now shown.
- When running the main script, we now check for any kind of
RunCommandsError
and print an error message (instead of spewing a traceback) when one is raised. In particular, this catches a bad/missing--env
. - Made some low-level improvements to the local runner class:
- Fixed some issues with prompting for user input by fixing issues with how subprocesses' stdout/stderr are read and mirrored back to the controlling terminal.
- Added initial PTY support.
- Renamed package from
taskrunner
toruncommands
. The latter name is available on PyPI and the term "command" is perhaps less ambiguous than "task". - Fleshed out the Paramiko remote runner a bit. It now A) works and B) caches connections per user/host. Needs review/testing. Should be made more robust in dealing with auth and network issues.
- Added
RemoteRunner
class. - Added a start at a Paramiko-based remote runner as an alternative to shelling
out to
ssh
. Work in progress. - Moved
NonBlockingStreamReader
into a separate module for potential reuse. E.g., it might be useful in the Paramiko-based remote runner. - Made
NonBlockingStreamReader
handle text streams. I.e., we no longer assume all streams are byte streams. - Improved handling of output in
LocalRunner
/NonBlockingStreamReader
. Streams can be closed after a subprocess exits, so we have to account for this. - Added
Parameter.takes_value
andParameter.takes_option_value
. These can be easier to use in some cases than checking foris_bool
(just because the meaning is more clear). - Improved completion by correctly handling options that don't take values.
This makes use of
Parameter.takes_option_value
. - Added
abort_on_unconfirmed
option toconfirm
. - Added
prompt
utility function. - Added
release
command.
- Added
timeout
option tolocal
command. Set default timeout forlocal
command toNone
(no timeout by default). - Added
timeout
option toremote
command. The default timeout for remote commands is 30 seconds. - Fleshed out command line completion, especially for Bash. It now works pretty well.
- Fixed a bug in the
show_config
command where it failed to abort when a badname
was passed.
- Added
config
option toCommand
/@command
. This makes specifying override config for a command easy. Useful for overriding default command config options when most commands use those defaults but one or two don't. - Added initial handling of
dict
. The logic for parsing-o name=value
options was moved into thecommand
module. - Added initial handling of
list
/tuple
command options. - Added initial completion support; a sample bash completion script is provided.
- Added
Result.__bool__()
becauseif command(config): ...
is convenient in some cases. - The default version set in
Config
is now the short hash of the HEAD of the git repo in the current directory instead of'X.Y.Z'
. This is easy to override by settingversion_getter = module:getter
in the project's command config. - Revamped internals of
LocalRunner
. In particular, improved handling of in/out/err stream data (but this is tricky to get right, so more work may be needed). When decoding stream data, the encoding is now read from the locale instead of hard coding 'UTF-8'. - Reimplemented
main
script so that it's just an entry point; moved the logic of running commands intocommands.run()
. - Fixed a typo/bug in
RawConfig._clone()
; was callingclone()
instead of_clone()
when descending into sub-config objects.
- Made the
commands_module
arg toCommandRunner.load_commands()
optional; useself.commands_module
by default. - Limited width of short command listing to 80 columns.
- Improved output of
show_config
when--name
is used and refers to a config object (by descending into the config object). - Added
Printer.echo()
for echoing commands and the like; it uses the same color asPrinter.debug()
because A) echoing is largely used for debugging and B) there aren't that many colors to choose from. - Fixed "danger" color in printer utility; was cyan for some reason instead of red.
Third alpha version.
- Don't allow options to be passed via
-o
when there's a corresponding script option; being able to pass the same option via two different vectors seems like it could be confusing. - Add
_overrides
option toRawConfig
; simplifies updating a config object with overrides without needing to make a separate call to do the update. - Add
RawConfig._clone(**overrides)
method. - Improve output of
runcommands -l
, the condensed command listing. Use the current terminal width to format commands into rows without mid-word wrapping. - Show condensed command listing when no commands are specified. The long command listing is really verbose and not that useful in this case.
- Add
-H
alias for--hide
to main script. - Standardize on
-E
for commands that have andecho
option and-H
for commands that have ahide
option. This also leaves-h
available for command help. - Use
-h
for command help. If a command has multiple H options, the first will get-H
(unless the command also has ahide
option) and the second won't get a short option name. - Normalize command option names more by stripping dashes (after converting underscores to dashes) and lower-casing.
Second alpha version.
- Attempt to fix buffering issues when running subprocesses via
LocalRunner
. I say "attempt" because this is pretty complex and hard to get just right. - Allow arbitrary config options to passed via the command line via
-o
; these options take precedence over config set via config file. - Improve (color) printer utility. Put the various color printing functions in a class and create a default instance of that class so that this instance can be imported instead of having to import the functions individually.
- Print warning, error, and debug messages to stderr by default.
- Make it easier to determine if stdout and/or stderr should be hidden by
adding some utility class methods to the
Hide
enum. - Only set the
hide
option for a command from the global config value if the command's default ishide=None
. TODO: Something similar forecho
, but that's a bit harder. - Remove unused imports, clean other lint, add
__all__
lists where appropriate, etc.
First alpha version.