Skip to content

Commit

Permalink
new move_folder_contents() file helper to re-arrange repos (#13509)
Browse files Browse the repository at this point in the history
* new move_folder_contents() file helper to re-arrange repos

* fix test
  • Loading branch information
memsharded authored Mar 24, 2023
1 parent 03a29d3 commit 7ef5ade
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 14 deletions.
3 changes: 2 additions & 1 deletion conan/tools/files/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from conan.tools.files.files import load, save, mkdir, rmdir, rm, ftp_download, download, get, \
rename, chdir, unzip, replace_in_file, collect_libs, check_md5, check_sha1, check_sha256
rename, chdir, unzip, replace_in_file, collect_libs, check_md5, check_sha1, check_sha256, \
move_folder_contents

from conan.tools.files.patches import patch, apply_conandata_patches, export_conandata_patches
from conan.tools.files.cpp_package import CppPackage
Expand Down
41 changes: 31 additions & 10 deletions conan/tools/files/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,18 +544,39 @@ def collect_libs(conanfile, folder=None):


# TODO: Do NOT document this yet. It is unclear the interface, maybe should be split
def swap_child_folder(parent_folder, child_folder):
def move_folder_contents(src_folder, dst_folder):
""" replaces the current folder contents with the contents of one child folder. This
is used in the SCM monorepo flow, when it is necessary to use one subproject subfolder
to replace the whole cloned git repo
/base-folder /base-folder
/pkg (src folder) /other/<otherfiles>
/other/<otherfiles> /pkg/<pkgfiles>
/pkg/<pkgfiles> <files>
<files>
/siblings
<siblingsfiles>
"""
for f in os.listdir(parent_folder):
if f != child_folder:
path = os.path.join(parent_folder, f)
if os.path.isfile(path):
os.remove(path)
# Remove potential "siblings" folders not wanted
src_folder_name = os.path.basename(src_folder)
for f in os.listdir(dst_folder):
if f != src_folder_name: # FIXME: Only works for 1st level subfolder
dst = os.path.join(dst_folder, f)
if os.path.isfile(dst):
os.remove(dst)
else:
_internal_rmdir(path)
child = os.path.join(parent_folder, child_folder)
for f in os.listdir(child):
shutil.move(os.path.join(child, f), os.path.join(parent_folder, f))
_internal_rmdir(dst)

# Move all the contents
for f in os.listdir(src_folder):
src = os.path.join(src_folder, f)
dst = os.path.join(dst_folder, f)
if not os.path.exists(dst):
shutil.move(src, dst_folder)
else:
for sub_src in os.listdir(src):
shutil.move(os.path.join(src, sub_src), dst)
_internal_rmdir(src)
try:
os.rmdir(src_folder)
except OSError:
pass
82 changes: 79 additions & 3 deletions conans/test/functional/tools/scm/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import pytest
import six

from conans.test.assets.cmake import gen_cmakelists
from conans.test.assets.sources import gen_function_cpp
from conans.test.utils.scm import create_local_git_repo, git_add_changes_commit, git_create_bare_repo
from conans.test.utils.test_files import temp_folder
from conans.test.utils.tools import TestClient
Expand Down Expand Up @@ -484,8 +486,7 @@ class TestGitMonorepoSCMFlow:
import os, shutil
from conan import ConanFile
from conan.tools.scm import Git
from conan.tools.files import load, update_conandata
from conan.tools.files.files import swap_child_folder
from conan.tools.files import load, update_conandata, move_folder_contents
class Pkg(ConanFile):
name = "{pkg}"
Expand All @@ -509,7 +510,8 @@ def source(self):
sources = self.conan_data["sources"]
git.clone(url=sources["url"], target=".")
git.checkout(commit=sources["commit"])
swap_child_folder(self.source_folder, sources["folder"])
move_folder_contents(os.path.join(self.source_folder, sources["folder"]),
self.source_folder)
def build(self):
cmake = os.path.join(self.source_folder, "CMakeLists.txt")
Expand Down Expand Up @@ -558,6 +560,80 @@ def test_full_scm(self):
assert "pkg2/0.1: MYCMAKE-BUILD: mycmake2!" in c2.out
assert "pkg2/0.1: MYFILE-BUILD: my2header!" in c2.out

@pytest.mark.tool_cmake
def test_exports_sources_common_code_layout(self):
""" This is a copy of test_exports_sources_common_code_layout in test_in_subfolder.py
but instead of using "exports", trying to implement it with Git features
"""
c = TestClient()
conanfile = textwrap.dedent("""
import os
from conan import ConanFile
from conan.tools.cmake import cmake_layout, CMake
from conan.tools.files import load, copy, save, update_conandata, move_folder_contents
from conan.tools.scm import Git
class Pkg(ConanFile):
name = "pkg"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeToolchain"
def export(self):
git = Git(self)
scm_url, scm_commit = git.get_url_and_commit()
update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}})
def layout(self):
self.folders.root = ".."
self.folders.subproject = "pkg"
cmake_layout(self)
def source(self):
git = Git(self)
sources = self.conan_data["sources"]
git.clone(url=sources["url"], target=".")
git.checkout(commit=sources["commit"])
# Layout is pkg/pkg/<files> and pkg/common/<files>
# Final we want is pkg/<files> and common/<files>
# NOTE: This abs_path is IMPORTANT to avoid the trailing "."
src_folder = os.path.abspath(self.source_folder)
move_folder_contents(src_folder, os.path.dirname(src_folder))
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
self.run(os.path.join(self.cpp.build.bindirs[0], "myapp"))
""")
cmake_include = "include(${CMAKE_CURRENT_LIST_DIR}/../common/myutils.cmake)"
c.save({"pkg/conanfile.py": conanfile,
"pkg/app.cpp": gen_function_cpp(name="main", includes=["../common/myheader"],
preprocessor=["MYDEFINE"]),
"pkg/CMakeLists.txt": gen_cmakelists(appsources=["app.cpp"],
custom_content=cmake_include),
"common/myutils.cmake": 'message(STATUS "MYUTILS.CMAKE!")',
"common/myheader.h": '#define MYDEFINE "MYDEFINEVALUE"'})
c.init_git_repo()

c.run("create pkg")
assert "MYUTILS.CMAKE!" in c.out
assert "main: Release!" in c.out
assert "MYDEFINE: MYDEFINEVALUE" in c.out

# Local flow
c.run("install pkg")
c.run("build pkg")
assert "MYUTILS.CMAKE!" in c.out
assert "main: Release!" in c.out
assert "MYDEFINE: MYDEFINEVALUE" in c.out

c.run("install pkg -s build_type=Debug")
c.run("build pkg")
assert "MYUTILS.CMAKE!" in c.out
assert "main: Debug!" in c.out
assert "MYDEFINE: MYDEFINEVALUE" in c.out


class TestConanFileSubfolder:
"""verify that we can have a conanfile in a subfolder
Expand Down

0 comments on commit 7ef5ade

Please sign in to comment.