class OrgmCliController(OrgmBaseController): def __init__(self, data_file=None, is_unit_testing=False): self._orgm_api = Organizem(data_file, is_unit_testing) # Command line users use only this call, indirectly, by passing command lines # to orgm.py#__main__(). # CLI API def run_cmd(self, title, args): # Validate and load args action, args = self._format_and_validate(args) # For actions matching on an element value, figure out which one # NOTE: Just uses first one. DOES NOT validate only one passed in match_elem, match_val = self._get_match(action, args) # For actions modified by a group_by arg, figure out which one group_elem = self._get_group(action, args) # For actions modified by a group by arg, figure out sorting of groups sort_order = self._get_sort(action, args) # Now turn cmd line action and arguments into Organizem API call # Actions to create new Items if action == Action.ADD: self._orgm_api.add_item(Item(args[Elem.TITLE], args)) elif action == Action.ADD_EMPTY: self._orgm_api.add_empty() # Matching actions elif action == Action.REMOVE: self._orgm_api.remove_items(match_elem, match_val, args[ActionArg.REGEX]) elif action == Action.FIND: items = self._orgm_api.find_items(match_elem, match_val, args[ActionArg.REGEX]) for item in items: print str(item) # Grouping actions elif action == Action.SHOW_GROUPED: grouped_items = self._orgm_api.get_grouped_items(group_elem) group_keys = grouped_items.keys() group_keys.sort() # If sort_order is DESCENDING, not the default ASCENDING (also the default for List#sort() ) # then reverse the group_keys before building grouped display if sort_order == ActionArg.DESCENDING: group_keys.reverse() for group_key in group_keys: label = self._orgm_api.format_group_label(group_elem, group_key) print label for item in grouped_items[group_key]: print str(item) elif action == Action.SHOW_ELEMENTS: elems = self._orgm_api.get_elements(group_elem) elems.sort() # If sort_order is DESCENDING, not the default ASCENDING, reverse group_keys if sort_order == ActionArg.DESCENDING: elems.reverse() for elem in elems: print elem elif action == Action.REBUILD_GROUPED: self._orgm_api.regroup_data_file(group_elem, sort_order) # Utility actions, backup and configuration elif action == Action.BACKUP: self._orgm_api.backup(args[ActionArg.FILENAME]) elif action == Action.SETCONF_DATA_FILE: self._orgm_api.setconf(Conf.DATA_FILE, args[ActionArg.FILENAME]) elif action == Action.SETCONF_BAK_FILE: self._orgm_api.setconf(Conf.BAK_FILE, args[ActionArg.FILENAME]) # Helpers def _format_and_validate(self, args): # Unpack args, trim and clean, repack # Get action first for clarity of code here # TODO - expunge the magic string! action = OrgmCliController._trim_quotes(args['action']) # Process all the data elements, values for fields in Elem, dynamically for elem in Elem.get_data_elems(): elem_type = Elem.get_elem_type(elem) if elem_type == Elem.LIST_TYPE: # Must split() the two list element types, so the string becomes Py list # Trim single and double quotes from each element # NOTE: _trim_quotes() keeps args not passed as None and empty strings as empty, # which is *crucial* to logic of _run_cli_get_group_elem() below args[elem] = [OrgmCliController._trim_quotes(t).strip() for t in args[elem].split(',')] elif elem_type == Elem.TEXT_TYPE: args[elem] = OrgmCliController._trim_quotes(args[elem]) # Process filename args[ActionArg.FILENAME] = OrgmCliController._trim_quotes(args[ActionArg.FILENAME]) # Validation if action == Action.ADD and not args[Elem.TITLE]: raise OrganizemIllegalUsageException("'--add' action must include '--title' element and a value for title.") elif (action == Action.SETCONF_DATA_FILE or action == Action.SETCONF_BAK_FILE) \ and not args[ActionArg.FILENAME]: raise OrganizemIllegalUsageException("'--setconf_*' actions must include '--filename' element and a value for filename.") return (action, args) def _get_match(self, action, args): match_elem = None match_val = None if action == Action.FIND or action == Action.REMOVE: for elemkey in Elem.get_data_elems(): if elemkey in args: argval = args[elemkey] if len(argval): match_elem = elemkey match_val = argval break # Validate that we have match_elem and match_val if action requires them if match_elem is None or match_val is None: raise OrganizemIllegalUsageException("'--find and --remove must include an element (e.g. --title) and a value for that element.") return (match_elem, match_val) def _get_group(self, action, args): group_elem = None if Action.is_group_action(action): for action_arg_key in ActionArg.get_group_by_action_args(): if action_arg_key in args and args[action_arg_key]: group_elem = ActionArg.elem_from_action_arg(action_arg_key) # Validate that we have group_elem if action requires it if group_elem is None: raise OrganizemIllegalUsageException("'--show_elements, --show_grouped and --rebuild_grouped must include a grouping element (e.g. --by_title).") return group_elem def _get_sort(self, action, args): # Sort defaults to asc but desc overrides if it is set if args[ActionArg.DESCENDING]: return ActionArg.DESCENDING else: return ActionArg.ASCENDING @staticmethod def _trim_quotes(arg): if arg is None or len(arg) < 2: return arg # Count leading and trailing quotes and slice them all away. Hacky. j = 0 k = len(arg) while j < k and (arg[j] == '"' or arg[j] == "'"): j += 1 while k > 0 and (arg[k-1] == '"' or arg[k-1] == "'"): k -= 1 return arg[j:k]
def __init__(self, data_file=None, is_unit_testing=False): self._orgm_api = Organizem(data_file, is_unit_testing)