def on_post_build(self, config): sources = set(self.sources) log.debug('Found {} unique sources in {} total embeds'.format( len(sources), len(self.sources))) self.sources = [] for source in sources: dest_rel_path = '{}-{}.{}'.format(source.source_rel, source.page_index, self.config['format']) abs_src_path = os.path.join(config['docs_dir'], source.source_rel) abs_dest_path = os.path.join(config['site_dir'], dest_rel_path) cache_filename, exit_status = self.exporter.ensure_file_cached( abs_src_path, source.source_rel, source.page_index, self.config['drawio_executable'], self.config['drawio_args'], self.config['cache_dir'], self.config['format']) if exit_status not in (None, 0): log.error( 'Export failed with exit status {}; skipping copy'.format( exit_status)) continue try: copy_file(cache_filename, abs_dest_path) except FileNotFoundError: log.warn('Export successful, but wrote no output file')
def test_copy_files_without_permissions(self): src_paths = [ 'foo.txt', 'bar.txt', 'baz.txt', ] expected = [ 'foo.txt', 'bar.txt', 'baz.txt', ] src_dir = tempfile.mkdtemp() dst_dir = tempfile.mkdtemp() try: for i, src in enumerate(src_paths): src = os.path.join(src_dir, src) with open(src, 'w') as f: f.write('content') # Set src file to read-only os.chmod(src, stat.S_IRUSR) utils.copy_file(src, dst_dir) self.assertTrue(os.path.isfile(os.path.join(dst_dir, expected[i]))) self.assertNotEqual(os.stat(src).st_mode, os.stat(os.path.join(dst_dir, expected[i])).st_mode) # While src was read-only, dst must remain writable self.assertTrue(os.access(os.path.join(dst_dir, expected[i]), os.W_OK)) finally: for src in src_paths: # Undo read-only so we can delete temp files src = os.path.join(src_dir, src) if os.path.exists(src): os.chmod(src, stat.S_IRUSR | stat.S_IWUSR) shutil.rmtree(src_dir) shutil.rmtree(dst_dir)
def on_post_build(self, config, **kwargs): "Build search index." output_base_path = os.path.join(config['site_dir'], 'search') search_index = self.search_index.generate_search_index() json_output_path = os.path.join(output_base_path, 'search_index.json') utils.write_file(search_index.encode('utf-8'), json_output_path) if not ('search_index_only' in config['theme'] and config['theme']['search_index_only']): # Include language support files in output. Copy them directly # so that only the needed files are included. files = [] if len(self.config['lang']) > 1 or 'en' not in self.config['lang']: files.append('lunr.stemmer.support.js') if len(self.config['lang']) > 1: files.append('lunr.multi.js') if ('ja' in self.config['lang'] or 'jp' in self.config['lang']): files.append('tinyseg.js') for lang in self.config['lang']: if (lang != 'en'): files.append('lunr.{}.js'.format(lang)) for filename in files: from_path = os.path.join(base_path, 'lunr-language', filename) to_path = os.path.join(output_base_path, filename) utils.copy_file(from_path, to_path)
def on_post_build(self, config, **kwargs): output_base_path = os.path.join(config['site_dir'], 'search') input_base_path = os.path.join(base_path, 'search') to_path = os.path.join(output_base_path, 'main.js') from_path = os.path.join(input_base_path, 'main.js') utils.copy_file(from_path, to_path)
def copy_file(self, dirty=False): """ Copy source file to destination, ensuring parent directories exist. """ if dirty and not self.is_modified(): log.debug("Skip copying unmodified file: '{}'".format(self.src_path)) else: log.debug("Copying media file: '{}'".format(self.src_path)) utils.copy_file(self.abs_src_path, self.abs_dest_path)
def test_copy_files(self): src_paths = [ 'foo.txt', 'bar.txt', 'baz.txt', ] dst_paths = [ 'foo.txt', 'foo/', # ensure src filename is appended 'foo/bar/baz.txt' # ensure missing dirs are created ] expected = [ 'foo.txt', 'foo/bar.txt', 'foo/bar/baz.txt', ] src_dir = tempfile.mkdtemp() dst_dir = tempfile.mkdtemp() try: for i, src in enumerate(src_paths): src = os.path.join(src_dir, src) with open(src, 'w') as f: f.write('content') dst = os.path.join(dst_dir, dst_paths[i]) utils.copy_file(src, dst) self.assertTrue(os.path.isfile(os.path.join(dst_dir, expected[i]))) finally: shutil.rmtree(src_dir) shutil.rmtree(dst_dir)
def on_post_build(self, config, **kwargs): "Build search index." output_base_path = os.path.join(config['site_dir'], 'search') if self.config['local_search_shim']: print( "INFO - local_search_shim Enabled! Make sure you've added shims/fetch_shim.js to your docs folder." ) # Change the search_index from being pure JSON to being JavaScript containing a global searchIndex variable with the JSON object we want # Also write it in the traditional format, so that either way works search_index = self.search_index.generate_search_index() search_index_shimmed = "shim_localSearchIndex = " + search_index json_output_path = os.path.join(output_base_path, 'search_index.json') json_output_path_shimmed = os.path.join(output_base_path, 'search_index.js') utils.write_file(search_index.encode('utf-8'), json_output_path) utils.write_file(search_index_shimmed.encode('utf-8'), json_output_path_shimmed) else: # Write the search index only in the traditional way print( "INFO - local_search_shim disabled. Generating only traditional JSON search index..." ) search_index = self.search_index.generate_search_index() json_output_path = os.path.join(output_base_path, 'search_index.json') utils.write_file(search_index.encode('utf-8'), json_output_path) if not ('search_index_only' in config['theme'] and config['theme']['search_index_only']): # Include language support files in output. Copy them directly # so that only the needed files are included. files = [] if len(self.config['lang']) > 1 or 'en' not in self.config['lang']: files.append('lunr.stemmer.support.js') if len(self.config['lang']) > 1: files.append('lunr.multi.js') for lang in self.config['lang']: if (lang != 'en'): files.append('lunr.{}.js'.format(lang)) for filename in files: from_path = os.path.join(base_path, 'lunr-language', filename) to_path = os.path.join(output_base_path, filename) utils.copy_file(from_path, to_path)
def on_post_build(self, config: Dict[str, Any], **kwargs) -> None: """ Run on post build. Adds the timeago assets to the build. """ # Add timeago files: if self.config.get("type") == "timeago" and self.config.get('enabled'): files = [ "js/timeago.min.js", "js/timeago_mkdocs_material.js", "css/timeago.css", ] for file in files: dest_file_path = os.path.join(config["site_dir"], file) src_file_path = os.path.join(HERE, file) assert os.path.exists(src_file_path) copy_file(src_file_path, dest_file_path)
def on_post_build(self, config): sources = set(self.sources) log.debug('Found {} unique sources in {} total embeds'.format( len(sources), len(self.sources))) self.sources = [] for source in sources: dest_rel_path = '{}-{}.{}'.format(source.source_rel, source.page_index, self.config['format']) abs_src_path = os.path.join(config['docs_dir'], source.source_rel) abs_dest_path = os.path.join(config['site_dir'], dest_rel_path) cache_filename = self.exporter.ensure_file_cached( abs_src_path, source.source_rel, source.page_index, self.config['drawio_executable'], self.config['cache_dir'], self.config['format']) try: copy_file(cache_filename, abs_dest_path) except FileNotFoundError: log.exception('Output file not created in cache')
def on_page_content(self, content, page, config, files): if not self.can_load(page.file.abs_src_path): return content exp = HTMLExporter() exp.template_file = self.template_file.name ipynb_path = page.file.abs_src_path nb = nbformat.read(ipynb_path, as_version=4) exporter_resources = { 'filename': os.path.split(page.file.abs_src_path)[1], } (body, resources) = exp.from_notebook_node(nb, resources=exporter_resources) # copy the notebook itself into the destination too nb_name = os.path.split(page.file.abs_src_path)[1] b = os.path.join(os.path.split(page.file.abs_dest_path)[0], nb_name) utils.copy_file(ipynb_path, b) return body
def on_post_build(self, config, **kwargs): "Build search index." output_base_path = os.path.join(config['site_dir'], 'search') search_index = self.search_index.generate_search_index() json_output_path = os.path.join(output_base_path, 'search_index.json') utils.write_file(search_index.encode('utf-8'), json_output_path) if not ('search_index_only' in config['theme'] and config['theme']['search_index_only']): # Include language support files in output. Copy them directly # so that only the needed files are included. files = [] if len(self.config['lang']) > 1 or 'en' not in self.config['lang']: files.append('lunr.stemmer.support.js') if len(self.config['lang']) > 1: files.append('lunr.multi.js') for lang in self.config['lang']: if (lang != 'en'): files.append('lunr.{}.js'.format(lang)) for filename in files: from_path = os.path.join(base_path, 'lunr-language', filename) to_path = os.path.join(output_base_path, filename) utils.copy_file(from_path, to_path)
def on_post_build(config, **kwargs): site_dir = config['site_dir'] # copy GitHub pages config utils.copy_file('CNAME', os.path.join(site_dir, 'CNAME')) # copy installation scripts utils.copy_file('../scripts/install.sh', os.path.join(site_dir, 'get')) utils.copy_file('../scripts/install.ps1', os.path.join(site_dir, 'get.ps1'))
def on_post_build(self, config): # Add print-site.js js_output_base_path = os.path.join(config["site_dir"], "js") js_file_path = os.path.join(js_output_base_path, "print-site.js") copy_file(os.path.join(os.path.join(HERE, "js"), "print-site.js"), js_file_path) # Add print-site.css css_output_base_path = os.path.join(config["site_dir"], "css") css_file_path = os.path.join(css_output_base_path, "print-site.css") copy_file(os.path.join(os.path.join(HERE, "css"), "print-site.css"), css_file_path) # Add theme CSS file css_file = "print-site-%s.css" % config.get("theme").name if css_file in os.listdir(os.path.join(HERE, "css")): css_file_path = os.path.join(css_output_base_path, css_file) copy_file(os.path.join(os.path.join(HERE, "css"), css_file), css_file_path) # Determine calls to required javascript functions js_calls = "" if config.get("theme").name == "material": js_calls += "change_material_theme('default');" if self.config.get("add_table_of_contents"): js_calls += "generate_toc();" # Add JS file for compatibility for mkdocs-material instant loading # note this is inserted to all mkdocs pages, # because each page can be the start of instant loading session js_instant_loading = (""" // Subscribe functions for compatibility // with mkdocs-material's instant loading feature body = document.getElementsByTagName('body')[0]; mkdocs_material_site_color_theme = body.getAttribute('data-md-color-scheme'); if ( typeof app !== "undefined" && typeof app.document$ !== "undefined" ) { app.document$.subscribe(function() { if ( document.querySelector("#print-site-page") !== null ) { %s } else { // Make sure to change the color theme back! if ( mkdocs_material_site_color_theme !== null ) { change_material_theme(mkdocs_material_site_color_theme); } } }) } """ % js_calls) write_file( js_instant_loading.encode("utf-8", errors="xmlcharrefreplace"), os.path.join(js_output_base_path, "print-site-instant-loading.js"), ) # Combine the HTML of all pages present in the navigation self.print_page.content = self.renderer.write_combined() # Get the info for MkDocs to be able to apply a theme template on our print page env = config["theme"].get_env() template = env.get_template("main.html") self.context["page"] = self.print_page # Render the theme template for the print page html = template.render(self.context) # Inject JS into print page print_site_js = (""" <script type="text/javascript"> window.addEventListener('load', function () { %s }) </script> """ % js_calls) html = html.replace("</body>", print_site_js + "</body>") # Write the print_page file to the output folder write_file( html.encode("utf-8", errors="xmlcharrefreplace"), self.print_page.file.abs_dest_path, )
def on_post_build(self, config, **kwargs): """ The post_build event does not alter any variables. Use this event to call post-build scripts. See https://www.mkdocs.org/user-guide/plugins/#on_post_build. """ if not self.config.get("enabled"): return if len(self.context) == 0: msg = "Could not find a template context.\n" msg += "Report an issue at https://github.com/timvink/mkdocs-print-site-plugin\n" msg += f"And mention the template you're using: {get_theme_name(config)}" raise PluginError(msg) # Add print-site.js js_output_base_path = os.path.join(config["site_dir"], "js") js_file_path = os.path.join(js_output_base_path, "print-site.js") copy_file(os.path.join(os.path.join(HERE, "js"), "print-site.js"), js_file_path) if self.config.get("include_css"): # Add print-site.css css_output_base_path = os.path.join(config["site_dir"], "css") css_file_path = os.path.join(css_output_base_path, "print-site.css") copy_file( os.path.join(os.path.join(HERE, "css"), "print-site.css"), css_file_path) # Add enumeration css for f in self.enum_css_files: f = f.replace("/", os.sep) css_file_path = os.path.join(config["site_dir"], f) copy_file(os.path.join(HERE, f), css_file_path) # Add theme CSS file css_file = "print-site-%s.css" % get_theme_name(config) if css_file in os.listdir(os.path.join(HERE, "css")): css_file_path = os.path.join(css_output_base_path, css_file) copy_file(os.path.join(os.path.join(HERE, "css"), css_file), css_file_path) # Combine the HTML of all pages present in the navigation self.print_page.content = self.renderer.write_combined() # Generate a TOC sidebar for HTML version of print page self.print_page.toc = self.renderer.get_toc_sidebar() # Get the info for MkDocs to be able to apply a theme template on our print page env = config["theme"].get_env() # env.list_templates() template = env.get_template("main.html") self.context["page"] = self.print_page # Render the theme template for the print page html = template.render(self.context) # Remove lazy loading attributes from images # https://regex101.com/r/HVpKPs/1 html = re.sub(r"(\<img.+)(loading=\"lazy\")", r"\1", html) # Compatiblity with mkdocs-chart-plugin # As this plugin adds some javascript to every page # It should be included in the print site also if config.get("plugins", {}).get("charts"): html = (config.get("plugins", {}).get("charts").add_javascript_variables( html, self.print_page, config)) # Compatibility with https://github.com/g-provost/lightgallery-markdown # This plugin insert link hrefs with double dashes, f.e. # <link href="//assets/css/somecss.css"> # Details https://github.com/timvink/mkdocs-print-site-plugin/issues/68 htmls = html.split("</head>") base_url = "../" if config.get("use_directory_urls") else "" htmls[0] = htmls[0].replace("href=\"//", f"href=\"{base_url}") htmls[0] = htmls[0].replace("src=\"//", f"src=\"{base_url}") html = "</head>".join(htmls) # Determine calls to required javascript functions js_calls = "remove_material_navigation();" js_calls += "remove_mkdocs_theme_navigation();" if self.config.get("add_table_of_contents"): js_calls += "generate_toc();" # Inject JS into print page print_site_js = (""" <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function () { %s }) </script> """ % js_calls) html = html.replace("</head>", print_site_js + "</head>") # Write the print_page file to the output folder write_file( html.encode("utf-8", errors="xmlcharrefreplace"), self.print_page.file.abs_dest_path, )
def on_post_build(self, config): """ The post_build event does not alter any variables. Use this event to call post-build scripts. See https://www.mkdocs.org/user-guide/plugins/#on_post_build. """ # Add print-site.js js_output_base_path = os.path.join(config["site_dir"], "js") js_file_path = os.path.join(js_output_base_path, "print-site.js") copy_file(os.path.join(os.path.join(HERE, "js"), "print-site.js"), js_file_path) # Add print-site.css css_output_base_path = os.path.join(config["site_dir"], "css") css_file_path = os.path.join(css_output_base_path, "print-site.css") copy_file(os.path.join(os.path.join(HERE, "css"), "print-site.css"), css_file_path) # Add theme CSS file css_file = "print-site-%s.css" % get_theme_name(config) if css_file in os.listdir(os.path.join(HERE, "css")): css_file_path = os.path.join(css_output_base_path, css_file) copy_file(os.path.join(os.path.join(HERE, "css"), css_file), css_file_path) # Determine calls to required javascript functions js_calls = "" if self.config.get("add_table_of_contents"): js_calls += "generate_toc();" # Add JS file for compatibility for mkdocs-material instant loading # note this is inserted to all mkdocs pages, # because each page can be the start of instant loading session js_instant_loading = (""" // Subscribe functions for compatibility // with mkdocs-material's instant loading feature if ( typeof app !== "undefined" && typeof app.document$ !== "undefined" ) { app.document$.subscribe(function() { if ( document.querySelector("#print-site-page") !== null ) { %s } }) } """ % js_calls) write_file( js_instant_loading.encode("utf-8", errors="xmlcharrefreplace"), os.path.join(js_output_base_path, "print-site-instant-loading.js"), ) # Combine the HTML of all pages present in the navigation self.print_page.content = self.renderer.write_combined() # Get the info for MkDocs to be able to apply a theme template on our print page env = config["theme"].get_env() template = env.get_template("main.html") self.context["page"] = self.print_page # Render the theme template for the print page html = template.render(self.context) # Inject JS into print page print_site_js = (""" <script type="text/javascript"> window.addEventListener('load', function () { %s }) </script> """ % js_calls) html = html.replace("</body>", print_site_js + "</body>") # Write the print_page file to the output folder write_file( html.encode("utf-8", errors="xmlcharrefreplace"), self.print_page.file.abs_dest_path, )