def jql_search(self, *args): """Submit a JQL search query to the server""" jql = None if args and args != ('', ): jql = ' '.join(args) SAVED_QUERIES.add(jql=jql) else: entry_type = ih.make_selections( ['Select a saved query', 'Type a JQL query'], prompt='Choose one', unbuffered=True) if 'Select a saved query' in entry_type: selected_query = ih.make_selections( SAVED_QUERIES.find(get_fields='name,jql'), prompt='Choose one', item_format='({name}) {jql}', unbuffered=True) if selected_query: jql = selected_query[0]['jql'] name = selected_query[0]['name'] _id = selected_query[0]['_id'] update_kwargs = {'chosen_on': dh.utc_now_float_string()} if name is None: name = ih.user_input('Enter a name for this selection') if name: update_kwargs.update(name=name) SAVED_QUERIES.update(_id, **update_kwargs) else: jql = ih.user_input('Enter your JQL query') if not jql: return SAVED_QUERIES.add(jql=jql) else: jql = ih.user_input('Enter your JQL query') if not jql: return SAVED_QUERIES.add(jql=jql) self._info['last_jql'] = jql if not 'order by' in jql.lower() and self._info['orderby_fields']: jql += ' ORDER BY ' + ', '.join(self._info['orderby_fields']) results = jql_search(jql, session=self._session, count=self._info['count_only'], fields=self._info['return_fields'], return_raw=self._info['raw_json']) pprint(results) print('\njql:', jql)
def prompt_for_new_branch_name(name=''): """Prompt user for the name of a new allowed branch name - name: if provided, verify that it is an acceptable new branch name and prompt if it is invalid Branch name is not allowed to have the name of any QA_BRANCHES as a prefix """ QA_BRANCHES = _get_repo_settings('QA_BRANCHES') NON_SELECTABLE_BRANCHES = _get_repo_settings('NON_SELECTABLE_BRANCHES') RX_QA_PREFIX = _get_repo_settings('RX_QA_PREFIX') remote_branches = get_remote_branches() local_branches = get_local_branches() while True: if not name: name = ih.user_input('Enter name of new branch to create') if not name: break if name in remote_branches: print('{} already exists on remote server'.format(repr(name))) name = '' elif name in local_branches: print('{} already exists locally'.format(repr(name))) name = '' elif name in NON_SELECTABLE_BRANCHES: print('{} is not allowed'.format(repr(name))) name = '' elif RX_QA_PREFIX.match(name): print('{} not allowed to use any of these as prefix: {}'.format( repr(name), repr(QA_BRANCHES))) name = '' else: break return name.replace(' ', '_')
def _settings_for_docker_ok(exception=False): """Return True if settings.ini has the required values set - exception: if True, raise an exception if settings are not ok (after optional sync attempt) If any are missing, prompt to sync settings with vimdiff """ global SETTINGS settings_keys_for_docker = [ 'container_name', 'image_version', 'port', 'rm', 'aof', 'redis_data_dir' ] missing_settings = set(settings_keys_for_docker) - set(SETTINGS.keys()) if missing_settings != set(): message = 'Update your settings.ini to have: {}'.format( sorted(list(missing_settings))) print(message) resp = ih.user_input('Sync settings.ini with vimdiff? (y/n)') if resp.lower().startswith('y'): sh.sync_settings_file(__name__) SETTINGS = sh.get_all_settings(__name__).get(sh.APP_ENV, {}) missing_settings = set(settings_keys_for_docker) - set( SETTINGS.keys()) if missing_settings == set(): return True elif exception: message = 'Update your settings.ini to have: {}'.format( sorted(list(missing_settings))) raise Exception(message) else: if exception: raise Exception(message) else: return True
def tag_release(auto=False): """Select a recent remote commit on TAG_BRANCH to tag - auto: if True, create tag on last commit and generate message Return True if tag was successful """ TAG_BRANCH = _get_repo_settings('TAG_BRANCH') success = update_branch(TAG_BRANCH) if not success: return tag = dh.local_now_string('%Y-%m%d-%H%M%S') if not auto: print('\nRecent commits') commit_id = select_commit_to_tag() if not commit_id: return summary = ih.user_input('One-line summary for tag') if not summary: summary = tag else: commit_id = get_last_commit_id() summary = tag commits = get_commits_since_last_tag(until=commit_id) if not commits: return notes_file = '/tmp/{}.txt'.format(tag) with open(notes_file, 'w') as fp: fp.write('{}\n\n'.format(summary)) fp.write('\n'.join(commits) + '\n') cmd = 'git tag -a {} {} -F {}'.format(tag, commit_id, repr(notes_file)) if not auto: bh.run('vim {}'.format(notes_file)) print('Tag command would be -> {}'.format(cmd)) resp = ih.user_input('Continue? (y/n)') if not resp.lower().startswith('y'): return ret_code = bh.run(cmd, show=True) if ret_code != 0: return return bh.run('git push --tags', show=True)
def merge_qa_to_source(qa='', auto=False): """Merge the QA-verified code to SOURCE_BRANCH and delete merged branch(es) - qa: name of qa branch to merge to source - auto: if True, don't ask if everything looks ok Return qa name if merge(s) and delete(s) were successful """ QA_BRANCHES = _get_repo_settings('QA_BRANCHES') SOURCE_BRANCH = _get_repo_settings('SOURCE_BRANCH') LOCAL_BRANCH = _get_repo_settings('LOCAL_BRANCH') if qa not in QA_BRANCHES: show_qa(all_qa=True) print() qa = select_qa(full_only=True) if not qa: return env_branches = get_qa_env_branches(qa, display=True) if not env_branches: print('Nothing on {} to merge...'.format(qa)) return print() if not auto: resp = ih.user_input('Does this look correct? (y/n)') if not resp.lower().startswith('y'): print('\nNot going to do anything') return most_recent = env_branches[0] delete_after_merge = most_recent['contains'][:] delete_after_merge.extend([b['branch'] for b in env_branches]) success = merge_branches_locally(SOURCE_BRANCH, source=qa) if not success: print('\nThere was a failure, not going to delete these: {}'.format( repr(delete_after_merge))) return cmd = 'git push -uf origin {}:{}'.format(LOCAL_BRANCH, SOURCE_BRANCH) ret_code = bh.run(cmd, show=True) if ret_code != 0: print('\nThere was a failure, not going to delete these: {}'.format( repr(delete_after_merge))) return delete_after_merge.extend(get_merged_remote_branches()) success = delete_remote_branches(*delete_after_merge) if success: return qa
def force_push_local(qa='', *branches, to_source=False): """Do a git push -f of LOCAL_BRANCH to specified qa branch or SOURCE_BRANCH - qa: name of qa branch to push to - branches: list of remote branch names that were merged into LOCAL_BRANCH - to_source: if True, force push to SOURCE_BRANCH (only allowed if func that called it is in FUNCS_ALLOWED_TO_FORCE_PUSH_TO_SOURCE) Return True if push was successful Only allowed to be called from funcs in FUNCS_ALLOWED_TO_FORCE_PUSH (because these are functions that just finished creating a clean LOCAL_BRANCH from the remote SOURCE_BRANCH, with other remote branches combined in (via rebase or merge) """ caller = inspect.stack()[1][3] assert caller in FUNCS_ALLOWED_TO_FORCE_PUSH, ( 'Only allowed to invoke force_push_local func from {}... not {}'. format(repr(FUNCS_ALLOWED_TO_FORCE_PUSH), repr(caller))) SOURCE_BRANCH = _get_repo_settings('SOURCE_BRANCH') if to_source: assert caller in FUNCS_ALLOWED_TO_FORCE_PUSH_TO_SOURCE, ( 'Only allowed to force push to {} when invoked from {}... not {}'. format(SOURCE_BRANCH, repr(FUNCS_ALLOWED_TO_FORCE_PUSH_TO_SOURCE), repr(caller))) QA_BRANCHES = _get_repo_settings('QA_BRANCHES') LOCAL_BRANCH = _get_repo_settings('LOCAL_BRANCH') current_branch = get_branch_name() if current_branch != LOCAL_BRANCH: print('Will not do a force push with branch {}, only {}'.format( repr(current_branch), repr(LOCAL_BRANCH))) return if qa not in QA_BRANCHES: print('Branch {} is not one of {}'.format(repr(qa), repr(QA_BRANCHES))) return env_branches = get_qa_env_branches(qa, display=True) if env_branches: print() resp = ih.user_input('Something is already there, are you sure? (y/n)') if not resp.lower().startswith('y'): return ret_codes = [] combined_name = qa + '--with--' + '--'.join(branches) cmd_part = 'git push -uf origin {}:'.format(LOCAL_BRANCH) ret_codes.append(bh.run(cmd_part + qa, show=True)) ret_codes.append(bh.run(cmd_part + combined_name, show=True)) if all([x == 0 for x in ret_codes]): return True
def main(query): """Pass a search query to duckduckgo api""" query = query or ih.user_input('duckduckgo query') if not query: return selected = ih.make_selections( ph.duckduckgo_api(query), wrap=True, item_format='{text}', ) if selected: ph.logger.info('Selected {}'.format(' '.join( [x['link'] for x in selected]))) with open(ph.LOGFILE, 'a') as fp: pprint(selected, fp)
def main(query): """Pass a search query to youtube""" query = query or ih.user_input('youtube query') if not query: return selected = ih.make_selections( ph.youtube_serp(query), wrap=False, item_format='{duration} .::. {title} .::. {user} .::. {uploaded}', ) if selected: ph.logger.info('Selected {}'.format(' '.join( [x['link'] for x in selected]))) with open(ph.LOGFILE, 'a') as fp: pprint(selected, fp)
def edit_comment_timestamp_select(): """Use select_comments to select a mark/comment for the current file Prompt for a new timestamp (usually +/-1 from current timestamp) """ selected = select_comments(prompt='Select mark/comment to edit timestamp') if selected: prompt = 'Enter new timestamp (old was {})'.format(selected[0].get('timestamp', '')) timestamp = ih.user_input(prompt) if timestamp: try: timestamp = int(timestamp) except ValueError: print('{} is not an integer'.format(timestamp)) else: _id = selected[0]['_id'] COMMENTS.update(_id, timestamp=timestamp) else: print()
def clear_qa(*qas, all_qa=False, force=False): """Clear whatever is on selected QA branches - qas: names of qa branches that may have things pushed to them - if no qas passed in, you will be prompted to select multiple - all_qa: if True and no qa passed in, clear all qa branches - force: if True, delete the specified qa branches without prompting for confirmation Return True if deleting branch(es) was successful """ QA_BRANCHES = _get_repo_settings('QA_BRANCHES') if not all_qa: valid = set(QA_BRANCHES).intersection(set(qas)) if valid == set(): qas = select_qa_with_times(multi=True) if not qas: return qas = [b['branch'] for b in qas] else: qas = list(valid) else: qas = QA_BRANCHES parts = [] for qa in qas: parts.append('^{}$|^{}--'.format(qa, qa)) branches = get_remote_branches(grep='|'.join(parts), all_branches=True) if not branches: return if not force: print('\n', branches, '\n') resp = ih.user_input('Does this look correct? (y/n)') if not resp.lower().startswith('y'): print('\nNot going to do anything') return return delete_remote_branches(*branches)
def main(query, **kwargs): """Pass a search query to google""" query = query or ih.user_input('google query') if not query: return session = ph.new_requests_session() selected = ih.make_selections( ph.google_serp(query, session=session, **kwargs), wrap=False, item_format='{title} .::. {link}', ) for item in selected: remote_basename = os.path.basename(item['link']) ext = remote_basename.split('.')[-1] localfile = '' if ext != remote_basename: localfile = lazy_filename(item['title']) + '.' + ext else: localfile = lazy_filename( item['link'].split('://')[-1].strip('/').replace('/', '--') ) + '.html' ph.download_file(item['link'], localfile, session=session)
def delete(basename=None): """Delete audio file and remove related data from COMMENTS In FILES, the item will be updated to 'audio=False' in case there is a related video file of the same name (which this will not delete) """ if basename is None: basename = get_current_basename() if not basename: return paths = get_paths_from_basenames(basename) if paths: files = moc.find_audio(*paths) if files: file_id = FILES[basename].get('_id') comment_ids = [ x['_id'] for x in COMMENTS.find('basename:{}'.format(basename), get_fields='_id') ] print('For {}, found {} file(s) and {} comment(s)'.format( repr(basename), len(files), len(comment_ids) )) yn = ih.user_input('\nAre you sure you want to delete? (y/n)') if yn.lower().startswith('y'): for f in files: try: remove(f.strip('\'"')) except Exception as e: logger.error('Could not delete {}... {}'.format(repr(f), repr(e))) else: logger.info('Deleted {}'.format(repr(f))) if file_id: FILES.update(file_id, audio=False) if comment_ids: COMMENTS.delete_many(*comment_ids)
def choose_old_selection_or_make_new_selection(field_type): """Choose from old groups of selections for field_type or make a new selection - field_type: one of the keys in ALLOWED_FIELD_TYPE_INFO dict """ assert field_type in ALLOWED_FIELD_TYPE_INFO, ( 'field_type {} is not one of {}'.format( repr(field_type), repr(sorted(ALLOWED_FIELD_TYPE_INFO.keys())))) selections = None choice = ih.make_selections( ['Choose from old selections', 'Make a new selection'], prompt='Choose one for {} fields in search results'.format(field_type), unbuffered=True) if 'Choose from old selections' in choice: found = SELECTED_FIELDS.find('type:{}'.format(field_type), get_fields='selected,name') selected = ih.make_selections(found, item_format='({name}): {selected}', prompt='Choose one', wrap=False, unbuffered=True) if selected: selections = selected[0]['selected'] name = selected[0]['name'] _id = selected[0]['_id'] update_kwargs = {'chosen_on': dh.utc_now_float_string()} if name is None: name = ih.user_input('Enter a name for this selection') if name: update_kwargs.update(name=name) SELECTED_FIELDS.update(_id, **update_kwargs) else: selections = get_last_or_make_selection(field_type, force_new=True) return selections
CharacterController.move_right(self._character_name, ih.from_string(n)) def up(self, n): """Move up n units""" CharacterController.move_up(self._character_name, ih.from_string(n)) def down(self, n): """Move down n units""" CharacterController.move_down(self._character_name, ih.from_string(n)) if GameLoop: display_name = ih.user_input('\nWhat is the character name') character_name = display_name.replace(' ', '_').lower() # Keyboard shortcuts that work when the gameloop is running chfunc = { 'h': (partial(CharacterController.move_left, character_name, 2), 'move left 2 units'), 'l': (partial(CharacterController.move_right, character_name, 2), 'move right 2 units'), 'k': (partial(CharacterController.move_up, character_name, 2), 'move up 2 units'), 'j': (partial(CharacterController.move_down, character_name, 2), 'move down 2 units'), 'H': (partial(CharacterController.move_left, character_name, 5), 'move left 5 units'), 'L': (partial(CharacterController.move_right, character_name,
def main(url_or_file): """Create a soup object from a url or file and explore with ipython""" url_or_file = url_or_file or ih.user_input('url') ph.soup_explore(url_or_file)
def main(**kwargs): """For matching instances, issue a command on the instance via SSH""" ec2 = ah.EC2(kwargs['profile']) find = kwargs['find'] command = kwargs['command'] use_private_ip = kwargs['private_ip'] matched_instances = [] local_pems = ah.find_all_pems() if not command: if kwargs['non_interactive']: print('No command specified') return else: command = ih.user_input('Enter remote command') if not command: print('No command specified') resp = ih.user_input( 'Do you want interactive SSH session(s)? (y/n)') if resp.lower().startswith('y') is False: return if ah.AWS_EC2 is not None: ec2.update_collection() running_instances = ah.AWS_EC2.find( 'status:running', get_fields='name, status, pem, id, ip, ip_private, sshuser', include_meta=False, limit=ah.AWS_EC2.size) else: instances = ec2.get_all_instances_filtered_data() running_instances = [ ih.rename_keys( ih.filter_keys( instance, 'Tags__Value, State__Name, KeyName, InstanceId, PublicIpAddress, PrivateIpAddress' ), **INSTANCE_KEY_NAME_MAPPING) for instance in ih.find_items(instances, 'State__Name:running') ] for term in ih.string_to_list(find): for item in ih.find_items(running_instances, 'name:${}'.format(term)): if item not in matched_instances: matched_instances.append(item) for item in ih.find_items(running_instances, 'id:${}'.format(term)): if item not in matched_instances: matched_instances.append(item) for item in ih.find_items(running_instances, 'ip:${}'.format(term)): if item not in matched_instances: matched_instances.append(item) for item in ih.find_items(running_instances, 'ip_private:${}'.format(term)): if item not in matched_instances: matched_instances.append(item) if not find: matched_instances = running_instances ih.sort_by_keys(matched_instances, 'name, ip') # # Uncomment and modify if you ever need to use a .pem file that # # is different than what AWS thinks it should be # for i, instance in enumerate(matched_instances): # if instance.get('pem', '') == 'old-pem': # matched_instances[i]['pem'] = 'new-pem' if kwargs['non_interactive'] is False: matched_instances = ih.make_selections( matched_instances, prompt='Select instances', item_format='{id} ({name}) at {ip} ({ip_private}) using {pem}', wrap=False) for instance in matched_instances: pem_name = instance['pem'] ip = instance['ip'] if not use_private_ip else instance['ip_private'] if not ip: continue pem_file = local_pems.get(pem_name) if not pem_file: print('Could not find {} pem in ~/.ssh for {}.'.format( repr(pem_name), repr(instance))) continue sshuser = instance.get('sshuser') if not sshuser: sshuser = ah.determine_ssh_user(ip, pem_file) if not sshuser and kwargs['verbose']: print('--------------------------------------------------') print('\nCould not determine SSH user for {}'.format( repr(instance))) continue else: if ah.AWS_EC2: hash_id = ah.AWS_EC2.get_hash_id_for_unique_value( instance['id']) ah.AWS_EC2.update(hash_id, sshuser=sshuser) if kwargs['verbose']: print('--------------------------------------------------') print('\nInstance {} ({}) at {} with pem {} and user {}\n'.format( instance['id'], instance['name'], ip, pem_name, sshuser)) ah.do_ssh(ip, pem_file, sshuser, command, kwargs['timeout'], kwargs['verbose'])
def __call__(self): print(self._startup_message) self._char_hist = [] self._cmd_hist = [] while True: click.secho(self._prompt, nl=False, fg='cyan', bold=True) try: ch = click.getchar() self._char_hist.append(ch) except (EOFError, KeyboardInterrupt): break else: if ch in ['\x03', '\x04']: break if ch == '?': try: if self._char_hist[-2] == '?': self.docstrings() self.shortcuts() else: print('?\n', self._class_doc()) print(self._startup_message) except IndexError: print('?\n', self._class_doc()) print(self._startup_message) elif ch == '-': try: if self._pre_input_hook: pre_input_data = self._pre_input_hook() else: pre_input_data = {} user_input = ih.user_input_fancy('', '- ') if self._post_input_hook: post_input_data = self._post_input_hook() else: post_input_data = {} if self._input_hook: bh.call_func( self._input_hook, **user_input, **pre_input_data, **post_input_data, logger=logger ) else: self._collection.add( cmd='-', user_input=user_input['text'], status='ok', **pre_input_data, **post_input_data ) except click.exceptions.Abort: print() continue elif ch == ':': try: user_input = click.prompt(text='', prompt_suffix=':', default='', show_default=False) except click.exceptions.Abort: print() continue else: if not user_input: print() continue cmd = user_input.split()[0] args = user_input.split()[1:] self._cmd_hist.append(cmd) if cmd == 'pdb': import pdb; pdb.set_trace() continue if cmd == 'ipython': ih.start_ipython(warn=True, self=self) continue try: cmd_func = getattr(self, cmd) except AttributeError: self._collection.add(cmd=cmd, status='error', error_type='invalid command') logger.error('invalid command: {}'.format(cmd)) result = self._wishlist.find( 'cmd:{}'.format(cmd), admin_fmt=True, item_format='[NOT FULFILLED YET] {message} ({_ts})' ) if result: print(result[0]) else: message = ih.user_input('what do you wish this command did') if message: self._wishlist.add(cmd=cmd, message=message) continue info = bh.call_func(cmd_func, *args, logger=logger) info['cmd'] = cmd if cmd in self._DONT_LOG_CMDS: info = {} if info: self._collection.add(**info) elif ch in self._chfunc_dict: print(ch) bh.call_func(self._chfunc_dict[ch][0], logger=logger) if ch in self._break_chars: break elif ch in self._break_chars: print(ch) break else: try: print(repr(ch), ord(ch)) except TypeError: # ord() expected a character, but string of length 2 found # - happens if you press 'Esc' before another key print(repr(ch)) result = self._wishlist.find( 'ch:{}'.format(ch), admin_fmt=True, item_format='[NOT FULFILLED YET] {message} ({_ts})' ) if result: print(result[0]) else: try: if ch == self._char_hist[-2]: message = ih.user_input('what do you wish this key press did') if message: self._wishlist.add(ch=ch, message=message) except IndexError: pass