Browse Source

Merge branch 'master' of gitlab.com:adqm/tako

master
adam j hartz 2 years ago
parent
commit
869120d9ed

+ 1
- 1
setup.py View File

@@ -145,7 +145,7 @@ def main():
145 145
                      'Topic :: System :: Shells',
146 146
                      'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)'],
147 147
         packages=['takoshell', 'takoshell.ply', 'takoshell.parsers',
148
-                  'takoshell.xoreutils', 'takoshell.completers'],
148
+                  'takoshell.coreutils', 'takoshell.completers'],
149 149
         package_dir={'takoshell': 'takoshell'},
150 150
         package_data={'takoshell': ['*.json', 'LICENSE']},
151 151
         cmdclass=cmdclass

+ 1
- 1
takoshell/__init__.py View File

@@ -19,4 +19,4 @@
19 19
 # xonsh is Copyright (c) 2015-2016 the xonsh developers and is licensed under
20 20
 # the 2-Clause BSD license.
21 21
 
22
-__version__ = '0.2.2'
22
+__version__ = '0.2.3'

+ 3
- 1
takoshell/aliases.py View File

@@ -36,7 +36,7 @@ from argparse import ArgumentParser
36 36
 
37 37
 from takoshell.dirstack import cd, pushd, popd, dirs
38 38
 from takoshell.jobs import jobs, fg, bg, clean_jobs, disown
39
-from takoshell.xoreutils import _which
39
+from takoshell.coreutils import _which, _echo, _umask
40 40
 from takoshell.completers._aliases import completer_alias
41 41
 
42 42
 
@@ -373,4 +373,6 @@ default_aliases = {
373 373
     'fgrep': ['fgrep', '--color=auto'],
374 374
     'ls': ['ls', '--color=auto', '-v'],
375 375
     'suppress_tako_welcome_message': suppress_welcome,
376
+    'echo': _echo.echo,
377
+    'umask': _umask.umask,
376 378
 }

+ 0
- 0
takoshell/coreutils/__init__.py View File


+ 58
- 0
takoshell/coreutils/_echo.py View File

@@ -0,0 +1,58 @@
1
+# This file is part of tako
2
+# Copyright (c) 2015-2017 Adam Hartz <hartz@mit.edu> and contributors
3
+#
4
+# This program is free software: you can redistribute it and/or modify it under
5
+# the terms of the GNU General Public License as published by the Free Software
6
+# Foundation, either version 3 of the License, or (at your option) any later
7
+# version.
8
+#
9
+# This program is distributed in the hope that it will be useful, but WITHOUT
10
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12
+# details.
13
+#
14
+# You should have received a copy of the GNU General Public License along with
15
+# this program.  If not, see <http://www.gnu.org/licenses/>.
16
+"""Implements a simple echo command for tako."""
17
+
18
+def echo(args, stdin, stdout, stderr):
19
+    """A simple echo command."""
20
+    opts = _echo_parse_args(args)
21
+    if opts is None:
22
+        return
23
+    if opts['help']:
24
+        print(ECHO_HELP, file=stdout)
25
+        return 0
26
+    ender = opts['end']
27
+    args = map(str, args)
28
+    if opts['escapes']:
29
+        args = map(lambda x: x.encode().decode('unicode_escape'), args)
30
+    print(*args, end=ender, file=stdout)
31
+
32
+
33
+def _echo_parse_args(args):
34
+    out = {'escapes': False, 'end': '\n', 'help': False}
35
+    if '-e' in args:
36
+        args.remove('-e')
37
+        out['escapes'] = True
38
+    if '-E' in args:
39
+        args.remove('-E')
40
+        out['escapes'] = False
41
+    if '-n' in args:
42
+        args.remove('-n')
43
+        out['end'] = ''
44
+    if '-h' in args or '--help' in args:
45
+        out['help'] = True
46
+    return out
47
+
48
+
49
+ECHO_HELP = """Usage: echo [OPTIONS]... [STRING]...
50
+Echo the STRING(s) to standard output.
51
+
52
+  -n             do not include the trailing newline
53
+  -e             enable interpretation of backslash escapes
54
+  -E             disable interpretation of backslash escapes (default)
55
+  -h  --help     display this message and exit
56
+
57
+This version of echo was written in Python for tako: https://takoshell.org
58
+Based on echo from GNU coreutils: http://www.gnu.org/software/coreutils/"""

+ 184
- 0
takoshell/coreutils/_umask.py View File

@@ -0,0 +1,184 @@
1
+# This file is part of tako
2
+# Copyright (c) 2015-2017 Adam Hartz <hartz@mit.edu> and contributors
3
+#
4
+# This program is free software: you can redistribute it and/or modify it under
5
+# the terms of the GNU General Public License as published by the Free Software
6
+# Foundation, either version 3 of the License, or (at your option) any later
7
+# version.
8
+#
9
+# This program is distributed in the hope that it will be useful, but WITHOUT
10
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12
+# details.
13
+#
14
+# You should have received a copy of the GNU General Public License along with
15
+# this program.  If not, see <http://www.gnu.org/licenses/>.
16
+"""Implements a umask command for tako."""
17
+
18
+import re
19
+import os
20
+
21
+symbolic_matcher = re.compile(r'([ugo]*|a)([+-=])([^\s,]*)')
22
+
23
+order = 'rwx'
24
+name_to_value = {'x': 1, 'w': 2, 'r': 4}
25
+value_to_name = {v: k for k, v in name_to_value.items()}
26
+
27
+class_to_loc = {'u': 6, 'g': 3, 'o': 0}  # how many bits to shift this class by
28
+loc_to_class = {v: k for k, v in class_to_loc.items()}
29
+
30
+function_map = {
31
+    '+': lambda orig, new: orig | new,  # add the given permission
32
+    '-': lambda orig, new: orig & ~new,  # remove the given permission
33
+    '=': lambda orig, new: new,  # set the permissions exactly
34
+}
35
+
36
+
37
+def current_mask():
38
+    out = os.umask(0)
39
+    os.umask(out)
40
+    return out
41
+
42
+
43
+def invert(perms):
44
+    return 0o777 - perms
45
+
46
+
47
+def get_oct_digits(mode):
48
+    """
49
+    Separate a given integer into its three components
50
+    """
51
+    if not 0 <= mode <= 0o777:
52
+        raise ValueError("expected a value between 000 and 777")
53
+    return {'u': (mode & 0o700) >> 6,
54
+            'g': (mode & 0o070) >> 3,
55
+            'o': mode & 0o007}
56
+
57
+
58
+def from_oct_digits(digits):
59
+    o = 0
60
+    for c, m in digits.items():
61
+        o |= (m << class_to_loc[c])
62
+    return o
63
+
64
+
65
+def get_symbolic_rep_single(digit):
66
+    """
67
+    Given a single octal digit, return the appropriate string representation.
68
+    For example, 6 becomes "rw".
69
+    """
70
+    o = ''
71
+    for sym in 'rwx':
72
+        num = name_to_value[sym]
73
+        if digit & num:
74
+            o += sym
75
+            digit -= num
76
+    return o
77
+
78
+
79
+def get_symbolic_rep(number):
80
+    digits = get_oct_digits(number)
81
+    return ','.join('%s=%s' % (class_, get_symbolic_rep_single(digits[class_]))
82
+                    for class_ in 'ugo')
83
+
84
+
85
+def get_numeric_rep_single(rep):
86
+    """
87
+    Given a string representation, return the appropriate octal digit.
88
+    For example, "rw" becomes 6.
89
+    """
90
+    o = 0
91
+    for sym in set(rep):
92
+        o += name_to_value[sym]
93
+    return o
94
+
95
+
96
+def single_symbolic_arg(arg, old=None):
97
+    # we'll assume this always operates in the "forward" direction (on the
98
+    # current permissions) rather than on the mask directly.
99
+    if old is None:
100
+        old = invert(current_mask())
101
+
102
+    match = symbolic_matcher.match(arg)
103
+    if not match:
104
+        raise ValueError('could not parse argument %r' % arg)
105
+
106
+    class_, op, mask = match.groups()
107
+
108
+    if class_ == 'a':
109
+        class_ = 'ugo'
110
+
111
+    invalid_chars = [i for i in mask if i not in name_to_value]
112
+    if invalid_chars:
113
+        raise ValueError('invalid mask %r' % mask)
114
+
115
+    digits = get_oct_digits(old)
116
+    new_num = get_numeric_rep_single(mask)
117
+
118
+    for c in set(class_):
119
+        digits[c] = function_map[op](digits[c], new_num)
120
+
121
+    return from_oct_digits(digits)
122
+
123
+
124
+def valid_numeric_argument(x):
125
+    try:
126
+        return len(x) == 3 and all(0 <= int(i) <= 7 for i in x)
127
+    except:
128
+        return False
129
+
130
+
131
+def umask(args, stdin, stdout, stderr):
132
+    if '-h' in args:
133
+        print(UMASK_HELP, file=stdout)
134
+        return 0
135
+    symbolic = False
136
+    while '-S' in args:
137
+        symbolic = True
138
+        args.remove('-S')
139
+    cur = current_mask()
140
+    if len(args) == 0:
141
+        # just print the current mask
142
+        if symbolic:
143
+            to_print = get_symbolic_rep(invert(cur))
144
+        else:
145
+            to_print = oct(cur)[2:]
146
+            while len(to_print) < 3:
147
+                to_print = '0%s' % to_print
148
+        print(to_print, file=stdout)
149
+        return 0
150
+    else:
151
+        num = [valid_numeric_argument(i) for i in args]
152
+        if any(num):
153
+            if not all(num):
154
+                print("error: can't mix numeric and symbolic arguments", file=stderr)
155
+                return 1
156
+            if len(num) != 1:
157
+                print("error: can't have more than one numeric argument", file=stderr)
158
+                return 1
159
+        for arg, isnum in zip(args, num):
160
+            if isnum:
161
+                cur = int(arg, 8)
162
+            else:
163
+                # this mode operates not on the mask, but on the current
164
+                # _permissions_.  so invert first, operate, then invert back.
165
+                cur = invert(cur)
166
+                for subarg in arg.split(','):
167
+                    try:
168
+                        cur = single_symbolic_arg(subarg, cur)
169
+                    except:
170
+                        print('error: could not parse argument: %r' % subarg, file=stderr)
171
+                        return 1
172
+                cur = invert(cur)
173
+            os.umask(cur)
174
+
175
+
176
+UMASK_HELP = """Usage: umask [-S] [mode]...
177
+View or set the file creation mask.
178
+
179
+  -S             when printing, show output in symbolic format
180
+  -h  --help     display this message and exit
181
+
182
+This version of umask was written in Python for tako: https://takoshell.org
183
+Based on the umask command from Bash:
184
+https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html"""

takoshell/xoreutils/_which.py → takoshell/coreutils/_which.py View File


+ 1
- 1
takoshell/environ.py View File

@@ -303,7 +303,7 @@ class Env(MutableMapping):
303 303
             args = self._d['ARGS']
304 304
             ix = int(m.group(1))
305 305
             if ix >= len(args):
306
-                e = "Not enough arguments given to access ARG{0}."
306
+                e = "Not enough arguments given to access ${0}."
307 307
                 raise KeyError(e.format(ix))
308 308
             val = self._d['ARGS'][ix]
309 309
         elif key in self._d:

+ 0
- 21
takoshell/xoreutils/__init__.py View File

@@ -1,21 +0,0 @@
1
-# This file is part of tako
2
-# Copyright (c) 2015-2017 Adam Hartz <hartz@mit.edu> and contributors
3
-#
4
-# This program is free software: you can redistribute it and/or modify it under
5
-# the terms of the GNU General Public License as published by the Free Software
6
-# Foundation, either version 3 of the License, or (at your option) any later
7
-# version.
8
-#
9
-# This program is distributed in the hope that it will be useful, but WITHOUT
10
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
-# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
12
-# details.
13
-#
14
-# You should have received a copy of the GNU General Public License along with
15
-# this program.  If not, see <http://www.gnu.org/licenses/>.
16
-#
17
-#
18
-# tako is a fork of xonsh (http://xon.sh)
19
-# xonsh is Copyright (c) 2015-2016 the xonsh developers and is licensed under
20
-# the 2-Clause BSD license.
21
-

Loading…
Cancel
Save