def test_help_with_param_specified(self, _): app = Application(Configuration([])) def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 --arg foo -h'.split()) s = """ Command az n1 Arguments --arg -a -b Global Arguments --help -h: Show this help message and exit. """ self.assertEqual(s, io.getvalue())
def test_help_group_children(self): app = Application(Configuration([])) def test_handler(): pass def test_handler2(): pass command = CliCommand('group1 group3 n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command2 = CliCommand('group1 group2 n1', test_handler2) command2.add_argument('foobar', '--foobar', '-fb', required=False) command2.add_argument('foobar2', '--foobar2', '-fb2', required=True) cmd_table = {'group1 group3 n1': command, 'group1 group2 n1': command2} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('group1 -h'.split()) s = '\nGroup\n az group1\n\nSubgroups:\n group2\n group3\n\n' self.assertEqual(s, io.getvalue())
def test_help_full_documentations(self, _): app = Application(Configuration()) def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.help = """ short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) examples: - name: foo example text: example details """ cmd_table = {'n1': command} config = Configuration() config.get_command_table = lambda args: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1: This module does xyz one-line or so. This module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2. Arguments --foobar2 -fb2 [Required]: One line partial sentence. Paragraph(s). --foobar -fb : One line partial sentence. Values from: az vm list, default. Text, markdown, etc. Global Arguments --help -h : Show this help message and exit. Examples foo example example details """ self.assertEqual(s, io.getvalue())
def test_help_global_params(self, mock_register_extensions, _): def register_globals(global_group): global_group.add_argument( "--query2", dest="_jmespath_query", metavar="JMESPATH", help="JMESPath query string. See http://jmespath.org/ " "for more information and examples.", ) mock_register_extensions.return_value = None def _register_global_parser(appl): # noqa pylint: disable=protected-access appl._event_handlers[appl.GLOBAL_PARSER_CREATED].append(register_globals) mock_register_extensions.side_effect = _register_global_parser def test_handler(): pass command = CliCommand("n1", test_handler) command.add_argument("arg", "--arg", "-a", required=False) command.add_argument("b", "-b", required=False) command.help = """ long-summary: | line1 line2 """ cmd_table = {"n1": command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute("n1 -h".split()) s = """ Command az n1 Line1 line2. Arguments --arg -a -b Global Arguments --help -h: Show this help message and exit. --query2 : JMESPath query string. See http://jmespath.org/ for more information and examples. """ self.assertEqual(s, io.getvalue())
def test_help_params_documentations(self, _): app = Application(Configuration()) def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.add_argument('foobar3', '--foobar3', '-fb3', required=False, help='the foobar3') command.help = """ parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) """ cmd_table = {'n1': command} config = Configuration() config.get_command_table = lambda argv: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1 Arguments --foobar2 -fb2 [Required]: One line partial sentence. Paragraph(s). --foobar -fb : One line partial sentence. Values from: az vm list, default. Text, markdown, etc. --foobar3 -fb3 : The foobar3. Global Arguments --help -h : Show this help message and exit. """ self.assertEqual(s, io.getvalue())
def test_client_request_id_is_refreshed_after_execution(self): def _handler(args): return True config = Configuration() config.get_command_table = lambda *_: {'test': CliCommand('test', _handler)} app = Application(config) app.execute(['test']) self.assertIn('x-ms-client-request-id', app.session['headers']) old_id = app.session['headers']['x-ms-client-request-id'] app.execute(['test']) self.assertIn('x-ms-client-request-id', app.session['headers']) self.assertNotEquals(old_id, app.session['headers']['x-ms-client-request-id'])
def test_choice_list_with_ints(self): def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False, choices=[1, 2, 3]) command.add_argument('b', '-b', required=False, choices=['a', 'b', 'c']) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application() app.initialize(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split())
def test_choice_list_with_ints(self): def test_handler(): pass command = CliCommand("n1", test_handler) command.add_argument("arg", "--arg", "-a", required=False, choices=[1, 2, 3]) command.add_argument("b", "-b", required=False, choices=["a", "b", "c"]) cmd_table = {"n1": command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application() app.initialize(config) with self.assertRaises(SystemExit): app.execute("n1 -h".split())
def test_help_plain_short_description(self): def test_handler(): pass command = CliCommand('n1', test_handler, description='the description') command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, 'n1: The description.' in io.getvalue())
def test_help_plain_short_description(self): def test_handler(): pass command = CliCommand("n1", test_handler, description="the description") command.add_argument("arg", "--arg", "-a", required=False) command.add_argument("b", "-b", required=False) cmd_table = {"n1": command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute("n1 -h".split()) self.assertEqual(True, "n1: The description." in io.getvalue())
def test_help_global_params(self, mock_register_extensions, _): def register_globals(global_group): global_group.add_argument('--query2', dest='_jmespath_query', metavar='JMESPATH', help='JMESPath query string. See http://jmespath.org/ ' 'for more information and examples.') mock_register_extensions.return_value = None mock_register_extensions.side_effect = lambda app: \ app._event_handlers[app.GLOBAL_PARSER_CREATED].append(register_globals) # pylint: disable=protected-access def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = """ long-summary: | line1 line2 """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) s = """ Command az n1 Line1 line2. Arguments --arg -a -b Global Arguments --help -h: Show this help message and exit. --query2 : JMESPath query string. See http://jmespath.org/ for more information and examples. """ self.assertEqual(s, io.getvalue())
def test_help_docstring_description_overrides_short_description(self): def test_handler(): pass command = CliCommand('n1', test_handler, description='short description') command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = 'short-summary: docstring summary' cmd_table = {'n1': command} config = Configuration() config.get_command_table = lambda args: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, 'n1: Docstring summary.' in io.getvalue())
def test_help_long_description_and_short_description(self): def test_handler(): pass command = CliCommand('n1', test_handler, description='short description') command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = 'long description' cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, io.getvalue().startswith('\nCommand\n az n1: Short description.\n Long description.')) # pylint: disable=line-too-long
def set_up_command_table(self, required_arg=False): command_table.clear() module_name = __name__ + '.' + self._testMethodName cli_command(module_name, 'test sample-vm-list', '{}#TestCommandWithConfiguredDefaults.sample_vm_list'.format(__name__)) register_cli_argument('test sample-vm-list', 'resource_group_name', CliArgumentType(options_list=('--resource-group-name', '-g'), configured_default='group', required=required_arg)) command_table['test sample-vm-list'].load_arguments() _update_command_definitions(command_table) self.argv = 'az test sample-vm-list'.split() config = Configuration() config.get_command_table = lambda argv: command_table self.application = Application(config)
def test_help_param(self): def test_handler(): pass command = CliCommand("n1", test_handler) command.add_argument("arg", "--arg", "-a", required=False) command.add_argument("b", "-b", required=False) cmd_table = {"n1": command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application() app.initialize(config) with self.assertRaises(SystemExit): app.execute("n1 -h".split()) with self.assertRaises(SystemExit): app.execute("n1 --help".split())
def test_help_param(self): def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application() app.initialize(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) with self.assertRaises(SystemExit): app.execute('n1 --help'.split())
def test_help_long_description_and_short_description(self): def test_handler(): pass command = CliCommand("n1", test_handler, description="short description") command.add_argument("arg", "--arg", "-a", required=False) command.add_argument("b", "-b", required=False) command.help = "long description" cmd_table = {"n1": command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute("n1 -h".split()) self.assertEqual( True, io.getvalue().startswith("\nCommand\n az n1: Short description.\n Long description.") ) # pylint: disable=line-too-long
def test_help_extra_missing_params(self): app = Application(Configuration([])) def test_handler(foobar2, foobar=None): # pylint: disable=unused-argument pass command = CliCommand("n1", test_handler) command.add_argument("foobar", "--foobar", "-fb", required=False) command.add_argument("foobar2", "--foobar2", "-fb2", required=True) cmd_table = {"n1": command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) # work around an argparse behavior where output is not printed and SystemExit # is not raised on Python 2.7.9 if sys.version_info < (2, 7, 10): try: app.execute("n1 -fb a --foobar value".split()) except SystemExit: pass try: app.execute("n1 -fb a --foobar2 value --foobar3 extra".split()) except SystemExit: pass else: with self.assertRaises(SystemExit): app.execute("n1 -fb a --foobar value".split()) with self.assertRaises(SystemExit): app.execute("n1 -fb a --foobar2 value --foobar3 extra".split()) self.assertTrue( "required" in io.getvalue() and "--foobar/-fb" not in io.getvalue() and "--foobar2/-fb2" in io.getvalue() and "unrecognized arguments: --foobar3 extra" in io.getvalue() )
def test_help_long_description_multi_line(self): def test_handler(): pass command = CliCommand('n1', test_handler) command.add_argument('arg', '--arg', '-a', required=False) command.add_argument('b', '-b', required=False) command.help = """ long-summary: | line1 line2 """ cmd_table = {'n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('n1 -h'.split()) self.assertEqual(True, io.getvalue().startswith('\nCommand\n az n1\n Line1\n line2.')) # pylint: disable=line-too-long
def test_list_value_parameter(self): hellos = [] def handler(args): hellos.append(args) command = CliCommand('test command', handler) command.add_argument('hello', '--hello', nargs='+', action=IterateAction) command.add_argument('something', '--something') cmd_table = {'test command': command} argv = 'az test command --hello world sir --something else'.split() config = Configuration() config.get_command_table = lambda argv: cmd_table application = Application(config) application.execute(argv[1:]) self.assertEqual(2, len(hellos)) self.assertEqual(hellos[0]['hello'], 'world') self.assertEqual(hellos[0]['something'], 'else') self.assertEqual(hellos[1]['hello'], 'sir') self.assertEqual(hellos[1]['something'], 'else')
def test_generic_update_empty_nodes(self): my_obj = { 'prop': None, 'list': [], 'dict': { 'dict2': None }, 'dict3': {} } def my_get(): return my_obj def my_set(**kwargs): # pylint:disable=unused-argument return my_obj config = Configuration([]) app = Application(config) setattr(sys.modules[__name__], my_get.__name__, my_get) setattr(sys.modules[__name__], my_set.__name__, my_set) cli_generic_update_command(None, 'gencommand', '{}#{}'.format( __name__, my_get.__name__), '{}#{}'.format(__name__, my_set.__name__)) # add to prop app.execute('gencommand --add prop a=b'.split()) self.assertEqual(my_obj['prop'][0]['a'], 'b', 'verify object added to null list') self.assertEqual(len(my_obj['prop'][0]), 1, 'verify only one object added to null list') # add to list app.execute('gencommand --add list c=d'.split()) self.assertEqual(my_obj['list'][0]['c'], 'd', 'verify object added to empty list') self.assertEqual(len(my_obj['list']), 1, 'verify only one object added to empty list') # set dict2 app.execute('gencommand --set dict.dict2.e=f'.split()) self.assertEqual(my_obj['dict']['dict2']['e'], 'f', 'verify object added to null dict') self.assertEqual(len(my_obj['dict']['dict2']), 1, 'verify only one object added to null dict') # set dict3 app.execute('gencommand --set dict3.g=h'.split()) self.assertEqual(my_obj['dict3']['g'], 'h', 'verify object added to empty dict') self.assertEqual(len(my_obj['dict3']), 1, 'verify only one object added to empty dict')
def test_generic_update_ids(self): my_objs = [{ 'prop': 'val', 'list': ['a', 'b', ['c', { 'd': 'e' }]] }, { 'prop': 'val', 'list': ['a', 'b', ['c', { 'd': 'e' }]] }] def my_get(name, resource_group): #pylint:disable=unused-argument # name is None when tests are run in a batch on Python <=2.7.9 if sys.version_info < (2, 7, 10): return my_objs[0] return my_objs[int(name)] def my_set(**kwargs): #pylint:disable=unused-argument return my_objs register_cli_argument( 'gencommand', 'name', CliArgumentType(options_list=('--name', '-n'), metavar='NAME', id_part='name')) cli_generic_update_command('gencommand', my_get, my_set) config = Configuration([]) APPLICATION.initialize(config) id_str = ( '/subscriptions/00000000-0000-0000-0000-0000000000000/resourceGroups/rg/' 'providers/Microsoft.Compute/virtualMachines/') APPLICATION.execute( 'gencommand --ids {0}0 {0}1 --resource-group bar --set prop=newval' .format(id_str).split()) self.assertEqual(my_objs[0]['prop'], 'newval', 'first object updated') # name is None when tests are run in a batch on Python <=2.7.9 if not sys.version_info < (2, 7, 10): self.assertEqual(my_objs[1]['prop'], 'newval', 'second object updated')
def test_help_long_description_from_docstring(self): """ Verifies that the first sentence of a docstring is extracted as the short description. Verifies that line breaks in the long summary are removed and leaves the text wrapping to the help system. """ def test_handler(): """Short Description. Long description with\nline break.""" pass setattr(sys.modules[__name__], test_handler.__name__, test_handler) cli_command(None, 'test', '{}#{}'.format(__name__, test_handler.__name__)) _update_command_definitions(command_table) config = Configuration([]) app = Application(config) with self.assertRaises(SystemExit): app.execute('test -h'.split()) self.assertEqual(True, io.getvalue().startswith('\nCommand\n az test: Short Description.\n Long description with line break.')) # pylint: disable=line-too-long
def test_command_consistency(self): argv = ['vm'] APPLICATION.initialize(Configuration(argv)) command_table = APPLICATION.configuration.get_command_table() vm_commands = ((vm_command, metadata) for vm_command, metadata in command_table.items() if vm_command.startswith('vm')) for command_name, command_metadata in vm_commands: for argument_name, expected_options_list in self.consistent_arguments.items( ): try: actual_options_list = command_metadata.arguments[ argument_name].options_list self.assertEqual( actual_options_list, expected_options_list, 'Argument {} of command {} has inconsistent flags'. format(argument_name, command_name)) except KeyError: pass
def main(args, output=sys.stdout, logging_stream=None): configure_logging(args, logging_stream) logger = get_az_logger(__name__) logger.debug('Command arguments %s', args) if args and (args[0] == '--version' or args[0] == '-v'): show_version_info_exit(output) azure_folder = get_config_dir() if not os.path.exists(azure_folder): os.makedirs(azure_folder) ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json')) CONFIG.load(os.path.join(azure_folder, 'az.json')) SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600) APPLICATION.initialize(Configuration()) try: cmd_result = APPLICATION.execute(args) # Commands can return a dictionary/list of results # If they do, we print the results. if cmd_result and cmd_result.result is not None: from azure.cli.core._output import OutputProducer formatter = OutputProducer.get_formatter( APPLICATION.configuration.output_format) OutputProducer(formatter=formatter, file=output).out(cmd_result) except Exception as ex: # pylint: disable=broad-except # TODO: include additional details of the exception in telemetry telemetry.set_exception( ex, 'outer-exception', 'Unexpected exception caught during application execution.') telemetry.set_failure() error_code = handle_exception(ex) return error_code
def cli_execute(self, cmd): """ sends the command to the CLI to be executed """ try: args = parse_quotes(cmd) azlogging.configure_logging(args) if len(args) > 0 and args[0] == 'feedback': SHELL_CONFIGURATION.set_feedback('yes') self.user_feedback = False azure_folder = get_config_dir() if not os.path.exists(azure_folder): os.makedirs(azure_folder) ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json')) CONFIG.load(os.path.join(azure_folder, 'az.json')) SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600) config = Configuration() self.app.initialize(config) result = self.app.execute(args) self.last_exit = 0 if result and result.result is not None: from azure.cli.core._output import OutputProducer if self.output: self.output.out(result) else: formatter = OutputProducer.get_formatter( self.app.configuration.output_format) OutputProducer(formatter=formatter, file=sys.stdout).out(result) self.last = result except Exception as ex: # pylint: disable=broad-except self.last_exit = handle_exception(ex) except SystemExit as ex: self.last_exit = int(ex.code)
def test_help_loads(self): app = Application() app.initialize(Configuration()) with mock.patch('azure.cli.core.commands.arm.APPLICATION', app): from azure.cli.core.commands.arm import add_id_parameters parser_dict = {} cmd_tbl = app.configuration.get_command_table() app.parser.load_command_table(cmd_tbl) for cmd in cmd_tbl: try: app.configuration.load_params(cmd) except KeyError: pass app.register(app.COMMAND_TABLE_PARAMS_LOADED, add_id_parameters) app.raise_event(app.COMMAND_TABLE_PARAMS_LOADED, command_table=cmd_tbl) app.parser.load_command_table(cmd_tbl) _store_parsers(app.parser, parser_dict) for name, parser in parser_dict.items(): try: help_file = _help.GroupHelpFile(name, parser) \ if _is_group(parser) \ else _help.CommandHelpFile(name, parser) help_file.load(parser) except Exception as ex: raise _help.HelpAuthoringException('{}, {}'.format( name, ex)) extras = [ k for k in azure.cli.core.help_files.helps.keys() if k not in parser_dict ] self.assertTrue( len(extras) == 0, 'Found help files that don\'t map to a command: ' + str(extras))
def test_generic_update(self): # pylint: disable=too-many-statements my_obj = TestObject() def my_get(): return my_obj def my_set(**kwargs): #pylint:disable=unused-argument return my_obj config = Configuration([]) app = Application(config) setattr(sys.modules[__name__], my_get.__name__, my_get) setattr(sys.modules[__name__], my_set.__name__, my_set) cli_generic_update_command(None, 'update-obj', '{}#{}'.format(__name__, my_get.__name__), '{}#{}'.format(__name__, my_set.__name__)) # Test simplest ways of setting properties app.execute('update-obj --set myProp=newValue'.split()) self.assertEqual(my_obj.my_prop, 'newValue', 'set simple property') app.execute('update-obj --set myProp=val3'.split()) self.assertEqual(my_obj.my_prop, 'val3', 'set simple property again') app.execute('update-obj --set myList[0]=newValA'.split()) self.assertEqual(my_obj.my_list[0], 'newValA', 'set simple list element') app.execute('update-obj --set myList[-4]=newValB'.split()) self.assertEqual(my_obj.my_list[0], 'newValB', 'set simple list element') app.execute('update-obj --set myDict.myCamelKey=success'.split()) self.assertEqual(my_obj.my_dict['myCamelKey'], 'success', 'set simple dict element with camel case key') app.execute('update-obj --set myDict.my_snake_key=success'.split()) self.assertEqual(my_obj.my_dict['my_snake_key'], 'success', 'set simple dict element with snake case key') # Test the different ways of indexing into a list of objects or dictionaries by filter app.execute( 'update-obj --set myListOfCamelDicts[myKey=value_2].myKey=new_value' .split()) self.assertEqual(my_obj.my_list_of_camel_dicts[1]['myKey'], 'new_value', 'index into list of dictionaries by camel-case key') app.execute( 'update-obj --set myListOfSnakeDicts[my_key=value2].my_key=new_value' .split()) self.assertEqual(my_obj.my_list_of_snake_dicts[1]['my_key'], 'new_value', 'index into list of dictionaries by snake-case key') app.execute( 'update-obj --set myListOfObjects[myString=1.2.3.4].myString=new_value' .split()) self.assertEqual(my_obj.my_list_of_objects[1].my_string, 'new_value', 'index into list of objects by key') # Test setting on elements nested within lists app.execute('update-obj --set myList[1][1]=newValue'.split()) self.assertEqual(my_obj.my_list[1][1], 'newValue', 'set nested list element') app.execute('update-obj --set myList[2].myKey=newValue'.split()) self.assertEqual(my_obj.my_list[2]['myKey'], 'newValue', 'set nested dict element') app.execute('update-obj --set myList[3].myInt=50'.split()) self.assertEqual(my_obj.my_list[3].my_int, 50, 'set nested object element') # Test overwriting and removing values app.execute('update-obj --set myProp={} myProp.foo=bar'.split()) self.assertEqual(my_obj.my_prop['foo'], 'bar', 'replace scalar with dict') app.execute( 'update-obj --set myProp=[] --add myProp key1=value1 --set myProp[0].key2=value2' .split()) self.assertEqual(my_obj.my_prop[0]['key1'], 'value1', 'replace scalar with new list and add a dict entry') self.assertEqual(my_obj.my_prop[0]['key2'], 'value2', 'add a second value to the new dict entry') app.execute( 'update-obj --remove myProp --add myProp str1 str2 --remove myProp 0' .split()) self.assertEqual(len(my_obj.my_prop), 1, 'nullify property, add two and remove one') self.assertEqual(my_obj.my_prop[0], 'str2', 'nullify property, add two and remove one') # Test various --add to lists app.execute('update-obj --set myList=[]'.split()) app.execute( shlex.split( 'update-obj --add myList key1=value1 key2=value2 foo "string in quotes" [] {} foo=bar' )) self.assertEqual(my_obj.my_list[0]['key1'], 'value1', 'add a value to a dictionary') self.assertEqual(my_obj.my_list[0]['key2'], 'value2', 'add a second value to the dictionary') self.assertEqual(my_obj.my_list[1], 'foo', 'add scalar value to list') self.assertEqual(my_obj.my_list[2], 'string in quotes', 'add scalar value with quotes to list') self.assertEqual(my_obj.my_list[3], [], 'add list to a list') self.assertEqual(my_obj.my_list[4], {}, 'add dict to a list') self.assertEqual(my_obj.my_list[-1]['foo'], 'bar', 'add second dict and verify when dict is at the end') # Test --remove self.assertEqual(len(my_obj.my_list), 6, 'pre-verify length of list') app.execute('update-obj --remove myList -2'.split()) self.assertEqual(len(my_obj.my_list), 5, 'verify one item removed') self.assertEqual(my_obj.my_list[4]['foo'], 'bar', 'verify correct item removed') self.assertEqual('key1' in my_obj.my_list[0], True, 'verify dict item exists') app.execute('update-obj --remove myList[0].key1'.split()) self.assertEqual('key1' not in my_obj.my_list[0], True, 'verify dict entry can be removed')
def test_generic_update_errors(self): #pylint: disable=no-self-use my_obj = TestObject() def my_get(a1, a2): #pylint: disable=unused-argument return my_obj def my_set(**kwargs): #pylint:disable=unused-argument return my_obj config = Configuration([]) app = Application(config) setattr(sys.modules[__name__], my_get.__name__, my_get) setattr(sys.modules[__name__], my_set.__name__, my_set) cli_generic_update_command(None, 'gencommand', '{}#{}'.format(__name__, my_get.__name__), '{}#{}'.format(__name__, my_set.__name__)) def _execute_with_error(command, error, message): try: app.execute(command.split()) except CLIError as err: if not error in str(err): raise AssertionError('{}\nExpected: {}\nActual: {}'.format( message, error, str(err))) else: raise AssertionError('exception not thrown') missing_remove_message = "Couldn't find 'doesntExist' in ''. Available options: ['myDict', 'myList', 'myListOfCamelDicts', 'myListOfObjects', 'myListOfSnakeDicts', 'myProp']" _execute_with_error('gencommand --a1 1 --a2 2 --remove doesntExist', missing_remove_message, 'remove non-existent property by name') _execute_with_error('gencommand --a1 1 --a2 2 --remove doesntExist 2', missing_remove_message, 'remove non-existent property by index') remove_prop_message = "Couldn't find 'doesntExist' in 'myList.doesntExist'. Available options: index into the collection 'myList.doesntExist' with [<index>] or [<key=value>]" _execute_with_error( 'gencommand --a1 1 --a2 2 --remove myList.doesntExist.missing 2', remove_prop_message, 'remove non-existent sub-property by index') _execute_with_error('gencommand --a1 1 --a2 2 --remove myList 20', "index 20 doesn't exist on myList", 'remove out-of-range index') set_on_list_message = "Couldn't find 'doesnt_exist' in 'myList'. Available options: index into the collection 'myList' with [<index>] or [<key=value>]" _execute_with_error( 'gencommand --a1 1 --a2 2 --set myList.doesnt_exist=foo', set_on_list_message, 'set shouldn\'t work on a list') _execute_with_error( 'gencommand --a1 1 --a2 2 --set myList.doesnt_exist.doesnt_exist2=foo', set_on_list_message, 'set shouldn\'t work on a list') _execute_with_error( 'gencommand --a1 1 --a2 2 --set myList[5].doesnt_exist=foo', "index 5 doesn't exist on myList", 'index out of range in path') _execute_with_error( 'gencommand --a1 1 --a2 2 --remove myList[0]', 'invalid syntax: --remove property.list <indexToRemove> OR --remove propertyToRemove', 'remove requires index to be space-separated') app.execute( "gencommand --a1 1 --a2 2 --set myDict={'foo':'bar'}".split()) _execute_with_error( 'gencommand --a1 1 --a2 2 --set myDict.foo.doo=boo', "Couldn't find 'foo' in 'myDict'. 'myDict' does not support further indexing.", 'Cannot dot index from a scalar value') _execute_with_error( 'gencommand --a1 1 --a2 2 --set myDict.foo[0]=boo', "Couldn't find 'foo' in 'myDict'. 'myDict' does not support further indexing.", 'Cannot list index from a scalar value') _execute_with_error( 'gencommand --a1 1 --a2 2 --add myDict la=da', "invalid syntax: --add property.listProperty <key=value, string or JSON string>", 'Add only works with lists') # add an entry which makes 'myKey' no longer unique app.execute( 'gencommand --a1 1 --a2 2 --add myListOfCamelDicts myKey=value_2'. split()) _execute_with_error( 'gencommand --a1 1 --a2 2 --set myListOfCamelDicts[myKey=value_2].myKey=foo', "non-unique key 'myKey' found multiple matches on myListOfCamelDicts. " "Key must be unique.", 'indexing by key must be unique') _execute_with_error( 'gencommand --a1 1 --a2 2 --set myListOfCamelDicts[myKey=foo].myKey=foo', "item with value 'foo' doesn\'t exist for key 'myKey' on myListOfCamelDicts", 'no match found when indexing by key and value')
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 ## Get command table via acure.cli.core azure_cli_version = get_cli_version() cmd_table = {} if azure_cli_version < '2.0.3': # External I/F has been changed since azure-cli-2.0.3 cmd_table = APPLICATION.configuration.get_command_table() else: config = Configuration() cmd_table = config.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)
import os import re import subprocess import sys from azure.cli.core.application import Configuration class Exporter(json.JSONEncoder): def default(self, o):#pylint: disable=method-hidden try: return super(Exporter, self).default(o) except TypeError: return str(o) parser = argparse.ArgumentParser(description='Command Table Parser') parser.add_argument('--commands', metavar='N', nargs='+', help='Filter by command scope') args = parser.parse_args() cmd_set_names = args.commands # ignore the params passed in now so they aren't used by the cli sys.argv = sys.argv[:1] config = Configuration([]) cmd_table = config.get_command_table() cmd_list = sorted([cmd_name for cmd_name in cmd_table.keys() if cmd_set_names is None or cmd_name.split()[0] in cmd_set_names]) for cmd in cmd_list: cmd_string = 'az {} -h'.format(cmd) os.system(cmd_string) print('\n===============================', flush=True)
def verify_packages(): # tmp dir to store all the built packages built_packages_dir = tempfile.mkdtemp() all_modules = automation_path.get_all_module_paths() all_command_modules = automation_path.get_command_modules_paths( include_prefix=True) modules_missing_manifest_in = [ name for name, path in all_modules if not os.path.isfile(os.path.join(path, 'MANIFEST.in')) ] if modules_missing_manifest_in: print_heading( 'Error: The following modules are missing the MANIFEST.in file.') print(modules_missing_manifest_in) sys.exit(1) # STEP 1:: Build the packages for name, path in all_modules: build_package(path, built_packages_dir) # STEP 2:: Install the CLI and dependencies azure_cli_modules_path = next(path for name, path in all_modules if name == 'azure-cli') install_package(azure_cli_modules_path, 'azure-cli', built_packages_dir) # Install the remaining command modules for name, fullpath in all_command_modules: install_package(fullpath, name, built_packages_dir) # STEP 3:: Validate the installation try: az_output = subprocess.check_output(['az', '--debug'], stderr=subprocess.STDOUT, universal_newlines=True) success = 'Error loading command module' not in az_output print(az_output, file=sys.stderr) except subprocess.CalledProcessError as err: success = False print(err, file=sys.stderr) if not success: print_heading('Error running the CLI!', f=sys.stderr) sys.exit(1) # STEP 4:: Run -h on each command print('Running --help on all commands.') from azure.cli.core.application import Configuration config = Configuration() all_commands = list(config.get_command_table()) pool_size = 5 chunk_size = 10 command_results = [] p = multiprocessing.Pool(pool_size) prev_percent = 0 for i, res in enumerate( p.imap_unordered(run_help_on_command_without_err, all_commands, chunk_size), 1): command_results.append(res) cur_percent = int((i / len(all_commands)) * 100) if cur_percent != prev_percent: print('{}% complete'.format(cur_percent), file=sys.stderr) prev_percent = cur_percent p.close() p.join() if not all(command_results): print_heading('Error running --help on commands in the CLI!', f=sys.stderr) sys.exit(1) print('OK.') # STEP 5:: Determine if any modules failed to install pip.utils.pkg_resources = imp.reload(pip.utils.pkg_resources) installed_command_modules = [ dist.key for dist in pip.get_installed_distributions(local_only=True) if dist.key.startswith(COMMAND_MODULE_PREFIX) ] print('Installed command modules', installed_command_modules) missing_modules = \ set([name for name, fullpath in all_command_modules]) - set(installed_command_modules) if missing_modules: print_heading( 'Error: The following modules were not installed successfully', f=sys.stderr) print(missing_modules, file=sys.stderr) sys.exit(1) # STEP 6:: Verify the wheels that get produced print_heading('Verifying wheels...') invalid_wheels = [] for wheel_path in glob.glob(os.path.join(built_packages_dir, '*.whl')): # Verify all non-nspkg wheels if 'nspkg' not in wheel_path and not _valid_wheel(wheel_path): invalid_wheels.append(wheel_path) if invalid_wheels: print_heading('Error: The following wheels are invalid', f=sys.stderr) print(invalid_wheels, file=sys.stderr) print(VALID_WHEEL_HELP, file=sys.stderr) sys.exit(1) print_heading('Verified wheels successfully.') print_heading('OK')
def test_help_group_help(self): app = Application(Configuration([])) def test_handler(): pass azure.cli.core.help_files.helps['test_group1 test_group2'] = """ type: group short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 examples: - name: foo example text: example details """ command = CliCommand('test_group1 test_group2 n1', test_handler) command.add_argument('foobar', '--foobar', '-fb', required=False) command.add_argument('foobar2', '--foobar2', '-fb2', required=True) command.help = """ short-summary: this module does xyz one-line or so long-summary: | this module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2 parameters: - name: --foobar -fb type: string required: false short-summary: one line partial sentence long-summary: text, markdown, etc. populator-commands: - az vm list - default - name: --foobar2 -fb2 type: string required: true short-summary: one line partial sentence long-summary: paragraph(s) examples: - name: foo example text: example details """ cmd_table = {'test_group1 test_group2 n1': command} config = Configuration([]) config.get_command_table = lambda: cmd_table app = Application(config) with self.assertRaises(SystemExit): app.execute('test_group1 test_group2 --help'.split()) s = """ Group az test_group1 test_group2: This module does xyz one-line or so. This module.... kjsdflkj... klsfkj paragraph1 this module.... kjsdflkj... klsfkj paragraph2. Commands: n1: This module does xyz one-line or so. Examples foo example example details """ self.assertEqual(s, io.getvalue()) del azure.cli.core.help_files.helps['test_group1 test_group2']
def run(self): """ runs the CLI """ telemetry.start() self.cli.buffers['symbols'].reset( initial_document=Document(u'%s' %shell_help) ) while True: try: document = self.cli.run(reset_current_buffer=True) text = document.text cmd = text outside = False if text.split() and text.split()[0] == 'az': cmd = ' '.join(text.split()[1:]) if self.default_command: cmd = self.default_command + " " + cmd # if self.default_params: # for param in self.default_params: # cmd += ' ' + param except AttributeError: # when the user pressed Control Q break else: if text.strip() == "quit" or text.strip() == "exit": break elif text.strip() == "clear": # clears the history, but only when you restart outside = True cmd = 'echo -n "" >' +\ os.path.join( SHELL_CONFIGURATION.get_config_dir(), SHELL_CONFIGURATION.get_history()) elif text.strip() == "help": print(help_doc.dump(shell_help)) if text: if text[0] == SELECT_SYMBOL['outside']: cmd = text[1:] outside = True # elif text.split()[0] == "az": # dumps the extra az # cmd = " ".join(text.split()[1:]) elif text[0] == SELECT_SYMBOL['exit_code']: print(self.last_exit) self.set_prompt() continue elif SELECT_SYMBOL['query'] in text: # query previous output if self.last and self.last.result: if hasattr(self.last.result, '__dict__'): input_dict = dict(self.last.result) else: input_dict = self.last.result try: result = jmespath.search( text.partition(SELECT_SYMBOL['query'])[2], input_dict) if isinstance(result, str): print(result) else: print(json.dumps(result, sort_keys=True, indent=2)) except jmespath.exceptions.ParseError: print("Invalid Query") self.set_prompt() continue elif "|" in text or ">" in text: # anything I don't parse, send off outside = True cmd = "az " + cmd elif SELECT_SYMBOL['example'] in text: global NOTIFICATIONS cmd = self.handle_example(text) if SELECT_SYMBOL['default'] in text: default = text.partition(SELECT_SYMBOL['default'])[2].split() if default[0].startswith('-'): value = self.handle_default_param(default) else: value = self.handle_default_command(default) print("defaulting: " + value) self.set_prompt() continue if SELECT_SYMBOL['undefault'] in text: value = text.partition(SELECT_SYMBOL['undefault'])[2].split() if len(value) == 0: self.default_command = "" set_default_command("", add=False) # self.default_params = [] print('undefaulting all') elif len(value) == 1 and value[0] == self.default_command: self.default_command = "" set_default_command("", add=False) print('undefaulting: ' + value[0]) # elif len(value) == 2 and ' '.join(value[:2]) in self.default_params: # self.default_params.remove(' '.join(value[:2])) # print('undefaulting: ' + ' '.join(value[:2])) self.set_prompt() continue if not text: # not input self.set_prompt() continue self.history.append(cmd) self.set_prompt() if outside: subprocess.Popen(cmd, shell=True).communicate() else: try: args = [str(command) for command in cmd.split()] azlogging.configure_logging(args) azure_folder = get_config_dir() if not os.path.exists(azure_folder): os.makedirs(azure_folder) ACCOUNT.load(os.path.join(azure_folder, 'azureProfile.json')) CONFIG.load(os.path.join(azure_folder, 'az.json')) SESSION.load(os.path.join(azure_folder, 'az.sess'), max_age=3600) config = Configuration(args) self.app.initialize(config) result = self.app.execute(args) if result and result.result is not None: from azure.cli.core._output import OutputProducer, format_json if self.output: self.output.out(result) else: formatter = OutputProducer.get_formatter( self.app.configuration.output_format) OutputProducer(formatter=formatter, file=self.input).out(result) self.last = result self.last_exit = 0 except Exception as ex: # pylint: disable=broad-except self.last_exit = handle_exception(ex) except SystemExit as ex: self.last_exit = ex.code if self.last_exit != 0: telemetry.set_failure() else: telemetry.set_success() print('Have a lovely day!!') telemetry.conclude()
# -------------------------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- import argparse import json from docutils import nodes from docutils.statemachine import ViewList from sphinx.util.compat import Directive from sphinx.util.nodes import nested_parse_with_titles from azure.cli.core.application import Application, Configuration import azure.cli.core._help as _help app = Application(Configuration()) for cmd in app.configuration.get_command_table(): try: app.execute(cmd.split() + ['-h']) except: pass class AzHelpGenDirective(Directive): def make_rst(self): INDENT = ' ' DOUBLEINDENT = INDENT * 2 parser_keys = [] parser_values = [] sub_parser_keys = [] sub_parser_values = []
def load_command_table(): APPLICATION.initialize(Configuration()) command_table = APPLICATION.configuration.get_command_table() _install_modules(command_table) return command_table
def dump_no_help(modules): APPLICATION.initialize(Configuration()) cmd_table = APPLICATION.configuration.get_command_table() exit_val = 0 for cmd in cmd_table: cmd_table[cmd].load_arguments() for mod in modules: try: import_module('azure.cli.command_modules.' + mod).load_params(mod) except Exception as ex: print("EXCEPTION: {} for module {}".format(ex, str(mod))) _update_command_definitions(cmd_table) add_id_parameters(cmd_table) with open(WHITE_DATA_FILE, 'r') as white: white_data = json.load(white) white_list_commands = set(white_data.get('commands', [])) white_list_subgroups = set(white_data.get('subgroups', [])) white_list_parameters = white_data.get('parameters', {}) command_list = set() subgroups_list = set() parameters = {} for cmd in cmd_table: if not cmd_table[ cmd].description and cmd not in helps and cmd not in white_list_commands: command_list.add(cmd) exit_val = 1 group_name = " ".join(cmd.split()[:-1]) if group_name not in helps: if group_name not in subgroups_list and group_name not in white_list_subgroups and group_name: exit_val = 1 subgroups_list.add(group_name) param_list = set() for key in cmd_table[cmd].arguments: name = cmd_table[cmd].arguments[key].name if not cmd_table[cmd].arguments[key].type.settings.get( 'help') and name not in white_list_parameters.get(cmd, []): exit_val = 1 param_list.add(name) if param_list: parameters[cmd] = param_list for cmd in helps: diction_help = yaml.load(helps[cmd]) if "short-summary" in diction_help and "type" in diction_help: if diction_help["type"] == "command" and cmd in command_list: command_list.remove(cmd) elif diction_help["type"] == "group" and cmd in subgroups_list: subgroups_list.remove(cmd) if "parameters" in diction_help: for param in diction_help["parameters"]: if "short-summary" in param and param["name"].split( )[0] in parameters: parameters.pop(cmd, None) data = { "subgroups": subgroups_list, "commands": command_list, "parameters": parameters } return exit_val, data
from __future__ import print_function from importlib import import_module import json import os import pkgutil import yaml from azure.cli.core.application import APPLICATION, Configuration from azure.cli.core.commands import _update_command_definitions, BLACKLISTED_MODS from azure.cli.core.help_files import helps from azure.cli.core.commands.arm import add_id_parameters import azclishell.configuration as config APPLICATION.initialize(Configuration()) CMD_TABLE = APPLICATION.configuration.get_command_table() def install_modules(): for cmd in CMD_TABLE: CMD_TABLE[cmd].load_arguments() try: mods_ns_pkg = import_module('azure.cli.command_modules') installed_command_modules = [ modname for _, modname, _ in pkgutil.iter_modules(mods_ns_pkg.__path__) if modname not in BLACKLISTED_MODS ] except ImportError:
def verify_packages(built_packages_dir): all_modules = automation_path.get_all_module_paths() all_command_modules = automation_path.get_command_modules_paths( include_prefix=True) modules_missing_manifest_in = [ name for name, path in all_modules if not os.path.isfile(os.path.join(path, 'MANIFEST.in')) ] if modules_missing_manifest_in: print_heading( 'Error: The following modules are missing the MANIFEST.in file.') print(modules_missing_manifest_in) sys.exit(1) # STEP 1:: Validate the installation try: az_output = subprocess.check_output(['az', '--debug'], stderr=subprocess.STDOUT, universal_newlines=True) success = 'Error loading command module' not in az_output print(az_output, file=sys.stderr) except subprocess.CalledProcessError as err: success = False print(err, file=sys.stderr) if not success: print_heading('Error running the CLI!', f=sys.stderr) sys.exit(1) # STEP 2:: Run -h on each command print('Running --help on all commands.') from azure.cli.core.application import Configuration config = Configuration() all_commands = list(config.get_command_table()) command_results = [] p = multiprocessing.Pool(multiprocessing.cpu_count()) for i, res in enumerate( p.imap_unordered(run_help_on_command_without_err, all_commands, 10), 1): sys.stderr.write('{}/{} \t'.format(i, len(all_commands))) sys.stderr.flush() command_results.append(res) p.close() p.join() if not all(command_results): print_heading('Error running --help on commands in the CLI!', f=sys.stderr) sys.exit(1) print('OK.') # STEP 3:: Determine if any modules failed to install pip.utils.pkg_resources = imp.reload(pip.utils.pkg_resources) installed_command_modules = [ dist.key for dist in pip.get_installed_distributions(local_only=True) if dist.key.startswith(COMMAND_MODULE_PREFIX) ] print('Installed command modules', installed_command_modules) missing_modules = set([name for name, fullpath in all_command_modules]) - set(installed_command_modules) - \ EXCLUDE_MODULES if missing_modules: print_heading( 'Error: The following modules were not installed successfully', f=sys.stderr) print(missing_modules, file=sys.stderr) sys.exit(1) # STEP 4:: Verify the wheels that get produced print_heading('Verifying wheels...') invalid_wheels = [] for wheel_path in glob.glob(os.path.join(built_packages_dir, '*.whl')): # Verify all non-nspkg wheels if 'nspkg' not in wheel_path and not _valid_wheel(wheel_path): invalid_wheels.append(wheel_path) if invalid_wheels: print_heading('Error: The following wheels are invalid', f=sys.stderr) print(invalid_wheels, file=sys.stderr) print(VALID_WHEEL_HELP, file=sys.stderr) sys.exit(1) print_heading('Verified wheels successfully.') print_heading('OK')
def _test(cmd_line): argv = cmd_line.split() config = Configuration() config.get_command_table = lambda argv: cmd_table application = Application(config) return application.execute(argv[1:])
def verify_packages(built_packages_dir): all_modules = automation_path.get_all_module_paths() all_command_modules = automation_path.get_command_modules_paths(include_prefix=True) modules_missing_manifest_in = [name for name, path in all_modules if not os.path.isfile(os.path.join(path, 'MANIFEST.in'))] if modules_missing_manifest_in: print_heading('Error: The following modules are missing the MANIFEST.in file.') print(modules_missing_manifest_in) sys.exit(1) # STEP 1:: Validate the installation try: az_output = subprocess.check_output(['az', '--debug'], stderr=subprocess.STDOUT, universal_newlines=True) success = 'Error loading command module' not in az_output print(az_output, file=sys.stderr) except subprocess.CalledProcessError as err: success = False print(err, file=sys.stderr) if not success: print_heading('Error running the CLI!', f=sys.stderr) sys.exit(1) # STEP 2:: Run -h on each command print('Running --help on all commands.') from azure.cli.core.application import Configuration config = Configuration() all_commands = list(config.get_command_table()) command_results = [] p = multiprocessing.Pool(multiprocessing.cpu_count()) for i, res in enumerate(p.imap_unordered(run_help_on_command_without_err, all_commands, 10), 1): sys.stderr.write('{}/{} \t'.format(i, len(all_commands))) sys.stderr.flush() command_results.append(res) p.close() p.join() if not all(command_results): print_heading('Error running --help on commands in the CLI!', f=sys.stderr) sys.exit(1) print('OK.') # STEP 3:: Determine if any modules failed to install pip.utils.pkg_resources = imp.reload(pip.utils.pkg_resources) installed_command_modules = [dist.key for dist in pip.get_installed_distributions(local_only=True) if dist.key.startswith(COMMAND_MODULE_PREFIX)] print('Installed command modules', installed_command_modules) missing_modules = set([name for name, fullpath in all_command_modules]) - set(installed_command_modules) - \ EXCLUDE_MODULES if missing_modules: print_heading('Error: The following modules were not installed successfully', f=sys.stderr) print(missing_modules, file=sys.stderr) sys.exit(1) # STEP 4:: Verify the wheels that get produced print_heading('Verifying wheels...') invalid_wheels = [] for wheel_path in glob.glob(os.path.join(built_packages_dir, '*.whl')): # Verify all non-nspkg wheels if 'nspkg' not in wheel_path and not _valid_wheel(wheel_path): invalid_wheels.append(wheel_path) if invalid_wheels: print_heading('Error: The following wheels are invalid', f=sys.stderr) print(invalid_wheels, file=sys.stderr) print(VALID_WHEEL_HELP, file=sys.stderr) sys.exit(1) print_heading('Verified wheels successfully.') print_heading('OK')
parser = argparse.ArgumentParser(description='Command Table Parser') parser.add_argument('--commands', metavar='N', nargs='+', help='Filter by first level command (OR)') parser.add_argument('--params', metavar='N', nargs='+', help='Filter by parameters (OR)') args = parser.parse_args() cmd_set_names = args.commands param_names = args.params # ignore the params passed in now so they aren't used by the cli sys.argv = sys.argv[:1] config = Configuration([]) cmd_table = config.get_command_table() cmd_list = [ cmd_name for cmd_name in cmd_table.keys() if cmd_set_names is None or cmd_name.split()[0] in cmd_set_names ] results = [] if param_names: for name in cmd_list: cmd_name = [x for x in cmd_table.keys() if name == x][0] cmd_args = cmd_table[cmd_name]['arguments'] match = False for arg in cmd_args: if match: break
def verify_packages(): # tmp dir to store all the built packages built_packages_dir = tempfile.mkdtemp() all_modules = automation_path.get_all_module_paths() all_command_modules = automation_path.get_command_modules_paths(include_prefix=True) modules_missing_manifest_in = [name for name, path in all_modules if not os.path.isfile(os.path.join(path, 'MANIFEST.in'))] if modules_missing_manifest_in: print_heading('Error: The following modules are missing the MANIFEST.in file.') print(modules_missing_manifest_in) sys.exit(1) # STEP 1:: Build the packages for name, path in all_modules: build_package(path, built_packages_dir) # STEP 2:: Install the CLI and dependencies azure_cli_modules_path = next(path for name, path in all_modules if name == 'azure-cli') install_package(azure_cli_modules_path, 'azure-cli', built_packages_dir) # Install the remaining command modules for name, fullpath in all_command_modules: install_package(fullpath, name, built_packages_dir) # STEP 3:: Validate the installation try: az_output = subprocess.check_output(['az', '--debug'], stderr=subprocess.STDOUT, universal_newlines=True) success = 'Error loading command module' not in az_output print(az_output, file=sys.stderr) except subprocess.CalledProcessError as err: success = False print(err, file=sys.stderr) if not success: print_heading('Error running the CLI!', f=sys.stderr) sys.exit(1) # STEP 4:: Run -h on each command print('Running --help on all commands.') from azure.cli.core.application import Configuration config = Configuration() all_commands = list(config.get_command_table()) pool_size = 5 chunk_size = 10 command_results = [] p = multiprocessing.Pool(pool_size) prev_percent = 0 for i, res in enumerate(p.imap_unordered(run_help_on_command_without_err, all_commands, chunk_size), 1): command_results.append(res) cur_percent = int((i/len(all_commands))*100) if cur_percent != prev_percent: print('{}% complete'.format(cur_percent), file=sys.stderr) prev_percent = cur_percent p.close() p.join() if not all(command_results): print_heading('Error running --help on commands in the CLI!', f=sys.stderr) sys.exit(1) print('OK.') # STEP 5:: Determine if any modules failed to install pip.utils.pkg_resources = imp.reload(pip.utils.pkg_resources) installed_command_modules = [dist.key for dist in pip.get_installed_distributions(local_only=True) if dist.key.startswith(COMMAND_MODULE_PREFIX)] print('Installed command modules', installed_command_modules) missing_modules = \ set([name for name, fullpath in all_command_modules]) - set(installed_command_modules) if missing_modules: print_heading('Error: The following modules were not installed successfully', f=sys.stderr) print(missing_modules, file=sys.stderr) sys.exit(1) # STEP 6:: Verify the wheels that get produced print_heading('Verifying wheels...') invalid_wheels = [] for wheel_path in glob.glob(os.path.join(built_packages_dir, '*.whl')): # Verify all non-nspkg wheels if 'nspkg' not in wheel_path and not _valid_wheel(wheel_path): invalid_wheels.append(wheel_path) if invalid_wheels: print_heading('Error: The following wheels are invalid', f=sys.stderr) print(invalid_wheels, file=sys.stderr) print(VALID_WHEEL_HELP, file=sys.stderr) sys.exit(1) print_heading('Verified wheels successfully.') print_heading('OK')