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

Conanfile set_name() and set_version() #5881

Merged
merged 15 commits into from Oct 23, 2019
6 changes: 2 additions & 4 deletions conans/client/conan_api.py
Expand Up @@ -261,7 +261,6 @@ def inspect(self, path, attributes, remote_name=None):
ref = ConanFileReference.loads(path)
except ConanException:
conanfile_path = _get_conanfile_path(path, get_cwd(), py=True)
ref = os.path.basename(conanfile_path)
conanfile_class = self.app.loader.load_class(conanfile_path)
else:
update = True if remote_name else False
Expand All @@ -271,7 +270,7 @@ def inspect(self, path, attributes, remote_name=None):
conanfile_class.name = ref.name
conanfile_class.version = ref.version

conanfile = conanfile_class(self.app.out, None, repr(ref))
conanfile = conanfile_class # temporary hack, to minimize changes

result = OrderedDict()
if not attributes:
Expand Down Expand Up @@ -1054,8 +1053,7 @@ def export_alias(self, reference, target_reference):
# Do not allow to override an existing package
alias_conanfile_path = self.app.cache.package_layout(ref).conanfile()
if os.path.exists(alias_conanfile_path):
conanfile_class = self.app.loader.load_class(alias_conanfile_path)
conanfile = conanfile_class(self.app.out, None, repr(ref))
conanfile = self.app.loader.load_class(alias_conanfile_path)
if not getattr(conanfile, 'alias', None):
raise ConanException("Reference '{}' is already a package, remove it before "
"creating and alias with the same name".format(ref))
Expand Down
82 changes: 47 additions & 35 deletions conans/client/loader.py
Expand Up @@ -29,10 +29,11 @@ def __init__(self, runner, output, python_requires):
sys.modules["conans"].python_requires = python_requires
self.cached_conanfiles = {}

def load_class(self, conanfile_path, lock_python_requires=None):
def load_class(self, conanfile_path, lock_python_requires=None, user=None, channel=None,
display=""):
cached = self.cached_conanfiles.get(conanfile_path)
if cached and cached[1] == lock_python_requires:
return cached[0]
return cached[0](self._output, self._runner, display, user, channel)

if lock_python_requires is not None:
self._python_requires.locked_versions = {r.name: r for r in lock_python_requires}
Expand All @@ -46,7 +47,7 @@ def load_class(self, conanfile_path, lock_python_requires=None):

conanfile.conan_data = self._load_data(conanfile_path)

return conanfile
return conanfile(self._output, self._runner, display, user, channel)
except ConanException as e:
raise ConanException("Error loading conanfile at '{}': {}".format(conanfile_path, e))

Expand All @@ -64,28 +65,37 @@ def _load_data(conanfile_path):
return data or {}

def load_export(self, conanfile_path, name, version, user, channel, lock_python_requires=None):
conanfile = self.load_class(conanfile_path, lock_python_requires)
conanfile = self.load_class(conanfile_path, lock_python_requires, user, channel)

if hasattr(conanfile, "get_name"):
if conanfile.name:
raise ConanException("Conanfile defined package 'name', get_name() redundant")
conanfile.get_name()
if hasattr(conanfile, "get_version"):
if conanfile.version:
raise ConanException("Conanfile defined package 'version', get_version() redundant")
conanfile.get_version()

# Export does a check on existing name & version
if "name" in conanfile.__dict__:
if name and name != conanfile.name:
raise ConanException("Package recipe exported with name %s!=%s"
% (name, conanfile.name))
elif not name:
raise ConanException("conanfile didn't specify name")
else:
if name and conanfile.name and name != conanfile.name:
raise ConanException("Package recipe exported with name %s!=%s" % (name, conanfile.name))
if name:
conanfile.name = name
if not conanfile.name:
raise ConanException("conanfile didn't specify name")

if "version" in conanfile.__dict__:
if version and version != conanfile.version:
raise ConanException("Package recipe exported with version %s!=%s"
% (version, conanfile.version))
elif not version:
raise ConanException("conanfile didn't specify version")
else:
if version and conanfile.version and version != conanfile.version:
raise ConanException("Package recipe exported with version %s!=%s"
% (version, conanfile.version))
if version:
conanfile.version = version
if not conanfile.version:
raise ConanException("conanfile didn't specify version")

ref = ConanFileReference(conanfile.name, conanfile.version, user, channel)
return conanfile(self._output, self._runner, str(ref), ref.user, ref.channel)
conanfile.display_name = str(ref)
conanfile.output.scope = conanfile.display_name
return conanfile

@staticmethod
def _initialize_conanfile(conanfile, processed_profile):
Expand All @@ -96,6 +106,7 @@ def _initialize_conanfile(conanfile, processed_profile):
if package_settings_values:
pkg_settings = package_settings_values.get(conanfile.name)
if pkg_settings is None:
# FIXME: This seems broken for packages without user/channel
ref = "%s/%s@%s/%s" % (conanfile.name, conanfile.version,
conanfile._conan_user, conanfile._conan_channel)
for pattern, settings in package_settings_values.items():
Expand All @@ -110,24 +121,24 @@ def _initialize_conanfile(conanfile, processed_profile):
def load_consumer(self, conanfile_path, processed_profile, name=None, version=None, user=None,
channel=None, test=None, lock_python_requires=None):

conanfile_class = self.load_class(conanfile_path, lock_python_requires)
if name and conanfile_class.name and name != conanfile_class.name:
raise ConanException("Package recipe name %s!=%s" % (name, conanfile_class.name))
if version and conanfile_class.version and version != conanfile_class.version:
conanfile = self.load_class(conanfile_path, lock_python_requires, user, channel)
if name and conanfile.name and name != conanfile.name:
raise ConanException("Package recipe name %s!=%s" % (name, conanfile.name))
if version and conanfile.version and version != conanfile.version:
raise ConanException("Package recipe version %s!=%s"
% (version, conanfile_class.version))
conanfile_class.name = name or conanfile_class.name
conanfile_class.version = version or conanfile_class.version
% (version, conanfile.version))
conanfile.name = name or conanfile.name
conanfile.version = version or conanfile.version
if test:
display_name = "%s (test package)" % str(test)
conanfile.display_name = "%s (test package)" % str(test)
else:
ref = ConanFileReference(conanfile_class.name, conanfile_class.version, user, channel,
ref = ConanFileReference(conanfile.name, conanfile.version, user, channel,
validate=False)
if str(ref):
display_name = "%s (%s)" % (os.path.basename(conanfile_path), str(ref))
conanfile.display_name = "%s (%s)" % (os.path.basename(conanfile_path), str(ref))
else:
display_name = os.path.basename(conanfile_path)
conanfile = conanfile_class(self._output, self._runner, display_name, user, channel)
conanfile.display_name = os.path.basename(conanfile_path)
conanfile.output.scope = conanfile.display_name
conanfile.in_local_cache = False
try:
self._initialize_conanfile(conanfile, processed_profile)
Expand All @@ -146,10 +157,11 @@ def load_consumer(self, conanfile_path, processed_profile, name=None, version=No
raise ConanException("%s: %s" % (conanfile_path, str(e)))

def load_conanfile(self, conanfile_path, processed_profile, ref, lock_python_requires=None):
conanfile_class = self.load_class(conanfile_path, lock_python_requires)
conanfile_class.name = ref.name
conanfile_class.version = ref.version
conanfile = conanfile_class(self._output, self._runner, str(ref), ref.user, ref.channel)
conanfile = self.load_class(conanfile_path, lock_python_requires, ref.user, ref.channel,
str(ref))
conanfile.name = ref.name
conanfile.version = ref.version

if processed_profile.dev_reference and processed_profile.dev_reference == ref:
conanfile.develop = True
try:
Expand Down
68 changes: 68 additions & 0 deletions conans/test/functional/conanfile/get_name_version_test.py
@@ -0,0 +1,68 @@
import textwrap
import unittest

from conans.test.utils.tools import TestClient


class GetVersionNameTest(unittest.TestCase):

def get_version_name_test(self):
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile
class Lib(ConanFile):
def get_name(self):
self.name = "pkg"
def get_version(self):
self.version = "2.1"
""")
client.save({"conanfile.py": conanfile})
client.run("export . user/testing")
self.assertIn("pkg/2.1@user/testing: A new conanfile.py version was exported", client.out)
client.run("install pkg/2.1@user/testing --build=missing")
self.assertIn("pkg/2.1@user/testing:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Build",
client.out)
client.run("install pkg/2.1@user/testing")
self.assertIn("pkg/2.1@user/testing:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Cache",
client.out)

def get_version_name_file_test(self):
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile, load
class Lib(ConanFile):
def get_name(self):
self.name = load("name.txt")
def get_version(self):
self.version = load("version.txt")
""")
client.save({"conanfile.py": conanfile,
"name.txt": "pkg",
"version.txt": "2.1"})
client.run("export . user/testing")
self.assertIn("pkg/2.1@user/testing: A new conanfile.py version was exported", client.out)
client.run("install pkg/2.1@user/testing --build=missing")
self.assertIn("pkg/2.1@user/testing:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Build",
client.out)
client.run("install pkg/2.1@user/testing")
self.assertIn("pkg/2.1@user/testing:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Cache",
client.out)

def get_version_name_errors_test(self):
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile
class Lib(ConanFile):
def get_name(self):
self.name = "pkg"
def get_version(self):
self.version = "2.1"
""")
client.save({"conanfile.py": conanfile})
client.run("export . other/1.1@user/testing", assert_error=True)
self.assertIn("ERROR: Package recipe exported with name other!=pkg", client.out)
client.run("export . 1.1@user/testing", assert_error=True)
self.assertIn("ERROR: Package recipe exported with version 1.1!=2.1", client.out)
# These are checked but match and don't conflict
client.run("export . 2.1@user/testing")
client.run("export . pkg/2.1@user/testing")
61 changes: 61 additions & 0 deletions conans/test/functional/python_requires/python_requires_test.py
Expand Up @@ -423,6 +423,67 @@ def build(self):
self.assertTrue(os.path.exists(os.path.join(client.cache.package_layout(ref).export(),
"other.txt")))

def reuse_name_version_test(self):
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile
class BasePkg(ConanFile):
name = "Base"
version = "1.1"
""")
client.save({"conanfile.py": conanfile})
client.run("export . lasote/testing")

reuse = textwrap.dedent("""
from conans import python_requires
base = python_requires("Base/1.1@lasote/testing")
class PkgTest(base.BasePkg):
pass
""")
client.save({"conanfile.py": reuse})
client.run("create . Pkg/0.1@lasote/testing", assert_error=True)
self.assertIn("ERROR: Package recipe exported with name Pkg!=Base", client.out)

reuse = textwrap.dedent("""
from conans import python_requires
base = python_requires("Base/1.1@lasote/testing")
class PkgTest(base.BasePkg):
name = "Pkg"
version = "0.1"
""")
client.save({"conanfile.py": reuse})
client.run("create . Pkg/0.1@lasote/testing")
self.assertIn("Pkg/0.1@lasote/testing: Created package ", client.out)
client.run("create . lasote/testing")
self.assertIn("Pkg/0.1@lasote/testing: Created package ", client.out)

def reuse_get_name_get_version_test(self):
client = TestClient()
conanfile = textwrap.dedent("""
from conans import ConanFile, load
class BasePkg(ConanFile):
def get_name(self):
self.name = load("name.txt")
def get_version(self):
self.version = load("version.txt")
""")
client.save({"conanfile.py": conanfile,
"name.txt": "Base",
"version.txt": "1.1"})
client.run("export . user/testing")

reuse = textwrap.dedent("""
from conans import python_requires
base = python_requires("Base/1.1@user/testing")
class PkgTest(base.BasePkg):
pass
""")
client.save({"conanfile.py": reuse,
"name.txt": "Pkg",
"version.txt": "2.3"})
client.run("create . user/testing")
self.assertIn("Pkg/2.3@user/testing: Created package", client.out)

def reuse_exports_conflict_test(self):
conanfile = """from conans import ConanFile
class Base(ConanFile):
Expand Down