def split_path(path): colon_pos = get_first_pos_of_char(':', path) slash_pos = get_last_pos_of_char('/', path) project, path, name = path[:colon_pos], path[colon_pos+1:slash_pos], path[slash_pos+1:] if path == '': path = '/' project = unescape_colon(project) path = unescape_colon(path) name = unescape_colon(name).replace('\\/', '/') return project, path, name
def get_matches(self, line, point, prefix, suffix): # This implementation is reliant on bash behavior that ':' is # treated as a word separator for determining prefix if get_last_pos_of_char(' ', line) != point - 1: prefix = split_unescaped(' ', line[:point])[-1] # Can immediately return if there are disallowed characters of # app names in the prefix if ':' in prefix: return [] self._populate_matches(prefix) return self.matches
def get_matches(self, line, point, prefix, suffix): # This implementation is reliant on bash behavior that ':' is # treated as a word separator for determining prefix if get_last_pos_of_char(' ', line) != point - 1: prefix = split_unescaped(' ', line[:point])[-1] self._populate_matches(prefix) if prefix.rfind(':') != -1: for i in range(len(self.matches)): self.matches[i] = self.matches[i][self.matches[i].rfind(':') + 1:] return self.matches
def split_path(path): colon_pos = get_first_pos_of_char(':', path) slash_pos = get_last_pos_of_char('/', path) project, path, name = path[:colon_pos], path[colon_pos + 1:slash_pos], path[slash_pos + 1:] if path == '': path = '/' project = unescape_colon(project) path = unescape_colon(path) name = unescape_colon(name).replace('\\/', '/') return project, path, name
def path_completer(text, expected=None, classes=None, perm_level=None, include_current_proj=False, typespec=None, visibility=None): ''' :param text: String to tab-complete to a path matching the syntax project-name:folder/entity_or_folder_name :type text: string :param expected: "folder", "entity", "project", or None (no restriction) as to the types of answers to look for :type expected: string :param classes: if expected="entity", the possible data object classes that are acceptable :type classes: list of strings :param perm_level: the minimum permissions level required, e.g. "VIEW" or "CONTRIBUTE" :type perm_level: string :param include_current_proj: Indicate whether the current project's name should be a potential result :type include_current_proj: boolean :param visibility: Visibility with which to restrict the completion (one of "either", "visible", or "hidden") (default behavior is dependent on *text*) Returns a list of matches to the text and restricted by the requested parameters. ''' colon_pos = get_last_pos_of_char(':', text) slash_pos = get_last_pos_of_char('/', text) delim_pos = max(colon_pos, slash_pos) # First get projects if necessary matches = [] if expected == 'project' and colon_pos > 0 and colon_pos == len(text) - 1: if dxpy.find_one_project(zero_ok=True, name=text[:colon_pos]) is not None: return [text + " "] if colon_pos < 0 and slash_pos < 0: # Might be tab-completing a project, but don't ever include # whatever's set as dxpy.WORKSPACE_ID unless expected == "project" # Also, don't bother if text=="" and expected is NOT "project" # Also, add space if expected == "project" if text != "" or expected == 'project': results = dxpy.find_projects(describe=True, level=perm_level) if not include_current_proj: results = [r for r in results if r['id'] != dxpy.WORKSPACE_ID] matches += [escape_colon(r['describe']['name'])+':' for r in results if r['describe']['name'].startswith(text)] if expected == 'project': return matches # Attempt to tab-complete to a folder or data object name if colon_pos < 0 and slash_pos >= 0: # Not tab-completing a project, and the project is unambiguous # (use dxpy.WORKSPACE_ID) if dxpy.WORKSPACE_ID is not None: # try-catch block in case dxpy.WORKSPACE_ID is garbage try: dxproj = dxpy.get_handler(dxpy.WORKSPACE_ID) folderpath, entity_name = clean_folder_path(text) matches += get_folder_matches(text, slash_pos, dxproj, folderpath) if expected != 'folder': if classes is not None: for classname in classes: matches += get_data_matches(text, slash_pos, dxproj, folderpath, classname=classname, typespec=typespec, visibility=visibility) else: matches += get_data_matches(text, slash_pos, dxproj, folderpath, typespec=typespec, visibility=visibility) except: pass else: # project is given by a path, but attempt to resolve to an # object or folder anyway try: proj_ids, folderpath, entity_name = resolve_path(text, multi_projects=True) except ResolutionError as details: sys.stderr.write("\n" + fill(unicode(details))) return matches for proj in proj_ids: # protects against dxpy.WORKSPACE_ID being garbage try: dxproj = dxpy.get_handler(proj) matches += get_folder_matches(text, delim_pos, dxproj, folderpath) if expected != 'folder': if classes is not None: for classname in classes: matches += get_data_matches(text, delim_pos, dxproj, folderpath, classname=classname, typespec=typespec, visibility=visibility) else: matches += get_data_matches(text, delim_pos, dxproj, folderpath, typespec=typespec, visibility=visibility) except: pass return matches
def path_completer(text, expected=None, classes=None, perm_level=None, include_current_proj=False, typespec=None, visibility=None): ''' :param text: String to tab-complete to a path matching the syntax project-name:folder/entity_or_folder_name :type text: string :param expected: "folder", "entity", "project", or None (no restriction) as to the types of answers to look for :type expected: string :param classes: if expected="entity", the possible data object classes that are acceptable :type classes: list of strings :param perm_level: the minimum permissions level required, e.g. "VIEW" or "CONTRIBUTE" :type perm_level: string :param include_current_proj: Indicate whether the current project's name should be a potential result :type include_current_proj: boolean :param visibility: Visibility with which to restrict the completion (one of "either", "visible", or "hidden") (default behavior is dependent on *text*) Returns a list of matches to the text and restricted by the requested parameters. ''' colon_pos = get_last_pos_of_char(':', text) slash_pos = get_last_pos_of_char('/', text) delim_pos = max(colon_pos, slash_pos) # First get projects if necessary matches = [] if expected == 'project' and colon_pos > 0 and colon_pos == len(text) - 1: if dxpy.find_one_project(zero_ok=True, name=text[:colon_pos]) is not None: return [text + " "] if colon_pos < 0 and slash_pos < 0: # Might be tab-completing a project, but don't ever include # whatever's set as dxpy.WORKSPACE_ID unless expected == "project" # Also, don't bother if text=="" and expected is NOT "project" # Also, add space if expected == "project" if text != "" or expected == 'project': results = dxpy.find_projects(describe=True, level=perm_level) if not include_current_proj: results = [r for r in results if r['id'] != dxpy.WORKSPACE_ID] matches += [ escape_colon(r['describe']['name']) + ':' for r in results if r['describe']['name'].startswith(text) ] if expected == 'project': return matches # Attempt to tab-complete to a folder or data object name if colon_pos < 0 and slash_pos >= 0: # Not tab-completing a project, and the project is unambiguous # (use dxpy.WORKSPACE_ID) if dxpy.WORKSPACE_ID is not None: # try-catch block in case dxpy.WORKSPACE_ID is garbage try: dxproj = dxpy.get_handler(dxpy.WORKSPACE_ID) folderpath, entity_name = clean_folder_path(text) matches += get_folder_matches(text, slash_pos, dxproj, folderpath) if expected != 'folder': if classes is not None: for classname in classes: matches += get_data_matches(text, slash_pos, dxproj, folderpath, classname=classname, typespec=typespec, visibility=visibility) else: matches += get_data_matches(text, slash_pos, dxproj, folderpath, typespec=typespec, visibility=visibility) except: pass else: # project is given by a path, but attempt to resolve to an # object or folder anyway try: proj_ids, folderpath, entity_name = resolve_path( text, multi_projects=True) except ResolutionError as details: sys.stderr.write("\n" + fill(unicode(details))) return matches for proj in proj_ids: # protects against dxpy.WORKSPACE_ID being garbage try: dxproj = dxpy.get_handler(proj) matches += get_folder_matches(text, delim_pos, dxproj, folderpath) if expected != 'folder': if classes is not None: for classname in classes: matches += get_data_matches(text, delim_pos, dxproj, folderpath, classname=classname, typespec=typespec, visibility=visibility) else: matches += get_data_matches(text, delim_pos, dxproj, folderpath, typespec=typespec, visibility=visibility) except: pass return matches