Cleanup code, use latin1 encoding for amiga file names.
This commit is contained in:
25
README.rst
25
README.rst
@@ -14,19 +14,32 @@ on my Amiga. Both reading from and writing into archive was implemented.
|
|||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
ULha requires `free lha <http://lha.sourceforge.jp>`_ implementation to work.
|
ULha requires free `lha`_ implementation to work. There is another lha
|
||||||
|
implementation under development - `lhasa`_, although it is currently limited
|
||||||
|
to list and extract only.
|
||||||
|
|
||||||
|
Limitations
|
||||||
|
-----------
|
||||||
|
|
||||||
|
For filenames which contain other characters outside of ASCII set, there is no
|
||||||
|
way to operate on them as `lha`_ simply ignore those files. Extracting full
|
||||||
|
archive will extract also those files, although names would be incorrectly
|
||||||
|
decoded, and hence, unusable on the AmigaOS. Looking forward for the `lhasa`_
|
||||||
|
to be completed, and then will switch to it.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* install `extfslib`_
|
* install `extfslib`_
|
||||||
* copy ``ulha`` to ``~/.local/share/mc/extfs.d/``
|
* copy ``ulha`` to ``~/.local/share/mc/extfs.d/``
|
||||||
* add or change entry for files handle in ``~/.config/mc/mc.ext``::
|
* add or change entry for files handle in ``~/.config/mc/mc.ext``:
|
||||||
|
|
||||||
# lha
|
.. code::ini
|
||||||
regex/\.[lL]([Hh][aA]|[Zz][hH])$
|
|
||||||
|
[lha]
|
||||||
|
Type=^LHa\ .*archive
|
||||||
Open=%cd %p/ulha://
|
Open=%cd %p/ulha://
|
||||||
View=%view{ascii} lha l %f
|
View=%view{ascii} /usr/libexec/mc/ext.d/archive.sh view lha
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
@@ -36,3 +49,5 @@ details.
|
|||||||
|
|
||||||
|
|
||||||
.. _extfslib: https://github.com/gryf/mc_extfslib
|
.. _extfslib: https://github.com/gryf/mc_extfslib
|
||||||
|
.. _lha: http://lha.sourceforge.jp
|
||||||
|
.. _lhasa: https://github.com/fragglet/lhasa
|
||||||
|
|||||||
101
ulha
101
ulha
@@ -2,19 +2,20 @@
|
|||||||
"""
|
"""
|
||||||
Lha Virtual filesystem executive for Midnight Commander.
|
Lha Virtual filesystem executive for Midnight Commander.
|
||||||
|
|
||||||
Tested against python 3.6, lha[1] 1.14 and mc 4.8.22
|
Tested against python 3.8, lha[1] 1.14 and mc 4.8.29
|
||||||
|
|
||||||
[1] http://lha.sourceforge.jp
|
[1] http://lha.sourceforge.jp
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
1.4 Cleanup code, use latin1
|
||||||
1.3 Switch to python3
|
1.3 Switch to python3
|
||||||
1.2 Moved item pattern to extfslib module
|
1.2 Moved item pattern to extfslib module
|
||||||
1.1 Moved common code into extfslib library
|
1.1 Moved common code into extfslib library
|
||||||
1.0 Initial release
|
1.0 Initial release
|
||||||
|
|
||||||
Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
|
Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
|
||||||
Date: 2019-06-30
|
Date: 2023-10-22
|
||||||
Version: 1.3
|
Version: 1.4
|
||||||
Licence: BSD
|
Licence: BSD
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
@@ -30,37 +31,39 @@ import extfslib
|
|||||||
class ULha(extfslib.Archive):
|
class ULha(extfslib.Archive):
|
||||||
"""Archive handle. Provides interface to MC's extfs subsystem"""
|
"""Archive handle. Provides interface to MC's extfs subsystem"""
|
||||||
|
|
||||||
LINE_PAT = re.compile(b"^((?P<perms>[d-][rswx-]{9})|(\[generic\])|"
|
LINE_PAT = re.compile(r"^((?P<perms>[d-][rswx-]{9})|(\[generic\])|"
|
||||||
b"(\[unknown\]))"
|
r"(\[unknown\]))"
|
||||||
b"((\s+\d+/\d+\s+)|(\s+))"
|
r"((\s+\d+/\d+\s+)|(\s+))"
|
||||||
b"(?P<uid>)(?P<gid>)" # just for the record
|
r"(?P<uid>)(?P<gid>)" # just for the record
|
||||||
b"(?P<size>\d+)"
|
r"(?P<size>\d+)"
|
||||||
b"\s+(\*{6}|\d+\.\d%)"
|
r"\s+(\*{6}|\d+\.\d%)"
|
||||||
b"\s(?P<month>[JFMASOND][a-z]{2})\s+" # month
|
r"\s(?P<month>[JFMASOND][a-z]{2})\s+" # month
|
||||||
b"(?P<day>\d+)\s+" # day
|
r"(?P<day>\d+)\s+" # day
|
||||||
b"(?P<yh>\d{4}|(\d{2}:\d{2}))" # year/hour
|
r"(?P<yh>\d{4}|(\d{2}:\d{2}))" # year/hour
|
||||||
b"\s(?P<fpath>.*)")
|
r"\s(?P<fpath>.*)")
|
||||||
ARCHIVER = b"lha"
|
ARCHIVER = "lha"
|
||||||
CMDS = {"list": b"lq",
|
CMDS = {"list": "lq",
|
||||||
"read": b"pq",
|
"read": "pq",
|
||||||
"write": b"aq",
|
"write": "aq",
|
||||||
"delete": b"dq"}
|
"delete": "dq"}
|
||||||
DATETIME = b"%(month)s %(day)s %(yh)s"
|
DATETIME = "%(month)s %(day)s %(yh)s"
|
||||||
|
|
||||||
def _get_dir(self):
|
def _get_dir(self):
|
||||||
"""Prepare archive file listing"""
|
"""Prepare archive file listing"""
|
||||||
contents = []
|
contents = []
|
||||||
|
|
||||||
out = self._call_command("list")
|
out = subprocess.run([self.ARCHIVER, self.CMDS['list'], self._arch],
|
||||||
if not out:
|
capture_output=True, encoding="Latin1")
|
||||||
|
if out.returncode != 0:
|
||||||
|
sys.stderr.write(out.stderr)
|
||||||
return
|
return
|
||||||
|
|
||||||
for line in out.split(b"\n"):
|
for line in out.stdout.split("\n"):
|
||||||
# -lhd- can store empty directories
|
# -lhd- can store empty directories
|
||||||
perms = b"-rw-r--r--"
|
perms = "-rw-r--r--"
|
||||||
if line.endswith(bytes(os.path.sep, 'utf-8')):
|
if line.endswith(os.path.sep):
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
perms = b"drw-r--r--"
|
perms = "drw-r--r--"
|
||||||
|
|
||||||
match = self.LINE_PAT.match(line)
|
match = self.LINE_PAT.match(line)
|
||||||
if not match:
|
if not match:
|
||||||
@@ -69,21 +72,21 @@ class ULha(extfslib.Archive):
|
|||||||
match_entry = match.groupdict()
|
match_entry = match.groupdict()
|
||||||
entry = {}
|
entry = {}
|
||||||
for key in match_entry:
|
for key in match_entry:
|
||||||
entry[bytes(key, 'utf-8')] = match_entry[key]
|
entry[key] = match_entry[key]
|
||||||
del match_entry
|
del match_entry
|
||||||
# UID and GID sometimes can have strange values depending on
|
# UID and GID sometimes can have strange values depending on
|
||||||
# the information that was written into archive. Most of the
|
# the information that was written into archive. Most of the
|
||||||
# times I was dealing with Amiga lha archives, so that i don't
|
# times I was dealing with Amiga lha archives, so that i don't
|
||||||
# really care about real user/group
|
# really care about real user/group
|
||||||
|
|
||||||
entry[b'uid'] = bytes(str(self._uid), 'utf-8')
|
entry['uid'] = str(self._uid)
|
||||||
entry[b'gid'] = bytes(str(self._gid), 'utf-8')
|
entry['gid'] = str(self._gid)
|
||||||
entry[b'datetime'] = self.DATETIME % entry
|
entry['datetime'] = self.DATETIME % entry
|
||||||
|
|
||||||
if not entry[b'perms']:
|
if not entry['perms']:
|
||||||
entry[b'perms'] = perms
|
entry['perms'] = perms
|
||||||
|
|
||||||
entry[b'display_name'] = self._map_name(entry[b'fpath'])
|
entry['display_name'] = self._map_name(entry['fpath'])
|
||||||
contents.append(entry)
|
contents.append(entry)
|
||||||
|
|
||||||
return contents
|
return contents
|
||||||
@@ -91,7 +94,7 @@ class ULha(extfslib.Archive):
|
|||||||
def list(self):
|
def list(self):
|
||||||
"""Output contents of the archive to stdout"""
|
"""Output contents of the archive to stdout"""
|
||||||
for entry in self._contents:
|
for entry in self._contents:
|
||||||
sys.stdout.buffer.write(self.ITEM % entry)
|
sys.stdout.write(self.ITEM.decode('utf-8') % entry)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def rm(self, dst):
|
def rm(self, dst):
|
||||||
@@ -107,12 +110,12 @@ class ULha(extfslib.Archive):
|
|||||||
"""Remove empty directory"""
|
"""Remove empty directory"""
|
||||||
dst = self._get_real_name(dst)
|
dst = self._get_real_name(dst)
|
||||||
|
|
||||||
if not dst.endswith(bytes(os.path.sep, 'utf-8')):
|
if not dst.endswith(os.path.sep):
|
||||||
dst += bytes(os.path.sep, 'utf-8')
|
dst += os.path.sep
|
||||||
|
|
||||||
if self._call_command('delete', dst=dst) is None:
|
res = subprocess.run([self.ARCHIVER, self.CMDS['delete'], dst],
|
||||||
return 1
|
capture_output=True)
|
||||||
return 0
|
return res.returncode
|
||||||
|
|
||||||
def run(self, dst):
|
def run(self, dst):
|
||||||
"""Execute file out of archive"""
|
"""Execute file out of archive"""
|
||||||
@@ -153,29 +156,19 @@ class ULha(extfslib.Archive):
|
|||||||
else:
|
else:
|
||||||
os.makedirs(dst)
|
os.makedirs(dst)
|
||||||
|
|
||||||
try:
|
res = subprocess.run([self.ARCHIVER, self.CMDS["write"], arch_abspath,
|
||||||
result = subprocess.check_call([self.ARCHIVER.decode('utf-8'),
|
dst], capture_output=True, encoding='utf-8')
|
||||||
self.CMDS["write"].decode('utf-8'),
|
|
||||||
arch_abspath, dst])
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
return 1
|
|
||||||
finally:
|
|
||||||
os.chdir(current_dir)
|
os.chdir(current_dir)
|
||||||
shutil.rmtree(tmpdir)
|
shutil.rmtree(tmpdir)
|
||||||
return result
|
return res.returncode
|
||||||
|
|
||||||
def copyout(self, src, dst):
|
def copyout(self, src, dst):
|
||||||
"""Copy file out form archive."""
|
"""Copy file out form archive."""
|
||||||
src = self._get_real_name(src)
|
src = self._get_real_name(src)
|
||||||
fobj = open(dst, "wb")
|
with open(dst, "wb") as fobj:
|
||||||
try:
|
res = subprocess.run([self.ARCHIVER, self.CMDS['read'], self._arch,
|
||||||
result = subprocess.check_call([self.ARCHIVER, self.CMDS['read'], self._arch,
|
|
||||||
src], stdout=fobj)
|
src], stdout=fobj)
|
||||||
except subprocess.CalledProcessError:
|
return res.returncode
|
||||||
return 1
|
|
||||||
finally:
|
|
||||||
fobj.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in New Issue
Block a user