Skip to content
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

Proposal for sources backup feature #13461

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
983c453
wip
memsharded Mar 9, 2023
1ca30e1
Create DownloadCache abstracion, add upload test
AbrilRBS Mar 9, 2023
91c8021
Remove unused import
AbrilRBS Mar 9, 2023
c4e1698
Merge pull request #48 from RubenRBS/memsharded-feature/backup_source…
memsharded Mar 9, 2023
9cefe83
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 10, 2023
d9b602f
wip
memsharded Mar 10, 2023
87b064a
wip
memsharded Mar 10, 2023
9b3a2a5
wip
memsharded Mar 10, 2023
17649da
Add soures backup fetching if present
AbrilRBS Mar 10, 2023
4c5f8b1
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 15, 2023
43adea8
fix test
memsharded Mar 15, 2023
d140f1d
checking file existence prior to upload
memsharded Mar 15, 2023
3aeacc4
Split upload and download urls
AbrilRBS Mar 15, 2023
6be07cc
Move conf to proper place in dict
AbrilRBS Mar 15, 2023
cd151f0
Merge branch 'feature/backup_sources_upload' into rr/feature/backup-s…
AbrilRBS Mar 15, 2023
e07423a
Merge pull request #49 from RubenRBS/rr/feature/backup-sources/downlo…
memsharded Mar 15, 2023
6095a0f
Create policy for backup sources cache miss
AbrilRBS Mar 15, 2023
27136c8
Ensure we specify a default for the conf
AbrilRBS Mar 15, 2023
7415799
Rename raise to error, raise on unknown value
AbrilRBS Mar 15, 2023
2158567
Merge pull request #50 from RubenRBS/rr/feature/backup-sources/cache_…
memsharded Mar 15, 2023
a9695f2
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 16, 2023
6a35745
credentials
memsharded Mar 16, 2023
af417c3
wip
memsharded Mar 16, 2023
25f7625
wip
memsharded Mar 16, 2023
742e256
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 16, 2023
63c8e4a
wip
memsharded Mar 16, 2023
cad0379
Update conan/api/subapi/upload.py
memsharded Mar 16, 2023
783a164
Update conan/api/subapi/upload.py
memsharded Mar 16, 2023
17ce194
Update conans/client/rest/file_uploader.py
memsharded Mar 16, 2023
aef2237
Update conan/api/subapi/upload.py
memsharded Mar 16, 2023
52a27e1
Update conans/client/downloaders/caching_file_downloader.py
memsharded Mar 16, 2023
35b4334
Update conan/api/subapi/upload.py
memsharded Mar 16, 2023
db4eff7
Have server folders in a dict and switch them instead of copying the …
AbrilRBS Mar 16, 2023
25cc41d
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 17, 2023
a8edc9d
new core conf and 500-error test
memsharded Mar 17, 2023
09198ee
Change layout of source_credentials.json and summary.json, fix test
AbrilRBS Mar 18, 2023
91506fd
Implement user-defined order, ensure a 500 in original url does not b…
AbrilRBS Mar 23, 2023
be6bc43
Remove unused conf
AbrilRBS Mar 23, 2023
7476eb1
Allow changed checksum workflow for backup sources
AbrilRBS Mar 27, 2023
7e73954
Fix test, it expected ConanException instead of ChecksumSignatureMiss…
AbrilRBS Mar 27, 2023
2c51338
Fix typo
AbrilRBS Mar 27, 2023
beb8621
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 27, 2023
7d92809
refactor and breaking test
memsharded Mar 28, 2023
bebb338
wip
memsharded Mar 28, 2023
8bf1f07
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 28, 2023
5fac255
wip
memsharded Mar 28, 2023
bfb7671
fixes
memsharded Mar 29, 2023
c0e526b
wip
memsharded Mar 29, 2023
13773e1
Minor changes
AbrilRBS Mar 29, 2023
2eb3474
remove space
memsharded Mar 29, 2023
a56fe60
fix cmake --presets message version
memsharded Mar 28, 2023
cfc640a
improve ConanProxy performance with cache
memsharded Mar 29, 2023
09c0a71
cmd_wrapper must get the conanfile argument
memsharded Mar 29, 2023
0d49f0e
refactor
memsharded Mar 29, 2023
0626ca0
Merge branch 'release/2.0' into feature/backup_sources_upload
memsharded Mar 30, 2023
975ed11
docstrings
memsharded Mar 30, 2023
7e91395
fix
memsharded Mar 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions conan/api/subapi/upload.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import os

from conan.api.output import ConanOutput
from conan.internal.conan_app import ConanApp
from conans.client.cmd.uploader import PackagePreparator, UploadExecutor, UploadUpstreamChecker
from conans.client.downloaders.download_cache import DownloadCache
from conans.client.pkg_sign import PkgSignaturesPlugin
from conans.client.rest.file_uploader import FileUploader
from conans.errors import ConanException, AuthenticationException, ForbiddenException


class UploadAPI:
Expand Down Expand Up @@ -40,3 +45,34 @@ def upload(self, package_list, remote):
app.remote_manager.check_credentials(remote)
executor = UploadExecutor(app)
executor.upload(package_list, remote)

def upload_backup_sources(self, package_list):
app = ConanApp(self.conan_api.cache_folder)
config = app.cache.new_config
url = config.get("core.sources:upload_url")
if url is None:
return
url = url if url.endswith("/") else url + "/"
download_cache_path = config.get("core.sources:download_cache")
download_cache_path = download_cache_path or app.cache.default_sources_backup_folder

files = DownloadCache(download_cache_path).get_backup_sources_files_to_upload(package_list)
# TODO: verify might need a config to force it to False
uploader = FileUploader(app.requester, verify=True, config=config)
# TODO: For Artifactory, we can list all files once and check from there instead
# of 1 request per file, but this is more general
for file in files:
basename = os.path.basename(file)
full_url = url + basename
try:
# Always upload summary .json but only upload blob if it does not already exist
if file.endswith(".json") or not uploader.exists(full_url, auth=None):
ConanOutput().info(f"Uploading file '{basename}' to backup sources server")
uploader.upload(full_url, file, dedup=False, auth=None)
else:
ConanOutput().info(f"File '{basename}' already in backup sources server, "
"skipping upload")
except (AuthenticationException, ForbiddenException) as e:
raise ConanException(f"The source backup server '{url}' needs authentication"
f"/permissions, please provide 'source_credentials.json': {e}")
return files
2 changes: 2 additions & 0 deletions conan/cli/commands/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ def upload(conan_api: ConanAPI, parser, *args):
conan_api.upload.prepare(package_list, enabled_remotes)
conan_api.upload.upload(package_list, remote)

conan_api.upload.upload_backup_sources(package_list)


def _ask_confirm_upload(conan_api, upload_data):
ui = UserInput(conan_api.config.get("core:non_interactive"))
Expand Down
5 changes: 3 additions & 2 deletions conan/internal/conan_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ def wrap(self, cmd, conanfile, **kwargs):


class ConanFileHelpers:
def __init__(self, requester, cmd_wrapper, global_conf):
def __init__(self, requester, cmd_wrapper, global_conf, cache):
self.requester = requester
self.cmd_wrapper = cmd_wrapper
self.global_conf = global_conf
self.cache = cache


class ConanApp(object):
Expand All @@ -56,5 +57,5 @@ def __init__(self, cache_folder):

self.pyreq_loader = PyRequireLoader(self.proxy, self.range_resolver)
cmd_wrap = CmdWrapper(self.cache)
conanfile_helpers = ConanFileHelpers(self.requester, cmd_wrap, global_conf)
conanfile_helpers = ConanFileHelpers(self.requester, cmd_wrap, global_conf, self.cache)
self.loader = ConanFileLoader(self.pyreq_loader, conanfile_helpers)
64 changes: 4 additions & 60 deletions conan/tools/files/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
from contextlib import contextmanager
from fnmatch import fnmatch
from shutil import which
from urllib.parse import urlparse
from urllib.request import url2pathname

from conan.api.output import ConanOutput
from conans.client.downloaders.caching_file_downloader import CachingFileDownloader

from conans.client.downloaders.caching_file_downloader import SourcesCachingDownloader
from conans.errors import ConanException
from conans.util.files import rmdir as _internal_rmdir
from conans.util.sha import check_with_algorithm_sum
Expand Down Expand Up @@ -189,70 +187,16 @@ def download(conanfile, url, filename, verify=True, retry=None, retry_wait=None,
:param sha1: SHA-1 hash code to check the downloaded file
:param sha256: SHA-256 hash code to check the downloaded file
"""
# TODO: Add all parameters to the new conf
requester = conanfile._conan_helpers.requester
global_conf = conanfile._conan_helpers.global_conf
config = conanfile.conf
out = ConanOutput()
overwrite = True

retry = retry if retry is not None else 2
retry = config.get("tools.files.download:retry", check_type=int, default=retry)
retry_wait = retry_wait if retry_wait is not None else 5
retry_wait = config.get("tools.files.download:retry_wait", check_type=int, default=retry_wait)

download_cache = None
if md5 or sha1 or sha256: # If there is no checksum, no cache is used
download_cache = config.get("tools.files.download:download_cache")
download_cache = download_cache or global_conf.get("core.download:download_cache")
if download_cache and not os.path.isabs(download_cache):
raise ConanException("core.download:download_cache must be an absolute path")

filename = os.path.abspath(filename)

def _download_file(file_url):
# The download cache is only used if a checksum is provided, otherwise, a normal download
if file_url.startswith("file:"):
_copy_local_file_from_uri(conanfile, url=file_url, file_path=filename, md5=md5,
sha1=sha1, sha256=sha256)
else:
downloader = CachingFileDownloader(requester, download_cache=download_cache)
os.makedirs(os.path.dirname(filename), exist_ok=True) # filename in subfolder must exist
downloader.download(url=file_url, file_path=filename, auth=auth, overwrite=overwrite,
verify_ssl=verify, retry=retry, retry_wait=retry_wait,
headers=headers, md5=md5, sha1=sha1, sha256=sha256,
conanfile=conanfile)
out.writeln("")

if not isinstance(url, (list, tuple)):
_download_file(url)
else: # We were provided several URLs to try
for url_it in url:
try:
_download_file(url_it)
break
except Exception as error:
message = "Could not download from the URL {}: {}.".format(url_it, str(error))
out.warning(message + " Trying another mirror.")
else:
raise ConanException("All downloads from ({}) URLs have failed.".format(len(url)))


def _copy_local_file_from_uri(conanfile, url, file_path, md5=None, sha1=None, sha256=None):
file_origin = _path_from_file_uri(url)
shutil.copyfile(file_origin, file_path)

if md5 is not None:
check_md5(conanfile, file_path, md5)
if sha1 is not None:
check_sha1(conanfile, file_path, sha1)
if sha256 is not None:
check_sha256(conanfile, file_path, sha256)


def _path_from_file_uri(uri):
path = urlparse(uri).path
return url2pathname(path)
downloader = SourcesCachingDownloader(conanfile)
downloader.download(url, filename, retry, retry_wait, verify, auth, headers, md5, sha1, sha256)


def rename(conanfile, src, dst):
Expand Down
4 changes: 4 additions & 0 deletions conans/client/cache/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ def get_latest_package_reference(self, pref):
def store(self):
return self._store_folder

@property
def default_sources_backup_folder(self):
return os.path.join(self.cache_folder, "sources")

@property
def remotes_path(self):
return os.path.join(self.cache_folder, REMOTES)
Expand Down
Loading