diff --git a/docs/changelog.rst b/docs/changelog.rst index 1e2f72310..19e6c5a6b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -13,6 +13,8 @@ To update |kitty|, :doc:`follow the instructions `. - When drawing unicode symbols that are followed by spaces, use multiple cells to avoid resized or cut-off glyphs (:iss:`1452`) +- diff kitten: Allow diffing remote files easily via ssh (:iss:`727`) + 0.14.6 [2019-09-25] --------------------- diff --git a/kittens/diff/main.py b/kittens/diff/main.py index 848411b9e..a6c1cbccf 100644 --- a/kittens/diff/main.py +++ b/kittens/diff/main.py @@ -2,14 +2,17 @@ # vim:fileencoding=utf-8 # License: GPL v3 Copyright: 2018, Kovid Goyal +import atexit import os import signal +import subprocess import sys +import tempfile import warnings from collections import defaultdict +from contextlib import suppress from functools import partial from gettext import gettext as _ -from contextlib import suppress from kitty.cli import CONFIG_HELP, parse_args from kitty.constants import appname @@ -506,7 +509,7 @@ def showwarning(message, category, filename, lineno, file=None, line=None): showwarning.warnings = [] -help_text = 'Show a side-by-side diff of the specified files/directories' +help_text = 'Show a side-by-side diff of the specified files/directories. You can also use ssh:hostname:remote-file-path to diff remote files.' usage = 'file_or_directory_left file_or_directory_right' @@ -516,6 +519,20 @@ def terminate_processes(processes): os.kill(pid, signal.SIGKILL) +def get_remote_file(path): + if path.startswith('ssh:'): + parts = path.split(':', 2) + if len(parts) == 3: + hostname, rpath = parts[1:] + with tempfile.NamedTemporaryFile(suffix='-' + os.path.basename(rpath), prefix='remote:', delete=False) as tf: + atexit.register(os.remove, tf.name) + p = subprocess.Popen(['ssh', hostname, 'cat', rpath], stdout=tf) + if p.wait() != 0: + raise SystemExit(p.returncode) + return tf.name + return path + + def main(args): warnings.showwarning = showwarning args, items = parse_args(args[1:], OPTIONS, usage, help_text, 'kitty +kitten diff') @@ -528,6 +545,7 @@ def main(args): opts = init_config(args) set_diff_command(opts.diff_cmd) lines_for_path.replace_tab_by = opts.replace_tab_by + left, right = map(get_remote_file, (left, right)) for f in left, right: if not os.path.exists(f): raise SystemExit('{} does not exist'.format(f))