Skip to content

Commit

Permalink
Merge pull request #133 from jacebrowning/feature/colored-output
Browse files Browse the repository at this point in the history
Add color to the output
  • Loading branch information
jacebrowning committed Jan 5, 2017
2 parents 52e4fb1 + 85b5167 commit 99d17e5
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 38 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Revision History

## 1.1 (unreleased)

- Added coloring to the command-line output.

## 1.0.2 (2016/07/28)

- Moved documentation to http://gitman.readthedocs.io/.
Expand Down
2 changes: 1 addition & 1 deletion gitman/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys

__project__ = 'GitMan'
__version__ = '1.0.2'
__version__ = '1.1b1'

CLI = 'gitman'
PLUGIN = 'deps'
Expand Down
27 changes: 15 additions & 12 deletions gitman/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,17 @@ def main(args=None, function=None):
common.configure_logging(namespace.verbose)

# Run the program
function, args, kwargs, exit_msg = _get_command(function, namespace)
function, args, kwargs, exit_message = _get_command(function, namespace)
if function is None:
parser.print_help()
sys.exit(1)
_run_command(function, args, kwargs, exit_msg)
_run_command(function, args, kwargs, exit_message)


def _get_command(function, namespace):
args = []
kwargs = {}
exit_msg = ""
exit_message = None

if namespace.command in ['install', 'update']:
function = getattr(commands, namespace.command)
Expand All @@ -139,7 +139,7 @@ def _get_command(function, namespace):
if namespace.command == 'update':
kwargs.update(recurse=namespace.recurse,
lock=namespace.lock)
exit_msg = "\n" + "Run again with '--force' to overwrite"
exit_message = "Run again with '--force' to overwrite changes"

elif namespace.command == 'list':
function = commands.display
Expand All @@ -156,7 +156,7 @@ def _get_command(function, namespace):
function = commands.delete
kwargs.update(root=namespace.root,
force=namespace.force)
exit_msg = "\n" + "Run again with '--force' to ignore"
exit_message = "Run again with '--force' to ignore changes"

elif namespace.command == 'show':
function = commands.show
Expand All @@ -171,26 +171,29 @@ def _get_command(function, namespace):
function = commands.edit
kwargs.update(root=namespace.root)

return function, args, kwargs, exit_msg
return function, args, kwargs, exit_message


def _run_command(function, args, kwargs, exit_msg):
def _run_command(function, args, kwargs, exit_message):
success = False
try:
log.debug("Running %s command...", getattr(function, '__name__', 'a'))
success = function(*args, **kwargs)
except KeyboardInterrupt:
log.debug("Command canceled")
exit_msg = ""
except RuntimeError as exc:
exit_msg = str(exc) + exit_msg
else:
exit_msg = ""
common.dedent(0)
common.show(str(exc), color='error')
common.show()
if exit_message:
common.show(exit_message, color='message')
common.show()

if success:
log.debug("Command succeeded")
else:
log.debug("Command failed")
sys.exit(exit_msg or 1)
sys.exit(1)


if __name__ == '__main__': # pragma: no cover (manual test)
Expand Down
24 changes: 16 additions & 8 deletions gitman/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def install(*names, root=None, depth=None,
config = load_config(root)

if config:
common.show("Installing dependencies...", log=False)
common.show()
common.show("Installing dependencies...", color='message', log=False)
common.show()
count = config.install_deps(*names, update=False, depth=depth,
force=force, fetch=fetch, clean=clean)
Expand Down Expand Up @@ -79,14 +80,16 @@ def update(*names, root=None, depth=None,
config = load_config(root)

if config:
common.show("Updating dependencies...", log=False)
common.show()
common.show("Updating dependencies...", color='message', log=False)
common.show()
count = config.install_deps(
*names, update=True, depth=depth,
recurse=recurse, force=force, fetch=True, clean=clean)
common.dedent(level=0)
if count and lock is not False:
common.show("Recording installed versions...", log=False)
common.show("Recording installed versions...",
color='message', log=False)
common.show()
config.lock_deps(*names, obey_existing=lock is None)

Expand All @@ -111,7 +114,9 @@ def display(*, root=None, depth=None, allow_dirty=True):
config = load_config(root)

if config:
common.show("Displaying current dependency versions...", log=False)
common.show()
common.show("Displaying current dependency versions...",
color='message', log=False)
common.show()
config.log(datetime.datetime.now().strftime("%F %T"))
count = 0
Expand Down Expand Up @@ -140,7 +145,8 @@ def lock(*names, root=None):
config = load_config(root)

if config:
common.show("Locking dependencies...", log=False)
common.show()
common.show("Locking dependencies...", color='message', log=False)
common.show()
count = config.lock_deps(*names, obey_existing=False)
common.dedent(level=0)
Expand All @@ -165,11 +171,13 @@ def delete(*, root=None, force=False):
config = load_config(root)

if config:
common.show("Checking for uncommitted changes...", log=False)
common.show()
common.show("Checking for uncommitted changes...",
color='message', log=False)
common.show()
count = len(list(config.get_deps(allow_dirty=force)))
common.dedent(level=0)
common.show("Deleting all dependencies...", log=False)
common.show("Deleting all dependencies...", color='message', log=False)
common.show()
config.uninstall_deps()

Expand All @@ -192,7 +200,7 @@ def show(*names, root=None):
return False

for name in names or [None]:
common.show(config.get_path(name))
common.show(config.get_path(name), color='path')

return True

Expand Down
49 changes: 46 additions & 3 deletions gitman/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,54 @@ def dedent(level=None):
_Config.indent_level = level


def show(message="", file=sys.stdout, log=logging.getLogger(__name__)):
def show(message="", color=None,
file=sys.stdout, log=logging.getLogger(__name__)):
"""Write to standard output or error if enabled."""
if _Config.verbosity == 0:
print(" " * _Config.indent_level + message, file=file)
print(' ' * 2 * _Config.indent_level + style(message, color), file=file)
elif _Config.verbosity >= 1:
message = message.strip()
if message and log:
log.info(message)
if color == 'error':
log.error(message)
else:
log.info(message)


BOLD = '\033[1m'
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
BLUE = '\033[34m'
MAGENTA = '\033[35m'
CYAN = '\033[36m'
WHITE = '\033[37m'
RESET = '\033[0m'

COLORS = dict(
revision=BOLD + BLUE,
dirty=BOLD + MAGENTA,
path='',
changes=YELLOW,
message=BOLD + WHITE,
error=BOLD + RED,
)


def style(msg, name, tty=None):
color_support = sys.stdout.isatty() if tty is None else tty
if not color_support:
return msg

if name == 'shell':
return msg.replace("$ ", BOLD + GREEN + "$ " + RESET)

color = COLORS.get(name)
if color:
return color + msg + RESET

if msg:
assert color is not None
return msg

return ""
2 changes: 1 addition & 1 deletion gitman/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def changes(include_untracked=False, display_status=True, _show=False):

if status and display_status:
for line in git('status', _show=True).splitlines():
common.show(line)
common.show(line, color='changes')

return status

Expand Down
21 changes: 11 additions & 10 deletions gitman/models/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ def __repr__(self):
return "<source {}>".format(self)

def __str__(self):
fmt = "'{r}' @ '{v}' in '{d}'"
pattern = "'{r}' @ '{v}' in '{d}'"
if self.link:
fmt += " <- '{s}'"
return fmt.format(r=self.repo, v=self.rev, d=self.name, s=self.link)
pattern += " <- '{s}'"
return pattern.format(r=self.repo, v=self.rev, d=self.name, s=self.link)

def __eq__(self, other):
return self.name == other.name
Expand All @@ -69,7 +69,7 @@ def update_files(self, force=False, fetch=False, clean=True):
log.debug("Confirming there are no uncommitted changes...")
if git.changes(include_untracked=clean):
common.show()
msg = "Uncommitted changes: {}".format(os.getcwd())
msg = "Uncommitted changes in {}".format(os.getcwd())
raise UncommittedChanges(msg)

# Fetch the desired revision
Expand All @@ -94,7 +94,7 @@ def create_link(self, root, force=False):
shell.rm(target)
else:
common.show()
msg = "Preexisting link location: {}".format(target)
msg = "Preexisting link location at {}".format(target)
raise UncommittedChanges(msg)
shell.ln(source, target)

Expand All @@ -107,16 +107,17 @@ def identify(self, allow_dirty=True, allow_missing=True):
path = os.getcwd()
url = git.get_url()
if git.changes(display_status=not allow_dirty, _show=True):
revision = self.DIRTY
if not allow_dirty:
common.show()
msg = "Uncommitted changes: {}".format(os.getcwd())
msg = "Uncommitted changes in {}".format(os.getcwd())
raise UncommittedChanges(msg)

common.show(self.DIRTY, color='dirty', log=False)
return path, url, self.DIRTY
else:
revision = git.get_hash(_show=True)
common.show(revision, log=False)

return path, url, revision
common.show(revision, color='revision', log=False)
return path, url, revision

elif allow_missing:

Expand Down
2 changes: 1 addition & 1 deletion gitman/shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def call(name, *args, _show=True, _ignore=False):
"""
program = CMD_PREFIX + ' '.join([name, *args])
if _show:
common.show(program)
common.show(program, color='shell')
else:
log.debug(program)

Expand Down
6 changes: 4 additions & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@ def describe_show():
def it_prints_location_by_default(show, location):
cli.main(['show'])

expect(show.mock_calls) == [call(location)]
expect(show.mock_calls) == [call(location, color='path')]

@patch('gitman.common.show')
def it_can_print_a_depenendcy_path(show, location):
cli.main(['show', 'bar'])

expect(show.mock_calls) == [call(os.path.join(location, "bar"))]
expect(show.mock_calls) == [
call(os.path.join(location, "bar"), color='path'),
]

def it_exits_when_no_config_found(tmpdir):
tmpdir.chdir()
Expand Down

0 comments on commit 99d17e5

Please sign in to comment.