[util] Move compatibility functions out of util
[youtube-dl] / youtube_dl / postprocessor / xattrpp.py
index 440df93ecc1503668f460284b8a325c8f61ee80f..b5cae41c8cd061a494a722c1db4261e3eca597b8 100644 (file)
@@ -3,7 +3,11 @@ import subprocess
 import sys
 
 from .common import PostProcessor
+from ..compat import (
+    subprocess_check_output
+)
 from ..utils import (
+    check_executable,
     hyphenate_date,
 )
 
@@ -29,68 +33,51 @@ class XAttrMetadataPP(PostProcessor):
         try:
             # try the pyxattr module...
             import xattr
+
             def write_xattr(path, key, value):
                 return xattr.setxattr(path, key, value)
 
         except ImportError:
+            if os.name == 'nt':
+                # Write xattrs to NTFS Alternate Data Streams:
+                # http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29
+                def write_xattr(path, key, value):
+                    assert ':' not in key
+                    assert os.path.exists(path)
 
-            if os.name == 'posix':
-                def which(bin):
-                    for dir in os.environ["PATH"].split(":"):
-                        path = os.path.join(dir, bin)
-                        if os.path.exists(path):
-                            return path
-
-                user_has_setfattr = which("setfattr")
-                user_has_xattr    = which("xattr")
+                    ads_fn = path + ":" + key
+                    with open(ads_fn, "wb") as f:
+                        f.write(value)
+            else:
+                user_has_setfattr = check_executable("setfattr", ['--version'])
+                user_has_xattr = check_executable("xattr", ['-h'])
 
                 if user_has_setfattr or user_has_xattr:
 
                     def write_xattr(path, key, value):
-                        import errno
-                        potential_errors = {
-                            # setfattr: /tmp/blah: Operation not supported
-                            "Operation not supported": errno.EOPNOTSUPP,
-                            # setfattr: ~/blah: No such file or directory
-                            # xattr: No such file: ~/blah
-                            "No such file": errno.ENOENT,
-                        }
-
                         if user_has_setfattr:
                             cmd = ['setfattr', '-n', key, '-v', value, path]
                         elif user_has_xattr:
                             cmd = ['xattr', '-w', key, value, path]
 
-                        try:
-                            subprocess.check_output(cmd, stderr=subprocess.STDOUT)
-                        except subprocess.CalledProcessError as e:
-                            errorstr = e.output.strip().decode()
-                            for potential_errorstr, potential_errno in potential_errors.items():
-                                if errorstr.find(potential_errorstr) > -1:
-                                    e = OSError(potential_errno, potential_errorstr)
-                                    e.__cause__ = None
-                                    raise e
-                            raise # Reraise unhandled error
+                        subprocess_check_output(cmd)
 
                 else:
                     # On Unix, and can't find pyxattr, setfattr, or xattr.
                     if sys.platform.startswith('linux'):
-                        self._downloader.report_error("Couldn't find a tool to set the xattrs. Install either the python 'pyxattr' or 'xattr' modules, or the GNU 'attr' package (which contains the 'setfattr' tool).")
-                    elif sys.platform == 'darwin':
-                        self._downloader.report_error("Couldn't find a tool to set the xattrs. Install either the python 'xattr' module, or the 'xattr' binary.")
-            else:
-                # Write xattrs to NTFS Alternate Data Streams: http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29
-                def write_xattr(path, key, value):
-                    assert(key.find(":") < 0)
-                    assert(path.find(":") < 0)
-                    assert(os.path.exists(path))
-
-                    ads_fn = path + ":" + key
-                    with open(ads_fn, "w") as f:
-                        f.write(value)
+                        self._downloader.report_error(
+                            "Couldn't find a tool to set the xattrs. "
+                            "Install either the python 'pyxattr' or 'xattr' "
+                            "modules, or the GNU 'attr' package "
+                            "(which contains the 'setfattr' tool).")
+                    else:
+                        self._downloader.report_error(
+                            "Couldn't find a tool to set the xattrs. "
+                            "Install either the python 'xattr' module, "
+                            "or the 'xattr' binary.")
 
         # Write the metadata to the file's xattrs
-        self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs...')
+        self._downloader.to_screen('[metadata] Writing metadata to file\'s xattrs')
 
         filename = info['filepath']
 
@@ -113,11 +100,12 @@ class XAttrMetadataPP(PostProcessor):
                     if infoname == "upload_date":
                         value = hyphenate_date(value)
 
-                    write_xattr(filename, xattrname, value)
+                    byte_value = value.encode('utf-8')
+                    write_xattr(filename, xattrname, byte_value)
 
             return True, info
 
-        except OSError:
+        except (subprocess.CalledProcessError, OSError):
             self._downloader.report_error("This filesystem doesn't support extended attributes. (You may have to enable them in your /etc/fstab)")
             return False, info