2013-12-16 17:20:40 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2013-12-16 20:08:28 +00:00
|
|
|
from __future__ import print_function
|
2013-12-16 17:20:40 +00:00
|
|
|
|
2013-12-16 22:13:45 +00:00
|
|
|
import errno
|
2013-12-17 02:27:41 +00:00
|
|
|
from itertools import islice
|
2013-12-16 20:08:28 +00:00
|
|
|
import os
|
2013-12-16 17:20:40 +00:00
|
|
|
import platform
|
2013-12-18 17:08:05 +00:00
|
|
|
import re
|
2013-12-16 22:13:45 +00:00
|
|
|
import shutil
|
2013-12-16 17:20:40 +00:00
|
|
|
import sys
|
2013-12-17 16:35:43 +00:00
|
|
|
import unicodedata
|
2013-12-16 17:20:40 +00:00
|
|
|
|
2013-12-18 22:51:26 +00:00
|
|
|
if sys.version_info[0] == 3:
|
|
|
|
imap = map
|
|
|
|
os.getcwdu = os.getcwd
|
|
|
|
else:
|
|
|
|
from itertools import imap
|
|
|
|
|
2013-12-16 17:20:40 +00:00
|
|
|
|
2013-12-16 20:08:28 +00:00
|
|
|
def create_dir(path):
|
|
|
|
"""Creates a directory atomically."""
|
|
|
|
try:
|
|
|
|
os.makedirs(path)
|
|
|
|
except OSError as exception:
|
|
|
|
if exception.errno != errno.EEXIST:
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
2013-12-16 21:39:49 +00:00
|
|
|
def decode(string):
|
|
|
|
"""Converts byte string to Unicode string."""
|
|
|
|
if is_python2():
|
2014-01-07 15:27:05 +00:00
|
|
|
# Python 2.6 does not support kwargs
|
|
|
|
return string.decode('utf-8', 'replace')
|
2013-12-16 21:39:49 +00:00
|
|
|
return string
|
|
|
|
|
|
|
|
|
|
|
|
def encode(string):
|
|
|
|
"""Converts Unicode string to byte string."""
|
|
|
|
if is_python2():
|
2014-01-07 15:27:05 +00:00
|
|
|
# Python 2.6 does not support kwargs
|
|
|
|
return string.encode('utf-8', 'replace')
|
2013-12-16 21:39:49 +00:00
|
|
|
return string
|
|
|
|
|
|
|
|
|
|
|
|
def encode_local(string, encoding=None):
|
|
|
|
"""Converts string into local filesystem encoding."""
|
|
|
|
if is_python2():
|
|
|
|
return decode(string).encode(encoding or sys.getfilesystemencoding())
|
|
|
|
return string
|
|
|
|
|
|
|
|
|
2013-12-17 02:27:41 +00:00
|
|
|
def first(xs):
|
|
|
|
it = iter(xs)
|
|
|
|
try:
|
2013-12-18 22:51:26 +00:00
|
|
|
if is_python3():
|
|
|
|
return it.__next__()
|
2013-12-17 02:27:41 +00:00
|
|
|
return it.next()
|
|
|
|
except StopIteration:
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2013-12-31 16:39:52 +00:00
|
|
|
def get_tab_entry_info(entry, separator):
|
2013-12-18 22:11:05 +00:00
|
|
|
"""
|
2013-12-31 16:39:52 +00:00
|
|
|
Given a tab entry in the following format return needle, index, and path:
|
2013-12-18 22:11:05 +00:00
|
|
|
|
2013-12-28 18:15:07 +00:00
|
|
|
[needle]__[index]__[path]
|
2013-12-18 17:08:05 +00:00
|
|
|
"""
|
2013-12-31 16:39:52 +00:00
|
|
|
needle, index, path = None, None, None
|
|
|
|
|
|
|
|
match_needle = re.search(r'(.*?)' + separator, entry)
|
|
|
|
match_index = re.search(separator + r'([0-9]{1})', entry)
|
2013-12-30 23:44:39 +00:00
|
|
|
match_path = re.search(
|
|
|
|
separator + r'[0-9]{1}' + separator + r'(.*)',
|
2013-12-31 16:39:52 +00:00
|
|
|
entry)
|
2013-12-28 18:15:07 +00:00
|
|
|
|
2013-12-30 23:44:39 +00:00
|
|
|
if match_needle:
|
2013-12-31 16:39:52 +00:00
|
|
|
needle = match_needle.group(1)
|
|
|
|
|
|
|
|
if match_index:
|
|
|
|
index = int(match_index.group(1))
|
2013-12-30 23:44:39 +00:00
|
|
|
|
|
|
|
if match_path:
|
|
|
|
path = match_path.group(1)
|
|
|
|
|
2013-12-31 16:39:52 +00:00
|
|
|
return needle, index, path
|
2013-12-18 17:08:05 +00:00
|
|
|
|
|
|
|
|
2013-12-17 20:48:12 +00:00
|
|
|
def get_pwd():
|
|
|
|
try:
|
|
|
|
return os.getcwdu()
|
|
|
|
except OSError:
|
|
|
|
print("Current directory no longer exists.", file=sys.stderr)
|
2014-01-01 00:02:08 +00:00
|
|
|
raise
|
2013-12-17 20:48:12 +00:00
|
|
|
|
|
|
|
|
2013-12-17 16:35:43 +00:00
|
|
|
def has_uppercase(string):
|
2013-12-18 22:51:26 +00:00
|
|
|
if is_python3():
|
|
|
|
return any(ch.isupper() for ch in string)
|
2013-12-17 16:35:43 +00:00
|
|
|
return any(unicodedata.category(c) == 'Lu' for c in unicode(string))
|
|
|
|
|
|
|
|
|
2013-12-17 22:06:27 +00:00
|
|
|
def in_bash():
|
|
|
|
return 'bash' in os.getenv('SHELL')
|
|
|
|
|
|
|
|
|
2013-12-16 21:39:49 +00:00
|
|
|
def is_python2():
|
|
|
|
return sys.version_info[0] == 2
|
|
|
|
|
|
|
|
|
2013-12-18 22:51:26 +00:00
|
|
|
def is_python3():
|
|
|
|
return sys.version_info[0] == 3
|
|
|
|
|
|
|
|
|
2013-12-16 17:20:40 +00:00
|
|
|
def is_linux():
|
|
|
|
return platform.system() == 'Linux'
|
|
|
|
|
|
|
|
|
|
|
|
def is_osx():
|
|
|
|
return platform.system() == 'Darwin'
|
|
|
|
|
|
|
|
|
2013-12-16 20:08:28 +00:00
|
|
|
def is_windows():
|
|
|
|
return platform.system() == 'Windows'
|
|
|
|
|
|
|
|
|
2013-12-17 21:57:36 +00:00
|
|
|
def last(xs):
|
|
|
|
it = iter(xs)
|
|
|
|
tmp = None
|
|
|
|
try:
|
2013-12-18 22:51:26 +00:00
|
|
|
if is_python3():
|
|
|
|
while True:
|
|
|
|
tmp = it.__next__()
|
|
|
|
else:
|
|
|
|
while True:
|
|
|
|
tmp = it.next()
|
2013-12-17 21:57:36 +00:00
|
|
|
except StopIteration:
|
|
|
|
return tmp
|
|
|
|
|
|
|
|
|
2013-12-16 20:08:28 +00:00
|
|
|
def move_file(src, dst):
|
|
|
|
"""
|
|
|
|
Atomically move file.
|
|
|
|
|
|
|
|
Windows does not allow for atomic file renaming (which is used by
|
|
|
|
os.rename / shutil.move) so destination paths must first be deleted.
|
|
|
|
"""
|
|
|
|
if is_windows() and os.path.exists(dst):
|
|
|
|
# raises exception if file is in use on Windows
|
|
|
|
os.remove(dst)
|
|
|
|
shutil.move(src, dst)
|
2013-12-16 22:54:27 +00:00
|
|
|
|
|
|
|
|
2013-12-17 20:48:12 +00:00
|
|
|
def print_entry(entry):
|
|
|
|
print(encode_local("%.1f:\t%s" % (entry.weight, entry.path)))
|
2013-12-17 02:27:41 +00:00
|
|
|
|
|
|
|
|
2013-12-18 17:08:05 +00:00
|
|
|
def print_tab_menu(needle, tab_entries, separator):
|
|
|
|
"""
|
|
|
|
Prints the tab completion menu according to the following format:
|
|
|
|
|
|
|
|
[needle]__[index]__[possible_match]
|
|
|
|
|
|
|
|
The needle (search pattern) and index are necessary to recreate the results
|
|
|
|
on subsequent calls.
|
|
|
|
"""
|
|
|
|
for i, entry in enumerate(tab_entries):
|
2013-12-31 14:37:33 +00:00
|
|
|
print(encode_local(
|
2013-12-18 17:08:05 +00:00
|
|
|
'%s%s%d%s%s' % (
|
|
|
|
needle,
|
2013-12-17 22:46:01 +00:00
|
|
|
separator,
|
2013-12-28 13:13:47 +00:00
|
|
|
i + 1,
|
2013-12-17 22:46:01 +00:00
|
|
|
separator,
|
2013-12-31 14:37:33 +00:00
|
|
|
entry.path)))
|
2013-12-17 22:46:01 +00:00
|
|
|
|
|
|
|
|
2013-12-18 17:08:05 +00:00
|
|
|
def sanitize(directories):
|
2013-12-31 22:34:35 +00:00
|
|
|
clean = lambda x: decode(x) if len(x) == 1 else decode(x).rstrip(os.sep)
|
2013-12-18 22:51:26 +00:00
|
|
|
return list(imap(clean, directories))
|
2013-12-18 17:08:05 +00:00
|
|
|
|
|
|
|
|
2013-12-17 16:54:55 +00:00
|
|
|
def second(xs):
|
|
|
|
it = iter(xs)
|
|
|
|
try:
|
|
|
|
it.next()
|
|
|
|
return it.next()
|
|
|
|
except StopIteration:
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2013-12-17 22:06:27 +00:00
|
|
|
def surround_quotes(string):
|
2013-12-18 18:06:42 +00:00
|
|
|
"""
|
|
|
|
Bash has problems dealing with certain paths so we're surrounding all
|
|
|
|
path outputs with quotes.
|
|
|
|
"""
|
2014-01-07 15:27:05 +00:00
|
|
|
if in_bash() and string:
|
|
|
|
# Python 2.6 requres field numbers
|
|
|
|
return '"{0}"'.format(string)
|
2013-12-17 22:06:27 +00:00
|
|
|
return string
|
|
|
|
|
|
|
|
|
2013-12-17 02:27:41 +00:00
|
|
|
def take(n, iterable):
|
|
|
|
"""Return first n items of an iterable."""
|
|
|
|
return islice(iterable, n)
|