最近だと静的ブログというのは Github Pages
にのせるのが普通なのかもしれませんが
私の場合はレンサバ的なものがあってそれが手持ち豚さんになってるのでそっちを使います。
私の使っているサーバは FTP/FTPS にしか対応していないし
SITE
コマンド のようにOSコマンドを実行する機能もないので、
アップロードするためのプログラムを Python で書きました。
コード
Python3.6 で動作確認してます。
私は以下を deploy.py
という名前で 直下
(outputs/
と同じ階層) に保存しました。
#!/usr/bin/env python3 # coding: utf-8 from ftplib import FTP, FTP_TLS, error_perm import argparse import getpass import glob import os import json parser = argparse.ArgumentParser('uploading files') parser.add_argument('--glob', '-g', default='*', help='アップロード対象をGLOBで指定') parser.add_argument('--onto', '-o', default='/', help='アップロード先のディレクトリ') parser.add_argument('--plain', action='store_false', help='指定すると暗号化しない。') parser.add_argument('--outputs', '-O', default='outputs/', help='outputs/ ディレクトリのパス') args = parser.parse_args() top = os.path.dirname(args.outputs.rstrip('/')) try: info = json.loads(open(os.path.join(top, 'deploy.json')).read()) except FileNotFoundError: info = {} if not info.get('user'): info['user'] = input('User: ') if not info.get('passwd'): info['passwd'] = getpass() if not info.get('host'): info['host'] = input('Host: ') def make_hierarchical_paths(path): dirs = path.strip('/').split('/') root = '/' if path.startswith('/') else '' return [ os.path.join(root, *dirs[0:i+1]) for i, dir in enumerate(dirs) ] ignore_errors = info.pop('ignore_errors', []) cli = (FTP if args.plain else FTP_TLS)(**info) try: cli.login() except error_perm as e: if str(e) not in ignore_errors: raise e os.chdir(args.outputs) created = set() for parent, _, _ in os.walk('.', topdown=False): for path in glob.glob(os.path.join(parent, args.glob)): for dirpath in make_hierarchical_paths(os.path.dirname(path)): if dirpath in created or not dirpath.strip('.'): continue print('making dir:', dirpath) try: cli.mkd(os.path.join(args.onto, dirpath)) except error_perm: pass created.add(dirpath) if os.path.isdir(path): continue with open(path, 'rb') as f: print('uploading content:', path) cli.storbinary("STOR " + os.path.join(args.onto, path), f)
- warning
- インデックスページが後になるように深い階層のファイルからアップロードされるようにしていますが、 環境によると思うので使う方は注意してください。
--plain
オプションは使ってないのでうまく動かなかったらごめんなさい m(_ _)m
解説
基本的にやることは単純明快で
Miyadaiku が出力してくれた
outputs/
をまるっと対象の FTP サーバに転送しています。
いくつかオプションを用意しました。
- glob
- 対象ファイルを限定するためのオプションです。 例えば html ファイルだけをアップロードしたい場合は
--glob *.html
のように指定します。 指定しないとすべてが対象となります。
- 対象ファイルを限定するためのオプションです。 例えば html ファイルだけをアップロードしたい場合は
- onto
- ファイルを配置するサーバ側のディレクトリを指定します。 指定しないと
/
に配置されます。
- ファイルを配置するサーバ側のディレクトリを指定します。 指定しないと
- plain
- 指定すると
SSL
による暗号化を行いません。 サーバがFTPS
に対応していない場合は 指定の必要があります。 指定しない場合はFTPS
による接続を試みます。
- 指定すると
- outputs
outputs
ディレクトリ のパス
を指定します。 指定しない場合、カレントディレクトリにあるoutputs
が対象になります。
また、 FTP を使うためにはサーバや認証情報が必要ですが毎回入力したくないので
deploy.json
がある場合はそこに書かれた接続情報を使うようにしています。
{ "user": "ユーザ名", "passwd": "パスワード", "host": "FTPのホストアドレス", "ignore_errors": ["ログインした時に無視するメッセージ"] }
user
, passwd
, host
は指定しないと 実行時に入力を求められます。
ignore_errors
ってなんだよって感じですが 私の場合はログインした場合に毎回 503 You are already logged in
って出てエラーになって進めない(謎)ので作りました。 環境によって発生する謎のエラー回避用です。
参考
ftplib --- FTPプロトコルクライアントソースコード: Lib/ftplib.py このモジュールでは FTP クラスと、それに関連するいくつかの項目を定義しています。 FTP クラスは、FTPプロトコルのクライアント側の機能を備えています。このクラスを使うとFTPのいろいろな機能の自動化、例えば他のFTPサーバのミラーリングといったことを実行するPythonプログラムを書くことができます。また、 urllib.request モ...https://docs.python.org/3/library/ftplib.html [Python] PythonからFTPを実行する - YoheiM .NET今日はftplibという標準モジュールを使って、PythonからFTPを行う方法をブログに残したいと思います。https://www.yoheim.net/blog.php?q=20170401