# Copyright (C) 2005 Aaron Bentley and Panometrics, Inc.
# <abentley@panoramicfeedback.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import calendar
import time
import os
import tempfile
import shutil
import doctest
def search_parent_directories(path, filename):
"""
Find the file (or directory) named filename in path or in any
of path's parents.
e.g.
search_parent_directories("/a/b/c", ".be")
will return the path to the first existing file from
/a/b/c/.be
/a/b/.be
/a/.be
/.be
or None if none of those files exist.
"""
path = os.path.realpath(path)
assert os.path.exists(path)
old_path = None
while True:
check_path = os.path.join(path, filename)
if os.path.exists(check_path):
return check_path
if path == old_path:
return None
old_path = path
path = os.path.dirname(path)
class Dir (object):
"A temporary directory for testing use"
def __init__(self):
self.path = tempfile.mkdtemp(prefix="BEtest")
self.rmtree = shutil.rmtree # save local reference for __del__
self.removed = False
def __del__(self):
self.cleanup()
def cleanup(self):
if self.removed == False:
self.rmtree(self.path)
self.removed = True
def __call__(self):
return self.path
RFC_2822_TIME_FMT = "%a, %d %b %Y %H:%M:%S +0000"
def time_to_str(time_val):
"""Convert a time value into an RFC 2822-formatted string. This format
lacks sub-second data.
>>> time_to_str(0)
'Thu, 01 Jan 1970 00:00:00 +0000'
"""
return time.strftime(RFC_2822_TIME_FMT, time.gmtime(time_val))
def str_to_time(str_time):
"""Convert an RFC 2822-fomatted string into a time falue.
>>> str_to_time("Thu, 01 Jan 1970 00:00:00 +0000")
0
>>> q = time.time()
>>> str_to_time(time_to_str(q)) == int(q)
True
"""
return calendar.timegm(time.strptime(str_time, RFC_2822_TIME_FMT))
def handy_time(time_val):
return time.strftime("%a, %d %b %Y %H:%M", time.localtime(time_val))
class CantFindEditor(Exception):
def __init__(self):
Exception.__init__(self, "Can't find editor to get string from")
def editor_string(comment=None):
"""Invokes the editor, and returns the user_produced text as a string
>>> if "EDITOR" in os.environ:
... del os.environ["EDITOR"]
>>> if "VISUAL" in os.environ:
... del os.environ["VISUAL"]
>>> editor_string()
Traceback (most recent call last):
CantFindEditor: Can't find editor to get string from
>>> os.environ["EDITOR"] = "echo bar > "
>>> editor_string()
u'bar\\n'
>>> os.environ["VISUAL"] = "echo baz > "
>>> editor_string()
u'baz\\n'
>>> del os.environ["EDITOR"]
>>> del os.environ["VISUAL"]
"""
for name in ('VISUAL', 'EDITOR'):
try:
editor = os.environ[name]
break
except KeyError:
pass
else:
raise CantFindEditor()
fhandle, fname = tempfile.mkstemp()
try:
if comment is not None:
os.write(fhandle, '\n'+comment_string(comment))
os.close(fhandle)
oldmtime = os.path.getmtime(fname)
os.system("%s %s" % (editor, fname))
output = trimmed_string(file(fname, "rb").read().decode("utf-8"))
if output.rstrip('\n') == "":
output = None
finally:
os.unlink(fname)
return output
def comment_string(comment):
"""
>>> comment_string('hello')
'== Anything below this line will be ignored ==\\nhello'
"""
return '== Anything below this line will be ignored ==\n' + comment
def trimmed_string(instring):
"""
>>> trimmed_string("hello\\n== Anything below this line will be ignored")
'hello\\n'
>>> trimmed_string("hi!\\n" + comment_string('Booga'))
'hi!\\n'
"""
out = []
for line in instring.splitlines(True):
if line.startswith('== Anything below this line will be ignored'):
break
out.append(line)
return ''.join(out)
suite = doctest.DocTestSuite()