From 5283837e6d378d289e751243ba8594220042827c Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 20 Apr 2020 03:19:58 +0000 Subject: [PATCH] windows fixes --- copyparty/__init__.py | 9 ++++++++- copyparty/__main__.py | 4 +++- copyparty/authsrv.py | 3 ++- copyparty/broker_mp.py | 4 +++- copyparty/broker_util.py | 7 +------ copyparty/httpcli.py | 4 ++-- copyparty/stolen/surrogateescape.py | 8 +++++++- copyparty/svchub.py | 16 ++++++++++++--- copyparty/up2k.py | 7 +++---- copyparty/util.py | 31 ++++++++++++++++++++++------- 10 files changed, 66 insertions(+), 27 deletions(-) diff --git a/copyparty/__init__.py b/copyparty/__init__.py index 2acd1cc7..7eb133e2 100644 --- a/copyparty/__init__.py +++ b/copyparty/__init__.py @@ -5,11 +5,17 @@ import platform import sys import os -WINDOWS = platform.system() == "Windows" PY2 = sys.version_info[0] == 2 if PY2: sys.dont_write_bytecode = True +WINDOWS = False +if platform.system() == "Windows": + WINDOWS = [int(x) for x in platform.version().split(".")] + +VT100 = not WINDOWS or WINDOWS >= [10, 0, 14393] +# introduced in anniversary update + class EnvParams(object): def __init__(self): @@ -24,6 +30,7 @@ class EnvParams(object): + "/copyparty" ) + self.cfg = self.cfg.replace("\\", "/") try: os.makedirs(self.cfg) except: diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 31c0258f..8d71c7b7 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -15,7 +15,7 @@ import locale import argparse from textwrap import dedent -from .__init__ import E, WINDOWS +from .__init__ import E, WINDOWS, VT100 from .__version__ import S_VERSION, S_BUILD_DT from .svchub import SvcHub from .util import py_desc @@ -28,6 +28,8 @@ class RiceFormatter(argparse.HelpFormatter): except the help += [...] line now has colors """ fmt = "\033[36m (default: \033[35m%(default)s\033[36m)\033[0m" + if not VT100: + fmt = " (default: %(default)s)" help = action.help if "%(default)" not in action.help: diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index 8342dbcb..33d1eccf 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -99,7 +99,8 @@ class VFS(object): """return user-readable [fsdir,real,virt] items at vpath""" virt_vis = {} # nodes readable by user abspath = self.canonical(rem) - real = [fsdec(x) for x in os.listdir(fsenc(abspath))] + items = os.listdir(fsenc(abspath)) + real = [fsdec(x) for x in items] real.sort() if not rem: for name, vn2 in sorted(self.nodes.items()): diff --git a/copyparty/broker_mp.py b/copyparty/broker_mp.py index 0e02091a..fcdf9fbb 100644 --- a/copyparty/broker_mp.py +++ b/copyparty/broker_mp.py @@ -4,7 +4,7 @@ from __future__ import print_function, unicode_literals import time import threading -from .__init__ import PY2, WINDOWS +from .__init__ import PY2, WINDOWS, VT100 from .broker_util import try_exec from .broker_mpw import MpWorker from .util import mp @@ -141,6 +141,8 @@ class BrokerMp(object): def debug_load_balancer(self): fmt = "\033[1m{}\033[0;36m{:4}\033[0m " + if not VT100: + fmt = "({}{:4})" last = "" while self.procs: diff --git a/copyparty/broker_util.py b/copyparty/broker_util.py index b635f600..3406dc91 100644 --- a/copyparty/broker_util.py +++ b/copyparty/broker_util.py @@ -5,12 +5,7 @@ from __future__ import print_function, unicode_literals import traceback from .__init__ import PY2 -from .util import Pebkac - -if not PY2: - from queue import Queue -else: - from Queue import Queue # pylint: disable=import-error,no-name-in-module +from .util import Pebkac, Queue class ExceptionalQueue(Queue, object): diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index cf9a1dae..fe5a280b 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -699,8 +699,8 @@ class HttpCli(object): try: inf = os.stat(fsenc(fspath)) - except FileNotFoundError: - self.log("broken symlink: {}".format(fspath)) + except: + self.log("broken symlink: {}".format(repr(fspath))) continue is_dir = stat.S_ISDIR(inf.st_mode) diff --git a/copyparty/stolen/surrogateescape.py b/copyparty/stolen/surrogateescape.py index d8830dfc..18e4431b 100644 --- a/copyparty/stolen/surrogateescape.py +++ b/copyparty/stolen/surrogateescape.py @@ -10,11 +10,12 @@ Original source: misc/python/surrogateescape.py in https://bitbucket.org/haypo/m # This code is released under the Python license and the BSD 2-clause license +import platform import codecs import sys PY3 = sys.version_info[0] > 2 - +WINDOWS = platform.system() == "Windows" FS_ERRORS = "surrogateescape" @@ -168,6 +169,11 @@ FS_ENCODING = sys.getfilesystemencoding() # FS_ENCODING = 'UTF-8'; fn = b('[abc\xff]'); encoded = u('[abc\udcff]') +if WINDOWS and not PY3: + # py2 thinks win* is mbcs, probably a bug? anyways this works + FS_ENCODING = 'utf-8' + + # normalize the filesystem encoding name. # For example, we expect "utf-8", not "UTF8". FS_ENCODING = codecs.lookup(FS_ENCODING).name diff --git a/copyparty/svchub.py b/copyparty/svchub.py index b41db72b..952527b8 100644 --- a/copyparty/svchub.py +++ b/copyparty/svchub.py @@ -8,7 +8,7 @@ import threading from datetime import datetime, timedelta import calendar -from .__init__ import PY2, WINDOWS +from .__init__ import PY2, WINDOWS, VT100 from .tcpsrv import TcpSrv from .up2k import Up2k from .util import mp @@ -84,13 +84,23 @@ class SvcHub(object): dt = dt.replace(hour=0, minute=0, second=0) self.next_day = calendar.timegm(dt.utctimetuple()) - ts = datetime.utcfromtimestamp(now).strftime("%H:%M:%S.%f")[:-3] fmt = "\033[36m{} \033[33m{:21} \033[0m{}" + if not VT100: + fmt = "{} {:21} {}" + if "\033" in msg: + msg = self.ansi_re.sub("", msg) + if "\033" in src: + src = self.ansi_re.sub("", src) + + ts = datetime.utcfromtimestamp(now).strftime("%H:%M:%S.%f")[:-3] msg = fmt.format(ts, src, msg) try: print(msg) except UnicodeEncodeError: - print(msg.encode("utf-8", "replace").decode()) + try: + print(msg.encode("utf-8", "replace").decode()) + except: + print(msg.encode("ascii", "replace").decode()) def check_mp_support(self): vmin = sys.version_info[1] diff --git a/copyparty/up2k.py b/copyparty/up2k.py index 34761f96..d6375b3d 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -10,11 +10,10 @@ import shutil import base64 import hashlib import threading -from queue import Queue from copy import deepcopy from .__init__ import WINDOWS -from .util import Pebkac +from .util import Pebkac, Queue class Up2k(object): @@ -105,8 +104,8 @@ class Up2k(object): try: lsrc = src ldst = dst - fs1 = os.stat(cj["rdir"]).st_dev - fs2 = os.stat(job["rdir"]).st_dev + fs1 = os.stat(os.path.split(src)[0]).st_dev + fs2 = os.stat(os.path.split(dst)[0]).st_dev if fs1 == 0: # py2 on winxp or other unsupported combination raise OSError() diff --git a/copyparty/util.py b/copyparty/util.py index 0029ca5b..0fd94cc1 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -10,7 +10,7 @@ import platform import threading import subprocess as sp # nosec -from .__init__ import PY2 +from .__init__ import PY2, WINDOWS from .stolen import surrogateescape FAKE_MP = False @@ -27,12 +27,16 @@ except ImportError: if not PY2: from urllib.parse import unquote_to_bytes as unquote from urllib.parse import quote_from_bytes as quote + from queue import Queue else: from urllib import unquote # pylint: disable=no-name-in-module from urllib import quote # pylint: disable=no-name-in-module + from Queue import Queue # pylint: disable=import-error,no-name-in-module surrogateescape.register_surrogateescape() FS_ENCODING = sys.getfilesystemencoding() +if WINDOWS and PY2: + FS_ENCODING = "utf-8" HTTPCODE = { @@ -362,24 +366,24 @@ def exclude_dotfiles(filepaths): def quotep(txt): """url quoter which deals with bytes correctly""" - btxt = fsenc(txt) + btxt = w8enc(txt) quot1 = quote(btxt, safe=b"/") if not PY2: quot1 = quot1.encode("ascii") quot2 = quot1.replace(b" ", b"+") - return fsdec(quot2) + return w8dec(quot2) def unquotep(txt): """url unquoter which deals with bytes correctly""" - btxt = fsenc(txt) + btxt = w8enc(txt) unq1 = btxt.replace(b"+", b" ") unq2 = unquote(unq1) - return fsdec(unq2) + return w8dec(unq2) -def fsdec(txt): +def w8dec(txt): """decodes filesystem-bytes to wtf8""" if PY2: return surrogateescape.decodefilename(txt) @@ -387,7 +391,7 @@ def fsdec(txt): return txt.decode(FS_ENCODING, "surrogateescape") -def fsenc(txt): +def w8enc(txt): """encodes wtf8 to filesystem-bytes""" if PY2: return surrogateescape.encodefilename(txt) @@ -395,6 +399,19 @@ def fsenc(txt): return txt.encode(FS_ENCODING, "surrogateescape") +if PY2 and WINDOWS: + # moonrunes become \x3f with bytestrings, + # losing mojibake support is worth + def _not_actually_mbcs(txt): + return txt + + fsenc = _not_actually_mbcs + fsdec = _not_actually_mbcs +else: + fsenc = w8enc + fsdec = w8dec + + def read_socket(sr, total_size): remains = total_size while remains > 0: