pyssg


Namepyssg JSON
Version 0.8.3 PyPI version JSON
download
home_pagehttps://github.com/luevano/pyssg
SummaryA Static Site Generator using markdown files
upload_time2022-12-27 09:00:46
maintainer
docs_urlNone
authorDavid Luevano Alvarado
requires_python
licenseGPLv3
keywords python static site generator markdown
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pyssg - Static Site Generator written in Python

Generates HTML files from MD files for a static site, personally using it for a blog-like site.

Initially inspired by Roman Zolotarev's [`ssg5`](https://rgz.ee/bin/ssg5) and [`rssg`](https://rgz.ee/bin/rssg), Luke Smith's [`lb` and `sup`](https://github.com/LukeSmithxyz/lb) and, pedantic.software's [`blogit`](https://pedantic.software/git/blogit/).

## Features and to-do

**NOTE:** WIP, there will be changes that will break the setup.

- [x] Build static site parsing `markdown` files ( `*.md` -> `*.html`)
	- [x] Uses [`jinja`](https://jinja.palletsprojects.com/en/3.0.x/) for templating.
	- [x] Preserves hand-made `*.html` files.
	- [x] Tag functionality, useful for blog-style sites.
	- [ ] Open Graph (and similar) support.
		- Technically, this works if you add the correct metadata to the `*.md` files and use the variables available for Jinja.
- [x] Build `sitemap.xml` file.
	- [ ] Include manually added `*.html` files.
- [x] Build `rss.xml` file.
	- [ ] Join the `static_url` to all relative URLs found to comply with the [RSS 2.0 spec](https://validator.w3.org/feed/docs/rss2.html).
		- This would be added to the parsed HTML text extracted from the MD files, so it would be available to the created `*.html` and `*.xml` files. Note that depending on the reader, it will append the URL specified in the RSS file or use the [`xml:base`](https://www.rssboard.org/news/151/relative-links) specified (for example, [newsboat](https://newsboat.org/) parses `xml:base`).
	- [ ] Include manually added `*.html` files.
- [x] YAML for configuration file, uses [`PyYAML`](https://pyyaml.org/).
	- [ ] Handle multiple "documents".
	- [ ] More complex directory structure to support multiple subdomains and different types of pages.
- [ ] Option/change to using an SQL database instead of the custom solution.
- [x] Checksum checking because the timestamp of the file is not enough.
- [ ] Use external markdown extensions.

### Markdown features

This program uses the base [`markdown` syntax](https://daringfireball.net/projects/markdown/syntax) plus additional syntax, all thanks to [`python-markdown`](https://python-markdown.github.io/) that provides [extensions](https://python-markdown.github.io/extensions/). The following extensions are used:

- Extra (collection of QoL extensions).
- Meta-Data.
- Sane Lists.
- SmartyPants.
- Table of Contents.
- WikiLinks.
- [yafg - Yet Another Figure Generator](https://git.sr.ht/~ferruck/yafg)
- [Markdown Checklist](https://github.com/FND/markdown-checklist)
- [PyMdown Extensions](https://facelessuser.github.io/pymdown-extensions/)
	- [Caret](https://facelessuser.github.io/pymdown-extensions/extensions/caret/)
	- [Tilde](https://facelessuser.github.io/pymdown-extensions/extensions/tilde/)
	- [Mark](https://facelessuser.github.io/pymdown-extensions/extensions/mark/)

## Installation

Install with `pip`:

```sh
pip install pyssg
```

Probably will add a PKBUILD (and possibly submit it to the AUR) in the future.

## Usage

1. Get the default configuration file:

```sh
pyssg --copy-default-config -c <path/to/config>
```

- Where `-c` is optional as by default `$XDG_CONFIG_HOME/pyssg/config.yaml` is used.

2. Edit the config file created as needed.

- `config.yaml` is parsed using [`PyYAML`](https://pyyaml.org/), [more about the config file](#config-file).

3. Initialize the directory structures (source, destination, template) and move template files:

```sh
pyssg -i
```

- You can modify the basic templates as needed (see [variables available for Jinja](#available-jinja-variables)).

- Strongly recommended to edit the `rss.xml` template.

4. Place your `*.md` files somewhere inside the source directory. It accepts sub-directories.

- Recommended (no longer mandatory) metadata keys that can be added to the top of `.md` files:

```
title: the title of your blog entry or whatever
author: your name or online handle
	another name maybe for multiple authors?
lang: the language the entry is written on
summary: a summary of the entry
tags: english
	short
	tutorial
	etc
```

- You can add more meta-data keys as long as it is [Python-Markdown compliant](https://python-markdown.github.io/extensions/meta_data/), and these will ve [available as Jinja variables](#available-jinja-variables).

5. Build the `*.html` with:

```sh
pyssg -b
```

- After this, you have ready to deploy `*.html` files.

## Config file

All sections/options need to be compliant with [`PyYAML`](https://pyyaml.org/) which should be compliant with [`YAML 1.2`](https://yaml.org/spec/1.2.2/). Additionaly, I've added the custom tag `!join` which concatenates strings from an array, which an be used as follows:

```yaml
variable: &variable_reference_name "value"
other_variable: !join [*variable_reference_name, "other_value", 1]
```

Which would produce `other_variable: "valueother_value1"`. Also environment variables will be expanded internally.

The following is a list of config items that need to be present in the config unless stated otherwise:

```yaml
%YAML 1.2
---
# not needed, shown here as an example of the !join tag
define: &root "$HOME/path/to/" # $HOME expands to /home/user, for example

title: "Example site"
path:
  src: !join [*root, "src"] # $HOME/path/to/src
  dst: "$HOME/some/other/path/to/dst"
  plt: "plt"
  db: !join [*root, "src/", "db.psv"]
url:
  main: "https://example.com"
fmt:
  date: "%a, %b %d, %Y @ %H:%M %Z"
  list_date: "%b %d"
  list_sep_date: "%B %Y"
dirs:
  /: # root "dir_path", whatever is sitting directly under "src"
	cfg:
	  plt: "page.html"
	  # the template can be specified instead of just True/False, a default template will used
	  tags: False
	  index: True
	  rss: True
	  sitemap: True
	  exclude_dirs: ["articles", "blog"] # optional; list of subdirectories to exclude when parsing the / dir_path
# below are other example "dir_paths", can be named anything, only the / (above) is mandatory
  articles:
    cfg:
	  plt: "page.html"
	  tags: True
	  index: True
	  rss: True
	  sitemap: True
  blog:
    cfg:
	  # ...
...
```

The config under `dirs` are just per-subdirectory configuration of directories under `src`. Only the `/` "dir_path" is required as it is the config for the root `src` path files.

The following will be added on runtime:

```yaml
%YAML 1.2
---
fmt:
  rss_date: "%a, %d %b %Y %H:%M:%S GMT" # fixed
  sitemap_date: "%Y-%m-%d" # fixed
info:
  version: "x.y.z" # current 'pyssg' version (0.5.1.dev16, for example)
  debug: True/False # depending if --debug was used when executing
  force: True/False # depending if --force was used when executing
rss_run_date: # date the program was run, formatted with 'fmt.rss_date'
sitemap_run_date: # date the program was run, formatted with 'fmt.sitemap_date'
...
```

You can add any other option/section that you can later use in the Jinja templates via the exposed config object. URL's shouldn't have the trailing slash `/`

## Available Jinja variables

These variables are exposed to use within the templates. The below list is displayed in the form of *variable (type) (available from): description*. `field1/field2/field3/...` describe config file section from the YAML file and option and `object.attribute` corresponding object and it's attribute.

- `config` (`dict`) (all): parsed config file plus the added options internally (as described in [config file](#config-file)).
- `dir_config` (`dict`) (all*): parsed dir_config file plus the added options internally (as described in [config file](#config-file)). *This is for all of the specific "dir_path" files, as per configured in the YAML file `dirs.dir_path.cfg` (for exmaple `dirs./.cfg` for the required dir_path).
- `all_pages` (`list(Page)`) (all): list of all the pages, sorted by creation time, reversed.
- `page` (`Page`) (`page.html`): contains the following attributes (genarally these are parsed from the metadata in the `*.md` files):
	- `title` (`str`): title of the page.
	- `author` (`list[str]`): list of authors of the page.
	- `lang` (`str`): page language, used for the general `html` tag `lang` attribute.
	- `summary` (`str`): summary of the page, as specified in the `*.md` file.
	- `content` (`str`): actual content of the page, this is the `html`.
	- `cdatetime` (`datetime.datetime`): creation datetime object of the page.
	- `cdate` (`method`): method thtat takes the name of the `fmt.FMT` and applies it to the `cdatetime` object.
	- `cdate_rss` (`str`): formatted `cdatetime` as required by rss.
	- `cdate_sitemap` (`str`): formatted `cdatetime` as required by sitemap.
	- `mdatetime` (`datetime.datetime`): modification datetime object of the page. Defaults to `None`.
	- `mdate` (`method`): method thtat takes the name of the `fmt.FMT` and applies it to the `mdatetime` object.
	- `mdate_rss` (`str`): formatted `mdatetime` as required by rss.
	- `mdate_sitemap` (`str`): formatted `mdatetime` as required by sitemap.
	- `tags` (`list(tuple(str))`): list of tuple of tags of the page, containing the name and the url of the tag, in that order. Defaults to empty list.
	- `url` (`str`): url of the page, this already includes the `url/main` from config file.
	- `image_url` (`str`): image url of the page, this already includes the `url/static`. Defaults to the `url/default_image` config option.
	- `next/previous` (`Page`): reference to the next or previous page object (containing all these attributes). Defaults to `None`.
	- `og` (`dict(str, str)`): dict for object graph metadata.
	- `meta` (`dict(str, list(str))`): meta dict as obtained from python-markdown, in case you use a meta tag not yet supported, it will be available there.
- `tag` (`tuple(str)`) (`tag.html`): tuple of name and url of the current tag.
- `tag_pages` (`list(Page)`) (`tag.html`): similar to `all_pages` but contains all the pages for the current tag.
- `all_tags` (`list(tuple(str))`) (all): similar to `page.tags` but contains all the tags.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/luevano/pyssg",
    "name": "pyssg",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "python,static,site,generator,markdown",
    "author": "David Luevano Alvarado",
    "author_email": "david@luevano.xyz",
    "download_url": "https://files.pythonhosted.org/packages/42/f7/856b7b1db77f83e6ec31631c4362de9f513a99764b7a4f77667acdc28221/pyssg-0.8.3.tar.gz",
    "platform": null,
    "description": "# pyssg - Static Site Generator written in Python\n\nGenerates HTML files from MD files for a static site, personally using it for a blog-like site.\n\nInitially inspired by Roman Zolotarev's [`ssg5`](https://rgz.ee/bin/ssg5) and [`rssg`](https://rgz.ee/bin/rssg), Luke Smith's [`lb` and `sup`](https://github.com/LukeSmithxyz/lb) and, pedantic.software's [`blogit`](https://pedantic.software/git/blogit/).\n\n## Features and to-do\n\n**NOTE:** WIP, there will be changes that will break the setup.\n\n- [x] Build static site parsing `markdown` files ( `*.md` -> `*.html`)\n\t- [x] Uses [`jinja`](https://jinja.palletsprojects.com/en/3.0.x/) for templating.\n\t- [x] Preserves hand-made `*.html` files.\n\t- [x] Tag functionality, useful for blog-style sites.\n\t- [ ] Open Graph (and similar) support.\n\t\t- Technically, this works if you add the correct metadata to the `*.md` files and use the variables available for Jinja.\n- [x] Build `sitemap.xml` file.\n\t- [ ] Include manually added `*.html` files.\n- [x] Build `rss.xml` file.\n\t- [ ] Join the `static_url` to all relative URLs found to comply with the [RSS 2.0 spec](https://validator.w3.org/feed/docs/rss2.html).\n\t\t- This would be added to the parsed HTML text extracted from the MD files, so it would be available to the created `*.html` and `*.xml` files. Note that depending on the reader, it will append the URL specified in the RSS file or use the [`xml:base`](https://www.rssboard.org/news/151/relative-links) specified (for example, [newsboat](https://newsboat.org/) parses `xml:base`).\n\t- [ ] Include manually added `*.html` files.\n- [x] YAML for configuration file, uses [`PyYAML`](https://pyyaml.org/).\n\t- [ ] Handle multiple \"documents\".\n\t- [ ] More complex directory structure to support multiple subdomains and different types of pages.\n- [ ] Option/change to using an SQL database instead of the custom solution.\n- [x] Checksum checking because the timestamp of the file is not enough.\n- [ ] Use external markdown extensions.\n\n### Markdown features\n\nThis program uses the base [`markdown` syntax](https://daringfireball.net/projects/markdown/syntax) plus additional syntax, all thanks to [`python-markdown`](https://python-markdown.github.io/) that provides [extensions](https://python-markdown.github.io/extensions/). The following extensions are used:\n\n- Extra (collection of QoL extensions).\n- Meta-Data.\n- Sane Lists.\n- SmartyPants.\n- Table of Contents.\n- WikiLinks.\n- [yafg - Yet Another Figure Generator](https://git.sr.ht/~ferruck/yafg)\n- [Markdown Checklist](https://github.com/FND/markdown-checklist)\n- [PyMdown Extensions](https://facelessuser.github.io/pymdown-extensions/)\n\t- [Caret](https://facelessuser.github.io/pymdown-extensions/extensions/caret/)\n\t- [Tilde](https://facelessuser.github.io/pymdown-extensions/extensions/tilde/)\n\t- [Mark](https://facelessuser.github.io/pymdown-extensions/extensions/mark/)\n\n## Installation\n\nInstall with `pip`:\n\n```sh\npip install pyssg\n```\n\nProbably will add a PKBUILD (and possibly submit it to the AUR) in the future.\n\n## Usage\n\n1. Get the default configuration file:\n\n```sh\npyssg --copy-default-config -c <path/to/config>\n```\n\n- Where `-c` is optional as by default `$XDG_CONFIG_HOME/pyssg/config.yaml` is used.\n\n2. Edit the config file created as needed.\n\n- `config.yaml` is parsed using [`PyYAML`](https://pyyaml.org/), [more about the config file](#config-file).\n\n3. Initialize the directory structures (source, destination, template) and move template files:\n\n```sh\npyssg -i\n```\n\n- You can modify the basic templates as needed (see [variables available for Jinja](#available-jinja-variables)).\n\n- Strongly recommended to edit the `rss.xml` template.\n\n4. Place your `*.md` files somewhere inside the source directory. It accepts sub-directories.\n\n- Recommended (no longer mandatory) metadata keys that can be added to the top of `.md` files:\n\n```\ntitle: the title of your blog entry or whatever\nauthor: your name or online handle\n\tanother name maybe for multiple authors?\nlang: the language the entry is written on\nsummary: a summary of the entry\ntags: english\n\tshort\n\ttutorial\n\tetc\n```\n\n- You can add more meta-data keys as long as it is [Python-Markdown compliant](https://python-markdown.github.io/extensions/meta_data/), and these will ve [available as Jinja variables](#available-jinja-variables).\n\n5. Build the `*.html` with:\n\n```sh\npyssg -b\n```\n\n- After this, you have ready to deploy `*.html` files.\n\n## Config file\n\nAll sections/options need to be compliant with [`PyYAML`](https://pyyaml.org/) which should be compliant with [`YAML 1.2`](https://yaml.org/spec/1.2.2/). Additionaly, I've added the custom tag `!join` which concatenates strings from an array, which an be used as follows:\n\n```yaml\nvariable: &variable_reference_name \"value\"\nother_variable: !join [*variable_reference_name, \"other_value\", 1]\n```\n\nWhich would produce `other_variable: \"valueother_value1\"`. Also environment variables will be expanded internally.\n\nThe following is a list of config items that need to be present in the config unless stated otherwise:\n\n```yaml\n%YAML 1.2\n---\n# not needed, shown here as an example of the !join tag\ndefine: &root \"$HOME/path/to/\" # $HOME expands to /home/user, for example\n\ntitle: \"Example site\"\npath:\n  src: !join [*root, \"src\"] # $HOME/path/to/src\n  dst: \"$HOME/some/other/path/to/dst\"\n  plt: \"plt\"\n  db: !join [*root, \"src/\", \"db.psv\"]\nurl:\n  main: \"https://example.com\"\nfmt:\n  date: \"%a, %b %d, %Y @ %H:%M %Z\"\n  list_date: \"%b %d\"\n  list_sep_date: \"%B %Y\"\ndirs:\n  /: # root \"dir_path\", whatever is sitting directly under \"src\"\n\tcfg:\n\t  plt: \"page.html\"\n\t  # the template can be specified instead of just True/False, a default template will used\n\t  tags: False\n\t  index: True\n\t  rss: True\n\t  sitemap: True\n\t  exclude_dirs: [\"articles\", \"blog\"] # optional; list of subdirectories to exclude when parsing the / dir_path\n# below are other example \"dir_paths\", can be named anything, only the / (above) is mandatory\n  articles:\n    cfg:\n\t  plt: \"page.html\"\n\t  tags: True\n\t  index: True\n\t  rss: True\n\t  sitemap: True\n  blog:\n    cfg:\n\t  # ...\n...\n```\n\nThe config under `dirs` are just per-subdirectory configuration of directories under `src`. Only the `/` \"dir_path\" is required as it is the config for the root `src` path files.\n\nThe following will be added on runtime:\n\n```yaml\n%YAML 1.2\n---\nfmt:\n  rss_date: \"%a, %d %b %Y %H:%M:%S GMT\" # fixed\n  sitemap_date: \"%Y-%m-%d\" # fixed\ninfo:\n  version: \"x.y.z\" # current 'pyssg' version (0.5.1.dev16, for example)\n  debug: True/False # depending if --debug was used when executing\n  force: True/False # depending if --force was used when executing\nrss_run_date: # date the program was run, formatted with 'fmt.rss_date'\nsitemap_run_date: # date the program was run, formatted with 'fmt.sitemap_date'\n...\n```\n\nYou can add any other option/section that you can later use in the Jinja templates via the exposed config object. URL's shouldn't have the trailing slash `/`\n\n## Available Jinja variables\n\nThese variables are exposed to use within the templates. The below list is displayed in the form of *variable (type) (available from): description*. `field1/field2/field3/...` describe config file section from the YAML file and option and `object.attribute` corresponding object and it's attribute.\n\n- `config` (`dict`) (all): parsed config file plus the added options internally (as described in [config file](#config-file)).\n- `dir_config` (`dict`) (all*): parsed dir_config file plus the added options internally (as described in [config file](#config-file)). *This is for all of the specific \"dir_path\" files, as per configured in the YAML file `dirs.dir_path.cfg` (for exmaple `dirs./.cfg` for the required dir_path).\n- `all_pages` (`list(Page)`) (all): list of all the pages, sorted by creation time, reversed.\n- `page` (`Page`) (`page.html`): contains the following attributes (genarally these are parsed from the metadata in the `*.md` files):\n\t- `title` (`str`): title of the page.\n\t- `author` (`list[str]`): list of authors of the page.\n\t- `lang` (`str`): page language, used for the general `html` tag `lang` attribute.\n\t- `summary` (`str`): summary of the page, as specified in the `*.md` file.\n\t- `content` (`str`): actual content of the page, this is the `html`.\n\t- `cdatetime` (`datetime.datetime`): creation datetime object of the page.\n\t- `cdate` (`method`): method thtat takes the name of the `fmt.FMT` and applies it to the `cdatetime` object.\n\t- `cdate_rss` (`str`): formatted `cdatetime` as required by rss.\n\t- `cdate_sitemap` (`str`): formatted `cdatetime` as required by sitemap.\n\t- `mdatetime` (`datetime.datetime`): modification datetime object of the page. Defaults to `None`.\n\t- `mdate` (`method`): method thtat takes the name of the `fmt.FMT` and applies it to the `mdatetime` object.\n\t- `mdate_rss` (`str`): formatted `mdatetime` as required by rss.\n\t- `mdate_sitemap` (`str`): formatted `mdatetime` as required by sitemap.\n\t- `tags` (`list(tuple(str))`): list of tuple of tags of the page, containing the name and the url of the tag, in that order. Defaults to empty list.\n\t- `url` (`str`): url of the page, this already includes the `url/main` from config file.\n\t- `image_url` (`str`): image url of the page, this already includes the `url/static`. Defaults to the `url/default_image` config option.\n\t- `next/previous` (`Page`): reference to the next or previous page object (containing all these attributes). Defaults to `None`.\n\t- `og` (`dict(str, str)`): dict for object graph metadata.\n\t- `meta` (`dict(str, list(str))`): meta dict as obtained from python-markdown, in case you use a meta tag not yet supported, it will be available there.\n- `tag` (`tuple(str)`) (`tag.html`): tuple of name and url of the current tag.\n- `tag_pages` (`list(Page)`) (`tag.html`): similar to `all_pages` but contains all the pages for the current tag.\n- `all_tags` (`list(tuple(str))`) (all): similar to `page.tags` but contains all the tags.\n\n",
    "bugtrack_url": null,
    "license": "GPLv3",
    "summary": "A Static Site Generator using markdown files",
    "version": "0.8.3",
    "split_keywords": [
        "python",
        "static",
        "site",
        "generator",
        "markdown"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "73ee4310aed779809e0f2e69adde2b9c",
                "sha256": "7c5a29723dfa88608c92b1bd5435aee3f8cfeb815a432cc7af141c3b270be7d3"
            },
            "downloads": -1,
            "filename": "pyssg-0.8.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "73ee4310aed779809e0f2e69adde2b9c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 37213,
            "upload_time": "2022-12-27T09:00:39",
            "upload_time_iso_8601": "2022-12-27T09:00:39.290971Z",
            "url": "https://files.pythonhosted.org/packages/7c/c9/f24fa3057ec4ba9be00faecff8bf4575d7d962c6a278801a636b8e6e56a8/pyssg-0.8.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "cec99d23d386084f42db2df7401c97d6",
                "sha256": "518e16e2a96ff94dd8972d92670e3a09201c4522224b66573058ac36d0dbd0a4"
            },
            "downloads": -1,
            "filename": "pyssg-0.8.3.tar.gz",
            "has_sig": false,
            "md5_digest": "cec99d23d386084f42db2df7401c97d6",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 6507458,
            "upload_time": "2022-12-27T09:00:46",
            "upload_time_iso_8601": "2022-12-27T09:00:46.167805Z",
            "url": "https://files.pythonhosted.org/packages/42/f7/856b7b1db77f83e6ec31631c4362de9f513a99764b7a4f77667acdc28221/pyssg-0.8.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-12-27 09:00:46",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "luevano",
    "github_project": "pyssg",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [],
    "lcname": "pyssg"
}
        
Elapsed time: 0.02157s