def test_log_subprocess_Popen_with_logging(monkeypatch): logger = _test_logger() verbose.push_verbose_logger(logger) try: recorded = dict(args=(), kwargs=()) def mock_Popen(*args, **kwargs): recorded['args'] = args recorded['kwargs'] = kwargs monkeypatch.setattr('subprocess.Popen', mock_Popen) logged_subprocess.Popen(['a', 'b'], foo='bar') assert recorded == dict(args=(), kwargs=dict(args=['a', 'b'], foo='bar')) assert logger.messages == ['$ a b'] finally: verbose.pop_verbose_logger()
def _parse_args_and_run_subcommand(argv): parser = ArgumentParser( prog="anaconda-project", description="Actions on projects (runnable projects).") subparsers = parser.add_subparsers(help="Sub-commands") parser.add_argument('-v', '--version', action='version', version=version) parser.add_argument('--verbose', action='store_true', default=False, help="show verbose debugging details") def add_directory_arg(preset): preset.add_argument( '--directory', metavar='PROJECT_DIR', default='.', help= "Project directory containing anaconda-project.yml (defaults to current directory)" ) def add_env_spec_arg(preset): preset.add_argument( '--env-spec', metavar='ENVIRONMENT_SPEC_NAME', default=None, action='store', help="An environment spec name from anaconda-project.yml") def add_prepare_args(preset, include_command=True): add_directory_arg(preset) add_env_spec_arg(preset) all_supported_modes = list(_all_ui_modes) # we don't support "ask about every single thing" mode yet. all_supported_modes.remove(UI_MODE_TEXT_ASK_QUESTIONS) preset.add_argument('--mode', metavar='MODE', default=UI_MODE_TEXT_DEVELOPMENT_DEFAULTS_OR_ASK, choices=_all_ui_modes, action='store', help="One of " + ", ".join(_all_ui_modes)) if include_command: preset.add_argument( '--command', metavar='COMMAND_NAME', default=None, action='store', help= "A command name from anaconda-project.yml (env spec for this command will be used)" ) def add_env_spec_name_arg(preset, required): preset.add_argument( '-n', '--name', metavar='ENVIRONMENT_SPEC_NAME', required=required, action='store', help="Name of the environment spec from anaconda-project.yml") preset = subparsers.add_parser( 'init', help="Initialize a directory with default project configuration") add_directory_arg(preset) preset.add_argument( '--with-anaconda-package', action='store_true', help="Add the 'anaconda' metapackage to the packages list.", default=None) preset.add_argument( '--empty-environment', action='store_true', help= "[DEPRECATED] Do not add the default package set to the environment.", default=None) preset.add_argument('-y', '--yes', action='store_true', help="Assume yes to all confirmation prompts", default=None) preset.set_defaults(main=init.main) preset = subparsers.add_parser( 'run', help="Run the project, setting up requirements first") add_prepare_args(preset, include_command=False) preset.add_argument('command', metavar='COMMAND_NAME', default=None, nargs='?', help="A command name from anaconda-project.yml") preset.add_argument('extra_args_for_command', metavar='EXTRA_ARGS_FOR_COMMAND', default=None, nargs=REMAINDER) preset.set_defaults(main=run.main) preset = subparsers.add_parser( 'prepare', help="Set up the project requirements, but does not run the project") preset.add_argument('--all', action='store_true', help="Prepare all environments", default=None) preset.add_argument('--refresh', action='store_true', help='Remove and recreate the environment', default=None) add_prepare_args(preset) preset.set_defaults(main=prepare.main) preset = subparsers.add_parser( 'clean', help= "Removes generated state (stops services, deletes environment files, etc)" ) add_directory_arg(preset) preset.set_defaults(main=clean.main) if not anaconda_project._beta_test_mode: preset = subparsers.add_parser( 'activate', help= "Set up the project and output shell export commands reflecting the setup" ) add_prepare_args(preset) preset.set_defaults(main=activate.main) preset = subparsers.add_parser( 'archive', help= "Create a .zip, .tar.gz, or .tar.bz2 archive with project files in it") add_directory_arg(preset) preset.add_argument('filename', metavar='ARCHIVE_FILENAME') preset.add_argument('--pack-envs', action='store_true', help='Experimental: Package env_specs into the archive' ' using conda-pack') preset.set_defaults(main=archive.main) preset = subparsers.add_parser( 'unarchive', help= "Unpack a .zip, .tar.gz, or .tar.bz2 archive with project files in it") preset.add_argument('filename', metavar='ARCHIVE_FILENAME') preset.add_argument('directory', metavar='DESTINATION_DIRECTORY', default=None, nargs='?') preset.set_defaults(main=unarchive.main) preset = subparsers.add_parser('upload', help="Upload the project to Anaconda Cloud") add_directory_arg(preset) preset.add_argument('-p', '--private', action='store_true', help="Upload a private project", default=None) preset.add_argument('-s', '--site', metavar='SITE', help='Select site to use') preset.add_argument( '-t', '--token', metavar='TOKEN', help='Auth token or a path to a file containing a token') preset.add_argument('-u', '--user', metavar='USERNAME', help='User account, defaults to the current user') preset.add_argument( '--suffix', metavar='SUFFIX', help='Project archive suffix (.tar.gz, .tar.bz2, .zip)', default='.tar.bz2', choices=['.tar.gz', '.tar.bz2', '.zip']) preset.set_defaults(main=upload.main) preset = subparsers.add_parser( 'download', help="Download the project from Anaconda Cloud") add_directory_arg(preset) preset.add_argument( 'project', help= 'The project to download as <username>/<projectname>. If <projectname>' + 'has spaces inclose everything in quotes "<username>/<project name>".' + 'If specified as <projectname> then the logged-in username is used.') preset.add_argument('--no-unpack', action='store_true', help='Do not unpack the project archive.') preset.add_argument( '--parent_dir', default=None, help= 'Download archive to specific directory, otherwise downloaded to current working directory.' ) preset.add_argument('-s', '--site', metavar='SITE', help='Select site to use') preset.add_argument( '-t', '--token', metavar='TOKEN', help='Auth token or a path to a file containing a token') preset.add_argument('-u', '--user', metavar='USERNAME', help='User account, defaults to the current user') preset.set_defaults(main=download.main) preset = subparsers.add_parser( 'dockerize', help="Build a docker image of the Anaconda Project.") add_directory_arg(preset) preset.add_argument( '-t', '--tag', default=None, help='Tag of the output docker image in the format name:tag. ' 'Default: "<project-name>:latest", where <project-name> is taken from ' 'the name tag in the anaconda-project.yml file.') preset.add_argument( '--command', default='default', help= 'Select the command to run. If unspecified the "default" command is run.\nThe default command ' 'is defined as either the command named "default" (if any) or (otherwise) ' 'the first command specified in the anaconda-project.yml file.') preset.add_argument('--builder-image', default='{}:latest'.format(DEFAULT_BUILDER_IMAGE), help='The s2i builder image') preset.add_argument( 'build_args', default=None, nargs="*", help='Optional arguments for the s2i build command. ' 'See the output of "s2i build --help" for the available arguments. ' 'It is recommended to include a -- separator before supplying these arguments.' ) preset.set_defaults(main=dockerize.main) preset = subparsers.add_parser( 'add-variable', help="Add a required environment variable to the project") add_env_spec_arg(preset) preset.add_argument('vars_to_add', metavar='VARS_TO_ADD', default=None, nargs=REMAINDER) preset.add_argument('--default', metavar='DEFAULT_VALUE', default=None, help='Default value if environment variable is unset') add_directory_arg(preset) preset.set_defaults(main=variable_commands.main_add) preset = subparsers.add_parser( 'remove-variable', help="Remove an environment variable from the project") add_env_spec_arg(preset) add_directory_arg(preset) preset.add_argument('vars_to_remove', metavar='VARS_TO_REMOVE', default=None, nargs=REMAINDER) preset.set_defaults(main=variable_commands.main_remove) preset = subparsers.add_parser('list-variables', help="List all variables on the project") add_env_spec_arg(preset) add_directory_arg(preset) preset.set_defaults(main=variable_commands.main_list) preset = subparsers.add_parser( 'set-variable', help="Set an environment variable value in anaconda-project-local.yml") add_env_spec_arg(preset) preset.add_argument('vars_and_values', metavar='VARS_AND_VALUES', default=None, nargs=REMAINDER) add_directory_arg(preset) preset.set_defaults(main=variable_commands.main_set) preset = subparsers.add_parser( 'unset-variable', help= "Unset an environment variable value from anaconda-project-local.yml") add_env_spec_arg(preset) add_directory_arg(preset) preset.add_argument('vars_to_unset', metavar='VARS_TO_UNSET', default=None, nargs=REMAINDER) preset.set_defaults(main=variable_commands.main_unset) preset = subparsers.add_parser( 'add-download', help="Add a URL to be downloaded before running commands") add_directory_arg(preset) add_env_spec_arg(preset) preset.add_argument('filename_variable', metavar='ENV_VAR_FOR_FILENAME', default=None) preset.add_argument('download_url', metavar='DOWNLOAD_URL', default=None) preset.add_argument( '--filename', help="The name to give the file/folder after downloading it", default=None) preset.add_argument('--hash-algorithm', help="Defines which hash algorithm to use", default=None, choices=_hash_algorithms) preset.add_argument( '--hash-value', help="The expected checksum hash of the downloaded file", default=None) preset.set_defaults(main=download_commands.main_add) preset = subparsers.add_parser( 'remove-download', help="Remove a download from the project and from the filesystem") add_directory_arg(preset) add_env_spec_arg(preset) preset.add_argument('filename_variable', metavar='ENV_VAR_FOR_FILENAME', default=None) preset.set_defaults(main=download_commands.main_remove) preset = subparsers.add_parser('list-downloads', help="List all downloads on the project") add_directory_arg(preset) add_env_spec_arg(preset) preset.set_defaults(main=download_commands.main_list) service_types = RequirementsRegistry().list_service_types() service_choices = list(map(lambda s: s.name, service_types)) def add_service_variable_name(preset): preset.add_argument('--variable', metavar='ENV_VAR_FOR_SERVICE_ADDRESS', default=None) preset = subparsers.add_parser( 'add-service', help="Add a service to be available before running commands") add_directory_arg(preset) add_env_spec_arg(preset) add_service_variable_name(preset) preset.add_argument('service_type', metavar='SERVICE_TYPE', default=None, choices=service_choices) preset.set_defaults(main=service_commands.main_add) preset = subparsers.add_parser('remove-service', help="Remove a service from the project") add_directory_arg(preset) add_env_spec_arg(preset) preset.add_argument('variable', metavar='SERVICE_REFERENCE', default=None) preset.set_defaults(main=service_commands.main_remove) preset = subparsers.add_parser('list-services', help="List services present in the project") add_directory_arg(preset) add_env_spec_arg(preset) preset.set_defaults(main=service_commands.main_list) def add_package_args(preset): preset.add_argument('--pip', action='store_true', help='Install the requested packages using pip.') preset.add_argument('-c', '--channel', metavar='CHANNEL', action='append', help='Channel to search for packages') preset.add_argument('packages', metavar='PACKAGES', default=None, nargs=REMAINDER) preset = subparsers.add_parser( 'add-env-spec', help="Add a new environment spec to the project") add_directory_arg(preset) add_package_args(preset) add_env_spec_name_arg(preset, required=True) preset.set_defaults(main=environment_commands.main_add) preset = subparsers.add_parser( 'remove-env-spec', help="Remove an environment spec from the project") add_directory_arg(preset) add_env_spec_name_arg(preset, required=True) preset.set_defaults(main=environment_commands.main_remove) preset = subparsers.add_parser( 'list-env-specs', help="List all environment specs for the project") add_directory_arg(preset) preset.set_defaults(main=environment_commands.main_list_env_specs) preset = subparsers.add_parser( 'export-env-spec', help="Save an environment spec as a conda environment file") add_directory_arg(preset) add_env_spec_name_arg(preset, required=False) preset.add_argument('filename', metavar='ENVIRONMENT_FILE') preset.set_defaults(main=environment_commands.main_export) preset = subparsers.add_parser( 'lock', help="Lock all packages at their current versions") add_directory_arg(preset) add_env_spec_name_arg(preset, required=False) preset.set_defaults(main=environment_commands.main_lock) preset = subparsers.add_parser('unlock', help="Remove locked package versions") add_directory_arg(preset) add_env_spec_name_arg(preset, required=False) preset.set_defaults(main=environment_commands.main_unlock) preset = subparsers.add_parser( 'update', help="Update all packages to their latest versions") add_directory_arg(preset) add_env_spec_name_arg(preset, required=False) preset.set_defaults(main=environment_commands.main_update) preset = subparsers.add_parser( 'add-packages', help="Add packages to one or all project environments") add_directory_arg(preset) add_env_spec_arg(preset) add_package_args(preset) preset.set_defaults(main=environment_commands.main_add_packages) preset = subparsers.add_parser( 'remove-packages', help="Remove packages from one or all project environments") add_directory_arg(preset) add_env_spec_arg(preset) preset.add_argument('--pip', action='store_true', help='Uninstall the requested packages using pip.') preset.add_argument('packages', metavar='PACKAGE_NAME', default=None, nargs='+') preset.set_defaults(main=environment_commands.main_remove_packages) preset = subparsers.add_parser( 'list-packages', help="List packages for an environment on the project") add_directory_arg(preset) add_env_spec_arg(preset) preset.set_defaults(main=environment_commands.main_list_packages) def add_platforms_list(preset): preset.add_argument('platforms', metavar='PLATFORM_NAME', default=None, nargs='+') preset = subparsers.add_parser( 'add-platforms', help="Add platforms to one or all project environments") add_directory_arg(preset) add_env_spec_arg(preset) add_platforms_list(preset) preset.set_defaults(main=environment_commands.main_add_platforms) preset = subparsers.add_parser( 'remove-platforms', help="Remove platforms from one or all project environments") add_directory_arg(preset) add_env_spec_arg(preset) add_platforms_list(preset) preset.set_defaults(main=environment_commands.main_remove_platforms) preset = subparsers.add_parser( 'list-platforms', help="List platforms for an environment on the project") add_directory_arg(preset) add_env_spec_arg(preset) preset.set_defaults(main=environment_commands.main_list_platforms) def add_command_name_arg(preset): preset.add_argument('name', metavar="NAME", help="Command name used to invoke it") preset = subparsers.add_parser('add-command', help="Add a new command to the project") add_directory_arg(preset) command_choices = list(ALL_COMMAND_TYPES) + ['ask'] command_choices.remove( "conda_app_entry") # conda_app_entry is sort of silly and may go away preset.add_argument('--type', action="store", choices=command_choices, help="Command type to add") add_command_name_arg(preset) add_env_spec_arg(preset) preset.add_argument( '--supports-http-options', dest='supports_http_options', action="store_true", help="The command supports project's HTTP server options") preset.add_argument( '--no-supports-http-options', dest='supports_http_options', action="store_false", help=" The command does not support project's HTTP server options") preset.add_argument('command', metavar="COMMAND", help="Command line or app filename to add") preset.set_defaults(main=command_commands.main, supports_http_options=None) preset = subparsers.add_parser('remove-command', help="Remove a command from the project") add_directory_arg(preset) add_command_name_arg(preset) preset.set_defaults(main=command_commands.main_remove) preset = subparsers.add_parser( 'list-default-command', help="List only the default command on the project") add_directory_arg(preset) preset.set_defaults(main=command_commands.main_default) preset = subparsers.add_parser('list-commands', help="List the commands on the project") add_directory_arg(preset) preset.set_defaults(main=command_commands.main_list) # argparse doesn't do this for us for whatever reason if len(argv) < 2: print("Must specify a subcommand.", file=sys.stderr) parser.print_usage(file=sys.stderr) return 2 # argparse exits with 2 on bad args, copy that try: args = parser.parse_args(argv[1:]) except SystemExit as e: return e.code if args.verbose: logger = (logging.getLoggerClass())(name="anaconda_project_verbose") logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(stream=sys.stderr) logger.addHandler(handler) push_verbose_logger(logger) try: # '--directory' is used for most subcommands; for unarchive, # args.directory is positional and may be None if 'directory' in args and args.directory is not None: args.directory = os.path.abspath(args.directory) return args.main(args) finally: if args.verbose: pop_verbose_logger()