diff options
-rw-r--r-- | Dockerfile | 3 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | _posts/2018/01/new-blog.rst | 72 | ||||
-rw-r--r-- | all.rss.xml | 18 | ||||
-rw-r--r-- | conf.py | 2 | ||||
-rw-r--r-- | rss.py | 64 |
6 files changed, 3 insertions, 164 deletions
@@ -14,8 +14,7 @@ ADD . /app | |||
14 | 14 | ||
15 | WORKDIR /app | 15 | WORKDIR /app |
16 | 16 | ||
17 | RUN /bin/bash -c "source /app/.venv/bin/activate && make html && make rss && cp rss.xml _build/html" | 17 | RUN /bin/bash -c "source /app/.venv/bin/activate && make html" |
18 | |||
19 | 18 | ||
20 | FROM alpine:latest | 19 | FROM alpine:latest |
21 | 20 | ||
@@ -1,10 +1,7 @@ | |||
1 | # Minimal makefile for Sphinx documentation | ||
2 | # | ||
3 | |||
4 | # You can set these variables from the command line. | 1 | # You can set these variables from the command line. |
5 | SPHINXOPTS = | 2 | SPHINXOPTS = |
6 | SPHINXBUILD = sphinx-build | 3 | SPHINXBUILD = sphinx-build |
7 | SPHINXPROJ = ring0xyz | 4 | SPHINXPROJ = blog |
8 | SOURCEDIR = . | 5 | SOURCEDIR = . |
9 | BUILDDIR = _build | 6 | BUILDDIR = _build |
10 | 7 | ||
@@ -12,9 +9,6 @@ BUILDDIR = _build | |||
12 | help: | 9 | help: |
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) | 10 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) |
14 | 11 | ||
15 | rss: | ||
16 | python rss.py > rss.xml | ||
17 | |||
18 | .PHONY: help Makefile | 12 | .PHONY: help Makefile |
19 | 13 | ||
20 | # Catch-all target: route all unknown targets to Sphinx using the new | 14 | # Catch-all target: route all unknown targets to Sphinx using the new |
diff --git a/_posts/2018/01/new-blog.rst b/_posts/2018/01/new-blog.rst deleted file mode 100644 index a638797..0000000 --- a/_posts/2018/01/new-blog.rst +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | :orphan: | ||
2 | |||
3 | .. _2018newblog: | ||
4 | |||
5 | 又一个新的博客 | ||
6 | ============== | ||
7 | |||
8 | :Publish Date: 2018-01-15 | ||
9 | |||
10 | 前段时间有朋友和我抱怨博客加载速度太慢了(。之前的博客架在Blogger上,为了让排版稍微美观一些,找了一个第三方的主题,加载了许多外部的 | ||
11 | 资源,导致网页载入速度非常慢。虽然我自己对于网站在国内的加载速度毫不在意,但是既然还有读者(少的可怜)在看,以及在这极少的读者中有用 | ||
12 | 户提出了这个问题,那就得解决。前段时间无意中看到一个博客( `git-pull`_ ),觉得主题简洁而又美观,于是开始 | ||
13 | 着手改造自己的博客。 | ||
14 | |||
15 | .. _git-pull: https://www.git-pull.com/index.html | ||
16 | |||
17 | 这次用了「大名鼎鼎」的 `Sphinx`_ ,一个软件开发过程中的文档生成工具来作为博客的静态网页生成引擎。 | ||
18 | 上手Sphinx非常简单,sphinx-quickstart这个工具和一般的博客生成器一样,集成了很多功能,把Makefile都写好了,可以说是完全开箱即用了。 | ||
19 | Sphinx的默认主题是 `Alabaster`_ ,现在你看到的这个主题就是在Alabaster上修改而来的。 | ||
20 | |||
21 | Sphinx的文档书写采用的是*.rst格式的文本,即 `reStructuredText`_ ,而不是Markdown。相比 | ||
22 | 之前,rst比Markdown的语法更加丰富/复杂,同时也提供了更加丰富的功能和可扩展性(虽然我估计我只能用到其中的20%甚至更少啦)。不清楚rst和 | ||
23 | Emacs社区的 `Org Mode`_ 相比哪一个的语法更加复杂呢。( | ||
24 | |||
25 | 建设博客离不开几件事情。首先当然就是部署运维啦。Sphinx通过Makefile可以生成静态html网页,托管静态html最方便的地方当然是GitHub Pages啦。 | ||
26 | 最简单粗暴的方法是在本地的环境中写完rst文本,然后本地 make html 通过之后,将html推送到GitHub Pages中。但是这种方式的移植性不高,想写 | ||
27 | 博客的话必须坐在自己的电脑前,同时依然存在一些手动的工作。所以当然选择Docker啦。但是这次用Docker的姿势和以往不同。平时我们用Docker的时候 | ||
28 | 最终都是想要得到docker build的产物docker image,然后由image来进行部署。但是我们这次的目标是GitHub Pages,没法部署容器。所以我在 | ||
29 | Dockerfile中生成静态html网页,然后在构建的过程中将静态网页push到repo的gh-pages分支中。当然其实不用Docker也能做到这一点。写一个脚本, | ||
30 | 然后在CI平台上执行脚本也行,就不做优劣对比了。 | ||
31 | |||
32 | 值得一提的是,Docker在17.05-ce版本之后引入了multi stage build的功能,可以在Dockerfile中FROM多个基础镜像,在下一个stage可以直接使用 | ||
33 | 之前stage构建出的产物。以我的博客这个项目为例。假如我是想通过image来部署,那么我最终的产物是静态html文件,那么我可能需要一个nginx的基础 | ||
34 | 镜像。nginx:alpine 这个基础镜像很小,不到10MB,在Dockerfile里面将html文件COPY进去之后,最终得到的image也只有10MB左右的大小。但是 | ||
35 | 之前我们为了得到静态html文件,可能得选用一个python的基础镜像,然后再apt/apk安装一些必要的编译工具,最终只是为了几百kb的html文件,但是 | ||
36 | 构建的镜像已经上百MB了。有了multi stage build之后,这个问题便非常好地被解决了。看了下面的Dockerfile之后,整体思路就非常清晰了。目前我 | ||
37 | 在本地写完rst文本,然后git push之后,CircleCI会自动进行Dockerfile的构建,然后将编译生成的静态html推送到gh-pages分支。 | ||
38 | |||
39 | .. raw:: html | ||
40 | |||
41 | <embed> | ||
42 | <script src="https://gist.github.com/clarkzjw/0cb4e15794a5a132b12df9741e0cc1e0.js"></script> | ||
43 | </embed> | ||
44 | |||
45 | 另外一个问题是博客的RSS。由于Sphinx最初的设计是作为一个文档生成工具,目前市面上有的和Sphinx结合的RSS生成工具大致有: | ||
46 | |||
47 | - Sphinx-contrib模块中的 `feed <https://bitbucket.org/birkenfeld/sphinx-contrib/src/tip/feed/>`__ | ||
48 | |||
49 | - 在sphinxcontrib.feed基础上开发的 `sphinxfeed <https://github.com/junkafarian/sphinxfeed>`__ | ||
50 | |||
51 | - 以及更新一点的 `sphinxcontrib-newsfeed <https://pypi.python.org/pypi/sphinxcontrib-newsfeed>`__ | ||
52 | |||
53 | 其中sphinxcontrib.feed和sphinxfeed的功能性更新都停止在2011年,不兼容Python 3,GitHub上有几个fork,但是也基本没有太多的改进。至于 | ||
54 | sphinxcontrib-newsfeed,并不能生成符合RSS规范的输出。。。所以只好自己简单粗暴造一个轮子了!(至少生成的xml能被RSS阅读器认识。。。 | ||
55 | |||
56 | RSS 订阅地址是 https://blog.jinwei.me/rss | ||
57 | |||
58 | 至于评论嘛。虽然博客流量小,2017年下来一年也没有10条评论,但是作为一个博客,这个功能还是必须得有!考察了目前市面上的评论方案,Disqus现在 | ||
59 | 差不多可以算是一家独大了。但是十分不喜欢Disqus。一个页面要加载的无关的数据太多了。然后看到了 `Isso`_ , 第一印象还不错,但是需要自己单独部 | ||
60 | 署。为了一年10条评论不到的数量级单独部署似乎成本略高。之前还见到了 `Staticman`_ , 但是这个方案和GitHub的issue绑定,一个博客实例对应 | ||
61 | GitHub的一个repo,然后每篇文章的评论对应这个repo中的issue。但是我不太能接受,毕竟不能强制每个评论的用户都有GitHub帐号。 | ||
62 | 今天无意中看到了 `just-comments`_ , 也是一个SaaS解决方案,但是非常地极简,决定先用着试试效果。( | ||
63 | |||
64 | 下一步,打算在博客中加入 `漢字標準格式 <https://css.hanzi.co/>`_ 这套排版框架。毕竟现在的页面排版看起来怪怪的,以及并不美观。( | ||
65 | |||
66 | .. _Org Mode: https://orgmode.org/ | ||
67 | .. _reStructuredText: http://docutils.sourceforge.net/rst.html | ||
68 | .. _Alabaster: https://alabaster.readthedocs.io/en/latest/ | ||
69 | .. _Sphinx: http://www.sphinx-doc.org/en/stable/ | ||
70 | .. _Isso: https://github.com/posativ/isso | ||
71 | .. _Staticman: https://staticman.net | ||
72 | .. _just-comments: https://just-comments.com/ | ||
diff --git a/all.rss.xml b/all.rss.xml deleted file mode 100644 index cafc7fd..0000000 --- a/all.rss.xml +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> | ||
3 | <channel> | ||
4 | <title>{{ site.name }}</title> | ||
5 | <link>{{ site.url }}</link> | ||
6 | <description>{{ site.tagline }}</description> | ||
7 | <atom:link href="{{ site.url }}/rss" rel="self" type="application/rss+xml" /> | ||
8 | {% for post in posts[:20] %} | ||
9 | <item> | ||
10 | <title>{{ post.title | e }}</title> | ||
11 | <description>{{ post.body | e }}</description> | ||
12 | <pubDate>{{ post.date_rss }}</pubDate> | ||
13 | <link>{{ site.url }}/{{ post.permalink }}</link> | ||
14 | <guid isPermaLink="true">{{ site.url }}/{{ post.permalink }}</guid> | ||
15 | </item> | ||
16 | {% endfor %} | ||
17 | </channel> | ||
18 | </rss> | ||
@@ -20,7 +20,7 @@ source_suffix = '.rst' | |||
20 | master_doc = 'index' | 20 | master_doc = 'index' |
21 | 21 | ||
22 | project = u'' | 22 | project = u'' |
23 | copyright = u'2013 - 2019, clarkzjw' # NOQA | 23 | copyright = u'2013 - 2020, clarkzjw' # NOQA |
24 | 24 | ||
25 | version = '0.0' | 25 | version = '0.0' |
26 | release = '0.0' | 26 | release = '0.0' |
@@ -1,64 +0,0 @@ | |||
1 | import glob | ||
2 | import os | ||
3 | |||
4 | import jinja2 | ||
5 | from bs4 import BeautifulSoup | ||
6 | |||
7 | |||
8 | class FilePathLoader(jinja2.BaseLoader): | ||
9 | def __init__(self, cwd): | ||
10 | self.cwd = cwd | ||
11 | |||
12 | def get_source(self, environment, template): | ||
13 | filename = os.path.join(self.cwd, template) | ||
14 | |||
15 | try: | ||
16 | with open(filename, 'r') as f: | ||
17 | contents = f.read() | ||
18 | except IOError: | ||
19 | raise jinja2.TemplateNotFound(filename) | ||
20 | |||
21 | return contents, filename, lambda: False | ||
22 | |||
23 | |||
24 | def render_template(cwd, template_path, context): | ||
25 | env = jinja2.Environment(loader=FilePathLoader(cwd)) | ||
26 | return env.get_template(template_path).render(context) | ||
27 | |||
28 | |||
29 | def main(): | ||
30 | |||
31 | filenames = glob.glob("./_build/html/_posts/*/*/*.html") | ||
32 | posts = [] | ||
33 | |||
34 | for file in filenames: | ||
35 | soup = BeautifulSoup(open(file), "html5lib") | ||
36 | body = soup.find_all("div", class_="body")[0].text | ||
37 | |||
38 | posts.append({ | ||
39 | "title": soup.title.string, | ||
40 | "body": body, | ||
41 | "date_rss": body[body.find("Publish Date:")+13:body.find("Publish Date:")+23], | ||
42 | "permalink": "/".join(file.split("/")[3:]) | ||
43 | }) | ||
44 | with open(file, "w") as file: | ||
45 | file.write(str(BeautifulSoup(str(soup).replace("\n", "").replace("\r", ""), "html5lib").prettify())) | ||
46 | |||
47 | context = { | ||
48 | "site": { | ||
49 | "name": "Hello World", | ||
50 | "url": "https://blog.jinwei.me", | ||
51 | "tagline": "Freedom is my birth right and I shall have it." | ||
52 | }, | ||
53 | "posts": posts | ||
54 | } | ||
55 | |||
56 | return render_template( | ||
57 | ".", | ||
58 | "all.rss.xml", | ||
59 | context | ||
60 | ) | ||
61 | |||
62 | |||
63 | if __name__ == '__main__': | ||
64 | print(main()) | ||