Repository: conan-io/conan

Issue:
Layout source folder when using ``source()`` to ``git clone`` a third-party fails 
- Layout defines source folder as ``src``
- Conan exports at least ``conanfile.py`` and ``conanmanifests.txt`` into the ``export`` folder in the cache
- The ``export`` folder in the cache is automatically copied to ``source/src`` in the cache.
- If the package tries to do a ``git clone <url> src`` to put the sources inside the ``src`` folder as the layout specified, it fails with "folder already exists".

Should we?
- Do not copy the ``export`` into the ``source/src`` folder, only the ``exports_sources``?
- Document some git gymnastics to do it, like cloning in a different folder?




Discussion:
I think the "exports" shouldn't go to the `src` because if you have sources you should use `exports_sources` right?
In case you have both `exports_sources` and a `git clone` (not likely but surely used) you probably need some [some trick](https://stackoverflow.com/questions/2411031/how-do-i-clone-into-a-non-empty-directory).


A test to make it fail:

```
def test_git_clone_with_source_layout():
    client = TestClient()
    conanfile = textwrap.dedent("""
           import os
           from conans import ConanFile
           class Pkg(ConanFile):
               exports = "*.txt"
               exports_sources = "*.cpp"

               def layout(self):
                   self.folders.source = "src"

               def source(self):
                   self.run('git clone "{}" src')
       """).format(client.current_folder)

    client.save({"conanfile.py": conanfile, "myfile.txt": "My file is copied",
                 "source.cpp": "sources"})
    with client.chdir(client.current_folder):
        client.run_command("git init .")
        client.run_command('git config user.email "you@example.com"')
        client.run_command('git config user.name "Your Name"')
        client.run_command("git add .")
        client.run_command('git commit -m  "commiting"')

    client.run("create . hello/1.0@")
```


I noticed this in the `source.py`:

```
               if cache:
                    _clean_source_folder(src_folder)  # TODO: Why is it needed in cache?
```

The answer to the # TODO is exactly this issue: it is trying to remove the `conanfile.py` and others to skip the errors cloning repositories. BUT as it is cleaning `src_folder` instead of `conanfile.source_folder` it was not cleaning anything. 
So, I still think that the `exports` should go to the base directory but we could fix it if we keep it.
Let's talk about it.

Resolving patch:
diff --git a/conans/client/source.py b/conans/client/source.py
--- a/conans/client/source.py
+++ b/conans/client/source.py
@@ -105,7 +105,7 @@ def get_sources_from_exports():
                 # First of all get the exported scm sources (if auto) or clone (if fixed)
                 _run_cache_scm(conanfile, scm_sources_folder, output)
                 # so self exported files have precedence over python_requires ones
-                merge_directories(export_folder, conanfile.source_folder)
+                merge_directories(export_folder, conanfile.folders.base_source)
                 # Now move the export-sources to the right location
                 merge_directories(export_source_folder, conanfile.folders.base_source)
 
@@ -139,7 +139,8 @@ def _run_source(conanfile, conanfile_path, hook_manager, reference, cache,
                 get_sources_from_exports()
 
                 if cache:
-                    _clean_source_folder(src_folder)  # TODO: Why is it needed in cache?
+                    # Clear the conanfile.py to avoid errors cloning git repositories.
+                    _clean_source_folder(src_folder)
                 with conanfile_exception_formatter(conanfile.display_name, "source"):
 
                     with conan_v2_property(conanfile, 'settings',


Test patch:
diff --git a/conans/test/functional/layout/test_in_cache.py b/conans/test/functional/layout/test_in_cache.py
--- a/conans/test/functional/layout/test_in_cache.py
+++ b/conans/test/functional/layout/test_in_cache.py
@@ -7,6 +7,7 @@
 from conans import load
 from conans.model.ref import ConanFileReference, PackageReference
 from conans.test.assets.genconanfile import GenConanfile
+from conans.test.utils.test_files import temp_folder
 from conans.test.utils.tools import TestClient
 
 
@@ -270,3 +271,36 @@ def generate(self):
     assert 'set(hello_INCLUDE_DIRS_RELEASE "${hello_PACKAGE_FOLDER_RELEASE}/foo/include")' in cmake
     assert 'set(hello_LIB_DIRS_RELEASE "${hello_PACKAGE_FOLDER_RELEASE}/foo/libs")' in cmake
     assert 'set(hello_LIBS_RELEASE foo)' in cmake
+
+
+def test_git_clone_with_source_layout():
+    client = TestClient()
+    repo = temp_folder()
+    conanfile = textwrap.dedent("""
+           import os
+           from conans import ConanFile
+           class Pkg(ConanFile):
+               exports = "*.txt"
+
+               def layout(self):
+                   self.folders.source = "src"
+
+               def source(self):
+                   self.run('git clone "{}" src')
+       """).format(repo.replace("\\", "/"))
+
+    client.save({"conanfile.py": conanfile,
+                 "myfile.txt": "My file is copied"})
+    with client.chdir(repo):
+        client.save({"cloned.txt": "foo"}, repo)
+        client.init_git_repo()
+
+    client.run("create . hello/1.0@")
+    sf = client.cache.package_layout(ConanFileReference.loads("hello/1.0@")).source()
+    assert os.path.exists(os.path.join(sf, "myfile.txt"))
+    # The conanfile is cleared from the root before cloning
+    assert not os.path.exists(os.path.join(sf, "conanfile.py"))
+    assert not os.path.exists(os.path.join(sf, "cloned.txt"))
+
+    assert os.path.exists(os.path.join(sf, "src", "cloned.txt"))
+    assert not os.path.exists(os.path.join(sf, "src", "myfile.txt"))