示例#1
0
    def provide(self, requirement, context):
        """Override superclass to start a download..

        If it locates a downloaded file with matching checksum, it sets the
        requirement's env var to that filename.

        """
        super_result = super(DownloadProvider, self).provide(requirement, context)

        if context.mode == PROVIDE_MODE_CHECK:
            return super_result
        # we do the download in both prod and dev mode

        frontend = _new_error_recorder(context.frontend)
        if requirement.env_var not in context.environ or context.status.analysis.config['source'] == 'download':
            filename = self._provide_download(requirement, context, frontend)
            if filename is not None:
                context.environ[requirement.env_var] = filename

        return super_result.copy_with_additions(errors=frontend.pop_errors())
示例#2
0
    def provide(self, requirement, context):
        """Override superclass to start a project-scoped redis-server.

        If it locates or starts a redis-server, it sets the
        requirement's env var to that server's URL.

        """
        assert 'PATH' in context.environ

        url = None
        source = context.status.analysis.config['source']

        super_result = super(RedisProvider, self).provide(requirement, context)

        url = context.environ.get(requirement.env_var, None)

        frontend = _new_error_recorder(context.frontend)

        # we jump through a little hoop to avoid a "can't connect to system redis"
        # message if we're going to end up successfully starting a local one.
        system_failed = False
        if url is None and (source == 'find_system' or source == 'find_all'):
            url = self._provide_system(requirement, context, frontend)
            if url is None:
                system_failed = True

        if url is None and (source == 'find_project' or source == 'find_all'):
            # we will only start a local Redis in "dev" mode, not prod or check mode
            if context.mode == PROVIDE_MODE_DEVELOPMENT:
                url = self._provide_project(requirement, context, frontend)

        if url is None:
            if system_failed:
                frontend.error("Could not connect to system default Redis.")
        else:
            context.environ[requirement.env_var] = url

        return super_result.copy_with_additions(errors=frontend.pop_errors())
示例#3
0
def _unarchive_project(archive_filename,
                       project_dir,
                       frontend,
                       parent_dir=None):
    """Unpack an archive of files in the project.

    This takes care of several details, for example it deals with
    hostile archives containing files outside of the dest
    directory, and it handles both tar and zip.

    It does not load or validate the unpacked project.

    project_dir can be None to auto-choose one.

    If parent_dir is non-None, place the project_dir in it. This is most useful
    if project_dir is None.

    Args:
        archive_filename (str): the tar or zip archive file
        project_dir (str): the directory that will contain the project config file
        parent_dir (str): place project directory in here

    Returns:
        a ``Status``, if failed has ``errors``, on success has a ``project_dir`` property
    """
    if project_dir is not None and os.path.isabs(
            project_dir) and parent_dir is not None:
        raise ValueError(
            "If supplying parent_dir to unarchive, project_dir must be relative or None"
        )

    frontend = _new_error_recorder(frontend)

    list_files = None
    extract_files = None
    if archive_filename.endswith(".zip"):
        list_files = _list_files_zip
        extract_files = _extract_files_zip
    elif any([
            archive_filename.endswith(suffix)
            for suffix in [".tar", ".tar.gz", ".tar.bz2"]
    ]):
        list_files = _list_files_tar
        extract_files = _extract_files_tar
    else:
        frontend.error(
            "Unsupported archive filename %s, must be a .zip, .tar.gz, or .tar.bz2"
            % (archive_filename))
        return SimpleStatus(success=False,
                            description=("Could not unpack archive %s" %
                                         archive_filename),
                            errors=frontend.pop_errors())

    try:
        result = _get_source_and_dest_files(archive_filename, list_files,
                                            project_dir, parent_dir, frontend)
        if result is None:
            return SimpleStatus(success=False,
                                description=("Could not unpack archive %s" %
                                             archive_filename),
                                errors=frontend.pop_errors())
        (canonical_project_dir, src_and_dest) = result

        if len(src_and_dest) == 0:
            frontend.error(
                "Archive does not contain a project directory or is empty.")
            return SimpleStatus(success=False,
                                description=("Could not unpack archive %s" %
                                             archive_filename),
                                errors=frontend.pop_errors())

        assert not os.path.exists(canonical_project_dir)
        os.makedirs(canonical_project_dir)

        try:
            extract_files(archive_filename, src_and_dest, frontend)
        except Exception as e:
            try:
                shutil.rmtree(canonical_project_dir)
            except (IOError, OSError):
                pass
            raise e

        return _UnarchiveStatus(
            success=True,
            description=("Project archive unpacked to %s." %
                         canonical_project_dir),
            project_dir=canonical_project_dir)
    except (IOError, OSError, zipfile.error, tarfile.TarError) as e:
        frontend.error(str(e))
        return SimpleStatus(success=False,
                            description="Failed to read project archive.",
                            errors=frontend.pop_errors())
示例#4
0
def _archive_project(project, filename):
    """Make an archive of the non-ignored files in the project.

    Args:
        project (``Project``): the project
        filename (str): name for the new zip or tar.gz archive file

    Returns:
        a ``Status``, if failed has ``errors``
    """
    failed = project.problems_status()
    if failed is not None:
        for error in failed.errors:
            project.frontend.error(error)
        return failed

    frontend = _new_error_recorder(project.frontend)

    if not os.path.exists(project.project_file.filename):
        frontend.error("%s does not exist." % project.project_file.basename)
        return SimpleStatus(success=False,
                            description="Can't create an archive.",
                            errors=frontend.pop_errors())

    # this would most likely happen in a GUI editor, if it reloaded
    # the project from memory but hadn't saved yet.
    if project.project_file.has_unsaved_changes:
        frontend.error("%s has been modified but not saved." %
                       project.project_file.basename)
        return SimpleStatus(success=False,
                            description="Can't create an archive.",
                            errors=frontend.pop_errors())

    infos = _enumerate_archive_files(
        project.directory_path,
        frontend,
        requirements=project.union_of_requirements_for_all_envs)
    if infos is None:
        return SimpleStatus(success=False,
                            description="Failed to list files in the project.",
                            errors=frontend.pop_errors())

    # don't put the destination zip into itself, since it's fairly natural to
    # create a archive right in the project directory
    relative_dest_file = subdirectory_relative_to_directory(
        filename, project.directory_path)
    if not os.path.isabs(relative_dest_file):
        infos = [
            info for info in infos if info.relative_path != relative_dest_file
        ]

    tmp_filename = filename + ".tmp-" + str(uuid.uuid4())
    try:
        if filename.lower().endswith(".zip"):
            _write_zip(project.name, infos, tmp_filename, frontend)
        elif filename.lower().endswith(".tar.gz"):
            _write_tar(project.name,
                       infos,
                       tmp_filename,
                       compression="gz",
                       frontend=frontend)
        elif filename.lower().endswith(".tar.bz2"):
            _write_tar(project.name,
                       infos,
                       tmp_filename,
                       compression="bz2",
                       frontend=frontend)
        elif filename.lower().endswith(".tar"):
            _write_tar(project.name,
                       infos,
                       tmp_filename,
                       compression=None,
                       frontend=frontend)
        else:
            frontend.error("Unsupported archive filename %s." % (filename))
            return SimpleStatus(
                success=False,
                description=
                "Project archive filename must be a .zip, .tar.gz, or .tar.bz2.",
                errors=frontend.pop_errors())
        rename_over_existing(tmp_filename, filename)
    except IOError as e:
        frontend.error(str(e))
        return SimpleStatus(
            success=False,
            description=("Failed to write project archive %s." % (filename)),
            errors=frontend.pop_errors())
    finally:
        try:
            os.remove(tmp_filename)
        except (IOError, OSError):
            pass

    unlocked = []
    for env_spec in project.env_specs.values():
        if env_spec.lock_set.disabled:
            unlocked.append(env_spec.name)

    if len(unlocked) > 0:
        frontend.info(
            "Warning: env specs are not locked, which means they may not "
            "work consistently for others or when deployed.")
        frontend.info(
            "  Consider using the 'anaconda-project lock' command to lock the project."
        )
        if len(unlocked) != len(project.env_specs):
            frontend.info("  Unlocked env specs are: " +
                          (", ".join(sorted(unlocked))))

    return SimpleStatus(success=True,
                        description=("Created project archive %s" % filename))