diff options
-rw-r--r-- | .travis.yml | 8 | ||||
-rwxr-xr-x | .travis/install.sh | 10 | ||||
-rwxr-xr-x | .travis/run.sh | 3 | ||||
-rw-r--r-- | CHANGES.txt | 5 | ||||
-rw-r--r-- | README.rst (renamed from README.txt) | 6 | ||||
-rwxr-xr-x | scripts/artifacts.py | 31 | ||||
-rw-r--r-- | xattr/__init__.py | 5 | ||||
-rw-r--r-- | xattr/compat.py | 11 | ||||
-rw-r--r-- | xattr/pyxattr_compat.py | 7 | ||||
-rw-r--r-- | xattr/tests/test_xattr.py | 25 | ||||
-rwxr-xr-x | xattr/tool.py | 15 |
11 files changed, 97 insertions, 29 deletions
diff --git a/.travis.yml b/.travis.yml index 8683af6..72da8c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,16 +9,16 @@ matrix: language: objective-c - os: osx language: objective-c - env: PYENV_VERSION=pypy3-2.4.0 + env: PYENV_VERSION=pypy3.3-5.2-alpha1 - os: osx language: objective-c - env: PYENV_VERSION=pypy-4.0.1 + env: PYENV_VERSION=pypy-5.4.1 - os: osx language: objective-c - env: PYENV_VERSION=2.7.11 + env: PYENV_VERSION=2.7.12 - os: osx language: objective-c - env: PYENV_VERSION=3.5.1 + env: PYENV_VERSION=3.5.2 install: - "./.travis/install.sh" script: diff --git a/.travis/install.sh b/.travis/install.sh index 40e88df..a90c451 100755 --- a/.travis/install.sh +++ b/.travis/install.sh @@ -4,11 +4,15 @@ set -e set -x if [[ -n "$PYENV_VERSION" ]]; then - if [ ! -e "$HOME/.pyenv" ]; then - git clone https://github.com/yyuu/pyenv.git ~/.pyenv + if [ ! -e "$HOME/.pyenv-xattr/.git" ]; then + if [ -e "$HOME/.pyenv-xattr" ]; then + rm -rf ~/.pyenv-xattr + fi + git clone https://github.com/yyuu/pyenv.git ~/.pyenv-xattr fi - PYENV_ROOT="$HOME/.pyenv" + PYENV_ROOT="$HOME/.pyenv-xattr" PATH="$PYENV_ROOT/bin:$PATH" + hash -r eval "$(pyenv init -)" hash -r pyenv install --list diff --git a/.travis/run.sh b/.travis/run.sh index a18c09c..3c1a219 100755 --- a/.travis/run.sh +++ b/.travis/run.sh @@ -4,8 +4,9 @@ set -e set -x if [[ -n "$PYENV_VERSION" ]]; then - PYENV_ROOT="$HOME/.pyenv" + PYENV_ROOT="$HOME/.pyenv-xattr" PATH="$PYENV_ROOT/bin:$PATH" + hash -r eval "$(pyenv init -)" fi diff --git a/CHANGES.txt b/CHANGES.txt index 07ca7d0..1734b00 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,8 @@ +Version 0.9.0 released XXXX-XX-XX + +* Allow (Python 2) long for fd + https://github.com/xattr/xattr/pull/51 + Version 0.8.0 released 2016-02-28 * Use os.fsencode where available to better handle filesystem quirks related @@ -1,3 +1,9 @@ +xattr +----- + +.. image:: https://travis-ci.org/xattr/xattr.svg?branch=master + :target: https://travis-ci.org/xattr/xattr + xattr is a Python wrapper for extended filesystem attributes. Extended attributes extend the basic attributes of files and directories diff --git a/scripts/artifacts.py b/scripts/artifacts.py index 089bf9b..8be54b9 100755 --- a/scripts/artifacts.py +++ b/scripts/artifacts.py @@ -40,10 +40,39 @@ def download_github_artifacts(): for asset in release['assets']: download_file(asset['browser_download_url'], 'dist/{name}'.format(**asset)) +def get_version(): + return subprocess.check_output([sys.executable, 'setup.py', '--version']).strip() + +def artifact_matcher(version): + return re.compile('^simplejson-{}.*\\.(exe|whl)$'.format(re.escape(version))) + +def sign_artifacts(version): + artifacts = set(os.listdir('dist')) + pattern = artifact_matcher(version) + for fn in artifacts: + if pattern.search(fn) and '{}.asc'.format(fn) not in artifacts: + sign_artifact(os.path.join('dist', fn)) + +def sign_artifact(path): + print(' '.join(['gpg', '--detach-sign', '-a', path])) + subprocess.check_call(['gpg', '--detach-sign', '-a', path]) + +def upload_artifacts(version): + artifacts = set(os.listdir('dist')) + pattern = artifact_matcher(version) + args = ['twine', 'upload'] + for fn in artifacts: + if pattern.search(fn): + filename = os.path.join('dist', fn) + args.extend([filename, filename + '.asc']) + subprocess.check_call(args) def main(): - #download_appveyor_artifacts() + # download_appveyor_artifacts() download_github_artifacts() + version = get_version() + sign_artifacts(version) + upload_artifacts(version) if __name__ == '__main__': diff --git a/xattr/__init__.py b/xattr/__init__.py index dad8e5a..57a771e 100644 --- a/xattr/__init__.py +++ b/xattr/__init__.py @@ -9,6 +9,7 @@ that exposes these extended attributes. __version__ = '0.8.0' +from .compat import integer_types from .lib import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, XATTR_RESOURCEFORK_NAME, _getxattr, _fgetxattr, _setxattr, _fsetxattr, @@ -46,14 +47,14 @@ class xattr(object): self.value = obj def __repr__(self): - if isinstance(self.value, int): + if isinstance(self.value, integer_types): flavor = "fd" else: flavor = "file" return "<%s %s=%r>" % (type(self).__name__, flavor, self.value) def _call(self, name_func, fd_func, *args): - if isinstance(self.value, int): + if isinstance(self.value, integer_types): return fd_func(self.value, *args) else: return name_func(self.value, *args) diff --git a/xattr/compat.py b/xattr/compat.py new file mode 100644 index 0000000..b3094e3 --- /dev/null +++ b/xattr/compat.py @@ -0,0 +1,11 @@ +"""Python 3 compatibility shims +""" +import sys +if sys.version_info[0] < 3: + integer_types = (int, long) + text_type = unicode + binary_type = str +else: + integer_types = (int,) + text_type = str + binary_type = bytes diff --git a/xattr/pyxattr_compat.py b/xattr/pyxattr_compat.py index 0ef913b..3d594de 100644 --- a/xattr/pyxattr_compat.py +++ b/xattr/pyxattr_compat.py @@ -8,6 +8,7 @@ This module provides compatibility for the pyxattr API. import sys +from .compat import (binary_type, integer_types, text_type) from .lib import (XATTR_NOFOLLOW, XATTR_CREATE, XATTR_REPLACE, XATTR_NOSECURITY, XATTR_MAXNAMELEN, XATTR_FINDERINFO_NAME, XATTR_RESOURCEFORK_NAME, _getxattr, _fgetxattr, _setxattr, _fsetxattr, @@ -29,13 +30,13 @@ _NO_NS = object() _fsencoding = sys.getfilesystemencoding() def _call(item, name_func, fd_func, *args): - if isinstance(item, int): + if isinstance(item, integer_types): return fd_func(item, *args) elif hasattr(item, 'fileno'): return fd_func(item.fileno(), *args) - elif isinstance(item, str): + elif isinstance(item, binary_type): return name_func(item, *args) - elif isinstance(item, unicode): + elif isinstance(item, text_type): item = item.encode(_fsencoding) return name_func(item, *args) else: diff --git a/xattr/tests/test_xattr.py b/xattr/tests/test_xattr.py index 548f735..c63a240 100644 --- a/xattr/tests/test_xattr.py +++ b/xattr/tests/test_xattr.py @@ -8,6 +8,11 @@ import xattr class BaseTestXattr(object): + # TESTDIR for temporary files usually defaults to "/tmp", + # which may not have XATTR support (e.g. tmpfs); + # manual override here. + TESTDIR = None + def test_attr(self): x = xattr.xattr(self.tempfile) @@ -66,15 +71,17 @@ class BaseTestXattr(object): self.assertEqual(str(e), msg) def test_symlink_attrs(self): - # Solaris doesn't support extended attributes on symlinks - if sys.platform == 'sunos5': - return symlinkPath = self.tempfilename + '.link' os.symlink(self.tempfilename, symlinkPath) try: symlink = xattr.xattr(symlinkPath, options=xattr.XATTR_NOFOLLOW) realfile = xattr.xattr(self.tempfilename) - symlink['user.islink'] = b'true' + try: + symlink['user.islink'] = b'true' + except IOError: + # Solaris, Linux don't support extended attributes on symlinks + raise unittest.SkipTest("XATTRs on symlink not allowed" + " on filesystem/platform") self.assertEqual(dict(realfile), {}) self.assertEqual(symlink['user.islink'], b'true') finally: @@ -83,7 +90,7 @@ class BaseTestXattr(object): class TestFile(TestCase, BaseTestXattr): def setUp(self): - self.tempfile = NamedTemporaryFile() + self.tempfile = NamedTemporaryFile(dir=self.TESTDIR) self.tempfilename = self.tempfile.name def tearDown(self): @@ -92,7 +99,7 @@ class TestFile(TestCase, BaseTestXattr): class TestDir(TestCase, BaseTestXattr): def setUp(self): - self.tempfile = mkdtemp() + self.tempfile = mkdtemp(dir=self.TESTDIR) self.tempfilename = self.tempfile def tearDown(self): @@ -107,7 +114,9 @@ except AttributeError: else: class TestFileWithSurrogates(TestFile): def setUp(self): - if sys.platform != 'linux': + if sys.platform not in ('linux', 'linux2'): raise unittest.SkipTest('Files with invalid encoded names are only supported under linux') - self.tempfile = NamedTemporaryFile(prefix=b'invalid-\xe9'.decode('utf8','surrogateescape')) + if sys.version_info[0] < 3: + raise unittest.SkipTest('Test is only available on Python3') # surrogateescape not avail in py2 + self.tempfile = NamedTemporaryFile(prefix=b'invalid-\xe9'.decode('utf8','surrogateescape'), dir=self.TESTDIR) self.tempfilename = self.tempfile.name diff --git a/xattr/tool.py b/xattr/tool.py index 573261f..5cdecbd 100755 --- a/xattr/tool.py +++ b/xattr/tool.py @@ -3,7 +3,7 @@ ## # Copyright (c) 2007 Apple Inc. # -# This is the MIT license. This software may also be distributed under the +# This is the MIT license. This software may also be distributed under the # same terms as Python (the PSF license). # # Permission is hereby granted, free of charge, to any person obtaining a @@ -35,6 +35,10 @@ import zlib import xattr +class NullsInString(Exception): + """Nulls in string.""" + + def usage(e=None): if e: print(e) @@ -62,10 +66,6 @@ def usage(e=None): sys.exit(0) -class NullsInString(Exception): - """Nulls in string.""" - - _FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)]) @@ -127,7 +127,7 @@ def main(): if write: if not args: usage("No attr_value") - attr_value = args.pop(0) + attr_value = args.pop(0).encode('utf-8') if len(args) > 1: multiple_files = True @@ -185,13 +185,14 @@ def main(): attr_value = decompress(attrs[attr_name]) except zlib.error: attr_value = attrs[attr_name] + attr_value = attr_value.decode('utf-8') except KeyError: onError("%sNo such xattr: %s" % (file_prefix, attr_name)) continue if long_format: try: - if attr_value.find('\0') >= 0: + if '\0' in attr_value: raise NullsInString print("".join((file_prefix, "%s: " % (attr_name,), attr_value))) except (UnicodeDecodeError, NullsInString): |