Merge branch 'master' into change_install_path

Conflicts:
	install.py
pull/297/head
Felix Laurie von Massenbach 10 years ago
commit 3c2189fcbf

1
.gitignore vendored

@ -3,4 +3,5 @@
*~ *~
*.tar.gz *.tar.gz
*.patch *.patch
.tox
tags tags

@ -1,11 +1,17 @@
language: python language: python
python: python: 2.7
- 2.6
- 2.7 env:
- TOX_ENV=py26
- TOX_ENV=py27
- TOX_ENV=py32
- TOX_ENV=py33
- TOX_ENV=py34
- TOX_ENV=flake8
install: install:
- pip install --use-mirrors testify - pip install tox
script: script:
- make test - tox -e $TOX_ENV

@ -14,7 +14,7 @@ docs:
pandoc -s -w markdown docs/header.md docs/install.md docs/body.md -o README.md pandoc -s -w markdown docs/header.md docs/install.md docs/body.md -o README.md
lint: lint:
@flake8 ./ --config=setup.cfg @flake8 ./ --config=tox.ini
release: docs release: docs
# Check for tag existence # Check for tag existence
@ -38,6 +38,6 @@ tar:
git archive --format=tar --prefix autojump_v$(VERSION)/ $(TAGNAME) | gzip > autojump_v$(VERSION).tar.gz git archive --format=tar --prefix autojump_v$(VERSION)/ $(TAGNAME) | gzip > autojump_v$(VERSION).tar.gz
sha1sum autojump_v$(VERSION).tar.gz sha1sum autojump_v$(VERSION).tar.gz
test: test: lint
@find . -type f -iname "*.pyc" -delete @find . -type f -iname "*.pyc" -delete
testify -v tests -x disabled tox

@ -38,7 +38,7 @@ can be used with `autojump` can be used with `j` and vice versa.
jo music jo music
- Opening a file manager to a child directory is also supported: Opening a file manager to a child directory is also supported:
jco images jco images
@ -54,7 +54,7 @@ can be used with `autojump` can be used with `j` and vice versa.
a different entry. In the above example, `j w in` would then change a different entry. In the above example, `j w in` would then change
directory to /home/user/work/inbox. directory to /home/user/work/inbox.
For more options refer to the help: For more options refer to help:
autojump --help autojump --help
@ -64,7 +64,12 @@ INSTALLATION
### REQUIREMENTS ### REQUIREMENTS
- Python v2.6+ - Python v2.6+
- Bash v4.0+, zsh, fish, or clink (Windows) - Supported shells:
- bash v4.0+
- zsh
- fish
- tcsh (experimental)
- clink on Windows (experimental)
### AUTOMATIC ### AUTOMATIC
@ -98,7 +103,7 @@ MacPorts also available:
Windows Windows
------- -------
Windows support is enabled by [clink](https://code.google.com/p/clink/), Windows support is enabled by [clink](https://code.google.com/p/clink/)
which should be installed prior to installing autojump. which should be installed prior to installing autojump.
### MANUAL ### MANUAL
@ -107,7 +112,7 @@ Grab a copy of autojump:
git clone git://github.com/joelthelion/autojump.git git clone git://github.com/joelthelion/autojump.git
Run the installation script and follow the on screen instructions. Run the installation script and follow on screen instructions.
cd autojump cd autojump
./install.py or ./uninstall.py ./install.py or ./uninstall.py

@ -193,9 +193,6 @@ def find_matches(entries, needles, check_entries=True):
def handle_tab_completion(needle, entries): def handle_tab_completion(needle, entries):
if not needle:
sys.exit(0)
tab_needle, tab_index, tab_path = get_tab_entry_info(needle, TAB_SEPARATOR) tab_needle, tab_index, tab_path = get_tab_entry_info(needle, TAB_SEPARATOR)
if tab_path: if tab_path:
@ -285,7 +282,7 @@ def match_consecutive(needles, haystack, ignore_case=False):
regex_no_sep_end = regex_no_sep + '$' regex_no_sep_end = regex_no_sep + '$'
regex_one_sep = regex_no_sep + sep + regex_no_sep regex_one_sep = regex_no_sep + sep + regex_no_sep
# can't use compiled regex because of flags # can't use compiled regex because of flags
regex_needle = regex_one_sep.join(needles).replace('\\', '\\\\') + regex_no_sep_end regex_needle = regex_one_sep.join(needles).replace('\\', '\\\\') + regex_no_sep_end # noqa
regex_flags = re.IGNORECASE | re.UNICODE if ignore_case else re.UNICODE regex_flags = re.IGNORECASE | re.UNICODE if ignore_case else re.UNICODE
found = lambda entry: re.search( found = lambda entry: re.search(
regex_needle, regex_needle,
@ -364,7 +361,7 @@ def main(args): # noqa
save(config, first(add_path(load(config), args.add))) save(config, first(add_path(load(config), args.add)))
elif args.complete: elif args.complete:
handle_tab_completion( handle_tab_completion(
needle=first(sanitize(args.directory)), needle=first(chain(sanitize(args.directory), [''])),
entries=entriefy(load(config))) entries=entriefy(load(config)))
elif args.decrease: elif args.decrease:
data, entry = decrease_path(load(config), get_pwd(), args.decrease) data, entry = decrease_path(load(config), get_pwd(), args.decrease)
@ -382,8 +379,12 @@ def main(args): # noqa
elif args.stat: elif args.stat:
print_stats(load(config), config['data_path']) print_stats(load(config), config['data_path'])
elif not args.directory: elif not args.directory:
# always return a path to calling shell functions # Return best match.
print_local('.') entries = entriefy(load(config))
print_local(first(chain(
imap(attrgetter('path'), find_matches(entries, [''])),
# always return a path to calling shell functions
['.'])))
else: else:
entries = entriefy(load(config)) entries = entriefy(load(config))
needles = sanitize(args.directory) needles = sanitize(args.directory)

@ -0,0 +1,12 @@
# set user installation paths
if (-d ~/.autojump/bin) then
set path = (~/.autojump/bin path)
endif
# prepend autojump to cwdcmd (run after every change of working directory)
if (`alias cwdcmd` !~ *autojump*) then
alias cwdcmd 'autojump --add $cwd >/dev/null;' `alias cwdcmd`
endif
#default autojump command
alias j 'cd `autojump -- \!:1`'

@ -137,5 +137,5 @@ def save(config, data):
# create backup file if it doesn't exist or is older than BACKUP_THRESHOLD # create backup file if it doesn't exist or is older than BACKUP_THRESHOLD
if not os.path.exists(config['backup_path']) or \ if not os.path.exists(config['backup_path']) or \
(time() - os.path.getmtime(config['backup_path']) > BACKUP_THRESHOLD): #noqa (time() - os.path.getmtime(config['backup_path']) > BACKUP_THRESHOLD): # noqa
shutil.copy(config['data_path'], config['backup_path']) shutil.copy(config['data_path'], config['backup_path'])

@ -30,6 +30,8 @@ def create_dir(path):
def encode_local(string): def encode_local(string):
"""Converts string into user's preferred encoding.""" """Converts string into user's preferred encoding."""
if is_python3():
return string
return string.encode(sys.getfilesystemencoding() or 'utf-8') return string.encode(sys.getfilesystemencoding() or 'utf-8')
@ -170,8 +172,12 @@ def sanitize(directories):
def second(xs): def second(xs):
it = iter(xs) it = iter(xs)
try: try:
it.next() if is_python2():
return it.next() it.next()
return it.next()
elif is_python3():
next(it)
return next(it)
except StopIteration: except StopIteration:
return None return None

@ -1,2 +1,4 @@
flake8>=2.0.0 flake8
testify mock
pytest
tox

@ -25,7 +25,7 @@ j\ foo
.fi .fi
.RE .RE
.IP \[bu] 2 .IP \[bu] 2
Jump To A Child Directory Jump To A Child Directory:
.RS 2 .RS 2
.PP .PP
Sometimes it\[aq]s convenient to jump to a child directory Sometimes it\[aq]s convenient to jump to a child directory
@ -52,7 +52,7 @@ jo\ music
\f[] \f[]
.fi .fi
.PP .PP
Opening a file manager to a child directory is also supported. Opening a file manager to a child directory is also supported:
.IP .IP
.nf .nf
\f[C] \f[C]

@ -21,7 +21,7 @@ be used with `autojump` can be used with `j` and vice versa.
j foo j foo
- Jump To A Child Directory - Jump To A Child Directory:
Sometimes it's convenient to jump to a child directory (sub-directory of Sometimes it's convenient to jump to a child directory (sub-directory of
current directory) rather than typing out the full name. current directory) rather than typing out the full name.
@ -35,7 +35,7 @@ be used with `autojump` can be used with `j` and vice versa.
jo music jo music
Opening a file manager to a child directory is also supported. Opening a file manager to a child directory is also supported:
jco images jco images

@ -3,7 +3,12 @@
### REQUIREMENTS ### REQUIREMENTS
- Python v2.6+ - Python v2.6+
- Bash v4.0+, zsh, fish, or clink (Windows) - Supported shells:
- bash v4.0+
- zsh
- fish
- tcsh (experimental)
- clink (Windows, experimental)
### AUTOMATIC ### AUTOMATIC
@ -47,4 +52,4 @@ Grab a copy of autojump:
Run the installation script and follow on screen instructions. Run the installation script and follow on screen instructions.
cd autojump cd autojump
./install.py or ./uinstall.py ./install.py or ./uninstall.py

@ -10,7 +10,7 @@ import sys
sys.path.append('bin') sys.path.append('bin')
from autojump_argparse import ArgumentParser from autojump_argparse import ArgumentParser
SUPPORTED_SHELLS = ('bash', 'zsh', 'fish') SUPPORTED_SHELLS = ('bash', 'zsh', 'fish', 'tcsh')
def cp(src, dest, dryrun=False): def cp(src, dest, dryrun=False):
@ -157,6 +157,7 @@ def print_post_installation_message(share_dir, bin_dir):
print('\n\t' + source_msg) print('\n\t' + source_msg)
if get_shell() == 'zsh': if get_shell() == 'zsh':
print("\n\tautoload -U compinit && compinit -u") print("\n\tautoload -U compinit && compinit -u")
print("\nPlease restart terminal(s) before running autojump.\n") print("\nPlease restart terminal(s) before running autojump.\n")

@ -1,5 +0,0 @@
[flake8]
filename = *.py,autojump
ignore = E126,E128
max-line-length = 79
max-complexity = 10

@ -1,39 +1,20 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from random import randrange
from shutil import rmtree
from tempfile import gettempdir
from tempfile import mkdtemp
import os import os
import sys import sys
import mock import mock
from testify import TestCase import pytest
from testify import assert_equal
from testify import assert_false
from testify import assert_raises
from testify import assert_true
from testify import class_setup
from testify import class_teardown
from testify import run
from testify import setup
from testify import suite
from testify import teardown
if sys.version_info[0] == 3:
os.getcwdu = os.getcwd
sys.path.append(os.path.join(os.getcwd(), 'bin'))
sys.path.append(os.path.join(os.getcwd(), 'bin'))
import autojump_utils import autojump_utils
from autojump_utils import create_dir
from autojump_utils import encode_local from autojump_utils import encode_local
from autojump_utils import first from autojump_utils import first
from autojump_utils import get_pwd
from autojump_utils import get_tab_entry_info from autojump_utils import get_tab_entry_info
from autojump_utils import has_uppercase from autojump_utils import has_uppercase
from autojump_utils import in_bash from autojump_utils import in_bash
from autojump_utils import is_python3
from autojump_utils import last from autojump_utils import last
from autojump_utils import move_file
from autojump_utils import sanitize from autojump_utils import sanitize
from autojump_utils import second from autojump_utils import second
from autojump_utils import surround_quotes from autojump_utils import surround_quotes
@ -41,170 +22,124 @@ from autojump_utils import take
from autojump_utils import unico from autojump_utils import unico
class StringUnitTests(TestCase): if is_python3():
@mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii') os.getcwdu = os.getcwd
def test_encode_local_ascii(self, _): xrange = range
assert_equal(encode_local(u'foo'), b'foo')
@suite('disabled', reason='#246') def u(string):
def test_encode_local_ascii_fails(self): """
with assert_raises(UnicodeDecodeError): This is a unicode() wrapper since u'string' is a Python3 compiler error.
with mock.patch.object( """
sys, if is_python3():
'getfilesystemencoding', return string
return_value='ascii'): return unicode(string, encoding='utf-8', errors='strict')
encode_local(u'日本語')
@mock.patch.object(sys, 'getfilesystemencoding', return_value=None) # strings
def test_encode_local_empty(self, _): @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
assert_equal(encode_local(b'foo'), u'foo') @mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii')
def test_encode_local_ascii(_):
@mock.patch.object(sys, 'getfilesystemencoding', return_value='utf-8') assert encode_local(u('foo')) == b'foo'
def test_encode_local_unicode(self, _):
assert_equal(encode_local(b'foo'), u'foo')
assert_equal(encode_local(u'foo'), u'foo') @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
@pytest.mark.xfail(reason="disabled due to pytest bug: https://bitbucket.org/hpk42/pytest/issue/534/pytest-fails-to-catch-unicodedecodeerrors") # noqa
def test_has_uppercase(self): @mock.patch.object(sys, 'getfilesystemencoding', return_value='ascii')
assert_true(has_uppercase('Foo')) def test_encode_local_ascii_fails(_):
assert_true(has_uppercase('foO')) with pytest.raises(UnicodeDecodeError):
assert_false(has_uppercase('foo')) encode_local(u('日本語'))
assert_false(has_uppercase(''))
@mock.patch.object(autojump_utils, 'in_bash', return_value=True) @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
def test_surround_quotes_in_bash(self, _): @mock.patch.object(sys, 'getfilesystemencoding', return_value=None)
assert_equal(surround_quotes('foo'), '"foo"') def test_encode_local_empty(_):
assert encode_local(b'foo') == u('foo')
@mock.patch.object(autojump_utils, 'in_bash', return_value=False)
def test_dont_surround_quotes_not_in_bash(self, _):
assert_equal(surround_quotes('foo'), 'foo') @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
@mock.patch.object(sys, 'getfilesystemencoding', return_value='utf-8')
def test_sanitize(self): def test_encode_local_unicode(_):
assert_equal(sanitize([]), []) assert encode_local(b'foo') == u('foo')
assert_equal(sanitize([r'/foo/bar/', r'/']), [u'/foo/bar', u'/']) assert encode_local(u('foo')) == u('foo')
def test_unico(self):
assert_equal(unico(b'blah'), u'blah') def test_has_uppercase():
assert_equal(unico(b'日本語'), u'日本語') assert has_uppercase('Foo')
assert_equal(unico(u'でもおれは中国人だ。'), u'でもおれは中国人だ。') assert has_uppercase('foO')
assert not has_uppercase('foo')
assert not has_uppercase('')
class IterationUnitTests(TestCase):
def test_first(self):
assert_equal(first(xrange(5)), 0) @mock.patch.object(autojump_utils, 'in_bash', return_value=True)
assert_equal(first([]), None) def test_surround_quotes_in_bash(_):
assert surround_quotes('foo') == '"foo"'
def test_second(self):
assert_equal(second(xrange(5)), 1)
assert_equal(second([]), None) @mock.patch.object(autojump_utils, 'in_bash', return_value=False)
def test_dont_surround_quotes_not_in_bash(_):
def test_last(self): assert surround_quotes('foo') == 'foo'
assert_equal(last(xrange(4)), 3)
assert_equal(last([]), None)
def test_sanitize():
def test_take(self): assert sanitize([]) == []
assert_equal(list(take(1, xrange(3))), [0]) assert sanitize([r'/foo/bar/', r'/']) == [u('/foo/bar'), u('/')]
assert_equal(list(take(2, xrange(3))), [0, 1])
assert_equal(list(take(4, xrange(3))), [0, 1, 2])
assert_equal(list(take(10, [])), []) @pytest.mark.skipif(is_python3(), reason="Unicode sucks.")
def test_unico():
assert unico(str('blah')) == u('blah')
class EnvironmentalVariableIntegrationTests(TestCase): assert unico(str('日本語')) == u('日本語')
@setup assert unico(u('でもおれは中国人だ。')) == u('でもおれは中国人だ。')
def create_tmp_dir(self):
self.tmp_dir = mkdtemp()
# iteration
@teardown def test_first():
def delete_tmp_dir(self): assert first(xrange(5)) == 0
try: assert first([]) is None
rmtree(self.tmp_dir)
except OSError:
pass def test_second():
assert second(xrange(5)) == 1
def test_in_bash(self): assert second([]) is None
os.environ['SHELL'] = '/bin/bash'
assert_true(in_bash())
def test_last():
assert last(xrange(4)) == 3
assert last([]) is None
def test_take():
assert list(take(1, xrange(3))) == [0]
assert list(take(2, xrange(3))) == [0, 1]
assert list(take(4, xrange(3))) == [0, 1, 2]
assert list(take(10, [])) == []
# environment variables
def test_in_bash():
for path in ['/bin/bash', '/usr/bin/bash']:
os.environ['SHELL'] = path
assert in_bash()
for path in ['/bin/zsh', '/usr/bin/zsh']:
os.environ['SHELL'] = '/usr/bin/zsh' os.environ['SHELL'] = '/usr/bin/zsh'
assert_false(in_bash()) assert not in_bash()
def test_good_get_pwd(self):
os.chdir(self.tmp_dir) # helper functions
assert_equal(get_pwd(), self.tmp_dir) def test_get_needle():
assert get_tab_entry_info('foo__', '__') == ('foo', None, None)
def test_bad_get_pwd(self):
os.chdir(self.tmp_dir)
rmtree(self.tmp_dir) def test_get_index():
assert_raises(OSError, get_pwd) assert get_tab_entry_info('foo__2', '__') == ('foo', 2, None)
class FileSystemIntegrationTests(TestCase): def test_get_path():
@class_setup assert get_tab_entry_info('foo__3__/foo/bar', '__') \
def init(self): == ('foo', 3, '/foo/bar')
self.tmp_dir = os.path.join(gettempdir(), 'autojump')
os.makedirs(self.tmp_dir)
def test_get_none():
@class_teardown assert get_tab_entry_info('gibberish content', '__') == (None, None, None)
def cleanup(self):
try:
rmtree(self.tmp_dir)
except OSError:
pass
def get_random_path(self):
path = gettempdir()
while os.path.exists(path):
random_string = '%30x' % randrange(16 ** 30)
path = os.path.join(self.tmp_dir, random_string)
return path
def get_random_file(self):
path = self.get_random_path()
with open(path, 'w+') as f:
f.write('filler\n')
return path
def test_create_dir(self):
path = self.get_random_path()
create_dir(path)
assert_true(os.path.exists(path))
# should not raise OSError if directory already exists
create_dir(path)
assert_true(os.path.exists(path))
def test_move_file(self):
src = self.get_random_file()
dst = self.get_random_path()
assert_true(os.path.exists(src))
assert_false(os.path.exists(dst))
move_file(src, dst)
assert_false(os.path.exists(src))
assert_true(os.path.exists(dst))
class HelperFunctionsUnitTests(TestCase):
def test_get_needle(self):
assert_equal(
get_tab_entry_info('foo__', '__'),
('foo', None, None))
def test_get_index(self):
assert_equal(
get_tab_entry_info('foo__2', '__'),
('foo', 2, None))
def test_get_path(self):
assert_equal(
get_tab_entry_info('foo__3__/foo/bar', '__'),
('foo', 3, '/foo/bar'))
def test_get_none(self):
assert_equal(
get_tab_entry_info('gibberish content', '__'),
(None, None, None))
if __name__ == "__main__":
run()

@ -0,0 +1,32 @@
[tox]
envlist =
py26,
py27,
py32,
py33,
py34
# ignore missing setup.py
skipsdist = True
[testenv]
deps = -rdev-requirements.txt
commands = py.test -rsxX -q
[testenv:flake8]
deps = flake8
commands = flake8 .
[flake8]
filename =
*.py,
autojump
ignore =
E126,
E128
max-line-length = 79
max-complexity = 10
show-pep8 = True
[pytest]
addopts = -rsxX -q
norecursedirs = .git .tox docs

@ -78,6 +78,7 @@ def remove_custom_installation(args, dryrun=False):
rm(os.path.join(etc_dir, 'autojump.sh'), dryrun) rm(os.path.join(etc_dir, 'autojump.sh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.bash'), dryrun) rm(os.path.join(etc_dir, 'autojump.bash'), dryrun)
rm(os.path.join(etc_dir, 'autojump.fish'), dryrun) rm(os.path.join(etc_dir, 'autojump.fish'), dryrun)
rm(os.path.join(etc_dir, 'autojump.tcsh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun) rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun)
rm(os.path.join(zshshare_dir, '_j'), dryrun) rm(os.path.join(zshshare_dir, '_j'), dryrun)
rmdir(icon_dir, dryrun) rmdir(icon_dir, dryrun)
@ -114,6 +115,7 @@ def remove_system_installation(dryrun=False):
rm(os.path.join(etc_dir, 'autojump.sh'), dryrun) rm(os.path.join(etc_dir, 'autojump.sh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.bash'), dryrun) rm(os.path.join(etc_dir, 'autojump.bash'), dryrun)
rm(os.path.join(etc_dir, 'autojump.fish'), dryrun) rm(os.path.join(etc_dir, 'autojump.fish'), dryrun)
rm(os.path.join(etc_dir, 'autojump.tcsh'), dryrun)
rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun) rm(os.path.join(etc_dir, 'autojump.zsh'), dryrun)
rm(os.path.join(zshshare_dir, '_j'), dryrun) rm(os.path.join(zshshare_dir, '_j'), dryrun)
rmdir(icon_dir, dryrun) rmdir(icon_dir, dryrun)

Loading…
Cancel
Save