def get_post(self, rel_url, include_draft=False): """ Get post for given relative url from filesystem. Possible input: - 2017/01/01/my-post/ - 2017/01/01/my-post/index.html :param rel_url: relative url :param include_draft: return draft post or not :return: a Post object """ raw_rel_url = str(rel_url) if rel_url.endswith('/index.html'): rel_url = rel_url.rsplit( '/', 1)[0] + '/' # remove the trailing 'index.html' post_filename = rel_url[:-1].replace('/', '-') post_file_path, post_file_ext = FileStorage.search_instance_file( 'posts', post_filename) if post_file_path is None or post_file_ext is None or \ get_standard_format_name(post_file_ext) is None: # no such post return None # construct the post object post = Post() post.rel_url = raw_rel_url # 'rel_url' contains no trailing 'index.html' post.unique_key = '/post/' + rel_url post.format = get_standard_format_name(post_file_ext) post.meta, post.raw_content = FileStorage.read_file(post_file_path) return post if include_draft or not post.is_draft else None
def test_parser_decorator(): class FakeParser: pass parser('FoRMat1')(FakeParser) assert get_standard_format_name('formAT1') == 'format1' parser('format2', ext_names='fmt2')(FakeParser) assert get_standard_format_name('fmt2') == 'format2' parser('format3', ext_names=['fmt3', 'f3'])(FakeParser) assert get_standard_format_name('fmt3') == 'format3' assert get_standard_format_name('f3') == 'format3'
def generate_pages_by_file(): """Generates custom pages of 'file' storage type.""" from veripress import app from veripress.model import storage from veripress.model.parsers import get_standard_format_name from veripress.helpers import traverse_directory deploy_dir = get_deploy_dir() def copy_file(src, dst): makedirs(os.path.dirname(dst), mode=0o755, exist_ok=True) shutil.copyfile(src, dst) with app.app_context(), app.test_client() as client: root_path = os.path.join(app.instance_path, 'pages') for path in traverse_directory(root_path): rel_path = os.path.relpath(path, root_path) # e.g. 'a/b/c/index.md' filename, ext = os.path.splitext(rel_path) # e.g. ('a/b/c/index', '.md') if get_standard_format_name(ext[1:]) is not None: # is source of custom page rel_url = filename.replace(os.path.sep, '/') + '.html' # e.g. 'a/b/c/index.html' page = storage.get_page(rel_url, include_draft=False) if page is not None: # it's not a draft, so generate the html page makedirs(os.path.join(deploy_dir, os.path.dirname(rel_path)), mode=0o755, exist_ok=True) with open(os.path.join(deploy_dir, filename + '.html'), 'wb') as f: f.write(client.get('/' + rel_url).data) if app.config['PAGE_SOURCE_ACCESSIBLE']: copy_file(path, os.path.join(deploy_dir, rel_path)) else: # is other direct files copy_file(path, os.path.join(deploy_dir, rel_path))
def get_page(self, rel_url, include_draft=False): """ Get custom page for given relative url from filesystem. Possible input: - my-page/ - my-page/index.html - my-another-page.html - a/b/c/ - a/b/c/d.html :param rel_url: relative url :param include_draft: return draft page or not :return: a Page object """ page_dir = os.path.dirname(rel_url.replace('/', os.path.sep)) page_path = os.path.join(current_app.instance_path, 'pages', page_dir) if not os.path.isdir(page_path): # no such directory return None page_filename = rel_url[len(page_dir):].lstrip('/') if not page_filename: page_filename = 'index' else: page_filename = os.path.splitext(page_filename)[0] page_file_path, page_file_ext = FileStorage.search_file( page_path, page_filename) if page_file_path is None or page_file_ext is None or \ get_standard_format_name(page_file_ext) is None: # no such page return None page = Page() page.rel_url = rel_url page.unique_key = '/' + (rel_url.rsplit('/', 1)[0] + '/' if rel_url.endswith('/index.html') else rel_url) page.format = get_standard_format_name(page_file_ext) page.meta, page.raw_content = FileStorage.read_file(page_file_path) return page if include_draft or not page.is_draft else None
def widgets_generator(path): """Loads valid widgets one by one in the given path.""" if os.path.isdir(path): for file in os.listdir(path): _, ext = os.path.splitext(file) format_name = get_standard_format_name(ext[1:]) if format_name is not None: # the format is supported, so load it widget = Widget() widget.format = format_name widget.meta, widget.raw_content = \ FileStorage.read_file(os.path.join(path, file)) yield widget
def fix_page_relative_url(rel_url): """ Fix page relative url to a standard, uniform format. Possible input: - my-page - my-page/ - my-page/index - my-page/index.htm - my-page/index.html - my-page/specific.file :param rel_url: relative url to fix :return: tuple(fixed relative url or FILE PATH if exists else None, file exists or not) """ rel_url = rel_url.lstrip('/') # trim all heading '/' endswith_slash = rel_url.endswith('/') rel_url = rel_url.rstrip('/') + ('/' if endswith_slash else '' ) # preserve only one trailing '/' if not rel_url or rel_url == '/': return None, False file_path = os.path.join(current_app.instance_path, 'pages', rel_url.replace('/', os.path.sep)) if rel_url.endswith('/'): index_html_file_path = os.path.join(file_path, 'index.html') if os.path.isfile(index_html_file_path): # index.html exists return index_html_file_path, True return rel_url, False elif os.path.isfile(file_path): ext = os.path.splitext(file_path)[1][1:] if get_standard_format_name(ext) is not None: # is source of custom page if current_app.config['PAGE_SOURCE_ACCESSIBLE']: return file_path, True else: # is other direct files return file_path, True elif os.path.isdir(file_path): return rel_url + '/', False sp = rel_url.rsplit('/', 1) m = re.match(r'(.+)\.html?', sp[-1]) if m: sp[-1] = m.group(1) + '.html' else: sp[-1] += '.html' return '/'.join(sp), False
def posts_generator(path): """Loads valid posts one by one in the given path.""" if os.path.isdir(path): for file in os.listdir(path): filename, ext = os.path.splitext(file) format_name = get_standard_format_name(ext[1:]) if format_name is not None and re.match( r'\d{4}-\d{2}-\d{2}-.+', filename): # the format is supported and the filename is valid, so load this post post = Post() post.format = format_name post.meta, post.raw_content = FileStorage.read_file( os.path.join(path, file)) post.rel_url = filename.replace('-', '/', 3) + '/' post.unique_key = '/post/' + post.rel_url yield post
def pages_generator(pages_root_path): for file_path in traverse_directory(pages_root_path, yield_dir=False): rel_path = os.path.relpath(file_path, pages_root_path) rel_path, ext = os.path.splitext(rel_path) if not ext or ext == '.' or get_standard_format_name( ext[1:]) is None: continue # pragma: no cover if rel_path.endswith(os.path.sep + 'index'): rel_path = rel_path[:-len('index')] else: rel_path += '.html' page = self.get_page(rel_path.replace(os.path.sep, '/'), include_draft=include_draft) if page is not None: yield page
def test_get_standard_format_name(): assert get_standard_format_name('txt') == 'txt' assert get_standard_format_name('TxT') == 'txt' assert get_standard_format_name('md') == 'markdown' assert get_standard_format_name('MDown') == 'markdown' assert get_standard_format_name('Markdown') == 'markdown'