This file is indexed.

/usr/lib/python3/dist-packages/cement/utils/shell.py is in python3-cement 2.10.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
"""Common Shell Utilities."""

import os
import sys
from subprocess import Popen, PIPE
from multiprocessing import Process
from threading import Thread
from ..core.meta import MetaMixin
from ..core.exc import FrameworkError


def exec_cmd(cmd_args, *args, **kw):
    """
    Execute a shell call using Subprocess.  All additional `*args` and
    `**kwargs` are passed directly to subprocess.Popen.  See `Subprocess
    <http://docs.python.org/library/subprocess.html>`_ for more information
    on the features of `Popen()`.

    :param cmd_args: List of command line arguments.
    :type cmd_args: list.
    :param args: Additional arguments are passed to Popen().
    :param kwargs: Additional keyword arguments are passed to Popen().
    :returns: The (stdout, stderror, return_code) of the command.
    :rtype: tuple

    Usage:

    .. code-block:: python

        from cement.utils import shell

        stdout, stderr, exitcode = shell.exec_cmd(['echo', 'helloworld'])

    """
    if 'stdout' not in kw.keys():
        kw['stdout'] = PIPE
    if 'stderr' not in kw.keys():
        kw['stderr'] = PIPE

    proc = Popen(cmd_args, *args, **kw)
    (stdout, stderr) = proc.communicate()
    proc.wait()
    return (stdout, stderr, proc.returncode)


def exec_cmd2(cmd_args, *args, **kw):
    """
    Similar to exec_cmd, however does not capture stdout, stderr (therefore
    allowing it to print to console).  All additional `*args` and
    `**kwargs` are passed directly to subprocess.Popen.  See `Subprocess
    <http://docs.python.org/library/subprocess.html>`_ for more information
    on the features of `Popen()`.

    :param cmd_args: List of command line arguments.
    :type cmd_args: list.
    :param args: Additional arguments are passed to Popen().
    :param kwargs: Additional keyword arguments are passed to Popen().
    :returns: The integer return code of the command.
    :rtype: int

    Usage:

    .. code-block:: python

        from cement.utils import shell

        exitcode = shell.exec_cmd2(['echo', 'helloworld'])

    """
    proc = Popen(cmd_args, *args, **kw)
    proc.wait()
    return proc.returncode


def spawn_process(target, start=True, join=False, *args, **kwargs):
    """
    A quick wrapper around multiprocessing.Process().  By default the start()
    function will be called before the spawned process object is returned.
    See `MultiProcessing
    <https://docs.python.org/2/library/multiprocessing.html>`_ for more
    information on the features of `Process()`.

    :param target: The target function to execute in the sub-process.
    :param start: Call start() on the process before returning the process
        object.
    :param join: Call join() on the process before returning the process
        object.  Only called if start=True.
    :param args: Additional arguments are passed to Process().
    :param kwargs: Additional keyword arguments are passed to Process().
    :returns: The process object returned by Process().

    Usage:

    .. code-block:: python

        from cement.utils import shell

        def add(a, b):
            print(a + b)

        p = shell.spawn_process(add, args=(12, 27))
        p.join()

    """
    proc = Process(target=target, *args, **kwargs)

    if start and not join:
        proc.start()
    elif start and join:
        proc.start()
        proc.join()
    return proc


def spawn_thread(target, start=True, join=False, *args, **kwargs):
    """
    A quick wrapper around threading.Thread().  By default the start()
    function will be called before the spawned thread object is returned
    See `Threading
    <https://docs.python.org/2/library/threading.html>`_ for more
    information on the features of `Thread()`.

    :param target: The target function to execute in the thread.
    :param start: Call start() on the thread before returning the thread
        object.
    :param join: Call join() on the thread before returning the thread
        object.  Only called if start=True.
    :param args: Additional arguments are passed to Thread().
    :param kwargs: Additional keyword arguments are passed to Thread().
    :returns: The thread object returned by Thread().

    Usage:

    .. code-block:: python

        from cement.utils import shell

        def add(a, b):
            print(a + b)

        t = shell.spawn_thread(add, args=(12, 27))
        t.join()

    """
    thr = Thread(target=target, *args, **kwargs)

    if start and not join:
        thr.start()
    elif start and join:
        thr.start()
        thr.join()
    return thr


class Prompt(MetaMixin):

    """
    A wrapper around `raw_input` or `input` (py3) whose purpose is to limit
    the redundent tasks of gather usr input.  Can be used in several ways
    depending on the use case (simple input, options, and numbered
    selection).

    :param text: The text displayed at the input prompt.

    Usage:

    Simple prompt to halt operations and wait for user to hit enter:

    .. code-block:: python

        p = shell.Prompt("Press Enter To Continue", default='ENTER')

    .. code-block:: text

        $ python myapp.py
        Press Enter To Continue

        $


    Provide a numbered list for longer selections:

    .. code-block:: python

        p = Prompt("Where do you live?",
                options=[
                    'San Antonio, TX',
                    'Austin, TX',
                    'Dallas, TX',
                    'Houston, TX',
                    ],
                numbered = True,
                )

    .. code-block:: text

        Where do you live?

        1: San Antonio, TX
        2: Austin, TX
        3: Dallas, TX
        4: Houston, TX

        Enter the number for your selection:


    Create a more complex prompt, and process the input from the user:

    .. code-block:: python

        class MyPrompt(Prompt):
            class Meta:
                text = "Do you agree to the terms?"
                options = ['Yes', 'no', 'maybe-so']
                options_separator = '|'
                default = 'no'
                clear = True
                max_attempts = 99

            def process_input(self):
                if self.input.lower() == 'yes':
                    # do something crazy
                    pass
                else:
                    # don't do anything... maybe exit?
                    print("User doesn't agree! I'm outa here")
                    sys.exit(1)

        MyPrompt()

    .. code-block:: text

        $ python myapp.py
        [TERMINAL CLEAR]

        Do you agree to the terms? [Yes|no|maybe-so] no
        User doesn't agree! I'm outa here

        $ echo $?

        $ 1

    """
    class Meta:

        """
        Optional meta-data (can also be passed as keyword arguments to the
        parent class).
        """
        # The text that is displayed to prompt the user
        text = "Tell me someting interesting:"

        #: A default value to use if the user doesn't provide any input
        default = None

        #: Options to provide to the user.  If set, the input must match one
        #: of the items in the options selection.
        options = None

        #: Separator to use within the option selection (non-numbered)
        options_separator = ','

        #: Display options in a numbered list, where the user can enter a
        #: number.  Useful for long selections.
        numbered = False

        #: The text to display along with the numbered selection for user
        #: input.
        selection_text = "Enter the number for your selection:"

        #: Whether or not to automatically prompt() the user once the class
        #: is instantiated.
        auto = True

        #: Whether to treat user input as case insensitive (only used to
        #: compare user input with available options).
        case_insensitive = True

        #: Whether or not to clear the terminal when prompting the user.
        clear = False

        #: Command to issue when clearing the terminal.
        clear_command = 'clear'

        #: Max attempts to get proper input from the user before giving up.
        max_attempts = 10

        #: Raise an exception when max_attempts is hit?  If not, Prompt
        #: passes the input through as `None`.
        max_attempts_exception = True

    def __init__(self, text=None, *args, **kw):
        if text is not None:
            kw['text'] = text
        super(Prompt, self).__init__(*args, **kw)

        self.input = None
        if self._meta.auto:
            self.prompt()

    def _prompt(self):
        if self._meta.clear:
            os.system(self._meta.clear_command)

        text = ""
        if self._meta.options is not None:
            if self._meta.numbered is True:
                text = text + self._meta.text + "\n\n"
                count = 1
                for option in self._meta.options:
                    text = text + "%s: %s\n" % (count, option)
                    count += 1
                text = text + "\n"
                text = text + self._meta.selection_text
            else:
                sep = self._meta.options_separator
                text = "%s [%s]" % (self._meta.text,
                                    sep.join(self._meta.options))
        else:
            text = self._meta.text

        if sys.version_info[0] < 3:                 # pragma: nocover  # noqa
            self.input = raw_input("%s " % text)    # pragma: nocover  # noqa
        else:                                       # pragma: nocover  # noqa
            self.input = input("%s " % text)        # pragma: nocover  # noqa

        if self.input == '' and self._meta.default is not None:
            self.input = self._meta.default
        elif self.input == '':
            self.input = None

    def prompt(self):
        """
        Prompt the user, and store their input as `self.input`.
        """

        attempt = 0
        while self.input is None:
            if attempt >= int(self._meta.max_attempts):
                if self._meta.max_attempts_exception is True:
                    raise FrameworkError("Maximum attempts exceeded getting "
                                         "valid user input")
                else:
                    return self.input

            attempt += 1
            self._prompt()

            if self.input is None:
                continue
            elif self._meta.options is not None:
                if self._meta.numbered:
                    try:
                        self.input = self._meta.options[int(self.input) - 1]
                    except (IndexError, ValueError) as e:
                        self.input = None
                        continue
                else:
                    if self._meta.case_insensitive is True:
                        lower_options = [x.lower()
                                         for x in self._meta.options]
                        if not self.input.lower() in lower_options:
                            self.input = None
                            continue
                    else:
                        if self.input not in self._meta.options:
                            self.input = None
                            continue

        self.process_input()
        return self.input

    def process_input(self):
        """
        Does not do anything.  Is intended to be used in a sub-class to handle
        user input after it is prompted.
        """
        pass