Пример #1
0
    def _InitVarsFromEnv(self, environ):
        # This is the way dash and bash work -- at startup, they turn everything in
        # 'environ' variable into shell variables.  Bash has an export_env
        # variable.  Dash has a loop through environ in init.c
        for n, v in environ.iteritems():
            self.SetVar(sh_lhs_expr.Name(n), value.Str(v),
                        (var_flags_e.Exported, ), scope_e.GlobalOnly)

        # If it's not in the environment, initialize it.  This makes it easier to
        # update later in ExecOpts.

        # TODO: IFS, etc. should follow this pattern.  Maybe need a SysCall
        # interface?  self.syscall.getcwd() etc.

        v = self.GetVar('SHELLOPTS')
        if v.tag == value_e.Undef:
            SetGlobalString(self, 'SHELLOPTS', '')
        # Now make it readonly
        self.SetVar(sh_lhs_expr.Name('SHELLOPTS'), None,
                    (var_flags_e.ReadOnly, ), scope_e.GlobalOnly)

        # Usually we inherit PWD from the parent shell.  When it's not set, we may
        # compute it.
        v = self.GetVar('PWD')
        if v.tag == value_e.Undef:
            SetGlobalString(self, 'PWD', _GetWorkingDir())
        # Now mark it exported, no matter what.  This is one of few variables
        # EXPORTED.  bash and dash both do it.  (e.g. env -i -- dash -c env)
        self.SetVar(sh_lhs_expr.Name('PWD'), None, (var_flags_e.Exported, ),
                    scope_e.GlobalOnly)
Пример #2
0
    def __call__(self, cmd_val):
        arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids)
        arg_r.Next()
        arg, _ = GETLINE_SPEC.Parse(arg_r)
        if arg.cstr:
            # TODO: implement it
            # returns error if it can't decode
            raise NotImplementedError()

        var_name, var_spid = arg_r.ReadRequired2('requires a variable name')

        if var_name.startswith(':'):  # optional : sigil
            var_name = var_name[1:]

        next_arg, next_spid = arg_r.Peek2()
        if next_arg is not None:
            raise args.UsageError('got extra argument', span_id=next_spid)

        # TODO: use a more efficient function in C
        line = builtin.ReadLineFromStdin()
        if not line:  # EOF
            return 1

        if not arg.end:
            if line.endswith('\r\n'):
                line = line[:-2]
            elif line.endswith('\n'):
                line = line[:-1]

        self.mem.SetVar(sh_lhs_expr.Name(var_name), value.Str(line), (),
                        scope_e.LocalOnly)
        return 0
Пример #3
0
def ToLValue(node):
    # type: (arith_expr_t) -> sh_lhs_expr_t
    """Determine if a node is a valid L-value by whitelisting tags.

  Valid:
    x = y
    a[1] = y
  Invalid:
    a[0][0] = y
  """
    UP_node = node
    with tagswitch(node) as case:
        if case(arith_expr_e.VarRef):
            node = cast(arith_expr__VarRef, UP_node)
            # For consistency with osh/cmd_parse.py, append a span_id.
            # TODO: (( a[ x ] = 1 )) and a[x]=1 should use different LST nodes.
            n = sh_lhs_expr.Name(node.token.val)
            n.spids.append(node.token.span_id)
            return n

        elif case(arith_expr_e.Binary):
            node = cast(arith_expr__Binary, UP_node)
            if (node.op_id == Id.Arith_LBracket
                    and node.left.tag_() == arith_expr_e.VarRef):
                left = cast(arith_expr__VarRef, node.left)
                return sh_lhs_expr.IndexedName(left.token.val, node.right)
            # But a[0][0] = 1 is NOT valid.

    return None
Пример #4
0
def SetStringDynamic(mem, name, s):
    """Set a string by looking up the stack.

  Used for getopts.
  """
    assert isinstance(s, str)
    mem.SetVar(sh_lhs_expr.Name(name), value.Str(s), (), scope_e.Dynamic)
Пример #5
0
def SetArrayDynamic(mem, name, a):
  """Set an array by looking up the stack.

  Used for _init_completion.
  """
  assert isinstance(a, list)
  mem.SetVar(sh_lhs_expr.Name(name), value.MaybeStrArray(a), (), scope_e.Dynamic)
Пример #6
0
def SetLocalString(mem, name, s):
    """Set a local string.

  Used for:
  1) for loop iteration variables
  2) temporary environments like FOO=bar BAR=$FOO cmd,
  3) read builtin
  """
    assert isinstance(s, str)
    mem.SetVar(sh_lhs_expr.Name(name), value.Str(s), (), scope_e.LocalOnly)
Пример #7
0
def ToLValue(node):
    # type: (arith_expr_t) -> sh_lhs_expr_t
    """Determine if a node is a valid L-value by whitelisting tags.

  Args:
    node: ExprNode (could be VarExprNode or BinaryExprNode)
  """
    # foo = bar, foo[1] = bar
    if isinstance(node, arith_expr__VarRef):
        # For consistency with osh/cmd_parse.py, append a span_id.
        # TODO: (( a[ x ] = 1 )) and a[x]=1 should use different LST nodes.
        n = sh_lhs_expr.Name(node.token.val)
        n.spids.append(node.token.span_id)
        return n
    if isinstance(node, arith_expr__Binary):
        # For example, a[0][0] = 1 is NOT valid.
        if (node.op_id == Id.Arith_LBracket
                and isinstance(node.left, arith_expr__VarRef)):
            return sh_lhs_expr.IndexedName(node.left.token.val, node.right)

    return None
Пример #8
0
    def Run(self, cmd_val):
        arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids)
        arg_r.Next()  # skip 'json'

        action, action_spid = arg_r.Peek2()
        if action is None:
            raise error.Usage(_JSON_ACTION_ERROR)
        arg_r.Next()

        if action == 'write':
            arg, _ = JSON_WRITE_SPEC.Parse(arg_r)

            # GetVar() of each name and print it.

            for var_name in arg_r.Rest():
                if var_name.startswith(':'):
                    var_name = var_name[1:]

                val = self.mem.GetVar(var_name)
                with tagswitch(val) as case:
                    if case(value_e.Undef):
                        # TODO: blame the right span_id
                        self.errfmt.Print("no variable named %r is defined",
                                          var_name)
                        return 1
                    elif case(value_e.Str):
                        obj = val.s
                    elif case(value_e.MaybeStrArray):
                        obj = val.strs
                    elif case(value_e.AssocArray):
                        obj = val.d
                    elif case(value_e.Obj):
                        obj = val.obj
                    else:
                        raise AssertionError(val)

                if arg.pretty:
                    indent = arg.indent
                    extra_newline = False
                else:
                    # How yajl works: if indent is -1, then everything is on one line.
                    indent = -1
                    extra_newline = True

                j = yajl.dump(obj, sys.stdout, indent=indent)
                if extra_newline:
                    sys.stdout.write('\n')

            # TODO: Accept a block.  They aren't hooked up yet.
            if cmd_val.block:
                # TODO: flatten value.{Str,Obj} into a flat dict?
                namespace = self.cmd_ev.EvalBlock(cmd_val.block)

                print(yajl.dump(namespace))

        elif action == 'read':
            arg, _ = JSON_READ_SPEC.Parse(arg_r)
            # TODO:
            # Respect -validate=F

            var_name, name_spid = arg_r.ReadRequired2("expected variable name")
            if var_name.startswith(':'):
                var_name = var_name[1:]

            if not match.IsValidVarName(var_name):
                raise error.Usage('got invalid variable name %r' % var_name,
                                  span_id=name_spid)

            try:
                # Use a global _STDIN, because we get EBADF on a redirect if we use a
                # local.  A Py_DECREF closes the file, which we don't want, because the
                # redirect is responsible for freeing it.
                #
                # https://github.com/oilshell/oil/issues/675
                #
                # TODO: write a better binding like yajl.readfd()
                #
                # It should use streaming like here:
                # https://lloyd.github.io/yajl/

                obj = yajl.load(_STDIN)
            except ValueError as e:
                self.errfmt.Print('json read: %s', e, span_id=action_spid)
                return 1

            self.mem.SetVar(sh_lhs_expr.Name(var_name), value.Obj(obj),
                            scope_e.LocalOnly)

        else:
            raise error.Usage(_JSON_ACTION_ERROR, span_id=action_spid)

        return 0
Пример #9
0
    def __call__(self, cmd_val):
        arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids)
        arg_r.Next()  # skip 'json'

        action, action_spid = arg_r.Peek2()
        if action is None:
            raise args.UsageError(_JSON_ACTION_ERROR)
        arg_r.Next()

        if action == 'write':
            arg, _ = JSON_WRITE_SPEC.Parse(arg_r)

            # GetVar() of each name and print it.

            for var_name in arg_r.Rest():
                if var_name.startswith(':'):
                    var_name = var_name[1:]

                val = self.mem.GetVar(var_name)
                with tagswitch(val) as case:
                    if case(value_e.Undef):
                        # TODO: blame the right span_id
                        self.errfmt.Print("no variable named %r is defined",
                                          var_name)
                        return 1
                    elif case(value_e.Str):
                        obj = val.s
                    elif case(value_e.MaybeStrArray):
                        obj = val.strs
                    elif case(value_e.AssocArray):
                        obj = val.d
                    elif case(value_e.Obj):
                        obj = val.obj
                    else:
                        raise AssertionError(val)

                if arg.pretty:
                    indent = arg.indent
                    extra_newline = False
                else:
                    # How yajl works: if indent is -1, then everything is on one line.
                    indent = -1
                    extra_newline = True

                j = yajl.dump(obj, sys.stdout, indent=indent)
                if extra_newline:
                    sys.stdout.write('\n')

            # TODO: Accept a block.  They aren't hooked up yet.
            if cmd_val.block:
                # TODO: flatten value.{Str,Obj} into a flat dict?
                namespace = self.ex.EvalBlock(cmd_val.block)

                print(yajl.dump(namespace))

        elif action == 'read':
            arg, _ = JSON_READ_SPEC.Parse(arg_r)
            # TODO:
            # Respect -validate=F

            var_name, name_spid = arg_r.ReadRequired2("expected variable name")
            if var_name.startswith(':'):
                var_name = var_name[1:]

            if not match.IsValidVarName(var_name):
                raise args.UsageError('got invalid variable name %r' %
                                      var_name,
                                      span_id=name_spid)

            # Have to use this over sys.stdin because of redirects
            # TODO: change binding to yajl.readfd() ?
            stdin = posix_.fdopen(0)
            try:
                obj = yajl.load(stdin)
            except ValueError as e:
                self.errfmt.Print('json read: %s', e, span_id=action_spid)
                return 1

            self.mem.SetVar(sh_lhs_expr.Name(var_name), value.Obj(obj), (),
                            scope_e.LocalOnly)

        else:
            raise args.UsageError(_JSON_ACTION_ERROR, span_id=action_spid)

        return 0
def SetGlobalFunc(mem, name, func):
    # type: (Mem, str, Union[Callable, ParameterizedArray, type]) -> None
    """Used by bin/oil.py to set split(), etc."""
    assert callable(func), func
    mem.SetVar(sh_lhs_expr.Name(name), value.Obj(func), scope_e.GlobalOnly)
Пример #11
0
def ExportGlobalString(mem, name, s):
    """Helper for completion, $PWD, $OLDPWD, etc."""
    assert isinstance(s, str)
    val = value.Str(s)
    mem.SetVar(sh_lhs_expr.Name(name), val, (var_flags_e.Exported, ),
               scope_e.GlobalOnly)
Пример #12
0
def SetLocalArray(mem, name, a):
    """Helper for completion."""
    assert isinstance(a, list)
    mem.SetVar(sh_lhs_expr.Name(name), value.MaybeStrArray(a), (),
               scope_e.LocalOnly)
Пример #13
0
def SetGlobalString(mem, name, s):
    """Helper for completion, etc."""
    assert isinstance(s, str)
    val = value.Str(s)
    mem.SetVar(sh_lhs_expr.Name(name), val, (), scope_e.GlobalOnly)
Пример #14
0
def SetGlobalFunc(mem, name, func):
    """Used by bin/oil.py to set split(), etc."""
    assert callable(func), func
    mem.SetVar(sh_lhs_expr.Name(name), value.Obj(func), (), scope_e.GlobalOnly)