conans/server/service/common/search.py
import os
import re
from fnmatch import translate
from conans import load
from conans.errors import NotFoundException, ForbiddenException, RecipeNotFoundException
from conans.model.info import ConanInfo
from conans.model.ref import PackageReference, ConanFileReference
from conans.paths import CONANINFO
from conans.search.search import filter_packages, _partial_match
from conans.util.files import list_folder_subdirs
from conans.util.log import logger
def _get_local_infos_min(server_store, ref, look_in_all_rrevs):
result = {}
rrevs = server_store.get_recipe_revisions(ref) if look_in_all_rrevs else [None]
for rrev in rrevs:
new_ref = ref.copy_with_rev(rrev.revision) if rrev else ref
subdirs = list_folder_subdirs(server_store.packages(new_ref), level=1)
for package_id in subdirs:
if package_id in result:
continue
# Read conaninfo
try:
pref = PackageReference(new_ref, package_id)
revision_entry = server_store.get_last_package_revision(pref)
if not revision_entry:
raise NotFoundException("")
pref = PackageReference(new_ref, package_id, revision_entry.revision)
info_path = os.path.join(server_store.package(pref), CONANINFO)
if not os.path.exists(info_path):
raise NotFoundException("")
content = load(info_path)
info = ConanInfo.loads(content)
# From Conan 1.48 the conaninfo.txt is sent raw.
result[package_id] = {"content": content}
# FIXME: This could be removed in the conan_server, Artifactory should keep it
# to guarantee compatibility with old conan clients.
conan_vars_info = info.serialize_min()
result[package_id].update(conan_vars_info)
except Exception as exc: # FIXME: Too wide
logger.error("Package %s has no ConanInfo file" % str(pref))
if str(exc):
logger.error(str(exc))
return result
def search_packages(server_store, ref, query, look_in_all_rrevs):
"""
Used both for v1 and v2. V1 will iterate rrevs.
Return a dict like this:
{package_ID: {name: "OpenCV",
version: "2.14",
settings: {os: Windows}}}
param ref: ConanFileReference object
"""
if not look_in_all_rrevs and ref.revision is None:
found_ref = server_store.get_last_revision(ref)
if found_ref is None:
raise RecipeNotFoundException(ref)
latest_rev = found_ref.revision
ref = ref.copy_with_rev(latest_rev)
if not os.path.exists(server_store.conan_revisions_root(ref.copy_clear_rev())):
raise RecipeNotFoundException(ref)
infos = _get_local_infos_min(server_store, ref, look_in_all_rrevs)
assert query is None, "The server is not filtering packages remotely anymore"
return infos
class SearchService(object):
def __init__(self, authorizer, server_store, auth_user):
self._authorizer = authorizer
self._server_store = server_store
self._auth_user = auth_user
def search_packages(self, reference, query, look_in_all_rrevs=False):
"""Shared between v1 and v2, v1 will iterate rrevs"""
self._authorizer.check_read_conan(self._auth_user, reference)
info = search_packages(self._server_store, reference, query, look_in_all_rrevs)
return info
def _search_recipes(self, pattern=None, ignorecase=True):
subdirs = list_folder_subdirs(basedir=self._server_store.store, level=5)
if not pattern:
return sorted([ConanFileReference(*folder.split("/")).copy_clear_rev()
for folder in subdirs])
else:
# Conan references in main storage
pattern = str(pattern)
b_pattern = translate(pattern)
b_pattern = re.compile(b_pattern, re.IGNORECASE) if ignorecase else re.compile(b_pattern)
ret = set()
for subdir in subdirs:
new_ref = ConanFileReference(*subdir.split("/"))
if _partial_match(b_pattern, repr(new_ref)):
ret.add(new_ref.copy_clear_rev())
return sorted(ret)
def search(self, pattern=None, ignorecase=True):
""" Get all the info about any package
Attributes:
pattern = wildcards like opencv/*
"""
refs = self._search_recipes(pattern, ignorecase)
filtered = []
# Filter out restricted items
for ref in refs:
try:
self._authorizer.check_read_conan(self._auth_user, ref)
filtered.append(ref)
except ForbiddenException:
pass
return filtered