where = os.path.realpath(sys.argv[0])
base = os.path.dirname(os.path.dirname(where))
+if sys.platform == "win32":
+ installed_tahoe = os.path.join(os.path.dirname(sys.executable), 'Scripts', 'tahoe.pyscript')
+else:
+ installed_tahoe = "/usr/bin/tahoe"
+
whoami = '''\
-I am a "bin/tahoe" executable who is only for the convenience of running
+I am a "bin%stahoe" executable who is only for the convenience of running
Tahoe from its source distribution -- I work only when invoked as the "tahoe"
script that lives in the "bin/" subdirectory of a Tahoe source code
distribution, and only if you have already run "make".
-'''
+''' % (os.path.sep,)
# look for Tahoe.home .
homemarker = os.path.join(base, "Tahoe.home")
print '''\
I just tried to run and found that I am not living in such a directory, so I
am stopping now. To run Tahoe after it has been is installed, please execute
-my brother, also named "tahoe", who gets installed into the appropriate place
-for executables when you run "make install" (perhaps as /usr/bin/tahoe).
-'''
+my brother, who gets installed into the appropriate place for executables
+when you run "make install" (perhaps as "%s").
+''' % (installed_tahoe,)
sys.exit(1)
# we've found our home. Put the tahoe support/lib etc. in our PYTHONPATH.
pp = supportdir
os.environ["PYTHONPATH"] = pp
-# find the location of the tahoe executable.
-bin_dir = "bin"
+# find commandline args and the location of the tahoe executable.
if sys.platform == "win32":
- bin_dir = "Scripts"
-executable = os.path.join(base, "support", bin_dir, "tahoe")
+ import re
+ from ctypes import WINFUNCTYPE, POINTER, byref, c_wchar_p, c_int, windll
+
+ GetCommandLineW = WINFUNCTYPE(c_wchar_p)(("GetCommandLineW", windll.kernel32))
+ CommandLineToArgvW = WINFUNCTYPE(POINTER(c_wchar_p), c_wchar_p, POINTER(c_int)) \
+ (("CommandLineToArgvW", windll.shell32))
+
+ argc = c_int(0)
+ argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
+
+ # See src/allmydata/scripts/runner.py for the corresponding unmangler.
+ # Note that this doesn't escape \x7F. If it did, test_unicode_arguments_and_output
+ # in test_runner.py wouldn't work.
+ def mangle(s):
+ return str(re.sub(ur'[^\x20-\x7F]', lambda m: u'\x7F%x;' % (ord(m.group(0)),), s))
+
+ argv = [mangle(argv_unicode[i]) for i in xrange(1, argc.value)]
+ local_tahoe = "Scripts\\tahoe.pyscript"
+else:
+ argv = sys.argv
+ local_tahoe = "bin/tahoe"
+
+script = os.path.join(base, "support", local_tahoe)
try:
- res = subprocess.call([executable] + sys.argv[1:], env=os.environ)
+ res = subprocess.call([sys.executable, script] + argv[1:], env=os.environ)
except (OSError, IOError), le:
if le.args[0] == errno.ENOENT:
print whoami
print '''\
-I just tried to run and could not find my brother, named
-"../support/bin/tahoe". To run Tahoe when it is installed, please execute my
-brother, also named "tahoe", who gets installed into the appropriate place
-for executables when you run "make install" (perhaps as /usr/bin/tahoe).
-'''
+I just tried to run and could not find my brother at
+"%s". To run Tahoe when it is installed, please execute my
+brother, who gets installed into the appropriate place for executables
+when you run "make install" (perhaps as "%s").
+''' % (script, installed_tahoe)
raise
except Exception, le:
print whoami
print '''\
-I just tried to invoke my brother, named "../support/bin/tahoe" and got an
-exception.
-'''
+I just tried to invoke my brother at "%s"
+and got an exception.
+''' % (script,)
raise
else:
sys.exit(res)
def run(self):
bin_tahoe_template = os.path.join("bin", "tahoe-script.template")
- # Create the 'tahoe-script.py' file under the 'bin' directory. The
- # 'tahoe-script.py' file is exactly the same as the
- # 'tahoe-script.template' script except that the shebang line is
- # rewritten to use our sys.executable for the interpreter. On
- # Windows, create a tahoe.exe will execute it. On non-Windows, make a
- # symlink to it from 'tahoe'. The tahoe.exe will be copied from the
- # setuptools egg's cli.exe and this will work from a zip-safe and
- # non-zip-safe setuptools egg.
+ if sys.platform == 'win32':
+ # 'tahoe' script is needed for cygwin
+ script_names = ["tahoe.pyscript", "tahoe"]
+ else:
+ script_names = ["tahoe"]
+
+ # Create the tahoe script file under the 'bin' directory. This
+ # file is exactly the same as the 'tahoe-script.template' script
+ # except that the shebang line is rewritten to use our sys.executable
+ # for the interpreter.
f = open(bin_tahoe_template, "rU")
script_lines = f.readlines()
f.close()
- script_lines[0] = "#!%s\n" % sys.executable
- tahoe_script = os.path.join("bin", "tahoe-script.py")
- f = open(tahoe_script, "w")
- for line in script_lines:
- f.write(line)
- f.close()
- if sys.platform == "win32":
- from pkg_resources import require
- setuptools_egg = require("setuptools")[0].location
- if os.path.isfile(setuptools_egg):
- z = zipfile.ZipFile(setuptools_egg, 'r')
- for filename in z.namelist():
- if 'cli.exe' in filename:
- cli_exe = z.read(filename)
- else:
- cli_exe = os.path.join(setuptools_egg, 'setuptools', 'cli.exe')
- tahoe_exe = os.path.join("bin", "tahoe.exe")
- if os.path.isfile(setuptools_egg):
- f = open(tahoe_exe, 'wb')
- f.write(cli_exe)
- f.close()
- else:
- shutil.copy(cli_exe, tahoe_exe)
- else:
+ script_lines[0] = '#!%s\n' % (sys.executable,)
+ for script_name in script_names:
+ tahoe_script = os.path.join("bin", script_name)
try:
- os.remove(os.path.join('bin', 'tahoe'))
- except:
- # okay, probably it was already gone
- pass
- os.symlink('tahoe-script.py', os.path.join('bin', 'tahoe'))
-
- # chmod +x bin/tahoe-script.py
- old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
- new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
- stat.S_IXGRP | stat.S_IRGRP |
- stat.S_IXOTH | stat.S_IROTH )
- os.chmod(tahoe_script, new_mode)
+ os.remove(tahoe_script)
+ except Exception:
+ if os.path.exists(tahoe_script):
+ raise
+ f = open(tahoe_script, "wb")
+ for line in script_lines:
+ f.write(line)
+ f.close()
+
+ # chmod +x
+ old_mode = stat.S_IMODE(os.stat(tahoe_script)[stat.ST_MODE])
+ new_mode = old_mode | (stat.S_IXUSR | stat.S_IRUSR |
+ stat.S_IXGRP | stat.S_IRGRP |
+ stat.S_IXOTH | stat.S_IROTH )
+ os.chmod(tahoe_script, new_mode)
+
+ old_tahoe_exe = os.path.join("bin", "tahoe.exe")
+ try:
+ os.remove(old_tahoe_exe)
+ except Exception:
+ if os.path.exists(old_tahoe_exe):
+ raise
+
class MySdist(sdist.sdist):
""" A hook in the sdist command so that we can determine whether this the
pkg_resources.require(allmydata.__appname__)
from allmydata.scripts.common import BaseOptions
from allmydata.scripts import debug, create_node, startstop_node, cli, keygen, stats_gatherer
+from allmydata.util.encodingutil import quote_output, get_argv_encoding
def GROUP(s):
# Usage.parseOptions compares argv[1] against command[0], so it will
class Options(BaseOptions, usage.Options):
- synopsis = "Usage: tahoe <command> [command options]"
+ synopsis = "\nUsage: tahoe <command> [command options]"
subCommands = ( GROUP("Administration")
+ create_node.subCommands
+ keygen.subCommands
def runner(argv,
run_by_human=True,
- stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr,
+ stdin=None, stdout=None, stderr=None,
install_node_control=True, additional_commands=None):
+ stdin = stdin or sys.stdin
+ stdout = stdout or sys.stdout
+ stderr = stderr or sys.stderr
+
config = Options()
if install_node_control:
config.subCommands.extend(startstop_node.subCommands)
c = config
while hasattr(c, 'subOptions'):
c = c.subOptions
- print str(c)
- print "%s: %s" % (sys.argv[0], e)
+ print >>stdout, str(c)
+ try:
+ msg = e.args[0].decode(get_argv_encoding())
+ except Exception:
+ msg = repr(e)
+ print >>stdout, "%s: %s\n" % (sys.argv[0], quote_output(msg, quotemarks=False))
return 1
command = config.subCommand
return rc
+
def run(install_node_control=True):
- rc = runner(sys.argv[1:])
+ if sys.platform == "win32":
+ from allmydata.windows.fixups import initialize
+ initialize()
+
+ rc = runner(sys.argv[1:], install_node_control=install_node_control)
sys.exit(rc)
# we disable incident reporting for all unit tests.
disable_foolscap_incidents()
+
+import sys
+if sys.platform == "win32":
+ from allmydata.windows.fixups import initialize
+ initialize()
if len(sys.argv) != 2:
print "Usage: %s lumi<e-grave>re" % sys.argv[0]
sys.exit(1)
-
+
+ if sys.platform == "win32":
+ try:
+ from allmydata.windows.fixups import initialize
+ except ImportError:
+ print "set PYTHONPATH to the src directory"
+ sys.exit(1)
+ initialize()
+
print
print "class MyWeirdOS(EncodingUtil, unittest.TestCase):"
print " uname = '%s'" % ' '.join(platform.uname())
- if sys.platform != "win32":
- print " argv = %s" % repr(sys.argv[1])
+ print " argv = %s" % repr(sys.argv[1])
print " platform = '%s'" % sys.platform
print " filesystem_encoding = '%s'" % sys.getfilesystemencoding()
print " output_encoding = '%s'" % sys.stdout.encoding
- print " argv_encoding = '%s'" % (sys.platform == "win32" and 'ascii' or sys.stdout.encoding)
-
+ print " argv_encoding = '%s'" % sys.stdout.encoding
try:
tmpdir = tempfile.mkdtemp()
for fname in TEST_FILENAMES:
import os, sys, locale
from allmydata.test.common_util import ReallyEqualMixin
+from allmydata.util import encodingutil
from allmydata.util.encodingutil import argv_to_unicode, unicode_to_url, \
unicode_to_output, quote_output, unicode_platform, listdir_unicode, \
FilenameEncodingError, get_output_encoding, get_filesystem_encoding, _reload
from twisted.python import usage
class EncodingUtilErrors(ReallyEqualMixin, unittest.TestCase):
- def tearDown(self):
- _reload()
@patch('sys.stdout')
def test_get_output_encoding(self, mock_stdout):
self.failUnlessReallyEqual(get_output_encoding(), 'utf-8')
mock_stdout.encoding = 'koi8-r'
+ expected = sys.platform == "win32" and 'utf-8' or 'koi8-r'
_reload()
- self.failUnlessReallyEqual(get_output_encoding(), 'koi8-r')
+ self.failUnlessReallyEqual(get_output_encoding(), expected)
mock_stdout.encoding = 'nonexistent_encoding'
- self.failUnlessRaises(AssertionError, _reload)
+ if sys.platform == "win32":
+ _reload()
+ self.failUnlessReallyEqual(get_output_encoding(), 'utf-8')
+ else:
+ self.failUnlessRaises(AssertionError, _reload)
@patch('locale.getpreferredencoding')
def test_get_output_encoding_not_from_stdout(self, mock_locale_getpreferredencoding):
old_stdout = sys.stdout
sys.stdout = DummyStdout()
try:
+ expected = sys.platform == "win32" and 'utf-8' or 'koi8-r'
_reload()
- self.failUnlessReallyEqual(get_output_encoding(), 'koi8-r')
+ self.failUnlessReallyEqual(get_output_encoding(), expected)
sys.stdout.encoding = None
_reload()
- self.failUnlessReallyEqual(get_output_encoding(), 'koi8-r')
+ self.failUnlessReallyEqual(get_output_encoding(), expected)
mock_locale_getpreferredencoding.return_value = None
_reload()
finally:
sys.stdout = old_stdout
- @patch('sys.stdout')
- def test_argv_to_unicode(self, mock):
- mock.encoding = 'utf-8'
- _reload()
-
+ def test_argv_to_unicode(self):
+ encodingutil.output_encoding = 'utf-8'
self.failUnlessRaises(usage.UsageError,
argv_to_unicode,
lumiere_nfc.encode('latin1'))
- @patch('sys.stdout')
- def test_unicode_to_output(self, mock):
- # Encoding koi8-r cannot represent e-grave
- mock.encoding = 'koi8-r'
- _reload()
+ def test_unicode_to_output(self):
+ encodingutil.output_encoding = 'koi8-r'
self.failUnlessRaises(UnicodeEncodeError, unicode_to_output, lumiere_nfc)
@patch('os.listdir')
listdir_unicode,
u'/' + lumiere_nfc)
+
class EncodingUtil(ReallyEqualMixin):
def setUp(self):
- # Mock sys.platform because unicode_platform() uses it
self.original_platform = sys.platform
sys.platform = self.platform
@patch('sys.stdout')
def test_unicode_to_output(self, mock):
- if 'output' not in dir(self):
+ if 'argv' not in dir(self):
return
mock.encoding = self.output_encoding
_reload()
- self.failUnlessReallyEqual(unicode_to_output(lumiere_nfc), self.output)
+ self.failUnlessReallyEqual(unicode_to_output(lumiere_nfc), self.argv)
def test_unicode_platform(self):
matrix = {
class QuoteOutput(ReallyEqualMixin, unittest.TestCase):
+ def tearDown(self):
+ _reload()
+
def _check(self, inp, out, enc, optional_quotes):
out2 = out
if optional_quotes:
out2 = out2[1:-1]
self.failUnlessReallyEqual(quote_output(inp, encoding=enc), out)
self.failUnlessReallyEqual(quote_output(inp, encoding=enc, quotemarks=False), out2)
- if out[0:2] != 'b"':
- if isinstance(inp, str):
- self.failUnlessReallyEqual(quote_output(unicode(inp), encoding=enc), out)
- self.failUnlessReallyEqual(quote_output(unicode(inp), encoding=enc, quotemarks=False), out2)
- else:
- self.failUnlessReallyEqual(quote_output(inp.encode('utf-8'), encoding=enc), out)
- self.failUnlessReallyEqual(quote_output(inp.encode('utf-8'), encoding=enc, quotemarks=False), out2)
+ if out[0:2] == 'b"':
+ pass
+ elif isinstance(inp, str):
+ self.failUnlessReallyEqual(quote_output(unicode(inp), encoding=enc), out)
+ self.failUnlessReallyEqual(quote_output(unicode(inp), encoding=enc, quotemarks=False), out2)
+ else:
+ self.failUnlessReallyEqual(quote_output(inp.encode('utf-8'), encoding=enc), out)
+ self.failUnlessReallyEqual(quote_output(inp.encode('utf-8'), encoding=enc, quotemarks=False), out2)
def _test_quote_output_all(self, enc):
def check(inp, out, optional_quotes=False):
check(u"\"\u2621", u"'\"\u2621'")
check(u"\u2621\"", u"'\u2621\"'", True)
- @patch('sys.stdout')
- def test_quote_output_mock(self, mock_stdout):
- mock_stdout.encoding = 'ascii'
- _reload()
+ def test_quote_output_default(self):
+ encodingutil.output_encoding = 'ascii'
self.test_quote_output_ascii(None)
- mock_stdout.encoding = 'latin1'
- _reload()
+ encodingutil.output_encoding = 'latin1'
self.test_quote_output_latin1(None)
- mock_stdout.encoding = 'utf-8'
- _reload()
+ encodingutil.output_encoding = 'utf-8'
self.test_quote_output_utf8(None)
class UbuntuKarmicUTF8(EncodingUtil, unittest.TestCase):
uname = 'Linux korn 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:05:01 UTC 2009 x86_64'
- output = 'lumi\xc3\xa8re'
argv = 'lumi\xc3\xa8re'
platform = 'linux2'
filesystem_encoding = 'UTF-8'
class UbuntuKarmicLatin1(EncodingUtil, unittest.TestCase):
uname = 'Linux korn 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:05:01 UTC 2009 x86_64'
- output = 'lumi\xe8re'
argv = 'lumi\xe8re'
platform = 'linux2'
filesystem_encoding = 'ISO-8859-1'
argv_encoding = 'ISO-8859-1'
dirlist = ['test_file', 'Blah blah.txt', '\xc4rtonwall.mp3']
-class WindowsXP(EncodingUtil, unittest.TestCase):
- uname = 'Windows XP 5.1.2600 x86 x86 Family 15 Model 75 Step ping 2, AuthenticAMD'
- output = 'lumi\x8are'
- platform = 'win32'
- filesystem_encoding = 'mbcs'
- output_encoding = 'cp850'
- argv_encoding = 'ascii'
- dirlist = [u'Blah blah.txt', u'test_file', u'\xc4rtonwall.mp3']
-
-class WindowsXP_UTF8(EncodingUtil, unittest.TestCase):
+class Windows(EncodingUtil, unittest.TestCase):
uname = 'Windows XP 5.1.2600 x86 x86 Family 15 Model 75 Step ping 2, AuthenticAMD'
- output = 'lumi\xc3\xa8re'
- platform = 'win32'
- filesystem_encoding = 'mbcs'
- output_encoding = 'cp65001'
- argv_encoding = 'ascii'
- dirlist = [u'Blah blah.txt', u'test_file', u'\xc4rtonwall.mp3']
-
-class WindowsVista(EncodingUtil, unittest.TestCase):
- uname = 'Windows Vista 6.0.6000 x86 x86 Family 6 Model 15 Stepping 11, GenuineIntel'
- output = 'lumi\x8are'
+ argv = 'lumi\xc3\xa8re'
platform = 'win32'
filesystem_encoding = 'mbcs'
- output_encoding = 'cp850'
- argv_encoding = 'ascii'
+ output_encoding = 'utf-8'
+ argv_encoding = 'utf-8'
dirlist = [u'Blah blah.txt', u'test_file', u'\xc4rtonwall.mp3']
class MacOSXLeopard(EncodingUtil, unittest.TestCase):
uname = 'Darwin g5.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:57:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_PPC Power Macintosh powerpc'
output = 'lumi\xc3\xa8re'
- argv = 'lumi\xc3\xa8re'
platform = 'darwin'
filesystem_encoding = 'utf-8'
output_encoding = 'UTF-8'
import os.path, re, sys
from cStringIO import StringIO
from allmydata.util import fileutil, pollmixin
+from allmydata.util.encodingutil import unicode_to_argv, unicode_to_output
from allmydata.scripts import runner
from allmydata.test import common_util
d.addCallback(_cb)
return d
+ def test_unicode_arguments_and_output(self):
+ self.skip_if_cannot_run_bintahoe()
+
+ tricky = u"\u2621"
+ try:
+ tricky_arg = unicode_to_argv(tricky, mangle=True)
+ tricky_out = unicode_to_output(tricky)
+ except UnicodeEncodeError:
+ raise unittest.SkipTest("A non-ASCII argument/output could not be encoded on this platform.")
+
+ d = utils.getProcessOutputAndValue(bintahoe, args=[tricky_arg], env=os.environ)
+ def _cb(res):
+ out, err, rc_or_sig = res
+ self.failUnlessEqual(rc_or_sig, 1, str((out, err, rc_or_sig)))
+ self.failUnlessIn("Unknown command: "+tricky_out, out)
+ d.addCallback(_cb)
+ return d
+
def test_version_no_noise(self):
self.skip_if_cannot_run_bintahoe()
import pkg_resources
from allmydata.util.fileutil import abspath_expanduser_unicode
-def _canonical_encoding(encoding):
+def canonical_encoding(encoding):
if encoding is None:
log.msg("Warning: falling back to UTF-8 encoding.", level=log.WEIRD)
encoding = 'utf-8'
elif encoding == "us-ascii" or encoding == "646" or encoding == "ansi_x3.4-1968":
encoding = 'ascii'
+ return encoding
+
+def check_encoding(encoding):
# sometimes Python returns an encoding name that it doesn't support for conversion
# fail early if this happens
try:
except (LookupError, AttributeError):
raise AssertionError("The character encoding '%s' is not supported for conversion." % (encoding,))
- return encoding
-
filesystem_encoding = None
output_encoding = None
argv_encoding = None
def _reload():
global filesystem_encoding, output_encoding, argv_encoding, is_unicode_platform
- filesystem_encoding = _canonical_encoding(sys.getfilesystemencoding())
-
- outenc = None
- if hasattr(sys.stdout, 'encoding'):
- outenc = sys.stdout.encoding
- if outenc is None:
- try:
- outenc = locale.getpreferredencoding()
- except Exception:
- pass # work around <http://bugs.python.org/issue1443504>
- output_encoding = _canonical_encoding(outenc)
+ filesystem_encoding = canonical_encoding(sys.getfilesystemencoding())
+ check_encoding(filesystem_encoding)
if sys.platform == 'win32':
- # Unicode arguments are not supported on Windows yet; see #565 and #1074.
- argv_encoding = 'ascii'
+ # On Windows we install UTF-8 stream wrappers for sys.stdout and
+ # sys.stderr, and reencode the arguments as UTF-8 (see scripts/runner.py).
+ output_encoding = 'utf-8'
else:
- argv_encoding = output_encoding
+ outenc = None
+ if hasattr(sys.stdout, 'encoding'):
+ outenc = sys.stdout.encoding
+ if outenc is None:
+ try:
+ outenc = locale.getpreferredencoding()
+ except Exception:
+ pass # work around <http://bugs.python.org/issue1443504>
+ output_encoding = canonical_encoding(outenc)
+
+ check_encoding(output_encoding)
+ argv_encoding = output_encoding
+
is_unicode_platform = sys.platform in ["win32", "darwin"]
_reload()