From a122e73b9b64a16a929330bd21cf1bcf9e206546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20Silkeb=C3=A6kken?= Date: Wed, 31 Jul 2013 22:15:35 +0200 Subject: [PATCH] Add files from @kovidgoyal's powerline-daemon repo Minor changes have been applied: - Removed copyright info and GPL 3 license since Powerline is MIT (needs confirmation from kovidgoyal before merge) - The `powerline-client` script is renamed to `powerline`, and calls the daemon or `powerline-render` (the previous `powerline`) to render a statusline - Minor coding style corrections to match the rest of the project - Python 3 support is removed for now due to setuptools failing with binary scripts Todo: - Automatically attempt to launch powerline-daemon the first time powerline is run if the daemon isn't already running? - pip install -e fails with binary files (it appears that pip recodes the powerline binary to ASCII, the compiled powerline script must be copied manually to ~/.local/bin after pip install -e has been run) --- client/powerline | Bin 0 -> 10732 bytes client/powerline.c | 115 +++++++ client/powerline.py | 77 +++++ scripts/.gitignore | 1 + scripts/powerline-daemon | 395 ++++++++++++++++++++++++ scripts/{powerline => powerline-render} | 0 setup.py | 36 ++- 7 files changed, 620 insertions(+), 4 deletions(-) create mode 100755 client/powerline create mode 100644 client/powerline.c create mode 100755 client/powerline.py create mode 100644 scripts/.gitignore create mode 100755 scripts/powerline-daemon rename scripts/{powerline => powerline-render} (100%) diff --git a/client/powerline b/client/powerline new file mode 100755 index 0000000000000000000000000000000000000000..fd6de02466fadefde0a29997f5b142205dd85172 GIT binary patch literal 10732 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 LQ1P3LRsVkg?!G}> literal 0 HcmV?d00001 diff --git a/client/powerline.c b/client/powerline.c new file mode 100644 index 00000000..cef562ec --- /dev/null +++ b/client/powerline.c @@ -0,0 +1,115 @@ +/* vim:fileencoding=utf-8:noet */ + +#include +#include +#include +#include +#include +#include +#include + +#define handle_error(msg) \ + do { perror(msg); exit(EXIT_FAILURE); } while (0) + +#ifndef TEMP_FAILURE_RETRY +#define TEMP_FAILURE_RETRY(expression) \ + ( \ + ({ long int __result; \ + do __result = (long int) (expression); \ + while (__result == -1L && errno == EINTR); \ + __result; })) +#endif + +extern char **environ; + +void do_write(int sd, const char *raw, int len) { + int written = 0, n = -1; + + while (written < len) { + n = TEMP_FAILURE_RETRY(write(sd, raw+written, len-written)); + if (n == -1) { + close(sd); + handle_error("write() failed"); + } + written += n; + } +} + +int main(int argc, char *argv[]) { + int sd = -1, i; + struct sockaddr_un server; + char address[50] = {}; + const char eof[2] = "\0\0"; + char buf[4096] = {}; + char *newargv[200] = {}; + char *wd = NULL; + char **envp; + + if (argc < 2) { printf("Must provide at least one argument.\n"); return EXIT_FAILURE; } + +#ifdef __APPLE__ + snprintf(address, 50, "/tmp/powerline-ipc-%d", getuid()); +#else + snprintf(address, 50, "powerline-ipc-%d", getuid()); +#endif + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sd == -1) handle_error("socket() failed"); + + memset(&server, 0, sizeof(struct sockaddr_un)); // Clear + server.sun_family = AF_UNIX; +#ifdef __APPLE__ + strncpy(server.sun_path, address, strlen(address)); +#else + strncpy(server.sun_path+1, address, strlen(address)); +#endif + +#ifdef __APPLE__ + if (connect(sd, (struct sockaddr *) &server, sizeof(server.sun_family) + strlen(address)) < 0) { +#else + if (connect(sd, (struct sockaddr *) &server, sizeof(server.sun_family) + strlen(address)+1) < 0) { +#endif + close(sd); + // We failed to connect to the daemon, execute powerline instead + argc = (argc < 199) ? argc : 199; + for (i=1; i < argc; i++) newargv[i] = argv[i]; + newargv[0] = "powerline-render"; + newargv[argc] = NULL; + execvp("powerline-render", newargv); + } + + for (i = 1; i < argc; i++) { + do_write(sd, argv[i], strlen(argv[i])); + do_write(sd, eof, 1); + } + + for(envp=environ; *envp; envp++) { + do_write(sd, "--env=", 6); + do_write(sd, *envp, strlen(*envp)); + do_write(sd, eof, 1); + } + + wd = getcwd(NULL, 0); + if (wd != NULL) { + do_write(sd, "--cwd=", 6); + do_write(sd, wd, strlen(wd)); + free(wd); wd = NULL; + } + + do_write(sd, eof, 2); + + i = -1; + while (i != 0) { + i = TEMP_FAILURE_RETRY(read(sd, buf, 4096)); + if (i == -1) { + close(sd); + handle_error("read() failed"); + } + if (i > 0) + write(STDOUT_FILENO, buf, i) || 0; + } + + close(sd); + + return 0; +} diff --git a/client/powerline.py b/client/powerline.py new file mode 100755 index 00000000..bbcfffbe --- /dev/null +++ b/client/powerline.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet + +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import sys +import socket +import os +import errno + +if len(sys.argv) < 2: + print('Must provide at least one argument.', file=sys.stderr) + raise SystemExit(1) + +platform = sys.platform.lower() +use_filesystem = 'darwin' in platform +# use_filesystem = True +del platform + +address = ('/tmp/powerline-ipc-%d' if use_filesystem else '\0powerline-ipc-%d')%os.getuid() + +sock = socket.socket(family=socket.AF_UNIX) + + +def eintr_retry_call(func, *args, **kwargs): + while True: + try: + return func(*args, **kwargs) + except EnvironmentError as e: + if getattr(e, 'errno', None) == errno.EINTR: + continue + raise + +try: + eintr_retry_call(sock.connect, address) +except Exception: + # Run the powerline renderer + args = ['powerline-render'] + sys.argv[1:] + os.execvp('powerline-render', args) + +fenc = sys.getfilesystemencoding() or 'utf-8' +if fenc == 'ascii': + fenc = 'utf-8' + +args = [x.encode(fenc) if isinstance(x, type('')) else x for x in sys.argv[1:]] + +try: + cwd = os.getcwd() +except EnvironmentError: + pass +else: + if isinstance(cwd, type('')): + cwd = cwd.encode(fenc) + args.append(b'--cwd=' + cwd) + + +env = (k + '=' + v for k, v in os.environ.items()) +env = (x if isinstance(x, bytes) else x.encode(fenc, 'replace') for x in env) +args.extend((b'--env=' + x for x in env)) + +EOF = b'\0\0' + +for a in args: + eintr_retry_call(sock.sendall, a + EOF[0]) + +eintr_retry_call(sock.sendall, EOF) + +received = [] +while True: + r = sock.recv(4096) + if not r: + break + received.append(r) + +sock.close() + +print (b''.join(received)) diff --git a/scripts/.gitignore b/scripts/.gitignore new file mode 100644 index 00000000..f2ffc12a --- /dev/null +++ b/scripts/.gitignore @@ -0,0 +1 @@ +powerline diff --git a/scripts/powerline-daemon b/scripts/powerline-daemon new file mode 100755 index 00000000..b7627cc4 --- /dev/null +++ b/scripts/powerline-daemon @@ -0,0 +1,395 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8:noet +from __future__ import (unicode_literals, division, absolute_import, print_function) + +import socket +import os +import errno +import sys +from argparse import ArgumentParser +from select import select +from signal import signal, SIGTERM +from time import sleep +from functools import partial +from locale import getpreferredencoding + +from powerline.shell import get_argparser, finish_args, ShellPowerline +from powerline.lib.monotonic import monotonic + +is_daemon = False +platform = sys.platform.lower() +use_filesystem = 'darwin' in platform +# use_filesystem = True +del platform + +if use_filesystem: + address = '/tmp/powerline-ipc-%d' + pidfile = address + '.pid' +else: + # Use the abstract namespace for sockets rather than the filesystem + # (Available only in linux) + address = '\0powerline-ipc-%d' +address = address % os.getuid() + + +class NonInteractiveArgParser(ArgumentParser): + def print_usage(self, file=None): + raise Exception(self.format_usage()) + + def print_help(self, file=None): + raise Exception(self.format_help()) + + def exit(self, status=0, message=None): + pass + + def error(self, message): + raise Exception(self.format_usage()) + + +parser = get_argparser(parser=NonInteractiveArgParser, description='powerline daemon') +parser.add_argument('--cwd', metavar='PATH') +parser.add_argument('--env', action='append') + +EOF = b'EOF\0\0' + +powerlines = {} +logger = None +config_loader = None +home = os.path.expanduser('~') + + +class PowerlineDaemon(ShellPowerline): + def get_log_handler(self): + if not is_daemon: + import logging + return logging.StreamHandler() + return super(PowerlineDaemon, self).get_log_handler() + + +def render(args): + global logger + global config_loader + environ = dict(((k, v) for k, v in (x.partition('=')[0::2] for x in args.env))) + cwd = environ.get('PWD', args.cwd or '/') + segment_info = { + 'getcwd': lambda: cwd, + 'home': environ.get('HOME', home), + 'environ': environ, + 'args': args, + } + key = (args.ext[0], args.renderer_module, + tuple(args.config) if args.config else None, + tuple(args.theme_option) if args.theme_option else None,) + if args.renderer_arg: + segment_info.update(args.renderer_arg) + finish_args(args) + pl = None + try: + pl = powerlines[key] + except KeyError: + try: + pl = powerlines[key] = PowerlineDaemon( + args, + logger=logger, + config_loader=config_loader + ) + except SystemExit: + # Somebody thought raising system exit was a good idea, + return '' + except Exception as e: + if pl: + pl.pl.exception('Failed to render {0}: {1}', str(key), str(e)) + else: + return 'Failed to render {0}: {1}'.format(str(key), str(e)) + if logger is None: + logger = pl.logger + if config_loader is None: + config_loader = pl.config_loader + return pl.render(width=args.width, side=args.side, segment_info=segment_info) + + +def eintr_retry_call(func, *args, **kwargs): + while True: + try: + return func(*args, **kwargs) + except EnvironmentError as e: + if getattr(e, 'errno', None) == errno.EINTR: + continue + raise + + +def do_read(conn, timeout=2.0): + ''' Read data from the client. If the client fails to send data within + timeout seconds, abort. ''' + read = [] + end_time = monotonic() + timeout + while not read or not read[-1].endswith(b'\0\0'): + r, w, e = select((conn,), (), (conn,), timeout) + if e: + return + if monotonic() > end_time: + return + if not r: + continue + x = eintr_retry_call(conn.recv, 4096) + if x: + read.append(x) + else: + break + return b''.join(read) + + +def do_write(conn, result): + try: + eintr_retry_call(conn.sendall, result + b'\0') + except Exception: + pass + + +encoding = getpreferredencoding() or 'UTF-8' +if encoding.lower() == 'ascii': + encoding = 'UTF-8' + + +def safe_bytes(o, encoding=encoding): + '''Return bytes instance without ever throwing an exception.''' + try: + try: + # We are assuming that o is a unicode object + return o.encode(encoding, 'replace') + except Exception: + # Object may have defined __bytes__ (python 3) or __str__ method + # (python 2) + # This also catches problem with non_ascii_bytes.encode('utf-8') + # that first tries to decode to UTF-8 using ascii codec (and fails + # in this case) and then encode to given encoding: errors= argument + # is not used in the first stage. + return bytes(o) + except Exception as e: + return safe_bytes(str(e), encoding) + + +def do_render(req): + try: + args = [x.decode(encoding) for x in req.split(b'\0') if x] + args = parser.parse_args(args) + return safe_bytes(render(args)) + except Exception as e: + return safe_bytes(str(e)) + + +def do_one(sock, read_sockets, write_sockets, result_map): + r, w, e = select( + tuple(read_sockets) + (sock,), + tuple(write_sockets), + tuple(read_sockets) + tuple(write_sockets) + (sock,), + 60.0 + ) + + if sock in e: + # We cannot accept any more connections, so we exit + raise SystemExit(1) + + for s in e: + # Discard all broken connections to clients + s.close() + read_sockets.discard(s) + write_sockets.discard(s) + + for s in r: + if s == sock: + # A client wants to connect + conn, _ = eintr_retry_call(sock.accept) + read_sockets.add(conn) + else: + # A client has sent some data + read_sockets.discard(s) + req = do_read(s) + if req == EOF: + raise SystemExit(0) + elif req: + ans = do_render(req) + result_map[s] = ans + write_sockets.add(s) + else: + s.close() + + for s in w: + # A client is ready to receive the result + write_sockets.discard(s) + result = result_map.pop(s) + try: + do_write(s, result) + finally: + s.close() + + +def main_loop(sock): + sock.listen(1) + sock.setblocking(0) + + read_sockets, write_sockets = set(), set() + result_map = {} + try: + while True: + do_one(sock, read_sockets, write_sockets, result_map) + except KeyboardInterrupt: + raise SystemExit(0) + return 0 + + +def daemonize(stdin=os.devnull, stdout=os.devnull, stderr=os.devnull): + try: + pid = os.fork() + if pid > 0: + # exit first parent + sys.exit(0) + except OSError as e: + print ("fork #1 failed: %d (%s)" % (e.errno, e.strerror), file=sys.stderr) + sys.exit(1) + + # decouple from parent environment + os.chdir("/") + os.setsid() + os.umask(0) + + # do second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + sys.exit(0) + except OSError as e: + print ("fork #2 failed: %d (%s)" % (e.errno, e.strerror), file=sys.stderr) + sys.exit(1) + + # Redirect standard file descriptors. + si = file(stdin, 'r') + so = file(stdout, 'a+') + se = file(stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + global is_daemon + is_daemon = True + + +def check_existing(): + if use_filesystem: + # We cannot bind if the socket file already exists so remove it, we + # already have a lock on pidfile, so this should be safe. + try: + os.unlink(address) + except EnvironmentError: + pass + + sock = socket.socket(family=socket.AF_UNIX) + try: + sock.bind(address) + except socket.error as e: + if getattr(e, 'errno', None) == errno.EADDRINUSE: + return None + raise + return sock + + +def test_connect(): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + try: + eintr_retry_call(sock.connect, address) + except socket.error: + return False + else: + eintr_retry_call(sock.sendall, EOF) + finally: + sock.close() + return True + + +def cleanup_lockfile(fd, *args): + try: + # Remove the directory entry for the lock file + os.unlink(pidfile) + # Close the file descriptor + os.close(fd) + except EnvironmentError: + pass + if args: + # Called in signal handler + raise SystemExit(1) + + +def lockpidfile(): + import fcntl + import atexit + import stat + fd = os.open(pidfile, os.O_WRONLY|os.O_CREAT, + stat.S_IRUSR|stat.S_IWUSR|stat.S_IRGRP|stat.S_IROTH) + try: + fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except EnvironmentError: + os.close(fd) + return None + os.lseek(fd, 0, os.SEEK_SET) + os.ftruncate(fd, 0) + os.write(fd, ('%d' % os.getpid()).encode('ascii')) + os.fsync(fd) + cleanup = partial(cleanup_lockfile, fd) + signal(SIGTERM, cleanup) + atexit.register(cleanup) + return fd + + +def main(): + p = ArgumentParser(description= + 'Daemon to improve the performance of powerline') + a = p.add_mutually_exclusive_group().add_argument + a('--kill', '-k', action='store_true', help='Kill an already running instance') + a('--foreground', '-f', action='store_true', help='Run in the foreground (dont daemonize)') + a('--replace', '-r', action='store_true', help='Replace an already running instance') + args = p.parse_args() + + if args.kill: + if test_connect(): + print ('Kill command sent to daemon, if it does not die in a couple of seconds use kill to kill it') + else: + print ('No running daemon found') + return + + if args.replace: + while test_connect(): + print ('Kill command sent to daemon, waiting for daemon to exit, press Ctrl-C to terminate wait and exit') + sleep(2) + + if use_filesystem and not args.foreground: + # We must daemonize before creating the locked pidfile, unfortunately, + # this means further print statements are discarded + daemonize() + + if use_filesystem: + # Create a locked pid file containing the daemon's PID + if lockpidfile() is None: + print ('The daemon is already running. Use %s -k to kill it.' % os.path.basename(sys.argv[0]), + file=sys.stderr) + raise SystemExit(1) + + # Bind to address or bail if we cannot bind + sock = check_existing() + if sock is None: + print ('The daemon is already running. Use %s -k to kill it.' % os.path.basename(sys.argv[0]), + file=sys.stderr) + raise SystemExit(1) + + if args.foreground: + return main_loop(sock) + + if not use_filesystem: + # We daemonize on linux + daemonize() + + main_loop(sock) + + +if __name__ == '__main__': + main() diff --git a/scripts/powerline b/scripts/powerline-render similarity index 100% rename from scripts/powerline rename to scripts/powerline-render diff --git a/setup.py b/setup.py index e341ceec..770a927e 100755 --- a/setup.py +++ b/setup.py @@ -3,16 +3,42 @@ from __future__ import unicode_literals import os import sys +import subprocess from setuptools import setup, find_packages -here = os.path.abspath(os.path.dirname(__file__)) +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) try: - README = open(os.path.join(here, 'README.rst'), 'rb').read().decode('utf-8') + README = open(os.path.join(CURRENT_DIR, 'README.rst'), 'rb').read().decode('utf-8') except IOError: README = '' -old_python = sys.version_info < (2, 7) +OLD_PYTHON = sys.version_info < (2, 7) + + +def compile_client(): + '''Compile the C powerline-client script.''' + + if hasattr(sys, 'getwindowsversion'): + raise NotImplementedError() + if sys.version_info >= (3, 0): + # FIXME Python 3 doesn't allow compiled C files to be included in the + # scripts list below. This is because Python 3 distutils tries to + # decode the file to ASCII, and fails when powerline-client is + # a binary. + raise NotImplementedError() + else: + from distutils.ccompiler import new_compiler + compiler = new_compiler().compiler + subprocess.check_call(compiler + ['-O3', 'client/powerline.c', '-o', 'scripts/powerline']) + +try: + compile_client() +except Exception: + # FIXME Catch more specific exceptions + import shutil + print('Compiling C version of powerline-client failed, using Python version instead') + shutil.copyfile('client/powerline.py', 'scripts/powerline') setup( name='Powerline', @@ -26,6 +52,8 @@ setup( scripts=[ 'scripts/powerline', 'scripts/powerline-lint', + 'scripts/powerline-daemon', + 'scripts/powerline-render', 'scripts/powerline-config', ], keywords='', @@ -38,5 +66,5 @@ setup( 'Sphinx', ], }, - test_suite='tests' if not old_python else None, + test_suite='tests' if not OLD_PYTHON else None, )