Cookiecutter is a small command-line Python utility used to generate projects from templates. It is largely used in the Python world, in particular for Django projects. You can find it here:
Cookiecutter GitHub repository: https://github.com/cookiecutter/cookiecutter
Cookiecutter Documentation: https://cookiecutter.readthedocs.io/
Despite its Python origin and vocation, Cookiecutter is a general-purpose tool. It can be used (ad is actually used) to generate any kind of software project. You can see a collection of Cookiecutters templates here:
https://github.com/search?q=cookiecutter&type=Repositories
Cookiecutter can also be used to create custom-tailored cookiecutter templates.
Things to know
Behind the scenes, Cookiecutter uses the same Jinja “template engine” used by Python’s Flask web framework:
https://jinja.palletsprojects.com/
This means that it just replace every “placeholder” found in a file (and in a file tree) with the value found in a given JSON file.
For example, if Cookiecutter finds this line in a file:
This file was created by {{author_name}}
And it has a JSON file with this line:
"author_name" = "Donald Duck"
Cookiecutter will just give you this line:
This file was created by Donald Duck
These new values are contained in a file called cookiecutter.json
By default, Cookiecutter processes a whole directory tree and all the files it contains giving you a new directory tree with the same files. Each file will contain the new values.
Weird file and directory names
Besides this, you have to be aware that Cookiecutter takes a part of its variables directly from the file system, in particular from the names of directories and files that are part of the source tree. This is the reason why, in a Cookiecutter source tree, you can see directories with names like this:
{{cookiecutter.directory_name}}
No matter how weird they can be, these names are perfectly legal on Linux (even if they make it hard to work on the command line, for example using the “cd” command) and Cookiecutter can use them to create file and directory names that depend on the content of its JSON file and/or are supplied by the user.
This simple structure makes it very easy to build your own cookiecutter template for your specific needs.
A GTK / Glade Cookiecutter example
As a starting point for our example, I will use the template suggested by Programmer’s Notes in Chapter 4 of his “GTK Glade Programming Tutorial” that you can find here:
https://prognotes.net/2015/07/gtk-3-glade-c-programming-template/
This template is intended to create a C-Language template for developing a GTK3 application for Linux using the Glade GUI designer.
The source tree
In a “regular” source tree, you would have this structure:
$ tree . . ├── glade │ └── main_window.glade ├── makefile └── src └── gtk_app.c
Replacing the usual file names with the “parametric” ones that will be used by Cookiecutter, we get the following source tree.
$ tree . . ├── glade │ └── main_window.glade ├── makefile └── src └── {{cookiecutter.main_c_source_filename}}.c
Please note the {{cookiecutter.main_c_source_filename}}.c
name for the main .c file.
Given that the top-level directory name must be “parametric”, we are forced to enclose the whole source tree in a “hosting” directory with a parametric Jinja name, like this:
$ tree . . ├── {{cookiecutter.directory_name}} │ ├── glade │ │ └── main_window.glade │ ├── makefile │ └── src │ └── {{cookiecutter.main_c_source_filename}}.c ├── cookiecutter.json ├── LICENSE └── README.md
Please note the {{cookiecutter.directory_name}}
top-level directory name. This will be the name of the directory containing our “project” (or “source tree”).
Please note, as well, that the enclosing directory contains a bunch of auxiliary files, like README.md, LICENSE and – most important! – the cookiecutter.json file that contains the values for the variables used by Cookiecutter. These files are only part of the Cookiecutter template and will not be part of the resulting GTK/Glade project.
The main.c file
The main.c file does not contains anything that must depend on the user’s choices and can be left unmodified:
#includeint main(int argc, char *argv[]) { GtkBuilder *builder; GtkWidget *window; gtk_init(&argc, &argv); // builder = gtk_builder_new(); // gtk_builder_add_from_file (builder, "glade/window_main.glade", NULL); // Update October 2019: The line below replaces the 2 lines above builder = gtk_builder_new_from_file("glade/main_window.glade"); window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window")); gtk_builder_connect_signals(builder, NULL); g_object_unref(builder); gtk_widget_show(window); gtk_main(); return 0; } // called when window is closed void on_window_main_destroy() { gtk_main_quit(); }
As you can see, it is exactly the same as in the original articles.
The main_window.glade file
The glade file is a XML file that describes the structure of the program’s GUI. It contains a title tag that depends on the user’s choices and for this reason, you can see a Jinja tag inside it:
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.16.1 --> <interface> <requires lib="gtk+" version="3.10"/> <object class="GtkWindow" id="main_window"> <property name="can_focus">False</property> <property name="title" translatable="yes">{{cookiecutter.main_window_title}} Main Window</property> <property name="default_width">640</property> <property name="default_height">480</property> <signal name="destroy" handler="on_main_window_destroy" swapped="no"/> <child> <placeholder/> </child> </object> </interface>
Please note the
{{cookiecutter.main_window_title}}
Injia tag for the main window title.
The makefile
The c makefile contains a couple of references to file names that depend on the user’s choice and must be “parametrized” accordingly:
TARGET={{cookiecutter.main_c_source_filename}} # compiler CC=gcc # debug DEBUG=-g # optimisation OPT=-O0 # warnings WARN=-Wall PTHREAD=-pthread CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe GTKLIB=`pkg-config --cflags --libs gtk+-3.0` # linker LD=gcc LDFLAGS=$(PTHREAD) $(GTKLIB) -export-dynamic OBJS= {{cookiecutter.main_c_source_filename}}.o all: $(OBJS) $(LD) -o $(TARGET) $(OBJS) $(LDFLAGS) {{cookiecutter.main_c_source_filename}}.o: src/{{cookiecutter.main_c_source_filename}}.c $(CC) -c $(CCFLAGS) src/{{cookiecutter.main_c_source_filename}}.c $(GTKLIB) -o {{cookiecutter.main_c_source_filename}}.o clean: rm -f *.o $(TARGET)
Please note the {{…}} Jinja tags.
How to use your new cookiecutter
Using this Cookiecutter template is as easy as to invoke the following command in your Linux terminal.
cookiecutter name-of-you-hosting-directory
On my Linux box, this boils down to:
cookiecutter /home/alex/Templates/Cookiecutters/cookiecutter_gtk_glade
If you use my example GitHub repository, you can use this command line:
cookiecutter https://github.com/alexbottoni/cookiecutter_gtk_glade.git
This command will download the template from GitHub and use it to generate a new GTK/Glade project in the directory of your choice. You will be asked:
- A “directory_name” for the top-level directory of your source tree. It defaults to “gtk_glade_app”.
- A “main_c_source_filename” for the name of your main C language file. It defaults to “main”.
- A “main_window_title” for the top-level window of your GUI. It defaults to “Main Window”.
Source Code of this article
You can find the source code for this article here:
https://github.com/alexbottoni/cookiecutter_gtk_glade
Alex Bottoni