PKM J%[azureshell/cache.py# -*- coding: utf-8 -*- class AzureShellCache: __inst = None __cache = {} @staticmethod def Instance(): if AzureShellCache.__inst == None: AzureShellCache() return AzureShellCache.__inst def __init__(self): if AzureShellCache.__inst != None: raise Exception("This must not be called!!") AzureShellCache.__inst = self def set(self, k, v): self.__cache[k] = v def get(self, k): return self.__cache.get(k) PKo'J 1: self._reset() elif current_length < self._last_position: # Hit backspace, and handling backspace return self._handle_backspace() elif not line: return [] #elif current_length != self._last_position + 1: # return self._complete_from_full_parse() # Only update the _last_position after the cases above were verified self._last_position = len(line) # Autocomplete with 'az' if line is a single space or 'a' # (assuming that user hits a space on a new line or typed in 'a') stripped_line = line.strip() if line and ( not stripped_line or stripped_line == 'a' ): return ['az'] # Skip if it's only space ' ' words = line.split() if (len(words) < 1): return [] # Now you have at least single word in the line like # azure> az # azure> az vm # azure> az vm list .. last_word = words[-1] logger.debug("_autocomplete last_word: {}".format(last_word)) if last_word in self._current.get('argument_tree', {}): # The last thing we completed was an argument, record this as self.last_arg self._last_option = last_word if line[-1] == ' ': # this is the case like: # 'az vm ' or 'az vm --debug ' # 1. 'az vm ' # Proceed next command completions if the command has childres # 2. 'az vm --debug ' ( current command is 'az vm' ) # Process the current command completion if not last_word.startswith('-'): next_command = self._current['command_tree'].get(last_word) if next_command is not None: self._current = next_command self._current_name = last_word self.cmd_path.append(self._current_name) return self._current['commands'][:] elif last_word.startswith('-'): all_args = self._current['arguments'] # Select args with Forward matching return [arg for arg in sorted(all_args) if arg.startswith(last_word)] logger.debug("_autocomplete dump: {}".format([cmd for cmd in sorted(self._current['commands']) if cmd.startswith(last_word)])) # Select commands with Forward matching return [cmd for cmd in sorted(self._current['commands']) if cmd.startswith(last_word)] def _reset(self): self._current_name = self._root_name self._current = self._index[self._root_name] self._last_position = 0 self._last_option = '' self.cmd_path = [self._current_name] def _handle_backspace(self): # reseting and starting from the beginning self._reset() line = self._current_line for i in range(1, len(self._current_line)): self._autocomplete(line[:i]) return self._autocomplete(line) PK'JIqazureshell/index.py# -*- coding: utf-8 -*- import os import json import logging from . import utils from .compat import urllib2 logger = logging.getLogger('azureshell.index') _AZURE_SHELL_REMOTE_URL_BASE = "https://azureshellrepo.blob.core.windows.net/index" _AZURE_SHELL_AVAILABLE_INDEX_FILE = "index.available" _AZURE_SHELL_LOCAL_INDEX_VERSION_FILE = "index.local" class AzureShellIndexException(Exception): pass class AzureShellIndex(object): def __init__(self, index_base_dir): self._index_base_dir = index_base_dir self._version_file = "{}/{}".format(index_base_dir, _AZURE_SHELL_LOCAL_INDEX_VERSION_FILE) def get_index_file(self, index_version): return "{}/cli-index.{}.json".format(self._index_base_dir, index_version) def get_local_version(self): if not os.path.exists(self._version_file): return None f = open(self._version_file) v = f.readline().strip() f.close return v def set_local_version(self,index_version): f = open(self._version_file,"w") f.writelines(str(index_version)) f.close def download_index_from_repository(self, index_version ): # Check available list and get the best version version_to_download = AzureShellIndex.get_best_index_version_in_repository(index_version) local_index_version = self.get_local_version() # Download index if needed if not local_index_version or version_to_download > local_index_version: if not os.path.isdir(self._index_base_dir): os.makedirs(self._index_base_dir) remote_url = "{}/cli-index.{}.json".format( _AZURE_SHELL_REMOTE_URL_BASE,version_to_download) logger.debug("Downloading...:{}".format(remote_url)) f = urllib2.urlopen(remote_url) data = f.read() local_index_file = "{}/cli-index.{}.json".format(self._index_base_dir, version_to_download) with open(local_index_file, "wb") as code: code.write(data) ## Update local index version self.set_local_version(version_to_download) return version_to_download def load(self, index_version): index_file = "{}/cli-index.{}.json".format(self._index_base_dir, index_version) return AzureShellIndex.load_index(index_file) ### TODO: error handling @staticmethod def get_best_index_version_in_repository( index_version ): # Check available list and get the best version remote_url = "{}/{}".format( _AZURE_SHELL_REMOTE_URL_BASE, _AZURE_SHELL_AVAILABLE_INDEX_FILE) logger.debug("Reading...:{}".format(remote_url)) f = urllib2.urlopen(remote_url) data = f.read().decode('utf-8') versions=data.splitlines() versions.sort(reverse=True) ## check if versions contains myversion my_nearest_version = index_version if not index_version in versions: ## get my nearest available version if not versions contains index_version for i in versions: if index_version > i: my_nearest_version = i break return my_nearest_version @staticmethod def load_index(index_file): if not os.path.exists(index_file): estr="index file does not exist:{}".format(index_file) logger.error(estr) raise AzureShellIndexException(estr) data = {} try: with open(index_file, 'r') as f: data = json.load(f) except Exception as e: logger.error(str(e)) raise AzureShellIndexException(str(e)) return data def _parse_command(name, command_obj,completions): if not command_obj: return if 'arguments' in command_obj: args = command_obj['arguments'] for arg in args: options = arg.split() completions['args'].update(options) if 'commands' in command_obj and 'command_tree' in command_obj: subcommand_names = command_obj['commands'] completions['commands'].extend(subcommand_names) cmd_tree = command_obj['command_tree'] for subcommand_name in cmd_tree.keys(): subcommand_obj = cmd_tree[subcommand_name] _parse_command(subcommand_name, subcommand_obj,completions) def get_completions_commands_and_arguments( index_data = {} ): completions = { 'commands': [], 'args': set() } index_root = index_data['az'] completions['commands'] = index_root['commands'] for command_name in completions['commands']: command_obj = index_root['command_tree'].get(command_name) _parse_command(command_name, command_obj, completions) return completions PKM Jt_kkazureshell/lexer.py# -*- coding: utf-8 -*- from pygments.lexer import words from pygments.lexer import RegexLexer from pygments.token import Text, Keyword, Literal, Name, Operator from .index import AzureShellIndex, get_completions_commands_and_arguments from .cache import AzureShellCache class AzureShellLexer(RegexLexer): index_data = {} index_data = AzureShellIndex.load_index( AzureShellCache.Instance().get('index_file')) completions = get_completions_commands_and_arguments(index_data) tokens = { 'root': [ (words( tuple(['az']), prefix=r'\b', suffix=r'\b'), Literal.String), (words( tuple(completions['commands']), prefix=r'\b', suffix=r'\b'), Name.Class), (words( tuple(list(completions['args'])), prefix=r'', suffix=r'\b'), Keyword.Declaration), # Everything else (r'.*\n', Text), ] } PK Jg  azureshell/compat.py# -*- coding: utf-8 -*- import sys if sys.version_info[0] == 3: ## Python3 text_type = str import urllib.request as urllib2 import configparser else: ## Python2 text_type = unicode import urllib2 import ConfigParser as configparser PKM J%˲ azureshell/utils.py# -*- coding: utf-8 -*- import os import sys import re import subprocess from . import compat from .cache import AzureShellCache AZURE_SHELL_MINIMUM_AZURE_CLI_VERSION = '2.0.0' def AS_ERR(s): sys.stderr.write("{}\n".format(s)) def find_executable_path(executable): path = os.environ['PATH'] pathlist = path.split(os.pathsep) if os.path.isfile(executable): return executable else: for path in pathlist: f = os.path.join(path, executable) if os.path.isfile(f): return f return '' def get_cli_version(): v = AzureShellCache.Instance().get('azure_cli_version') if v: return v cmd_string = 'az --version' proc = subprocess.Popen(cmd_string,shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while True: line = proc.stdout.readline() l = line.strip().decode('utf-8') if l.startswith('azure-cli'): r = re.compile("([a-z-]*) \((.*)\)") o = r.findall(l) if len(o) == 1 and len(o[0]) ==2: v = o[0][1] AzureShellCache.Instance().set('azure_cli_version',v) break if not line and proc.poll() is not None: break return v def get_azurecli_modules_path(): ## Getting a path for python executable taht AzureCLI leverage executable = find_executable_path('az') python_path = None f = open(executable) l = f.readline().strip() while l: if not l.startswith('#') and l.find('python'): cols = l.split() if len(cols) > 1: python_path = cols[0] break l = f.readline().strip() f.close if not python_path: return None ## Getting python module paths that Azure CLI configures azurecli_modules_path =None cmd_string="{} < group1 -name -summary -subgroups = [] -commands =[] group_name2 => group2 ... commands_map cmd1 => cmd_object1 -summary -arguments : [] -argument_tree : {} arg1 => arg_object1 {} -required -options -help arg2 => arg_object2 arg3 => arg_object3 -example -command -group cmd2 => cmd_object2 ... """ def new_parsing_group(): return { 'name': '', 'commands': [], 'subgroups': [], 'summary': '', } def new_parsing_command(): return { 'summary': '', 'arguments': [], 'argument_tree': {}, 'example': '', 'command': '', 'group': '' } def new_parsing_argument(): return { 'required': False, 'options': '', 'help': '' } def dump_cmd_object(c): logger.debug("cmd dump: command:{} summary:{} arguments:{} example:{} group:{}".format( c['command'], c['summary'], "|".join(c['arguments']), c['example'], c['group'])) def dump_group_object(g): logger.debug("group dump:{} subgroup:{} summary:{} cmdlist={}".format( g['name'], "|".join(g['subgroups']), g['summary'], "|".join(g['commands']))) def convert_help_column(c): c = c.replace(_AZURE_SHELL_INDEX_GEN_USER_HOME, '') c = c.replace(_AZURE_SHELL_INDEX_GEN_USER, '') return c IN_BLOCK_TYPE_NONE = 0 IN_BLOCK_TYPE_COMMAND = 1 IN_BLOCK_TYPE_ARGUMENTS = 2 IN_BLOCK_TYPE_EXAMPLES = 3 def capture_cmd(cmd): logger.debug("Capturing command: {}".format(cmd)) cmd_string = 'az {} -h'.format(cmd) proc = subprocess.Popen(cmd_string, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) cmd_object= new_parsing_command() in_block_type = IN_BLOCK_TYPE_NONE cur_argument = '' while True: line = proc.stdout.readline() l = line.strip() if l =='Command': in_block_type = IN_BLOCK_TYPE_COMMAND elif l.find("Arguments") >= 0: in_block_type = IN_BLOCK_TYPE_ARGUMENTS elif l.find("Examples") >= 0: in_block_type = IN_BLOCK_TYPE_EXAMPLES elif l: if in_block_type == IN_BLOCK_TYPE_COMMAND: colon_pos = l.find(':') if colon_pos > 0: l = l[colon_pos+1:].lstrip() cmd_object['summary'] = cmd_object['summary'] + l elif in_block_type ==IN_BLOCK_TYPE_ARGUMENTS: ### options if l[0:2] == '--': arg_object = new_parsing_argument() colon_pos = l.find(':') options_column = l[0:colon_pos].rstrip() help_column = l[colon_pos+1:].strip() required_pos = options_column.find('[Required]') options = options_column is_required=False if required_pos > 0: arg_object['required'] = True options = options_column[0:required_pos].rstrip() arg_object['options'] = options arg_object['help'] = convert_help_column(help_column) l = cmd_object['arguments'] l.append(options) cmd_object['arguments'] = l cmd_object['argument_tree'][options]=arg_object cmd_object['group']= get_group_name_from_command(cmd) cmd_object['command']=cmd cur_argument = options else: arg_object = cmd_object['argument_tree'][cur_argument] arg_object['help'] = convert_help_column("{} {}".format(arg_object['help'],l)) cmd_object['argument_tree'][cur_argument] = arg_object elif in_block_type ==IN_BLOCK_TYPE_EXAMPLES: cmd_object['example'] = "{}\n{}".format(cmd_object['example'],l) else: in_block_type = IN_BLOCK_TYPE_NONE ## reset logger.error("[Warning] OTHER::cmd:{} :: {}".format(cmd_string, l)) # Break the loop when # - buffer is empty and # - Popen.poll returns not None (=process terminate) if not line and proc.poll() is not None: break dump_cmd_object(cmd_object) return cmd_object def get_group_name_from_command(cmd): group_name = " ".join(cmd.split()[:-1]) if not group_name: group_name = 'az' return group_name def get_parent_name_from_group_name(group_name): parent = " ".join(group_name.split()[:-1]) if not parent and group_name != 'az': parent = 'az' return parent ## Create Group & SubGroup Tree def get_groups(cmd_table): from azure.cli.core.help_files import helps groups_map = {} ## Populate group and group summary from helps for cmd in helps: diction_help = yaml.load(helps[cmd]) if diction_help.has_key('type') and diction_help['type'] != 'group': continue group_name = cmd group = new_parsing_group() if diction_help.has_key('short-summary'): group['name'] = group_name group['summary'] = diction_help['short-summary'] groups_map[group_name] = group ## Populate group from cmd table for cmd in cmd_table: group_name = get_group_name_from_command(cmd) if not groups_map.has_key(group_name): group = new_parsing_group() group_cmd_list = [] group_cmd_list.append(cmd) group['name'] = group_name group['commands'].append(cmd) groups_map[group_name] = group else: groups_map[group_name]['commands'].append(cmd) return groups_map def LEAF_NODE(node): return node.split()[-1] def LEAF_NODES(nodes): l=[] for node in nodes: l.append(node.split()[-1]) return l def populate_group_command_tree(group, groups_map,cmds_map): ## Inrease the limit just in case recursive func calling use up recursionlimit #import sys #sys.setrecursionlimit(10000) subgroups = [] for subgroup_name in group['subgroups']: if groups_map.has_key(subgroup_name): subgroup = groups_map[subgroup_name] populate_group_command_tree(subgroup, groups_map, cmds_map) subgroups.append(subgroup) group['subgroups']=subgroups cmd_list = [] for cmd_name in group['commands']: if cmds_map.has_key(cmd_name): cmd_list.append(cmds_map[cmd_name]) group['commands']=cmd_list def group_to_index_tree(index_tree, group_name, groups_map,cmds_map): index_tree['arguments'] = [] index_tree['argument_tree'] = {} index_tree['summary'] = groups_map[group_name]['summary'] child_index_tree_dict = [] leaf_command_list = [] # group.commands -> index_tree.commands leaf_command_list = LEAF_NODES(groups_map[group_name]['commands']) # group.commands -> index_tree.command_tree child_index_tree_dict = {} for cmd_name in groups_map[group_name]['commands']: child_index_tree = new_index_command_tree() command_to_index_tree(child_index_tree, cmd_name, cmds_map) child_index_tree_dict[LEAF_NODE(cmd_name)] = child_index_tree # group.subgroups -> index_tree.commands + index_tree.command_tree for subgroup_name in groups_map[group_name]['subgroups']: leaf_command_list.append(LEAF_NODE(subgroup_name)) child_index_tree = new_index_command_tree() group_to_index_tree(child_index_tree, subgroup_name, groups_map,cmds_map) child_index_tree_dict[LEAF_NODE(subgroup_name)] = child_index_tree index_tree['commands'] = leaf_command_list index_tree['command_tree'] = child_index_tree_dict def command_to_index_tree(index_tree, command_name, cmds_map): if cmds_map.has_key(command_name): index_tree['arguments'] = cmds_map[command_name]['arguments'] index_tree['argument_tree'] = cmds_map[command_name]['argument_tree'] index_tree['commands'] = [] index_tree['command_tree'] = {} index_tree['summary'] = cmds_map[command_name]['summary'] ## ## Main entrypoint for Azure Shell Index Generator ## def main(): parser = argparse.ArgumentParser(description='Azure Shell CLI Index Generator') parser.add_argument( '-o','--output', help='Azure Shell index file output path (ex. /tmp/cli-index.json)') parser.add_argument( '--verbose', action='store_true', help='Increase verbosity') args = parser.parse_args() ## Logging config handler = logging.StreamHandler(sys.stdout) if args.verbose: handler.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG) else: handler.setLevel(logging.INFO) logger.setLevel(logging.INFO) logger.addHandler(handler) # Output file validation and config if not args.output: logger.error('[ERROR] No output file specified with -o or --output param!') sys.exit(1) output_file = os.path.abspath(args.output) if not os.path.isdir(os.path.dirname(output_file)): logger.error('[ERROR] No directory exists for output file:{}'.format(output_file)) sys.exit(1) ## az executable command path check if not find_executable_path('az'): logger.error("[ERROR] NO azure cli (az) executable command found!") logger.error("Please install Azure CLI 2.0 and set its executable dir to PATH") logger.error("See https://github.com/Azure/azure-cli") sys.exit(1) azure_cli_version = get_cli_version() ## Check minimum azure-cli version if azure_cli_version < AZURE_SHELL_MINIMUM_AZURE_CLI_VERSION: logger.error("[ERROR] Azure CLI 2.0 minimum version failure!") logger.error("Minimum azure-cli version required: {} (Your version: {})".format( AZURE_SHELL_MINIMUM_AZURE_CLI_VERSION, azure_cli_version)) logger.error("Please install the latest azure-cli and set its executable dir to PATH") logger.error("See https://github.com/Azure/azure-cli") sys.exit(1) ## Import Azure CLI core modules module_import_trial_count = 0 while True: try: from azure.cli.core.help_files import helps from azure.cli.core.application import APPLICATION, Configuration break except ImportError: if module_import_trial_count > 0: logger.error("[ERROR] azure.cli.core module import failure!") sys.exit(1) ## Getting AzureCLI modules path and append it to current path list azurecli_modules_path = get_azurecli_modules_path() if azurecli_modules_path: sys.path.append(azurecli_modules_path) module_import_trial_count = module_import_trial_count + 1 cmd_table = APPLICATION.configuration.get_command_table() groups_map = {} cmds_map = {} groups_map = get_groups(cmd_table) ## Populate subgroups for each groups for group_name in groups_map.keys(): parent_name = get_parent_name_from_group_name(group_name) if parent_name: groups_map[parent_name]['subgroups'].append(group_name) logger.info("Start generating index...") logger.info("Output index file: {}".format(output_file)) ## Get command list cmd_list = cmd_table.keys() for cmd in cmd_list: try: cmds_map[cmd] = capture_cmd(cmd) except: pass ## Create Json Tree from root 'az' group index_tree = new_index_command_tree() group_to_index_tree(index_tree, 'az', groups_map,cmds_map) root_tree = {'az': index_tree} result_json = json.dumps(root_tree) ## Write json to your specified output file with open(output_file, "w") as f: f.write(result_json) PKM Jpazureshell/azureshell.conf[azureshell] # Pygments: highlighter style # run ./scripts/get-styles.py # 'manni', 'igor', 'lovelace', 'xcode', 'vim', 'autumn', 'abap', 'vs', # 'rrt', 'native', 'perldoc', 'borland', 'arduino', 'tango', 'emacs', 'friendly' # To disable themes, set highlighter_style = none highlighter_style = vim # log_file location. log_file = ~/.azureshell/azureshell.log # # # Default log level. Possible values: "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG". log_level = INFO PKM J)  azureshell/logger.pyimport os import logging _DEFAULT_AZURE_SHELL_LOG_LEVEL = 'INFO' _DEFAULT_AZURE_SHELL_LOG_FORMAT = '%(asctime)s %(levelname)s %(message)s' def init_logger(name, log_file, log_level = _DEFAULT_AZURE_SHELL_LOG_LEVEL, log_format = _DEFAULT_AZURE_SHELL_LOG_FORMAT): logger = logging.getLogger(name) handler = logging.FileHandler(os.path.expanduser(log_file)) formatter = logging.Formatter(log_format) handler.setFormatter(formatter) logger.addHandler(handler) switcher = { 'CRITICAL': logging.CRITICAL, 'ERROR': logging.ERROR, 'WARNING': logging.WARNING, 'INFO': logging.INFO, 'DEBUG': logging.DEBUG } logger.setLevel(switcher.get(log_level.upper(),logging.INFO)) PKM Jִazureshell/config.py# -*- coding: utf-8 -*- import os from .compat import configparser _DEFAULT_AZURE_SHELL_CONFIG_HIGHLIGHTER_STYLE = 'vim' _DEFAULT_AZURE_SHELL_CONFIG_LOG_FILE = '~/azureshell.log' _DEFAULT_AZURE_SHELL_CONFIG_LOG_LEVEL = 'INFO' class AzureShellConfig(object): def __init__(self, config_file=None): self._config_file = config_file self._config_parser = configparser.SafeConfigParser() if self._config_file: self._config_parser.read(config_file) @staticmethod def makedefaultconfig(config_file): dir_name = os.path.dirname(config_file) if not os.path.isdir(dir_name): os.makedirs(dir_name) with open(config_file, "w") as f: f.write("[azureshell]\n# Pygments: highlighter style\n# run ./scripts/get-styles.py\n# 'manni', 'igor', 'lovelace', 'xcode', 'vim', 'autumn', 'abap', 'vs', 'rrt', 'native', 'perldoc', 'borland', 'arduino', 'tango', 'emacs', 'friendly', 'monokai', 'paraiso-dark'\n# To disable themes, set highlighter_style = none\nhighlighter_style = vim\n\n# log_file location\nlog_file = ~/.azureshell/azureshell.log\n\n# Default log level. Possible values: 'CRITICAL', 'ERROR', 'WARNING', 'INFO' and 'DEBUG'\nlog_level = DEBUG") def _get_string(self, section, key, default_val): v ='' if not self._config_file: return default_val try: v = self._config_parser.get(section, key) except configparser.NoOptionError as e: v = default_val return v @property def highlighter_style(self): return self._get_string('azureshell','highlighter_style',_DEFAULT_AZURE_SHELL_CONFIG_HIGHLIGHTER_STYLE) @property def log_file(self): return self._get_string('azureshell','log_file',_DEFAULT_AZURE_SHELL_CONFIG_LOG_FILE) @property def log_level(self): return self._get_string('azureshell','log_level',_DEFAULT_AZURE_SHELL_CONFIG_LOG_LEVEL) PKM J,azureshell/azureshell.py# -*- coding: utf-8 -*- from __future__ import unicode_literals import os import sys import subprocess import logging from prompt_toolkit.document import Document from prompt_toolkit.shortcuts import create_eventloop,create_default_layout from prompt_toolkit.layout.processors import HighlightMatchingBracketProcessor, ConditionalProcessor from prompt_toolkit.filters import Always, HasFocus, IsDone from prompt_toolkit.enums import DEFAULT_BUFFER from prompt_toolkit.buffer import Buffer from prompt_toolkit.interface import CommandLineInterface, Application, AbortAction, AcceptAction from prompt_toolkit.auto_suggest import AutoSuggestFromHistory from prompt_toolkit.history import InMemoryHistory, FileHistory from prompt_toolkit.key_binding.manager import KeyBindingManager from pygments.token import Token from pygments.util import ClassNotFound from pygments.styles import get_style_by_name from prompt_toolkit.styles import default_style_extensions, style_from_dict from .cache import AzureShellCache logger = logging.getLogger('azureshell.azureshell') class InputInterrupt(Exception): pass class AzureShell(object): def __init__(self, config, completer): self._cli = None self._env = os.environ.copy() self.history = InMemoryHistory() self.file_history = FileHistory( "{}/history".format(AzureShellCache.Instance().get('base_dir'))) self._config = config self.completer = completer def run(self): while True: try: document = self.get_cli().run(reset_current_buffer=True) text = document.text except InputInterrupt: pass except (KeyboardInterrupt, EOFError): logger.debug("breaking loop due to KeyboardInterrupt or EOFError") break else: if text.startswith('exit') or text.startswith('quit'): sys.exit(0) if text.startswith('az'): full_cmd = text self.history.append(full_cmd) else: full_cmd = text[0:] logger.debug("Execute subprocess command:{}".format(full_cmd)) self.get_cli().request_redraw() p = subprocess.Popen(full_cmd, shell=True, env=self._env) p.communicate() def on_input_timeout(self, cli): document = cli.current_buffer.document text = document.text logger.debug("on_input_timeout document:{}".format(document)) # Add 'az' to current buffer if no text typed in #if not document.text: # cli.current_buffer.document = Document(u'az', 2) cli.request_redraw() def get_cli(self): if self._cli is None: self._cli = self.create_cli() return self._cli def create_cli(self): ## KeyBindings configuration key_binding = KeyBindingManager( enable_search=True, enable_abort_and_exit_bindings=True, enable_system_bindings=True, enable_auto_suggest_bindings=True, enable_open_in_editor=False) ## Buffer configuration default_buffer= Buffer( history=self.file_history, auto_suggest=AutoSuggestFromHistory(), enable_history_search=True, completer=self.completer, complete_while_typing=Always(), accept_action=AcceptAction.RETURN_DOCUMENT) ## Style configuration try: style = get_style_by_name(self._config.highlighter_style) except ClassNotFound: style = get_style_by_name('native') styles = {} styles.update(style.styles) styles.update(default_style_extensions) styles.update({ Token.Menu.Completions.Completion: 'bg:#003fff #ffffff', Token.Menu.Completions.Completion.Current: 'bg:#5ab300 #000000', Token.Menu.Completions.Meta.Current: 'bg:#5ab300 #ffffff', Token.Menu.Completions.Meta: 'bg:#ffffff #000000', Token.Scrollbar: 'bg:#003fff', Token.Scrollbar.Button: 'bg:#003333', }) prompt_style = style_from_dict(styles) ## Application application = Application( layout=self.create_cli_layout(), mouse_support=False, style=prompt_style, buffer=default_buffer, on_abort=AbortAction.RETRY, on_exit=AbortAction.RAISE_EXCEPTION, on_input_timeout=self.on_input_timeout, key_bindings_registry=key_binding.registry, ) cli = CommandLineInterface(application=application, eventloop=create_eventloop()) return cli def create_cli_layout(self): from .lexer import AzureShellLexer lexer = AzureShellLexer return create_default_layout ( message =u'azure> ', reserve_space_for_menu=8, lexer=lexer, extra_input_processors=[ ConditionalProcessor( processor=HighlightMatchingBracketProcessor(chars='[](){}'), filter=HasFocus(DEFAULT_BUFFER) & ~IsDone()) ] ) PK(JhC +azure_shell-0.2.3.dist-info/DESCRIPTION.rstazure-shell =========== An interactive Azure CLI 2.0 command line interface. [Note] Microsoft official Azure CLI 2.0 shell can be found at `Azure/azure-cli-shell `__ .. figure:: https://github.com/yokawasa/azure-shell/raw/master/img/azure-shell-console.gif :alt: Features -------- - Auto-completion of Azure CLI group, subgroups, commands, and parameters - Syntax highlighting - Command history Supported Environments ---------------------- - Python versions: 2.7, 3.3, 3.4, 3.5, 3.5, 3.6 and maybe more - OS: Mac, Ubuntu, CentOS, Bash-on-Windows, or any platform where azure-cli can be installed Prerequisites ------------- You need Azure CLI 2.0 installed as prerequisites for azure-shell. Please refer to `Install Azure CLI 2.0 `__ and install it if not yet installed Installation ------------ The azure-shell requires python and pip to install. You can install the azure-shell using pip: :: pip install azure-shell If you've already have azure-shell installed and want to upgrade to the latest version, you can upgrade like this: :: pip install --upgrade azure-shell Usage ----- Once you've installed the azure-shell, you can run azure-shell by simply typing azure-shell: :: azure-shell You can exit the azure-shell by typing either exit or quit: :: azure> exit Basically you can run azure-shell without making any configurations but you can give options to azure-shell to change its default behabior: :: azure-shell --help Usage: azure-shell [-h] [--version] [--basedir BASEDIR] [--config CONFIG] [--index INDEX] An interactive Azure CLI command line interface optional arguments: -h, --help show this help message and exit --version show program's version number and exit --basedir BASEDIR Azure Shell base dir path ($HOME/.azureshell by default) --config CONFIG Azure Shell config file path ($HOME/.azureshell/azureshell.conf by default) --index INDEX Azure Shell index file to load ($HOME/.azureshel/cli- index-.json) Azure Shell Index Generator --------------------------- You can generate an index for azure-shell using azure-shell-index-generator command. Please be noted that it will take time before all data generation works are done :: azure-shell-index-generator --output ~/.azureshell/cli-index.json Basically you don't need to generate the index by yourself as azure-shell automatically downloads an index from its repository and load it for commands and parameters completion in startup time. But you also can give azure-shell your index using --index option. :: azure-shell --index ~/.azureshell/cli-index.json Contributing ------------ Bug reports and pull requests are welcome on GitHub at https://github.com/yokawasa/azure-shell More Information ---------------- - `Get started with Azure CLI 2.0 `__ - `Install Azure CLI 2.0 `__ PK(J fxoo,azure_shell-0.2.3.dist-info/entry_points.txt[console_scripts] azure-shell = azureshell:main azure-shell-index-generator = azureshell.index_generator:main PK(Jɓ6)azure_shell-0.2.3.dist-info/metadata.json{"classifiers": ["Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: System Administrators", "Natural Language :: English", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6"], "download_url": "https://pypi.python.org/pypi/azure-shell", "extensions": {"python.commands": {"wrap_console": {"azure-shell": "azureshell:main", "azure-shell-index-generator": "azureshell.index_generator:main"}}, "python.details": {"contacts": [{"email": "yoichi.kawasaki@outlook.com", "name": "Yoichi Kawasaki", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/yokawasa/azure-shell"}}, "python.exports": {"console_scripts": {"azure-shell": "azureshell:main", "azure-shell-index-generator": "azureshell.index_generator:main"}}}, "extras": [], "generator": "bdist_wheel (0.26.0)", "keywords": ["azure", "azure-shell", "shell", "azure-cli"], "license": "Apache License 2.0", "metadata_version": "2.0", "name": "azure-shell", "platform": "any", "run_requires": [{"requires": ["Pygments (<3.0.0,>=2.1.3)", "configparser (>=3.5.0)", "prompt-toolkit (<1.1.0,>=1.0.0)", "pyyaml"]}], "summary": "An interactive Azure CLI 2.0 command line interface", "version": "0.2.3"}PK(JS%% )azure_shell-0.2.3.dist-info/top_level.txtazureshell PK(Jndnn!azure_shell-0.2.3.dist-info/WHEELWheel-Version: 1.0 Generator: bdist_wheel (0.26.0) Root-Is-Purelib: true Tag: py2-none-any Tag: py3-none-any PK(J$azure_shell-0.2.3.dist-info/METADATAMetadata-Version: 2.0 Name: azure-shell Version: 0.2.3 Summary: An interactive Azure CLI 2.0 command line interface Home-page: https://github.com/yokawasa/azure-shell Author: Yoichi Kawasaki Author-email: yoichi.kawasaki@outlook.com License: Apache License 2.0 Download-URL: https://pypi.python.org/pypi/azure-shell Keywords: azure azure-shell,shell,azure-cli Platform: any Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Intended Audience :: System Administrators Classifier: Natural Language :: English Classifier: License :: OSI Approved :: Apache Software License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Requires-Dist: Pygments (<3.0.0,>=2.1.3) Requires-Dist: configparser (>=3.5.0) Requires-Dist: prompt-toolkit (<1.1.0,>=1.0.0) Requires-Dist: pyyaml azure-shell =========== An interactive Azure CLI 2.0 command line interface. [Note] Microsoft official Azure CLI 2.0 shell can be found at `Azure/azure-cli-shell `__ .. figure:: https://github.com/yokawasa/azure-shell/raw/master/img/azure-shell-console.gif :alt: Features -------- - Auto-completion of Azure CLI group, subgroups, commands, and parameters - Syntax highlighting - Command history Supported Environments ---------------------- - Python versions: 2.7, 3.3, 3.4, 3.5, 3.5, 3.6 and maybe more - OS: Mac, Ubuntu, CentOS, Bash-on-Windows, or any platform where azure-cli can be installed Prerequisites ------------- You need Azure CLI 2.0 installed as prerequisites for azure-shell. Please refer to `Install Azure CLI 2.0 `__ and install it if not yet installed Installation ------------ The azure-shell requires python and pip to install. You can install the azure-shell using pip: :: pip install azure-shell If you've already have azure-shell installed and want to upgrade to the latest version, you can upgrade like this: :: pip install --upgrade azure-shell Usage ----- Once you've installed the azure-shell, you can run azure-shell by simply typing azure-shell: :: azure-shell You can exit the azure-shell by typing either exit or quit: :: azure> exit Basically you can run azure-shell without making any configurations but you can give options to azure-shell to change its default behabior: :: azure-shell --help Usage: azure-shell [-h] [--version] [--basedir BASEDIR] [--config CONFIG] [--index INDEX] An interactive Azure CLI command line interface optional arguments: -h, --help show this help message and exit --version show program's version number and exit --basedir BASEDIR Azure Shell base dir path ($HOME/.azureshell by default) --config CONFIG Azure Shell config file path ($HOME/.azureshell/azureshell.conf by default) --index INDEX Azure Shell index file to load ($HOME/.azureshel/cli- index-.json) Azure Shell Index Generator --------------------------- You can generate an index for azure-shell using azure-shell-index-generator command. Please be noted that it will take time before all data generation works are done :: azure-shell-index-generator --output ~/.azureshell/cli-index.json Basically you don't need to generate the index by yourself as azure-shell automatically downloads an index from its repository and load it for commands and parameters completion in startup time. But you also can give azure-shell your index using --index option. :: azure-shell --index ~/.azureshell/cli-index.json Contributing ------------ Bug reports and pull requests are welcome on GitHub at https://github.com/yokawasa/azure-shell More Information ---------------- - `Get started with Azure CLI 2.0 `__ - `Install Azure CLI 2.0 `__ PK(J}P$$"azure_shell-0.2.3.dist-info/RECORDazure_shell-0.2.3.dist-info/DESCRIPTION.rst,sha256=ZxzcxEOlQDdHhQQ9Demt7xTgPCYURFIrA4AOXjqHyVU,3243 azure_shell-0.2.3.dist-info/METADATA,sha256=UttosKc3cEA2yzPDWUqBgosPCJQQ0qcpqIVk5X9JJTA,4344 azure_shell-0.2.3.dist-info/RECORD,, azure_shell-0.2.3.dist-info/WHEEL,sha256=GrqQvamwgBV4nLoJe0vhYRSWzWsx7xjlt74FT0SWYfE,110 azure_shell-0.2.3.dist-info/entry_points.txt,sha256=Y5x17iBWXEsoqOo7wsq9NaSMqpxxdjXvoLokcHTTqrM,111 azure_shell-0.2.3.dist-info/metadata.json,sha256=uIYHXcX-Eko0O8dEgDKKK7ZbkG34LNt0lSiduYfr9rI,1520 azure_shell-0.2.3.dist-info/top_level.txt,sha256=an8Gmn97jB7oKhXZMXHY9mjwxDYfk1iPQ_cehSGR3us,11 azureshell/__init__.py,sha256=gP-QAjp1LZyQREhw16HoTX7RMmDzC0cSajk1r-szaXo,4231 azureshell/azureshell.conf,sha256=pd6vOlH5EFv45x6qoE_MCYHtG8gOQvo2ZPXdeW0Ukts,474 azureshell/azureshell.py,sha256=EqgKik4sq8uQZF072h7iZEdP6WiXupJtJ_sgGbX4heA,5391 azureshell/cache.py,sha256=mThpIA_a8e7TrN8flMUhe1_1uEqaQvLzwKvyZkrMf_w,509 azureshell/compat.py,sha256=hgvkvRufB3QKanuTEmdRRgovl1SqLcaJsqJn7YAYBxI,267 azureshell/completer.py,sha256=y903OSW_ih9LNTO8FY1aZRProrCFWoqIsSVZAcEMFzw,6048 azureshell/config.py,sha256=zihtA4XMEnHbvUtClFiReS5eVFVnE07Z3Yr91jrFIOc,1972 azureshell/index.py,sha256=4G-fqw1lS9UR67_opCGSZ4fs9-IGbndKLrS4nPJgFV4,4845 azureshell/index_generator.py,sha256=9-P3Ydk4iUsH8f6c4-QSUOZN9WXo8Tz7edlko4tce58,13011 azureshell/lexer.py,sha256=t9pOmHU5ufefuzYMKanU_NO7Oln677Gmic1rFAEJQUc,875 azureshell/logger.py,sha256=LBGY63n_zFVRNhr9JMciS9tRa6RX07vnbw-_zJ-sf0M,778 azureshell/utils.py,sha256=A28a01ZgPBnqQzcCHOmvq_9gD8SMWISuBpYCcAUUnTQ,2482 PKM J%[azureshell/cache.pyPKo'J