def Open(self, path, mode='r'): # type: (str, str) -> mylib.LineReader """Opens a path for read, but moves it out of the reserved 3-9 fd range. Returns: A Python file object. The caller is responsible for Close(). Raises: OSError if the path can't be found. """ if mode == 'r': fd_mode = posix.O_RDONLY elif mode == 'w': fd_mode = posix.O_CREAT | posix.O_RDWR else: raise AssertionError(mode) fd = posix.open(path, fd_mode, 0o666) # may raise OSError new_fd = self._GetFreeDescriptor() posix.dup2(fd, new_fd) posix.close(fd) try: f = posix.fdopen(new_fd, mode) # Might raise IOError except IOError as e: raise OSError(*e.args) # Consistently raise OSError return f
def Open(self, path, mode='r'): # type: (str, str) -> mylib.LineReader """Opens a path for read, but moves it out of the reserved 3-9 fd range. Returns: A Python file object. The caller is responsible for Close(). Raises: OSError if the path can't be found. """ if mode == 'r': fd_mode = posix.O_RDONLY elif mode == 'w': fd_mode = posix.O_CREAT | posix.O_RDWR else: raise AssertionError(mode) fd = posix.open(path, fd_mode, 0o666) # may raise OSError # Immediately move it to a new location new_fd = fcntl.fcntl(fd, fcntl.F_DUPFD, _SHELL_MIN_FD) posix.close(fd) # Return a Python file handle try: f = posix.fdopen(new_fd, mode) # Might raise IOError except IOError as e: raise OSError(*e.args) # Consistently raise OSError return f
def _Open(self, path, c_mode, fd_mode): # type: (str, str, int) -> mylib.LineReader fd = posix.open(path, fd_mode, 0o666) # may raise OSError # Immediately move it to a new location new_fd = fcntl_.fcntl(fd, fcntl_.F_DUPFD, _SHELL_MIN_FD) # type: int posix.close(fd) # Return a Python file handle # Might raise IOError. Python-induced wart: we have to handle BOTH IOError # and OSError at higher levels. f = posix.fdopen(new_fd, c_mode) return f
def _Open(self, path, c_mode, fd_mode): # type: (str, str, int) -> mylib.LineReader fd = posix.open(path, fd_mode, 0o666) # may raise OSError # Immediately move it to a new location new_fd = fcntl.fcntl(fd, fcntl.F_DUPFD, _SHELL_MIN_FD) posix.close(fd) # Return a Python file handle try: f = posix.fdopen(new_fd, c_mode) # Might raise IOError except IOError as e: raise OSError(*e.args) # Consistently raise OSError return f
def testPrint(self): # Conclusion: print CAN raise IOError with EINTR. if posix_.environ.get('EINTR_TEST'): signal.signal(signal.SIGTERM, _Handler) r, w = posix_.pipe() log('Hanging on write in pid %d', posix_.getpid()) f = posix_.fdopen(w, 'w') # 1 byte bigger than pipe size print('x' * 65537, file=f) log('1: done') # write returns early when a signal interrupts it, and we read at least # one byte! We do NOT get EINTR> # On the second try, it didn't write anything, and we get EINTR! log('Second try (pid %d)', posix_.getpid()) print('x' * 65537, file=f) log('2: done')
args.Int, default=2, help='Indent JSON by this amount') JSON_READ_SPEC = flag_spec.OilFlags('json-read') # yajl has this option JSON_READ_SPEC.Flag('-validate', args.Bool, default=True, help='Validate UTF-8') _JSON_ACTION_ERROR = "builtin expects 'read' or 'write'" # global file object that can be passed to yajl.load(), and that also can be # used with redirects. See comment below. _STDIN = posix.fdopen(0) class Json(vm._Builtin): """Json I/O. -indent pretty prints it. Is the default indent 2? -pretty=0 can turn it off. json echo :myobj json echo -indent 2 :myobj :other_obj { x = 1 d = {name: 'andy'} }
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