-
Notifications
You must be signed in to change notification settings - Fork 993
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/metadata2 #14152
Feature/metadata2 #14152
Changes from all commits
a379818
5e60254
ad52e62
404066a
05195cf
df090d4
6bbf321
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -158,10 +158,10 @@ def __init__(self, requester, config, scope=None): | |
raise ConanException("core.download:download_cache must be an absolute path") | ||
self._file_downloader = FileDownloader(requester, scope=scope) | ||
|
||
def download(self, url, file_path, auth, verify_ssl, retry, retry_wait): | ||
if not self._download_cache: | ||
def download(self, url, file_path, auth, verify_ssl, retry, retry_wait, metadata=False): | ||
if not self._download_cache or metadata: # Metadata not cached and can be overwritten | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The metadata cannot be cached, as it is not immutable, and not controlled by checksum |
||
self._file_downloader.download(url, file_path, retry=retry, retry_wait=retry_wait, | ||
verify_ssl=verify_ssl, auth=auth, overwrite=False) | ||
verify_ssl=verify_ssl, auth=auth, overwrite=metadata) | ||
return | ||
|
||
download_cache = DownloadCache(self._download_cache) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -155,7 +155,7 @@ def build_package(self, node, package_layout): | |
prev = self._package(conanfile, pref) | ||
assert prev | ||
node.prev = prev | ||
except ConanException as exc: | ||
except ConanException as exc: # TODO: Remove this? unnecessary? | ||
raise exc | ||
|
||
return node.pref | ||
|
@@ -326,12 +326,14 @@ def _handle_package(self, package, install_reference, handled_count, total_count | |
|
||
# Make sure that all nodes with same pref compute package_info() | ||
pkg_folder = package_layout.package() | ||
pkg_metadata = package_layout.metadata() | ||
assert os.path.isdir(pkg_folder), "Pkg '%s' folder must exist: %s" % (str(pref), pkg_folder) | ||
for n in package.nodes: | ||
n.prev = pref.revision # Make sure the prev is assigned | ||
conanfile = n.conanfile | ||
# Call the info method | ||
conanfile.folders.set_base_package(pkg_folder) | ||
conanfile.folders.set_base_pkg_metadata(pkg_metadata) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This allows deployers to access |
||
self._call_package_info(conanfile, pkg_folder, is_editable=False) | ||
|
||
def _handle_node_editable(self, install_node): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,20 +39,24 @@ def _get_file_list_json(self, url): | |
def get_recipe(self, ref, dest_folder, metadata, only_metadata): | ||
url = self.router.recipe_snapshot(ref) | ||
data = self._get_file_list_json(url) | ||
files = data["files"] | ||
accepted_files = ["conanfile.py", "conan_export.tgz", "conanmanifest.txt", "metadata/sign"] | ||
if only_metadata: | ||
accepted_files = [] | ||
metadata = metadata or [] | ||
metadata = [f"metadata/{m}" for m in metadata] | ||
files = [f for f in files if any(f.startswith(m) for m in accepted_files) | ||
or any(fnmatch.fnmatch(f, m) for m in metadata)] | ||
|
||
# If we didn't indicated reference, server got the latest, use absolute now, it's safer | ||
urls = {fn: self.router.recipe_file(ref, fn) for fn in files} | ||
self._download_and_save_files(urls, dest_folder, files, parallel=True) | ||
ret = {fn: os.path.join(dest_folder, fn) for fn in files} | ||
return ret | ||
server_files = data["files"] | ||
result = {} | ||
|
||
if not only_metadata: | ||
accepted_files = ["conanfile.py", "conan_export.tgz", "conanmanifest.txt", | ||
"metadata/sign"] | ||
files = [f for f in server_files if any(f.startswith(m) for m in accepted_files)] | ||
# If we didn't indicated reference, server got the latest, use absolute now, it's safer | ||
urls = {fn: self.router.recipe_file(ref, fn) for fn in files} | ||
self._download_and_save_files(urls, dest_folder, files, parallel=True) | ||
result.update({fn: os.path.join(dest_folder, fn) for fn in files}) | ||
if metadata: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to separate the download to define |
||
metadata = [f"metadata/{m}" for m in metadata] | ||
files = [f for f in server_files if any(fnmatch.fnmatch(f, m) for m in metadata)] | ||
urls = {fn: self.router.recipe_file(ref, fn) for fn in files} | ||
self._download_and_save_files(urls, dest_folder, files, parallel=True, metadata=True) | ||
result.update({fn: os.path.join(dest_folder, fn) for fn in files}) | ||
return result | ||
|
||
def get_recipe_sources(self, ref, dest_folder): | ||
# If revision not specified, check latest | ||
|
@@ -73,21 +77,26 @@ def get_recipe_sources(self, ref, dest_folder): | |
def get_package(self, pref, dest_folder, metadata, only_metadata): | ||
url = self.router.package_snapshot(pref) | ||
data = self._get_file_list_json(url) | ||
files = data["files"] | ||
server_files = data["files"] | ||
result = {} | ||
# Download only known files, but not metadata (except sign) | ||
accepted_files = ["conaninfo.txt", "conan_package.tgz", "conanmanifest.txt", "metadata/sign"] | ||
if only_metadata: | ||
accepted_files = [] | ||
metadata = metadata or [] | ||
metadata = [f"metadata/{m}" for m in metadata] | ||
files = [f for f in files if any(f.startswith(m) for m in accepted_files) | ||
or any(fnmatch.fnmatch(f, m) for m in metadata)] | ||
|
||
# If we didn't indicated reference, server got the latest, use absolute now, it's safer | ||
urls = {fn: self.router.package_file(pref, fn) for fn in files} | ||
self._download_and_save_files(urls, dest_folder, files, scope=str(pref.ref)) | ||
ret = {fn: os.path.join(dest_folder, fn) for fn in files} | ||
return ret | ||
if not only_metadata: # Retrieve package first, then metadata | ||
accepted_files = ["conaninfo.txt", "conan_package.tgz", "conanmanifest.txt", | ||
"metadata/sign"] | ||
files = [f for f in server_files if any(f.startswith(m) for m in accepted_files)] | ||
# If we didn't indicated reference, server got the latest, use absolute now, it's safer | ||
urls = {fn: self.router.package_file(pref, fn) for fn in files} | ||
self._download_and_save_files(urls, dest_folder, files, scope=str(pref.ref)) | ||
result.update({fn: os.path.join(dest_folder, fn) for fn in files}) | ||
|
||
if metadata: | ||
metadata = [f"metadata/{m}" for m in metadata] | ||
files = [f for f in server_files if any(fnmatch.fnmatch(f, m) for m in metadata)] | ||
urls = {fn: self.router.package_file(pref, fn) for fn in files} | ||
self._download_and_save_files(urls, dest_folder, files, scope=str(pref.ref), | ||
metadata=True) | ||
result.update({fn: os.path.join(dest_folder, fn) for fn in files}) | ||
return result | ||
|
||
@staticmethod | ||
def _is_dir(path, files): | ||
|
@@ -145,7 +154,8 @@ def _upload_files(self, files, urls): | |
raise ConanException("Execute upload again to retry upload the failed files: %s" | ||
% ", ".join(failed)) | ||
|
||
def _download_and_save_files(self, urls, dest_folder, files, parallel=False, scope=None): | ||
def _download_and_save_files(self, urls, dest_folder, files, parallel=False, scope=None, | ||
metadata=False): | ||
# Take advantage of filenames ordering, so that conan_package.tgz and conan_export.tgz | ||
# can be < conanfile, conaninfo, and sent always the last, so smaller files go first | ||
retry = self._config.get("core.download:retry", check_type=int, default=2) | ||
|
@@ -160,13 +170,14 @@ def _download_and_save_files(self, urls, dest_folder, files, parallel=False, sco | |
if parallel: | ||
kwargs = {"url": resource_url, "file_path": abs_path, "retry": retry, | ||
"retry_wait": retry_wait, "verify_ssl": self.verify_ssl, | ||
"auth": self.auth} | ||
"auth": self.auth, "metadata": metadata} | ||
thread = ExceptionThread(target=downloader.download, kwargs=kwargs) | ||
threads.append(thread) | ||
thread.start() | ||
else: | ||
downloader.download(url=resource_url, file_path=abs_path, auth=self.auth, | ||
verify_ssl=self.verify_ssl, retry=retry, retry_wait=retry_wait) | ||
verify_ssl=self.verify_ssl, retry=retry, retry_wait=retry_wait, | ||
metadata=metadata) | ||
for t in threads: | ||
t.join() | ||
for t in threads: # Need to join all before raising errors | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -278,8 +278,8 @@ def recipe_metadata_folder(self): | |
return self.folders.recipe_metadata_folder | ||
|
||
@property | ||
def pkg_metadata_folder(self): | ||
return self.folders.pkg_metadata_folder | ||
def package_metadata_folder(self): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a rename, to not use the |
||
return self.folders.package_metadata_folder | ||
|
||
@property | ||
def build_path(self) -> Path: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import textwrap | ||
|
||
from conans.test.utils.tools import TestClient | ||
|
||
|
||
class TestMetadataDeploy: | ||
""" prove we can gather metadata too with a deployer | ||
""" | ||
|
||
def test_deploy(self): | ||
# FIXME: It only supports package metadata deployment, because missing internal interface | ||
conanfile = textwrap.dedent(""" | ||
import os | ||
from conan import ConanFile | ||
from conan.tools.files import save, copy | ||
|
||
class Pkg(ConanFile): | ||
version = "0.1" | ||
|
||
def source(self): | ||
save(self, os.path.join(self.recipe_metadata_folder, "logs", "src.log"), | ||
f"srclog {self.name}!!") | ||
|
||
def build(self): | ||
save(self, "mylogs.txt", f"some logs {self.name}!!!") | ||
copy(self, "mylogs.txt", src=self.build_folder, | ||
dst=os.path.join(self.package_metadata_folder, "logs")) | ||
""") | ||
deploy = textwrap.dedent(""" | ||
import os, shutil | ||
|
||
def deploy(graph, output_folder, **kwargs): | ||
conanfile = graph.root.conanfile | ||
for r, d in conanfile.dependencies.items(): | ||
shutil.copytree(d.package_metadata_folder, os.path.join(output_folder, "pkgs", | ||
d.ref.name)) | ||
# FIXME: Missing | ||
#shutil.copytree(d.recipe_metadata_folder, os.path.join(output_folder, "pkgs", | ||
# d.ref.name)) | ||
""") | ||
|
||
c = TestClient() | ||
c.save({"conanfile.py": conanfile, | ||
"deploy.py": deploy}) | ||
c.run("create . --name=pkg1") | ||
c.run("create . --name=pkg2") | ||
c.run("install --requires=pkg1/0.1 --requires=pkg2/0.1 --deployer=deploy") | ||
assert "some logs pkg1!!!" in c.load("pkgs/pkg1/logs/mylogs.txt") | ||
assert "some logs pkg2!!!" in c.load("pkgs/pkg2/logs/mylogs.txt") | ||
# TODO: This must pass | ||
# assert "srclog pkg1!!!" in c.load("recipes/pkg1/logs/src.log") | ||
# assert "srclog pkg2!!!" in c.load("recipes/pkg2/logs/src.log") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Automatic creation of the folder, so
conan cache path --folder=metadata
has an existing folder to copy things to.