Search code examples
pythoncookiecutter

In a coockiecutter template, add folder only if choice variable has a given value


I am creating a cookiecutter template and would like to add a folder (and the files it contains) only if a variable has a given value. For example cookiecutter.json:

{
    "project_slug":"project_folder"
    "i_want_this_folder":['y','n']
}

and my template structure looks like:

template
└── {{ cookiecutter.project_slug }}
    ├── config.ini
    ├── data
    │   └── data.csv
    ├── {% if cookiecutter.i_want_this_folder == 'y' %}my_folder{% endif %}
        └── some_files

However, when running cookiecutter template and choose 'n' I get an error

Error: "~/project_folder" directory already exists

Is my syntax for the folder name correct?


Solution

  • I was facing the same issue having the option to add or no folders with different contents (all folders can exist at the same time). The structure of the project is the following:

    ├── {{cookiecutter.project_slug}}                 
    │   │
    │   ├── folder_1_to_add_or_no 
    │   │    ├── file1.py
    │   │    ├── file2.py
    │   │    └── file3.txt
    │   │
    │   ├── folder_2_to_add_or_no 
    │   │    ├── image.png
    │   │    ├── data.csv
    │   │    └── file.txt         
    │   │
    │   └── folder_3_to_add_or_no 
    │        ├── file1.py
    │        └── some_dir 
    │
    ├── hooks 
    │   └── post_gen_project.py 
    │
    └── cookiecutter.json 
    

    where the cookiecutter.json contains the following

    {
      "project_owner": "some-name",
      "project_slug": "some-project",
      "add_folder_one": ["yes", "no"],
      "add_folder_two": ["yes", "no"],
      "add_folder_three": ["yes", "no"],
    }
    

    as each directory folder_X_to_add_or_no contains different files, the trick is to remove those folders that the answer is "no", you can do this through a hook. Inside the post_gen_project.py file

    # post_gen_project.py
    import os
    import shutil
    
    from pathlib import Path
    
    # Current path
    path = Path(os.getcwd())
    
    # Source path
    parent_path = path.parent.absolute()
    
    def remove(filepath):
        if os.path.isfile(filepath):
            os.remove(filepath)
        elif os.path.isdir(filepath):
            shutil.rmtree(filepath)
            
    folders_to_add = [
        'folder_one',
        'folder_two',
        'folder_three'
    ] 
    
    for folder in folders_to_add:
    
        # Check if user wants the folder
        cookiecutter_var = '{{cookiecutter.' + f'{folder}' + '}}'
        add_folder = cookiecutter_var == 'yes'
        
        # User does not want folder so remove it
        if not add_folder:
    
            folder_path = os.path.join(
                parent_path, 
                '{{cookiecutter.project_slug}}', 
                'folder'
            )
    
            remove(folder_path)
    

    Now the folders the user choose not to add will be removed.

    Select add_folder_one:
    1 - yes
    2 - no
    Choose from 1, 2 [1]: 
    

    References

    This answer is based on briancapello answer on this github issue