def debug(recipe_or_package_path_or_metadata_tuples, path=None, test=False, output_id=None, config=None, verbose=True, **kwargs): """Set up either build/host or test environments, leaving you with a quick tool to debug your package's build or test phase. """ from fnmatch import fnmatch import logging import os import time from conda_build.conda_interface import string_types from conda_build.build import test as run_test, build as run_build from conda_build.utils import CONDA_TARBALL_EXTENSIONS, on_win, LoggingContext is_package = False default_config = get_or_merge_config(config, **kwargs) args = {"set_build_id": False} if not path: path = os.path.join(default_config.croot, "debug_{}".format(int(time.time() * 1000))) config = get_or_merge_config(config=default_config, croot=path, verbose=verbose, _prefix_length=10, **args) config.channel_urls = get_channel_urls(kwargs) metadata_tuples = [] if isinstance(recipe_or_package_path_or_metadata_tuples, string_types): ext = os.path.splitext(recipe_or_package_path_or_metadata_tuples)[1] if not ext or not any(ext in _ for _ in CONDA_TARBALL_EXTENSIONS): metadata_tuples = render(recipe_or_package_path_or_metadata_tuples, config=config, **kwargs) else: # this is a package, we only support testing test = True is_package = True else: metadata_tuples = recipe_or_package_path_or_metadata_tuples if metadata_tuples: outputs = get_output_file_paths(metadata_tuples) matched_outputs = outputs if output_id: matched_outputs = [ _ for _ in outputs if fnmatch(os.path.basename(_), output_id) ] if len(matched_outputs) > 1: raise ValueError( "Specified --output-id matches more than one output ({}). Please refine your output id so that only " "a single output is found.".format(matched_outputs)) elif not matched_outputs: raise ValueError( "Specified --output-id did not match any outputs. Available outputs are: {} Please check it and try again" .format(outputs)) if len(matched_outputs) > 1: raise ValueError( "More than one output found for this recipe ({}). Please use the --output-id argument to filter down " "to a single output.".format(outputs)) else: matched_outputs = outputs target_metadata = metadata_tuples[outputs.index(matched_outputs[0])][0] # make sure that none of the _placehold stuff gets added to env paths target_metadata.config.prefix_length = 10 ext = ".bat" if on_win else ".sh" if verbose: log_context = LoggingContext() else: log_context = LoggingContext(logging.CRITICAL + 1) if not test: with log_context: run_build(target_metadata, stats={}, provision_only=True) activation_file = "build_env_setup" + ext activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=target_metadata.config.work_dir, source="call" if on_win else "source", activation_file=os.path.join(target_metadata.config.work_dir, activation_file)) else: if not is_package: raise ValueError( "Debugging for test mode is only supported for package files that already exist. " "Please build your package first, then use it to create the debugging environment." ) else: test_input = recipe_or_package_path_or_metadata_tuples # use the package to create an env and extract the test files. Stop short of running the tests. # tell people what steps to take next with log_context: run_test(test_input, config=config, stats={}, provision_only=True) activation_file = os.path.join(config.test_dir, "conda_test_env_vars" + ext) activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=config.test_dir, source="call" if on_win else "source", activation_file=os.path.join(config.test_dir, activation_file)) return activation_string
def debug(recipe_or_package_path_or_metadata_tuples, path=None, test=False, output_id=None, config=None, verbose=True, link_source_method='auto', **kwargs): """Set up either build/host or test environments, leaving you with a quick tool to debug your package's build or test phase. """ from fnmatch import fnmatch import logging import os import time from conda_build.conda_interface import string_types from conda_build.build import test as run_test, build as run_build from conda_build.utils import CONDA_TARBALL_EXTENSIONS, on_win, LoggingContext is_package = False default_config = get_or_merge_config(config, **kwargs) args = {"set_build_id": False} path_is_build_dir = False workdirs = [ os.path.join(recipe_or_package_path_or_metadata_tuples, d) for d in ( os.listdir(recipe_or_package_path_or_metadata_tuples) if os.path. isdir(recipe_or_package_path_or_metadata_tuples) else []) if (d.startswith('work') and os.path.isdir( os.path.join(recipe_or_package_path_or_metadata_tuples, d))) ] metadatas_conda_debug = [ os.path.join(f, "metadata_conda_debug.yaml") for f in workdirs if os.path.isfile(os.path.join(f, "metadata_conda_debug.yaml")) ] metadatas_conda_debug = sorted(metadatas_conda_debug) if len(metadatas_conda_debug): path_is_build_dir = True path = recipe_or_package_path_or_metadata_tuples if not path: path = os.path.join(default_config.croot, "debug_{}".format(int(time.time() * 1000))) config = get_or_merge_config(config=default_config, croot=path, verbose=verbose, _prefix_length=10, **args) config.channel_urls = get_channel_urls(kwargs) metadata_tuples = [] best_link_source_method = 'skip' if isinstance(recipe_or_package_path_or_metadata_tuples, string_types): if path_is_build_dir: for metadata_conda_debug in metadatas_conda_debug: best_link_source_method = 'symlink' from conda_build.metadata import MetaData metadata = MetaData(metadata_conda_debug, config, {}) metadata_tuples.append((metadata, False, True)) else: ext = os.path.splitext( recipe_or_package_path_or_metadata_tuples)[1] if not ext or not any(ext in _ for _ in CONDA_TARBALL_EXTENSIONS): metadata_tuples = render( recipe_or_package_path_or_metadata_tuples, config=config, **kwargs) else: # this is a package, we only support testing test = True is_package = True else: metadata_tuples = recipe_or_package_path_or_metadata_tuples if metadata_tuples: outputs = get_output_file_paths(metadata_tuples) matched_outputs = outputs if output_id: matched_outputs = [ _ for _ in outputs if fnmatch(os.path.basename(_), output_id) ] if len(matched_outputs) > 1: raise ValueError( "Specified --output-id matches more than one output ({}). Please refine your output id so that only " "a single output is found.".format(matched_outputs)) elif not matched_outputs: raise ValueError( "Specified --output-id did not match any outputs. Available outputs are: {} Please check it and try again" .format(outputs)) if len(matched_outputs) > 1 and not path_is_build_dir: raise ValueError( "More than one output found for this recipe ({}). Please use the --output-id argument to filter down " "to a single output.".format(outputs)) else: matched_outputs = outputs target_metadata = metadata_tuples[outputs.index(matched_outputs[0])][0] # make sure that none of the _placehold stuff gets added to env paths target_metadata.config.prefix_length = 10 if best_link_source_method == 'symlink': for metadata, _, _ in metadata_tuples: debug_source_loc = os.path.join( os.sep + 'usr', 'local', 'src', 'conda', '{}-{}'.format(metadata.get_value('package/name'), metadata.get_value('package/version'))) link_target = os.path.dirname(metadata.meta_path) try: dn = os.path.dirname(debug_source_loc) try: os.makedirs(dn) except FileExistsError: pass try: os.unlink(debug_source_loc) except: pass print("Making debug info source symlink: {} => {}".format( debug_source_loc, link_target)) os.symlink(link_target, debug_source_loc) except PermissionError as e: raise Exception( "You do not have the necessary permissions to create symlinks in {}\nerror: {}" .format(dn, str(e))) except Exception as e: raise Exception( "Unknown error creating symlinks in {}\nerror: {}".format( dn, str(e))) ext = ".bat" if on_win else ".sh" if verbose: log_context = LoggingContext() else: log_context = LoggingContext(logging.CRITICAL + 1) if path_is_build_dir: activation_file = "build_env_setup" + ext activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=target_metadata.config.work_dir, source="call" if on_win else "source", activation_file=os.path.join(target_metadata.config.work_dir, activation_file)) elif not test: with log_context: run_build(target_metadata, stats={}, provision_only=True) activation_file = "build_env_setup" + ext activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=target_metadata.config.work_dir, source="call" if on_win else "source", activation_file=os.path.join(target_metadata.config.work_dir, activation_file)) else: if not is_package: raise ValueError( "Debugging for test mode is only supported for package files that already exist. " "Please build your package first, then use it to create the debugging environment." ) else: test_input = recipe_or_package_path_or_metadata_tuples # use the package to create an env and extract the test files. Stop short of running the tests. # tell people what steps to take next with log_context: run_test(test_input, config=config, stats={}, provision_only=True) activation_file = os.path.join(config.test_dir, "conda_test_env_vars" + ext) activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=config.test_dir, source="call" if on_win else "source", activation_file=os.path.join(config.test_dir, activation_file)) return activation_string
def debug(recipe_or_package_path_or_metadata_tuples, path=None, test=False, output_id=None, config=None, verbose=True, link_source_method='auto', **kwargs): """Set up either build/host or test environments, leaving you with a quick tool to debug your package's build or test phase. """ from fnmatch import fnmatch import logging import os import time from conda_build.conda_interface import string_types from conda_build.build import test as run_test, build as run_build from conda_build.utils import CONDA_TARBALL_EXTENSIONS, on_win, LoggingContext is_package = False default_config = get_or_merge_config(config, **kwargs) args = {"set_build_id": False} path_is_build_dir = False workdirs = [os.path.join(recipe_or_package_path_or_metadata_tuples, d) for d in (os.listdir(recipe_or_package_path_or_metadata_tuples) if os.path.isdir(recipe_or_package_path_or_metadata_tuples) else []) if (d.startswith('work') and os.path.isdir(os.path.join(recipe_or_package_path_or_metadata_tuples, d)))] metadatas_conda_debug = [os.path.join(f, "metadata_conda_debug.yaml") for f in workdirs if os.path.isfile(os.path.join(f, "metadata_conda_debug.yaml"))] metadatas_conda_debug = sorted(metadatas_conda_debug) if len(metadatas_conda_debug): path_is_build_dir = True path = recipe_or_package_path_or_metadata_tuples if not path: path = os.path.join(default_config.croot, "debug_{}".format(int(time.time() * 1000))) config = get_or_merge_config(config=default_config, croot=path, verbose=verbose, _prefix_length=10, **args) config.channel_urls = get_channel_urls(kwargs) metadata_tuples = [] best_link_source_method = 'skip' if isinstance(recipe_or_package_path_or_metadata_tuples, string_types): if path_is_build_dir: for metadata_conda_debug in metadatas_conda_debug: best_link_source_method = 'symlink' from conda_build.metadata import MetaData metadata = MetaData(metadata_conda_debug, config, {}) metadata_tuples.append((metadata, False, True)) else: ext = os.path.splitext(recipe_or_package_path_or_metadata_tuples)[1] if not ext or not any(ext in _ for _ in CONDA_TARBALL_EXTENSIONS): metadata_tuples = render(recipe_or_package_path_or_metadata_tuples, config=config, **kwargs) else: # this is a package, we only support testing test = True is_package = True else: metadata_tuples = recipe_or_package_path_or_metadata_tuples if metadata_tuples: outputs = get_output_file_paths(metadata_tuples) matched_outputs = outputs if output_id: matched_outputs = [_ for _ in outputs if fnmatch(os.path.basename(_), output_id)] if len(matched_outputs) > 1: raise ValueError("Specified --output-id matches more than one output ({}). Please refine your output id so that only " "a single output is found.".format(matched_outputs)) elif not matched_outputs: raise ValueError("Specified --output-id did not match any outputs. Available outputs are: {} Please check it and try again".format(outputs)) if len(matched_outputs) > 1 and not path_is_build_dir: raise ValueError("More than one output found for this recipe ({}). Please use the --output-id argument to filter down " "to a single output.".format(outputs)) else: matched_outputs = outputs target_metadata = metadata_tuples[outputs.index(matched_outputs[0])][0] # make sure that none of the _placehold stuff gets added to env paths target_metadata.config.prefix_length = 10 if best_link_source_method == 'symlink': for metadata, _, _ in metadata_tuples: debug_source_loc = os.path.join(os.sep + 'usr', 'local', 'src', 'conda', '{}-{}'.format(metadata.get_value('package/name'), metadata.get_value('package/version'))) link_target = os.path.dirname(metadata.meta_path) try: dn = os.path.dirname(debug_source_loc) try: os.makedirs(dn) except FileExistsError: pass try: os.unlink(debug_source_loc) except: pass print("Making debug info source symlink: {} => {}".format(debug_source_loc, link_target)) os.symlink(link_target, debug_source_loc) except PermissionError as e: raise Exception("You do not have the necessary permissions to create symlinks in {}\nerror: {}" .format(dn, str(e))) except Exception as e: raise Exception("Unknown error creating symlinks in {}\nerror: {}" .format(dn, str(e))) ext = ".bat" if on_win else ".sh" if verbose: log_context = LoggingContext() else: log_context = LoggingContext(logging.CRITICAL + 1) if path_is_build_dir: activation_file = "build_env_setup" + ext activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=target_metadata.config.work_dir, source="call" if on_win else "source", activation_file=os.path.join(target_metadata.config.work_dir, activation_file)) elif not test: with log_context: run_build(target_metadata, stats={}, provision_only=True) activation_file = "build_env_setup" + ext activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=target_metadata.config.work_dir, source="call" if on_win else "source", activation_file=os.path.join(target_metadata.config.work_dir, activation_file)) else: if not is_package: raise ValueError("Debugging for test mode is only supported for package files that already exist. " "Please build your package first, then use it to create the debugging environment.") else: test_input = recipe_or_package_path_or_metadata_tuples # use the package to create an env and extract the test files. Stop short of running the tests. # tell people what steps to take next with log_context: run_test(test_input, config=config, stats={}, provision_only=True) activation_file = os.path.join(config.test_dir, "conda_test_env_vars" + ext) activation_string = "cd {work_dir} && {source} {activation_file}\n".format( work_dir=config.test_dir, source="call" if on_win else "source", activation_file=os.path.join(config.test_dir, activation_file)) return activation_string