def path_to_url(url, nav): scheme, netloc, path, query, query, fragment = urlparse(url) if scheme or netloc or not path: # Ignore URLs unless they are a relative link to a markdown file. return url if nav and not utils.is_markdown_file(path): path = utils.create_media_urls(nav, [path])[0] elif nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = nav.file_context.make_absolute(path) if target_file not in nav.source_files: source_file = nav.file_context.current_file msg = ( 'The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.' ) assert False, msg % (source_file, target_file) path = utils.get_url_path(target_file, nav.use_directory_urls) path = nav.url_context.make_relative(path) else: path = utils.get_url_path(path).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. url = urlunparse((scheme, netloc, path, query, query, fragment)) return url
def __call__(self, match): url = match.groups()[0] scheme, netloc, path, query, query, fragment = urlparse(url) if (scheme or netloc or not utils.is_markdown_file(path)): # Ignore URLs unless they are a relative link to a markdown file. return 'a href="%s"' % url if self.nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = self.nav.file_context.make_absolute(path) if target_file not in self.nav.source_files: source_file = self.nav.file_context.current_file msg = ( 'The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.' ) assert False, msg % (source_file, target_file) path = utils.get_url_path(target_file) path = self.nav.url_context.make_relative(path) else: path = utils.get_url_path(path).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. url = urlunparse((scheme, netloc, path, query, query, fragment)) return 'a href="%s"' % url
def path_to_url(url, nav, strict): scheme, netloc, path, query, query, fragment = urlparse(url) if scheme or netloc or not path: # Ignore URLs unless they are a relative link to a markdown file. return url if nav and not utils.is_markdown_file(path): path = utils.create_relative_media_url(nav, path) elif nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = nav.file_context.make_absolute(path) if target_file not in nav.source_files: source_file = nav.file_context.current_file msg = ( 'The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.' ) % (source_file, target_file) # In strict mode raise an error at this point. if strict: raise MarkdownNotFound(msg) # Otherwise, when strict mode isn't enabled, print out a warning # to the user and leave the URL as it is. #print(msg) #return url path = utils.get_url_path(target_file, nav.use_directory_urls) path = nav.url_context.make_relative(path) else: path = utils.get_url_path(path).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. url = urlunparse((scheme, netloc, path, query, query, fragment)) return url
def __call__(self, match): url = match.groups()[0] scheme, netloc, path, query, query, fragment = urlparse.urlparse(url) if (scheme or netloc or not utils.is_markdown_file(path)): # Ignore URLs unless they are a relative link to a markdown file. return 'a href="%s"' % url if self.nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = self.nav.file_context.make_absolute(path) if target_file not in self.nav.source_files: source_file = self.nav.file_context.current_file msg = ( 'The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.' ) assert False, msg % (source_file, target_file) path = utils.get_url_path(target_file, self.url_format) path = self.nav.url_context.make_relative(path) else: path = utils.get_url_path(path, self.url_format).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. url = urlparse.urlunparse((scheme, netloc, path, query, query, fragment)) return 'a href="%s"' % url
def path_to_url(url, nav): scheme, netloc, path, query, query, fragment = urlparse(url) if scheme or netloc or not path: # Ignore URLs unless they are a relative link to a markdown file. return url if nav and not utils.is_markdown_file(path): path = utils.create_media_urls(nav, [path])[0] elif nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = nav.file_context.make_absolute(path) if target_file not in nav.source_files: source_file = nav.file_context.current_file msg = ('The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.') assert False, msg % (source_file, target_file) path = utils.get_url_path(target_file, nav.use_directory_urls) path = nav.url_context.make_relative(path) else: path = utils.get_url_path(path).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. url = urlunparse((scheme, netloc, path, query, query, fragment)) return url
def test_is_markdown_file(self): expected_results = { 'index.md': True, 'index.MARKDOWN': True, 'index.txt': False, 'indexmd': False } for path, expected_result in expected_results.items(): is_markdown = utils.is_markdown_file(path) self.assertEqual(is_markdown, expected_result)
def on_files(self, files, config, **kwargs): self.redirects = self.config.get('redirect_maps', {}) # SHIM! Produce a warning if the old root-level 'redirects' config is present if config.get('redirects'): log.warn("The root-level 'redirects:' setting is not valid and has been changed in version 1.0! " "The plugin-level 'redirect-map' must be used instead. See https://git.io/fjdBN") # Validate user-provided redirect "old files" for page_old in self.redirects.keys(): if not utils.is_markdown_file(page_old): log.warn("redirects plugin: '%s' is not a valid markdown file!", page_old) # Build a dict of known document pages to validate against later self.doc_pages = {} for page in files.documentation_pages(): # object type: mkdocs.structure.files.File self.doc_pages[page.src_path.replace('\\', '/')] = page
def path_to_url(url, nav, strict): scheme, netloc, path, params, query, fragment = (utils.urlparse(url)) if scheme or netloc or not path or AMP_SUBSTITUTE in url: # Ignore URLs unless they are a relative link to a markdown file. # AMP_SUBSTITUTE is used internally by Markdown only for email,which is # not a relative link. As urlparse errors on them, skip explicitly return url if nav and not utils.is_markdown_file(path): path = utils.create_relative_media_url(nav, path) elif nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = nav.file_context.make_absolute(path) if target_file.startswith(os.path.sep): target_file = target_file[1:] if target_file not in nav.source_files: source_file = nav.file_context.current_file msg = ('The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.') % ( source_file, target_file) # In strict mode raise an error at this point. if strict: raise MarkdownNotFound(msg) # Otherwise, when strict mode isn't enabled, log a warning # to the user and leave the URL as it is. # suppress the Warning # log.warning(msg) # return url path = utils.get_url_path(target_file, nav.use_directory_urls) path = nav.url_context.make_relative(path) else: path = utils.get_url_path(path).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. fragments = (scheme, netloc, path, params, query, fragment) url = utils.urlunparse(fragments) return url
def path_to_url(url, nav, strict): scheme, netloc, path, params, query, fragment = ( utils.urlparse(url)) if scheme or netloc or not path or AMP_SUBSTITUTE in url: # Ignore URLs unless they are a relative link to a markdown file. # AMP_SUBSTITUTE is used internally by Markdown only for email,which is # not a relative link. As urlparse errors on them, skip explicitly return url if nav and not utils.is_markdown_file(path): path = utils.create_relative_media_url(nav, path) elif nav: # If the site navigation has been provided, then validate # the internal hyperlink, making sure the target actually exists. target_file = nav.file_context.make_absolute(path) if target_file.startswith(os.path.sep): target_file = target_file[1:] if target_file not in nav.source_files: source_file = nav.file_context.current_file msg = ( 'The page "%s" contained a hyperlink to "%s" which ' 'is not listed in the "pages" configuration.' ) % (source_file, target_file) # In strict mode raise an error at this point. if strict: raise MarkdownNotFound(msg) # Otherwise, when strict mode isn't enabled, log a warning # to the user and leave the URL as it is. log.warning(msg) return url path = utils.get_url_path(target_file, nav.use_directory_urls) path = nav.url_context.make_relative(path) else: path = utils.get_url_path(path).lstrip('/') # Convert the .md hyperlink to a relative hyperlink to the HTML page. fragments = (scheme, netloc, path, params, query, fragment) url = utils.urlunparse(fragments) return url
def validate_config(user_config): config = DEFAULT_CONFIG.copy() config.update(user_config) assert config['site_name'], "Config must contain 'site_name' setting." if not config['pages']: # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] for (dirpath, dirnames, filenames) in os.walk(config['docs_dir']): for filename in sorted(filenames): if not utils.is_markdown_file(filename): continue fullpath = os.path.join(dirpath, filename) relpath = os.path.relpath(fullpath, config['docs_dir']) # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == 'index': pages.insert(0, relpath) else: pages.append(relpath) config['pages'] = pages if not config['theme_dir']: package_dir = os.path.dirname(__file__) config['theme_dir'] = os.path.join(package_dir, 'themes', config['theme']) if config['repo_url'] and not config['repo_name']: repo_host = urlparse.urlparse(config['repo_url']).netloc.lower() if repo_host == 'github.com': config['repo_name'] = 'GitHub' elif repo_host == 'bitbucket.com': config['repo_name'] = 'Bitbucket' else: config['repo_name'] = repo_host.split('.')[0].title() return config
def validate_config(user_config): config = DEFAULT_CONFIG.copy() theme_in_config = 'theme' in user_config config.update(user_config) if not config['site_name']: raise ConfigurationError("Config must contain 'site_name' setting.") # Validate that the docs_dir and site_dir don't contain the # other as this will lead to copying back and forth on each # and eventually make a deep nested mess. abs_site_dir = os.path.abspath(config['site_dir']) abs_docs_dir = os.path.abspath(config['docs_dir']) if abs_docs_dir.startswith(abs_site_dir): raise ConfigurationError( "The 'docs_dir' can't be within the 'site_dir'.") elif abs_site_dir.startswith(abs_docs_dir): raise ConfigurationError( "The 'site_dir' can't be within the 'docs_dir'.") # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] extra_css = [] extra_javascript = [] for (dirpath, _, filenames) in os.walk(config['docs_dir']): for filename in sorted(filenames): fullpath = os.path.join(dirpath, filename) relpath = os.path.normpath( os.path.relpath(fullpath, config['docs_dir'])) if utils.is_markdown_file(filename): # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == 'index': pages.insert(0, relpath) else: pages.append(relpath) elif utils.is_css_file(filename): extra_css.append(relpath) elif utils.is_javascript_file(filename): extra_javascript.append(relpath) if config['pages'] is None: config['pages'] = pages else: """ If the user has provided the pages config, then iterate through and check for Windows style paths. If they are found, output a warning and continue. """ for page_config in config['pages']: if isinstance(page_config, str): path = page_config elif len(page_config) in (1, 2, 3): path = page_config[0] if ntpath.sep in path: log.warning("The config path contains Windows style paths (\\ " " backward slash) and will have comparability " "issues if it is used on another platform.") break if config['extra_css'] is None: config['extra_css'] = extra_css if config['extra_javascript'] is None: config['extra_javascript'] = extra_javascript package_dir = os.path.dirname(__file__) theme_dir = [ os.path.join(package_dir, 'themes', config['theme']), ] if config['theme_dir'] is not None: # If the user has given us a custom theme but not a # builtin theme name then we don't want to merge them. if not theme_in_config: theme_dir = [] theme_dir.insert(0, config['theme_dir']) config['theme_dir'] = theme_dir # Add the search assets to the theme_dir, this means that # they will then we copied into the output directory but can # be overwritten by themes if needed. config['theme_dir'].append(os.path.join(package_dir, 'assets', 'search')) if config['repo_url'] is not None and config['repo_name'] is None: repo_host = urlparse(config['repo_url']).netloc.lower() if repo_host == 'github.com': config['repo_name'] = 'GitHub' elif repo_host == 'bitbucket.org': config['repo_name'] = 'Bitbucket' else: config['repo_name'] = repo_host.split('.')[0].title() if config['include_next_prev'] is None: config['include_next_prev'] = len(config['pages']) > 1 if config['include_nav'] is None: config['include_nav'] = len(config['pages']) > 1 # To Do: # The docs dir must exist. # The theme dir must exist. # Ensure 'theme' is one of 'mkdocs', 'readthedocs', 'custom' # A homepage 'index' must exist. # The theme 'base.html' file must exist. # Cannot set repo_name without setting repo_url. # Cannot set 'include_next_prev: true' when only one page exists. # Cannot set 'include_nav: true' when only one page exists. # Error if any config keys provided that are not in the DEFAULT_CONFIG. return config
def validate_config(user_config): config = DEFAULT_CONFIG.copy() theme_in_config = 'theme' in user_config config.update(user_config) if not config['site_name']: raise ConfigurationError("Config must contain 'site_name' setting.") # Validate that the docs_dir and site_dir don't contain the # other as this will lead to copying back and forth on each # and eventually make a deep nested mess. abs_site_dir = os.path.abspath(config['site_dir']) abs_docs_dir = os.path.abspath(config['docs_dir']) if abs_docs_dir.startswith(abs_site_dir): raise ConfigurationError( "The 'docs_dir' can't be within the 'site_dir'.") elif abs_site_dir.startswith(abs_docs_dir): raise ConfigurationError( "The 'site_dir' can't be within the 'docs_dir'.") # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] extra_css = [] extra_javascript = [] extra_templates = [] for (dirpath, _, filenames) in os.walk(config['docs_dir']): for filename in sorted(filenames): fullpath = os.path.join(dirpath, filename) relpath = os.path.normpath(os.path.relpath(fullpath, config['docs_dir'])) if utils.is_markdown_file(filename): # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == 'index': pages.insert(0, relpath) else: pages.append(relpath) elif utils.is_css_file(filename): extra_css.append(relpath) elif utils.is_javascript_file(filename): extra_javascript.append(relpath) elif utils.is_template_file(filename): extra_templates.append(filename) if config['pages'] is None: config['pages'] = pages else: """ If the user has provided the pages config, then iterate through and check for Windows style paths. If they are found, output a warning and continue. """ for page_config in config['pages']: if isinstance(page_config, str): path = page_config elif len(page_config) in (1, 2, 3): path = page_config[0] if ntpath.sep in path: log.warning("The config path contains Windows style paths (\\ " " backward slash) and will have comparability " "issues if it is used on another platform.") break if config['extra_css'] is None: config['extra_css'] = extra_css if config['extra_javascript'] is None: config['extra_javascript'] = extra_javascript if config['extra_templates'] is None: config['extra_templates'] = extra_templates package_dir = os.path.dirname(__file__) theme_dir = [os.path.join(package_dir, 'themes', config['theme']), ] config['mkdocs_templates'] = os.path.join(package_dir, 'templates') if config['theme_dir'] is not None: # If the user has given us a custom theme but not a # builtin theme name then we don't want to merge them. if not theme_in_config: theme_dir = [] theme_dir.insert(0, config['theme_dir']) config['theme_dir'] = theme_dir # Add the search assets to the theme_dir, this means that # they will then we copied into the output directory but can # be overwritten by themes if needed. config['theme_dir'].append(os.path.join(package_dir, 'assets', 'search')) if config['repo_url'] is not None and config['repo_name'] is None: repo_host = urlparse(config['repo_url']).netloc.lower() if repo_host == 'github.com': config['repo_name'] = 'GitHub' elif repo_host == 'bitbucket.org': config['repo_name'] = 'Bitbucket' else: config['repo_name'] = repo_host.split('.')[0].title() if config['include_next_prev'] is None: config['include_next_prev'] = len(config['pages']) > 1 if config['include_nav'] is None: config['include_nav'] = len(config['pages']) > 1 # To Do: # The docs dir must exist. # The theme dir must exist. # Ensure 'theme' is one of 'mkdocs', 'readthedocs', 'custom' # A homepage 'index' must exist. # The theme 'base.html' file must exist. # Cannot set repo_name without setting repo_url. # Cannot set 'include_next_prev: true' when only one page exists. # Cannot set 'include_nav: true' when only one page exists. # Error if any config keys provided that are not in the DEFAULT_CONFIG. return config
def validate_config(user_config): config = DEFAULT_CONFIG.copy() theme_in_config = 'theme' in user_config config.update(user_config) if not config['site_name']: raise ConfigurationError("Config must contain 'site_name' setting.") # Validate that the docs_dir and site_dir don't contain the # other as this will lead to copying back and forth on each # and eventually make a deep nested mess. abs_site_dir = os.path.abspath(config['site_dir']) abs_docs_dir = os.path.abspath(config['docs_dir']) if abs_docs_dir.startswith(abs_site_dir): raise ConfigurationError( "The 'docs_dir' can't be within the 'site_dir'.") elif abs_site_dir.startswith(abs_docs_dir): raise ConfigurationError( "The 'site_dir' can't be within the 'docs_dir'.") # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] extra_css = [] extra_javascript = [] for (dirpath, dirnames, filenames) in os.walk(config['docs_dir']): for filename in sorted(filenames): fullpath = os.path.join(dirpath, filename) relpath = os.path.relpath(fullpath, config['docs_dir']) if utils.is_markdown_file(filename): # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == 'index': pages.insert(0, relpath) else: pages.append(relpath) elif utils.is_css_file(filename): extra_css.append(relpath) elif utils.is_javascript_file(filename): extra_javascript.append(relpath) if config['pages'] is None: config['pages'] = pages if config['extra_css'] is None: config['extra_css'] = extra_css if config['extra_javascript'] is None: config['extra_javascript'] = extra_javascript package_dir = os.path.dirname(__file__) theme_dir = [os.path.join(package_dir, 'themes', config['theme'])] if config['theme_dir'] is not None: # If the user has given us a custom theme but not a # builtin theme name then we don't want to merge them. if not theme_in_config: theme_dir = [] theme_dir.insert(0, config['theme_dir']) config['theme_dir'] = theme_dir if config['repo_url'] is not None and config['repo_name'] is None: repo_host = urlparse(config['repo_url']).netloc.lower() if repo_host == 'github.com': config['repo_name'] = 'GitHub' elif repo_host == 'bitbucket.org': config['repo_name'] = 'Bitbucket' else: config['repo_name'] = repo_host.split('.')[0].title() if config['include_next_prev'] is None: config['include_next_prev'] = len(config['pages']) > 1 if config['include_nav'] is None: config['include_nav'] = len(config['pages']) > 1 # To Do: # The docs dir must exist. # The theme dir must exist. # Ensure 'theme' is one of 'mkdocs', 'readthedocs', 'custom' # A homepage 'index' must exist. # The theme 'base.html' file must exist. # Cannot set repo_name without setting repo_url. # Cannot set 'include_next_prev: true' when only one page exists. # Cannot set 'include_nav: true' when only one page exists. # Error if any config keys provided that are not in the DEFAULT_CONFIG. return config
def validate_config(user_config): config = DEFAULT_CONFIG.copy() config.update(user_config) assert config['site_name'], "Config must contain 'site_name' setting." # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] extra_css = [] extra_javascript = [] for (dirpath, dirnames, filenames) in os.walk(config['docs_dir']): for filename in sorted(filenames): fullpath = os.path.join(dirpath, filename) relpath = os.path.relpath(fullpath, config['docs_dir']) if utils.is_markdown_file(filename): # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == 'index': pages.insert(0, relpath) else: pages.append(relpath) elif utils.is_css_file(filename): extra_css.append(relpath) elif utils.is_javascript_file(filename): extra_javascript.append(relpath) if config['pages'] is None: config['pages'] = pages if config['extra_css'] is None: config['extra_css'] = extra_css if config['extra_javascript'] is None: config['extra_javascript'] = extra_javascript if config['theme_dir'] is None: package_dir = os.path.dirname(__file__) config['theme_dir'] = os.path.join(package_dir, 'themes', config['theme']) if config['repo_url'] is not None and config['repo_name'] is None: repo_host = urlparse(config['repo_url']).netloc.lower() if repo_host == 'github.com': config['repo_name'] = 'GitHub' elif repo_host == 'bitbucket.com': config['repo_name'] = 'Bitbucket' else: config['repo_name'] = repo_host.split('.')[0].title() if config['include_next_prev'] is None: config['include_next_prev'] = len(config['pages']) > 1 if config['include_nav'] is None: config['include_nav'] = len(config['pages']) > 1 # To Do: # The docs dir must exist. # The theme dir must exist. # Ensure 'theme' is one of 'mkdocs', 'readthedocs', 'custom' # A homepage 'index' must exist. # The theme 'base.html' file must exist. # Cannot set repo_name without setting repo_url. # Cannot set 'include_next_prev: true' when only one page exists. # Cannot set 'include_nav: true' when only one page exists. # Error if any config keys provided that are not in the DEFAULT_CONFIG. return config
def validate_config(user_config): config = DEFAULT_CONFIG.copy() config.update(user_config) if not config['site_name']: sys.stderr.write("Config must contain 'site_name' setting.") sys.exit(errno.EINVAL) # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] extra_css = [] extra_javascript = [] for (dirpath, dirnames, filenames) in os.walk(config['docs_dir']): for filename in sorted(filenames): fullpath = os.path.join(dirpath, filename) relpath = os.path.relpath(fullpath, config['docs_dir']) if utils.is_markdown_file(filename): # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == 'index': pages.insert(0, relpath) else: pages.append(relpath) elif utils.is_css_file(filename): extra_css.append(relpath) elif utils.is_javascript_file(filename): extra_javascript.append(relpath) if config['pages'] is None: config['pages'] = pages if config['extra_css'] is None: config['extra_css'] = extra_css if config['extra_javascript'] is None: config['extra_javascript'] = extra_javascript package_dir = os.path.dirname(__file__) theme_dir = [os.path.join(package_dir, 'themes', config['theme'])] if config['theme_dir'] is not None: theme_dir.insert(0, config['theme_dir']) config['theme_dir'] = theme_dir if config['repo_url'] is not None and config['repo_name'] is None: repo_host = urlparse(config['repo_url']).netloc.lower() if repo_host == 'github.com': config['repo_name'] = 'GitHub' elif repo_host == 'bitbucket.com': config['repo_name'] = 'Bitbucket' else: config['repo_name'] = repo_host.split('.')[0].title() if config['include_next_prev'] is None: config['include_next_prev'] = len(config['pages']) > 1 if config['include_nav'] is None: config['include_nav'] = len(config['pages']) > 1 # To Do: # The docs dir must exist. # The theme dir must exist. # Ensure 'theme' is one of 'mkdocs', 'readthedocs', 'custom' # A homepage 'index' must exist. # The theme 'base.html' file must exist. # Cannot set repo_name without setting repo_url. # Cannot set 'include_next_prev: true' when only one page exists. # Cannot set 'include_nav: true' when only one page exists. # Error if any config keys provided that are not in the DEFAULT_CONFIG. return config
def build_pages(config, dump_json=False): """ Builds all the pages and writes them into the build directory. """ site_navigation = nav.SiteNavigation(config['pages'], config['use_directory_urls']) loader = jinja2.FileSystemLoader(config['theme_dir']) env = jinja2.Environment(loader=loader) search_index = search.SearchIndex() build_template('404.html', env, config, site_navigation) build_template('search.html', env, config, site_navigation) nav_pages = [] for page in site_navigation.walk_pages(): nav_pages.append(page.input_path) # Read the input file input_path = os.path.join(config['docs_dir'], page.input_path) input_content = open(input_path, 'r').read() if PY2: input_content = input_content.decode('utf-8') # Process the markdown text html_content, table_of_contents, meta = convert_markdown( input_content, site_navigation, extensions=config['markdown_extensions'], strict=config['strict'] ) context = get_global_context(site_navigation, config) context.update(get_page_context( page, html_content, site_navigation, table_of_contents, meta, config )) # Allow 'template:' override in md source files. if 'template' in meta: template = env.get_template(meta['template'][0]) else: template = env.get_template('base.html') if not utils.is_markdown_file(page.input_path): template = env.get_template('base_without_toc.html') # Render the template. output_content = template.render(context) # Write the output file. output_path = os.path.join(config['site_dir'], page.output_path) if dump_json: json_context = { 'content': context['content'], 'title': context['current_page'].title, 'url': context['current_page'].abs_url, 'language': 'en', } utils.write_file(json.dumps(json_context, indent=4).encode('utf-8'), output_path.replace('.html', '.json')) else: utils.write_file(output_content.encode('utf-8'), output_path) search_index.add_entry_from_context(page, html_content, table_of_contents) # generate html for other md files files = ListFilesByTxt(os.path.join(config['docs_dir']),'.md') for mdf in files: title = os.path.basename(mdf) title = os.path.splitext(title)[0] path = os.path.relpath(mdf,config['docs_dir']) url = utils.get_url_path(path,config['use_directory_urls']) output_path = utils.get_html_path(path) if(path in nav_pages):continue input_content = open(mdf, 'r').read() if PY2: input_content = input_content.decode('utf-8') site_navigation.url_context.set_current_url(url) # Process the markdown text html_content, table_of_contents, meta = convert_markdown( input_content, site_navigation, extensions=config['markdown_extensions'] ) context = get_global_context(site_navigation, config) page = nav.Page(title=title, url=url,path=path,url_context=site_navigation.url_context) context.update(get_page_context( page, html_content, site_navigation, table_of_contents, meta, config )) if 'template' in meta: template = env.get_template(meta['template'][0]) else: template = env.get_template('base.html') if not utils.is_markdown_file(mdf): template = env.get_template('base_without_toc.html') # Render the template. output_content = template.render(context) # Write the output file. output_path = os.path.join(config['site_dir'], output_path) utils.write_file(output_content.encode('utf-8'), output_path) #search_index.add_entry_from_context(page, html_content, table_of_contents) build_template('js/tipuesearch/tipuesearch_content.js', env, config, extra_context={ 'search_index': search_index.generate_search_index() })
def build_pages(config, dump_json=False): """ Builds all the pages and writes them into the build directory. """ site_navigation = nav.SiteNavigation(config['pages'], config['use_directory_urls']) loader = jinja2.FileSystemLoader(config['theme_dir']) env = jinja2.Environment(loader=loader) search_index = search.SearchIndex() build_template('404.html', env, config, site_navigation) build_template('search.html', env, config, site_navigation) nav_pages = [] for page in site_navigation.walk_pages(): nav_pages.append(page.input_path) # Read the input file input_path = os.path.join(config['docs_dir'], page.input_path) input_content = open(input_path, 'r').read() if PY2: input_content = input_content.decode('utf-8') # Process the markdown text html_content, table_of_contents, meta = convert_markdown( input_content, site_navigation, extensions=config['markdown_extensions'], strict=config['strict']) context = get_global_context(site_navigation, config) context.update( get_page_context(page, html_content, site_navigation, table_of_contents, meta, config)) # Allow 'template:' override in md source files. if 'template' in meta: template = env.get_template(meta['template'][0]) else: template = env.get_template('base.html') if not utils.is_markdown_file(page.input_path): template = env.get_template('base_without_toc.html') # Render the template. output_content = template.render(context) # Write the output file. output_path = os.path.join(config['site_dir'], page.output_path) if dump_json: json_context = { 'content': context['content'], 'title': context['current_page'].title, 'url': context['current_page'].abs_url, 'language': 'en', } utils.write_file( json.dumps(json_context, indent=4).encode('utf-8'), output_path.replace('.html', '.json')) else: utils.write_file(output_content.encode('utf-8'), output_path) search_index.add_entry_from_context(page, html_content, table_of_contents) # generate html for other md files files = ListFilesByTxt(os.path.join(config['docs_dir']), '.md') for mdf in files: title = os.path.basename(mdf) title = os.path.splitext(title)[0] path = os.path.relpath(mdf, config['docs_dir']) url = utils.get_url_path(path, config['use_directory_urls']) output_path = utils.get_html_path(path) if (path in nav_pages): continue input_content = open(mdf, 'r').read() if PY2: input_content = input_content.decode('utf-8') site_navigation.url_context.set_current_url(url) # Process the markdown text html_content, table_of_contents, meta = convert_markdown( input_content, site_navigation, extensions=config['markdown_extensions']) context = get_global_context(site_navigation, config) page = nav.Page(title=title, url=url, path=path, url_context=site_navigation.url_context) context.update( get_page_context(page, html_content, site_navigation, table_of_contents, meta, config)) if 'template' in meta: template = env.get_template(meta['template'][0]) else: template = env.get_template('base.html') if not utils.is_markdown_file(mdf): template = env.get_template('base_without_toc.html') # Render the template. output_content = template.render(context) # Write the output file. output_path = os.path.join(config['site_dir'], output_path) utils.write_file(output_content.encode('utf-8'), output_path) #search_index.add_entry_from_context(page, html_content, table_of_contents) build_template( 'js/tipuesearch/tipuesearch_content.js', env, config, extra_context={'search_index': search_index.generate_search_index()})
def documentation_in_temp_folder(config: dict) -> Iterator[Tuple[str, str]]: """Build documentation within a temp folder, returning that folder name before it is deleted.""" if config["append_directory_to_python_path"] and not config[ "directory"] in sys.path: sys.path.append(config["directory"]) with tempfile.TemporaryDirectory() as input_dir: input_dir = os.path.join(input_dir, "input") os.mkdir(input_dir) with tempfile.TemporaryDirectory() as temp_output_dir: with yaspin( text= "Copying source documentation to temporary compilation directory" ) as spinner: for root_file in os.listdir(config["directory"]): root_file_absolute = os.path.join(config["directory"], root_file) if os.path.isfile(root_file_absolute) and is_markdown_file( root_file_absolute): shutil.copyfile(root_file_absolute, os.path.join(input_dir, root_file)) for source_directory in [config["docs_dir"] ] + config["extra_dirs"]: directory_absolute = os.path.join(config["directory"], source_directory) if os.path.isdir(directory_absolute): shutil.copytree( directory_absolute, os.path.join(input_dir, source_directory)) spinner.ok("Done") if "docs_dir" not in config["mkdocs"]: config["mkdocs"]["docs_dir"] = input_dir if "site_dir" not in config["mkdocs"]: config["mkdocs"]["site_dir"] = temp_output_dir if "nav" not in config["mkdocs"]: nav = config["mkdocs"]["nav"] = [] root_docs = sorted(glob(os.path.join(input_dir, "*.md"))) readme_doc = os.path.join(input_dir, "README.md") if readme_doc in root_docs: root_docs.remove(readme_doc) else: with open(readme_doc, "w") as readme_doc_file: readme_doc_file.write(NO_HOME_PAGE) nav.append({"Home": "README.md"}) nav.extend(_doc(doc, input_dir, config) for doc in root_docs) nav.extend( _nested_docs(os.path.join(input_dir, config["docs_dir"]), input_dir, config)) else: nav = config["mkdocs"]["nav"] if nav: index_nav = nav[0] index_page: str = "" if index_nav and isinstance(index_nav, dict): index_page = tuple(index_nav.values())[0] elif isinstance(index_nav, str): # pragma: no cover index_page = index_nav if index_page: destination_index_page = os.path.join( input_dir, "index.md") if (index_page != "README.md" and index_page != "index.md" and not os.path.exists(destination_index_page)): shutil.copyfile( os.path.join(input_dir, index_page), destination_index_page) if config["include_reference_documentation"]: with yaspin( text= "Auto generating reference documentation using pdocs" ) as spinner: if "output_dir" not in config["pdocs"]: config["pdocs"]["output_dir"] = os.path.join( input_dir, "reference") pdocs(config["pdocs"]) reference_docs = _nested_docs( config["pdocs"]["output_dir"], input_dir, config) nav.append({"Reference": reference_docs}) # type: ignore spinner.ok("Done") with yaspin( text="Rendering complete website from Markdown using MkDocs" ) as spinner: mkdocs(config["mkdocs"]) spinner.ok("Done") # remove any settings pointing to the temp dirs if config["mkdocs"]["docs_dir"].startswith(input_dir): del config["mkdocs"]["docs_dir"] if config["mkdocs"]["site_dir"].startswith(temp_output_dir): del config["mkdocs"]["site_dir"] if config["pdocs"]["output_dir"].startswith(input_dir): del config["pdocs"]["output_dir"] if config["include_reference_documentation"]: nav.pop() yield input_dir, temp_output_dir
def is_source_code_link(self, path): return not is_markdown_file(path) and not is_image_file(path) and path.startswith(self.config['repos_prefix'])
def validate_config(user_config): config = DEFAULT_CONFIG.copy() config.update(user_config) assert config["site_name"], "Config must contain 'site_name' setting." # If not specified, then the 'pages' config simply includes all # markdown files in the docs dir, without generating any header items # for them. pages = [] extra_css = [] extra_javascript = [] for (dirpath, dirnames, filenames) in os.walk(config["docs_dir"]): for filename in sorted(filenames): fullpath = os.path.join(dirpath, filename) relpath = os.path.relpath(fullpath, config["docs_dir"]) if utils.is_markdown_file(filename): # index pages should always be the first listed page. if os.path.splitext(relpath)[0] == "index": pages.insert(0, relpath) else: pages.append(relpath) elif utils.is_css_file(filename): extra_css.append(relpath) elif utils.is_javascript_file(filename): extra_javascript.append(relpath) if config["pages"] is None: config["pages"] = pages if config["extra_css"] is None: config["extra_css"] = extra_css if config["extra_javascript"] is None: config["extra_javascript"] = extra_javascript if config["theme_dir"] is None: package_dir = os.path.dirname(__file__) config["theme_dir"] = os.path.join(package_dir, "themes", config["theme"]) if config["repo_url"] is not None and config["repo_name"] is None: repo_host = urlparse(config["repo_url"]).netloc.lower() if repo_host == "github.com": config["repo_name"] = "GitHub" elif repo_host == "bitbucket.com": config["repo_name"] = "Bitbucket" else: config["repo_name"] = repo_host.split(".")[0].title() if config["include_next_prev"] is None: config["include_next_prev"] = len(config["pages"]) > 1 if config["include_nav"] is None: config["include_nav"] = len(config["pages"]) > 1 # To Do: # The docs dir must exist. # The theme dir must exist. # Ensure 'theme' is one of 'mkdocs', 'readthedocs', 'custom' # A homepage 'index' must exist. # The theme 'base.html' file must exist. # Cannot set repo_name without setting repo_url. # Cannot set 'include_next_prev: true' when only one page exists. # Cannot set 'include_nav: true' when only one page exists. # Error if any config keys provided that are not in the DEFAULT_CONFIG. return config