1
0
mirror of https://github.com/gryf/mc_adbfs.git synced 2025-12-18 20:10:21 +01:00

Fix bad filenames for Python3.

In Python3, if there are filenames encoded with 8-bit encodings, there
might be an issues with converting them into unicode objects. This is a
workaround on this subject. Python2 is not affected.

Other than that, there was tests added to cover this case, appropriate
Makefile which automate creating venvs for both: Python 2 and 3, and
also there is a check against pep8 rules using flake8.
This commit is contained in:
2019-05-14 21:10:28 +02:00
parent 63fdc2c605
commit 5ece2d579c
5 changed files with 184 additions and 5 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.test
__pycache__
adbfsc

55
Makefile Normal file
View File

@@ -0,0 +1,55 @@
# simple makefile for running tests for the adbfs plugin
all: test_dir py2 py3 flake8
TEST_DIR='.test'
PY2_VENV=$(TEST_DIR)/py2
PY3_VENV=$(TEST_DIR)/py3
FL8_VENV=$(TEST_DIR)/flake8
TST_EXISTS=$(shell [ -e $(TEST_DIR) ] && echo 1 || echo 0)
PY2_EXISTS=$(shell [ -e $(PY2_VENV) ] && echo 1 || echo 0)
PY3_EXISTS=$(shell [ -e $(PY3_VENV) ] && echo 1 || echo 0)
FL8_EXISTS=$(shell [ -e $(FL8_VENV) ] && echo 1 || echo 0)
py3: test_dir virtualenv3
.test/py3/bin/python test_adbfs.py
py2: test_dir virtualenv2
.test/py2/bin/python test_adbfs.py
flake8: test_dir virtualenv_flake8
.test/flake8/bin/flake8 adbfs test_adbfs.py
ifeq ($(TST_EXISTS), 0)
test_dir:
mkdir -p .test
else
test_dir:
endif
ifeq ($(PY3_EXISTS), 0)
virtualenv3:
virtualenv -p python3 $(PY3_VENV)
$(PY3_VENV)/bin/pip install six
else
virtualenv3:
endif
ifeq ($(PY2_EXISTS), 0)
virtualenv2:
virtualenv -p python2 $(PY2_VENV)
$(PY2_VENV)/bin/pip install mock
else
virtualenv2:
endif
ifeq ($(FL8_EXISTS), 0)
virtualenv_flake8:
virtualenv -p python2 $(FL8_VENV)
$(FL8_VENV)/bin/pip install flake8
else
virtualenv_flake8:
endif
clean:
rm -fr $(TEST_DIR) __pycache__ adbfsc

View File

@@ -5,6 +5,7 @@ Midnight Commander adbfs external fs plugin
This is Midnight Commander extfs plugin for browsing Android device through This is Midnight Commander extfs plugin for browsing Android device through
``adb`` interface written in Python. ``adb`` interface written in Python.
Rquirements Rquirements
=========== ===========
@@ -24,6 +25,7 @@ Make sure, that issuing from command line:
it should display files from root directory on the device. it should display files from root directory on the device.
Features Features
======== ========
@@ -35,12 +37,14 @@ Features
* Symbolic links in lists are corrected to be relative to the file system * Symbolic links in lists are corrected to be relative to the file system
* Symbolic links also point to the right target, skipping intermediate links * Symbolic links also point to the right target, skipping intermediate links
Installation Installation
============ ============
Copy adbfs into ``~/.local/share/mc/extfs.d/`` directory and make it executable Copy adbfs into ``~/.local/share/mc/extfs.d/`` directory and make it executable
if needed. if needed.
Usage Usage
===== =====
@@ -48,13 +52,14 @@ To use it, just issue:
.. code:: shell-session .. code:: shell-session
cd adbfs:// $ cd adbfs://
under MC - after some time you should see the files and directories on your under MC - after some time you should see the files and directories on your
device. For convenience you can add a bookmark (accessible under CTRL+\) for device. For convenience you can add a bookmark (accessible under CTRL+\\) for
fast access. The time is depended on how many files and directories you have on fast access. The time is depended on how many files and directories you have on
your device and how fast it is :) your device and how fast it is :)
Configuration Configuration
============= =============
@@ -72,7 +77,6 @@ You can configure behaviour of this plugin using ``.ini`` file located under
adb_command = adb adb_command = adb
adb_connect = adb_connect =
where: where:
* ``debug`` will provide a little bit more verbose information, useful for * ``debug`` will provide a little bit more verbose information, useful for
@@ -93,6 +97,43 @@ where:
feature. Typical value here is a device IP address with optional port, which feature. Typical value here is a device IP address with optional port, which
defaults to 5555. defaults to 5555.
Contribution
============
There is a ``Makefile`` in the top directory, which is basic helper for running
the tests. Please use it, and adapt/add tests for provided fixes/functionality.
It requires GNU ``make`` program, and also ``virtualenv`` besides Python in
version 2 and 3. Using it is simple as running following command:
.. code:: shell-session
$ make
it will run `py2`, `py3` and `flake8` jobs to check it against the code. For
running tests against Python 3:
.. code:: shell-session
$ make py3
or Python 2:
.. code:: shell-session
$ make py2
or flake 8:
.. code:: shell-session
$ make flake8
Exit status on any of those means that test fail. Appropriate message/traceback
will also be visible.
Limitations Limitations
=========== ===========
@@ -103,6 +144,7 @@ Limitations
* The implementation is experimental and it's by now working with mine device; * The implementation is experimental and it's by now working with mine device;
while it might not work with yours while it might not work with yours
License License
======= =======

12
adbfs
View File

@@ -17,7 +17,7 @@ import re
import subprocess import subprocess
import sys import sys
__version__ = 0.11 __version__ = 0.12
XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config')) XDG_CONFIG_HOME = os.getenv('XDG_CONFIG_HOME', os.path.expanduser('~/.config'))
@@ -30,7 +30,15 @@ def check_output(command_list, stderr=None):
""" """
result = subprocess.check_output(command_list, stderr=stderr) result = subprocess.check_output(command_list, stderr=stderr)
if not isinstance(result, str): if not isinstance(result, str):
result = result.decode('utf-8') _result = []
for t in result.split(b'\n'):
if not t:
continue
try:
_result.append(t.decode('utf-8'))
except UnicodeDecodeError:
_result.append(t.decode('iso-8859-1'))
result = '\n'.join(_result) + '\n'
return result return result

71
test_adbfs.py Normal file
View File

@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
import os
import six
import unittest
try:
from unittest import mock
except ImportError:
import mock
FILE = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'adbfs')
try:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
spec = spec_from_loader("adbfs", SourceFileLoader("adbfs", FILE))
adbfs = module_from_spec(spec)
spec.loader.exec_module(adbfs)
except ImportError:
# py27
import imp
adbfs = imp.load_source('adbfs', FILE)
LISTING = '''\
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/Grüß Gott
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/\x80
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/Γεια σας
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/Здравствуйте
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/שָׁלוֹם
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/السَّلامُ عَلَيْكُمْ
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/გამარჯობა
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/こんにちは。
-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 /storage/emulated/0/안녕하십니까
''' # noqa
class TestCheckOutput(unittest.TestCase):
@mock.patch('subprocess.check_output')
def test_check_output(self, out):
"""
As for Python2 (and its last version: 2.7), subprocess.check_output
always return string like objects, contrary to bytes - no conversion
to string is needed.
Python3 treats string as unicode objects, but subprocess.check_output
returns bytes object, which is equvalend for py2 string… annoying.
"""
if six.PY3:
out.return_value = bytes(LISTING, 'utf-8')
else:
out.return_value = LISTING
result = adbfs.check_output(None)
self.assertEqual(result, LISTING)
@mock.patch('subprocess.check_output')
def test_check_output_py3_invalid_char(self, out):
"""
Special case for py3. We have bytes with some weird character - like
some system write something with codepage, instead of utf8.
"""
if six.PY2:
# doesn't affect Python 2
return
line = (b'-rw-rw---- 1 0 1015 0 01/01/2010 22:11:01 '
b'/storage/emulated/0/\xe2\n') # Latin 1 char â
out.return_value = bytes(line)
result = adbfs.check_output(None)
self.assertEqual(result, line.decode('iso-8859-1'))
if __name__ == "__main__":
unittest.main()