Mercurial > piecrust2
comparison piecrust/publishing/publisher.py @ 621:8f9c0bdb3724
publish: Polish/refactor the publishing workflows.
* Add a `--preview` option.
* The `--list` option gives a nicer output, and prints warnings/errors for
incorrect configuration.
* Moved most of the `shell` code into a base class that's reusable.
* Simplified the code to log publishing to a file.
* Nicer output overall, with times.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Mon, 08 Feb 2016 20:44:26 -0800 |
parents | e2e955a3bb25 |
children | 6abb436fea5b |
comparison
equal
deleted
inserted
replaced
620:c2708f20a87b | 621:8f9c0bdb3724 |
---|---|
1 import os.path | |
2 import time | |
1 import logging | 3 import logging |
4 import urllib.parse | |
5 from piecrust.chefutil import format_timed | |
2 from piecrust.publishing.base import PublishingContext | 6 from piecrust.publishing.base import PublishingContext |
3 | 7 |
4 | 8 |
5 logger = logging.getLogger(__name__) | 9 logger = logging.getLogger(__name__) |
6 | 10 |
15 | 19 |
16 class Publisher(object): | 20 class Publisher(object): |
17 def __init__(self, app): | 21 def __init__(self, app): |
18 self.app = app | 22 self.app = app |
19 | 23 |
20 def run(self, target, log_file=None): | 24 def run(self, target, preview=False, log_file=None): |
25 start_time = time.perf_counter() | |
26 | |
27 # Get the configuration for this target. | |
21 target_cfg = self.app.config.get('publish/%s' % target) | 28 target_cfg = self.app.config.get('publish/%s' % target) |
22 if not target_cfg: | 29 if not target_cfg: |
23 raise InvalidPublishTargetError( | 30 raise InvalidPublishTargetError( |
24 "No such publish target: %s" % target) | 31 "No such publish target: %s" % target) |
25 | 32 |
26 target_type = target_cfg.get('type') | 33 target_type = None |
27 if not target_type: | 34 bake_first = True |
28 raise InvalidPublishTargetError( | 35 parsed_url = None |
29 "Publish target '%s' doesn't specify a type." % target) | 36 if isinstance(target_cfg, dict): |
37 target_type = target_cfg.get('type') | |
38 if not target_type: | |
39 raise InvalidPublishTargetError( | |
40 "Publish target '%s' doesn't specify a type." % target) | |
41 bake_first = target_cfg.get('bake', True) | |
42 elif isinstance(target_cfg, str): | |
43 comps = urllib.parse.urlparse(target_cfg) | |
44 if not comps.scheme: | |
45 raise InvalidPublishTargetError( | |
46 "Publish target '%s' has an invalid target URL." % | |
47 target) | |
48 parsed_url = comps | |
49 target_type = find_publisher_name(self.app, comps.scheme) | |
50 if target_type is None: | |
51 raise InvalidPublishTargetError( | |
52 "No such publish target scheme: %s" % comps.scheme) | |
30 | 53 |
54 # Setup logging stuff. | |
55 hdlr = None | |
56 root_logger = logging.getLogger() | |
57 if log_file and not preview: | |
58 logger.debug("Adding file handler for: %s" % log_file) | |
59 hdlr = logging.FileHandler(log_file, mode='w', encoding='utf8') | |
60 root_logger.addHandler(hdlr) | |
61 if not preview: | |
62 logger.info("Deploying to %s" % target) | |
63 else: | |
64 logger.info("Previewing deployment to %s" % target) | |
65 | |
66 # Bake first is necessary. | |
67 bake_out_dir = None | |
68 if bake_first: | |
69 bake_out_dir = os.path.join(self.app.cache_dir, 'pub', target) | |
70 if not preview: | |
71 bake_start_time = time.perf_counter() | |
72 logger.debug("Baking first to: %s" % bake_out_dir) | |
73 | |
74 from piecrust.baking.baker import Baker | |
75 baker = Baker(self.app, bake_out_dir) | |
76 rec1 = baker.bake() | |
77 | |
78 from piecrust.processing.pipeline import ProcessorPipeline | |
79 proc = ProcessorPipeline(self.app, bake_out_dir) | |
80 rec2 = proc.run() | |
81 | |
82 if not rec1.success or not rec2.success: | |
83 raise Exception( | |
84 "Error during baking, aborting publishing.") | |
85 logger.info(format_timed(bake_start_time, "Baked website.")) | |
86 else: | |
87 logger.info("Would bake to: %s" % bake_out_dir) | |
88 | |
89 # Create the appropriate publisher. | |
31 pub = None | 90 pub = None |
32 for pub_cls in self.app.plugin_loader.getPublishers(): | 91 for pub_cls in self.app.plugin_loader.getPublishers(): |
33 if pub_cls.PUBLISHER_NAME == target_type: | 92 if pub_cls.PUBLISHER_NAME == target_type: |
34 pub = pub_cls(self.app, target) | 93 pub = pub_cls(self.app, target) |
35 break | 94 break |
36 if pub is None: | 95 if pub is None: |
37 raise InvalidPublishTargetError( | 96 raise InvalidPublishTargetError( |
38 "Publish target '%s' has invalid type: %s" % | 97 "Publish target '%s' has invalid type: %s" % |
39 (target, target_type)) | 98 (target, target_type)) |
99 pub.parsed_url = parsed_url | |
100 | |
101 # Publish! | |
102 logger.debug( | |
103 "Running publish target '%s' with publisher: %s" % | |
104 (target, pub.PUBLISHER_NAME)) | |
105 pub_start_time = time.perf_counter() | |
40 | 106 |
41 ctx = PublishingContext() | 107 ctx = PublishingContext() |
42 | 108 ctx.bake_out_dir = bake_out_dir |
43 hdlr = None | 109 ctx.preview = preview |
44 if log_file: | |
45 if not pub.is_using_custom_logging: | |
46 logger.debug("Adding file handler for: %s" % log_file) | |
47 hdlr = logging.FileHandler(log_file, mode='w', encoding='utf8') | |
48 logger.addHandler(hdlr) | |
49 else: | |
50 logger.debug("Creating custom log file: %s" % log_file) | |
51 ctx.custom_logging_file = open( | |
52 log_file, mode='w', encoding='utf8') | |
53 | |
54 intro_msg = ("Running publish target '%s' with publisher: %s" % | |
55 (target, pub.PUBLISHER_NAME)) | |
56 logger.debug(intro_msg) | |
57 if ctx.custom_logging_file: | |
58 ctx.custom_logging_file.write(intro_msg + "\n") | |
59 | |
60 try: | 110 try: |
61 success = pub.run(ctx) | 111 success = pub.run(ctx) |
62 except Exception as ex: | 112 except Exception as ex: |
63 raise PublishingError( | 113 raise PublishingError( |
64 "Error publishing to target: %s" % target) from ex | 114 "Error publishing to target: %s" % target) from ex |
65 finally: | 115 finally: |
66 if ctx.custom_logging_file: | |
67 ctx.custom_logging_file.close() | |
68 if hdlr: | 116 if hdlr: |
69 logger.removeHandler(hdlr) | 117 root_logger.removeHandler(hdlr) |
70 hdlr.close() | 118 hdlr.close() |
71 | 119 |
72 if not success: | 120 if not success: |
73 raise PublishingError( | 121 raise PublishingError( |
74 "Unknown error publishing to target: %s" % target) | 122 "Unknown error publishing to target: %s" % target) |
123 logger.info(format_timed( | |
124 pub_start_time, "Ran publisher %s" % pub.PUBLISHER_NAME)) | |
75 | 125 |
126 logger.info(format_timed(start_time, 'Deployed to %s' % target)) | |
127 | |
128 | |
129 def find_publisher_class(app, scheme): | |
130 for pub_cls in app.plugin_loader.getPublishers(): | |
131 pub_sch = getattr(pub_cls, 'PUBLISHER_SCHEME', None) | |
132 if ('bake+%s' % pub_sch) == scheme: | |
133 return pub_cls | |
134 return None | |
135 | |
136 | |
137 def find_publisher_name(app, scheme): | |
138 pub_cls = find_publisher_class(app, scheme) | |
139 if pub_cls: | |
140 return pub_cls.PUBLISHER_NAME | |
141 return None | |
142 |