annotate piecrust/commands/builtin/themes.py @ 411:e7b865f8f335

bake: Enable multiprocess baking. Baking is now done by running a worker per CPU, and sending jobs to them. This changes several things across the codebase: * Ability to not cache things related to pages other than the 'main' page (i.e. the page at the bottom of the execution stack). * Decouple the baking process from the bake records, so only the main process keeps track (and modifies) the bake record. * Remove the need for 'batch page getters' and loading a page directly from the page factories. There are various smaller changes too included here, including support for scope performance timers that are saved with the bake record and can be printed out to the console. Yes I got carried away. For testing, the in-memory 'mock' file-system doesn't work anymore, since we're spawning processes, so this is replaced by a 'tmpfs' file-system which is saved in temporary files on disk and deleted after tests have run.
author Ludovic Chabant <ludovic@chabant.com>
date Fri, 12 Jun 2015 17:09:19 -0700
parents d70a4adb61dd
children c5df200354e8
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
273
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
1 import os
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
2 import os.path
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
3 import shutil
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
4 import logging
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
5 import yaml
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
6 from piecrust import (
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
7 RESOURCES_DIR, THEME_DIR, THEME_CONFIG_PATH, THEME_INFO_PATH)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
8 from piecrust.commands.base import ChefCommand
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
9
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
10
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
11 logger = logging.getLogger(__name__)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
12
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
13
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
14 class ThemesCommand(ChefCommand):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
15 def __init__(self):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
16 super(ThemesCommand, self).__init__()
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
17 self.name = 'themes'
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
18 self.description = "Manage the themes for the current website."
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
19
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
20 def setupParser(self, parser, app):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
21 if app.root_dir is None:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
22 return
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
23
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
24 subparsers = parser.add_subparsers()
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
25 p = subparsers.add_parser(
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
26 'create',
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
27 help="Create a new theme for the current website.")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
28 p.add_argument(
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
29 '--from-default',
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
30 action='store_true',
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
31 help=("Create a new theme by copying the default PieCrust "
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
32 "theme into the theme directory"))
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
33 p.add_argument(
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
34 'theme_name',
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
35 help=("The name of the theme"))
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
36 p.set_defaults(sub_func=self._createTheme)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
37
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
38 p = subparsers.add_parser(
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
39 'override',
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
40 help="Copies a theme to the website for customization.")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
41 p.set_defaults(sub_func=self._overrideTheme)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
42
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
43 def checkedRun(self, ctx):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
44 ctx.args.sub_func(ctx)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
45
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
46 def _createTheme(self, ctx):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
47 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
48 if os.path.exists(theme_dir):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
49 logger.warning("A theme already exists, and will be overwritten. "
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
50 "Are you sure? [Y/n]")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
51 ans = input()
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
52 if len(ans) > 0 and ans.lower() not in ['y', 'yes']:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
53 return 1
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
54
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
55 shutil.rmtree(theme_dir)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
56
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
57 try:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
58 if ctx.args.from_default:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
59 def reporting_copy2(src, dst):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
60 rel_dst = os.path.relpath(dst, ctx.app.root_dir)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
61 logger.info(rel_dst)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
62 shutil.copy2(src, dst)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
63
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
64 default_theme_dir = os.path.join(RESOURCES_DIR, 'theme')
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
65 shutil.copytree(default_theme_dir, theme_dir,
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
66 copy_function=reporting_copy2)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
67 return 0
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
68
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
69 logger.info("Creating theme directory.")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
70 os.makedirs(theme_dir)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
71
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
72 logger.info("Creating theme_config.yml")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
73 config_path = os.path.join(theme_dir, THEME_CONFIG_PATH)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
74 with open(config_path, 'w', encoding='utf8') as fp:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
75 fp.write('')
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
76
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
77 logger.info("Creating theme_info.yml")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
78 info_path = os.path.join(theme_dir, THEME_INFO_PATH)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
79 with open(info_path, 'w', encoding='utf8') as fp:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
80 yaml.dump(
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
81 {
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
82 'name': ctx.args.theme_name or 'My New Theme',
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
83 'description': "A new PieCrust theme.",
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
84 'authors': ['Your Name Here <email or twitter>'],
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
85 'url': 'http://www.example.org'},
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
86 fp,
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
87 default_flow_style=False)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
88 return 0
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
89 except:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
90 logger.error("Error occured, deleting theme directory.")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
91 shutil.rmtree(theme_dir)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
92 raise
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
93
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
94 def _overrideTheme(self, ctx):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
95 app_dir = ctx.app.root_dir
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
96 theme_dir = ctx.app.theme_dir
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
97 if not theme_dir:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
98 logger.error("There is not theme currently applied to override.")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
99 return 1
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
100
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
101 copies = []
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
102 for dirpath, dirnames, filenames in os.walk(theme_dir):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
103 rel_dirpath = os.path.relpath(dirpath, theme_dir)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
104 for name in filenames:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
105 if (dirpath == theme_dir and
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
106 name in [THEME_CONFIG_PATH, THEME_INFO_PATH]):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
107 continue
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
108 src_path = os.path.join(dirpath, name)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
109 dst_path = os.path.join(app_dir, rel_dirpath, name)
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
110 copies.append((src_path, dst_path))
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
111
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
112 conflicts = []
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
113 for c in copies:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
114 if os.path.exists(c[1]):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
115 conflicts.append(c[1])
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
116 if conflicts:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
117 logger.warning("Some website files will be overwritten:")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
118 for c in conflicts:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
119 logger.warning(os.path.relpath(c, app_dir))
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
120 logger.warning("Are you sure? [Y/n]")
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
121 ans = input()
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
122 if len(ans) > 0 and ans.lower() not in ['y', 'yes']:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
123 return 1
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
124
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
125 for c in copies:
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
126 logger.info(os.path.relpath(c[1], app_dir))
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
127 if not os.path.exists(os.path.dirname(c[1])):
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
128 os.makedirs(os.path.dirname(c[1]))
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
129 shutil.copy2(c[0], c[1])
d70a4adb61dd themes: Add the `chef themes` command
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
130