Skip to content

Commit

Permalink
proposing base_source_folder, and folders.root (#10654)
Browse files Browse the repository at this point in the history
* proposing base_source_folder, and folders.root

* Update conans/model/layout.py

Co-authored-by: Luis Martinez <lasote@gmail.com>

* [feature] `ConfDefinition` and `Conf` enhancements. (#10537)

* first approach. Big changes in Conf

* Fixing errors

* Fixing more tests

* Deleted useless iteration

* All the tests passing

* Testing

* Added items method

* fixed rebased

* Keeping old functions for backward compatibility

* backward compatibility

* Keeping indentation

* Ordering methods and improved legacy logic

* Added fixme

* Reverted breaking changes

* Added more complete test

* Added more access Conf tests

* Added docstring

* Splitted string asserts

* Added get/pop functions

* Breaking refactor. Trying new structure

* fixing tests

* Changing tests

* Fixed tests

* Fixed Python 2.x problems

* Removed useless layer of types

* Fixed py2

* Fixed errors and added cast param to apply function to convert any type

* Added TODO

* Improved docstring

* Fixed error

* Update conans/model/conf.py

Co-authored-by: James <james@conan.io>

* Update conans/model/conf.py

Co-authored-by: James <james@conan.io>

* Added check_type and removed cast

* Changed main structure. Now simpler and more powerful

* Explicit default

* Fixed error

* Simplified compile options

* Changed all the legacy conf getitem built-ins

* Fixed test

* Fixed bad type

* Added more tests

* More tests

* Fix test for Python2

* Added more tests. Fixed corner-cases

* Added one cli test and improved boolean conf UX

* Moved str conveersion

* Added one more mechanism to other smart conversion. Added more tests

* Removed useless OR

Co-authored-by: James <james@conan.io>

* [PkgConfigDeps] Added new property `component_version` (#10633)

* Added custom versions and descriptions for components

* Changed property to component_version. Backported to legacy PkgConfig

* package_folder available when "conan install" consumer (#10655)

* WIP: Test failing

* output_folder absolute only when existing

* Fix test windows

* added a few conf checkers (#10656)

* Use absolute paths in conanbuild.sh (#10653)

* use absolute path

* Update conans/test/integration/environment/test_env.py

Co-authored-by: James <james@conan.io>

* fix tests

* fix test

* fix win

* fix win

Co-authored-by: James <james@conan.io>

* Cleanup tmpdirs (#10663)

* refactor toolchain (#10665)

* fix not finding the Premake executable (#10250)

Co-authored-by: James <james@conan.io>

* review

Co-authored-by: Luis Martinez <lasote@gmail.com>
Co-authored-by: Francisco Ramírez <franchuti688@gmail.com>
Co-authored-by: Carlos Zoido <mrgalleta@gmail.com>
Co-authored-by: Enhex <enhex0@gmail.com>
  • Loading branch information
5 people committed Mar 1, 2022
1 parent dff225b commit 50daee0
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 16 deletions.
7 changes: 1 addition & 6 deletions conans/client/cmd/build.py
Expand Up @@ -45,12 +45,7 @@ def cmd_build(app, conanfile_path, base_path, source_folder, build_folder, packa
# Only base_path and conanfile_path will remain
if hasattr(conan_file, "layout"):
conanfile_folder = os.path.dirname(conanfile_path)
conan_file.folders.set_base_build(layout_build_folder or conanfile_folder)
conan_file.folders.set_base_source(layout_source_folder or conanfile_folder)
conan_file.folders.set_base_package(layout_build_folder or conanfile_folder)
conan_file.folders.set_base_generators(layout_build_folder or conanfile_folder)
conan_file.folders.set_base_install(layout_build_folder or conanfile_folder)
conan_file.folders.set_base_imports(layout_build_folder or conanfile_folder)
conan_file.folders.set_base_folders(conanfile_folder, layout_build_folder)
else:
conan_file.folders.set_base_build(build_folder)
conan_file.folders.set_base_source(source_folder)
Expand Down
5 changes: 1 addition & 4 deletions conans/client/cmd/export_pkg.py
Expand Up @@ -59,11 +59,8 @@ def _init_conanfile_infos():
conanfile.develop = True
if hasattr(conanfile, "layout"):
conanfile_folder = os.path.dirname(source_conanfile_path)
conanfile.folders.set_base_build(conanfile_folder)
conanfile.folders.set_base_source(conanfile_folder)
conanfile.folders.set_base_folders(conanfile_folder, output_folder=None)
conanfile.folders.set_base_package(dest_package_folder)
conanfile.folders.set_base_install(conanfile_folder)
conanfile.folders.set_base_generators(conanfile_folder)
else:
conanfile.folders.set_base_build(build_folder)
conanfile.folders.set_base_source(source_folder)
Expand Down
7 changes: 1 addition & 6 deletions conans/client/installer.py
Expand Up @@ -467,12 +467,7 @@ def _handle_node_editable(self, node, profile_host, profile_build, graph_lock):
base_path = package_layout.base_folder()

if hasattr(conanfile, "layout"):
conanfile.folders.set_base_package(package_layout.output_folder or base_path)
conanfile.folders.set_base_source(base_path)
conanfile.folders.set_base_build(package_layout.output_folder or base_path)
conanfile.folders.set_base_generators(package_layout.output_folder or base_path)
conanfile.folders.set_base_install(base_path)
conanfile.folders.set_base_imports(package_layout.output_folder or base_path)
conanfile.folders.set_base_folders(base_path, package_layout.output_folder)
else:
conanfile.folders.set_base_package(base_path)
conanfile.folders.set_base_source(None)
Expand Down
9 changes: 9 additions & 0 deletions conans/model/conan_file.py
Expand Up @@ -254,6 +254,15 @@ def new_cpp_info(self):
def source_folder(self):
return self.folders.source_folder

@property
def base_source_folder(self):
""" returns the base_source folder, that is the containing source folder in the cache
irrespective of the layout() and where the final self.source_folder (computed with the
layout()) points.
This can be necessary in the source() or build() methods to locate where exported sources
are, like patches or entire files that will be used to complete downloaded sources"""
return self.folders._base_source

@property
def build_folder(self):
return self.folders.build_folder
Expand Down
25 changes: 25 additions & 0 deletions conans/model/layout.py
Expand Up @@ -26,10 +26,35 @@ def __init__(self):
self.package = ""
self.generators = ""
self.imports = ""
# Relative location of the project root, if the conanfile is not in that project root, but
# in a subfolder: e.g: If the conanfile is in a subfolder then self.root = ".."
self.root = None

def __repr__(self):
return str(self.__dict__)

def set_base_folders(self, conanfile_folder, output_folder):
""" this methods can be used for defining all the base folders in the
local flow (conan install, source, build), where only the current conanfile location
and the potential --output-folder user argument are the folders to take into account
If the "layout()" method defines a self.folders.root = "xxx" it will be used to compute
the base folder
@param conanfile_folder: the location where the current consumer conanfile is
@param output_folder: Can potentially be None (for export-pkg: TODO), in that case
the conanfile location is used"""
# This must be called only after ``layout()`` has been called
base_folder = conanfile_folder if self.root is None else \
os.path.normpath(os.path.join(conanfile_folder, self.root))

self._base_source = base_folder

self._base_install = output_folder or base_folder
self._base_build = output_folder or base_folder
self._base_package = output_folder or base_folder
self._base_generators = output_folder or base_folder
self._base_imports = output_folder or base_folder

@property
def source_folder(self):
if self._base_source is None:
Expand Down
58 changes: 58 additions & 0 deletions conans/test/functional/layout/test_exports_sources.py
@@ -0,0 +1,58 @@
import textwrap

from conans.test.utils.tools import TestClient


def test_exports_sources_patch():
"""
tests that using ``self.base_source_folder`` we can access both from the source() and build()
methods the folder where the exported sources (patches, new build files) are. And maintain
a local flow without exports copies
"""
c = TestClient()
conanfile = textwrap.dedent("""
import os, shutil
from conan import ConanFile
from conan.tools.files import load, copy, save
class Pkg(ConanFile):
name = "pkg"
version = "0.1"
exports_sources = "CMakeLists.txt", "patches*"
def layout(self):
self.folders.source = "src"
def source(self):
save(self, "CMakeLists.txt", "old, bad") # EMULATE A DOWNLOAD!
base_source = self.base_source_folder
mypatch = load(self, os.path.join(base_source, "patches/mypatch"))
self.output.info("MYPATCH-SOURCE {}".format(mypatch))
shutil.copy(os.path.join(base_source, "CMakeLists.txt"),
"CMakeLists.txt")
def build(self):
path = os.path.join(self.source_folder, "CMakeLists.txt")
cmake = load(self, path)
self.output.info("MYCMAKE-BUILD: {}".format(cmake))
path = os.path.join(self.base_source_folder, "patches/mypatch")
cmake = load(self, path)
self.output.info("MYPATCH-BUILD: {}".format(cmake))
""")
c.save({"conanfile.py": conanfile,
"patches/mypatch": "mypatch!",
"CMakeLists.txt": "mycmake!"})
c.run("create .")
assert "pkg/0.1: MYPATCH-SOURCE mypatch!" in c.out
assert "pkg/0.1: MYCMAKE-BUILD: mycmake!" in c.out
assert "pkg/0.1: MYPATCH-BUILD: mypatch!" in c.out

# Local flow
c.run("install .")
c.run("source .")
assert "conanfile.py (pkg/0.1): MYPATCH-SOURCE mypatch!" in c.out
assert c.load("CMakeLists.txt") == "mycmake!" # My original one
assert c.load("src/CMakeLists.txt") == "mycmake!" # The one patched by "source()"
c.run("build .")
assert "conanfile.py (pkg/0.1): MYCMAKE-BUILD: mycmake!" in c.out
assert "conanfile.py (pkg/0.1): MYPATCH-BUILD: mypatch!" in c.out
49 changes: 49 additions & 0 deletions conans/test/functional/layout/test_in_subfolder.py
@@ -0,0 +1,49 @@
import textwrap

from conans.test.utils.tools import TestClient


def test_exports_sources_own_code_in_subfolder():
""" test that we can put the conanfile in a subfolder, and it can work. The key is
the exports_sources() method that can do:
os.path.join(self.recipe_folder, "..")
And the layout: self.folders.root = ".."
"""
c = TestClient()
conanfile = textwrap.dedent("""
import os
from conan import ConanFile
from conan.tools.files import load, copy
class Pkg(ConanFile):
name = "pkg"
version = "0.1"
def layout(self):
self.folders.root = ".."
self.folders.source = "."
self.folders.build = "build"
def export_sources(self):
source_folder = os.path.join(self.recipe_folder, "..")
copy(self, "*.txt", source_folder, self.export_sources_folder)
def source(self):
cmake = load(self, "CMakeLists.txt")
self.output.info("MYCMAKE-SRC: {}".format(cmake))
def build(self):
path = os.path.join(self.source_folder, "CMakeLists.txt")
cmake = load(self, path)
self.output.info("MYCMAKE-BUILD: {}".format(cmake))
""")
c.save({"conan/conanfile.py": conanfile,
"CMakeLists.txt": "mycmake!"})
c.run("create conan")
assert "pkg/0.1: MYCMAKE-SRC: mycmake!" in c.out
assert "pkg/0.1: MYCMAKE-BUILD: mycmake!" in c.out

# Local flow
c.run("install conan")
# SOURCE NOT CALLED! It doesnt make sense (will fail due to local exports)
c.run("build conan")
assert "conanfile.py (pkg/0.1): MYCMAKE-BUILD: mycmake!" in c.out

0 comments on commit 50daee0

Please sign in to comment.