0
0
.dotfiles/powerline-bin/powerline/lib/shell.py

134 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)
import sys
import os
from subprocess import Popen, PIPE
from functools import partial
from powerline.lib.encoding import get_preferred_input_encoding, get_preferred_output_encoding
if sys.platform.startswith('win32'):
# Prevent windows from launching consoles when calling commands
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
Popen = partial(Popen, creationflags=0x08000000)
def run_cmd(pl, cmd, stdin=None, strip=True):
'''Run command and return its stdout, stripped
If running command fails returns None and logs failure to ``pl`` argument.
:param PowerlineLogger pl:
Logger used to log failures.
:param list cmd:
Command which will be run.
:param str stdin:
String passed to command. May be None.
:param bool strip:
True if the result should be stripped.
'''
try:
p = Popen(cmd, shell=False, stdout=PIPE, stdin=PIPE)
except OSError as e:
pl.exception('Could not execute command ({0}): {1}', e, cmd)
return None
else:
stdout, err = p.communicate(
stdin if stdin is None else stdin.encode(get_preferred_output_encoding()))
stdout = stdout.decode(get_preferred_input_encoding())
return stdout.strip() if strip else stdout
def asrun(pl, ascript):
'''Run the given AppleScript and return the standard output and error.'''
return run_cmd(pl, ['osascript', '-'], ascript)
def readlines(cmd, cwd):
'''Run command and read its output, line by line
:param list cmd:
Command which will be run.
:param str cwd:
Working directory of the command which will be run.
'''
p = Popen(cmd, shell=False, stdout=PIPE, stderr=PIPE, cwd=cwd)
encoding = get_preferred_input_encoding()
p.stderr.close()
with p.stdout:
for line in p.stdout:
yield line[:-1].decode(encoding)
try:
from shutil import which
except ImportError:
# shutil.which was added in python-3.3. Here is what was added:
# Lib/shutil.py, commit 5abe28a9c8fe701ba19b1db5190863384e96c798
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
'''Given a command, mode, and a PATH string, return the path which
conforms to the given mode on the PATH, or None if there is no such
file.
``mode`` defaults to os.F_OK | os.X_OK. ``path`` defaults to the result
of ``os.environ.get('PATH')``, or can be overridden with a custom search
path.
'''
# Check that a given file can be accessed with the correct mode.
# Additionally check that `file` is not a directory, as on Windows
# directories pass the os.access check.
def _access_check(fn, mode):
return (
os.path.exists(fn)
and os.access(fn, mode)
and not os.path.isdir(fn)
)
# If were given a path with a directory part, look it up directly rather
# than referring to PATH directories. This includes checking relative to the
# current directory, e.g. ./script
if os.path.dirname(cmd):
if _access_check(cmd, mode):
return cmd
return None
if path is None:
path = os.environ.get('PATH', os.defpath)
if not path:
return None
path = path.split(os.pathsep)
if sys.platform == 'win32':
# The current directory takes precedence on Windows.
if os.curdir not in path:
path.insert(0, os.curdir)
# PATHEXT is necessary to check on Windows.
pathext = os.environ.get('PATHEXT', '').split(os.pathsep)
# See if the given file matches any of the expected path extensions.
# This will allow us to short circuit when given 'python.exe'.
# If it does match, only test that one, otherwise we have to try
# others.
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
files = [cmd]
else:
files = [cmd + ext for ext in pathext]
else:
# On other platforms you dont have things like PATHEXT to tell you
# what file suffixes are executable, so just pass on cmd as-is.
files = [cmd]
seen = set()
for dir in path:
normdir = os.path.normcase(dir)
if normdir not in seen:
seen.add(normdir)
for thefile in files:
name = os.path.join(dir, thefile)
if _access_check(name, mode):
return name
return None