def test_log_path(): # use log base path log_base_path = '/some/path'.replace('/', os.sep) set_default_log_path(base_path=log_base_path) assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use log base path if environment variable is not set log_base_path_env_var = 'TEST_COLCON_LOG_BASE_PATH' set_default_log_path(base_path=log_base_path, env_var=log_base_path_env_var) assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use explicitly passed log base path even if environment variable is set with EnvironmentContext(**{log_base_path_env_var: '/not/used'}): assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use environment variable when set and no base path passed log_base_path = '/other/path'.replace('/', os.sep) set_default_log_path(base_path=None, env_var=log_base_path_env_var) with EnvironmentContext(**{log_base_path_env_var: log_base_path}): assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use specific subdirectory subdirectory = 'sub' set_default_log_path(base_path=log_base_path, env_var=log_base_path_env_var, subdirectory=subdirectory) assert isinstance(get_log_path(), Path) assert get_log_path() == Path(log_base_path) / subdirectory
def test_create_log_path_race(): # check race if log path is created at the same time subdirectory = 'sub' with TemporaryDirectory(prefix='test_colcon_') as log_path: log_path = Path(log_path) set_default_log_path(base_path=log_path, subdirectory=subdirectory) # spawn thread which hold the lock for some time def hold_lock_for_some_time(): with location._create_log_path_lock: sleep(1) (log_path / subdirectory).mkdir() Thread(target=hold_lock_for_some_time).start() with patch('os.makedirs') as makedirs: makedirs.side_effect = AssertionError('should not be called') create_log_path('verb') # no latest symlink is being created either assert not (log_path / 'latest').exists()
def test_log_path(): # use log base path log_base_path = '/some/path'.replace('/', os.sep) set_default_log_path(base_path=log_base_path) assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use log base path if environment variable is not set log_base_path_env_var = 'TEST_COLCON_LOG_BASE_PATH' set_default_log_path( base_path=log_base_path, env_var=log_base_path_env_var) assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use environment variable when set log_base_path = '/other/path'.replace('/', os.sep) with EnvironmentContext(**{log_base_path_env_var: log_base_path}): assert isinstance(get_log_path(), Path) assert str(get_log_path().parent) == log_base_path # use specific subdirectory subdirectory = 'sub' with patch('colcon_core.location.logger.info') as info: set_default_log_path( base_path=log_base_path, env_var=log_base_path_env_var, subdirectory=subdirectory) assert isinstance(get_log_path(), Path) assert get_log_path() == Path(log_base_path) / subdirectory info.assert_called_once_with( "Using log path '{log_base_path}/{subdirectory}'" .format_map(locals()).replace('/', os.sep))
def _main(*, command_name, argv): global colcon_logger # default log level colcon_logger.setLevel(logging.WARNING) set_logger_level_from_env( colcon_logger, '{command_name}_LOG_LEVEL'.format_map(locals()).upper()) colcon_logger.debug( 'Command line arguments: {argv}' .format(argv=argv if argv is not None else sys.argv)) # set default locations for config files set_default_config_path( path=( Path('~') / '.{command_name}'.format_map(locals())).expanduser(), env_var='{command_name}_HOME'.format_map(locals()).upper()) parser = create_parser('colcon_core.environment_variable') verb_extensions = get_verb_extensions() # add subparsers for all verb extensions but without arguments for now subparser = create_subparser( parser, command_name, verb_extensions, attribute='verb_name') verb_parsers = add_parsers_without_arguments( parser, subparser, verb_extensions, attribute='verb_name') with SuppressUsageOutput([parser] + list(verb_parsers.values())): known_args, _ = parser.parse_known_args(args=argv) # add the arguments for the requested verb if known_args.verb_name: add_parser_arguments(known_args.verb_parser, known_args.verb_extension) args = parser.parse_args(args=argv) context = CommandContext(command_name=command_name, args=args) if args.log_level: colcon_logger.setLevel(args.log_level) colcon_logger.debug( 'Parsed command line arguments: {args}'.format_map(locals())) # error: no verb provided if args.verb_name is None: print(parser.format_usage()) return 'Error: No verb provided' # set default locations for log files now = datetime.datetime.now() now_str = str(now)[:-7].replace(' ', '_').replace(':', '-') set_default_log_path( base_path=args.log_base, env_var='{command_name}_LOG_PATH'.format_map(locals()).upper(), subdirectory='{args.verb_name}_{now_str}'.format_map(locals())) # add a file handler writing all levels if logging isn't disabled log_path = get_log_path() if log_path is not None: create_log_path(args.verb_name) handler = add_file_handler( colcon_logger, log_path / 'logger_all.log') # write previous log messages to the file handler log_record = colcon_logger.makeRecord( colcon_logger.name, logging.DEBUG, __file__, 0, 'Command line arguments: {argv}' .format(argv=argv if argv is not None else sys.argv), None, None) handler.handle(log_record) log_record = colcon_logger.makeRecord( colcon_logger.name, logging.DEBUG, __file__, 0, 'Parsed command line arguments: {args}'.format_map(locals()), None, None) handler.handle(log_record) # invoke verb return verb_main(context, colcon_logger)
def test_create_log_path(): # no need to create a directory if the path already exists log_path = Path(os.getcwd()) set_default_log_path( base_path=log_path.parent, subdirectory=log_path.name) with patch('os.makedirs') as makedirs: makedirs.side_effect = AssertionError('should not be called') create_log_path('verb') # no latest symlink is being created either assert not (log_path.parent / 'latest').exists() subdirectory = 'sub' with TemporaryDirectory(prefix='test_colcon_') as log_path: log_path = Path(log_path) # create a directory and symlink when the path doesn't exist set_default_log_path(base_path=log_path, subdirectory=subdirectory) with patch('os.makedirs', wraps=os.makedirs) as makedirs: create_log_path('verb') makedirs.assert_called_once_with( str(log_path / subdirectory), exist_ok=True) assert (log_path / subdirectory).exists() # skip all symlink tests on Windows for now if sys.platform == 'win32': return # check that `latest_verb` was created and points to the subdirectory assert (log_path / 'latest_verb').is_symlink() assert (log_path / 'latest_verb').resolve() == \ (log_path / subdirectory).resolve() # check that `latest` was created and points to the subdirectory assert (log_path / 'latest').is_symlink() assert (log_path / 'latest').resolve() == \ (log_path / subdirectory).resolve() # create directory but correct latest symlink already exists (log_path / subdirectory).rmdir() create_log_path('verb') assert (log_path / subdirectory).exists() assert (log_path / 'latest').is_symlink() assert (log_path / 'latest').resolve() == \ (log_path / subdirectory).resolve() # create directory and update latest symlink subdirectory = 'other_sub' set_default_log_path(base_path=log_path, subdirectory=subdirectory) create_log_path('verb') assert (log_path / subdirectory).exists() assert (log_path / 'latest').is_symlink() assert (log_path / 'latest').resolve() == \ (log_path / subdirectory).resolve() # create directory but latest is not a symlink (log_path / subdirectory).rmdir() (log_path / 'latest').unlink() (log_path / 'latest').mkdir() create_log_path('verb') assert (log_path / subdirectory).exists() assert not (log_path / 'latest').is_symlink()
def main(*, command_name='colcon', argv=None): """ Execute the main logic of the command. The overview of the process: * Configure logging level based on an environment variable * Configure the configuration path * Create the argument parser * Document all environment variables * Decorate the parsers with additional functionality * Add the available verbs and their arguments * Configure logging level based on an arguments * Create an invocation specific log directory * Invoke the logic of the selected verb (if applicable) :param str command_name: The name of the command invoked :param list argv: The list of arguments :returns: The return code """ global colcon_logger # default log level colcon_logger.setLevel(logging.WARN) set_logger_level_from_env( colcon_logger, '{command_name}_LOG_LEVEL'.format_map(locals()).upper()) colcon_logger.debug('Command line arguments: {argv}'.format( argv=argv if argv is not None else sys.argv)) # set default locations for config files set_default_config_path( path=(Path('~') / '.{command_name}'.format_map(locals())).expanduser(), env_var='{command_name}_HOME'.format_map(locals()).upper()) parser = create_parser('colcon_core.environment_variable') verb_extensions = get_verb_extensions() # add subparsers for all verb extensions but without arguments for now subparser = create_subparser(parser, command_name, verb_extensions, attribute='verb_name') verb_parsers = add_parsers_without_arguments(parser, subparser, verb_extensions, attribute='verb_name') with SuppressUsageOutput([parser] + list(verb_parsers.values())): known_args, _ = parser.parse_known_args(args=argv) # add the arguments for the requested verb if known_args.verb_name: add_parser_arguments(known_args.verb_parser, known_args.verb_extension) args = parser.parse_args(args=argv) context = CommandContext(command_name=command_name, args=args) if args.log_level: colcon_logger.setLevel(args.log_level) colcon_logger.debug('Parsed command line arguments: {args}'.format_map( locals())) # error: no verb provided if args.verb_name is None: print(parser.format_usage()) return 'Error: No verb provided' # set default locations for log files now = datetime.datetime.now() now_str = str(now)[:-7].replace(' ', '_').replace(':', '-') set_default_log_path( base_path=args.log_base, env_var='{command_name}_LOG_PATH'.format_map(locals()).upper(), subdirectory='{args.verb_name}_{now_str}'.format_map(locals())) # add a file handler writing all levels create_log_path(args.verb_name) handler = add_file_handler(colcon_logger, get_log_path() / 'logger_all.log') # write previous log messages to the file handler log_record = colcon_logger.makeRecord( colcon_logger.name, logging.DEBUG, __file__, 0, 'Command line arguments: {argv}'.format( argv=argv if argv is not None else sys.argv), None, None) handler.handle(log_record) log_record = colcon_logger.makeRecord( colcon_logger.name, logging.DEBUG, __file__, 0, 'Parsed command line arguments: {args}'.format_map(locals()), None, None) handler.handle(log_record) # invoke verb return verb_main(context, colcon_logger)
def test_create_log_path(): # no need to create a directory if the path already exists log_path = Path(os.getcwd()) set_default_log_path(base_path=log_path.parent, subdirectory=log_path.name) with patch('os.makedirs') as makedirs: makedirs.side_effect = AssertionError('should not be called') create_log_path('verb') # no latest symlink is being created either assert not (log_path.parent / 'latest').exists() subdirectory = 'sub' with TemporaryDirectory(prefix='test_colcon_') as log_path: log_path = Path(log_path) set_default_log_path(base_path=log_path, subdirectory=subdirectory) # repeated call is a noop with patch('os.makedirs') as makedirs: makedirs.side_effect = AssertionError('should not be called') create_log_path('verb2') assert not (log_path.parent / 'latest').exists() # create a directory and symlink when the path doesn't exist location._create_log_path_called = False with patch('os.makedirs', wraps=os.makedirs) as makedirs: create_log_path('verb') makedirs.assert_called_once_with(str(log_path / subdirectory)) assert (log_path / subdirectory).exists() # since the directory already exists create one with a suffix location._create_log_path_called = False with patch('os.makedirs', wraps=os.makedirs) as makedirs: create_log_path('verb') assert makedirs.call_count == 2 assert len(makedirs.call_args_list[0][0]) == 1 assert makedirs.call_args_list[0][0][0] == str(log_path / subdirectory) assert len(makedirs.call_args_list[1][0]) == 1 assert makedirs.call_args_list[1][0][0] == str( log_path / subdirectory) + '_2' assert (log_path / (str(subdirectory) + '_2')).exists() # and another increment of the suffix location._create_log_path_called = False location._log_subdirectory = subdirectory with patch('os.makedirs', wraps=os.makedirs) as makedirs: create_log_path('verb') assert makedirs.call_count == 3 assert len(makedirs.call_args_list[0][0]) == 1 assert makedirs.call_args_list[0][0][0] == str(log_path / subdirectory) assert len(makedirs.call_args_list[1][0]) == 1 assert makedirs.call_args_list[1][0][0] == str( log_path / subdirectory) + '_2' assert len(makedirs.call_args_list[2][0]) == 1 assert makedirs.call_args_list[2][0][0] == str( log_path / subdirectory) + '_3' assert (log_path / (str(subdirectory) + '_3')).exists() subdirectory += '_3' # skip all symlink tests on Windows for now if sys.platform == 'win32': return # check that `latest_verb` was created and points to the subdirectory assert (log_path / 'latest_verb').is_symlink() assert (log_path / 'latest_verb').resolve() == \ (log_path / subdirectory).resolve() # check that `latest` was created and points to the subdirectory assert (log_path / 'latest').is_symlink() assert (log_path / 'latest').resolve() == \ (log_path / subdirectory).resolve() # create directory but correct latest symlink already exists (log_path / subdirectory).rmdir() location._create_log_path_called = False create_log_path('verb') assert (log_path / subdirectory).exists() assert (log_path / 'latest').is_symlink() assert (log_path / 'latest').resolve() == \ (log_path / subdirectory).resolve() # create directory and update latest symlink subdirectory = 'other_sub' set_default_log_path(base_path=log_path, subdirectory=subdirectory) location._create_log_path_called = False create_log_path('verb') assert (log_path / subdirectory).exists() assert (log_path / 'latest').is_symlink() assert (log_path / 'latest').resolve() == \ (log_path / subdirectory).resolve() # create directory but latest is not a symlink (log_path / subdirectory).rmdir() (log_path / 'latest').unlink() (log_path / 'latest').mkdir() location._create_log_path_called = False create_log_path('verb') assert (log_path / subdirectory).exists() assert not (log_path / 'latest').is_symlink()