def test_codegen_success(codegen_gen_py_inputs, popen_helper): gen_py = codegen_gen_py_inputs stderr_ret = ( '[main] INFO io.swagger.parser.Swagger20Parser - reading from' ' swagger.json' '[main] INFO io.swagger.codegen.AbstractGenerator - writing file' ' .dvp-gen-output/swagger_server/generated/test_gen_file.py') popen_helper.set_popen_output(0, stderr=stderr_ret) codegen.generate_python(gen_py.name, gen_py.source_dir, gen_py.plugin_content_dir, gen_py.schema_dict) assert popen_helper.stdout_input == subprocess.PIPE assert popen_helper.stderr_input == subprocess.PIPE assert os.path.exists(popen_helper.swagger_file) assert popen_helper.package_name == codegen.CODEGEN_PACKAGE assert popen_helper.module_name == codegen.CODEGEN_MODULE expected_output_dir = os.path.join(gen_py.plugin_content_dir, const.OUTPUT_DIR_NAME) assert popen_helper.output_dir == expected_output_dir # Validate that the "generated" file were copied. util_file = os.path.join(gen_py.source_dir, codegen.CODEGEN_PACKAGE, 'util.py') init_file = os.path.join(gen_py.source_dir, codegen.CODEGEN_PACKAGE, '__init__.py') gen_file = os.path.join(gen_py.source_dir, codegen.CODEGEN_PACKAGE, codegen.CODEGEN_MODULE, TestCodegen.TEST_GEN_FILE) assert os.path.exists(util_file) assert os.path.exists(init_file) assert os.path.exists(gen_file)
def init(root, ingestion_strategy, name, host_type): """ Creates a valid plugin in a given directory. The plugin created will be able to be built and uploaded immediately. This command is designed to help novice plugin developers. There are decisions made, such as what the entry point file looks like, in order to make it easier for authors to get started. The command is expected to be used by experienced developers, but they are not the primary audience. Args: root (str): The path of the plugin's root directory ingestion_strategy (str): The plugin type. Either DIRECT or STAGED name (str): The name of the plugin to display. host_type (list of str): The host type supported by the plugin """ logger.info('Initializing directory: %s', root) logger.debug( 'init parameters: %s', { 'Root': root, 'Ingestion Strategy': ingestion_strategy, 'Name': name, 'Host Types': host_type }) # Files paths based on 'root' to be used throughout src_dir_path = os.path.join(root, DEFAULT_SRC_DIRECTORY) config_file_path = os.path.join(root, DEFAULT_PLUGIN_CONFIG_FILE) schema_file_path = os.path.join(root, DEFAULT_SCHEMA_FILE) entry_point_file_path = os.path.join(src_dir_path, DEFAULT_ENTRY_POINT_FILE) # Make sure nothing is overwritten file_util.validate_paths_do_not_exist(config_file_path, schema_file_path, src_dir_path) # Make an UUID for the plugin plugin_id = str(uuid.uuid4()) logger.debug("Using %s as the plugin id.", plugin_id) # if name is not provided the name will be equal to plugin_id. if not name: name = plugin_id # # Some magic to get the yaml module to maintain the order when dumping # an OrderedDict # yaml.add_representer( OrderedDict, lambda dumper, data: dumper.represent_mapping( 'tag:yaml.org,2002:map', data.items())) logger.debug("Using %s as the plugin's entry point.", DEFAULT_ENTRY_POINT) try: # # Create the source directory. We've already validated that this # directory doesn't exist. # logger.info('Creating source directory at %r.', src_dir_path) os.mkdir(src_dir_path) # # Copy the schema file template into the root directory. The schema # file is static and doesn't depend on any input so it can just be # copied. By copying we can also avoid dealing with ordering issues. # logger.info('Writing schema file at %s.', schema_file_path) shutil.copyfile(SCHEMA_TEMPLATE_PATH, schema_file_path) # Read and valida the schema file result = plugin_util.read_and_validate_schema_file( schema_file_path, False) # Generate the definitions based on the schema file codegen.generate_python(name, src_dir_path, os.path.dirname(config_file_path), result.plugin_schemas) # # Create the plugin config file. The config file relies on input from # the user, so it's easier to deal with a dictionary than a file. This # must be done only after both the schema file and src dir have been # created since the paths need to exist. # logger.info('Writing config file at %s.', config_file_path) with open(config_file_path, 'w+') as f: config = _get_default_plugin_config(plugin_id, ingestion_strategy, name, DEFAULT_ENTRY_POINT, DEFAULT_SRC_DIRECTORY, DEFAULT_SCHEMA_FILE, host_type) yaml.dump(config, f, default_flow_style=False) # # Copy the entry point template into the root directory. The entry # point file is static and doesn't depend on any input so it can just # be copied. # logger.info('Writing entry file at %s.', entry_point_file_path) with open(entry_point_file_path, 'w+') as f: entry_point_content = _get_entry_point_contents( plugin_id, ingestion_strategy, host_type) f.write(entry_point_content) except Exception as e: logger.debug('Attempting to cleanup after failure. %s', e) file_util.delete_paths(config_file_path, schema_file_path, src_dir_path) raise exceptions.UserError( 'Failed to initialize plugin directory {}: {}.'.format(root, e))
def build(plugin_config, upload_artifact, generate_only, skip_id_validation): """This builds the plugin using the configurations provided in config yaml file provided as input. It reads schemas and source code from the files given in yaml file, generates an encoded string of zip of source code, prepares plugin json output file that can be used by upload command later. Args: plugin_config: Plugin config file used for building plugin. upload_artifact: The file to which output of build is written to. generate_only: Only generate python classes from schema definitions. skip_id_validation: Skip validation of the plugin id. """ logger.debug( "Build parameters include plugin_config: %s, upload_artifact: %s," " generate_only: %s", plugin_config, upload_artifact, generate_only, ) # Read content of the plugin config file provided and perform validations logger.info("Reading and validating plugin config file %s", plugin_config) try: result = plugin_util.read_and_validate_plugin_config_file( plugin_config, not generate_only, False, skip_id_validation) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) plugin_config_content = result.plugin_config_content logger.debug("plugin config file content is : %s", result.plugin_config_content) schema_file = plugin_util.get_schema_file_path( plugin_config, plugin_config_content["schemaFile"]) # Read schemas from the file provided in the config and validate them logger.info("Reading and validating schemas from %s", schema_file) try: result = plugin_util.read_and_validate_schema_file( schema_file, not generate_only) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) schemas = result.plugin_schemas logger.debug("schemas found: %s", schemas) # Resolve the paths for source directory and schema file src_dir = file_util.get_src_dir_path(plugin_config, plugin_config_content["srcDir"]) logger.debug("Source directory path resolved is %s", src_dir) # # Call directly into codegen to generate the python classes and make sure # the ones we zip up are up to date with the schemas. # try: codegen.generate_python( plugin_config_content["name"], src_dir, os.path.dirname(plugin_config), schemas, ) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) if generate_only: # # If the generate_only flag is set then just return after generation # has happened. # logger.info("Generating python code only. Skipping artifact build.") return # # Validate the plugin config content by importing the module # and check the entry point as well. Returns a manifest on # successful validation. # try: result = plugin_util.get_plugin_manifest(plugin_config, plugin_config_content, not generate_only, skip_id_validation) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) plugin_manifest = {} if result: plugin_manifest = result.plugin_manifest if result.warnings: warning_msg = util_classes.MessageUtils.warning_msg( result.warnings) logger.warn("{}\n{} Warning(s). {} Error(s).".format( warning_msg, len(result.warnings["warning"]), 0)) # Prepare the output artifact. try: plugin_output = prepare_upload_artifact(plugin_config_content, src_dir, schemas, plugin_manifest) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) # Write it to upload_artifact as json. try: generate_upload_artifact(upload_artifact, plugin_output) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) logger.info("Successfully generated artifact file at %s.", upload_artifact) logger.warn("\nBUILD SUCCESSFUL.")
def build(plugin_config, upload_artifact, generate_only, skip_id_validation, local_vsdk_root=None): """This builds the plugin using the configurations provided in config yaml file provided as input. It reads schemas and source code from the files given in yaml file, generates an encoded string of zip of source code, prepares plugin json output file that can be used by upload command later. Args: plugin_config: Plugin config file used for building plugin. upload_artifact: The file to which output of build is written to. generate_only: Only generate python classes from schema definitions. skip_id_validation: Skip validation of the plugin id. local_vsdk_root: The local path to the root of the Virtualization SDK repository. """ logger.debug( 'Build parameters include plugin_config: %s, upload_artifact: %s,' ' generate_only: %s', plugin_config, upload_artifact, generate_only) if local_vsdk_root: local_vsdk_root = os.path.expanduser(local_vsdk_root) # Read content of the plugin config file provided and perform validations logger.info('Validating plugin config file %s', plugin_config) try: result = plugin_util.validate_plugin_config_file( plugin_config, not generate_only, skip_id_validation) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) plugin_config_content = result.plugin_config_content logger.debug('plugin config file content is : %s', result.plugin_config_content) schema_file = plugin_util.get_schema_file_path( plugin_config, plugin_config_content['schemaFile']) # Read schemas from the file provided in the config and validate them logger.info('Validating schemas from %s', schema_file) try: result = plugin_util.validate_schema_file(schema_file, not generate_only) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) schemas = result.plugin_schemas logger.debug('schemas found: %s', schemas) # Resolve the paths for source directory and schema file src_dir = file_util.get_src_dir_path(plugin_config, plugin_config_content['srcDir']) logger.debug('Source directory path resolved is %s', src_dir) # # Call directly into codegen to generate the python classes and make sure # the ones we zip up are up to date with the schemas. # try: codegen.generate_python(plugin_config_content['name'], src_dir, os.path.dirname(plugin_config), schemas) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) if generate_only: # # If the generate_only flag is set then just return after generation # has happened. # logger.info('Generating python code only. Skipping artifact build.') return # # Validate the plugin config content by importing the module # and check the entry point as well. Returns a manifest on # successful validation. # try: result = plugin_util.get_plugin_manifest(plugin_config, plugin_config_content, not generate_only, skip_id_validation) except (exceptions.UserError, exceptions.SDKToolingError) as err: raise exceptions.BuildFailedError(err) plugin_manifest = {} if result: plugin_manifest = result.plugin_manifest # # Setup a build directory for the plugin in its root. Dependencies are # packaged with the plugin and should not be installed into the original # source directory. # root = os.path.dirname(plugin_config) build_dir = os.path.join(root, BUILD_DIR_NAME) build_src_dir = os.path.join(build_dir, os.path.basename(src_dir)) # Copy everything from the source directory into the build directory. file_util.clean_copy(src_dir, build_src_dir) # Install dependencies in the plugin's source root in the build directory. plugin_dependency_util.install_deps(build_src_dir, local_vsdk_root=local_vsdk_root) # Prepare the output artifact. try: plugin_output = prepare_upload_artifact(plugin_config_content, build_src_dir, schemas, plugin_manifest) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) # Write it to upload_artifact as json. try: generate_upload_artifact(upload_artifact, plugin_output) except exceptions.UserError as err: raise exceptions.BuildFailedError(err) logger.info('Successfully generated artifact file at %s.', upload_artifact) logger.warn('\nBUILD SUCCESSFUL.')