Skip to content

Commit e0749e6

Browse files
committed
adding option for --log-file on the load command
1 parent 8858179 commit e0749e6

File tree

6 files changed

+125
-31
lines changed

6 files changed

+125
-31
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Here you can find the recent changes to tmuxp
66

77
current
88
-------
9+
- Adding option to dump `load` output to log file
910
- *Insert changes/features/fixes for next release here*
1011

1112
tmuxp 1.6.2 (2020-11-08)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ skip-string-normalization = true
33

44
[tool.poetry]
55
name = "tmuxp"
6-
version = "1.6.2"
6+
version = "1.6.3"
77
description = "tmux session manager"
88
license = "MIT"
99
authors = ["Tony Narlock <tony@git-pull.com>"]

tests/test_cli.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,33 @@ def test_load_zsh_autotitle_warning(cli_args, tmpdir, monkeypatch):
408408
assert 'Please set' not in result.output
409409

410410

411+
@pytest.mark.parametrize(
412+
"cli_args",
413+
[
414+
(['load', '.', '--log-file', 'log.txt']),
415+
],
416+
)
417+
def test_load_log_file(cli_args, tmpdir, monkeypatch):
418+
# create dummy tmuxp yaml that breaks to prevent actually loading tmux
419+
tmpdir.join('.tmuxp.yaml').write(
420+
"""
421+
session_name: hello
422+
"""
423+
)
424+
tmpdir.join('.oh-my-zsh').ensure(dir=True)
425+
monkeypatch.setenv('HOME', str(tmpdir))
426+
427+
with tmpdir.as_cwd():
428+
print('tmpdir: {0}'.format(tmpdir))
429+
runner = CliRunner()
430+
431+
# If autoconfirm (-y) no need to prompt y
432+
input_args = 'y\ny\n' if '-y' not in cli_args else ''
433+
434+
runner.invoke(cli.cli, cli_args, input=input_args)
435+
assert 'Loading' in tmpdir.join('log.txt').open().read()
436+
437+
411438
@pytest.mark.parametrize("cli_cmd", ['shell', ('shell', '--pdb')])
412439
@pytest.mark.parametrize(
413440
"cli_args,inputs,env,expected_output",

tmuxp/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__title__ = 'tmuxp'
22
__package_name__ = 'tmuxp'
3-
__version__ = '1.6.2'
3+
__version__ = '1.6.3'
44
__description__ = 'tmux session manager'
55
__email__ = 'tony@git-pull.com'
66
__author__ = 'Tony Narlock'

tmuxp/cli.py

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ def get_cwd():
4242
return os.getcwd()
4343

4444

45+
def tmuxp_echo(message=None, log_level='INFO', **click_kwargs):
46+
"""
47+
Combines logging.log and click.echo
48+
"""
49+
logger.log(log.LOG_LEVELS[log_level], click.unstyle(message))
50+
click.echo(message, **click_kwargs)
51+
52+
4553
def get_config_dir():
4654
"""
4755
Return tmuxp configuration directory.
@@ -246,8 +254,8 @@ def scan_config_argument(ctx, param, value, config_dir=None):
246254
config_dir = config_dir()
247255

248256
if not config:
249-
click.echo("Enter at least one CONFIG")
250-
click.echo(ctx.get_help(), color=ctx.color)
257+
tmuxp_echo("Enter at least one CONFIG")
258+
tmuxp_echo(ctx.get_help(), color=ctx.color)
251259
ctx.exit()
252260

253261
if isinstance(value, string_types):
@@ -357,11 +365,14 @@ def scan_config(config, config_dir=None):
357365
]
358366

359367
if len(candidates) > 1:
360-
click.secho(
361-
'Multiple .tmuxp.{yml,yaml,json} configs in %s' % dirname(config),
362-
fg="red",
368+
tmuxp_echo(
369+
click.style(
370+
'Multiple .tmuxp.{yml,yaml,json} configs in %s'
371+
% dirname(config),
372+
fg="red",
373+
)
363374
)
364-
click.echo(
375+
tmuxp_echo(
365376
click.wrap_text(
366377
'This is undefined behavior, use only one. '
367378
'Use file names e.g. myproject.json, coolproject.yaml. '
@@ -381,7 +392,46 @@ def scan_config(config, config_dir=None):
381392
return config
382393

383394

395+
<<<<<<< Updated upstream
384396
def _reattach(session):
397+
=======
398+
def load_plugins(sconf):
399+
"""
400+
Load and return plugins in config
401+
"""
402+
plugins = []
403+
if 'plugins' in sconf:
404+
for plugin in sconf['plugins']:
405+
try:
406+
module_name = plugin.split('.')
407+
module_name = '.'.join(module_name[:-1])
408+
plugin_name = plugin.split('.')[-1]
409+
plugin = getattr(importlib.import_module(module_name), plugin_name)
410+
plugins.append(plugin())
411+
except exc.TmuxpPluginException as error:
412+
if not click.confirm(
413+
'%sSkip loading %s?'
414+
% (click.style(str(error), fg='yellow'), plugin_name),
415+
default=True,
416+
):
417+
tmuxp_echo(
418+
click.style('[Not Skipping] ', fg='yellow')
419+
+ 'Plugin versions constraint not met. Exiting...'
420+
)
421+
sys.exit(1)
422+
except Exception as error:
423+
tmuxp_echo(
424+
click.style('[Plugin Error] ', fg='red')
425+
+ "Couldn\'t load {0}\n".format(plugin)
426+
+ click.style('{0}'.format(error), fg='yellow')
427+
)
428+
sys.exit(1)
429+
430+
return plugins
431+
432+
433+
def _reattach(builder):
434+
>>>>>>> Stashed changes
385435
"""
386436
Reattach session (depending on env being inside tmux already or not)
387437
@@ -505,6 +555,11 @@ def load_workspace(
505555
# get the canonical path, eliminating any symlinks
506556
config_file = os.path.realpath(config_file)
507557

558+
tmuxp_echo(
559+
click.style('[Loading] ', fg='green')
560+
+ click.style(config_file, fg='blue', bold=True)
561+
)
562+
508563
# kaptan allows us to open a yaml or json file as a dict
509564
sconfig = kaptan.Kaptan()
510565
sconfig = sconfig.import_config(config_file).get()
@@ -525,7 +580,7 @@ def load_workspace(
525580
try: # load WorkspaceBuilder object for tmuxp config / tmux server
526581
builder = WorkspaceBuilder(sconf=sconfig, server=t)
527582
except exc.EmptyConfigException:
528-
click.echo('%s is empty or parsed no config data' % config_file, err=True)
583+
tmuxp_echo('%s is empty or parsed no config data' % config_file, err=True)
529584
return
530585

531586
session_name = sconfig['session_name']
@@ -545,11 +600,6 @@ def load_workspace(
545600
return
546601

547602
try:
548-
click.echo(
549-
click.style('[Loading] ', fg='green')
550-
+ click.style(config_file, fg='blue', bold=True)
551-
)
552-
553603
builder.build() # load tmux session via workspace builder
554604

555605
if 'TMUX' in os.environ: # tmuxp ran from inside tmux
@@ -586,8 +636,8 @@ def load_workspace(
586636
except exc.TmuxpException as e:
587637
import traceback
588638

589-
click.echo(traceback.format_exc(), err=True)
590-
click.echo(e, err=True)
639+
tmuxp_echo(traceback.format_exc(), err=True)
640+
tmuxp_echo(e, err=True)
591641

592642
choice = click.prompt(
593643
'Error loading workspace. (k)ill, (a)ttach, (d)etach?',
@@ -597,7 +647,7 @@ def load_workspace(
597647

598648
if choice == 'k':
599649
builder.session.kill_session()
600-
click.echo('Session killed.')
650+
tmuxp_echo('Session killed.')
601651
elif choice == 'a':
602652
if 'TMUX' in os.environ:
603653
builder.session.switch_client()
@@ -625,12 +675,12 @@ def cli(log_level):
625675
try:
626676
has_minimum_version()
627677
except TmuxCommandNotFound:
628-
click.echo('tmux not found. tmuxp requires you install tmux first.')
678+
tmuxp_echo('tmux not found. tmuxp requires you install tmux first.')
629679
sys.exit()
630680
except exc.TmuxpException as e:
631-
click.echo(e, err=True)
681+
tmuxp_echo(e, err=True)
632682
sys.exit()
633-
setup_logger(level=log_level.upper())
683+
setup_logger(logger=logger, level=log_level.upper())
634684

635685

636686
def setup_logger(logger=None, level='INFO'):
@@ -649,12 +699,12 @@ def setup_logger(logger=None, level='INFO'):
649699
logger = logging.getLogger()
650700

651701
if not logger.handlers: # setup logger handlers
652-
channel = logging.StreamHandler()
653-
channel.setFormatter(log.DebugLogFormatter())
654-
702+
# channel = logging.StreamHandler()
703+
# channel.setFormatter(log.DebugLogFormatter())
655704
# channel.setFormatter(log.LogFormatter())
705+
656706
logger.setLevel(level)
657-
logger.addHandler(channel)
707+
# logger.addHandler(channel)
658708

659709

660710
def startup(config_dir):
@@ -875,6 +925,7 @@ def command_freeze(session_name, socket_name, socket_path, force):
875925
flag_value=88,
876926
help='Like -2, but indicates that the terminal supports 88 colours.',
877927
)
928+
@click.option('--log-file', help='File to log errors/output to')
878929
def command_load(
879930
ctx,
880931
config,
@@ -884,6 +935,7 @@ def command_load(
884935
answer_yes,
885936
detached,
886937
colors,
938+
log_file,
887939
):
888940
"""Load a tmux workspace from each CONFIG.
889941
@@ -908,6 +960,10 @@ def command_load(
908960
detached mode.
909961
"""
910962
util.oh_my_zsh_auto_title()
963+
if log_file:
964+
logfile_handler = logging.FileHandler(log_file)
965+
logfile_handler.setFormatter(log.LogFormatter())
966+
logger.addHandler(logfile_handler)
911967

912968
tmux_options = {
913969
'socket_name': socket_name,
@@ -919,8 +975,8 @@ def command_load(
919975
}
920976

921977
if not config:
922-
click.echo("Enter at least one CONFIG")
923-
click.echo(ctx.get_help(), color=ctx.color)
978+
tmuxp_echo("Enter at least one CONFIG")
979+
tmuxp_echo(ctx.get_help(), color=ctx.color)
924980
ctx.exit()
925981

926982
if isinstance(config, string_types):
@@ -962,7 +1018,7 @@ def import_config(configfile, importfunc):
9621018
else:
9631019
sys.exit('Unknown config format.')
9641020

965-
click.echo(
1021+
tmuxp_echo(
9661022
newconfig + '---------------------------------------------------------------'
9671023
'\n'
9681024
'Configuration import does its best to convert files.\n'
@@ -984,9 +1040,9 @@ def import_config(configfile, importfunc):
9841040
buf.write(newconfig)
9851041
buf.close()
9861042

987-
click.echo('Saved to %s.' % dest)
1043+
tmuxp_echo('Saved to %s.' % dest)
9881044
else:
989-
click.echo(
1045+
tmuxp_echo(
9901046
'tmuxp has examples in JSON and YAML format at '
9911047
'<http://tmuxp.git-pull.com/examples.html>\n'
9921048
'View tmuxp docs at <http://tmuxp.git-pull.com/>'
@@ -1125,4 +1181,4 @@ def format_tmux_resp(std_resp):
11251181
% format_tmux_resp(tmux_cmd('show-window-options', '-g')),
11261182
]
11271183

1128-
click.echo('\n'.join(output))
1184+
tmuxp_echo('\n'.join(output))

tmuxp/log.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@
2121
'CRITICAL': Fore.RED,
2222
}
2323

24+
LOG_LEVELS = {
25+
'CRITICAL': 50,
26+
'ERROR': 40,
27+
'WARNING': 30,
28+
'INFO': 20,
29+
'DEBUG': 10,
30+
'NOTSET': 0,
31+
}
32+
2433

2534
def default_log_template(self, record):
2635
"""
@@ -89,8 +98,9 @@ def format(self, record):
8998

9099
prefix = self.template(record) % record.__dict__
91100

101+
parts = prefix.split(record.message)
92102
formatted = prefix + " " + record.message
93-
return formatted.replace("\n", "\n ")
103+
return formatted.replace("\n", "\n" + parts[0] + " ")
94104

95105

96106
def debug_log_template(self, record):

0 commit comments

Comments
 (0)