Source code for cookiecutter.generate

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
cookiecutter.generate
---------------------

Functions for generating a project from a project template.
"""
from __future__ import unicode_literals
import logging
import os
import shutil
import sys

from jinja2 import FileSystemLoader, Template
from jinja2.environment import Environment
from binaryornot.check import is_binary

from .exceptions import NonTemplatedInputDirException
from .utils import make_sure_path_exists, unicode_open


if sys.version_info[:2] < (2, 7):
    import simplejson as json
    from ordereddict import OrderedDict
else:
    import json
    from collections import OrderedDict


[docs]def generate_context(config_file='cookiecutter.json'): """ Generates the context for a Cookiecutter project template. Loads the JSON file as a Python object, with key being the JSON filename. :param config_file: JSON file containing project config values. :paramtype config_file: filename """ context = {} file_handle = open(config_file) obj = json.load(file_handle, encoding='utf-8', object_pairs_hook=OrderedDict) # Add the Python object to the context dictionary file_name = os.path.split(config_file)[1] file_stem = file_name.split('.')[0] context[file_stem] = obj logging.debug('Context generated is {0}'.format(context)) return context
[docs]def generate_file(infile, context, env): """ 1. Render the contents of infile. 2. Render the filename of infile as the name of outfile. 3. Write the rendered infile to outfile. :param infile: Input file to generate the file from. """ logging.debug("Generating file {0}".format(infile)) # Render the path to the output file (but don't include the filename) outdir_tmpl = Template(os.path.dirname(os.path.abspath(infile))) outdir = outdir_tmpl.render(**context) fname = os.path.basename(os.path.abspath(infile)) # input/output filename # Write it to the corresponding place in output_dir outfile = os.path.join(outdir, fname) logging.debug("outfile is {0}".format(outfile)) # Just copy over binary files. Don't render. logging.debug("Check {0} to see if it's a binary".format(infile)) if is_binary(infile): logging.debug("Copying binary {0} to {1} without rendering" .format(infile, outfile)) shutil.copyfile(infile, outfile) else: # Force fwd slashes on Windows for get_template # This is a by-design Jinja issue infile_fwd_slashes = infile.replace(os.path.sep, '/') # Render the file tmpl = env.get_template(infile_fwd_slashes) rendered_file = tmpl.render(**context) # Render the output filename before writing name_tmpl = Template(outfile) rendered_name = name_tmpl.render(**context) logging.debug("Writing {0}".format(rendered_name)) with unicode_open(rendered_name, 'w') as fh: fh.write(rendered_file)
[docs]def generate_files(template_dir, context=None): """ Renders the templates and saves them to files. :param input_dir: Project template input directory. :paramtype input_dir: directory """ # Always use utf-8 template_dir = template_dir logging.debug('Generating project from {0}...'.format(template_dir)) context = context or {} env = Environment() env.loader = FileSystemLoader('.') # Render dirname before writing name_tmpl = Template(template_dir) output_dir = name_tmpl.render(**context) if output_dir == template_dir: raise NonTemplatedInputDirException logging.debug("output_dir is {0}".format(output_dir)) make_sure_path_exists(output_dir) for root, dirs, files in os.walk(template_dir): for d in dirs: indir = os.path.join(root, d) outdir = indir.replace(template_dir, output_dir, 1) # Render dirname before writing name_tmpl = Template(outdir) rendered_dirname = name_tmpl.render(**context) make_sure_path_exists(rendered_dirname) for f in files: logging.debug("f is {0}".format(f)) infile = os.path.join(root, f) generate_file(infile, context, env)