summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Luevano Alvarado <david@luevano.xyz>2022-04-17 02:13:36 -0600
committerDavid Luevano Alvarado <david@luevano.xyz>2022-04-17 02:13:36 -0600
commit3c0691df1b7ff1fd04e22ab6055e84cc2137504e (patch)
treedded20edb6c37f2b6904447684db693fcddf16a7 /src
parentf203d11cff37d6809396d0ea39bf53abe9bad182 (diff)
refactor config handler and morev0.6.0
Refactored the configuration handling to use configparser; also the argument parser; generally added more 'logging'; updated template resources; and more minor things
Diffstat (limited to 'src')
-rw-r--r--src/pyssg/arg_parser.py50
-rw-r--r--src/pyssg/builder.py32
-rw-r--r--src/pyssg/configuration.py151
-rw-r--r--src/pyssg/page.py34
-rw-r--r--src/pyssg/parser.py18
-rw-r--r--src/pyssg/plt/default.ini22
-rw-r--r--src/pyssg/plt/index.html6
-rw-r--r--src/pyssg/plt/page.html4
-rw-r--r--src/pyssg/plt/rss.xml18
-rw-r--r--src/pyssg/plt/sitemap.xml2
-rw-r--r--src/pyssg/plt/tag.html4
-rw-r--r--src/pyssg/pyssg.py85
-rw-r--r--src/pyssg/utils.py28
13 files changed, 204 insertions, 250 deletions
diff --git a/src/pyssg/arg_parser.py b/src/pyssg/arg_parser.py
index 4ee7d57..90fb8c1 100644
--- a/src/pyssg/arg_parser.py
+++ b/src/pyssg/arg_parser.py
@@ -3,21 +3,40 @@ from argparse import ArgumentParser, Namespace
def get_parsed_arguments() -> Namespace:
parser = ArgumentParser(prog='pyssg',
- description='''Static Site Generator that reads
- Markdown files and creates HTML files.\nIf
- [-c]onfig file is provided (or exists in default
- location) all other options are ignored.\nFor
- datetime formats see:
+ description='''Static Site Generator that parses
+ Markdown files into HTML files. For datetime
+ formats see:
https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes''')
parser.add_argument('-v', '--version',
action='store_true',
help='''print program version''')
parser.add_argument('-c', '--config',
- default='$XDG_CONFIG_HOME/pyssg/pyssgrc',
+ # don't give a default here, as it would seem like
+ # --config was passed
+ # default='$XDG_CONFIG_HOME/pyssg/config.ini',
type=str,
- help='''config file (path) to read from; defaults to
- 'pyssgrc' first, then
- '$XDG_CONFIG_HOME/pyssg/pyssgrc' ''')
+ help='''config file (path) to read from; if not passed,
+ '$XDG_CONFIG_HOME/pyssg/config.ini' is used''')
+ parser.add_argument('--copy-default-config',
+ action='store_true',
+ help='''copies the default config to path specified in
+ --config flag''')
+ parser.add_argument('-i', '--init',
+ action='store_true',
+ help='''initializes the directory structures and copies
+ over default templates''')
+ parser.add_argument('-b', '--build',
+ action='store_true',
+ help='''generates all HTML files by parsing MD files
+ present in source directory and copies over manually
+ written HTML files''')
+ parser.add_argument('-f', '--force',
+ action='store_true',
+ help='''force building all pages and not only the
+ updated ones''')
+ # really not needed, too much bloat and case scenarios to check for,
+ # instead, just read from config file or default config file
+ """
parser.add_argument('-s', '--src',
default='src',
type=str,
@@ -68,17 +87,6 @@ def get_parsed_arguments() -> Namespace:
help='''date format used for the separator between page
entries in a list; defaults to '%%B %%Y' ('March 2021',
for example)''')
- parser.add_argument('-i', '--init',
- action='store_true',
- help='''initializes the dir structure, templates,
- as well as the 'src' and 'dst' directories''')
- parser.add_argument('-b', '--build',
- action='store_true',
- help='''generates all html files and passes over
- existing (handmade) ones''')
- parser.add_argument('-f', '--force',
- action='store_true',
- help='''force building all pages and not only the
- updated ones''')
+ """
return parser.parse_args()
diff --git a/src/pyssg/builder.py b/src/pyssg/builder.py
index 84494da..130062e 100644
--- a/src/pyssg/builder.py
+++ b/src/pyssg/builder.py
@@ -4,8 +4,8 @@ from copy import deepcopy
from operator import itemgetter
from jinja2 import Environment, Template
from markdown import Markdown
+from configparser import ConfigParser
-from .configuration import Configuration
from .database import Database
from .parser import MDParser
from .page import Page
@@ -13,11 +13,11 @@ from .discovery import get_file_list, get_dir_structure
class Builder:
- def __init__(self, config: Configuration,
+ def __init__(self, config: ConfigParser,
env: Environment,
db: Database,
md: Markdown):
- self.config: Configuration = config
+ self.config: ConfigParser = config
self.env: Environment = env
self.db: Database = db
self.md: Markdown = md
@@ -33,15 +33,19 @@ class Builder:
def build(self) -> None:
- self.dirs = get_dir_structure(self.config.src, ['templates'])
- self.md_files = get_file_list(self.config.src, ['.md'], ['templates'])
- self.html_files = get_file_list(self.config.src, ['.html'], ['templates'])
+ self.dirs = get_dir_structure(self.config.get('path', 'src'),
+ ['templates'])
+ self.md_files = get_file_list(self.config.get('path', 'src'),
+ ['.md'],
+ ['templates'])
+ self.html_files = get_file_list(self.config.get('path', 'src'),
+ ['.html'],
+ ['templates'])
self.__create_dir_structure()
self.__copy_html_files()
- parser: MDParser = MDParser(self.config.src,
- self.md_files,
+ parser: MDParser = MDParser(self.md_files,
self.config,
self.db,
self.md)
@@ -69,7 +73,7 @@ class Builder:
# for the dir structure,
# doesn't matter if the dir already exists
try:
- os.makedirs(os.path.join(self.config.dst, d))
+ os.makedirs(os.path.join(self.config.get('path', 'dst'), d))
except FileExistsError:
pass
@@ -79,18 +83,18 @@ class Builder:
dst_file: str = None
for f in self.html_files:
- src_file = os.path.join(self.config.src, f)
- dst_file = os.path.join(self.config.dst, f)
+ src_file = os.path.join(self.config.get('path', 'src'), f)
+ dst_file = os.path.join(self.config.get('path', 'dst'), f)
# only copy files if they have been modified (or are new)
- if self.db.update(src_file, remove=f'{self.config.src}/'):
+ if self.db.update(src_file, remove=f'{self.config.get("path", "src")}/'):
shutil.copy2(src_file, dst_file)
def __render_articles(self) -> None:
article_vars: dict = deepcopy(self.common_vars)
# check if only updated should be created
- if self.config.force:
+ if self.config.getboolean('other', 'force'):
for p in self.all_pages:
article_vars['page'] = p
self.__render_template("page.html",
@@ -132,5 +136,5 @@ class Builder:
template: Template = self.env.get_template(template_name)
content: str = template.render(**template_vars)
- with open(os.path.join(self.config.dst, file_name), 'w') as f:
+ with open(os.path.join(self.config.get('path', 'dst'), file_name), 'w') as f:
f.write(content)
diff --git a/src/pyssg/configuration.py b/src/pyssg/configuration.py
index 5a09a7a..dd6bfaa 100644
--- a/src/pyssg/configuration.py
+++ b/src/pyssg/configuration.py
@@ -1,133 +1,42 @@
-from typing import Union
+import sys
from importlib.metadata import version
+from importlib.resources import path as rpath
from datetime import datetime, timezone
+from configparser import ConfigParser
-class Configuration:
- def __init__(self, path: str):
- self.path: str = path
- # config file specific
- self.src: str = None
- self.dst: str = None
- self.plt: str = None
- self.url: str = None
- self.static_url: str = None
- self.default_image_url: str = None
- self.title: str = None
- self.dformat: str = None
- self.l_dformat: str = None
- self.lsep_dformat: str = None
- self.force: bool = None
+DEFAULT_CONFIG_PATH = '$XDG_CONFIG_HOME/pyssg/config.ini'
+VERSION = version('pyssg')
- # other
- self.version: str = version('pyssg')
- self.dformat_rss: str = '%a, %d %b %Y %H:%M:%S GMT'
- self.dformat_sitemap: str = '%Y-%m-%d'
- self.run_date_rss = datetime.now(tz=timezone.utc).strftime(self.dformat_rss)
- self.run_date_sitemap = \
- datetime.now(tz=timezone.utc).strftime(self.dformat_sitemap)
+def __check_well_formed_config(config: ConfigParser) -> None:
+ default_config: ConfigParser = ConfigParser()
+ with rpath('pyssg.plt', 'default.ini') as p:
+ default_config.read(p)
- def read(self):
- try:
- lines: list[str] = None
- with open(self.path, 'r') as f:
- lines = f.readlines()
+ for section in default_config.sections():
+ if not config.has_section(section):
+ print(f'config does not have section "{section}"')
+ sys.exit(1)
+ for option in default_config.options(section):
+ if not config.has_option(section, option):
+ print(f'config does not have option "{option}" in section "{section}"')
+ sys.exit(1)
- opts: dict[str, Union[str, bool]] = dict()
- for l in lines:
- kv: list[str] = l.split('=', 1)
- if len(kv) != 2:
- raise Exception('wrong config syntax')
- k: str = kv[0].strip().lower()
- v_temp: str = kv[1].strip()
- # check if value should be a boolean true
- v: Union[str, bool] = v_temp\
- if v_temp.lower() not in ['true', '1', 'yes']\
- else True
+def get_parsed_config(path: str) -> ConfigParser:
+ config: ConfigParser = ConfigParser()
+ config.read(path)
- opts[k] = v
+ __check_well_formed_config(config)
- try:
- self.src = opts['src']
- except KeyError: pass
+ # set other required options
+ config.set('fmt', 'rss_date', '%%a, %%d %%b %%Y %%H:%%M:%%S GMT')
+ config.set('fmt', 'sitemap_date', '%%Y-%%m-%%d')
+ config.set('info', 'version', VERSION)
+ config.set('info', 'rss_run_date', datetime.now(
+ tz=timezone.utc).strftime(config.get('fmt', 'rss_date')))
+ config.set('info', 'sitemap_run_date', datetime.now(
+ tz=timezone.utc).strftime(config.get('fmt', 'sitemap_date')))
- try:
- self.dst = opts['dst']
- except KeyError: pass
-
- try:
- self.plt = opts['plt']
- except KeyError: pass
-
- try:
- self.url = opts['url']
- except KeyError: pass
-
- try:
- self.static_url = opts['static_url']
- except KeyError: pass
-
- try:
- self.default_image_url = opts['default_image_url']
- except KeyError: pass
-
- try:
- self.title = opts['title']
- except KeyError: pass
-
- try:
- self.dformat = opts['date_format']
- except KeyError: pass
-
- try:
- self.l_dformat = opts['list_date_format']
- except KeyError: pass
-
- try:
- self.lsep_dformat = opts['list_sep_date_format']
- except KeyError: pass
-
- try:
- # if the parser above didn't read a boolean true, then take it
- # as a false anyways
- self.force = opts['force'] if opts['force'] is True else False
- except KeyError: pass
-
- except OSError: pass
-
-
- def fill_missing(self, opts: dict[str, Union[str, bool]]) -> None:
- if self.src is None:
- self.src = opts['src']
-
- if self.dst is None:
- self.dst = opts['dst']
-
- if self.plt is None:
- self.plt = opts['plt']
-
- if self.url is None:
- self.url = opts['url']
-
- if self.static_url is None:
- self.static_url = opts['static_url']
-
- if self.default_image_url is None:
- self.default_image_url = opts['default_image_url']
-
- if self.title is None:
- self.title = opts['title']
-
- if self.dformat is None:
- self.dformat = opts['date_format']
-
- if self.l_dformat is None:
- self.l_dformat = opts['list_date_format']
-
- if self.lsep_dformat is None:
- self.lsep_dformat = opts['list_sep_date_format']
-
- if self.force is None:
- self.force = opts['force']
+ return config
diff --git a/src/pyssg/page.py b/src/pyssg/page.py
index 6b83d39..784749c 100644
--- a/src/pyssg/page.py
+++ b/src/pyssg/page.py
@@ -1,6 +1,6 @@
from datetime import datetime, timezone
-from .configuration import Configuration
+from configparser import ConfigParser
class Page:
@@ -10,14 +10,14 @@ class Page:
mtime: float,
html: str,
meta: dict,
- config: Configuration):
+ config: ConfigParser):
# initial data
self.name: str = name
self.ctimestamp: float = ctime
self.mtimestamp: float = mtime
self.content: str = html
self.meta: dict = meta
- self.config: Configuration = config
+ self.config: ConfigParser = config
# data from self.meta
self.title: str = ''
@@ -66,23 +66,23 @@ class Page:
# dates
self.cdatetime = datetime.fromtimestamp(self.ctimestamp,
tz=timezone.utc)
- self.cdate = self.cdatetime.strftime(self.config.dformat)
- self.cdate_list = self.cdatetime.strftime(self.config.l_dformat)
- self.cdate_list_sep = self.cdatetime.strftime(self.config.lsep_dformat)
- self.cdate_rss = self.cdatetime.strftime(self.config.dformat_rss)
+ self.cdate = self.cdatetime.strftime(self.config.get('fmt', 'date'))
+ self.cdate_list = self.cdatetime.strftime(self.config.get('fmt', 'list_date'))
+ self.cdate_list_sep = self.cdatetime.strftime(self.config.get('fmt', 'list_sep_date'))
+ self.cdate_rss = self.cdatetime.strftime(self.config.get('fmt', 'rss_date'))
self.cdate_sitemap = \
- self.cdatetime.strftime(self.config.dformat_sitemap)
+ self.cdatetime.strftime(self.config.get('fmt', 'sitemap_date'))
# only if file/page has been modified
if self.mtimestamp != 0.0:
self.mdatetime = datetime.fromtimestamp(self.mtimestamp,
tz=timezone.utc)
- self.mdate = self.mdatetime.strftime(self.config.dformat)
- self.mdate_list = self.mdatetime.strftime(self.config.l_dformat)
- self.mdate_list_sep = self.mdatetime.strftime(self.config.lsep_dformat)
- self.mdate_rss = self.mdatetime.strftime(self.config.dformat_rss)
+ self.mdate = self.mdatetime.strftime(self.config.get('fmt', 'date'))
+ self.mdate_list = self.mdatetime.strftime(self.config.get('fmt', 'list_date'))
+ self.mdate_list_sep = self.mdatetime.strftime(self.config.get('fmt', 'list_sep_date'))
+ self.mdate_rss = self.mdatetime.strftime(self.config.get('fmt', 'rss_date'))
self.mdate_sitemap = \
- self.mdatetime.strftime(self.config.dformat_sitemap)
+ self.mdatetime.strftime(self.config.get('fmt', 'sitemap_date'))
# not always contains tags
try:
@@ -91,17 +91,17 @@ class Page:
for t in tags_only:
self.tags.append((t,
- f'{self.config.url}/tag/@{t}.html'))
+ f'{self.config.get("url", "main")}/tag/@{t}.html'))
except KeyError: pass
- self.url = f'{self.config.url}/{self.name.replace(".md", ".html")}'
+ self.url = f'{self.config.get("url", "main")}/{self.name.replace(".md", ".html")}'
try:
self.image_url = \
- f'{self.config.static_url}/{self.meta["image_url"][0]}'
+ f'{self.config.get("url", "static")}/{self.meta["image_url"][0]}'
except KeyError:
self.image_url = \
- f'{self.config.static_url}/{self.config.default_image_url}'
+ f'{self.config.get("url", "static")}/{self.config.get("url", "default_image")}'
# if contains open graph elements
try:
diff --git a/src/pyssg/parser.py b/src/pyssg/parser.py
index f2d23eb..2888fcb 100644
--- a/src/pyssg/parser.py
+++ b/src/pyssg/parser.py
@@ -1,24 +1,21 @@
import os
from operator import itemgetter
-from datetime import datetime
from markdown import Markdown
+from configparser import ConfigParser
from .database import Database
-from .configuration import Configuration
from .page import Page
# parser of md files, stores list of pages and tags
class MDParser:
- def __init__(self, src: str,
- files: list[str],
- config: Configuration,
+ def __init__(self, files: list[str],
+ config: ConfigParser,
db: Database,
md: Markdown):
- self.src: str = src
self.files: list[str] = files
- self.config: Configuration = config
+ self.config: ConfigParser = config
self.db: Database = db
self.md: Markdown = md
@@ -32,12 +29,13 @@ class MDParser:
self.all_pages = []
self.updated_pages = []
self.all_tags = []
- all_tag_names: list[str] = []
+ # not used, not sure why i had this
+ # all_tag_names: list[str] = []
for f in self.files:
- src_file: str = os.path.join(self.src, f)
+ src_file: str = os.path.join(self.config.get('path', 'src'), f)
# get flag if update is successful
- updated: bool = self.db.update(src_file, remove=f'{self.src}/')
+ updated: bool = self.db.update(src_file, remove=f'{self.config.get("path", "src")}/')
content: str = self.md.reset().convert(open(src_file).read())
page: Page = Page(f,
diff --git a/src/pyssg/plt/default.ini b/src/pyssg/plt/default.ini
index 2700d28..ab4eac1 100644
--- a/src/pyssg/plt/default.ini
+++ b/src/pyssg/plt/default.ini
@@ -1,14 +1,16 @@
-[dir_paths]
+[path]
src=src
dst=dst
plt=plt
-[urls]
-url=https://example.com
-static_url=https://static.example.com
-default_image_url=/images/default.png
-[formats]
-date_format=%%a, %%b %%d, %%Y @ %%H:%%M %%Z
-list_date_format=%%b %%d
-list_sep_date_format=%%B %%Y
+[url]
+main=https://example.com
+static=https://static.example.com
+default_image=/images/default.png
+[fmt]
+date=%%a, %%b %%d, %%Y @ %%H:%%M %%Z
+list_date=%%b %%d
+list_sep_date=%%B %%Y
[info]
-title=Example site \ No newline at end of file
+title=Example site
+[other]
+force=False \ No newline at end of file
diff --git a/src/pyssg/plt/index.html b/src/pyssg/plt/index.html
index e06efdb..09ca786 100644
--- a/src/pyssg/plt/index.html
+++ b/src/pyssg/plt/index.html
@@ -2,11 +2,11 @@
<html lang="en">
<head>
<meta charset="utf-8">
- <base href="{{config.static_url}}">
- <title>Index -- {{config.title}}</title>
+ <base href="{{config.get('url', 'static')}}">
+ <title>Index -- {{config.get('info', 'title')}}</title>
</head>
<body>
- <h1>Index -- {{config.title}}</h1>
+ <h1>Index -- {{config.get('info', 'title')}}</h1>
<p>Some text here.</p>
<p>Tags:
diff --git a/src/pyssg/plt/page.html b/src/pyssg/plt/page.html
index 2fc3943..15663fa 100644
--- a/src/pyssg/plt/page.html
+++ b/src/pyssg/plt/page.html
@@ -2,8 +2,8 @@
<html lang="{{page.lang}}">
<head>
<meta charset="utf-8">
- <base href="{{config.static_url}}">
- <title>{{page.title}} -- {{config.title}}</title>
+ <base href="{{config.get('url', 'static')}}">
+ <title>{{page.title}} -- {{config.get('info', 'title')}}</title>
</head>
<body>
<h1>{{page.title}}</h1>
diff --git a/src/pyssg/plt/rss.xml b/src/pyssg/plt/rss.xml
index 42020d7..be6ddf0 100644
--- a/src/pyssg/plt/rss.xml
+++ b/src/pyssg/plt/rss.xml
@@ -3,24 +3,24 @@
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
- <title>{{config.title}}</title>
- <link>{{config.url}}</link>
- <atom:link href="{{config.url}}/rss.xml" rel="self" type="application/rss+xml"/>
+ <title>{{config.get('info', 'title')}}</title>
+ <link>{{config.get('url', 'main')}}</link>
+ <atom:link href="{{config.get('url', 'main')}}/rss.xml" rel="self" type="application/rss+xml"/>
<description>Short site description.</description>
<language>en-us</language>
<category>Blog</category>
<copyright>Copyright 2021 Somebody</copyright>
<managingEditor>some@one.com (Sombody)</managingEditor>
<webMaster>some@one.com (Sombody)</webMaster>
- <pubDate>{{config.run_date_rss}}</pubDate>
- <lastBuildDate>{{run_date_rss}}</lastBuildDate>
- <generator>pyssg v{{config.version}}</generator>
+ <pubDate>{{config.get('info', 'rss_run_date')}}</pubDate>
+ <lastBuildDate>{{config.get('info', 'rss_run_date')}}</lastBuildDate>
+ <generator>pyssg v{{config.get('info', 'version')}}</generator>
<docs>https://validator.w3.org/feed/docs/rss2.html</docs>
<ttl>30</ttl>
<image>
- <url>{{config.static_url}}/images/blog.png</url>
- <title>{{config.title}}</title>
- <link>{{config.url}}</link>
+ <url>{{config.get('url', 'static')}}/images/blog.png</url>
+ <title>{{config.get('info', 'title')}}</title>
+ <link>{{config.get('url', 'main')}}</link>
</image>
{%for p in all_pages%}
<item>
diff --git a/src/pyssg/plt/sitemap.xml b/src/pyssg/plt/sitemap.xml
index 26ee5c1..af1212a 100644
--- a/src/pyssg/plt/sitemap.xml
+++ b/src/pyssg/plt/sitemap.xml
@@ -14,7 +14,7 @@
{%for t in all_tags%}
<url>
<loc>{{t[1]}}</loc>
- <lastmod>{{config.run_date_sitemap}}</lastmod>
+ <lastmod>{{config.get('info', 'sitemap_run_date')}}</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
diff --git a/src/pyssg/plt/tag.html b/src/pyssg/plt/tag.html
index d856ce4..ffd1956 100644
--- a/src/pyssg/plt/tag.html
+++ b/src/pyssg/plt/tag.html
@@ -2,8 +2,8 @@
<html lang="en">
<head>
<meta charset="utf-8">
- <base href="{{config.static_url}}">
- <title>Posts filtered by {{tag[0]}} -- {{config.title}}</title>
+ <base href="{{config.get('url', 'static')}}">
+ <title>Posts filtered by {{tag[0]}} -- {{config.get('info', 'title')}}</title>
</head>
<body>
<h1>Posts filtered by {{tag[0]}}</h1>
diff --git a/src/pyssg/pyssg.py b/src/pyssg/pyssg.py
index e694565..9b82231 100644
--- a/src/pyssg/pyssg.py
+++ b/src/pyssg/pyssg.py
@@ -1,7 +1,8 @@
import os
-import shutil
-from importlib.resources import path
+import sys
+from importlib.resources import path as rpath
from typing import Union
+from configparser import ConfigParser
from jinja2 import Environment, FileSystemLoader
from markdown import Markdown
@@ -9,61 +10,65 @@ from yafg import YafgExtension
from MarkdownHighlight.highlight import HighlightExtension
from markdown_checklist.extension import ChecklistExtension
+from .utils import create_dir, copy_file, sanity_check_path
from .arg_parser import get_parsed_arguments
-from .configuration import Configuration
+from .configuration import get_parsed_config, DEFAULT_CONFIG_PATH, VERSION
from .database import Database
from .builder import Builder
def main() -> None:
- opts: dict[str, Union[str, bool]] = vars(get_parsed_arguments())
- conf_path: str = opts['config']
- conf_path = os.path.expandvars(conf_path)
-
-
- config: Configuration = None
- if os.path.exists('pyssgrc'):
- config = Configuration('pyssgrc')
- else:
- config = Configuration(conf_path)
-
- config.read()
- config.fill_missing(opts)
-
- if opts['version']:
- print(f'pyssg v{config.version}')
- return
-
- if opts['init']:
- try:
- os.mkdir(config.src)
- os.makedirs(os.path.join(config.dst, 'tag'))
- os.mkdir(config.plt)
- except FileExistsError:
- pass
-
- # copy basic template files
+ args: dict[str, Union[str, bool]] = vars(get_parsed_arguments())
+ if not len(sys.argv) > 1:
+ print(f'pyssg v{VERSION} - no arguments passed, --help for more')
+ sys.exit(0)
+
+ if args['version']:
+ print(f'pyssg v{VERSION}')
+ sys.exit(0)
+
+ config_path: str = args['config'] if args['config'] else DEFAULT_CONFIG_PATH
+ config_path = os.path.normpath(os.path.expandvars(config_path))
+ sanity_check_path(config_path)
+ config_dir, _ = os.path.split(config_path)
+
+ if args['copy_default_config']:
+ create_dir(config_dir)
+ with rpath('pyssg.plt', 'default.ini') as p:
+ copy_file(p, config_path)
+ sys.exit(0)
+
+ if not os.path.exists(config_path):
+ print(f'''config file does't exist in path "{config_path}"; make sure
+ the path is correct; use --copy-default-config to if you
+ haven't already''')
+ sys.exit(1)
+
+ config: ConfigParser = get_parsed_config(config_path)
+
+ if args['init']:
+ create_dir(config.get('path', 'src'))
+ create_dir(os.path.join(config.get('path', 'dst'), 'tag'), True)
+ create_dir(config.get('path', 'plt'))
files: list[str] = ('index.html',
'page.html',
'tag.html',
'rss.xml',
'sitemap.xml')
for f in files:
- plt_file: str = os.path.join(config.plt, f)
- with path('pyssg.plt', f) as p:
- if not os.path.exists(plt_file):
- shutil.copy(p, plt_file)
-
- return
+ plt_file: str = os.path.join(config.get('path', 'plt'), f)
+ with rpath('pyssg.plt', f) as p:
+ copy_file(p, plt_file)
+ sys.exit(0)
- if opts['build']:
+ if args['build']:
# start the db
- db: Database = Database(os.path.join(config.src, '.files'))
+ db: Database = Database(os.path.join(config.get('path', 'src'), '.files'))
db.read()
# the autoescape option could be a security risk if used in a dynamic
# website, as far as i can tell
- env: Environment = Environment(loader=FileSystemLoader(config.plt),
+ env: Environment = Environment(loader=FileSystemLoader(config.get('path', 'plt')),
autoescape=False,
trim_blocks=True,
lstrip_blocks=True)
@@ -92,4 +97,4 @@ def main() -> None:
builder.build()
db.write()
- return
+ sys.exit(0)
diff --git a/src/pyssg/utils.py b/src/pyssg/utils.py
new file mode 100644
index 0000000..8e5d90e
--- /dev/null
+++ b/src/pyssg/utils.py
@@ -0,0 +1,28 @@
+import os
+import sys
+import shutil
+
+
+def create_dir(path: str, p: bool=False) -> None:
+ try:
+ if p:
+ os.makedirs(path)
+ else:
+ os.mkdir(path)
+ print(f'created directory "{path}"')
+ except FileExistsError:
+ print(f'directory "{path}" already exists')
+
+
+def copy_file(src: str, dst: str) -> None:
+ if not os.path.exists(dst):
+ shutil.copy(src, dst)
+ print(f'copied file "{src}" to "{dst}"')
+ else:
+ print(f'"{dst}" already exists')
+
+
+def sanity_check_path(path: str) -> None:
+ if '$' in path:
+ print(f'"$" character found in path: "{path}"; could be due to non-existant env var.')
+ sys.exit(1)