Skip to content

Commit

Permalink
Merge branch 'develop2' into release/2.0-beta
Browse files Browse the repository at this point in the history
  • Loading branch information
czoido committed Feb 16, 2023
2 parents 7b6a8b4 + 7133154 commit ff689e5
Show file tree
Hide file tree
Showing 223 changed files with 3,047 additions and 2,651 deletions.
26 changes: 0 additions & 26 deletions conan/api/subapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,26 +0,0 @@
import functools
import os

from conans.util.tracer import log_conan_api_call


def api_method(f):
"""Useful decorator to manage Conan API methods"""

@functools.wraps(f)
def wrapper(subapi, *args, **kwargs):
try: # getcwd can fail if Conan runs on an non-existing folder
old_curdir = os.getcwd()
except EnvironmentError:
old_curdir = None

try:
# FIXME: Fix this hack if we want to keep the action recorder
subapi_name = str(subapi.__class__.__name__).replace("API", "").lower()
log_conan_api_call("{}.{}".format(subapi_name, f.__name__), kwargs)
return f(subapi, *args, **kwargs)
finally:
if old_curdir:
os.chdir(old_curdir)

return wrapper
32 changes: 25 additions & 7 deletions conan/api/subapi/cache.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,76 @@
from conan.api.subapi import api_method
from conan.internal.conan_app import ConanApp
from conan.internal.integrity_check import IntegrityChecker
from conans.errors import ConanException
from conans.model.package_ref import PkgReference
from conans.model.recipe_ref import RecipeReference
from conans.util.files import rmdir


class CacheAPI:

def __init__(self, conan_api):
self.conan_api = conan_api

@api_method
def export_path(self, ref: RecipeReference):
app = ConanApp(self.conan_api.cache_folder)
ref = _resolve_latest_ref(app, ref)
ref_layout = app.cache.ref_layout(ref)
return ref_layout.export()

@api_method
def export_source_path(self, ref: RecipeReference):
app = ConanApp(self.conan_api.cache_folder)
ref = _resolve_latest_ref(app, ref)
ref_layout = app.cache.ref_layout(ref)
return ref_layout.export_sources()

@api_method
def source_path(self, ref: RecipeReference):
app = ConanApp(self.conan_api.cache_folder)
ref = _resolve_latest_ref(app, ref)
ref_layout = app.cache.ref_layout(ref)
return ref_layout.source()

@api_method
def build_path(self, pref: PkgReference):
app = ConanApp(self.conan_api.cache_folder)
pref = _resolve_latest_pref(app, pref)
ref_layout = app.cache.pkg_layout(pref)
return ref_layout.build()

@api_method
def package_path(self, pref: PkgReference):
app = ConanApp(self.conan_api.cache_folder)
pref = _resolve_latest_pref(app, pref)
ref_layout = app.cache.pkg_layout(pref)
return ref_layout.package()

@api_method
def check_integrity(self, package_list):
"""Check if the recipes and packages are corrupted (it will raise a ConanExcepcion)"""
app = ConanApp(self.conan_api.cache_folder)
checker = IntegrityChecker(app)
checker.check(package_list)

def clean(self, package_list, source=None, build=None, download=None):
"""
Remove non critical folders from the cache, like source, build and download (.tgz store)
folders.
:param package_list: the package lists that should be cleaned
:param source: boolean, remove the "source" folder if True
:param build: boolean, remove the "build" folder if True
:param download: boolena, remove the "download (.tgz)" folder if True
:return:
"""
app = ConanApp(self.conan_api.cache_folder)
for ref, ref_bundle in package_list.refs():
ref_layout = app.cache.ref_layout(ref)
if source:
rmdir(ref_layout.source())
if download:
rmdir(ref_layout.download_export())
for pref, _ in package_list.prefs(ref, ref_bundle):
pref_layout = app.cache.pkg_layout(pref)
if build:
rmdir(pref_layout.build())
if download:
rmdir(pref_layout.download_package())


def _resolve_latest_ref(app, ref):
if ref.revision is None or ref.revision == "latest":
Expand Down
4 changes: 0 additions & 4 deletions conan/api/subapi/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from conan.api.subapi import api_method
from conan.internal.conan_app import ConanApp


Expand All @@ -7,11 +6,9 @@ class ConfigAPI:
def __init__(self, conan_api):
self.conan_api = conan_api

@api_method
def home(self):
return self.conan_api.cache_folder

@api_method
def install(self, path_or_url, verify_ssl, config_type=None, args=None,
source_folder=None, target_folder=None):
# TODO: We probably want to split this into git-folder-http cases?
Expand All @@ -21,7 +18,6 @@ def install(self, path_or_url, verify_ssl, config_type=None, args=None,
config_type=config_type, args=args,
source_folder=source_folder, target_folder=target_folder)

@api_method
def get(self, name, default=None, check_type=None):
app = ConanApp(self.conan_api.cache_folder)
return app.cache.new_config.get(name, default=default, check_type=check_type)
3 changes: 0 additions & 3 deletions conan/api/subapi/download.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from conan.api.model import Remote
from conan.api.subapi import api_method
from conan.api.output import ConanOutput
from conan.internal.conan_app import ConanApp
from conans.client.source import retrieve_exports_sources
Expand All @@ -13,7 +12,6 @@ class DownloadAPI:
def __init__(self, conan_api):
self.conan_api = conan_api

@api_method
def recipe(self, ref: RecipeReference, remote: Remote):
output = ConanOutput()
app = ConanApp(self.conan_api.cache_folder)
Expand All @@ -34,7 +32,6 @@ def recipe(self, ref: RecipeReference, remote: Remote):
retrieve_exports_sources(app.remote_manager, layout, conanfile, ref, [remote])
return True

@api_method
def package(self, pref: PkgReference, remote: Remote):
output = ConanOutput()
app = ConanApp(self.conan_api.cache_folder)
Expand Down
9 changes: 0 additions & 9 deletions conan/api/subapi/export.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
from conan.api.output import ConanOutput
from conan.api.subapi import api_method
from conan.internal.conan_app import ConanApp
from conans.client.cmd.export import cmd_export
from conans.client.conanfile.package import run_package_method
from conans.client.graph.graph import BINARY_INVALID
from conans.errors import ConanInvalidConfiguration
from conans.model.package_ref import PkgReference


Expand All @@ -13,13 +10,11 @@ class ExportAPI:
def __init__(self, conan_api):
self.conan_api = conan_api

@api_method
def export(self, path, name, version, user, channel, lockfile=None, remotes=None):
app = ConanApp(self.conan_api.cache_folder)
return cmd_export(app, path, name, version, user, channel, graph_lock=lockfile,
remotes=remotes)

@api_method
def export_pkg(self, deps_graph, source_folder, output_folder):
app = ConanApp(self.conan_api.cache_folder)
cache, hook_manager = app.cache, app.hook_manager
Expand All @@ -32,10 +27,6 @@ def export_pkg(self, deps_graph, source_folder, output_folder):
ref = pkg_node.ref
out = ConanOutput(scope=pkg_node.conanfile.display_name)
out.info("Exporting binary from user folder to Conan cache")
if pkg_node.binary == BINARY_INVALID:
binary, reason = "Invalid", pkg_node.conanfile.info.invalid
msg = "{}: Invalid ID: {}: {}".format(ref, binary, reason)
raise ConanInvalidConfiguration(msg)
conanfile = pkg_node.conanfile

package_id = pkg_node.package_id
Expand Down
17 changes: 6 additions & 11 deletions conan/api/subapi/graph.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os

from conan.api.output import ConanOutput
from conan.api.subapi import api_method
from conan.internal.conan_app import ConanApp
from conan.cli.printers.graph import print_graph_basic
from conans.client.graph.graph import Node, RECIPE_CONSUMER, CONTEXT_HOST, RECIPE_VIRTUAL
Expand All @@ -22,7 +21,8 @@ def __init__(self, conan_api):

def _load_root_consumer_conanfile(self, path, profile_host, profile_build,
name=None, version=None, user=None, channel=None,
update=None, remotes=None, lockfile=None):
update=None, remotes=None, lockfile=None,
is_build_require=False):
app = ConanApp(self.conan_api.cache_folder)

if path.endswith(".py"):
Expand All @@ -37,7 +37,7 @@ def _load_root_consumer_conanfile(self, path, profile_host, profile_build,
ref = RecipeReference(conanfile.name, conanfile.version,
conanfile.user, conanfile.channel)
initialize_conanfile_profile(conanfile, profile_build, profile_host, CONTEXT_HOST,
False, ref)
is_build_require, ref)
if ref.name:
profile_host.options.scope(ref)
root_node = Node(ref, conanfile, context=CONTEXT_HOST, recipe=RECIPE_CONSUMER, path=path)
Expand All @@ -49,7 +49,6 @@ def _load_root_consumer_conanfile(self, path, profile_host, profile_build,
path=path)
return root_node

@api_method
def load_root_test_conanfile(self, path, tested_reference, profile_host, profile_build,
update=None, remotes=None, lockfile=None,
tested_python_requires=None):
Expand Down Expand Up @@ -110,7 +109,6 @@ def _scope_options(profile, requires, tool_requires):
if tool_requires and len(tool_requires) == 1 and not requires:
profile.options.scope(tool_requires[0])

@api_method
def load_graph_requires(self, requires, tool_requires, profile_host, profile_build,
lockfile, remotes, update, check_updates=False, allow_error=False):
requires = [RecipeReference.loads(r) if isinstance(r, str) else r for r in requires] \
Expand Down Expand Up @@ -145,10 +143,9 @@ def load_graph_requires(self, requires, tool_requires, profile_host, profile_bui

return deps_graph

@api_method
def load_graph_consumer(self, path, name, version, user, channel,
profile_host, profile_build, lockfile, remotes, update,
allow_error=False, check_updates=False):
allow_error=False, check_updates=False, is_build_require=False):
out = ConanOutput()
out.title("Input profiles")
out.info("Profile host:")
Expand All @@ -159,7 +156,8 @@ def load_graph_consumer(self, path, name, version, user, channel,
root_node = self._load_root_consumer_conanfile(path, profile_host, profile_build,
name=name, version=version, user=user,
channel=channel, lockfile=lockfile,
remotes=remotes, update=update)
remotes=remotes, update=update,
is_build_require=is_build_require)

out.title("Computing dependency graph")
deps_graph = self.load_graph(root_node, profile_host=profile_host,
Expand All @@ -173,7 +171,6 @@ def load_graph_consumer(self, path, name, version, user, channel,

return deps_graph

@api_method
def load_graph(self, root_node, profile_host, profile_build, lockfile=None, remotes=None,
update=False, check_update=False):
""" Compute the dependency graph, starting from a root package, evaluation the graph with
Expand Down Expand Up @@ -203,7 +200,6 @@ def load_graph(self, root_node, profile_host, profile_build, lockfile=None, remo
deps_graph = builder.load_graph(root_node, profile_host, profile_build, lockfile)
return deps_graph

@api_method
def analyze_binaries(self, graph, build_mode=None, remotes=None, update=None, lockfile=None):
""" Given a dependency graph, will compute the package_ids of all recipes in the graph, and
evaluate if they should be built from sources, downloaded from a remote server, of if the
Expand All @@ -221,7 +217,6 @@ def analyze_binaries(self, graph, build_mode=None, remotes=None, update=None, lo
binaries_analyzer = GraphBinariesAnalyzer(conan_app)
binaries_analyzer.evaluate_graph(graph, build_mode, lockfile, remotes, update)

@api_method
def load_conanfile_class(self, path):
""" Given a path to a conanfile.py file, it loads its class (not instance) to allow
inspecting the class attributes, like 'name', 'version', 'description', 'options' etc"""
Expand Down
5 changes: 1 addition & 4 deletions conan/api/subapi/install.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from conan.api.subapi import api_method
from conan.internal.conan_app import ConanApp
from conan.internal.deploy import do_deploys
from conans.client.generators import write_generators
Expand All @@ -12,7 +11,6 @@ class InstallAPI:
def __init__(self, conan_api):
self.conan_api = conan_api

@api_method
def install_binaries(self, deps_graph, remotes=None):
""" Install binaries for dependency graph
:param deps_graph: Dependency graph to intall packages for
Expand All @@ -23,7 +21,6 @@ def install_binaries(self, deps_graph, remotes=None):
installer.install_system_requires(deps_graph) # TODO: Optimize InstallGraph computation
installer.install(deps_graph, remotes)

@api_method
def install_system_requires(self, graph, only_info=False):
""" Install binaries for dependency graph
:param only_info: Only allow reporting and checking, but never install
Expand All @@ -33,9 +30,9 @@ def install_system_requires(self, graph, only_info=False):
installer = BinaryInstaller(app)
installer.install_system_requires(graph, only_info)

@api_method
def install_sources(self, graph, remotes):
""" Install sources for dependency graph
:param remotes:
:param graph: Dependency graph to install packages for
"""
app = ConanApp(self.conan_api.cache_folder)
Expand Down
27 changes: 26 additions & 1 deletion conan/api/subapi/local.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import os

from conan.cli.commands import make_abs_path
from conan.internal.conan_app import ConanApp
from conans.errors import ConanException
from conans.model.recipe_ref import RecipeReference


class LocalAPI:

def __init__(self, conan_api):
self.conan_api = conan_api
self._conan_api = conan_api

@staticmethod
def get_conanfile_path(path, cwd, py):
Expand All @@ -33,3 +35,26 @@ def get_conanfile_path(path, cwd, py):
raise ConanException("A conanfile.py is needed, " + path + " is not acceptable")

return path

def editable_add(self, path, name=None, version=None, user=None, channel=None, cwd=None,
output_folder=None):
path = self._conan_api.local.get_conanfile_path(path, cwd, py=True)
app = ConanApp(self._conan_api.cache_folder)
conanfile = app.loader.load_named(path, name, version, user, channel)
ref = RecipeReference(conanfile.name, conanfile.version, conanfile.user, conanfile.channel)
# Retrieve conanfile.py from target_path
target_path = self._conan_api.local.get_conanfile_path(path=path, cwd=cwd, py=True)
output_folder = make_abs_path(output_folder) if output_folder else None
# Check the conanfile is there, and name/version matches
app.cache.editable_packages.add(ref, target_path, output_folder=output_folder)
return ref

def editable_remove(self, path=None, requires=None, cwd=None):
app = ConanApp(self._conan_api.cache_folder)
if path:
path = self._conan_api.local.get_conanfile_path(path, cwd, py=True)
return app.cache.editable_packages.remove(path, requires)

def editable_list(self):
app = ConanApp(self._conan_api.cache_folder)
return app.cache.editable_packages.edited_refs
11 changes: 5 additions & 6 deletions conan/api/subapi/lockfile.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os

from conan.api.output import ConanOutput
from conan.api.subapi import api_method
from conan.cli.commands import make_abs_path
from conans.errors import ConanException
from conans.model.graph_lock import Lockfile, LOCKFILE
Expand All @@ -12,11 +11,11 @@ class LockfileAPI:
def __init__(self, conan_api):
self.conan_api = conan_api

@api_method
def get_lockfile(self, lockfile=None, conanfile_path=None, cwd=None, partial=False):
""" obtain a lockfile, following this logic:
- If lockfile is explicitly defined, it would be either absolute or relative to cwd
the lockfile file must exist. If lockfile="None" (as string, no lockfile will be used)
- If lockfile is explicitly defined, it would be either absolute or relative to cwd and
the lockfile file must exist. If lockfile="" (empty string) the default "conan.lock"
lockfile will not be automatically used even if it is present.
- If lockfile is not defined, it will still look for a default conan.lock:
- if conanfile_path is defined, it will be besides it
- if conanfile_path is not defined, the default conan.lock should be in cwd
Expand All @@ -27,8 +26,8 @@ def get_lockfile(self, lockfile=None, conanfile_path=None, cwd=None, partial=Fal
:param conanfile_path: The full path to the conanfile, if existing
:param lockfile: the name of the lockfile file
"""
if lockfile == "None":
# Allow a way with ``--lockfile=None`` to optout automatic usage of conan.lock
if lockfile == "":
# Allow a way with ``--lockfile=""`` to optout automatic usage of conan.lock
return

cwd = cwd or os.getcwd()
Expand Down
Loading

0 comments on commit ff689e5

Please sign in to comment.