# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # rapid-photo-downloader # rapid-photo-downloader/Makefile # rapid-photo-downloader/distinfo # rapid-photo-downloader/pkg-descr # rapid-photo-downloader/files # rapid-photo-downloader/files/patch-raphodo_rapid.py # rapid-photo-downloader/files/patch-raphodo_cache.py # rapid-photo-downloader/files/patch-raphodo_storage.py # rapid-photo-downloader/files/patch-raphodo_utilities.py # echo c - rapid-photo-downloader mkdir -p rapid-photo-downloader > /dev/null 2>&1 echo x - rapid-photo-downloader/Makefile sed 's/^X//' >rapid-photo-downloader/Makefile << '538ae8e6a8d84e84bc9cf417e3f5503f' X# $FreeBSD$ X XPORTNAME= rapid-photo-downloader XDISTVERSION= 0.9.17 XCATEGORIES= graphics XMASTER_SITES= https://launchpad.net/rapid/pyqt/${PORTVERSION}/+download/ X XMAINTAINER= m.ne@gmx.net XCOMMENT= Import photos and videos efficiently and reliably X XLICENSE= GPLv3 X XBUILD_DEPENDS= intltool-update:textproc/intltool XLIB_DEPENDS= libgexiv2.so:graphics/gexiv2 \ X libgudev-1.0.so:devel/libgudev XRUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}arrow>0:devel/py-arrow@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}colour>0:graphics/py-colour@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}dateutil>2.2:devel/py-dateutil@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}easygui>=0:x11-toolkits/py-easygui@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}gobject3>0:devel/py-gobject3@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}gphoto2>=1.4.0:graphics/py-gphoto2@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}gstreamer1>=1.0:multimedia/py-gstreamer1@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}notify2>0:devel/py-notify2@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}psutil>=3.4.2:sysutils/py-psutil@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}pymediainfo>=1.0:multimedia/py-pymediainfo@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}pyzmq>0:net/py-pyzmq@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}rawkit>0:graphics/py-rawkit@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}requests>=0:www/py-requests@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}sortedcontainers>0:devel/py-sortedcontainers@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}tenacity>0:devel/py-tenacity@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}tornado>=4.1:www/py-tornado@${PY_FLAVOR} \ X ${PYTHON_PKGNAMEPREFIX}xdg>0:devel/py-xdg@${PY_FLAVOR} \ X exiftool:graphics/p5-Image-ExifTool X XUSES= desktop-file-utils gettext pyqt:5 python:3.4+ qt:5 XUSE_PYTHON= autoplist distutils XUSE_QT= imageformats_run XUSE_PYQT= core XBINARY_ALIAS= python3=${PYTHON_VERSION} X XNO_ARCH= yes X XOPTIONS_DEFINE= COLOUR PROGRESS XOPTIONS_DEFAULT= COLOUR PROGRESS X XCOLOUR_DESC= generates coloured program output XPROGRESS_DESC= shows a progress bar on the command line X XCOLOUR_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}colorlog>0:devel/py-colorlog@${PY_FLAVOR} XPROGRESS_RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}pyprind>=1.4.0:misc/py-pyprind@${PY_FLAVOR} X X.include 538ae8e6a8d84e84bc9cf417e3f5503f echo x - rapid-photo-downloader/distinfo sed 's/^X//' >rapid-photo-downloader/distinfo << 'a1cadbd8dfcb75c43b7156f95a156e7a' XTIMESTAMP = 1568565754 XSHA256 (rapid-photo-downloader-0.9.17.tar.gz) = 26dbce5d2e775af39ce8f17224a862ed71a86a47768a7ebb04193d96535c7883 XSIZE (rapid-photo-downloader-0.9.17.tar.gz) = 6877573 a1cadbd8dfcb75c43b7156f95a156e7a echo x - rapid-photo-downloader/pkg-descr sed 's/^X//' >rapid-photo-downloader/pkg-descr << '718606f121792ac7694cb2e8bff1dc67' XRapid Photo Downloader imports photos and videos from cameras, phones, Xmemory cards and other devices at high speed. It can be configured to Xrename photos and videos with meaningful filenames you specify. It can Xalso back up photos and videos as they are downloaded. It downloads Xfrom and backs up to multiple devices simultaneously. X XWWW: http://www.damonlynch.net/rapid/ 718606f121792ac7694cb2e8bff1dc67 echo c - rapid-photo-downloader/files mkdir -p rapid-photo-downloader/files > /dev/null 2>&1 echo x - rapid-photo-downloader/files/patch-raphodo_rapid.py sed 's/^X//' >rapid-photo-downloader/files/patch-raphodo_rapid.py << '75687e41dd787b91d57f594639ef0dde' X--- raphodo/rapid.py.orig 2019-08-18 03:58:11 UTC X+++ raphodo/rapid.py X@@ -98,7 +98,7 @@ from PyQt5.QtNetwork import QLocalSocket, QLocalServer X import sip X X from raphodo.storage import ( X- ValidMounts, CameraHotplug, UDisks2Monitor, GVolumeMonitor, have_gio, X+ ValidMounts, CameraHotplug, GVolumeMonitor, have_gio, X has_one_or_more_folders, mountPaths, get_desktop_environment, get_desktop, X gvfs_controls_mounts, get_default_file_manager, validate_download_folder, X validate_source_folder, get_fdo_cache_thumb_base_directory, WatchDownloadDirs, get_media_dir, X@@ -584,12 +584,12 @@ class RapidWindow(QMainWindow): X self.prefs.backup_files = backup X else: X logging.info("Backing up files: %s", self.prefs.backup_files) X- X+ X if backup_auto_detect is not None: X self.prefs.backup_device_autodetection = backup_auto_detect X elif self.prefs.backup_files: X logging.info("Backup device auto detection: %s", self.prefs.backup_device_autodetection) X- X+ X if photo_backup_identifier is not None: X self.prefs.photo_backup_identifier = photo_backup_identifier X elif self.prefs.backup_files and self.prefs.backup_device_autodetection: X@@ -599,7 +599,7 @@ class RapidWindow(QMainWindow): X self.prefs.video_backup_identifier = video_backup_identifier X elif self.prefs.backup_files and self.prefs.backup_device_autodetection: X logging.info("video backup identifier: %s", self.prefs.video_backup_identifier) X- X+ X if photo_backup_location is not None: X self.prefs.backup_photo_location = photo_backup_location X elif self.prefs.backup_files and not self.prefs.backup_device_autodetection: X@@ -934,18 +934,6 @@ class RapidWindow(QMainWindow): X logging.debug("Starting camera hotplug monitor...") X QTimer.singleShot(0, self.cameraHotplugThread.start) X X- # Monitor when the user adds or removes a partition X- self.udisks2Monitor = UDisks2Monitor(self.validMounts) X- self.udisks2MonitorThread = QThread() X- self.udisks2MonitorThread.started.connect(self.udisks2Monitor.startMonitor) X- self.udisks2Unmount.connect(self.udisks2Monitor.unmount_volume) X- self.udisks2Monitor.moveToThread(self.udisks2MonitorThread) X- self.udisks2Monitor.partitionMounted.connect(self.partitionMounted) X- self.udisks2Monitor.partitionUnmounted.connect(self.partitionUmounted) X- # Start the monitor only on the thread it will be running on X- logging.debug("Starting UDisks2 monitor...") X- QTimer.singleShot(0, self.udisks2MonitorThread.start) X- X if self.gvfsControlsMounts: X # Gio.VolumeMonitor must be in the main thread, according to X # Gnome documentation X@@ -2119,7 +2107,7 @@ class RapidWindow(QMainWindow): X select_text=_('Select a destination folder') X ) X self.photoDestination.addWidget(self.photoDestinationWidget) X- X+ X self.videoDestinationDisplay = DestinationDisplay( X menu=True, file_type=FileType.video, parent=self X ) X@@ -2582,11 +2570,11 @@ class RapidWindow(QMainWindow): X X body = _( X r"""Please report the problem at {website}.

X- Include in your bug report the program's log files. The bug report must include X- {log_file}, but attaching the other log files is often helpful.

X+ Include in your bug report the program's log files. The bug report must include X+ {log_file}, but attaching the other log files is often helpful.

X If possible, please also include the program's configuration file X- {config_file}.

X- Click here to open the log directory, and X+ {config_file}.

X+ Click here to open the log directory, and X here to open the configuration directory. X """ X ).format( X@@ -2622,7 +2610,7 @@ class RapidWindow(QMainWindow): X X :param message: the text to display X :param rich_text: whether it text to display is in HTML format X- :param title: optional title for message box, else defaults to X+ :param title: optional title for message box, else defaults to X localized 'Rapid Photo Downloader' X :return: the message box X """ X@@ -4652,8 +4640,6 @@ Do you want to proceed with the download? X self.sendTerminateToThread(self.backup_controller) X X if not self.gvfsControlsMounts: X- self.udisks2MonitorThread.quit() X- self.udisks2MonitorThread.wait() X self.cameraHotplugThread.quit() X self.cameraHotplugThread.wait() X else: X@@ -5254,7 +5240,7 @@ Do you want to proceed with the download? X After a preference change, rescan already scanned devices X :param ignore_cameras: if True, don't rescan cameras X :param rescan_path: if True, include manually specified paths X- (i.e. This Computer) X+ (i.e. This Computer) X """ X X if rescan_path: X@@ -6243,7 +6229,7 @@ def main(): X logger = iplogging.setup_main_process_logging(logging_level=logging_level) X X logging.info("Rapid Photo Downloader is starting") X- X+ X if args.photo_renaming: X photo_rename = args.photo_renaming == 'on' X if photo_rename: X@@ -6252,7 +6238,7 @@ def main(): X logging.info("Photo renaming turned off from command line") X else: X photo_rename = None X- X+ X if args.video_renaming: X video_rename = args.video_renaming == 'on' X if video_rename: X@@ -6313,13 +6299,13 @@ def main(): X logging.info("This Computer path set from command line: %s", this_computer_location) X else: X this_computer_location=None X- X+ X if args.photo_location: X photo_location = os.path.abspath(args.photo_location) X logging.info("Photo location set from command line: %s", photo_location) X else: X photo_location=None X- X+ X if args.video_location: X video_location = os.path.abspath(args.video_location) X logging.info("video location set from command line: %s", video_location) 75687e41dd787b91d57f594639ef0dde echo x - rapid-photo-downloader/files/patch-raphodo_cache.py sed 's/^X//' >rapid-photo-downloader/files/patch-raphodo_cache.py << '628d5ada4c3ed48f3fbf2d704be8946f' X--- raphodo/cache.py.orig 2019-07-31 17:16:30 UTC X+++ raphodo/cache.py X@@ -131,7 +131,7 @@ class Cache: X not be generated) X """ X X- assert sys.platform.startswith('linux') X+ assert sys.platform.startswith('linux') or sys.platform.startswith('freebsd') X self.cache_dir = cache_dir X self.failure_dir = failure_dir X assert self.cache_dir 628d5ada4c3ed48f3fbf2d704be8946f echo x - rapid-photo-downloader/files/patch-raphodo_storage.py sed 's/^X//' >rapid-photo-downloader/files/patch-raphodo_storage.py << '72d58b37c82d6a71eeca44efd2cab851' X--- raphodo/storage.py.orig 2019-07-09 21:12:19 UTC X+++ raphodo/storage.py X@@ -68,10 +68,9 @@ import xdg X import gi X X gi.require_version('GUdev', '1.0') X-gi.require_version('UDisks', '2.0') X gi.require_version('GExiv2', '0.10') X gi.require_version('GLib', '2.0') X-from gi.repository import GUdev, UDisks, GLib X+from gi.repository import GUdev, GLib X X from gettext import gettext as _ X X@@ -170,7 +169,7 @@ def get_media_dir() -> str: X X """ X X- if sys.platform.startswith('linux'): X+ if sys.platform.startswith('linux') or sys.platform.startswith('freebsd'): X media_dir = '/media/{}'.format(get_user_name()) X run_media_dir = '/run{}'.format(media_dir) X distro = get_distro() X@@ -278,7 +277,7 @@ class ValidMounts(): X self.validMountFolders, e.g. /media/, etc. X """ X X- if not sys.platform.startswith('linux'): X+ if not sys.platform.startswith('linux') and not sys.platform.startswith('freebsd'): X raise ("Mounts.setValidMountPoints() not implemented on %s", sys.platform()) X else: X try: X@@ -646,7 +645,7 @@ def get_default_file_manager() -> Tuple[Optional[str], X X _default_file_manager_probed = True X X- assert sys.platform.startswith('linux') X+ assert sys.platform.startswith('linux') or sys.platform.startswith('freebsd') X cmd = shlex.split('xdg-mime query default inode/directory') X try: X desktop_file = subprocess.check_output(cmd, universal_newlines=True) # type: str X@@ -791,7 +790,7 @@ def validate_download_folder(path: Optional[str], X X :param path: path to analyze X :param write_on_waccesss_failure: if os.access reports path is not writable, test X- nonetheless to see if it's writable by writing and deleting a test file X+ nonetheless to see if it's writable by writing and deleting a test file X :return: Tuple indicating validity and path made absolute X X >>> validate_download_folder('/some/bogus/and/ridiculous/path') X@@ -1008,259 +1007,6 @@ class CameraHotplug(QObject): X self.cameraRemoved.emit() X X X-class UDisks2Monitor(QObject): X- # Most of this class is Copyright 2008-2015 Canonical X- X- partitionMounted = pyqtSignal(str, list, bool) X- partitionUnmounted = pyqtSignal(str) X- X- loop_prefix = '/org/freedesktop/UDisks2/block_devices/loop' X- not_interesting = ( X- '/org/freedesktop/UDisks2/block_devices/dm_', X- '/org/freedesktop/UDisks2/block_devices/ram', X- '/org/freedesktop/UDisks2/block_devices/zram', X- ) X- X- def __init__(self, validMounts: ValidMounts) -> None: X- super().__init__() X- self.validMounts = validMounts X- X- @pyqtSlot() X- def startMonitor(self) -> None: X- self.udisks = UDisks.Client.new_sync(None) X- self.manager = self.udisks.get_object_manager() X- self.manager.connect('object-added', X- lambda man, obj: self._udisks_obj_added(obj)) X- self.manager.connect('object-removed', X- lambda man, obj: self._device_removed(obj)) X- X- # Track the paths of the mount points, which is useful when unmounting X- # objects. X- self.known_mounts = {} # type: Dict[str, str] X- for obj in self.manager.get_objects(): X- path = obj.get_object_path() X- fs = obj.get_filesystem() X- if fs: X- mount_points = fs.get_cached_property('MountPoints').get_bytestring_array() X- if mount_points: X- self.known_mounts[path] = mount_points[0] X- logging.debug("... UDisks2 monitor started") X- X- def _udisks_obj_added(self, obj) -> None: X- path = obj.get_object_path() X- for boring in self.not_interesting: X- if path.startswith(boring): X- return X- block = obj.get_block() X- if not block: X- return X- X- drive = self._get_drive(block) X- X- part = obj.get_partition() X- is_system = block.get_cached_property('HintSystem').get_boolean() X- is_loop = path.startswith(self.loop_prefix) and not \ X- block.get_cached_property('ReadOnly').get_boolean() X- if not is_system or is_loop: X- if part: X- self._udisks_partition_added(obj, block, drive, path) X- X- def _get_drive(self, block) -> Optional[UDisks.Drive]: X- drive_name = block.get_cached_property('Drive').get_string() X- if drive_name != '/': X- return self.udisks.get_object(drive_name).get_drive() X- else: X- return None X- X- def _udisks_partition_added(self, obj, block, drive, path) -> None: X- logging.debug('UDisks: partition added: %s' % path) X- fstype = block.get_cached_property('IdType').get_string() X- logging.debug('Udisks: id-type: %s' % fstype) X- X- fs = obj.get_filesystem() X- X- if fs: X- icon_names = self.get_icon_names(obj) X- X- if drive is not None: X- ejectable = drive.get_property('ejectable') X- else: X- ejectable = False X- mount_point = '' X- mount_points = fs.get_cached_property('MountPoints').get_bytestring_array() X- if len(mount_points) == 0: X- try: X- logging.debug("UDisks: attempting to mount %s", path) X- mount_point = self.retry_mount(fs, fstype) X- if not mount_point: X- raise Exception X- else: X- logging.debug("UDisks: successfully mounted at %s", mount_point) X- except Exception: X- logging.error('UDisks: could not mount the device: %s', path) X- return X- else: X- mount_point = mount_points[0] X- logging.debug("UDisks: already mounted at %s", mount_point) X- X- self.known_mounts[path] = mount_point X- if self.validMounts.pathIsValidMountPoint(mount_point): X- self.partitionMounted.emit(mount_point, icon_names, ejectable) X- X- else: X- logging.debug("Udisks: partition has no file system %s", path) X- X- def retry_mount(self, fs, fstype) -> str: X- # Variant parameter construction Copyright Bernard Baeyens, and is X- # licensed under GNU General Public License Version 2 or higher. X- # https://github.com/berbae/udisksvm X- list_options = '' X- if fstype == 'vfat': X- list_options = 'flush' X- elif fstype == 'ext2': X- list_options = 'sync' X- G_VARIANT_TYPE_VARDICT = GLib.VariantType.new('a{sv}') X- param_builder = GLib.VariantBuilder.new(G_VARIANT_TYPE_VARDICT) X- optname = GLib.Variant.new_string('fstype') # s X- value = GLib.Variant.new_string(fstype) X- vvalue = GLib.Variant.new_variant(value) # v X- newsv = GLib.Variant.new_dict_entry(optname, vvalue) # {sv} X- param_builder.add_value(newsv) X- optname = GLib.Variant.new_string('options') X- value = GLib.Variant.new_string(list_options) X- vvalue = GLib.Variant.new_variant(value) X- newsv = GLib.Variant.new_dict_entry(optname, vvalue) X- param_builder.add_value(newsv) X- vparam = param_builder.end() # a{sv} X- X- # Try to mount until it does not fail with "Busy" X- timeout = 10 X- while timeout >= 0: X- try: X- return fs.call_mount_sync(vparam, None) X- except GLib.GError as e: X- if not 'UDisks2.Error.DeviceBusy' in e.message: X- raise X- logging.debug('Udisks: Device busy.') X- time.sleep(0.3) X- timeout -= 1 X- return '' X- X- def get_icon_names(self, obj: UDisks.Object) -> List[str]: X- # Get icon information, if possible X- icon_names = [] X- if have_gio: X- info = self.udisks.get_object_info(obj) X- icon = info.get_icon() X- if isinstance(icon, Gio.ThemedIcon): X- icon_names = icon.get_names() X- return icon_names X- X- # Next four class member functions from Damon Lynch, not Canonical X- def _device_removed(self, obj: UDisks.Object) -> None: X- # path here refers to the udev / udisks path, not the mount point X- path = obj.get_object_path() X- if path in self.known_mounts: X- mount_point = self.known_mounts[path] X- del self.known_mounts[path] X- self.partitionUnmounted.emit(mount_point) X- X- def get_can_eject(self, obj: UDisks.Object) -> bool: X- block = obj.get_block() X- drive = self._get_drive(block) X- if drive is not None: X- return drive.get_property('ejectable') X- return False X- X- def get_device_props(self, device_path: str) -> Tuple[List[str], bool]: X- """ X- Given a device, get the icon names suggested by udev, and X- determine whether the mount is ejectable or not. X- :param device_path: system path of the device to check, X- e.g. /dev/sdc1 X- :return: icon names and eject boolean X- """ X- X- object_path = '/org/freedesktop/UDisks2/block_devices/{}'.format( X- os.path.split(device_path)[1]) X- obj = self.udisks.get_object(object_path) X- icon_names = self.get_icon_names(obj) X- can_eject = self.get_can_eject(obj) X- return (icon_names, can_eject) X- X- @pyqtSlot(str) X- def unmount_volume(self, mount_point: str) -> None: X- X- G_VARIANT_TYPE_VARDICT = GLib.VariantType.new('a{sv}') X- param_builder = GLib.VariantBuilder.new(G_VARIANT_TYPE_VARDICT) X- X- # Variant parameter construction Copyright Bernard Baeyens, and is X- # licensed under GNU General Public License Version 2 or higher. X- # https://github.com/berbae/udisksvm X- X- optname = GLib.Variant.new_string('force') X- value = GLib.Variant.new_boolean(False) X- vvalue = GLib.Variant.new_variant(value) X- newsv = GLib.Variant.new_dict_entry(optname, vvalue) X- param_builder.add_value(newsv) X- X- vparam = param_builder.end() # a{sv} X- X- path = None X- # Get the path from the dict we keep of known mounts X- for key, value in self.known_mounts.items(): X- if value == mount_point: X- path = key X- break X- if path is None: X- logging.error("Could not find UDisks2 path used to be able to unmount %s", mount_point) X- X- fs = None X- for obj in self.manager.get_objects(): X- opath = obj.get_object_path() X- if path == opath: X- fs = obj.get_filesystem() X- if fs is None: X- logging.error("Could not find UDisks2 filesystem used to be able to unmount %s", X- mount_point) X- X- logging.debug("Unmounting %s...", mount_point) X- try: X- fs.call_unmount(vparam, None, self.umount_volume_callback, (mount_point, fs)) X- except GLib.GError: X- value = sys.exc_info()[1] X- logging.error('Unmounting failed with error:') X- logging.error("%s", value) X- X- def umount_volume_callback(self, source_object: UDisks.FilesystemProxy, X- result: Gio.AsyncResult, X- user_data: Tuple[str, UDisks.Filesystem]) -> None: X- """ X- Callback for asynchronous unmount operation. X- X- :param source_object: the FilesystemProxy object X- :param result: result of the unmount X- :param user_data: mount_point and the file system X- """ X- X- mount_point, fs = user_data X- X- try: X- if fs.call_unmount_finish(result): X- logging.debug("...successfully unmounted %s", mount_point) X- else: X- # this is the result even when the unmount was unsuccessful X- logging.debug("...possibly failed to unmount %s", mount_point) X- except GLib.GError as e: X- logging.error('Exception occurred unmounting %s', mount_point) X- logging.exception('Traceback:') X- except: X- logging.error('Exception occurred unmounting %s', mount_point) X- logging.exception('Traceback:') X- X- self.partitionUnmounted.emit(mount_point) X- X- X if have_gio: X class GVolumeMonitor(QObject): X r""" X@@ -1577,7 +1323,7 @@ def get_mount_size(mount: QStorageInfo) -> Tuple[int, X """ X Uses GIO to get bytes total and bytes free (available) for the mount that a X path is in. X- X+ X :param path: path located anywhere in the mount X :return: bytes_total, bytes_free X """ 72d58b37c82d6a71eeca44efd2cab851 echo x - rapid-photo-downloader/files/patch-raphodo_utilities.py sed 's/^X//' >rapid-photo-downloader/files/patch-raphodo_utilities.py << '70d95c243b9526dde209b940aff4dbe9' X--- raphodo/utilities.py.orig 2019-08-18 03:58:11 UTC X+++ raphodo/utilities.py X@@ -76,10 +76,11 @@ if arrow_version >= parse_version('0.14.3') and arrow_ X # Linux specific code to ensure child processes exit when parent dies X # See http://stackoverflow.com/questions/19447603/ X # how-to-kill-a-python-child-process-created-with-subprocess-check-output-when-t/ X-libc = ctypes.CDLL("libc.so.6") X+libc = ctypes.CDLL("libc.so.7") X def set_pdeathsig(sig = signal.SIGTERM): X def callable(): X- return libc.prctl(1, sig) X+ return 0 X+ #return libc.procctl(0, 0, 11, sig) X return callable X X X@@ -195,8 +196,8 @@ def show_errors(): X # kilobytes, etc. X suffixes = [_('B'), _('KB'), _('MB'), _('GB'), _('TB'), _('PB'), _('EB'), _('ZB'), _('YB')] X X-def format_size_for_user(size_in_bytes: int, X- zero_string: str='', X+def format_size_for_user(size_in_bytes: int, X+ zero_string: str='', X no_decimals: int=2) -> str: X r""" X Humanize display of bytes. X@@ -382,12 +383,12 @@ def find_mount_point(path: str) -> str: X Find the mount point of a path X See: X http://stackoverflow.com/questions/4453602/how-to-find-the-mountpoint-a-file-resides-on X- X+ X >>> print(find_mount_point('/crazy/path')) X / X- X- :param path: X- :return: X+ X+ :param path: X+ :return: X """ X path = os.path.realpath(path) X while not os.path.ismount(path): X@@ -724,13 +725,13 @@ def _collect_duplicates(basenames, paths): X X def make_path_end_snippets_unique(*paths) -> List[str]: X r""" X- Make list of path ends unique given possible common path endings. X- X- A snippet starts from the end of the path, in extreme cases possibly up the path start. X+ Make list of path ends unique given possible common path endings. X X+ A snippet starts from the end of the path, in extreme cases possibly up the path start. X+ X :param paths: sequence of paths to generate unique end snippets for X :return: list of unique snippets X- X+ X >>> p0 = '/home/damon/photos' X >>> p1 = '/media/damon/backup1/photos' X >>> p2 = '/media/damon/backup2/photos' 70d95c243b9526dde209b940aff4dbe9 exit