示例#1
0
def refer(conf, spec):
    """Take the package installed in venv_dir and refer to it.

    Returns True if it modified the filesystem.
    """

    package_dir = expand.package_dir(conf, spec)
    target_dir = service_dir(conf, spec)

    if not os.path.isdir(package_dir):
        raise InstallerError(
            "{package_dir} not found".format(package_dir=package_dir))

    if os.path.isdir(target_dir):
        # We assume there's nothing to do
        return False

    if os.path.exists(target_dir):
        raise InstallerError(
            "{target_dir} already exists".format(target_dir=target_dir))

    try:
        os.mkdir(target_dir, 0o755)
        os.symlink(package_dir, os.path.join(target_dir, _VENV_DIR))
        os.mkdir(os.path.join(target_dir, _ETC_DIR), 0o755)

    except Exception as e:
        raise InstallerError(
            "{package_dir} could not be installed as {target_dir}".format(
                package_dir=package_dir, target_dir=target_dir), e)

    return True
示例#2
0
def activate(base_location, spec):
    """Symlink to an installed version

        Given the availability of some pre-installed version,
        create the appropriate symlink.
        Raise an error if the pre-installed version does not exist.
        Raise an error (note, do we want to do this?) if there's already
        something installed there.
    """

    location = os.path.join(base_location, spec.service)
    current_version = active_version(base_location, spec)
    if current_version is not None:
        raise InstallerError(
            "{location} already has an installed version: {version}"
            .format(location=location, version=current_version))

    spec = ensure_suffix(base_location, spec)
    target = spec.service + "-" + spec.suffix
    if not os.path.isdir(location + "-" + spec.suffix):
        raise InstallerError(
            "No pre-expanded version {version} for {location} found"
            .format(location=location, version=str(spec.version)))

    try:
        os.symlink(target, location)
    except OSError:
        raise InstallerError(
            "Cannot symlink {location} to {target}"
            .format(location=location, target=target))
示例#3
0
def deactivate(base_location, spec):
    """Deactivate an installed version

        Given an installed version at the given location,
        deactivate it.
        If an explicit version is specified, then it is an error
        if any other version is present.
        Otherwise, we'll simply deactivate whatever is found
        there.
    """

    location = os.path.join(base_location, spec.service)
    current_version = active_version(base_location, spec)
    if spec.version is not None and current_version != spec.version:
        msg = ("Attempt to deinstall {version} from {location} -"
               " {current} found instead")
        raise InstallerError(msg
                             .format(location=location,
                                     version=str(spec.version),
                                     current=current_version))

    if os.path.islink(location):
        try:
            os.unlink(location)
        except IOError as e:
            raise InstallerError("Can't unlink {location}"
                                 .format(location=location), e)
示例#4
0
def remove(config, spec):
    """Remove an exploded version

    This is an error if the version's currently activated.
    There's no error if the version is already not there.

    Returns True if it modified the filesystem
    """

    location = service_pointer(config, spec)
    current_version = active_version(config.SERVICE_LOCATION, spec)
    if current_version == spec.version:
        raise InstallerError(
            "Cannot remove {version} for {location} since it is current active"
            .format(location=location, version=spec.version))

    ensure_suffix(config.SERVICE_LOCATION, spec)
    target = service_dir(config, spec)

    if not os.path.exists(target):
        return False

    if not os.path.isdir(target):
        msg = ("Cannot remove {version} for {location} since it is not"
               " a directory".format(location=location, version=spec.version))
        raise InstallerError(msg)

    try:
        # Delete recursively
        shutil.rmtree(target)
    except Exception as e:
        raise InstallerError("Could not delete {target}".format(target=target),
                             e)

    return True
示例#5
0
def explode(config, spec):
    """Take the package installed in cache_dir and expand it.

    This will be a no-op if there's already something
    at the target.

    We require the source package to be present in
    the cache_dir, with the name
    $(basename $location)-suffix.tgz

    Returns (True, spec) if it modified the filesystem.
    """

    spec = cache.assert_package_present(config, spec)
    cache_file = cache.cache_file(config, spec)
    target_dir = package_dir(config, spec)

    if not os.path.isfile(cache_file):
        raise InstallerError(
            "{cache_file} not found".format(cache_file=cache_file))

    if not tarfile.is_tarfile(cache_file):
        raise InstallerError(
            "{cache_file} is not in the correct format".format(
                cache_file=cache_file))

    if os.path.isdir(target_dir):
        # We assume there's nothing to do
        return (False, spec)

    if os.path.exists(target_dir):
        raise InstallerError(
            "{target_dir} already exists".format(target_dir=target_dir))

    try:
        os.mkdir(target_dir, 0o755)

        gname = config['group_name']
        group = grp.getgrnam(gname)
        gid = group.gr_gid

        with tarfile.open(cache_file) as tar:
            members = tar.getmembers()
            for m in members:
                m.uid = 0
                m.gid = gid
                m.uname = 'root'
                m.gname = gname
                m.mode |= config['extra_mode_bits']
            tar.extractall(path=target_dir, members=members)

    except Exception as e:
        raise InstallerError(
            "{cache_file} could not be exploded to {target_dir}".format(
                cache_file=cache_file, target_dir=target_dir), e)

    return (True, spec)
示例#6
0
def guess_from_suffix(file_name, format, group=2):
    """Return a best guess, given a directory or tarball name"""

    file = os.path.basename(file_name)
    match = format.match(file)
    if not match:
        raise InstallerError(
            "{} doesn't have a viable suffix".format(file_name))
    version = match.group(group)

    # The suffix is from an older ISO image
    guess = best_guess(version)
    if guess == version:
        raise InstallerError("{} has an unknown suffix".format(file_name))

    return from_str(guess)
示例#7
0
def active_version(base_location, spec):
    """Is there a package installed at the specified location?

        If so, return its version; otherwise None.
        If it looks like something's not right (eg, bad
        symlink or some other file there), throw an exception.
    """

    location = os.path.join(base_location, spec.service)
    try:
        if not os.path.exists(location):
            return None
        target = os.readlink(location)
        if not target.startswith(spec.service + "-"):
            raise InstallerError(
                "{location} is not an installed venv; target is {target}"
                .format(location=location, target=target))
        return from_service_dir(os.path.join(base_location, target))
    except OSError:
        raise InstallerError("{location} is not a symlink"
                             .format(location=location))
示例#8
0
def assert_package_present(config, spec):
    index = indexer.load_index(config.CACHE_DIR)

    if 'packages' not in index:
        raise InstallerError("Badly formed index file in {cache_dir}".format(
            cache_dir=config.CACHE_DIR))
    packages = index['packages']

    if spec.package not in packages:
        raise InstallerError(
            "{package} not listed in index in {cache_dir}".format(
                package=spec.package, cache_dir=config.CACHE_DIR))
    available = index['packages'][spec.package]

    if spec.version is VERSION_LATEST:
        try:
            v = max(available.keys(), key=from_str)
            spec.version = from_str(best_guess(v))
        except KeyError:
            raise InstallerError(
                "no versions of {package} are not available".format(
                    package=spec.package))

    if str(spec.version) not in available:
        raise InstallerError("{version} of {package} is not available".format(
            package=spec.package, version=str(spec.version)))

    spec.tarball = available[str(spec.version)]['file']
    spec.suffix = available[str(spec.version)]['suffix']

    source = config.repo_url + spec.tarball
    target = os.path.join(config.CACHE_DIR, spec.tarball)

    if not os.path.isfile(target):
        # If the file's there, assume we've nothing to do
        _download(source, target)

    return spec
示例#9
0
def ensure_suffix(base_location, spec):
    try:
        if spec.suffix is not None:
            return spec
    except AttributeError:
        pass

    # Locate the appropriate suffix associated with this verison.
    for file_name in os.listdir(base_location):
        match = DIR_FORMAT.match(file_name)
        if not match:
            continue
        #if not file_name.startswith(spec.service + "-"):
        if spec.service != match.group(1):
            continue
        dir = os.path.join(base_location, file_name)
        if spec.version != from_service_dir(dir):
            continue
        spec.suffix = match.group(2)
        return spec

    raise InstallerError(
        "Cannot find version {version} for service {service}"
        .format(version=str(spec.version), service=spec.service))