Example #1
0
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
Example #2
0
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
Example #3
0
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