def Run(self, cmd_val): # type: (cmd_value__Argv) -> int num_args = len(cmd_val.argv) - 1 if num_args == 0: # TODO: It's suppose to try another dir before doing this? self.errfmt.Print_('pushd: no other directory') return 1 elif num_args > 1: e_usage('got too many arguments') # TODO: 'cd' uses normpath? Is that inconsistent? dest_dir = os_path.abspath(cmd_val.argv[1]) err_num = pyos.Chdir(dest_dir) if err_num != 0: self.errfmt.Print_("pushd: %r: %s" % (dest_dir, posix.strerror(err_num)), span_id=cmd_val.arg_spids[1]) return 1 self.dir_stack.Push(dest_dir) _PrintDirStack(self.dir_stack, SINGLE_LINE, state.MaybeString(self.mem, 'HOME')) state.ExportGlobalString(self.mem, 'PWD', dest_dir) self.mem.SetPwd(dest_dir) return 0
def _PopDirStack(mem, dir_stack, errfmt): # type: (Mem, DirStack, ErrorFormatter) -> bool """Helper for popd and cd { ... }.""" dest_dir = dir_stack.Pop() if dest_dir is None: errfmt.Print_('popd: directory stack is empty') return False err_num = pyos.Chdir(dest_dir) if err_num != 0: # Happens if a directory is deleted in pushing and popping errfmt.Print_("popd: %r: %s" % (dest_dir, posix.strerror(err_num))) return False state.SetGlobalString(mem, 'PWD', dest_dir) mem.SetPwd(dest_dir) return True
def Run(self, cmd_val): # type: (cmd_value__Argv) -> int attrs, arg_r = flag_spec.ParseCmdVal('cd', cmd_val) arg = arg_types.cd(attrs.attrs) dest_dir, arg_spid = arg_r.Peek2() if dest_dir is None: val = self.mem.GetValue('HOME') try: dest_dir = state.GetString(self.mem, 'HOME') except error.Runtime as e: self.errfmt.Print_(e.UserErrorString()) return 1 if dest_dir == '-': try: dest_dir = state.GetString(self.mem, 'OLDPWD') print(dest_dir) # Shells print the directory except error.Runtime as e: self.errfmt.Print_(e.UserErrorString()) return 1 try: pwd = state.GetString(self.mem, 'PWD') except error.Runtime as e: self.errfmt.Print_(e.UserErrorString()) return 1 # Calculate new directory, chdir() to it, then set PWD to it. NOTE: We can't # call posix.getcwd() because it can raise OSError if the directory was # removed (ENOENT.) abspath = os_path.join(pwd, dest_dir) # make it absolute, for cd .. if arg.P: # -P means resolve symbolic links, then process '..' real_dest_dir = libc.realpath(abspath) else: # -L means process '..' first. This just does string manipulation. (But # realpath afterward isn't correct?) real_dest_dir = os_path.normpath(abspath) err_num = pyos.Chdir(real_dest_dir) if err_num != 0: self.errfmt.Print_("cd %r: %s" % (real_dest_dir, posix.strerror(err_num)), span_id=arg_spid) return 1 state.ExportGlobalString(self.mem, 'PWD', real_dest_dir) # WEIRD: We need a copy that is NOT PWD, because the user could mutate PWD. # Other shells use global variables. self.mem.SetPwd(real_dest_dir) if cmd_val.block: self.dir_stack.Push(real_dest_dir) try: unused = self.cmd_ev.EvalBlock(cmd_val.block) finally: # TODO: Change this to a context manager. # note: it might be more consistent to use an exception here. if not _PopDirStack(self.mem, self.dir_stack, self.errfmt): return 1 else: # No block state.ExportGlobalString(self.mem, 'OLDPWD', pwd) self.dir_stack.Reset() # for pushd/popd/dirs return 0