Conan: [bug] Windows: conan create fails if recipe is inside a symlinked folder

Created on 24 Oct 2018  Â·  4Comments  Â·  Source: conan-io/conan

Environment

  • Conan 1.8.4
  • Python [3.6, 3.7]
  • Windows [10, 2016 server]

How to reproduce
I'm using conan-bzip2 as a "simple" example but the same goes for conan-zlib for instance and most likely any other.

  • clone the repo: git clone https://github.com/conan-community/conan-bzip2.git
  • create a symlink to the directory: mklink /D conan-bzip2-link conan-bzip2
  • run conan create on the symlink: conan create conan-bzip2-link test/link

The result is an error:
bzip2/1.0.6@test/link: ERROR: Package 'ce1f8ff23addde793223a2a82ed7fe355c57a589' build failed bzip2/1.0.6@test/link: WARN: Build folder C:\Users\vagrant\.conan\data\bzip2\1.0.6\test\link\build\ce1f8ff23addde793223a2a82ed7fe355c57a589 ERROR: bzip2/1.0.6@test/link: Error in build() method, line 41 shutil.move("CMakeLists.txt", "%s/CMakeLists.txt" % self.zip_folder_name) FileNotFoundError: [Errno 2] No such file or directory: 'CMakeLists.txt'

The process fails because Conan does not correctly copy the source in the $HOME\.conandatabzip21.0.6testlinkexport directory (notably conan_export.tgz and CMakeLists.txt are missing).

For the curious
I've stumbled upon this bug in my team CI that is using Concourse.
Concourse, on Windows workers, creates symlinked directory for the git repository toward volumes that are copied among the workers.

high low queue bug

Most helpful comment

@danimtb If I follow the equivalent steps to reproduce in Linux, namely:

  • clone the repo: git clone https://github.com/conan-community/conan-bzip2.git
  • create a symlink to the directory: ln -s conan-bzip2-link conan-bzip2
  • run conan create on the symlink: conan create conan-bzip2-link test/link

I don't observe any anomaly when running as my non privileged user.

All 4 comments

I am not that familiar with code, but file_copier.py line 108 (method _filter_files) skips symbolic links adding them to the linked_subfolders.
then, file_copier.py line 154 (method _link_folders) ignores symbolic links which starts from dot - if relpath.startswith("."):. it is supposed to ignore symbolic links outside of folders, however, single dot doesn't go outside, it refers to the same folder.
this appears to be a bug for me, but even after changing it to the if relpath.startswith(".."):, it fails for me with the following error:

Traceback (most recent call last):
  File "C:/bincrafters/conan\conans\client\command.py", line 1427, in run
    method(args[0][1:])
  File "C:/bincrafters/conan\conans\client\command.py", line 297, in create
    test_build_folder=args.test_build_folder)
  File "C:/bincrafters/conan\conans\client\conan_api.py", line 86, in wrapper
    return f(*args, **kwargs)
  File "C:/bincrafters/conan\conans\client\conan_api.py", line 356, in create
    self._client_cache, self._hook_manager)
  File "C:/bincrafters/conan\conans\client\cmd\export.py", line 59, in cmd_export
    keep_source)
  File "C:/bincrafters/conan\conans\client\cmd\export.py", line 159, in _export_conanfile
    export_recipe(conanfile, origin_folder, exports_folder)
  File "C:/bincrafters/conan\conans\client\cmd\export.py", line 265, in export_recipe
    copier(pattern, links=True, excludes=excluded_exports)
  File "C:/bincrafters/conan\conans\client\file_copier.py", line 83, in __call__
    self._link_folders(src, dst, link_folders)
  File "C:/bincrafters/conan\conans\client\file_copier.py", line 171, in _link_folders
    os.symlink(link, dst_link)
OSError: symbolic link privilege not held

ERROR: symbolic link privilege not held

Process finished with exit code 1

@conan-io/barbarians WDYT?

@SSE4 I have seen that error in windows and you have to run Conan with administrator privileges, otherwise the creation of symlinks during the copy process fail.

@aledeganopix4d I have tested and this looks like a bug in the exports and exports_sources not following the links correctly. Did you see this same result under Linux?

@danimtb If I follow the equivalent steps to reproduce in Linux, namely:

  • clone the repo: git clone https://github.com/conan-community/conan-bzip2.git
  • create a symlink to the directory: ln -s conan-bzip2-link conan-bzip2
  • run conan create on the symlink: conan create conan-bzip2-link test/link

I don't observe any anomaly when running as my non privileged user.

(I'm having a look at this issue after working on #5342, although it is not related to this bug, it can add information to this one)

Running the example provided by @aledeganopix4d as a privileged user I'm reproducing the error. From my POV the issue is related to the insights provided by @SSE4

  • the recipe itself is a linked folder (. is a linked folder)
  • the recipe contains: exports_sources = "CMakeLists.txt"
  • iterating the source directory in the FileCopier class we find the following code:

```python
for root, subfolders, files in walk(src, followlinks=True):
if root in excluded_folders:
subfolders[:] = []
continue

        if links and os.path.islink(root):
            linked_folders.append(os.path.relpath(root, src))
            subfolders[:] = []
            continue

`` Here, theifcondition is satisfied forroot, which has the same value assrcand here we get the value.` and then the logic reported by @SSE4 .

In my Mac I don't get the same behaviour (I assume that Linux will be the same). In the Mac the evaluation of os.path.islink(root) return False. Have a look at these lines:

⇒  ls -la /Users/jgsogo/dev/conan/issues/symlinks/conan-bzip2-link
lrwxr-xr-x  1 jgsogo  staff  11 12 jun 15:51 /Users/jgsogo/dev/conan/issues/symlinks/conan-bzip2-link -> conan-bzip2
[python3]jgsogo@Mac:~/dev/conan/issues/symlinks|
⇒  python
Python 3.7.3 (default, Mar 27 2019, 09:23:39) 
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.path.islink('/Users/jgsogo/dev/conan/issues/symlinks/conan-bzip2-link')
True
>>> os.path.islink('/Users/jgsogo/dev/conan/issues/symlinks/conan-bzip2-link/')
False

... with the final / it is not a symlink, without it it is :fearful: Windows returns always the same:

>>> os.path.islink("C:/Users/jgsogo/dev/conan-bzip2-link/")    
True                                                          
>>> os.path.islink("C:/Users/jgsogo/dev/conan-bzip2-link")     
True                                                          
>>>                                                           
Was this page helpful?
0 / 5 - 0 ratings