From a9c3cc1abb94b838bba35bd4ea9532874db5f4c9 Mon Sep 17 00:00:00 2001
From: Adar Nimrod <nimrod@shore.co.il>
Date: Fri, 13 Apr 2018 22:20:30 +0300
Subject: [PATCH] Revamped automation.

- Hard dependency on Python 3.6.
- Migrated from tox to pipenv.
- Minimized diff between pelicanconf.py and publishconf.py (dev and
prod).
- Updated .gitignore.
- Simplified some Fabric tasks, removed unused tasks (requires Python
3.6).
- Added local dev server with auto-regenerated files Fabric task.
- Removed develop_server.sh and Makefile, Fabric does everything.
- Changed README from reStructuredText to Markdown, updated content.
- Added .envrc for easy pipenv support for development.
- Reran pelican-quickstart from the latest release, applied changes.
- Corrections for working links in local dev, no longer needs
pelican.serve, Python http.server works just as well.
---
 .envrc            |   2 +
 .gitignore        |  56 ++++++++--
 Makefile          | 108 -------------------
 Pipfile           |  13 +++
 Pipfile.lock      | 265 ++++++++++++++++++++++++++++++++++++++++++++++
 README.md         |  37 +++++++
 README.rst        |  11 --
 develop_server.sh | 103 ------------------
 fabfile.py        |  53 +++++-----
 pelicanconf.py    |  28 ++---
 publishconf.py    |  16 ---
 tox.ini           |  25 -----
 12 files changed, 404 insertions(+), 313 deletions(-)
 create mode 100755 .envrc
 delete mode 100644 Makefile
 create mode 100644 Pipfile
 create mode 100644 Pipfile.lock
 create mode 100644 README.md
 delete mode 100644 README.rst
 delete mode 100755 develop_server.sh
 delete mode 100644 tox.ini

diff --git a/.envrc b/.envrc
new file mode 100755
index 0000000..f270360
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,2 @@
+source_up
+layout pipenv
diff --git a/.gitignore b/.gitignore
index c225913..e2e995d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,50 @@
-output/
-cache/
-.cache/
-.tox/
-*.log
+~*
+*~
+*.sw[op]
 *.py[cod]
+.DS_Store
 __pycache__/
-*~
-~*
-*.sw[po]
+.vagrant/
+vendor/
+Thumbs.db
+*.retry
+.svn/
+.sass-cache/
+*.log
+*.out
+*.so
+node_modules/
+.npm/
+nbproject/
+*.ipynb
+.idea/
+*.egg-info/
+*.[ao]
+.classpath
+.cache/
+bower_components/
+*.class
+*.[ewj]ar
+secring.*
+.*.kate-swp
+.swp.*
+.directory
+.Trash-*
+build/
+_build/
+dist/
+.tox/
+*.pdf
+*.exe
+*.dll
+*.gz
+*.tgz
+*.tar
+*.rar
+*.zip
+*.pid
+*.lock
+*.env
+.bundle/
+!Pipfile.lock
+output/
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 2a85726..0000000
--- a/Makefile
+++ /dev/null
@@ -1,108 +0,0 @@
-PY=python
-PELICAN=pelican
-PELICANOPTS=
-
-BASEDIR=$(CURDIR)
-INPUTDIR=$(BASEDIR)/content
-OUTPUTDIR=$(BASEDIR)/output
-CONFFILE=$(BASEDIR)/pelicanconf.py
-PUBLISHCONF=$(BASEDIR)/publishconf.py
-
-FTP_HOST=localhost
-FTP_USER=anonymous
-FTP_TARGET_DIR=/
-
-SSH_HOST=ns1.shore.co.il
-SSH_PORT=22
-SSH_USER=nimrod
-SSH_TARGET_DIR=/var/www/htdocs/blog
-
-S3_BUCKET=my_s3_bucket
-
-CLOUDFILES_USERNAME=my_rackspace_username
-CLOUDFILES_API_KEY=my_rackspace_api_key
-CLOUDFILES_CONTAINER=my_cloudfiles_container
-
-DROPBOX_DIR=~/Dropbox/Public/
-
-DEBUG ?= 0
-ifeq ($(DEBUG), 1)
-	PELICANOPTS += -D
-endif
-
-help:
-	@echo 'Makefile for a pelican Web site                                        '
-	@echo '                                                                       '
-	@echo 'Usage:                                                                 '
-	@echo '   make html                        (re)generate the web site          '
-	@echo '   make clean                       remove the generated files         '
-	@echo '   make regenerate                  regenerate files upon modification '
-	@echo '   make publish                     generate using production settings '
-	@echo '   make serve [PORT=8000]           serve site at http://localhost:8000'
-	@echo '   make devserver [PORT=8000]       start/restart develop_server.sh    '
-	@echo '   make stopserver                  stop local server                  '
-	@echo '   make ssh_upload                  upload the web site via SSH        '
-	@echo '   make rsync_upload                upload the web site via rsync+ssh  '
-	@echo '   make dropbox_upload              upload the web site via Dropbox    '
-	@echo '   make ftp_upload                  upload the web site via FTP        '
-	@echo '   make s3_upload                   upload the web site via S3         '
-	@echo '   make cf_upload                   upload the web site via Cloud Files'
-	@echo '   make github                      upload the web site via gh-pages   '
-	@echo '                                                                       '
-	@echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html'
-	@echo '                                                                       '
-
-html:
-	$(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
-
-clean:
-	[ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR)
-
-regenerate:
-	$(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
-
-serve:
-ifdef PORT
-	cd $(OUTPUTDIR) && $(PY) -m pelican.server $(PORT)
-else
-	cd $(OUTPUTDIR) && $(PY) -m pelican.server
-endif
-
-devserver:
-ifdef PORT
-	$(BASEDIR)/develop_server.sh restart $(PORT)
-else
-	$(BASEDIR)/develop_server.sh restart
-endif
-
-stopserver:
-	kill -9 `cat pelican.pid`
-	kill -9 `cat srv.pid`
-	@echo 'Stopped Pelican and SimpleHTTPServer processes running in background.'
-
-publish:
-	$(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
-
-ssh_upload: publish
-	scp -P $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
-
-rsync_upload: publish
-	rsync -e "ssh -p $(SSH_PORT)" -P -rvz --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude
-
-dropbox_upload: publish
-	cp -r $(OUTPUTDIR)/* $(DROPBOX_DIR)
-
-ftp_upload: publish
-	lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit"
-
-s3_upload: publish
-	s3cmd sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --acl-public --delete-removed
-
-cf_upload: publish
-	cd $(OUTPUTDIR) && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) .
-
-github: publish
-	ghp-import $(OUTPUTDIR)
-	git push origin gh-pages
-
-.PHONY: html help clean regenerate serve devserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github
diff --git a/Pipfile b/Pipfile
new file mode 100644
index 0000000..4dba548
--- /dev/null
+++ b/Pipfile
@@ -0,0 +1,13 @@
+[[source]]
+url = "https://pypi.python.org/simple"
+verify_ssl = true
+name = "pypi"
+
+[packages]
+pelican = "*"
+"fabric3" = "*"
+
+[dev-packages]
+
+[requires]
+python_version = "3.6"
diff --git a/Pipfile.lock b/Pipfile.lock
new file mode 100644
index 0000000..1e0ae4f
--- /dev/null
+++ b/Pipfile.lock
@@ -0,0 +1,265 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "99a7866438caf331d7a71c217ae528ee63dca44541edef81efe180dbef28acc3"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.6"
+        },
+        "sources": [
+            {
+                "name": "pypi",
+                "url": "https://pypi.python.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "asn1crypto": {
+            "hashes": [
+                "sha256:2f1adbb7546ed199e3c90ef23ec95c5cf3585bac7d11fb7eb562a3fe89c64e87",
+                "sha256:9d5c20441baf0cb60a4ac34cc447c6c189024b6b4c6cd7877034f4965c464e49"
+            ],
+            "version": "==0.24.0"
+        },
+        "bcrypt": {
+            "hashes": [
+                "sha256:01477981abf74e306e8ee31629a940a5e9138de000c6b0898f7f850461c4a0a5",
+                "sha256:054d6e0acaea429e6da3613fcd12d05ee29a531794d96f6ab959f29a39f33391",
+                "sha256:0872eeecdf9a429c1420158500eedb323a132bc5bf3339475151c52414729e70",
+                "sha256:09a3b8c258b815eadb611bad04ca15ec77d86aa9ce56070e1af0d5932f17642a",
+                "sha256:0f317e4ffbdd15c3c0f8ab5fbd86aa9aabc7bea18b5cc5951b456fe39e9f738c",
+                "sha256:2788c32673a2ad0062bea850ab73cffc0dba874db10d7a3682b6f2f280553f20",
+                "sha256:321d4d48be25b8d77594d8324c0585c80ae91ac214f62db9098734e5e7fb280f",
+                "sha256:346d6f84ff0b493dbc90c6b77136df83e81f903f0b95525ee80e5e6d5e4eef84",
+                "sha256:34dd60b90b0f6de94a89e71fcd19913a30e83091c8468d0923a93a0cccbfbbff",
+                "sha256:3b4c23300c4eded8895442c003ae9b14328ae69309ac5867e7530de8bdd7875d",
+                "sha256:43d1960e7db14042319c46925892d5fa99b08ff21d57482e6f5328a1aca03588",
+                "sha256:49e96267cd9be55a349fd74f9852eb9ae2c427cd7f6455d0f1765d7332292832",
+                "sha256:67ed1a374c9155ec0840214ce804616de49c3df9c5bc66740687c1c9b1cd9e8d",
+                "sha256:6efd9ca20aefbaf2e7e6817a2c6ed4a50ff6900fafdea1bcb1d0e9471743b144",
+                "sha256:8569844a5d8e1fdde4d7712a05ab2e6061343ac34af6e7e3d7935b2bd1907bfd",
+                "sha256:8629ea6a8a59f865add1d6a87464c3c676e60101b8d16ef404d0a031424a8491",
+                "sha256:988cac675e25133d01a78f2286189c1f01974470817a33eaf4cfee573cfb72a5",
+                "sha256:9a6fedda73aba1568962f7543a1f586051c54febbc74e87769bad6a4b8587c39",
+                "sha256:9eced8962ce3b7124fe20fd358cf8c7470706437fa064b9874f849ad4c5866fc",
+                "sha256:a005ed6163490988711ff732386b08effcbf8df62ae93dd1e5bda0714fad8afb",
+                "sha256:ae35dbcb6b011af6c840893b32399252d81ff57d52c13e12422e16b5fea1d0fb",
+                "sha256:b1e8491c6740f21b37cca77bc64677696a3fb9f32360794d57fa8477b7329eda",
+                "sha256:c906bdb482162e9ef48eea9f8c0d967acceb5c84f2d25574c7d2a58d04861df1",
+                "sha256:cb18ffdc861dbb244f14be32c47ab69604d0aca415bee53485fcea4f8e93d5ef",
+                "sha256:d86da365dda59010ba0d1ac45aa78390f56bf7f992e65f70b3b081d5e5257b09",
+                "sha256:e22f0997622e1ceec834fd25947dc2ee2962c2133ea693d61805bc867abaf7ea",
+                "sha256:f2fe545d27a619a552396533cddf70d83cecd880a611cdfdbb87ca6aec52f66b",
+                "sha256:f7fd3ed3745fe6e81e28dc3b3d76cce31525a91f32a387e1febd6b982caf8cdb",
+                "sha256:f9210820ee4818d84658ed7df16a7f30c9fba7d8b139959950acef91745cc0f7"
+            ],
+            "version": "==3.1.4"
+        },
+        "blinker": {
+            "hashes": [
+                "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"
+            ],
+            "version": "==1.4"
+        },
+        "cffi": {
+            "hashes": [
+                "sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
+                "sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
+                "sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
+                "sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
+                "sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93",
+                "sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257",
+                "sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3",
+                "sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc",
+                "sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04",
+                "sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6",
+                "sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359",
+                "sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596",
+                "sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b",
+                "sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd",
+                "sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95",
+                "sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e",
+                "sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6",
+                "sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca",
+                "sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31",
+                "sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1",
+                "sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085",
+                "sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801",
+                "sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4",
+                "sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184",
+                "sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917",
+                "sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
+                "sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
+            ],
+            "version": "==1.11.5"
+        },
+        "cryptography": {
+            "hashes": [
+                "sha256:3f3b65d5a16e6b52fba63dc860b62ca9832f51f1a2ae5083c78b6840275f12dd",
+                "sha256:551a3abfe0c8c6833df4192a63371aa2ff43afd8f570ed345d31f251d78e7e04",
+                "sha256:5cb990056b7cadcca26813311187ad751ea644712022a3976443691168781b6f",
+                "sha256:60bda7f12ecb828358be53095fc9c6edda7de8f1ef571f96c00b2363643fa3cd",
+                "sha256:6fef51ec447fe9f8351894024e94736862900d3a9aa2961528e602eb65c92bdb",
+                "sha256:77d0ad229d47a6e0272d00f6bf8ac06ce14715a9fd02c9a97f5a2869aab3ccb2",
+                "sha256:808fe471b1a6b777f026f7dc7bd9a4959da4bfab64972f2bbe91e22527c1c037",
+                "sha256:9b62fb4d18529c84b961efd9187fecbb48e89aa1a0f9f4161c61b7fc42a101bd",
+                "sha256:9e5bed45ec6b4f828866ac6a6bedf08388ffcfa68abe9e94b34bb40977aba531",
+                "sha256:9fc295bf69130a342e7a19a39d7bbeb15c0bcaabc7382ec33ef3b2b7d18d2f63",
+                "sha256:abd070b5849ed64e6d349199bef955ee0ad99aefbad792f0c587f8effa681a5e",
+                "sha256:ba6a774749b6e510cffc2fb98535f717e0e5fd91c7c99a61d223293df79ab351",
+                "sha256:c332118647f084c983c6a3e1dba0f3bcb051f69d12baccac68db8d62d177eb8a",
+                "sha256:d6f46e862ee36df81e6342c2177ba84e70f722d9dc9c6c394f9f1f434c4a5563",
+                "sha256:db6013746f73bf8edd9c3d1d3f94db635b9422f503db3fc5ef105233d4c011ab",
+                "sha256:f57008eaff597c69cf692c3518f6d4800f0309253bb138b526a37fe9ef0c7471",
+                "sha256:f6c821ac253c19f2ad4c8691633ae1d1a17f120d5b01ea1d256d7b602bc59887"
+            ],
+            "version": "==2.2.2"
+        },
+        "docutils": {
+            "hashes": [
+                "sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
+                "sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
+                "sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
+            ],
+            "version": "==0.14"
+        },
+        "fabric3": {
+            "hashes": [
+                "sha256:647e485ec83f30b587862f92374d6affc217f3d79819d1d7f512e42e7ae51e81",
+                "sha256:7c5a5f2eb3079eb6bd2a69931f1ca298844c730ce3fdc68111db16e8857a0408"
+            ],
+            "index": "pypi",
+            "version": "==1.14.post1"
+        },
+        "feedgenerator": {
+            "hashes": [
+                "sha256:5ae05daa9cfa47fa406ee4744d0b7fa1c8a05a7a47ee0ad328ddf55327cfb106"
+            ],
+            "version": "==1.9"
+        },
+        "idna": {
+            "hashes": [
+                "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
+                "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"
+            ],
+            "version": "==2.6"
+        },
+        "jinja2": {
+            "hashes": [
+                "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
+                "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
+            ],
+            "version": "==2.10"
+        },
+        "markupsafe": {
+            "hashes": [
+                "sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
+            ],
+            "version": "==1.0"
+        },
+        "paramiko": {
+            "hashes": [
+                "sha256:24fb31c947de85fbdeca09e222d41206781581fb0bdf118d2ef18f6e414cd388",
+                "sha256:33e36775a6c71790ba7692a73f948b329cf9295a72b0102144b031114bd2a4f3"
+            ],
+            "version": "==2.4.1"
+        },
+        "pelican": {
+            "hashes": [
+                "sha256:2a5347fe47464ee743bff99b6e81d1b5823f2e70e7be5bd6ed66a5bdd5f3578b",
+                "sha256:f1456c163a963d498abd741ea7c6f47984365ecd8bbd6e118c44e247815cb7ef"
+            ],
+            "index": "pypi",
+            "version": "==3.7.1"
+        },
+        "pyasn1": {
+            "hashes": [
+                "sha256:0d7f6e959fe53f3960a23d73f35e1fce61348b30915b6664309ca756de7c1f89",
+                "sha256:5a0db897b311d265cde49615cf783f1c78613138605cdd0f907ecfa5b2aba3ee",
+                "sha256:758cb50abddc03e4563fd9e7f03db56e3e87b58c0bd01247360326e5c0c7ffa5",
+                "sha256:7d626683e3d792cccc608da02498aff37ab4f3dafd8905d6bf755d11f9b26b43",
+                "sha256:a7efe807c4b83a859e2735c692b92ed7b567cfddc4163763412920041d876c2b",
+                "sha256:b5a9ca48055b9a20f6d1b3d68e38692e5431c86a0f99ea602e61294e891fee5b",
+                "sha256:c07d6e587b2f928366b1f67c09bda026a3e6fcc99e80a744dc67f8fca3895626",
+                "sha256:d258b0a71994f7770599835249cece1caef3c70def868c4915e6e5ca49b67d15",
+                "sha256:d5cd6ed995dba16fad0c521cfe31cd2d68400b53fcc2bce93326829be73ab6d1",
+                "sha256:d84c2aea3cf43780e9e6a19f4e4dddee9f6976519020e64e47c57e5c7a8c3dd2",
+                "sha256:e85895087905c65b5b594eb91f7522664c85545b147d5f4d4e7b1b07da8dcbdc",
+                "sha256:f81c96761fca60d64b1c9b79ec2e40cf9495a745cf570613079ef324aeb9672b"
+            ],
+            "version": "==0.4.2"
+        },
+        "pycparser": {
+            "hashes": [
+                "sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
+            ],
+            "version": "==2.18"
+        },
+        "pygments": {
+            "hashes": [
+                "sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
+                "sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
+            ],
+            "version": "==2.2.0"
+        },
+        "pynacl": {
+            "hashes": [
+                "sha256:04e30e5bdeeb2d5b34107f28cd2f5bbfdc6c616f3be88fc6f53582ff1669eeca",
+                "sha256:0bfa0d94d2be6874e40f896e0a67e290749151e7de767c5aefbad1121cad7512",
+                "sha256:11aa4e141b2456ce5cecc19c130e970793fa3a2c2e6fbb8ad65b28f35aa9e6b6",
+                "sha256:13bdc1fe084ff9ac7653ae5a924cae03bf4bb07c6667c9eb5b6eb3c570220776",
+                "sha256:14339dc233e7a9dda80a3800e64e7ff89d0878ba23360eea24f1af1b13772cac",
+                "sha256:1d33e775fab3f383167afb20b9927aaf4961b953d76eeb271a5703a6d756b65b",
+                "sha256:2a42b2399d0428619e58dac7734838102d35f6dcdee149e0088823629bf99fbb",
+                "sha256:2dce05ac8b3c37b9e2f65eab56c544885607394753e9613fd159d5e2045c2d98",
+                "sha256:6453b0dae593163ffc6db6f9c9c1597d35c650598e2c39c0590d1757207a1ac2",
+                "sha256:73a5a96fb5fbf2215beee2353a128d382dbca83f5341f0d3c750877a236569ef",
+                "sha256:8abb4ef79161a5f58848b30ab6fb98d8c466da21fdd65558ce1d7afc02c70b5f",
+                "sha256:8ac1167195b32a8755de06efd5b2d2fe76fc864517dab66aaf65662cc59e1988",
+                "sha256:8f505f42f659012794414fa57c498404e64db78f1d98dfd40e318c569f3c783b",
+                "sha256:be71cd5fce04061e1f3d39597f93619c80cdd3558a6c9ba99a546f144a8d8101",
+                "sha256:cf6877124ae6a0698404e169b3ba534542cfbc43f939d46b927d956daf0a373a",
+                "sha256:d0eb5b2795b7ee2cbcfcadacbe95a13afbda048a262bd369da9904fecb568975",
+                "sha256:d795f506bcc9463efb5ebb0f65ed77921dcc9e0a50499dedd89f208445de9ecb",
+                "sha256:d8aaf7e5d6b0e0ef7d6dbf7abeb75085713d0100b4eb1a4e4e857de76d77ac45",
+                "sha256:e0d38fa0a75f65f556fb912f2c6790d1fa29b7dd27a1d9cc5591b281321eaaa9",
+                "sha256:eb2acabbd487a46b38540a819ef67e477a674481f84a82a7ba2234b9ba46f752",
+                "sha256:eeee629828d0eb4f6d98ac41e9a3a6461d114d1d0aa111a8931c049359298da0",
+                "sha256:f5ce9e26d25eb0b2d96f3ef0ad70e1d3ae89b5d60255c462252a3e456a48c053",
+                "sha256:fabf73d5d0286f9e078774f3435601d2735c94ce9e514ac4fb945701edead7e4"
+            ],
+            "version": "==1.2.1"
+        },
+        "python-dateutil": {
+            "hashes": [
+                "sha256:3220490fb9741e2342e1cf29a503394fdac874bc39568288717ee67047ff29df",
+                "sha256:9d8074be4c993fbe4947878ce593052f71dac82932a677d49194d8ce9778002e"
+            ],
+            "version": "==2.7.2"
+        },
+        "pytz": {
+            "hashes": [
+                "sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555",
+                "sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749"
+            ],
+            "version": "==2018.4"
+        },
+        "six": {
+            "hashes": [
+                "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
+                "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
+            ],
+            "version": "==1.11.0"
+        },
+        "unidecode": {
+            "hashes": [
+                "sha256:72f49d3729f3d8f5799f710b97c1451c5163102e76d64d20e170aedbbd923582",
+                "sha256:8c33dd588e0c9bc22a76eaa0c715a5434851f726131bd44a6c26471746efabf5"
+            ],
+            "version": "==1.0.22"
+        }
+    },
+    "develop": {}
+}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..538c53b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,37 @@
+# Blog
+
+> My (Nimrod Adar) blog.
+
+## Requirements
+
+- Python 3.6
+- [Pipenv](https://pipenv.org)
+
+## Usage
+
+All tasks are done via `fab` using `pipenv`
+```
+pipenv run $ fab -l
+Available commands:
+
+    build       Build local version of site
+    clean       Remove generated files
+    dev         Auto-regenerate files and serve at http://localhost:8080/
+    preview     Build production version of site
+    publish     Publish to production via rsync
+    regenerate  Automatically regenerate site upon file modification
+    serve       Serve site at http://localhost:8080/
+```
+
+
+## License
+
+This software is licensed under the [Creative Commons - Attribution 4.0
+International license](https://creativecommons.org/licenses/by/4.0/).
+
+## Author Information
+
+Nimrod Adar, [contact me](mailto:nimrod@shore.co.il) or visit my [website](
+https://www.shore.co.il/). Patches are welcome via [`git send-email`](
+http://git-scm.com/book/en/v2/Git-Commands-Email). The repository is located
+at: <https://www.shore.co.il/git/>.
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 5c2628c..0000000
--- a/README.rst
+++ /dev/null
@@ -1,11 +0,0 @@
-Blog
-====
-
-My (Nimrod Adar) blog.
-
-todo
-----
-
-- Add git hooks to publish when commiting changes.
-- License (the license for Pelican except for the content which is under
-  Creative Commons).
diff --git a/develop_server.sh b/develop_server.sh
deleted file mode 100755
index ed6f286..0000000
--- a/develop_server.sh
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env bash
-##
-# This section should match your Makefile
-##
-PY=python
-PELICAN=pelican
-PELICANOPTS=
-
-BASEDIR=$(pwd)
-INPUTDIR=$BASEDIR/content
-OUTPUTDIR=$BASEDIR/output
-CONFFILE=$BASEDIR/pelicanconf.py
-
-###
-# Don't change stuff below here unless you are sure
-###
-
-SRV_PID=$BASEDIR/srv.pid
-PELICAN_PID=$BASEDIR/pelican.pid
-
-function usage(){
-  echo "usage: $0 (stop) (start) (restart) [port]"
-  echo "This starts pelican in debug and reload mode and then launches"
-  echo "A pelican.server to help site development. It doesn't read"
-  echo "your pelican options so you edit any paths in your Makefile"
-  echo "you will need to edit it as well"
-  exit 3
-}
-
-function alive() {
-  kill -0 $1 >/dev/null 2>&1
-}
-
-function shut_down(){
-  PID=$(cat $SRV_PID)
-  if [[ $? -eq 0 ]]; then
-    if alive $PID; then
-      echo "Killing pelican.server"
-      kill $PID
-    else
-      echo "Stale PID, deleting"
-    fi
-    rm $SRV_PID
-  else
-    echo "pelican.server PIDFile not found"
-  fi
-
-  PID=$(cat $PELICAN_PID)
-  if [[ $? -eq 0 ]]; then
-    if alive $PID; then
-      echo "Killing Pelican"
-      kill $PID
-    else
-      echo "Stale PID, deleting"
-    fi
-    rm $PELICAN_PID
-  else
-    echo "Pelican PIDFile not found"
-  fi
-}
-
-function start_up(){
-  local port=$1
-  echo "Starting up Pelican and pelican.server"
-  shift
-  $PELICAN --debug --autoreload -r $INPUTDIR -o $OUTPUTDIR -s $CONFFILE $PELICANOPTS &
-  pelican_pid=$!
-  echo $pelican_pid > $PELICAN_PID
-  cd $OUTPUTDIR
-  $PY -m pelican.server $port &
-  srv_pid=$!
-  echo $srv_pid > $SRV_PID
-  cd $BASEDIR
-  sleep 1
-  if ! alive $pelican_pid ; then
-    echo "Pelican didn't start. Is the pelican package installed?"
-    return 1
-  elif ! alive $srv_pid ; then
-    echo "pelican.server didn't start. Is there something else which uses port 8000?"
-    return 1
-  fi
-  echo 'Pelican and pelican.server processes now running in background.'
-}
-
-###
-#  MAIN
-###
-[[ ($# -eq 0) || ($# -gt 2) ]] && usage
-port=''
-[[ $# -eq 2 ]] && port=$2
-
-if [[ $1 == "stop" ]]; then
-  shut_down
-elif [[ $1 == "restart" ]]; then
-  shut_down
-  start_up $port
-elif [[ $1 == "start" ]]; then
-  if ! start_up $port; then
-    shut_down 
-  fi
-else
-  usage
-fi
diff --git a/fabfile.py b/fabfile.py
index 7da34f3..fc2c611 100644
--- a/fabfile.py
+++ b/fabfile.py
@@ -1,60 +1,57 @@
-from fabric.api import *
+from fabric.api import lcd, env, local, hosts
 import fabric.contrib.project as project
-import os
+import multiprocessing
 
 # Local path configuration (can be absolute or relative to fabfile)
 env.deploy_path = 'output'
 DEPLOY_PATH = env.deploy_path
 
 # Remote server configuration
-production = 'nimrod@www.shore.co.il:22'
+production = 'www.shore.co.il'
 dest_path = '/var/www/htdocs/www.shore.co.il/blog/'
 
-# Rackspace Cloud Files configuration settings
-env.cloudfiles_username = 'my_rackspace_username'
-env.cloudfiles_api_key = 'my_rackspace_api_key'
-env.cloudfiles_container = 'my_cloudfiles_container'
-
 
 def clean():
-    if os.path.isdir(DEPLOY_PATH):
-        local('rm -rf {deploy_path}'.format(**env))
-        local('mkdir {deploy_path}'.format(**env))
+    """Remove generated files"""
+    local(f'rm -r __pycache__/ {DEPLOY_PATH}/*')
+
 
 def build():
+    """Build local version of site"""
     local('pelican -s pelicanconf.py')
 
-def rebuild():
-    clean()
-    build()
 
 def regenerate():
-    local('pelican -r -s pelicanconf.py')
+    """Automatically regenerate site upon file modification"""
+    local('pelican -D -r -s pelicanconf.py')
+
 
 def serve():
-    local('cd {deploy_path} && python -m SimpleHTTPServer 8080'.format(**env))
+    """Serve site at http://localhost:8080/"""
+    with lcd(DEPLOY_PATH):
+        local('python -m http.server 8080')
+
+
+def dev():
+    """Auto-regenerate files and serve at http://localhost:8080/"""
+    server_process = multiprocessing.Process(target=serve)
+    server_process.start()
+    regenerate()
 
-def reserve():
-    build()
-    serve()
 
 def preview():
+    """Build production version of site"""
     local('pelican -s publishconf.py')
 
-def cf_upload():
-    rebuild()
-    local('cd {deploy_path} && '
-          'swift -v -A https://auth.api.rackspacecloud.com/v1.0 '
-          '-U {cloudfiles_username} '
-          '-K {cloudfiles_api_key} '
-          'upload -c {cloudfiles_container} .'.format(**env))
 
 @hosts(production)
 def publish():
-    local('pelican -s publishconf.py')
+    """Publish to production via rsync"""
+    preview()
     project.rsync_project(
         remote_dir=dest_path,
         exclude=".DS_Store",
         local_dir=DEPLOY_PATH.rstrip('/') + '/',
-        delete=True
+        delete=True,
+        extra_opts='-c',
     )
diff --git a/pelicanconf.py b/pelicanconf.py
index 6602452..f86b682 100644
--- a/pelicanconf.py
+++ b/pelicanconf.py
@@ -2,35 +2,31 @@
 # -*- coding: utf-8 -*- #
 from __future__ import unicode_literals
 
-AUTHOR = u'Nimrod Adar'
-SITENAME = u'My notes and rumblings'
-SITEURL = 'https://www.shore.co.il/blog'
+AUTHOR = 'Nimrod Adar'
+SITENAME = 'My notes and ramblings'
+SITEURL = 'http://localhost:8080'
+
+PATH = 'content'
 
 TIMEZONE = 'Asia/Jerusalem'
 
-DEFAULT_LANG = u'en'
+DEFAULT_LANG = 'en'
 
 # Feed generation is usually not desired when developing
-FEED_ALL_ATOM = None
+FEED_ALL_ATOM = 'feeds/all.atom.xml'
 CATEGORY_FEED_ATOM = None
 TRANSLATION_FEED_ATOM = None
+AUTHOR_FEED_ATOM = None
+AUTHOR_FEED_RSS = None
 
 # Blogroll
 LINKS = ()
 
-# Social widget
-#SOCIAL = (('You can add links in your config file', '#'),
-#          ('Another social link', '#'),)
-
 DEFAULT_PAGINATION = 3
 
 # Uncomment following line if you want document-relative URLs when developing
-#RELATIVE_URLS = True
-
-PATH = "content"
+RELATIVE_URLS = True
 DIRECT_TEMPLATES = ('index', 'archives')
-#DIRECT_TEMPLATES = ('index')
-#DISPLAY_CATEGORIES_ON_MENU = True
 DISPLAY_CATEGORIES_ON_MENU = False
 DISPLAY_PAGES_ON_MENU = True
 MENUITEMS = (('Code', 'https://www.shore.co.il/git/'),)
@@ -39,3 +35,7 @@ TAGS_SAVE_AS = ''
 TAG_SAVE_AS = ''
 STATIC_PATHS = ['static']
 ARTICLE_URL = '{slug}/'
+DELETE_OUTPUT_DIRECTORY = True
+
+SLUGIFY_SOURCE = 'basename'
+ARTICLE_SAVE_AS = '{slug}/index.html'
diff --git a/publishconf.py b/publishconf.py
index 678e10e..79f771e 100644
--- a/publishconf.py
+++ b/publishconf.py
@@ -12,19 +12,3 @@ from pelicanconf import *
 
 SITEURL = 'https://www.shore.co.il/blog'
 RELATIVE_URLS = False
-
-FEED_ALL_ATOM = 'feeds/all.atom.xml'
-#CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml'
-CATEGORY_FEED_ATOM = None
-
-DELETE_OUTPUT_DIRECTORY = True
-#DEFAULT_METADATA = (('author', u'Nimrod Adar'),)
-SLUGIFY_SOURCE = 'basename'
-ARTICLE_SAVE_AS = '{slug}/index.html'
-
-# Following items are often useful when publishing
-
-#DISQUS_SITENAME = ""
-#GOOGLE_ANALYTICS = ""
-#STATIC_PATHS = [ 'static' ]
-TRANSLATION_FEED_ATOM = None
diff --git a/tox.ini b/tox.ini
deleted file mode 100644
index 95f637a..0000000
--- a/tox.ini
+++ /dev/null
@@ -1,25 +0,0 @@
-[tox]
-envlist = build
-skipsdist = True
-
-[testenv]
-envdir = {toxinidir}/.tox/env
-basepython = python2
-deps =
-    Fabric
-    pelican
-whitelist_externals =
-    git
-
-[testenv:build]
-commands =
-    fab build
-
-[testenv:serve]
-commands =
-    fab reserve
-
-[testenv:publish]
-commands =
-    fab publish
-    git push
-- 
GitLab