def main(directory=False): if directory: os.chdir(directory) config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: config.apply_file(cf) # Lock source and destination to the same paths as the Makefile. srcdir = '.' destdir = os.path.join('_build', get_conf_builder(srcdir)) status = build(srcdir, destdir) if status != 0: sys.exit(status) reasons = config.skip_submit_reasons() if reasons: print("Not submitting content to the content service because:", file=sys.stderr) print(file=sys.stderr) for reason in reasons: print(" * " + reason, file=sys.stderr) print(file=sys.stderr) return submit(destdir, config.content_store_url, config.content_store_apikey, config.content_id_base)
def init(self): SingleFileHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: self.deconst_config.apply_file(cf) self.should_submit = not self.deconst_config.skip_submit_reasons()
def init_builder(builder): """ Common Builder initialization. """ builder.translator_class = OffsetHTMLTranslator builder.deconst_config = Configuration(os.environ) if path.exists('_deconst.json'): with open('_deconst.json', 'r', encoding='utf-8') as cf: builder.deconst_config.apply_file(cf)
def main(): config = Configuration(os.environ) # Lock source and destination to the same paths as the Makefile. srcdir, destdir = '.', '_build/deconst' status = build(srcdir, destdir) if status != 0: sys.exit(status) reasons = config.skip_submit_reasons() if reasons: print("Not submitting content to the content service because:", file=sys.stderr) print(file=sys.stderr) for reason in reasons: print(" * " + reason, file=sys.stderr) print(file=sys.stderr) return submit(destdir, config.content_store_url, config.content_id_base)
def init(self): SingleFileHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: self.deconst_config.apply_file(cf) try: self.git_root = self.deconst_config.get_git_root(os.getcwd()) except FileNotFoundError: self.git_root = None self.should_submit = not self.deconst_config.skip_submit_reasons()
def init(self): JSONHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) self.should_submit = not self.deconst_config.skip_submit_reasons()
class DeconstJSONBuilder(JSONHTMLBuilder): """ Custom Sphinx builder that generates Deconst-compatible JSON documents. """ implementation = jsonimpl name = 'deconst' out_suffix = '.json' def init(self): JSONHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) self.should_submit = not self.deconst_config.skip_submit_reasons() def finish(self): """ We need to write images and static assets *first*. Also, the search indices and so on aren't necessary. """ def dump_context(self, context, filename): """ Override the default serialization code to save a derived metadata envelope, instead. """ envelope = { "body": context["body"], "title": context["title"], "layout_key": context["deconst_layout_key"] } super().dump_context(envelope, filename) def handle_page(self, pagename, ctx, *args, **kwargs): """ Override the default serialization code to save a derived metadata envelope, instead. """ meta = self.env.metadata[pagename] ctx["deconst_layout_key"] = meta.get( "deconstlayout", self.config.deconst_default_layout) super().handle_page(pagename, ctx, *args, **kwargs) def post_process_images(self, doctree): """ Publish images to the content store. Modify the image reference with the """ JSONHTMLBuilder.post_process_images(self, doctree) if self.should_submit: for node in doctree.traverse(nodes.image): node['uri'] = self._publish_entry(node['uri']) def _publish_entry(self, srcfile): # TODO guess the content-type url = self.deconst_config.content_store_url + "assets" basename = path.basename(srcfile) files = {basename: open(srcfile, 'rb')} response = requests.post(url, files=files) response.raise_for_status() return response.json()[basename]
class DeconstSingleJSONBuilder(SingleFileHTMLBuilder): """ Custom Sphinx builder that generates Deconst-compatible JSON documents. """ name = 'deconst-single' def init(self): SingleFileHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: self.deconst_config.apply_file(cf) try: self.git_root = self.deconst_config.get_git_root(os.getcwd()) except FileNotFoundError: self.git_root = None self.should_submit = not self.deconst_config.skip_submit_reasons() def fix_refuris(self, tree): """ The parent implementation of this includes the base file name, which breaks if we serve with a trailing slash. We just want what's between the last "#" and the end of the string """ # fix refuris with double anchor for refnode in tree.traverse(nodes.reference): if 'refuri' not in refnode: continue refuri = refnode['refuri'] hashindex = refuri.rfind('#') if hashindex < 0: continue # Leave absolute URLs alone if re.match("^https?://", refuri): continue refnode['refuri'] = refuri[hashindex:] def write(self, *ignored): docnames = self.env.all_docs self.info(bold('preparing documents... '), nonl=True) self.prepare_writing(docnames) self.info('done') self.info(bold('assembling single document... '), nonl=True) doctree = self.assemble_doctree() doctree.settings = self.docsettings self.env.toc_secnumbers = self.assemble_toc_secnumbers() self.secnumbers = self.env.toc_secnumbers.get(self.config.master_doc, {}) self.fignumbers = self.env.toc_fignumbers.get(self.config.master_doc, {}) target_uri = self.get_target_uri(self.config.master_doc) self.imgpath = relative_uri(target_uri, '_images') self.dlpath = relative_uri(target_uri, '_downloads') self.current_docname = self.config.master_doc if self.should_submit: self.post_process_images(doctree) # Merge this page's metadata with the repo-wide data. meta = self.deconst_config.meta.copy() meta.update(self.env.metadata.get(self.config.master_doc)) title = self.env.longtitles.get(self.config.master_doc) toc = self.env.get_toctree_for(self.config.master_doc, self, False) self.fix_refuris(toc) rendered_title = self.render_partial(title)['title'] rendered_toc = self.render_partial(toc)['fragment'] layout_key = meta.get('deconstlayout', self.config.deconst_default_layout) unsearchable = meta.get('deconstunsearchable', self.config.deconst_default_unsearchable) if unsearchable is not None: unsearchable = unsearchable in ("true", True) rendered_body = self.write_body(doctree) if self.git_root != None and self.deconst_config.github_url != "": # current_page_name has no extension, and it _might_ not be .rst fileglob = path.join( os.getcwd(), self.env.srcdir, self.config.master_doc + ".*" ) edit_segments = [ self.deconst_config.github_url, "edit", self.deconst_config.github_branch, path.relpath(glob.glob(fileglob)[0], self.git_root) ] meta["github_edit_url"] = '/'.join(segment.strip('/') for segment in edit_segments) envelope = { "title": meta.get('deconsttitle', rendered_title), "body": rendered_body, "toc": rendered_toc, "layout_key": layout_key, "meta": dict(meta) } if unsearchable is not None: envelope["unsearchable"] = unsearchable page_cats = meta.get('deconstcategories') global_cats = self.config.deconst_categories if page_cats is not None or global_cats is not None: cats = set() if page_cats is not None: cats.update(re.split("\s*,\s*", page_cats)) cats.update(global_cats or []) envelope["categories"] = list(cats) outfile = os.path.join(self.outdir, self.config.master_doc + '.json') with open(outfile, 'w', encoding="utf-8") as dumpfile: json.dump(envelope, dumpfile) def write_body(self, doctree): destination = StringOutput(encoding='utf-8') doctree.settings = self.docsettings self.docwriter.write(doctree, destination) self.docwriter.assemble_parts() return self.docwriter.parts['fragment'] def finish(self): """ Nothing to see here """ def post_process_images(self, doctree): """ Publish images to the content store. Modify the image reference with the """ SingleFileHTMLBuilder.post_process_images(self, doctree) if self.should_submit: for node in doctree.traverse(nodes.image): node['uri'] = self._publish_entry(node['uri']) def _publish_entry(self, srcfile): (content_type, _) = mimetypes.guess_type(srcfile) auth = 'deconst apikey="{}"'.format( self.deconst_config.content_store_apikey) headers = {"Authorization": auth} verify = self.deconst_config.tls_verify url = self.deconst_config.content_store_url + "assets" basename = path.basename(srcfile) if content_type: payload = (basename, open(srcfile, 'rb'), content_type) else: payload = open(srcfile, 'rb') files = {basename: payload} response = requests.post(url, files=files, headers=headers, verify=verify) response.raise_for_status() return response.json()[basename]
class DeconstSerialJSONBuilder(JSONHTMLBuilder): """ Custom Sphinx builder that generates Deconst-compatible JSON documents. """ implementation = jsonimpl name = 'deconst' out_suffix = '.json' def init(self): JSONHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: self.deconst_config.apply_file(cf) try: self.git_root = self.deconst_config.get_git_root(os.getcwd()) except FileNotFoundError: self.git_root = None self.should_submit = not self.deconst_config.skip_submit_reasons() def finish(self): """ We need to write images and static assets *first*. Also, the search indices and so on aren't necessary. """ def dump_context(self, context, filename): """ Override the default serialization code to save a derived metadata envelope, instead. """ # Merge this page's metadata with the repo-wide data. meta = self.deconst_config.meta.copy() meta.update(context['meta']) if self.git_root != None and self.deconst_config.github_url != "": # current_page_name has no extension, and it _might_ not be .rst fileglob = path.join( os.getcwd(), context["current_page_name"] + ".*" ) edit_segments = [ self.deconst_config.github_url, "edit", self.deconst_config.github_branch, path.relpath(glob.glob(fileglob)[0], self.git_root) ] meta["github_edit_url"] = '/'.join(segment.strip('/') for segment in edit_segments) envelope = { "body": context["body"], "title": context["deconst_title"], "layout_key": context["deconst_layout_key"], "meta": meta } if context["deconst_unsearchable"] is not None: unsearchable = context["deconst_unsearchable"] in ("true", True) envelope["unsearchable"] = unsearchable page_cats = context["deconst_categories"] global_cats = self.config.deconst_categories if page_cats is not None or global_cats is not None: cats = set() if page_cats is not None: cats.update(re.split("\s*,\s*", page_cats)) cats.update(global_cats or []) envelope["categories"] = list(cats) n = context.get("next") p = context.get("prev") if n: envelope["next"] = { "url": n["link"], "title": n["title"] } if p: envelope["previous"] = { "url": p["link"], "title": p["title"] } if context["display_toc"]: envelope["toc"] = context["toc"] super().dump_context(envelope, filename) def handle_page(self, pagename, ctx, *args, **kwargs): """ Override the default serialization code to save a derived metadata envelope, instead. """ meta = self.env.metadata[pagename] ctx["deconst_layout_key"] = meta.get( "deconstlayout", self.config.deconst_default_layout) ctx["deconst_title"] = meta.get("deconsttitle", ctx["title"]) ctx["deconst_categories"] = meta.get("deconstcategories") ctx["deconst_unsearchable"] = meta.get( "deconstunsearchable", self.config.deconst_default_unsearchable) super().handle_page(pagename, ctx, *args, **kwargs) def post_process_images(self, doctree): """ Publish images to the content store. Modify the image reference with the """ JSONHTMLBuilder.post_process_images(self, doctree) if self.should_submit: for node in doctree.traverse(nodes.image): node['uri'] = self._publish_entry(node['uri']) def _publish_entry(self, srcfile): (content_type, _) = mimetypes.guess_type(srcfile) auth = 'deconst apikey="{}"'.format( self.deconst_config.content_store_apikey) headers = {"Authorization": auth} verify = self.deconst_config.tls_verify url = self.deconst_config.content_store_url + "assets" basename = path.basename(srcfile) if content_type: payload = (basename, open(srcfile, 'rb'), content_type) else: payload = open(srcfile, 'rb') files = {basename: payload} response = requests.post(url, files=files, headers=headers, verify=verify) response.raise_for_status() return response.json()[basename]
class DeconstSingleJSONBuilder(SingleFileHTMLBuilder): """ Custom Sphinx builder that generates Deconst-compatible JSON documents. """ name = 'deconst-single' def init(self): SingleFileHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: self.deconst_config.apply_file(cf) self.should_submit = not self.deconst_config.skip_submit_reasons() def fix_refuris(self, tree): """ The parent implementation of this includes the base file name, which breaks if we serve with a trailing slash. We just want what's between the last "#" and the end of the string """ # fix refuris with double anchor for refnode in tree.traverse(nodes.reference): if 'refuri' not in refnode: continue refuri = refnode['refuri'] hashindex = refuri.rfind('#') if hashindex < 0: continue # Leave absolute URLs alone if re.match("^https?://", refuri): continue refnode['refuri'] = refuri[hashindex:] def write(self, *ignored): docnames = self.env.all_docs self.info(bold('preparing documents... '), nonl=True) self.prepare_writing(docnames) self.info('done') self.info(bold('assembling single document... '), nonl=True) doctree = self.assemble_doctree() doctree.settings = self.docsettings self.env.toc_secnumbers = self.assemble_toc_secnumbers() self.secnumbers = self.env.toc_secnumbers.get(self.config.master_doc, {}) self.fignumbers = self.env.toc_fignumbers.get(self.config.master_doc, {}) target_uri = self.get_target_uri(self.config.master_doc) self.imgpath = relative_uri(target_uri, '_images') self.dlpath = relative_uri(target_uri, '_downloads') self.current_docname = self.config.master_doc if self.should_submit: self.post_process_images(doctree) meta = self.env.metadata.get(self.config.master_doc) title = self.env.longtitles.get(self.config.master_doc) toc = self.env.get_toctree_for(self.config.master_doc, self, False) self.fix_refuris(toc) rendered_title = self.render_partial(title)['title'] rendered_toc = self.render_partial(toc)['fragment'] layout_key = meta.get('deconstlayout', self.config.deconst_default_layout) rendered_body = self.write_body(doctree) envelope = { "title": meta.get('deconsttitle', rendered_title), "body": rendered_body, "toc": rendered_toc, "layout_key": layout_key, "meta": dict(meta) } outfile = os.path.join(self.outdir, self.config.master_doc + '.json') with open(outfile, 'w', encoding="utf-8") as dumpfile: json.dump(envelope, dumpfile) def write_body(self, doctree): destination = StringOutput(encoding='utf-8') doctree.settings = self.docsettings self.docwriter.write(doctree, destination) self.docwriter.assemble_parts() return self.docwriter.parts['fragment'] def finish(self): """ Nothing to see here """ def post_process_images(self, doctree): """ Publish images to the content store. Modify the image reference with the """ SingleFileHTMLBuilder.post_process_images(self, doctree) if self.should_submit: for node in doctree.traverse(nodes.image): node['uri'] = self._publish_entry(node['uri']) def _publish_entry(self, srcfile): (content_type, _) = mimetypes.guess_type(srcfile) auth = 'deconst apikey="{}"'.format( self.deconst_config.content_store_apikey) headers = {"Authorization": auth} url = self.deconst_config.content_store_url + "assets" basename = path.basename(srcfile) if content_type: payload = (basename, open(srcfile, 'rb'), content_type) else: payload = open(srcfile, 'rb') files = {basename: payload} response = requests.post(url, files=files, headers=headers) response.raise_for_status() return response.json()[basename]
class DeconstSerialJSONBuilder(JSONHTMLBuilder): """ Custom Sphinx builder that generates Deconst-compatible JSON documents. """ implementation = jsonimpl name = "deconst" out_suffix = ".json" def init(self): JSONHTMLBuilder.init(self) self.deconst_config = Configuration(os.environ) if os.path.exists("_deconst.json"): with open("_deconst.json", "r", encoding="utf-8") as cf: self.deconst_config.apply_file(cf) self.should_submit = not self.deconst_config.skip_submit_reasons() def finish(self): """ We need to write images and static assets *first*. Also, the search indices and so on aren't necessary. """ def dump_context(self, context, filename): """ Override the default serialization code to save a derived metadata envelope, instead. """ envelope = { "body": context["body"], "title": context["deconst_title"], "layout_key": context["deconst_layout_key"], } n = context.get("next") p = context.get("prev") if n: envelope["next"] = {"url": n["link"], "title": n["title"]} if p: envelope["previous"] = {"url": p["link"], "title": p["title"]} if context["display_toc"]: envelope["toc"] = context["toc"] super().dump_context(envelope, filename) def handle_page(self, pagename, ctx, *args, **kwargs): """ Override the default serialization code to save a derived metadata envelope, instead. """ meta = self.env.metadata[pagename] ctx["deconst_layout_key"] = meta.get("deconstlayout", self.config.deconst_default_layout) ctx["deconst_title"] = meta.get("deconsttitle", ctx["title"]) super().handle_page(pagename, ctx, *args, **kwargs) def post_process_images(self, doctree): """ Publish images to the content store. Modify the image reference with the """ JSONHTMLBuilder.post_process_images(self, doctree) if self.should_submit: for node in doctree.traverse(nodes.image): node["uri"] = self._publish_entry(node["uri"]) def _publish_entry(self, srcfile): (content_type, _) = mimetypes.guess_type(srcfile) auth = 'deconst apikey="{}"'.format(self.deconst_config.content_store_apikey) headers = {"Authorization": auth} url = self.deconst_config.content_store_url + "assets" basename = path.basename(srcfile) if content_type: payload = (basename, open(srcfile, "rb"), content_type) else: payload = open(srcfile, "rb") files = {basename: payload} response = requests.post(url, files=files, headers=headers) response.raise_for_status() return response.json()[basename]