Beispiel #1
0
    def Run(self, cmd_val):
        # type: (cmd_value__Argv) -> int
        arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids)
        arg_r.Next()

        # NOTE: If first char is a colon, error reporting is different.  Alpine
        # might not use that?
        spec_str = arg_r.ReadRequired('requires an argspec')

        var_name, var_spid = arg_r.ReadRequired2(
            'requires the name of a variable to set')

        spec = self.spec_cache.get(spec_str)
        if spec is None:
            spec = _ParseOptSpec(spec_str)
            self.spec_cache[spec_str] = spec

        user_argv = self.mem.GetArgv() if arg_r.AtEnd() else arg_r.Rest()
        #util.log('user_argv %s', user_argv)
        status, flag_char = _GetOpts(spec, user_argv, self.my_state,
                                     self.errfmt)

        if match.IsValidVarName(var_name):
            state.SetRefString(self.mem, var_name, flag_char)
        else:
            # NOTE: The builtin has PARTIALLY set state.  This happens in all shells
            # except mksh.
            raise error.Usage('got invalid variable name %r' % var_name,
                              span_id=var_spid)
        return status
Beispiel #2
0
    def Run(self, cmd_val):
        # type: (cmd_value__Argv) -> int

        # TODO: Also hard usage error here too?
        attrs, arg_r = flag_spec.ParseOilCmdVal('run', cmd_val)
        arg = arg_types.run(attrs.attrs)

        if arg_r.Peek() is None:
            # HARD ERROR, not e_usage(), because errexit is often disabled!
            e_die("'run' expected a command to run", status=2)

        argv, spids = arg_r.Rest2()
        cmd_val2 = cmd_value.Argv(argv, spids, cmd_val.block)

        # Set in the 'except' block, e.g. if 'myfunc' failed
        failure_spid = runtime.NO_SPID
        try:
            # Temporarily turn ON errexit, and blame the 'run' spid.  Note that
            # 'if run myproc' disables it and then enables it!
            with state.ctx_ErrExit(self.mutable_opts, True,
                                   cmd_val.arg_spids[0]):
                # Pass do_fork=True.  Slight annoyance: the real value is a field of
                # command.Simple().  See _NoForkLast() in CommandEvaluator We have an
                # extra fork (miss out on an optimization) of code like ( status ls )
                # or forkwait { status ls }, but that is NOT idiomatic code.  status is
                # for functions.
                status = self.shell_ex.RunSimpleCommand(cmd_val2, True)
                #log('st %d', status)
        except error.ErrExit as e:  # from functino call
            #log('e %d', e.exit_status)
            status = e.exit_status
            failure_spid = e.span_id

        # Do this before -allow-status-01
        if arg.status_ok is not None:
            status = _AdjustStatus(arg.status_ok, status)

        if arg.allow_status_01 and status not in (0, 1):
            if failure_spid != runtime.NO_SPID:
                self.errfmt.Print_('(original failure)', span_id=failure_spid)
                self.errfmt.StderrLine('')

            raise error.ErrExit('fatal: status %d when --allow-status-01' %
                                status,
                                span_id=spids[0],
                                status=status)

        if arg.assign_status is not None:
            var_name = arg.assign_status
            if var_name.startswith(':'):
                var_name = var_name[1:]

            state.SetRefString(self.mem, var_name, str(status))
            return 0  # don't fail

        return status
Beispiel #3
0
    def _Read(self, arg, names):
        # type: (arg_types.read, List[str]) -> int

        if arg.n >= 0:  # read a certain number of bytes (-1 means unset)
            if len(names):
                name = names[0]
            else:
                name = 'REPLY'  # default variable name

            stdin_fd = self.stdin.fileno()
            s = self._ReadN(stdin_fd, arg.n)

            state.SetRefString(self.mem, name, s)

            # Did we read all the bytes we wanted?
            return 0 if len(s) == arg.n else 1

        if len(names) == 0:
            names.append('REPLY')

        # leftover words assigned to the last name
        if arg.a is not None:
            max_results = 0  # no max
        else:
            max_results = len(names)

        if arg.Z:  # -0 is synonym for -r -d ''
            raw = True
            delim_char = '\0'
        else:
            raw = arg.r
            if arg.d is not None:
                if len(arg.d):
                    delim_char = arg.d[0]
                else:
                    delim_char = '\0'  # -d '' delimits by NUL
            else:
                delim_char = '\n'  # read a line

        # We have to read more than one line if there is a line continuation (and
        # it's not -r).
        parts = []  # type: List[mylib.BufWriter]
        join_next = False
        status = 0
        while True:
            line, eof = _ReadUntilDelim(delim_char)

            if eof:
                # status 1 to terminate loop.  (This is true even though we set
                # variables).
                status = 1

            #log('LINE %r', line)
            if len(line) == 0:
                break

            spans = self.splitter.SplitForRead(line, not raw)
            done, join_next = _AppendParts(line, spans, max_results, join_next,
                                           parts)

            #log('PARTS %s continued %s', parts, continued)
            if done:
                break

        entries = [buf.getvalue() for buf in parts]
        num_parts = len(entries)
        if arg.a is not None:
            state.SetRefArray(self.mem, arg.a, entries)
        else:
            for i in xrange(max_results):
                if i < num_parts:
                    s = entries[i]
                else:
                    s = ''  # if there are too many variables
                #log('read: %s = %s', names[i], s)
                state.SetRefString(self.mem, names[i], s)

        return status
Beispiel #4
0
 def Fail(self):
     # type: () -> None
     """On failure, reset OPTARG."""
     state.SetRefString(self.mem, 'OPTARG', '')
Beispiel #5
0
 def SetArg(self, optarg):
     # type: (str) -> None
     """Set OPTARG."""
     state.SetRefString(self.mem, 'OPTARG', optarg)
Beispiel #6
0
 def IncIndex(self):
     # type: () -> None
     """Increment OPTIND."""
     # Note: bash-completion uses a *local* OPTIND !  Not global.
     assert self._optind != -1
     state.SetRefString(self.mem, 'OPTIND', str(self._optind + 1))
Beispiel #7
0
    def Run(self, cmd_val):
        # type: (cmd_value__Argv) -> int
        argv = cmd_val.argv[1:]
        arg_r = args.Reader(argv)
        arg = COMPADJUST_SPEC.Parse(arg_r)
        var_names = arg_r.Rest()  # Output variables to set
        for name in var_names:
            # Ironically we could complete these
            if name not in ['cur', 'prev', 'words', 'cword']:
                raise error.Usage('Invalid output variable name %r' % name)
        #print(arg)

        # TODO: How does the user test a completion function programmatically?  Set
        # COMP_ARGV?
        val = self.mem.GetValue('COMP_ARGV')
        if val.tag != value_e.MaybeStrArray:
            raise error.Usage("COMP_ARGV should be an array")
        comp_argv = val.strs

        # These are the ones from COMP_WORDBREAKS that we care about.  The rest occur
        # "outside" of words.
        break_chars = [':', '=']
        if arg.s:  # implied
            break_chars.remove('=')
        # NOTE: The syntax is -n := and not -n : -n =.
        omit_chars = arg.n or ''
        for c in omit_chars:
            if c in break_chars:
                break_chars.remove(c)

        # argv adjusted according to 'break_chars'.
        adjusted_argv = []  # type: List[str]
        for a in comp_argv:
            completion.AdjustArg(a, break_chars, adjusted_argv)

        if 'words' in var_names:
            state.SetRefArray(self.mem, 'words', adjusted_argv)

        n = len(adjusted_argv)
        cur = adjusted_argv[-1]
        prev = '' if n < 2 else adjusted_argv[-2]

        if arg.s:
            if cur.startswith(
                    '--') and '=' in cur:  # Split into flag name and value
                prev, cur = cur.split('=', 1)
                split = 'true'
            else:
                split = 'false'
            # Do NOT set 'split' without -s.  Caller might not have declared it.
            # Also does not respect var_names, because we don't need it.
            state.SetRefString(self.mem, 'split', split)

        if 'cur' in var_names:
            state.SetRefString(self.mem, 'cur', cur)
        if 'prev' in var_names:
            state.SetRefString(self.mem, 'prev', prev)
        if 'cword' in var_names:
            # Same weird invariant after adjustment
            state.SetRefString(self.mem, 'cword', str(n - 1))

        return 0