Symlinks within cookiecutter templates are copied as directories rather than as symlinks.
Here's a cookiecutter template with just the name variable in cookiecutter.json:
12:42 $ tree symlink-cc/
symlink-cc/
โโโ cookiecutter.json
โโโ {{\ cookiecutter.name\ }}
โโโ original
โย ย โโโ afile.txt
โโโ symlink -> original
I can successfully run cookiecutter.
12:38 $ cookiecutter symlink-cc
name [pjb]: pjb
In the output, the symlink turns into a standard directory.
12:42 $ tree pjb/
pjb/
โโโ original
โย ย โโโ afile.txt
โโโ symlink
Working on a PR that should fix this.
Nice catch @pjbull! We look forward to your PR ๐
What I would like is support for copying all symlinks as-is, not just symlinks to existing directories.
My use case is I have symlinks in the cooiecutter template that use relative paths to point to directories that do not exist (specifically, to directories that will be created by npm install in a new project).
In that situation, symlinks are added to os.walk's files list (not dirs list), and cookiecutter stops with an IOError exception when going to read the symlink's target.
Traceback (most recent call last):
File "/Users/david/venv/bin/cookiecutter", line 11, in <module>
load_entry_point('cookiecutter==1.5.1', 'console_scripts', 'cookiecutter')()
File "/Users/david/venv/lib/python2.7/site-packages/click/core.py", line 722, in __call__
return self.main(*args, **kwargs)
File "/Users/david/venv/lib/python2.7/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/Users/david/venv/lib/python2.7/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/Users/david/venv/lib/python2.7/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/Users/david/venv/lib/python2.7/site-packages/cookiecutter/cli.py", line 123, in main
default_config=default_config,
File "/Users/david/venv/lib/python2.7/site-packages/cookiecutter/main.py", line 91, in cookiecutter
output_dir=output_dir
File "/Users/david/venv/lib/python2.7/site-packages/cookiecutter/generate.py", line 349, in generate_files
generate_file(project_dir, infile, context, env)
File "/Users/david/venv/lib/python2.7/site-packages/cookiecutter/generate.py", line 153, in generate_file
if is_binary(infile):
File "/Users/david/venv/lib/python2.7/site-packages/binaryornot/check.py", line 24, in is_binary
chunk = get_starting_chunk(filename)
File "/Users/david/venv/lib/python2.7/site-packages/binaryornot/helpers.py", line 32, in get_starting_chunk
with open(filename, 'rb') as f:
IOError: [Errno 2] No such file or directory: u'{{ cookiecutter.static_dir }}/src/bulma'
This is Python 2.7, current master of cookiecutter (a000a8f236a79b7d2dbffc6e945fcd69007a9baf).
According to my analysis the culprit of this behavior is shutil.copytree. In Python 3.3 this function also causes the following error (for a symlink framework to a directory):
Traceback (most recent call last):
File "/home/peter/.virtualenvs/name-of-the-project/bin/cookiecutter", line 11, in <module>
sys.exit(main())
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/click/core.py", line 722, in __call__
return self.main(*args, **kwargs)
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/cookiecutter/cli.py", line 123, in main
default_config=default_config,
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/cookiecutter/main.py", line 91, in cookiecutter
output_dir=output_dir
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages/cookiecutter/generate.py", line 314, in generate_files
shutil.copytree(indir, outdir)
File "/home/peter/.virtualenvs/name-of-the-project/lib/python3.3/shutil.py", line 343, in copytree
raise Error(errors)
shutil.Error: [('_/frameworks/Symfony/web/bundles/framework', '/home/peter/Development/repos/name-of-the-project/_/frameworks/Symfony/web/bundles/framework', "[Errno 21] Is a directory: '_/frameworks/Symfony/web/bundles/framework'")]
There is a bug report on the Python bug tracker for this issue: https://bugs.python.org/issue21697
According to https://github.com/pypa/pip/issues/1006#issuecomment-19890662 the error should go away if we set symlinks=True in shutil.copytree().
Details on the cookiecutter and Python version I used for the above stacktrace:
$ cookiecutter --version
Cookiecutter 1.5.1 from /home/peter/.virtualenvs/name-of-the-project/lib/python3.3/site-packages (Python 3.3)
Most helpful comment
Nice catch @pjbull! We look forward to your PR ๐