1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3from __future__ import print_function
4
5import os
6import platform
7import shutil
8import sys
9
10sys.path.append('bin')
11from autojump_argparse import ArgumentParser  # noqa
12
13SUPPORTED_SHELLS = ('bash', 'zsh', 'fish', 'tcsh')
14
15
16def cp(src, dest, dryrun=False):
17    print('copying file: %s -> %s' % (src, dest))
18    if not dryrun:
19        shutil.copy(src, dest)
20
21
22def get_shell():
23    return os.path.basename(os.getenv('SHELL', ''))
24
25
26def mkdir(path, dryrun=False):
27    print('creating directory:', path)
28    if not dryrun and not os.path.exists(path):
29        os.makedirs(path)
30
31
32def modify_autojump_sh(etc_dir, share_dir, dryrun=False):
33    """Append custom installation path to autojump.sh"""
34    custom_install = '\
35        \n# check custom install \
36        \nif [ -s %s/autojump.${shell} ]; then \
37        \n    source %s/autojump.${shell} \
38        \nfi\n' % (share_dir, share_dir)
39
40    with open(os.path.join(etc_dir, 'autojump.sh'), 'a') as f:
41        f.write(custom_install)
42
43
44def modify_autojump_lua(clink_dir, bin_dir, dryrun=False):
45    """Prepend custom AUTOJUMP_BIN_DIR definition to autojump.lua"""
46    custom_install = "local AUTOJUMP_BIN_DIR = \"%s\"\n" % bin_dir.replace(
47        '\\',
48        '\\\\',
49    )
50    clink_file = os.path.join(clink_dir, 'autojump.lua')
51    with open(clink_file, 'r') as f:
52        original = f.read()
53    with open(clink_file, 'w') as f:
54        f.write(custom_install + original)
55
56
57def parse_arguments():  # noqa
58    if platform.system() == 'Windows':
59        default_user_destdir = os.path.join(
60            os.getenv('LOCALAPPDATA', ''),
61            'autojump',
62        )
63    else:
64        default_user_destdir = os.path.join(
65            os.path.expanduser('~'),
66            '.autojump',
67        )
68    default_user_prefix = ''
69    default_user_zshshare = 'functions'
70    default_system_destdir = '/'
71    default_system_prefix = '/usr/local'
72    default_system_zshshare = '/usr/share/zsh/site-functions'
73    default_clink_dir = os.path.join(os.getenv('LOCALAPPDATA', ''), 'clink')
74
75    parser = ArgumentParser(
76        description='Installs autojump globally for root users, otherwise \
77            installs in current user\'s home directory.'
78    )
79    parser.add_argument(
80        '-n', '--dryrun', action='store_true', default=False,
81        help='simulate installation',
82    )
83    parser.add_argument(
84        '-f', '--force', action='store_true', default=False,
85        help='skip root user, shell type, Python version checks',
86    )
87    parser.add_argument(
88        '-d', '--destdir', metavar='DIR', default=default_user_destdir,
89        help='set destination to DIR',
90    )
91    parser.add_argument(
92        '-p', '--prefix', metavar='DIR', default=default_user_prefix,
93        help='set prefix to DIR',
94    )
95    parser.add_argument(
96        '-z', '--zshshare', metavar='DIR', default=default_user_zshshare,
97        help='set zsh share destination to DIR',
98    )
99    parser.add_argument(
100        '-c', '--clinkdir', metavar='DIR', default=default_clink_dir,
101        help='set clink directory location to DIR (Windows only)',
102    )
103    parser.add_argument(
104        '-s', '--system', action='store_true', default=False,
105        help='install system wide for all users',
106    )
107
108    args = parser.parse_args()
109
110    if not args.force:
111        if sys.version_info[0] == 2 and sys.version_info[1] < 6:
112            print('Python v2.6+ or v3.0+ required.', file=sys.stderr)
113            sys.exit(1)
114        if args.system:
115            if platform.system() == 'Windows':
116                print(
117                    'System-wide installation is not supported on Windows.',
118                    file=sys.stderr,
119                )
120                sys.exit(1)
121            elif os.geteuid() != 0:
122                print(
123                    'Please rerun as root for system-wide installation.',
124                    file=sys.stderr,
125                )
126                sys.exit(1)
127
128        if platform.system() != 'Windows' \
129                and get_shell() not in SUPPORTED_SHELLS:
130            print(
131                'Unsupported shell: %s' % os.getenv('SHELL'),
132                file=sys.stderr,
133            )
134            sys.exit(1)
135
136    if args.destdir != default_user_destdir \
137            or args.prefix != default_user_prefix \
138            or args.zshshare != default_user_zshshare:
139        args.custom_install = True
140    else:
141        args.custom_install = False
142
143    if args.system:
144        if args.custom_install:
145            print(
146                'Custom paths incompatible with --system option.',
147                file=sys.stderr,
148            )
149            sys.exit(1)
150
151        args.destdir = default_system_destdir
152        args.prefix = default_system_prefix
153        args.zshshare = default_system_zshshare
154
155    return args
156
157
158def show_post_installation_message(etc_dir, share_dir, bin_dir):
159    if platform.system() == 'Windows':
160        print('\nPlease manually add %s to your user path' % bin_dir)
161    else:
162        if get_shell() == 'fish':
163            aj_shell = '%s/autojump.fish' % share_dir
164            source_msg = 'if test -f %s; . %s; end' % (aj_shell, aj_shell)
165            rcfile = '~/.config/fish/config.fish'
166        else:
167            aj_shell = '%s/autojump.sh' % etc_dir
168            source_msg = '[[ -s %s ]] && source %s' % (aj_shell, aj_shell)
169
170            if platform.system() == 'Darwin' and get_shell() == 'bash':
171                rcfile = '~/.profile'
172            else:
173                rcfile = '~/.%src' % get_shell()
174
175        print('\nPlease manually add the following line(s) to %s:' % rcfile)
176        print('\n\t' + source_msg)
177        if get_shell() == 'zsh':
178            print('\n\tautoload -U compinit && compinit -u')
179
180    print('\nPlease restart terminal(s) before running autojump.\n')
181
182
183def main(args):
184    if args.dryrun:
185        print('Installing autojump to %s (DRYRUN)...' % args.destdir)
186    else:
187        print('Installing autojump to %s ...' % args.destdir)
188
189    bin_dir = os.path.join(args.destdir, args.prefix, 'bin')
190    etc_dir = os.path.join(args.destdir, 'etc', 'profile.d')
191    doc_dir = os.path.join(args.destdir, args.prefix, 'share', 'man', 'man1')
192    share_dir = os.path.join(args.destdir, args.prefix, 'share', 'autojump')
193    zshshare_dir = os.path.join(args.destdir, args.zshshare)
194
195    mkdir(bin_dir, args.dryrun)
196    mkdir(doc_dir, args.dryrun)
197    mkdir(etc_dir, args.dryrun)
198    mkdir(share_dir, args.dryrun)
199
200    cp('./bin/autojump', bin_dir, args.dryrun)
201    cp('./bin/autojump_argparse.py', bin_dir, args.dryrun)
202    cp('./bin/autojump_data.py', bin_dir, args.dryrun)
203    cp('./bin/autojump_match.py', bin_dir, args.dryrun)
204    cp('./bin/autojump_utils.py', bin_dir, args.dryrun)
205    cp('./bin/icon.png', share_dir, args.dryrun)
206    cp('./docs/autojump.1', doc_dir, args.dryrun)
207
208    if platform.system() == 'Windows':
209        cp('./bin/autojump.lua', args.clinkdir, args.dryrun)
210        cp('./bin/autojump.bat', bin_dir, args.dryrun)
211        cp('./bin/j.bat', bin_dir, args.dryrun)
212        cp('./bin/jc.bat', bin_dir, args.dryrun)
213        cp('./bin/jo.bat', bin_dir, args.dryrun)
214        cp('./bin/jco.bat', bin_dir, args.dryrun)
215
216        if args.custom_install:
217            modify_autojump_lua(args.clinkdir, bin_dir, args.dryrun)
218    else:
219        mkdir(etc_dir, args.dryrun)
220        mkdir(share_dir, args.dryrun)
221        mkdir(zshshare_dir, args.dryrun)
222
223        cp('./bin/autojump.sh', etc_dir, args.dryrun)
224        cp('./bin/autojump.bash', share_dir, args.dryrun)
225        cp('./bin/autojump.fish', share_dir, args.dryrun)
226        cp('./bin/autojump.zsh', share_dir, args.dryrun)
227        cp('./bin/_j', zshshare_dir, args.dryrun)
228
229        if args.custom_install:
230            modify_autojump_sh(etc_dir, share_dir, args.dryrun)
231
232    show_post_installation_message(etc_dir, share_dir, bin_dir)
233
234
235if __name__ == '__main__':
236    sys.exit(main(parse_arguments()))
237