comparison piecrust/commands/builtin/themes.py @ 488:a00750896316

themes: Improve CLI, add `deactivate` command. * `link` command renamed to `activate`. * `deactivate` command removes the active theme. * `info` command shows information about the active theme. Runs by default when doing `chef themes`.
author Ludovic Chabant <ludovic@chabant.com>
date Wed, 22 Jul 2015 21:32:54 -0700
parents d5885c6d64bd
children 5336e146ac8d
comparison
equal deleted inserted replaced
487:61508ae67488 488:a00750896316
21 if app.root_dir is None: 21 if app.root_dir is None:
22 return 22 return
23 23
24 subparsers = parser.add_subparsers() 24 subparsers = parser.add_subparsers()
25 p = subparsers.add_parser( 25 p = subparsers.add_parser(
26 'info',
27 help="Provides information about the current theme.")
28 p.set_defaults(sub_func=self._info)
29
30 p = subparsers.add_parser(
26 'create', 31 'create',
27 help="Create a new theme for the current website.") 32 help="Create a new theme for the current website.")
28 p.add_argument( 33 p.add_argument(
29 '--from-default', 34 '--from-default',
30 action='store_true', 35 action='store_true',
39 'override', 44 'override',
40 help="Copies a theme to the website for customization.") 45 help="Copies a theme to the website for customization.")
41 p.set_defaults(sub_func=self._overrideTheme) 46 p.set_defaults(sub_func=self._overrideTheme)
42 47
43 p = subparsers.add_parser( 48 p = subparsers.add_parser(
44 'link', 49 'activate',
45 help="Installs a theme as a link to an already existing " 50 help="Makes a given theme the active one for the current "
46 "theme on disk.") 51 "website by creating a symbolic link to it from the "
52 "'theme' directory. If a symbolic link can't be created "
53 "the theme will be copied to the 'theme' directory.")
47 p.add_argument( 54 p.add_argument(
48 'theme_dir', 55 'theme_dir',
49 help="The directory of the theme to link.") 56 help="The directory of the theme to link.")
50 p.set_defaults(sub_func=self._linkTheme) 57 p.add_argument(
58 '--link-only',
59 action='store_true',
60 help="Abort the activation if a symbolic link can't be "
61 "created")
62 p.set_defaults(sub_func=self._activateTheme)
63
64 p = subparsers.add_parser(
65 'deactivate',
66 help="Removes the currently active theme for the website. "
67 "This removes the symbolic link to the theme, if any, or "
68 "deletes the theme folder if it was copied locally.")
69 p.set_defaults(sub_func=self._deactivateTheme)
51 70
52 def checkedRun(self, ctx): 71 def checkedRun(self, ctx):
53 if not hasattr(ctx.args, 'sub_func'): 72 if not hasattr(ctx.args, 'sub_func'):
54 ctx.parser.parse_args(['themes', '--help']) 73 ctx.args = ctx.parser.parse_args(['themes', 'info'])
55 return
56 ctx.args.sub_func(ctx) 74 ctx.args.sub_func(ctx)
75
76 def _info(self, ctx):
77 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR)
78 if not os.path.exists(theme_dir):
79 logger.info("Using default theme, from: %s" % ctx.app.theme_dir)
80 elif os.path.islink(theme_dir):
81 target = os.readlink(theme_dir)
82 target = os.path.join(os.path.dirname(theme_dir), target)
83 logger.info("Using theme, from: %s" % target)
84 else:
85 logger.info("Using local theme.")
57 86
58 def _createTheme(self, ctx): 87 def _createTheme(self, ctx):
59 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR) 88 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR)
60 if os.path.exists(theme_dir): 89 if os.path.exists(theme_dir):
61 logger.warning("A theme already exists, and will be overwritten. " 90 logger.warning("A theme already exists, and will be overwritten. "
138 logger.info(os.path.relpath(c[1], app_dir)) 167 logger.info(os.path.relpath(c[1], app_dir))
139 if not os.path.exists(os.path.dirname(c[1])): 168 if not os.path.exists(os.path.dirname(c[1])):
140 os.makedirs(os.path.dirname(c[1])) 169 os.makedirs(os.path.dirname(c[1]))
141 shutil.copy2(c[0], c[1]) 170 shutil.copy2(c[0], c[1])
142 171
143 def _linkTheme(self, ctx): 172 def _activateTheme(self, ctx):
144 if not os.path.isdir(ctx.args.theme_dir): 173 if not os.path.isdir(ctx.args.theme_dir):
145 logger.error("Invalid theme directory: %s" % ctx.args.theme_dir) 174 logger.error("Invalid theme directory: %s" % ctx.args.theme_dir)
146 return 1 175 return 1
147 176
148 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR) 177 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR)
157 if len(ans) > 0 and ans.lower() not in ['y', 'yes']: 186 if len(ans) > 0 and ans.lower() not in ['y', 'yes']:
158 return 1 187 return 1
159 188
160 shutil.rmtree(theme_dir) 189 shutil.rmtree(theme_dir)
161 190
162 os.symlink(ctx.args.theme_dir, theme_dir) 191 try:
163 192 os.symlink(ctx.args.theme_dir, theme_dir)
193 except (NotImplementedError, OSError) as ex:
194 if ctx.args.link_only:
195 logger.error("Couldn't symlink the theme: %s" % ex)
196 return 1
197
198 # pre-Vista Windows, or unprivileged user... gotta copy the
199 # theme the old fashioned way.
200 logging.warning("Can't create a symbolic link... copying the "
201 "theme directory instead.")
202 ignore = shutil.ignore_patterns('.git*', '.hg*', '.svn', '.bzr')
203 shutil.copytree(ctx.args.theme_dir, theme_dir, ignore=ignore)
204
205 def _deactivateTheme(self, ctx):
206 theme_dir = os.path.join(ctx.app.root_dir, THEME_DIR)
207
208 if os.path.islink(theme_dir):
209 logger.debug("Unlinking: %s" % theme_dir)
210 os.unlink(theme_dir)
211 elif os.path.isdir(theme_dir):
212 logger.warning("The active theme is local. Are you sure you want "
213 "to delete the theme directory? [Y/n]")
214 ans = input()
215 if len(ans) > 0 and ans.lower() not in ['y', 'yes']:
216 return 1
217
218 shutil.rmtree(theme_dir)
219 else:
220 logger.info("No currently active theme.")
221