def AppBundleMain(argv): login_shell = False b = os_path.basename(argv[0]) main_name, ext = os_path.splitext(b) if main_name.startswith('-'): login_shell = True main_name = main_name[1:] if main_name == 'oil' and ext: # oil.py or oil.ovm try: first_arg = argv[1] except IndexError: raise args.UsageError('Missing required applet name.') if first_arg in ('-h', '--help'): builtin.Help(['bundle-usage'], pyutil.GetResourceLoader()) sys.exit(0) if first_arg in ('-V', '--version'): _ShowVersion() sys.exit(0) main_name = first_arg if main_name.startswith('-'): # TODO: Remove duplication above login_shell = True main_name = main_name[1:] argv0 = argv[1] main_argv = argv[2:] else: argv0 = argv[0] main_argv = argv[1:] if main_name in ('osh', 'sh'): status = ShellMain('osh', argv0, main_argv, login_shell) _tlog('done osh main') return status elif main_name == 'oshc': try: return OshCommandMain(main_argv) except args.UsageError as e: ui.Stderr('oshc usage error: %s', e.msg) return 2 elif main_name == 'oil': return ShellMain('oil', argv0, main_argv, login_shell) elif main_name == 'wok': return WokMain(main_argv) elif main_name == 'boil': return BoilMain(main_argv) # For testing latency elif main_name == 'true': return 0 elif main_name == 'false': return 1 elif main_name == 'readlink': return readlink.main(main_argv) else: raise args.UsageError('Invalid applet name %r.' % main_name)
def GetSpecForName(self, argv0): """ Args: argv0: A finished argv0 to lookup """ pair = self.lookup.get(argv0) # NOTE: Could be '' if pair: return pair key = os_path.basename(argv0) pair = self.lookup.get(key) if pair: return pair for glob_pat, base_opts, user_spec in self.patterns: #log('Matching %r %r', key, glob_pat) if libc.fnmatch(glob_pat, key): return base_opts, user_spec return None, None
def GetSpecForName(self, argv0): """ Args: argv0: A finished argv0 to lookup """ user_spec = self.lookup.get(argv0) # NOTE: Could be '' if user_spec: return user_spec key = os_path.basename(argv0) actions = self.lookup.get(key) if user_spec: return user_spec for glob_pat, base_opts, user_spec in self.patterns: #log('Matching %r %r', key, glob_pat) if libc.fnmatch(glob_pat, key): return base_opts, user_spec # Nothing matched return self.lookup['__fallback']
def Matches(self, comp): # type: (Api) -> List[str] # Have to clear the response every time. TODO: Reuse the object? state.SetGlobalArray(self.cmd_ev.mem, 'COMPREPLY', []) # New completions should use COMP_ARGV, a construct specific to OSH> state.SetGlobalArray(self.cmd_ev.mem, 'COMP_ARGV', comp.partial_argv) # Old completions may use COMP_WORDS. It is split by : and = to emulate # bash's behavior. # More commonly, they will call _init_completion and use the 'words' output # of that, ignoring COMP_WORDS. comp_words = [] for a in comp.partial_argv: AdjustArg(a, [':', '='], comp_words) if comp.index == -1: # cmopgen comp_cword = comp.index else: comp_cword = len(comp_words) - 1 # weird invariant state.SetGlobalArray(self.cmd_ev.mem, 'COMP_WORDS', comp_words) state.SetGlobalString(self.cmd_ev.mem, 'COMP_CWORD', str(comp_cword)) state.SetGlobalString(self.cmd_ev.mem, 'COMP_LINE', comp.line) state.SetGlobalString(self.cmd_ev.mem, 'COMP_POINT', str(comp.end)) argv = [comp.first, comp.to_complete, comp.prev] self.log('Running completion function %r with arguments %s', self.func.name, argv) self.comp_lookup.ClearCommandsChanged() status = self.cmd_ev.RunFuncForCompletion(self.func, argv) commands_changed = self.comp_lookup.GetCommandsChanged() self.log('comp.first %s, commands_changed: %s', comp.first, commands_changed) if status == 124: cmd = os_path.basename(comp.first) if cmd in commands_changed: self.log('Got status 124 from %r and %s commands changed', self.func.name, commands_changed) raise _RetryCompletion() else: # This happens with my own completion scripts. bash doesn't show an # error. self.log( "Function %r returned 124, but the completion spec for %r wasn't " "changed", self.func.name, cmd) return [] # Read the response. # NOTE: 'COMP_REPLY' would follow the naming convention! val = state.GetGlobal(self.cmd_ev.mem, 'COMPREPLY') if val.tag_() == value_e.Undef: # We set it above, so this error would only happen if the user unset it. # Not changing it means there were no completions. # TODO: This writes over the command line; it would be better to use an # error object. stderr_line('osh: Ran function %r but COMPREPLY was unset', self.func.name) return [] if val.tag_() != value_e.MaybeStrArray: log('ERROR: COMPREPLY should be an array, got %s', val) return [] self.log('COMPREPLY %s', val) # Return this all at once so we don't have a generator. COMPREPLY happens # all at once anyway. return val.strs
def _ReplaceBackslashCodes(self, tokens): # type: (List[Tuple[Id_t, str]]) -> str ret = [] # type: List[str] non_printing = 0 for id_, value in tokens: # BadBacklash means they should have escaped with \\. TODO: Make it an error. # 'echo -e' has a similar issue. if id_ in (Id.PS_Literals, Id.PS_BadBackslash): ret.append(value) elif id_ == Id.PS_Octal3: i = int(value[1:], 8) ret.append(chr(i % 256)) elif id_ == Id.PS_LBrace: non_printing += 1 ret.append('\x01') elif id_ == Id.PS_RBrace: non_printing -= 1 if non_printing < 0: # e.g. \]\[ return PROMPT_ERROR ret.append('\x02') elif id_ == Id.PS_Subst: # \u \h \w etc. ch = value[1:] if ch == '$': # So the user can tell if they're root or not. r = self.cache.Get('$') elif ch == 'u': r = self.cache.Get('user') elif ch == 'h': hostname = self.cache.Get('hostname') # foo.com -> foo r, _ = mylib.split_once(hostname, '.') elif ch == 'H': r = self.cache.Get('hostname') elif ch == 'w': try: pwd = state.GetString(self.mem, 'PWD') home = state.MaybeString( self.mem, 'HOME') # doesn't have to exist # Shorten to ~/mydir r = ui.PrettyDir(pwd, home) except error.Runtime as e: r = '<Error: %s>' % e.UserErrorString() elif ch == 'W': val = self.mem.GetValue('PWD') if val.tag_() == value_e.Str: str_val = cast(value__Str, val) r = os_path.basename(str_val.s) else: r = '<Error: PWD is not a string> ' else: r = consts.LookupCharPrompt(ch) # TODO: Handle more codes # R(r'\\[adehHjlnrstT@AuvVwW!#$\\]', Id.PS_Subst), if r is None: r = r'<Error: \%s not implemented in $PS1> ' % ch # See comment above on bash hack for $. ret.append(r.replace('$', '\\$')) else: raise AssertionError('Invalid token %r' % id_) # mismatched brackets, see https://github.com/oilshell/oil/pull/256 if non_printing != 0: return PROMPT_ERROR return ''.join(ret)
def AppBundleMain(argv): # type: (List[str]) -> int # NOTE: This has a side effect of deleting _OVM_* from the environment! loader = pyutil.GetResourceLoader() b = os_path.basename(argv[0]) main_name, ext = os_path.splitext(b) arg_r = args.Reader(argv) if main_name == 'oil' and ext: # oil.py or oil.ovm arg_r.Next() first_arg = arg_r.Peek() if first_arg is None: raise error.Usage('Missing required applet name.') if first_arg in ('-h', '--help'): errfmt = None # not needed here help_builtin = builtin_misc.Help(loader, errfmt) help_builtin.Run(pure.MakeBuiltinArgv(['bundle-usage'])) sys.exit(0) if first_arg in ('-V', '--version'): pyutil.ShowAppVersion('Oil', loader) sys.exit(0) main_name = first_arg login_shell = False if main_name.startswith('-'): login_shell = True main_name = main_name[1:] if main_name in ('osh', 'sh'): # TODO: # - Initialize a different shell if line_input isn't present status = shell.Main('osh', arg_r, posix.environ, login_shell, loader, line_input) _tlog('done osh main') return status elif main_name == 'osh-pure': # TODO: pure.Main() pass elif main_name == 'oshc': arg_r.Next() main_argv = arg_r.Rest() try: return OshCommandMain(main_argv) except error.Usage as e: stderr_line('oshc usage error: %s', e.msg) return 2 elif main_name == 'oil': return shell.Main('oil', arg_r, posix.environ, login_shell, loader, line_input) elif main_name == 'tea': main_argv = arg_r.Rest() return TeaMain(main_argv) # For testing latency elif main_name == 'true': return 0 elif main_name == 'false': return 1 elif main_name == 'readlink': main_argv = arg_r.Rest() return readlink.main(main_argv) else: raise error.Usage('Invalid applet name %r.' % main_name)
def _ReplaceBackslashCodes(self, tokens): # type: (List[Tuple[Id, str]]) -> str ret = [] non_printing = 0 for id_, value in tokens: # BadBacklash means they should have escaped with \\. TODO: Make it an error. # 'echo -e' has a similar issue. if id_ in (Id.PS_Literals, Id.PS_BadBackslash): ret.append(value) elif id_ == Id.PS_Octal3: i = int(value[1:], 8) ret.append(chr(i % 256)) elif id_ == Id.PS_LBrace: non_printing += 1 ret.append('\x01') elif id_ == Id.PS_RBrace: non_printing -= 1 if non_printing < 0: # e.g. \]\[ return PROMPT_ERROR ret.append('\x02') elif id_ == Id.PS_Subst: # \u \h \w etc. char = value[1:] if char == '$': # So the user can tell if they're root or not. r = '#' if self.cache.Get('euid') == 0 else '$' elif char == 'u': r = self.cache.Get('user') elif char == 'h': r = self.cache.Get('hostname').split('.')[0] elif char == 'H': r = self.cache.Get('hostname') elif char == 'w': val = self.mem.GetVar('PWD') if val.tag == value_e.Str: # Shorten to ~/mydir r = ui.PrettyDir(val.s, self.mem.GetVar('HOME')) else: r = '<Error: PWD is not a string> ' elif char == 'W': val = self.mem.GetVar('PWD') if val.tag == value_e.Str: r = os_path.basename(val.s) else: r = '<Error: PWD is not a string> ' elif char in _ONE_CHAR: r = _ONE_CHAR[char] else: r = r'<Error: \%s not implemented in $PS1> ' % char # See comment above on bash hack for $. ret.append(r.replace('$', '\\$')) else: raise AssertionError('Invalid token %r' % id_) # mismatched brackets, see https://github.com/oilshell/oil/pull/256 if non_printing != 0: return PROMPT_ERROR return ''.join(ret)
def _ReplaceBackslashCodes(self, tokens): ret = [] non_printing = 0 for id_, value in tokens: # BadBacklash means they should have escaped with \\, but we can't # make this an error. if id_ in (Id.PS_Literals, Id.PS_BadBackslash): ret.append(value) elif id_ == Id.PS_Octal3: i = int(value[1:], 8) ret.append(chr(i % 256)) elif id_ == Id.PS_LBrace: non_printing += 1 elif id_ == Id.PS_RBrace: non_printing -= 1 elif id_ == Id.PS_Subst: # \u \h \w etc. char = value[1:] if char == '$': # So the user can tell if they're root or not. r = '#' if self.cache.Get('euid') == 0 else '$' elif char == 'u': r = self.cache.Get('user') elif char == 'h': r = self.cache.Get('hostname').split('.')[0] elif char == 'H': r = self.cache.Get('hostname') elif char == 'w': # TODO: This should shorten to ~foo when applicable. val = self.mem.GetVar('PWD') if val.tag == value_e.Str: r = val.s else: r = '<Error: PWD is not a string>' elif char == 'W': val = self.mem.GetVar('PWD') if val.tag == value_e.Str: r = os_path.basename(val.s) else: r = '<Error: PWD is not a string>' elif char in _ONE_CHAR: r = _ONE_CHAR[char] else: r = '<\%s not implemented in $PS1> $' % char # See comment above on bash hack for $. ret.append(r.replace('$', '\\$')) else: raise AssertionError('Invalid token %r' % id_) return ''.join(ret)
def testBasename(self): self.assertEqual('bar', os_path.basename('foo/bar'))