1import os 2import shutil 3 4from conans.client.source import retrieve_exports_sources 5from conans.errors import ConanException 6from conans.model.ref import ConanFileReference, PackageReference 7from conans.util.files import rmdir 8 9 10def _prepare_sources(cache, ref, remote_manager, loader, remotes): 11 conan_file_path = cache.package_layout(ref).conanfile() 12 conanfile = loader.load_basic(conan_file_path) 13 retrieve_exports_sources(remote_manager, cache, conanfile, ref, remotes) 14 return conanfile.short_paths 15 16 17def cmd_copy(ref, user_channel, package_ids, cache, user_io, remote_manager, loader, remotes, 18 force=False): 19 """ 20 param package_ids: Falsey=do not copy binaries. True=All existing. []=list of ids 21 """ 22 # It is important to get the revision early, so "retrieve_exports_sources" can 23 # get the right revision sources, not latest 24 layout = cache.package_layout(ref) 25 src_metadata = layout.load_metadata() 26 ref = ref.copy_with_rev(src_metadata.recipe.revision) 27 short_paths = _prepare_sources(cache, ref, remote_manager, loader, remotes) 28 package_ids = layout.package_ids() if package_ids is True else (package_ids or []) 29 package_copy(ref, user_channel, package_ids, cache, user_io, short_paths, force) 30 31 32def package_copy(src_ref, user_channel, package_ids, cache, user_io, short_paths=False, 33 force=False): 34 35 ref = "%s/%s@%s" % (src_ref.name, src_ref.version, user_channel) 36 if ref.count('@') > 1: 37 raise ConanException("Destination must contain user/channel only.") 38 39 dest_ref = ConanFileReference.loads(ref) 40 # Generate metadata 41 src_layout = cache.package_layout(src_ref, short_paths) 42 src_metadata = src_layout.load_metadata() 43 dst_layout = cache.package_layout(dest_ref, short_paths) 44 45 # Copy export 46 export_origin = src_layout.export() 47 if not os.path.exists(export_origin): 48 raise ConanException("'%s' doesn't exist" % str(src_ref)) 49 export_dest = dst_layout.export() 50 if os.path.exists(export_dest): 51 if not force and not user_io.request_boolean("'%s' already exist. Override?" 52 % str(dest_ref)): 53 return 54 rmdir(export_dest) 55 shutil.copytree(export_origin, export_dest, symlinks=True) 56 user_io.out.info("Copied %s to %s" % (str(src_ref), str(dest_ref))) 57 58 export_sources_origin = src_layout.export_sources() 59 export_sources_dest = dst_layout.export_sources() 60 if os.path.exists(export_sources_dest): 61 rmdir(export_sources_dest) 62 shutil.copytree(export_sources_origin, export_sources_dest, symlinks=True) 63 user_io.out.info("Copied sources %s to %s" % (str(src_ref), str(dest_ref))) 64 65 # Copy packages 66 package_revisions = {} # To be stored in the metadata 67 for package_id in package_ids: 68 pref_origin = PackageReference(src_ref, package_id) 69 pref_dest = PackageReference(dest_ref, package_id) 70 package_path_origin = src_layout.package(pref_origin) 71 if dst_layout.package_id_exists(package_id): 72 if not force and not user_io.request_boolean("Package '%s' already exist." 73 " Override?" % str(package_id)): 74 continue 75 dst_layout.package_remove(pref_dest) 76 package_path_dest = dst_layout.package(pref_dest) 77 package_revisions[package_id] = (src_metadata.packages[package_id].revision, 78 src_metadata.recipe.revision) 79 shutil.copytree(package_path_origin, package_path_dest, symlinks=True) 80 user_io.out.info("Copied %s to %s" % (str(package_id), str(dest_ref))) 81 82 # The downloaded .tgz files can also be copied 83 src_download = src_layout.download_package(pref_origin) 84 dst_download = dst_layout.download_package(pref_dest) 85 rmdir(dst_download) 86 if os.path.isdir(src_download): 87 shutil.copytree(src_download, dst_download) 88 89 # The downloaded export and sources .tgz files can also be copied 90 src_download = src_layout.download_export() 91 dst_download = dst_layout.download_export() 92 rmdir(dst_download) 93 if os.path.isdir(src_download): 94 shutil.copytree(src_download, dst_download) 95 96 # Generate the metadata 97 with dst_layout.update_metadata() as metadata: 98 metadata.recipe.revision = src_metadata.recipe.revision 99 for package_id, (revision, recipe_revision) in package_revisions.items(): 100 metadata.packages[package_id].revision = revision 101 metadata.packages[package_id].recipe_revision = recipe_revision 102