Beispiel #1
0
def _ResolveNames(names, funcs, aliases, search_path):
  results = []
  for name in names:
    if name in funcs:
      kind = ('function', name)
    elif name in aliases:
      kind = ('alias', name)

    # TODO: Use match instead?
    elif consts.LookupNormalBuiltin(name) != 0:
      kind = ('builtin', name)
    elif consts.LookupSpecialBuiltin(name) != 0:
      kind = ('builtin', name)
    elif consts.LookupAssignBuiltin(name) != 0:
      kind = ('builtin', name)
    elif lexer_def.IsOtherBuiltin(name):  # continue, etc.
      kind = ('builtin', name)

    elif lexer_def.IsKeyword(name):
      kind = ('keyword', name)
    else:
      resolved = search_path.Lookup(name)
      if resolved is None:
        kind = (None, None)
      else:
        kind = ('file', resolved) 
    results.append(kind)

  return results
Beispiel #2
0
def ResolveNames(names, funcs, aliases, search_path):
    # type: (List[str], Dict[str, command__ShFunction], Dict[str, str], SearchPath) -> Tuple[str, str]
    results = []
    for name in names:
        if name in funcs:
            kind = ('function', name)
        elif name in aliases:
            kind = ('alias', name)

        # TODO: Use match instead?
        elif consts.LookupNormalBuiltin(name) != 0:
            kind = ('builtin', name)
        elif consts.LookupSpecialBuiltin(name) != 0:
            kind = ('builtin', name)
        elif consts.LookupAssignBuiltin(name) != 0:
            kind = ('builtin', name)
        elif lexer_def.IsControlFlow(name):  # continue, etc.
            kind = ('keyword', name)

        elif lexer_def.IsKeyword(name):
            kind = ('keyword', name)
        else:
            resolved = search_path.Lookup(name)
            if resolved is None:
                kind = (None, None)
            else:
                kind = ('file', resolved)
        results.append(kind)

    return results
  def Run(self, cmd_val):
    # type: (cmd_value__Argv) -> int

    if len(cmd_val.argv) == 1:
      return 0  # this could be an error in strict mode?

    name = cmd_val.argv[1]

    # Run regular builtin or special builtin
    to_run = consts.LookupNormalBuiltin(name)
    if to_run == consts.NO_INDEX:
      to_run = consts.LookupSpecialBuiltin(name)
    if to_run == consts.NO_INDEX:
      span_id = cmd_val.arg_spids[1]
      if consts.LookupAssignBuiltin(name) != consts.NO_INDEX:
        # NOTE: There's a similar restriction for 'command'
        self.errfmt.Print("Can't run assignment builtin recursively",
                          span_id=span_id)
      else:
        self.errfmt.Print("%r isn't a shell builtin", name, span_id=span_id)
      return 1

    cmd_val2 = cmd_value.Argv(cmd_val.argv[1:], cmd_val.arg_spids[1:],
                              cmd_val.block)
    return self.shell_ex.RunBuiltin(to_run, cmd_val2)
Beispiel #4
0
def _ResolveNames(names, funcs, aliases, search_path):
    # type: (List[str], Dict[str, Proc], Dict[str, str], state.SearchPath) -> List[Tuple[str, str]]
    results = []  # type: List[Tuple[str, str]]
    for name in names:
        if name in funcs:
            kind = ('function', name)
        elif name in aliases:
            kind = ('alias', name)

        # TODO: Use match instead?
        elif consts.LookupNormalBuiltin(name) != 0:
            kind = ('builtin', name)
        elif consts.LookupSpecialBuiltin(name) != 0:
            kind = ('builtin', name)
        elif consts.LookupAssignBuiltin(name) != 0:
            kind = ('builtin', name)
        elif consts.IsControlFlow(name):  # continue, etc.
            kind = ('keyword', name)

        elif consts.IsKeyword(name):
            kind = ('keyword', name)
        else:
            resolved = search_path.Lookup(name)
            if resolved is None:
                no_str = None  # type: Optional[str]
                kind = (no_str, name)
            else:
                kind = ('file', resolved)
        results.append(kind)

    return results
Beispiel #5
0
    def _Visit(self, node):
        """
    """
        #log('VISIT %s', node.__class__.__name__)

        # NOTE: The tags are not unique!!!  We would need this:
        # if isinstance(node, ast.command) and node.tag == command_e.Simple:
        # But it's easier to check the __class__ attribute.

        cls = node.__class__
        if cls is command.Simple:
            #log('SimpleCommand %s', node.words)
            #log('--')
            #node.PrettyPrint()

            # Things to consider:
            # - source and .
            # - DONE builtins: get a list from builtin.py
            # - DONE functions: have to enter function definitions into a dictionary
            # - Commands that call others: sudo, su, find, xargs, etc.
            # - builtins that call others: exec, command
            #   - except not command -v!

            if not node.words:
                return

            w = node.words[0]
            ok, argv0, _ = word_.StaticEval(w)
            if not ok:
                log("Couldn't statically evaluate %r", w)
                return

            if (consts.LookupSpecialBuiltin(argv0) == consts.NO_INDEX
                    and consts.LookupAssignBuiltin(argv0) == consts.NO_INDEX
                    and consts.LookupNormalBuiltin(argv0) == consts.NO_INDEX):
                self.progs_used[argv0] = True

            # NOTE: If argv1 is $0, then we do NOT print a warning!
            if argv0 == 'sudo':
                if len(node.words) < 2:
                    return
                w1 = node.words[1]
                ok, argv1, _ = word_.StaticEval(w1)
                if not ok:
                    log("Couldn't statically evaluate %r", w)
                    return

                # Should we mark them behind 'sudo'?  e.g. "sudo apt install"?
                self.progs_used[argv1] = True

        elif cls is command.ShFunction:
            self.funcs_defined[node.name] = True
Beispiel #6
0
 def record_word(self, word_ob, text):
     pos = word_.LeftMostSpanForWord(word_ob)
     self.word_obs[text] = word_ob
     if (consts.LookupSpecialBuiltin(text) == consts.NO_INDEX
             and consts.LookupAssignBuiltin(text) == consts.NO_INDEX
             and consts.LookupNormalBuiltin(text) == consts.NO_INDEX):
         logger.info("Recording command: %r", text)
         logger.debug("   position: %d, word object: %r", pos, word_ob)
         self.commands[text].append(pos)
     else:
         # TODO: no immediate use since I'm no longer patching builtins
         # but there may still be utility in recording builtins a script
         # depends on. This would support spotting function/alias
         # clashes and such.
         self.builtins[text].append(pos)
Beispiel #7
0
  def RunSimpleCommand(self, cmd_val, do_fork, call_procs=True):
    # type: (cmd_value__Argv, bool, bool) -> int
    """
    Run builtins, functions, external commands

    Oil and other languages might have different, simpler rules.  No special
    builtins, etc.

    Oil might have OIL_PATH = @( ... ) or something.

    Interpreters might want to define all their own builtins.

    Args:
      procs: whether to look up procs.
    """
    argv = cmd_val.argv
    span_id = cmd_val.arg_spids[0] if len(cmd_val.arg_spids) else runtime.NO_SPID

    # This happens when you write "$@" but have no arguments.
    if len(argv) == 0:
      if self.exec_opts.strict_argv():
        e_die("Command evaluated to an empty argv array", span_id=span_id)
      else:
        return 0  # status 0, or skip it?

    arg0 = argv[0]

    builtin_id = consts.LookupAssignBuiltin(arg0)
    if builtin_id != consts.NO_INDEX:
      # command readonly is disallowed, for technical reasons.  Could relax it
      # later.
      self.errfmt.Print_("Can't run assignment builtin recursively",
                        span_id=span_id)
      return 1

    builtin_id = consts.LookupSpecialBuiltin(arg0)
    if builtin_id != consts.NO_INDEX:
      status = self.RunBuiltin(builtin_id, cmd_val)
      # TODO: Enable this and fix spec test failures.
      # Also update _SPECIAL_BUILTINS in osh/builtin.py.
      #if status != 0:
      #  e_die('special builtin failed', status=status)
      return status

    # TODO: if shopt -s namespaces, then look up in current namespace FIRST.
    #
    # Then fallback on self.procs, which should be renamed self.procs?
    #
    # honestly there is no real chance of colllision because
    # foo-bar() {} can't be accessed anyway
    # functions can have hyphens, but variables can't

    # Builtins like 'true' can be redefined as functions.
    if call_procs:
      proc_node = self.procs.get(arg0)
      if proc_node is not None:
        if (self.exec_opts.strict_errexit() and 
            self.mutable_opts.ErrExitIsDisabled()):
          self.errfmt.Print_('errexit was disabled for this construct',
                             span_id=self.mutable_opts.ErrExitSpanId())
          self.errfmt.StderrLine('')
          e_die("Can't run a proc while errexit is disabled. "
                "Use 'run' or wrap it in a process with $0 myproc",
                span_id=span_id)

        # NOTE: Functions could call 'exit 42' directly, etc.
        status = self.cmd_ev.RunProc(proc_node, argv[1:])
        return status

      # TODO:
      # look up arg0 in global namespace?  And see if the type is value.Obj
      # And it's a proc?
      # isinstance(val.obj, objects.Proc)
      UP_val = self.mem.GetVar(arg0)

      if mylib.PYTHON:  # Not reusing CPython objects
        if UP_val.tag_() == value_e.Obj:
          val = cast(value__Obj, UP_val)
          if isinstance(val.obj, objects.Proc):
            status = self.cmd_ev.RunOilProc(val.obj, argv[1:])
            return status

    builtin_id = consts.LookupNormalBuiltin(arg0)

    if builtin_id != consts.NO_INDEX:
      return self.RunBuiltin(builtin_id, cmd_val)

    environ = self.mem.GetExported()  # Include temporary variables

    if cmd_val.block:
      e_die('Unexpected block passed to external command %r', arg0,
            span_id=cmd_val.block.spids[0])

    # Resolve argv[0] BEFORE forking.
    argv0_path = self.search_path.CachedLookup(arg0)
    if argv0_path is None:
      self.errfmt.Print_('%r not found' % arg0, span_id=span_id)
      return 127

    # Normal case: ls /
    if do_fork:
      thunk = process.ExternalThunk(self.ext_prog, argv0_path, cmd_val, environ)
      p = process.Process(thunk, self.job_state)
      status = p.Run(self.waiter)
      return status

    # Already forked for pipeline: ls / | wc -l
    # TODO: count subshell?  ( ls / ) vs. ( ls /; ls / )
    self.ext_prog.Exec(argv0_path, cmd_val, environ)  # NEVER RETURNS
    assert False, "This line should never be reached" # makes mypy happy