File: shells.py

package info (click to toggle)
python-userpath 1.9.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 228 kB
  • sloc: python: 771; makefile: 21; sh: 16
file content (111 lines) | stat: -rw-r--r-- 3,757 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
from os import environ, path, pathsep


DEFAULT_SHELLS = ('bash', 'sh')


class Shell(object):
    comment_starter = '#'

    def __init__(self, home=None):
        self.home = home or path.expanduser('~')


class Sh(Shell):
    def config(self, location, front=True):
        head, tail = (location, '$PATH') if front else ('$PATH', location)
        new_path = '{}{}{}'.format(head, pathsep, tail)

        return {path.join(self.home, '.profile'): 'PATH="{}"'.format(new_path)}

    @classmethod
    def show_path_commands(cls):
        # TODO: Find out what file influences non-login shells. The issue may simply be our Docker setup.
        return [['sh', '-i', '-l', '-c', 'echo $PATH']]


class Bash(Shell):
    def config(self, location, front=True):
        head, tail = (location, '$PATH') if front else ('$PATH', location)
        new_path = '{}{}{}'.format(head, pathsep, tail)
        contents = 'export PATH="{}"'.format(new_path)

        configs = {path.join(self.home, '.bashrc'): contents}

        # https://github.com/ofek/userpath/issues/3#issuecomment-492491977
        profile_path = path.join(self.home, '.profile')
        bash_profile_path = path.join(self.home, '.bash_profile')

        if path.exists(profile_path) and not path.exists(bash_profile_path):
            login_config = profile_path
        else:
            # NOTE: If it is decided in future that we want to make a distinction between
            # login and non-login shells, be aware that macOS will still need this since
            # Terminal.app runs a login shell by default for each new terminal window.
            login_config = bash_profile_path

        configs[login_config] = contents

        return configs

    @classmethod
    def show_path_commands(cls):
        return [['bash', '-i', '-c', 'echo $PATH'], ['bash', '-i', '-l', '-c', 'echo $PATH']]


class Fish(Shell):
    def config(self, location, front=True):
        location = ' '.join(location.split(pathsep))
        head, tail = (location, '$PATH') if front else ('$PATH', location)

        # https://github.com/fish-shell/fish-shell/issues/527#issuecomment-12436286
        contents = 'set PATH {} {}'.format(head, tail)

        return {path.join(self.home, '.config', 'fish', 'config.fish'): contents}

    @classmethod
    def show_path_commands(cls):
        return [
            ['fish', '-i', '-c', 'for p in $PATH; echo "$p"; end'],
            ['fish', '-i', '-l', '-c', 'for p in $PATH; echo "$p"; end'],
        ]


class Xonsh(Shell):
    def config(self, location, front=True):
        locations = location.split(pathsep)

        if front:
            contents = '\n'.join('$PATH.insert(0, {!r})'.format(location) for location in reversed(locations))
        else:
            contents = '\n'.join('$PATH.append({!r})'.format(location) for location in locations)

        return {path.join(self.home, '.xonshrc'): contents}

    @classmethod
    def show_path_commands(cls):
        command = "print('{}'.join($PATH))".format(pathsep)
        return [['xonsh', '-i', '-c', command], ['xonsh', '-i', '--login', '-c', command]]


class Zsh(Shell):
    def config(self, location, front=True):
        head, tail = (location, '$PATH') if front else ('$PATH', location)
        new_path = '{}{}{}'.format(head, pathsep, tail)
        contents = 'export PATH="{}"'.format(new_path)

        zdotdir = environ.get('ZDOTDIR', self.home)
        return {path.join(zdotdir, '.zshrc'): contents, path.join(zdotdir, '.zprofile'): contents}

    @classmethod
    def show_path_commands(cls):
        return [['zsh', '-i', '-c', 'echo $PATH'], ['zsh', '-i', '-l', '-c', 'echo $PATH']]


SHELLS = {
    'bash': Bash,
    'fish': Fish,
    'sh': Sh,
    'xonsh': Xonsh,
    'zsh': Zsh,
}