We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
exports_sources fails to properly handle symlinks
To help us debug your issue please explain:

- [x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).
- [x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.

OS: macOS 10.14.5
Conan: 1.16.0 (installed with pip into virtualenv, but also fails with 1.16.0 from Brew). Works with 1.15.1.
Python: 3.7.3 (installed from MacPorts)

`conanfile.py` has `exports_sources=src/*`, there is `src/foo.framework` with symlinks:
```
.
├── Headers -> Versions/Current/Headers
├── Resources -> Versions/Current/Resources
├── Versions
│   ├── A
│   │   ├── Headers
│   │   │   └── foo.h
│   │   ├── Resources
│   │   │   ├── Info.plist
│   │   │   └── en.lproj
│   │   │       └── InfoPlist.strings
│   │   └── foo
│   └── Current -> A
└── foo -> Versions/Current/foo
```
`conan create . test/test` fails with the following error:
```
% conan create . test/test                                                                                                                                                                                                                                          master
Exporting package recipe
symlinks/1.0.0@test/test exports_sources: Copied 1 '.txt' file: CMakeLists.txt
symlinks/1.0.0@test/test exports_sources: Copied 1 '.cpp' file: hello.cpp
symlinks/1.0.0@test/test exports_sources: Copied 2 '.h' files: hello.h, foo.h
symlinks/1.0.0@test/test exports_sources: Copied 2 files: foo, foo
symlinks/1.0.0@test/test exports_sources: Copied 1 '.plist' file: Info.plist
symlinks/1.0.0@test/test exports_sources: Copied 1 '.strings' file: InfoPlist.strings
symlinks/1.0.0@test/test: The stored package has not changed
symlinks/1.0.0@test/test: Source folder is corrupted, forcing removal
Configuration:
[settings]
[options]
[build_requires]
[env]

symlinks/1.0.0@test/test: Forced build from source
Installing package: symlinks/1.0.0@test/test
Requirements
    symlinks/1.0.0@test/test from local cache - Cache
Packages
    symlinks/1.0.0@test/test:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Build

symlinks/1.0.0@test/test: WARN: Build folder is dirty, removing it: /Users/paul/.conan/data/symlinks/1.0.0/test/test/build/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9
symlinks/1.0.0@test/test: WARN: Trying to remove corrupted source folder
symlinks/1.0.0@test/test: WARN: This can take a while for big packages
symlinks/1.0.0@test/test: Configuring sources in /Users/paul/.conan/data/symlinks/1.0.0/test/test/source
ERROR: [Errno 17] File exists: 'Versions/Current/Resources' -> '/Users/paul/.conan/data/symlinks/1.0.0/test/test/source/src/foo.framework/Resources'
```

Sample project: [conan_symlinks](https://github.com/Paultergeist/conan_symlinks)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `conans/client/source.py`
Content:
```
1 import os
2 import shutil
3 
4 import six
5 
6 from conans.client import tools
7 from conans.client.cmd.export import export_recipe, export_source
8 from conans.client.file_copier import FileCopier
9 from conans.errors import ConanException, ConanExceptionInUserConanfileMethod, \
10     conanfile_exception_formatter
11 from conans.model.conan_file import get_env_context_manager
12 from conans.model.scm import SCM, get_scm_data
13 from conans.paths import CONANFILE, CONAN_MANIFEST, EXPORT_SOURCES_TGZ_NAME, EXPORT_TGZ_NAME
14 from conans.util.files import (clean_dirty, is_dirty, load, mkdir, rmdir, set_dirty, walk)
15 
16 
17 def complete_recipe_sources(remote_manager, cache, conanfile, ref, remotes):
18     """ the "exports_sources" sources are not retrieved unless necessary to build. In some
19     occassions, conan needs to get them too, like if uploading to a server, to keep the recipes
20     complete
21     """
22     sources_folder = cache.package_layout(ref, conanfile.short_paths).export_sources()
23     if os.path.exists(sources_folder):
24         return None
25 
26     if conanfile.exports_sources is None:
27         mkdir(sources_folder)
28         return None
29 
30     # If not path to sources exists, we have a problem, at least an empty folder
31     # should be there
32     current_remote = cache.package_layout(ref).load_metadata().recipe.remote
33     if current_remote:
34         current_remote = remotes[current_remote]
35     if not current_remote:
36         raise ConanException("Error while trying to get recipe sources for %s. "
37                              "No remote defined" % str(ref))
38 
39     export_path = cache.package_layout(ref).export()
40     remote_manager.get_recipe_sources(ref, export_path, sources_folder, current_remote)
41 
42 
43 def merge_directories(src, dst, excluded=None, symlinks=True):
44     src = os.path.normpath(src)
45     dst = os.path.normpath(dst)
46     excluded = excluded or []
47     excluded = [os.path.normpath(entry) for entry in excluded]
48 
49     def is_excluded(origin_path):
50         if origin_path == dst:
51             return True
52         rel_path = os.path.normpath(os.path.relpath(origin_path, src))
53         if rel_path in excluded:
54             return True
55         return False
56 
57     linked_folders = []
58     for src_dir, dirs, files in walk(src, followlinks=True):
59 
60         if is_excluded(src_dir):
61             dirs[:] = []
62             continue
63 
64         if os.path.islink(src_dir):
65             rel_link = os.path.relpath(src_dir, src)
66             linked_folders.append(rel_link)
67             continue
68 
69         # Overwriting the dirs will prevents walk to get into them
70         files[:] = [d for d in files if not is_excluded(os.path.join(src_dir, d))]
71 
72         dst_dir = os.path.normpath(os.path.join(dst, os.path.relpath(src_dir, src)))
73         if not os.path.exists(dst_dir):
74             os.makedirs(dst_dir)
75         for file_ in files:
76             src_file = os.path.join(src_dir, file_)
77             dst_file = os.path.join(dst_dir, file_)
78             if os.path.islink(src_file) and symlinks:
79                 linkto = os.readlink(src_file)
80                 os.symlink(linkto, dst_file)
81             else:
82                 shutil.copy2(src_file, dst_file)
83 
84     FileCopier.link_folders(src, dst, linked_folders)
85 
86 
87 def config_source_local(src_folder, conanfile, conanfile_path, hook_manager):
88     """ Entry point for the "conan source" command.
89     """
90     conanfile_folder = os.path.dirname(conanfile_path)
91 
92     def get_sources_from_exports():
93         if conanfile_folder != src_folder:
94             conanfile.output.info("Executing exports to: %s" % src_folder)
95             export_recipe(conanfile, conanfile_folder, src_folder)
96             export_source(conanfile, conanfile_folder, src_folder)
97 
98     _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference=None, cache=None,
99                 local_sources_path=conanfile_folder,
100                 get_sources_from_exports=get_sources_from_exports)
101 
102 
103 def config_source(export_folder, export_source_folder, src_folder, conanfile, output,
104                   conanfile_path, reference, hook_manager, cache):
105     """ Implements the sources configuration when a package is going to be built in the
106     local cache.
107     """
108 
109     def remove_source(raise_error=True):
110         output.warn("This can take a while for big packages")
111         try:
112             rmdir(src_folder)
113         except BaseException as e_rm:
114             set_dirty(src_folder)
115             msg = str(e_rm)
116             if six.PY2:
117                 msg = str(e_rm).decode("latin1")  # Windows prints some chars in latin1
118             output.error("Unable to remove source folder %s\n%s" % (src_folder, msg))
119             output.warn("**** Please delete it manually ****")
120             if raise_error or isinstance(e_rm, KeyboardInterrupt):
121                 raise ConanException("Unable to remove source folder")
122 
123     sources_pointer = cache.package_layout(reference).scm_folder()
124     local_sources_path = load(sources_pointer) if os.path.exists(sources_pointer) else None
125     if is_dirty(src_folder):
126         output.warn("Trying to remove corrupted source folder")
127         remove_source()
128     elif conanfile.build_policy_always:
129         output.warn("Detected build_policy 'always', trying to remove source folder")
130         remove_source()
131     elif local_sources_path and os.path.exists(local_sources_path):
132         output.warn("Detected 'scm' auto in conanfile, trying to remove source folder")
133         remove_source()
134 
135     if not os.path.exists(src_folder):  # No source folder, need to get it
136         set_dirty(src_folder)
137         mkdir(src_folder)
138 
139         def get_sources_from_exports():
140             # so self exported files have precedence over python_requires ones
141             merge_directories(export_folder, src_folder)
142             # Now move the export-sources to the right location
143             merge_directories(export_source_folder, src_folder)
144 
145         _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference,
146                     cache, local_sources_path, get_sources_from_exports=get_sources_from_exports)
147         clean_dirty(src_folder)  # Everything went well, remove DIRTY flag
148 
149 
150 def _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference, cache,
151                 local_sources_path, get_sources_from_exports):
152     """Execute the source core functionality, both for local cache and user space, in order:
153         - Calling pre_source hook
154         - Getting sources from SCM
155         - Getting sources from exported folders in the local cache
156         - Clean potential TGZ and other files in the local cache
157         - Executing the recipe source() method
158         - Calling post_source hook
159     """
160     conanfile.source_folder = src_folder
161     conanfile.build_folder = None
162     conanfile.package_folder = None
163     with tools.chdir(src_folder):
164         try:
165             with get_env_context_manager(conanfile):
166                 hook_manager.execute("pre_source", conanfile=conanfile,
167                                      conanfile_path=conanfile_path,
168                                      reference=reference)
169                 output = conanfile.output
170                 output.info('Configuring sources in %s' % src_folder)
171                 _run_scm(conanfile, src_folder, local_sources_path, output, cache=cache)
172 
173                 get_sources_from_exports()
174 
175                 if cache:
176                     _clean_source_folder(src_folder)  # TODO: Why is it needed in cache?
177                 with conanfile_exception_formatter(conanfile.display_name, "source"):
178                     conanfile.source()
179 
180                 hook_manager.execute("post_source", conanfile=conanfile,
181                                      conanfile_path=conanfile_path,
182                                      reference=reference)
183         except ConanExceptionInUserConanfileMethod:
184             raise
185         except Exception as e:
186             raise ConanException(e)
187 
188 
189 def _clean_source_folder(folder):
190     for f in (EXPORT_TGZ_NAME, EXPORT_SOURCES_TGZ_NAME, CONANFILE+"c",
191               CONANFILE+"o", CONANFILE, CONAN_MANIFEST):
192         try:
193             os.remove(os.path.join(folder, f))
194         except OSError:
195             pass
196     try:
197         shutil.rmtree(os.path.join(folder, "__pycache__"))
198     except OSError:
199         pass
200 
201 
202 def _run_scm(conanfile, src_folder, local_sources_path, output, cache):
203     scm_data = get_scm_data(conanfile)
204     if not scm_data:
205         return
206 
207     dest_dir = os.path.normpath(os.path.join(src_folder, scm_data.subfolder))
208     if cache:
209         # When in cache, capturing the sources from user space is done only if exists
210         if not local_sources_path or not os.path.exists(local_sources_path):
211             local_sources_path = None
212     else:
213         # In user space, if revision="auto", then copy
214         if scm_data.capture_origin or scm_data.capture_revision:  # FIXME: or clause?
215             scm = SCM(scm_data, local_sources_path, output)
216             scm_url = scm_data.url if scm_data.url != "auto" else \
217                 scm.get_qualified_remote_url(remove_credentials=True)
218 
219             src_path = scm.get_local_path_to_url(url=scm_url)
220             if src_path:
221                 local_sources_path = src_path
222         else:
223             local_sources_path = None
224 
225     if local_sources_path and conanfile.develop:
226         excluded = SCM(scm_data, local_sources_path, output).excluded_files
227         output.info("Getting sources from folder: %s" % local_sources_path)
228         merge_directories(local_sources_path, dest_dir, excluded=excluded)
229     else:
230         output.info("Getting sources from url: '%s'" % scm_data.url)
231         scm = SCM(scm_data, dest_dir, output)
232         scm.checkout()
233 
234     if cache:
235         # This is a bit weird. Why after a SCM should we remove files. Maybe check conan 2.0
236         _clean_source_folder(dest_dir)  # TODO: Why removing in the cache? There is no danger.
237
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/conans/client/source.py b/conans/client/source.py
--- a/conans/client/source.py
+++ b/conans/client/source.py
@@ -5,7 +5,6 @@
 
 from conans.client import tools
 from conans.client.cmd.export import export_recipe, export_source
-from conans.client.file_copier import FileCopier
 from conans.errors import ConanException, ConanExceptionInUserConanfileMethod, \
     conanfile_exception_formatter
 from conans.model.conan_file import get_env_context_manager
@@ -40,7 +39,7 @@
     remote_manager.get_recipe_sources(ref, export_path, sources_folder, current_remote)
 
 
-def merge_directories(src, dst, excluded=None, symlinks=True):
+def merge_directories(src, dst, excluded=None):
     src = os.path.normpath(src)
     dst = os.path.normpath(dst)
     excluded = excluded or []
@@ -54,16 +53,30 @@
             return True
         return False
 
-    linked_folders = []
-    for src_dir, dirs, files in walk(src, followlinks=True):
+    def link_to_rel(pointer_src):
+        linkto = os.readlink(pointer_src)
+        if not os.path.isabs(linkto):
+            linkto = os.path.join(os.path.dirname(pointer_src), linkto)
+
+        # Check if it is outside the sources
+        out_of_source = os.path.relpath(linkto, os.path.realpath(src)).startswith(".")
+        if out_of_source:
+            # May warn about out of sources symlink
+            return
+
+        # Create the symlink
+        linkto_rel = os.path.relpath(linkto, os.path.dirname(pointer_src))
+        pointer_dst = os.path.normpath(os.path.join(dst, os.path.relpath(pointer_src, src)))
+        os.symlink(linkto_rel, pointer_dst)
 
+    for src_dir, dirs, files in walk(src, followlinks=True):
         if is_excluded(src_dir):
             dirs[:] = []
             continue
 
         if os.path.islink(src_dir):
-            rel_link = os.path.relpath(src_dir, src)
-            linked_folders.append(rel_link)
+            link_to_rel(src_dir)
+            dirs[:] = []  # Do not enter subdirectories
             continue
 
         # Overwriting the dirs will prevents walk to get into them
@@ -75,14 +88,11 @@
         for file_ in files:
             src_file = os.path.join(src_dir, file_)
             dst_file = os.path.join(dst_dir, file_)
-            if os.path.islink(src_file) and symlinks:
-                linkto = os.readlink(src_file)
-                os.symlink(linkto, dst_file)
+            if os.path.islink(src_file):
+                link_to_rel(src_file)
             else:
                 shutil.copy2(src_file, dst_file)
 
-    FileCopier.link_folders(src, dst, linked_folders)
-
 
 def config_source_local(src_folder, conanfile, conanfile_path, hook_manager):
     """ Entry point for the "conan source" command.

{"golden_diff": "diff --git a/conans/client/source.py b/conans/client/source.py\n--- a/conans/client/source.py\n+++ b/conans/client/source.py\n@@ -5,7 +5,6 @@\n \n from conans.client import tools\n from conans.client.cmd.export import export_recipe, export_source\n-from conans.client.file_copier import FileCopier\n from conans.errors import ConanException, ConanExceptionInUserConanfileMethod, \\\n     conanfile_exception_formatter\n from conans.model.conan_file import get_env_context_manager\n@@ -40,7 +39,7 @@\n     remote_manager.get_recipe_sources(ref, export_path, sources_folder, current_remote)\n \n \n-def merge_directories(src, dst, excluded=None, symlinks=True):\n+def merge_directories(src, dst, excluded=None):\n     src = os.path.normpath(src)\n     dst = os.path.normpath(dst)\n     excluded = excluded or []\n@@ -54,16 +53,30 @@\n             return True\n         return False\n \n-    linked_folders = []\n-    for src_dir, dirs, files in walk(src, followlinks=True):\n+    def link_to_rel(pointer_src):\n+        linkto = os.readlink(pointer_src)\n+        if not os.path.isabs(linkto):\n+            linkto = os.path.join(os.path.dirname(pointer_src), linkto)\n+\n+        # Check if it is outside the sources\n+        out_of_source = os.path.relpath(linkto, os.path.realpath(src)).startswith(\".\")\n+        if out_of_source:\n+            # May warn about out of sources symlink\n+            return\n+\n+        # Create the symlink\n+        linkto_rel = os.path.relpath(linkto, os.path.dirname(pointer_src))\n+        pointer_dst = os.path.normpath(os.path.join(dst, os.path.relpath(pointer_src, src)))\n+        os.symlink(linkto_rel, pointer_dst)\n \n+    for src_dir, dirs, files in walk(src, followlinks=True):\n         if is_excluded(src_dir):\n             dirs[:] = []\n             continue\n \n         if os.path.islink(src_dir):\n-            rel_link = os.path.relpath(src_dir, src)\n-            linked_folders.append(rel_link)\n+            link_to_rel(src_dir)\n+            dirs[:] = []  # Do not enter subdirectories\n             continue\n \n         # Overwriting the dirs will prevents walk to get into them\n@@ -75,14 +88,11 @@\n         for file_ in files:\n             src_file = os.path.join(src_dir, file_)\n             dst_file = os.path.join(dst_dir, file_)\n-            if os.path.islink(src_file) and symlinks:\n-                linkto = os.readlink(src_file)\n-                os.symlink(linkto, dst_file)\n+            if os.path.islink(src_file):\n+                link_to_rel(src_file)\n             else:\n                 shutil.copy2(src_file, dst_file)\n \n-    FileCopier.link_folders(src, dst, linked_folders)\n-\n \n def config_source_local(src_folder, conanfile, conanfile_path, hook_manager):\n     \"\"\" Entry point for the \"conan source\" command.\n", "issue": "exports_sources fails to properly handle symlinks\nTo help us debug your issue please explain:\r\n\r\n- [x] I've read the [CONTRIBUTING guide](https://github.com/conan-io/conan/blob/develop/.github/CONTRIBUTING.md).\r\n- [x] I've specified the Conan version, operating system version and any tool that can be relevant.\r\n- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.\r\n\r\nOS: macOS 10.14.5\r\nConan: 1.16.0 (installed with pip into virtualenv, but also fails with 1.16.0 from Brew). Works with 1.15.1.\r\nPython: 3.7.3 (installed from MacPorts)\r\n\r\n`conanfile.py` has `exports_sources=src/*`, there is `src/foo.framework` with symlinks:\r\n```\r\n.\r\n\u251c\u2500\u2500 Headers -> Versions/Current/Headers\r\n\u251c\u2500\u2500 Resources -> Versions/Current/Resources\r\n\u251c\u2500\u2500 Versions\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 A\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 Headers\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 foo.h\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 Resources\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 Info.plist\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 en.lproj\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2502\u00a0\u00a0     \u2514\u2500\u2500 InfoPlist.strings\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 foo\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 Current -> A\r\n\u2514\u2500\u2500 foo -> Versions/Current/foo\r\n```\r\n`conan create . test/test` fails with the following error:\r\n```\r\n% conan create . test/test                                                                                                                                                                                                                                          master\r\nExporting package recipe\r\nsymlinks/1.0.0@test/test exports_sources: Copied 1 '.txt' file: CMakeLists.txt\r\nsymlinks/1.0.0@test/test exports_sources: Copied 1 '.cpp' file: hello.cpp\r\nsymlinks/1.0.0@test/test exports_sources: Copied 2 '.h' files: hello.h, foo.h\r\nsymlinks/1.0.0@test/test exports_sources: Copied 2 files: foo, foo\r\nsymlinks/1.0.0@test/test exports_sources: Copied 1 '.plist' file: Info.plist\r\nsymlinks/1.0.0@test/test exports_sources: Copied 1 '.strings' file: InfoPlist.strings\r\nsymlinks/1.0.0@test/test: The stored package has not changed\r\nsymlinks/1.0.0@test/test: Source folder is corrupted, forcing removal\r\nConfiguration:\r\n[settings]\r\n[options]\r\n[build_requires]\r\n[env]\r\n\r\nsymlinks/1.0.0@test/test: Forced build from source\r\nInstalling package: symlinks/1.0.0@test/test\r\nRequirements\r\n    symlinks/1.0.0@test/test from local cache - Cache\r\nPackages\r\n    symlinks/1.0.0@test/test:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Build\r\n\r\nsymlinks/1.0.0@test/test: WARN: Build folder is dirty, removing it: /Users/paul/.conan/data/symlinks/1.0.0/test/test/build/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9\r\nsymlinks/1.0.0@test/test: WARN: Trying to remove corrupted source folder\r\nsymlinks/1.0.0@test/test: WARN: This can take a while for big packages\r\nsymlinks/1.0.0@test/test: Configuring sources in /Users/paul/.conan/data/symlinks/1.0.0/test/test/source\r\nERROR: [Errno 17] File exists: 'Versions/Current/Resources' -> '/Users/paul/.conan/data/symlinks/1.0.0/test/test/source/src/foo.framework/Resources'\r\n```\r\n\r\nSample project: [conan_symlinks](https://github.com/Paultergeist/conan_symlinks)\n", "before_files": [{"content": "import os\nimport shutil\n\nimport six\n\nfrom conans.client import tools\nfrom conans.client.cmd.export import export_recipe, export_source\nfrom conans.client.file_copier import FileCopier\nfrom conans.errors import ConanException, ConanExceptionInUserConanfileMethod, \\\n    conanfile_exception_formatter\nfrom conans.model.conan_file import get_env_context_manager\nfrom conans.model.scm import SCM, get_scm_data\nfrom conans.paths import CONANFILE, CONAN_MANIFEST, EXPORT_SOURCES_TGZ_NAME, EXPORT_TGZ_NAME\nfrom conans.util.files import (clean_dirty, is_dirty, load, mkdir, rmdir, set_dirty, walk)\n\n\ndef complete_recipe_sources(remote_manager, cache, conanfile, ref, remotes):\n    \"\"\" the \"exports_sources\" sources are not retrieved unless necessary to build. In some\n    occassions, conan needs to get them too, like if uploading to a server, to keep the recipes\n    complete\n    \"\"\"\n    sources_folder = cache.package_layout(ref, conanfile.short_paths).export_sources()\n    if os.path.exists(sources_folder):\n        return None\n\n    if conanfile.exports_sources is None:\n        mkdir(sources_folder)\n        return None\n\n    # If not path to sources exists, we have a problem, at least an empty folder\n    # should be there\n    current_remote = cache.package_layout(ref).load_metadata().recipe.remote\n    if current_remote:\n        current_remote = remotes[current_remote]\n    if not current_remote:\n        raise ConanException(\"Error while trying to get recipe sources for %s. \"\n                             \"No remote defined\" % str(ref))\n\n    export_path = cache.package_layout(ref).export()\n    remote_manager.get_recipe_sources(ref, export_path, sources_folder, current_remote)\n\n\ndef merge_directories(src, dst, excluded=None, symlinks=True):\n    src = os.path.normpath(src)\n    dst = os.path.normpath(dst)\n    excluded = excluded or []\n    excluded = [os.path.normpath(entry) for entry in excluded]\n\n    def is_excluded(origin_path):\n        if origin_path == dst:\n            return True\n        rel_path = os.path.normpath(os.path.relpath(origin_path, src))\n        if rel_path in excluded:\n            return True\n        return False\n\n    linked_folders = []\n    for src_dir, dirs, files in walk(src, followlinks=True):\n\n        if is_excluded(src_dir):\n            dirs[:] = []\n            continue\n\n        if os.path.islink(src_dir):\n            rel_link = os.path.relpath(src_dir, src)\n            linked_folders.append(rel_link)\n            continue\n\n        # Overwriting the dirs will prevents walk to get into them\n        files[:] = [d for d in files if not is_excluded(os.path.join(src_dir, d))]\n\n        dst_dir = os.path.normpath(os.path.join(dst, os.path.relpath(src_dir, src)))\n        if not os.path.exists(dst_dir):\n            os.makedirs(dst_dir)\n        for file_ in files:\n            src_file = os.path.join(src_dir, file_)\n            dst_file = os.path.join(dst_dir, file_)\n            if os.path.islink(src_file) and symlinks:\n                linkto = os.readlink(src_file)\n                os.symlink(linkto, dst_file)\n            else:\n                shutil.copy2(src_file, dst_file)\n\n    FileCopier.link_folders(src, dst, linked_folders)\n\n\ndef config_source_local(src_folder, conanfile, conanfile_path, hook_manager):\n    \"\"\" Entry point for the \"conan source\" command.\n    \"\"\"\n    conanfile_folder = os.path.dirname(conanfile_path)\n\n    def get_sources_from_exports():\n        if conanfile_folder != src_folder:\n            conanfile.output.info(\"Executing exports to: %s\" % src_folder)\n            export_recipe(conanfile, conanfile_folder, src_folder)\n            export_source(conanfile, conanfile_folder, src_folder)\n\n    _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference=None, cache=None,\n                local_sources_path=conanfile_folder,\n                get_sources_from_exports=get_sources_from_exports)\n\n\ndef config_source(export_folder, export_source_folder, src_folder, conanfile, output,\n                  conanfile_path, reference, hook_manager, cache):\n    \"\"\" Implements the sources configuration when a package is going to be built in the\n    local cache.\n    \"\"\"\n\n    def remove_source(raise_error=True):\n        output.warn(\"This can take a while for big packages\")\n        try:\n            rmdir(src_folder)\n        except BaseException as e_rm:\n            set_dirty(src_folder)\n            msg = str(e_rm)\n            if six.PY2:\n                msg = str(e_rm).decode(\"latin1\")  # Windows prints some chars in latin1\n            output.error(\"Unable to remove source folder %s\\n%s\" % (src_folder, msg))\n            output.warn(\"**** Please delete it manually ****\")\n            if raise_error or isinstance(e_rm, KeyboardInterrupt):\n                raise ConanException(\"Unable to remove source folder\")\n\n    sources_pointer = cache.package_layout(reference).scm_folder()\n    local_sources_path = load(sources_pointer) if os.path.exists(sources_pointer) else None\n    if is_dirty(src_folder):\n        output.warn(\"Trying to remove corrupted source folder\")\n        remove_source()\n    elif conanfile.build_policy_always:\n        output.warn(\"Detected build_policy 'always', trying to remove source folder\")\n        remove_source()\n    elif local_sources_path and os.path.exists(local_sources_path):\n        output.warn(\"Detected 'scm' auto in conanfile, trying to remove source folder\")\n        remove_source()\n\n    if not os.path.exists(src_folder):  # No source folder, need to get it\n        set_dirty(src_folder)\n        mkdir(src_folder)\n\n        def get_sources_from_exports():\n            # so self exported files have precedence over python_requires ones\n            merge_directories(export_folder, src_folder)\n            # Now move the export-sources to the right location\n            merge_directories(export_source_folder, src_folder)\n\n        _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference,\n                    cache, local_sources_path, get_sources_from_exports=get_sources_from_exports)\n        clean_dirty(src_folder)  # Everything went well, remove DIRTY flag\n\n\ndef _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference, cache,\n                local_sources_path, get_sources_from_exports):\n    \"\"\"Execute the source core functionality, both for local cache and user space, in order:\n        - Calling pre_source hook\n        - Getting sources from SCM\n        - Getting sources from exported folders in the local cache\n        - Clean potential TGZ and other files in the local cache\n        - Executing the recipe source() method\n        - Calling post_source hook\n    \"\"\"\n    conanfile.source_folder = src_folder\n    conanfile.build_folder = None\n    conanfile.package_folder = None\n    with tools.chdir(src_folder):\n        try:\n            with get_env_context_manager(conanfile):\n                hook_manager.execute(\"pre_source\", conanfile=conanfile,\n                                     conanfile_path=conanfile_path,\n                                     reference=reference)\n                output = conanfile.output\n                output.info('Configuring sources in %s' % src_folder)\n                _run_scm(conanfile, src_folder, local_sources_path, output, cache=cache)\n\n                get_sources_from_exports()\n\n                if cache:\n                    _clean_source_folder(src_folder)  # TODO: Why is it needed in cache?\n                with conanfile_exception_formatter(conanfile.display_name, \"source\"):\n                    conanfile.source()\n\n                hook_manager.execute(\"post_source\", conanfile=conanfile,\n                                     conanfile_path=conanfile_path,\n                                     reference=reference)\n        except ConanExceptionInUserConanfileMethod:\n            raise\n        except Exception as e:\n            raise ConanException(e)\n\n\ndef _clean_source_folder(folder):\n    for f in (EXPORT_TGZ_NAME, EXPORT_SOURCES_TGZ_NAME, CONANFILE+\"c\",\n              CONANFILE+\"o\", CONANFILE, CONAN_MANIFEST):\n        try:\n            os.remove(os.path.join(folder, f))\n        except OSError:\n            pass\n    try:\n        shutil.rmtree(os.path.join(folder, \"__pycache__\"))\n    except OSError:\n        pass\n\n\ndef _run_scm(conanfile, src_folder, local_sources_path, output, cache):\n    scm_data = get_scm_data(conanfile)\n    if not scm_data:\n        return\n\n    dest_dir = os.path.normpath(os.path.join(src_folder, scm_data.subfolder))\n    if cache:\n        # When in cache, capturing the sources from user space is done only if exists\n        if not local_sources_path or not os.path.exists(local_sources_path):\n            local_sources_path = None\n    else:\n        # In user space, if revision=\"auto\", then copy\n        if scm_data.capture_origin or scm_data.capture_revision:  # FIXME: or clause?\n            scm = SCM(scm_data, local_sources_path, output)\n            scm_url = scm_data.url if scm_data.url != \"auto\" else \\\n                scm.get_qualified_remote_url(remove_credentials=True)\n\n            src_path = scm.get_local_path_to_url(url=scm_url)\n            if src_path:\n                local_sources_path = src_path\n        else:\n            local_sources_path = None\n\n    if local_sources_path and conanfile.develop:\n        excluded = SCM(scm_data, local_sources_path, output).excluded_files\n        output.info(\"Getting sources from folder: %s\" % local_sources_path)\n        merge_directories(local_sources_path, dest_dir, excluded=excluded)\n    else:\n        output.info(\"Getting sources from url: '%s'\" % scm_data.url)\n        scm = SCM(scm_data, dest_dir, output)\n        scm.checkout()\n\n    if cache:\n        # This is a bit weird. Why after a SCM should we remove files. Maybe check conan 2.0\n        _clean_source_folder(dest_dir)  # TODO: Why removing in the cache? There is no danger.\n", "path": "conans/client/source.py"}], "after_files": [{"content": "import os\nimport shutil\n\nimport six\n\nfrom conans.client import tools\nfrom conans.client.cmd.export import export_recipe, export_source\nfrom conans.errors import ConanException, ConanExceptionInUserConanfileMethod, \\\n    conanfile_exception_formatter\nfrom conans.model.conan_file import get_env_context_manager\nfrom conans.model.scm import SCM, get_scm_data\nfrom conans.paths import CONANFILE, CONAN_MANIFEST, EXPORT_SOURCES_TGZ_NAME, EXPORT_TGZ_NAME\nfrom conans.util.files import (clean_dirty, is_dirty, load, mkdir, rmdir, set_dirty, walk)\n\n\ndef complete_recipe_sources(remote_manager, cache, conanfile, ref, remotes):\n    \"\"\" the \"exports_sources\" sources are not retrieved unless necessary to build. In some\n    occassions, conan needs to get them too, like if uploading to a server, to keep the recipes\n    complete\n    \"\"\"\n    sources_folder = cache.package_layout(ref, conanfile.short_paths).export_sources()\n    if os.path.exists(sources_folder):\n        return None\n\n    if conanfile.exports_sources is None:\n        mkdir(sources_folder)\n        return None\n\n    # If not path to sources exists, we have a problem, at least an empty folder\n    # should be there\n    current_remote = cache.package_layout(ref).load_metadata().recipe.remote\n    if current_remote:\n        current_remote = remotes[current_remote]\n    if not current_remote:\n        raise ConanException(\"Error while trying to get recipe sources for %s. \"\n                             \"No remote defined\" % str(ref))\n\n    export_path = cache.package_layout(ref).export()\n    remote_manager.get_recipe_sources(ref, export_path, sources_folder, current_remote)\n\n\ndef merge_directories(src, dst, excluded=None):\n    src = os.path.normpath(src)\n    dst = os.path.normpath(dst)\n    excluded = excluded or []\n    excluded = [os.path.normpath(entry) for entry in excluded]\n\n    def is_excluded(origin_path):\n        if origin_path == dst:\n            return True\n        rel_path = os.path.normpath(os.path.relpath(origin_path, src))\n        if rel_path in excluded:\n            return True\n        return False\n\n    def link_to_rel(pointer_src):\n        linkto = os.readlink(pointer_src)\n        if not os.path.isabs(linkto):\n            linkto = os.path.join(os.path.dirname(pointer_src), linkto)\n\n        # Check if it is outside the sources\n        out_of_source = os.path.relpath(linkto, os.path.realpath(src)).startswith(\".\")\n        if out_of_source:\n            # May warn about out of sources symlink\n            return\n\n        # Create the symlink\n        linkto_rel = os.path.relpath(linkto, os.path.dirname(pointer_src))\n        pointer_dst = os.path.normpath(os.path.join(dst, os.path.relpath(pointer_src, src)))\n        os.symlink(linkto_rel, pointer_dst)\n\n    for src_dir, dirs, files in walk(src, followlinks=True):\n        if is_excluded(src_dir):\n            dirs[:] = []\n            continue\n\n        if os.path.islink(src_dir):\n            link_to_rel(src_dir)\n            dirs[:] = []  # Do not enter subdirectories\n            continue\n\n        # Overwriting the dirs will prevents walk to get into them\n        files[:] = [d for d in files if not is_excluded(os.path.join(src_dir, d))]\n\n        dst_dir = os.path.normpath(os.path.join(dst, os.path.relpath(src_dir, src)))\n        if not os.path.exists(dst_dir):\n            os.makedirs(dst_dir)\n        for file_ in files:\n            src_file = os.path.join(src_dir, file_)\n            dst_file = os.path.join(dst_dir, file_)\n            if os.path.islink(src_file):\n                link_to_rel(src_file)\n            else:\n                shutil.copy2(src_file, dst_file)\n\n\ndef config_source_local(src_folder, conanfile, conanfile_path, hook_manager):\n    \"\"\" Entry point for the \"conan source\" command.\n    \"\"\"\n    conanfile_folder = os.path.dirname(conanfile_path)\n\n    def get_sources_from_exports():\n        if conanfile_folder != src_folder:\n            conanfile.output.info(\"Executing exports to: %s\" % src_folder)\n            export_recipe(conanfile, conanfile_folder, src_folder)\n            export_source(conanfile, conanfile_folder, src_folder)\n\n    _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference=None, cache=None,\n                local_sources_path=conanfile_folder,\n                get_sources_from_exports=get_sources_from_exports)\n\n\ndef config_source(export_folder, export_source_folder, src_folder, conanfile, output,\n                  conanfile_path, reference, hook_manager, cache):\n    \"\"\" Implements the sources configuration when a package is going to be built in the\n    local cache.\n    \"\"\"\n\n    def remove_source(raise_error=True):\n        output.warn(\"This can take a while for big packages\")\n        try:\n            rmdir(src_folder)\n        except BaseException as e_rm:\n            set_dirty(src_folder)\n            msg = str(e_rm)\n            if six.PY2:\n                msg = str(e_rm).decode(\"latin1\")  # Windows prints some chars in latin1\n            output.error(\"Unable to remove source folder %s\\n%s\" % (src_folder, msg))\n            output.warn(\"**** Please delete it manually ****\")\n            if raise_error or isinstance(e_rm, KeyboardInterrupt):\n                raise ConanException(\"Unable to remove source folder\")\n\n    sources_pointer = cache.package_layout(reference).scm_folder()\n    local_sources_path = load(sources_pointer) if os.path.exists(sources_pointer) else None\n    if is_dirty(src_folder):\n        output.warn(\"Trying to remove corrupted source folder\")\n        remove_source()\n    elif conanfile.build_policy_always:\n        output.warn(\"Detected build_policy 'always', trying to remove source folder\")\n        remove_source()\n    elif local_sources_path and os.path.exists(local_sources_path):\n        output.warn(\"Detected 'scm' auto in conanfile, trying to remove source folder\")\n        remove_source()\n\n    if not os.path.exists(src_folder):  # No source folder, need to get it\n        set_dirty(src_folder)\n        mkdir(src_folder)\n\n        def get_sources_from_exports():\n            # so self exported files have precedence over python_requires ones\n            merge_directories(export_folder, src_folder)\n            # Now move the export-sources to the right location\n            merge_directories(export_source_folder, src_folder)\n\n        _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference,\n                    cache, local_sources_path, get_sources_from_exports=get_sources_from_exports)\n        clean_dirty(src_folder)  # Everything went well, remove DIRTY flag\n\n\ndef _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference, cache,\n                local_sources_path, get_sources_from_exports):\n    \"\"\"Execute the source core functionality, both for local cache and user space, in order:\n        - Calling pre_source hook\n        - Getting sources from SCM\n        - Getting sources from exported folders in the local cache\n        - Clean potential TGZ and other files in the local cache\n        - Executing the recipe source() method\n        - Calling post_source hook\n    \"\"\"\n    conanfile.source_folder = src_folder\n    conanfile.build_folder = None\n    conanfile.package_folder = None\n    with tools.chdir(src_folder):\n        try:\n            with get_env_context_manager(conanfile):\n                hook_manager.execute(\"pre_source\", conanfile=conanfile,\n                                     conanfile_path=conanfile_path,\n                                     reference=reference)\n                output = conanfile.output\n                output.info('Configuring sources in %s' % src_folder)\n                _run_scm(conanfile, src_folder, local_sources_path, output, cache=cache)\n\n                get_sources_from_exports()\n\n                if cache:\n                    _clean_source_folder(src_folder)  # TODO: Why is it needed in cache?\n                with conanfile_exception_formatter(conanfile.display_name, \"source\"):\n                    conanfile.source()\n\n                hook_manager.execute(\"post_source\", conanfile=conanfile,\n                                     conanfile_path=conanfile_path,\n                                     reference=reference)\n        except ConanExceptionInUserConanfileMethod:\n            raise\n        except Exception as e:\n            raise ConanException(e)\n\n\ndef _clean_source_folder(folder):\n    for f in (EXPORT_TGZ_NAME, EXPORT_SOURCES_TGZ_NAME, CONANFILE+\"c\",\n              CONANFILE+\"o\", CONANFILE, CONAN_MANIFEST):\n        try:\n            os.remove(os.path.join(folder, f))\n        except OSError:\n            pass\n    try:\n        shutil.rmtree(os.path.join(folder, \"__pycache__\"))\n    except OSError:\n        pass\n\n\ndef _run_scm(conanfile, src_folder, local_sources_path, output, cache):\n    scm_data = get_scm_data(conanfile)\n    if not scm_data:\n        return\n\n    dest_dir = os.path.normpath(os.path.join(src_folder, scm_data.subfolder))\n    if cache:\n        # When in cache, capturing the sources from user space is done only if exists\n        if not local_sources_path or not os.path.exists(local_sources_path):\n            local_sources_path = None\n    else:\n        # In user space, if revision=\"auto\", then copy\n        if scm_data.capture_origin or scm_data.capture_revision:  # FIXME: or clause?\n            scm = SCM(scm_data, local_sources_path, output)\n            scm_url = scm_data.url if scm_data.url != \"auto\" else \\\n                scm.get_qualified_remote_url(remove_credentials=True)\n\n            src_path = scm.get_local_path_to_url(url=scm_url)\n            if src_path:\n                local_sources_path = src_path\n        else:\n            local_sources_path = None\n\n    if local_sources_path and conanfile.develop:\n        excluded = SCM(scm_data, local_sources_path, output).excluded_files\n        output.info(\"Getting sources from folder: %s\" % local_sources_path)\n        merge_directories(local_sources_path, dest_dir, excluded=excluded)\n    else:\n        output.info(\"Getting sources from url: '%s'\" % scm_data.url)\n        scm = SCM(scm_data, dest_dir, output)\n        scm.checkout()\n\n    if cache:\n        # This is a bit weird. Why after a SCM should we remove files. Maybe check conan 2.0\n        _clean_source_folder(dest_dir)  # TODO: Why removing in the cache? There is no danger.\n", "path": "conans/client/source.py"}]}