145 lines
4.4 KiB
Python
145 lines
4.4 KiB
Python
|
import os
|
||
|
from typing import List
|
||
|
|
||
|
from dbt import semver
|
||
|
from dbt.clients import registry, system
|
||
|
from dbt.contracts.project import (
|
||
|
RegistryPackageMetadata,
|
||
|
RegistryPackage,
|
||
|
)
|
||
|
from dbt.deps.base import PinnedPackage, UnpinnedPackage, get_downloads_path
|
||
|
from dbt.exceptions import (
|
||
|
package_version_not_found,
|
||
|
VersionsNotCompatibleException,
|
||
|
DependencyException,
|
||
|
package_not_found,
|
||
|
)
|
||
|
|
||
|
|
||
|
class RegistryPackageMixin:
|
||
|
def __init__(self, package: str) -> None:
|
||
|
super().__init__()
|
||
|
self.package = package
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
return self.package
|
||
|
|
||
|
def source_type(self) -> str:
|
||
|
return 'hub'
|
||
|
|
||
|
|
||
|
class RegistryPinnedPackage(RegistryPackageMixin, PinnedPackage):
|
||
|
def __init__(self,
|
||
|
package: str,
|
||
|
version: str,
|
||
|
version_latest: str) -> None:
|
||
|
super().__init__(package)
|
||
|
self.version = version
|
||
|
self.version_latest = version_latest
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
return self.package
|
||
|
|
||
|
def source_type(self):
|
||
|
return 'hub'
|
||
|
|
||
|
def get_version(self):
|
||
|
return self.version
|
||
|
|
||
|
def get_version_latest(self):
|
||
|
return self.version_latest
|
||
|
|
||
|
def nice_version_name(self):
|
||
|
return 'version {}'.format(self.version)
|
||
|
|
||
|
def _fetch_metadata(self, project, renderer) -> RegistryPackageMetadata:
|
||
|
dct = registry.package_version(self.package, self.version)
|
||
|
return RegistryPackageMetadata.from_dict(dct)
|
||
|
|
||
|
def install(self, project, renderer):
|
||
|
metadata = self.fetch_metadata(project, renderer)
|
||
|
|
||
|
tar_name = '{}.{}.tar.gz'.format(self.package, self.version)
|
||
|
tar_path = os.path.realpath(
|
||
|
os.path.join(get_downloads_path(), tar_name)
|
||
|
)
|
||
|
system.make_directory(os.path.dirname(tar_path))
|
||
|
|
||
|
download_url = metadata.downloads.tarball
|
||
|
system.download_with_retries(download_url, tar_path)
|
||
|
deps_path = project.modules_path
|
||
|
package_name = self.get_project_name(project, renderer)
|
||
|
system.untar_package(tar_path, deps_path, package_name)
|
||
|
|
||
|
|
||
|
class RegistryUnpinnedPackage(
|
||
|
RegistryPackageMixin, UnpinnedPackage[RegistryPinnedPackage]
|
||
|
):
|
||
|
def __init__(
|
||
|
self,
|
||
|
package: str,
|
||
|
versions: List[semver.VersionSpecifier],
|
||
|
install_prerelease: bool
|
||
|
) -> None:
|
||
|
super().__init__(package)
|
||
|
self.versions = versions
|
||
|
self.install_prerelease = install_prerelease
|
||
|
|
||
|
def _check_in_index(self):
|
||
|
index = registry.index_cached()
|
||
|
if self.package not in index:
|
||
|
package_not_found(self.package)
|
||
|
|
||
|
@classmethod
|
||
|
def from_contract(
|
||
|
cls, contract: RegistryPackage
|
||
|
) -> 'RegistryUnpinnedPackage':
|
||
|
raw_version = contract.get_versions()
|
||
|
|
||
|
versions = [
|
||
|
semver.VersionSpecifier.from_version_string(v)
|
||
|
for v in raw_version
|
||
|
]
|
||
|
return cls(
|
||
|
package=contract.package,
|
||
|
versions=versions,
|
||
|
install_prerelease=contract.install_prerelease
|
||
|
)
|
||
|
|
||
|
def incorporate(
|
||
|
self, other: 'RegistryUnpinnedPackage'
|
||
|
) -> 'RegistryUnpinnedPackage':
|
||
|
return RegistryUnpinnedPackage(
|
||
|
package=self.package,
|
||
|
install_prerelease=self.install_prerelease,
|
||
|
versions=self.versions + other.versions,
|
||
|
)
|
||
|
|
||
|
def resolved(self) -> RegistryPinnedPackage:
|
||
|
self._check_in_index()
|
||
|
try:
|
||
|
range_ = semver.reduce_versions(*self.versions)
|
||
|
except VersionsNotCompatibleException as e:
|
||
|
new_msg = ('Version error for package {}: {}'
|
||
|
.format(self.name, e))
|
||
|
raise DependencyException(new_msg) from e
|
||
|
|
||
|
available = registry.get_available_versions(self.package)
|
||
|
installable = semver.filter_installable(
|
||
|
available,
|
||
|
self.install_prerelease
|
||
|
)
|
||
|
available_latest = installable[-1]
|
||
|
|
||
|
# for now, pick a version and then recurse. later on,
|
||
|
# we'll probably want to traverse multiple options
|
||
|
# so we can match packages. not going to make a difference
|
||
|
# right now.
|
||
|
target = semver.resolve_to_specific_version(range_, installable)
|
||
|
if not target:
|
||
|
package_version_not_found(self.package, range_, installable)
|
||
|
return RegistryPinnedPackage(package=self.package, version=target,
|
||
|
version_latest=available_latest)
|