Автозагрузка из DropboxOwncloud

x Denis Speranskiy -
Tags: #pelican #bash

Upd 17/03/2016: скрипты немного исправлены для работы с Owncloud

Зачем это всё?

Как я уже говорил, сайт работает на Pelican. А узнал я о нём от замечательного, но, к сожалению, умирающего сервиса calepin.co. Этот сервис предлагает очень удобную штуку- подключается к Dropbox аккаунту и из файлов, размещённых в его папке, создаёт статический сайт на своём сервере. Можно даже своё доменное имя прикрутить, а можно и их воспользоваться. В общем всё было бы хорошо, если бы не нереальный долгий отклик их сервера из России- пользоваться невозможно. Там то я узнал о том, что работает он на Pelican.

В общем, с тех пор я продолжал хотеть такую же штуку- автоматическая сборка и загрузка сайта при изменении файлов в определённой подпапке в Dropbox. Удобно же писать в бложик, когда бьёшь баклуши появилась свободная минутка на работе, а потом вжжжик и всё на сайте уже. Плюс, на Dropbox есть версионность файлов, то есть можно откатиться в случае ахтунга.

И так, берём в одну руку Bash, в другую Linux и приступаем к упражнениям!

Incron- наш лучший друг!

Incron- это такая служба, которая следит за изменениями в файловой системе, и если, в указанном месте происходит указанное событие- выполняет заданную команду. Вот, собственно, и план:

  • пишем скрипт по сборке сайте и его копировании на сервер;
  • добавляем приятную удобность;
  • настраиваем incron;
  • Готово!

Скрипты

Принцип работы скрипта следующий: Incron следит за папкой, в которой хранятся исходные файлы Pelican. Там же создан файл upload.txt, изменением которого и происходит активация сборки и копирования сайта. Так сделано для того, чтобы скрипт не выполнялся при каждом сохранении файла внутри наблюдаемой папки. Пэтому в incron скрипту в виде параметра $# передаётся имя измененного файла (точнее файла, у которого изменились атрибуты), скрипт анализирует полученное и запускает или нет процедуры сборки и копирования сайта.

Почему нельзя просто следить за файлом? Потому что оказалось, что при обычном изменении файла происходит его фактическое удаление и пересоздание. Таким образом, изменяется node (не знаю как по-русски), и incron и inotify теряют возможность следить за ним.

Скрипт выглядит следующим образом:

#!/bin/bash
export LANG=ru_RU.UTF-8
par=${1%.*}
if [ -n "$par" ] && [ $par == "cid" ]; then
    /home/USERNAME/.gem/ruby/2.3.0/bin/sass /home/USERNAME/.config/pelican/themes/Pelican-Cid/src/sass/cid.sass /home/USERNAME/.config/pelican/themes/Pelican-Cid/static/css/cid.css 2>&1
elif [ -n "$par" ] && [ $par == "upload" ]; then
    pelican -s /home/USERNAME/.config/pelican/pelicanconf.py /home/server/http/owncloud/data/OCUsername/files/Personal/Blog/ -o /tmp/output
    rsync -avc --delete /tmp/output/ hostingUserName@hosting address:/home/public
    rm -rf /tmp/output
elif [ -n "$par" ] && [ $par == "test" ]; then
    pelican -s /home/USERNAME/.config/pelican/pelicanconf.py /home/server/http/owncloud/data/OCUsername/files/Personal/Blog/ -o /tmp/output
fi

Про cid и sass: это сделано для того, чтобы следить за изменением исходных файлов CSS и, соответсвенно, пересобирать их при изменении.

Так как на моём сайте всё картинки- черно белые, решено было это тоже автоматизировать. При появлении картинки в папке images автомаГически, при помощи imagemagick мы меняем ей права (иногда при скачивании из Интернета они не правильные), делаем её ЧБ и меняем размер до 700px по ширине (если необходимо). Для того, чтобы скрипт поменял размер картинки, её нужно сохранить в виде resize_имя_файла, скрипт потом сам удалит лишнее. Вот так он выглядит:

#!/bin/bash
chmod 644 $1\/$2
convert $1\/$2 -colorspace Gray $1\/$2
if [[ ${2:0:7} == resize_ ]];
 then 
    convert $1\/$2 -resize 700x700 $1\/${2#*_}
    rm -f $1\/$2
    php -f /usr/share/webapps/owncloud/occ files:scan --path OCUserName\/files\/Personal\/Blog\/images > /dev/null 2>&1
fi

Установка и настройка incron

Не знаю как в вашем, а в моём дистрибутиве incron есть в стандартных репозиториях, так что устанавливаем:

sudo pacman -S incron

Принцип работы- такой же как и в обычном cron- конфигурация через incrontab:

$ incrontab -e

Синтаксис следующий:

/путь/который/нужно/мониторить СОБЫТИЕ /какую/команду/выполнять $передаваемыеПараметры

Здесь всё расписано на буржуйском.

Получилось вот что (запускается от пользователя USERNAME):

/home/server/http/owncloud/data/OCUsername/files/Personal/Blog IN_ATTRIB /home/USERNAME/bin/build-publish.sh $#
/home/USERNAME/.config/pelican/themes/Pelican-Cid/src/sass IN_ATTRIB,IN_MOVED_TO /home/USERNAME/bin/build-publish.sh $#

А это запускается от пользователя apache (http)

sudo -u http incrontab -e
/home/server/http/owncloud/data/Speranskiy/files/Personal/Blog/images IN_CREATE,IN_MOVED_TO /home/speranza/bin/prepImage.sh $@ $#

Почему IN_ATTRIB? Да потому что incron далеко не образец написания программ и он не определяет сколько изменений произошло на самом деле. Он работает очень просто- произошло событие- выполнил команду. А проблема в том, что при простом изменении файла, например, IN_MODIFY вообще не происходит, а IN_CLOSE_WRITE происходит 2 раза и скрипт выполняется два раза. Вообще интересно наблюдать как происходят события файловой системы при помощи inotifywait, что предоставляется пакетом inotify-tools:

$ inotifywait --monitor /путь/который/нужно/мониторить

В общем при изменении файла гарантированно один раз происходит только изменение атрибутов, поэтому это событие и использовано.

Так же, помните, что в incron не предусмотрена защита от "зацикливания", поэтому если действие, приводящее к изменению файла вызывается атрибутом IN_MODIFY, то это приведёт к повисанию всей системы- OS будет занята перезаписыванием одного и того же файла бесконечно.

Пуск и отладка!

Сервис ставится в автозагрузку и запускается следующим образом (для systemd):

sudo systemctl enable incrond
sudo systemctl start incrond

Да, сервис работает от root, но правила выполняет от пользователя.

Посмотреть что делает сервис можно так:

journalctl -f -u incrond

Но в journalctl пишутся только выполняемые команды и подробностей там не видно. Чтобы посмотреть глубже можно остановить службу и запустить её прямо из терминала c параметром -n:

sudo systemctl stop incrond
sudo incrond -n

Вывод

В результате получилось не совсем то, что хотел- для работы нужно держать ноутбук включенным. Конечно я не буду этого делать и пускай обновляется когда я или моя ненаглядная его включит. По хорошему, нужно было на сервере устанавливать dropbox-cli и всё это дело настраивать там, но мой хостинг почему-то работает на FreeBSD, а я с ней не дружу. Из плюсов моей реализации- ограничение траффика на хостинг, а он у меня платный, так что- экономия.