Compnet

仕事とか遊びとか、日々折々

2016-11-27(日)

Pelican でアップロードする

Posted by Nakane, R. in technical   

先の記事では、Pelicanpelican-quickstart コマンドで作られる四つの設定ファイルのうちの pelicanconf.py と publishconf.py について書きました。 ここでは、残るふたつの fabfile.py と Makefile について書きます。

fabfile.py は Python 製のデプロイ ツールである Fabric の指示ファイル、Maikefile はビルド ツールである GNU make の指示ファイルです。 fabfile.py と Maikefile には pelican-quickstart コマンドの質問Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n):Y で答えた後の、> What is the hostname of your FTP server?:> Where is your Dropbox directory?: などの回答を基にした設定が保存されています。

pelican-quickstart コマンドで作成された fabfile.py は以下の通りです。

from fabric.api import *
import fabric.contrib.project as project
import os
import shutil
import sys
import SocketServer

from pelican.server import ComplexHTTPRequestHandler

# Local path configuration (can be absolute or relative to fabfile)
env.deploy_path = 'output'
DEPLOY_PATH = env.deploy_path

# Remote server configuration
production = 'root@localhost:22'
dest_path = '/var/www'

# 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'

# Github Pages configuration
env.github_pages_branch = "gh-pages"

# Port for `serve`
PORT = 8000

def clean():
    """Remove generated files"""
    if os.path.isdir(DEPLOY_PATH):
        shutil.rmtree(DEPLOY_PATH)
        os.makedirs(DEPLOY_PATH)

def build():
    """Build local version of site"""
    local('pelican -s pelicanconf.py')

def rebuild():
    """`clean` then `build`"""
    clean()
    build()

def regenerate():
    """Automatically regenerate site upon file modification"""
    local('pelican -r -s pelicanconf.py')

def serve():
    """Serve site at http://localhost:8000/"""
    os.chdir(env.deploy_path)

    class AddressReuseTCPServer(SocketServer.TCPServer):
        allow_reuse_address = True

    server = AddressReuseTCPServer(('', PORT), ComplexHTTPRequestHandler)

    sys.stderr.write('Serving on port {0} ...\n'.format(PORT))
    server.serve_forever()

def reserve():
    """`build`, then `serve`"""
    build()
    serve()

def preview():
    """Build production version of site"""
    local('pelican -s publishconf.py')

def cf_upload():
    """Publish to Rackspace Cloud Files"""
    rebuild()
    with lcd(DEPLOY_PATH):
        local('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():
    """Publish to production via rsync"""
    local('pelican -s publishconf.py')
    project.rsync_project(
        remote_dir=dest_path,
        exclude=".DS_Store",
        local_dir=DEPLOY_PATH.rstrip('/') + '/',
        delete=True,
        extra_opts='-c',
    )

def gh_pages():
    """Publish to GitHub Pages"""
    rebuild()
    local("ghp-import -b {github_pages_branch} {deploy_path}".format(**env))
    local("git push origin {github_pages_branch}".format(**env))

Maikefile ファイルは以下のようになっています。

PY?=python3
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=localhost
SSH_PORT=22
SSH_USER=root
SSH_TARGET_DIR=/var/www

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/

GITHUB_PAGES_BRANCH=gh-pages

DEBUG ?= 0
ifeq ($(DEBUG), 1)
    PELICANOPTS += -D
endif

RELATIVE ?= 0
ifeq ($(RELATIVE), 1)
    PELICANOPTS += --relative-urls
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 serve-global [SERVER=0.0.0.0]  serve (as root) to $(SERVER):80    '
    @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 'Set the RELATIVE variable to 1 to enable relative urls                    '
    @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

serve-global:
ifdef SERVER
    cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 $(SERVER)
else
    cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 0.0.0.0
endif


devserver:
ifdef PORT
    $(BASEDIR)/develop_server.sh restart $(PORT)
else
    $(BASEDIR)/develop_server.sh restart
endif

stopserver:
    $(BASEDIR)/develop_server.sh stop
    @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 -rvzc --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 --guess-mime-type

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 -m "Generate Pelican site" -b $(GITHUB_PAGES_BRANCH) $(OUTPUTDIR)
    git push origin $(GITHUB_PAGES_BRANCH)

.PHONY: html help clean regenerate serve serve-global devserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github

fabfile.py には rsync を使ったアップロードと Rackspace Cloud Files へのアップロードの設定しかないなど、Makefile に比べるときちんと保守されていない印象があります。 いずれは Makefile と同じ程度の機能が組み込まれて、fabfile.py を GitHub へのアップロードなどもできるようになるかもしれません。 しかし現状の fabfile.py の構成がそのまま使えるとか、自身で fabfile.py を修正したりタスクを追加するなど手を加えるのでなければ、Makefile を使う方がよさそうです。

Makefile を使うのであれば make html コマンドが「Pelican で Web サイトを生成」で紹介した pelican コマンドと同じ働きをします。 make html コマンドでは生成される Web サイトは評価環境になります。 本番環境の Web サイトを生成したいときは make publish コマンドを使います。 Makefile を見ると分かりますが、評価環境と本番環境のどちらも同じディレクトリに Web サイトを生成するようになっています。 評価環境で生成したファイルを綺麗にしてから本番環境を生成したいときは、make publish コマンドの前に make clean コマンドを実行します。

本番環境の Web サイトを生成したら、公開するための Web サーバーにアップロードします。 FTP でアップロードすることもできますが、筆者は rsync を使います。

rsync で Web サーバーにアップロードするときのコマンドは make rsync_upload です。 筆者の場合は pelican-quickstart コマンドで fabfile.py と makefile ファイルを作るように回答はしましたが、その後の質問には適当に回答したためにそのままで使えるようにはなっていません。 そこで、make rsync_upload コマンドを使う前に、Makefile ファイルを少し修正します。

以下に make rsync_upload コマンドで実行される箇所を Makefile ファイルから抜き出します。

    :
rsync_upload: publish
    rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude
    :

これを見ると、SSH_PORTOUTPUTDIRSSH_USERSSH_HOSTSSH_TARGET_DIR を設定すれば良さそうです。 この中で OUTPUTDIR は Makefile の最初の方で OUTPUTDIR=$(BASEDIR)/output のように設定されていて、このままで問題ありません。 それ以外は以下のように設定されていて、筆者の環境とはまったく違っているので、これらを適切に修正します。

    :
SSH_HOST=localhost
SSH_PORT=22
SSH_USER=root
SSH_TARGET_DIR=/var/www
    :

まずは SSH_HOST=localhostlocalhost をアップロードするサーバーのホスト名に書き替えます。 SSH_PORT=22 はそのままでいいでしょう。 SSH_USER=rootroot は rsync でアップロードするときに使うユーザー名に直します。 SSH_TARGET_DIR=/var/www/var/www は Web サーバーの HTML のルート ディレクトリにします。

以下はこれらを筆者の環境に合うように修正した Maikefile ファイルです。 ここには修正箇所だけを示します。 なお、ユーザー名は仮名にしてあります。

    :
SSH_HOST=www.compnet.jp
SSH_PORT=22
SSH_USER=username
SSH_TARGET_DIR=/var/www/pelican
    :

実は筆者の環境では、これだけでは rsync で Web サーバーにアップロードできるようになりません。 これについては改めて別の記事に書きます。

Comments