"""
Functions to import from various other static site generators
"""
# Refactoring idea: make this into its own sub-package and use a plugin system
import abc
import os
import shutil
import yaml
from .exceptions import UnableToImport
from .model import ABC
from .site import Site
[docs]
class Importer(ABC):
"""
Base class for all importers
:param site:
Site object for the destination
:param src_path:
Path to the thing to import
"""
def __init__(self, site: Site, src_path: str) -> None:
self.site = site
self.src_path = src_path
[docs]
@abc.abstractmethod
def run(self) -> None:
raise NotImplementedError
[docs]
def ensure_directories(self) -> None:
for _dir in ("media", "templates", "pages", "posts"):
path = os.path.join(self.site.site_path, _dir)
if not os.path.exists(path):
os.mkdir(path)
elif not os.path.isdir(path):
raise UnableToImport("{} exists but is not a directory".format(path))
[docs]
class Posty1Importer(Importer):
"""
Importer to pull from a Posty 1.x site
"""
[docs]
def run(self) -> None:
self.ensure_directories()
self.import_media()
self.import_templates()
self.import_pages()
self.import_posts()
[docs]
def import_media(self) -> None:
self._copy_files("_media", "media")
[docs]
def import_templates(self) -> None:
self._copy_files("_templates", "templates")
[docs]
def import_pages(self) -> None:
src_dir = os.path.join(self.src_path, "_pages")
dst_dir = os.path.join(self.site.site_path, "pages")
for page in os.listdir(src_dir):
src_file = os.path.join(src_dir, page)
dst_file = os.path.join(dst_dir, page)
new_page = self._convert_page(open(src_file).read())
with open(dst_file, "w") as fh:
fh.write(new_page)
[docs]
def import_posts(self) -> None:
src_dir = os.path.join(self.src_path, "_posts")
dst_dir = os.path.join(self.site.site_path, "posts")
for post in os.listdir(src_dir):
src_file = os.path.join(src_dir, post)
dst_file = os.path.join(dst_dir, post)
new_post = self._convert_post(open(src_file).read())
with open(dst_file, "w") as fh:
fh.write(new_post)
def _copy_files(self, src: str, dst: str) -> None:
"""
Copy all the files in ``src_dir`` into ``dst_dir``. Each given dir
should be relative to the source/destination sites
:param src:
Relative path to copy files from in the source Posty 1 site
:param dst:
Relative path to copy files to in the destination Posty 2 site
"""
src_dir = os.path.join(self.src_path, src)
dst_dir = os.path.join(self.site.site_path, dst)
for _file in os.listdir(src_dir):
src_path = os.path.join(src_dir, _file)
dst_path = os.path.join(dst_dir, _file)
print("Copying {} to {}".format(src_path, dst_path))
if os.path.isfile(src_path):
shutil.copy(src_path, dst_path)
elif os.path.isdir(src_path):
shutil.copytree(src_path, dst_path)
else:
print(f" Looks like {src_path} isn't a file nor dir, not copying.")
def _convert_page(self, old_page: str) -> str:
"""
Converts an old Posty 1.x page into a new-style one. Notably just
throws away any existing `url`
"""
old_page = old_page.replace("\r\n", "\n")
docs = old_page.split("---\n")
new_page = ""
meta = yaml.safe_load(docs[1])
if "url" in meta.keys():
del meta["url"]
new_page += yaml.dump(meta, default_flow_style=False)
new_page += "---\n"
new_page += docs[2]
return new_page
def _convert_post(self, old_post: str) -> str:
"""
Converts an old Posty post (a string) into a new-style post with a
blurb and updated metadata. Returns a string containing the three YAML
documents.
:param old_post:
A string containing the contents of an old post file
"""
old_post = old_post.replace("\r\n", "\n")
docs = old_post.split("---\n")
new_post = ""
# Convert the metadata
meta = yaml.safe_load(docs[1])
meta.setdefault("tags", [])
new_post += yaml.dump(meta, default_flow_style=False)
# Create a blurb out of the first paragraph
body = docs[2].strip().split("\n\n")
blurb = body[0]
rest_of_post = "\n\n".join(body[1:])
new_post += "---\n"
new_post += blurb
# Drop in the rest of the post
new_post += "\n---\n"
new_post += rest_of_post
return new_post