Современный Web-UI для SVN в 2020 году

l_2kl8unfj7waipnge-7bfmgx38.pngcSvn — это web-интерфейс к Subversion репозиториям. Основу cSvn представляет CGI-скрипт написанный на языке С.

В мае 2020 года был опубликован релиз очередной версии Apache Subversion 1.14.0. В свете этого события, был создан новый, современный web-интерфейс для просмотра Subversion репозиториев на любых устройствах. Это весьма позитивная новость для тех, кто использует централизованные системы версионного контроля по тому, что до вчерашнего дня существовал лишь один достойный web-UI (WebSVN), написанный на PHP и, к сожалению, отстающий от современных требований.

В данной статье рассматривается установка и настройка cSvn для работы с использованием Nginx + uWsgi. Настройка серверных компонентов достаточно проста и практически не отличается от настройки cGit.

На стороне клиента работает элементарный JavaScript составляющий не более 350 строк и таблица стилей размером 24K в распакованном виде. Markdown-тексты обрабатываются на стороне сервера с помощью библиотеки md4c, которая успешно зарекомендовала себя в проекте KDE Plasma.

Вместо screenshot-ов, лучше посмотреть на работающий cSvn сервер.

Стоит заметить, что с помощью cSvn можно просматривать не только собственные репозитории, но и настроить просмотр сторонних ресурсов по протоколам HTTPS и SVN.


Требования к системе

cSvn использует библиотеки libpcre2, md4c, libmagic, входящую в состав пакета File и libxml2. На сервере должны быть установлены: HTTP сервер Nginx, сервер uWsgi и, разумеется Apache Subversion.


Инсталляция продуктов

cSvn пакет состоит из двух частей. Первая представляет собой обычный Linux демон, который отвечает за разбор конфигурационного файла /etc/csvnrc. Вторая — непосредственно является CGI-скриптом, отвечающим на HTTP запросы клиента. Обе части устанавливаются одновременно.


Исходные тексты

Получить исходный пакет cSvn можно двумя способами: загрузить с FTP-сервера или с помощью Subversion:

svn checkout svn://radix.pro/csvn/trunk csvn

Если использован второй способ, то перед сборкой пакета необходимо приготовить исходные тексты для их последующего конфигурирования. Для этого нужно воспользоваться скриптом bootstrap:

cd csvn
./bootstarp

который установит Autotools средства, соберет коллекцию aclocal.m4 и создаст configure скрипт.


Сборка пакета

Сборка и установка cSvn ни чем не отличается от любых других продуктов, использующих средства Autoconf, Automake:

./configure --prefix=/usr \
            --sysconfdir=/etc \
            --with-config=/etc/csvnrc \
            --with-controldir=/etc/rc.d \
            --with-logrotatedir=/etc/logrotate.d \
            --with-scriptdir=/var/www/htdocs/csvn \
            --with-homedir=/var/lib/csvn \
            --with-logdir=/var/log \
            --with-piddir=/var/run
make
make install

Здесь, параметр --with-scriptdir определяет место установки CGI-скрипта и связанных с ним файлов, необходимых для работы сервера cSvn. Далее, в описании настроек сервера Nginx, мы будем использовать именно этот каталог. Разумеется, пользователи могут настроить работу cSvn и виртуального HTTP сервера относительно любого другоро каталога.


Права доступа

После инсталляции пакета cSvn необходимо отдать права на каталог /var/www/htdocs/csvn пользователю, от имени которого работает Nginx:

  chown -R nginx:nginx /var/www/htdocs/csvn

Subversion репозитории

Перед первым запуском сервера cSvn необходимо создать конфигурационный файл /etc/csvnrc, в котором должны быть определены все обязательные переменные и описан хотя бы один репозиторий.

На странице руководства csvnrc (5) приведен рабочий файл конфигурации сервера:


/etc/csvnrc:

svn-utc-offset = +0300;

checkout-prefix-readonly = 'svn://radix.pro';
checkout-prefix          = 'svn+ssh://svn@radix.pro';

branches = 'branches';
trunk    = 'trunk';
tags     = 'tags';

snapshots = 'tar.xz';

css = '/.csvn/css/csvn.css';
logo = '/.csvn/pixmaps/csvn-banner-280x280.png';
logo-alt = "Radix.pro";
logo-link = "https://radix.pro";
main-menu-logo = '/.csvn/pixmaps/logo/SVN-logo-white-744x744.svg';
favicon-path = '/.csvn/pixmaps/favicon';
syntax-highlight-css = '_csvn.css';
header = '/.csvn/html/header.html';
footer = '/.csvn/html/footer.html';
page-size = 200;

owner = "Andrey V.Kosteltsev";
author = "Andrey V.Kosteltsev";
title = "Radix.pro SVN Repositories";
description = "Subversion repositories hosted at radix.pro (St.-Petersburg)";
keywords = "cSvn repositories";
copyright = "© Andrey V. Kosteltsev, 2019 – 2020.";
copyright-notice = "Where any material of this site is being reproduced, published or issued to others the reference to the source is obligatory.";

home-page = "https://radix.pro/";

section "Tools" {
  repo 'csvn' {
    owner = "Andrey V.Kosteltsev";
    title = "cSvn CGI Script";
    description = "cSvn CGI Script – is a web frontend for Subversion™ Repositories";
    home-page = "https://radix.pro/";
  }
}

Его можно использовать как начальный шаблон.

После создания конфигурационного файла /etc/csvnrc можно проверить работу csvnd (8) демона.

В случае работы на системе с BSD-like инициализацией, для запуска csvnd (8) демона достаточно выполнить команду

/etc/rc.d/rc.csvnd start

Для систем использующих systemd, необходимо воспользоваться утилитой systemctl:

systemctl enable csvnd.service
systemctl start csvnd.service


Здесь необходимо упомянуть следующее…

При сборке и установке исходного пакета cSvn, устанавливается start/stop скрипт /etc/rc.d/rc.csvnd. Если же речь идет о системах использующих systemd, то для установки cSvn лучше использовать бинарный RPM или pacman пакет, поскольку в таких пакетах файл /etc/rc.d/rc.csvnd заменяется на Systemd Unit,


/usr/lib/systemd/system/csvnd.service:
[Unit]
Description=The cSvn daemon
After=network.target

[Service]
PIDFile=/var/run/csvnd.pid
ExecStart=/usr/sbin/csvnd --daemonize --inotify --config=/etc/csvnrc
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

устанавливаемый в каталог /usr/lib/systemd/system.

Если для используемой вами системы еще не создан пакет cSvn, то вы его можете приготовить самостоятельно, по инструкциям, приведенным к каталоге doc/build-packages.

Если же вы не хотите создавать пакет для вашей системы, то вы можете просто поместить файл csvnd.service в каталог /usr/lib/systemd/system/ и выполнить запуск демона самостоятельно.


После запуска csvnd (8) демона надо убедиться в существовании файла /dev/shm/csvn.bcf и, в случае его отсутствия посмотреть на ошибки приведенные в /var/log/csvnd.log файле.


Настройка uWsgi

Поскольку на этапе конфигурирования мы выбрали для инсталляции cSvn CGI-скрипта каталог /var/www/htdocs/csvn/, файл /etc/uwsgi/csvn.ini должен ваглядеть следующим образом:


/etc/uwsgi/csvn.ini:

[uwsgi]
master          = true
plugins         = cgi
socket          = /run/uwsgi/%n.sock
uid             = nginx
gid             = nginx
procname-master = uwsgi csvn
processes       = 1
threads         = 2
cgi             = /var/www/htdocs/csvn/csvn.cgi

Здесь переменная cgi устанавливает полное имя CGI-скрипта cSvn.

Для запуска uWsgi демона на системах с BSD-like инициализацией, такой как Slackware, необходимо создать start/stop скрипт следующего вида:


/ets/rc.d/rc.csvn-uwsgi:

#!/bin/sh
#
# uWSGI daemon control script.
#

CONF=csvn
BIN=/usr/bin/uwsgi
CONFDIR=/etc/uwsgi
PID=/var/run/$CONF-uwsgi.pid

uwsgi_start() {
  # Sanity checks.
  if [ ! -r $CONFDIR/csvn.ini ]; then # no config files, exit:
    echo "There are config files in $CONFDIR directory. Abort."
    exit 1
  fi

  if [ -s $PID ]; then
    echo "uWSGI for cSvn appears to already be running?"
    exit 1
  fi

  echo "Starting uWSGI for cSvn server daemon..."
  if [ -x $BIN ]; then
    /bin/mkdir -p /run/uwsgi
    /bin/chown nginx:nginx /run/uwsgi
    /bin/chmod 0755 /run/uwsgi
    $BIN --thunder-lock --pidfile $PID --daemonize /var/log/csvn-uwsgi.log --ini $CONFDIR/$CONF.ini
  fi
}

uwsgi_stop() {
  echo "Shutdown uWSGI for cSvn gracefully..."
  /bin/kill -INT $(cat $PID)
  /bin/rm -f $PID
}

uwsgi_reload() {
  echo "Reloading uWSGI for cSvn configuration..."
  kill -HUP $(cat $PID)
}

uwsgi_restart() {
  uwsgi_stop
  sleep 3
  uwsgi_start
}

case "$1" in
  start)
    uwsgi_start
    ;;
  stop)
    uwsgi_stop
    ;;
  reload)
    uwsgi_reload
    ;;
  restart)
    uwsgi_restart
    ;;
  *)
  echo "usage: `basename $0` {start|stop|reload|restart}"
esac

Дать ему права на выполнение

  chmod a+x /ets/rc.d/rc.csvn-uwsgi

и добавить следующие строчки в файлы /etc/rc.d/rc.M, /etc/rc.d/rc.6, соответственно:


/etc/rc.d/rc.M:

# Start uWSGI for cSvn server:
if [ -x /etc/rc.d/rc.csvn-uwsgi ]; then
  /etc/rc.d/rc.csvn-uwsgi start
fi


/etc/rc.d/rc.6:

# Stop uWSGI for cSvn server:
if [ -x /etc/rc.d/rc.csvn-uwsgi ]; then
  /etc/rc.d/rc.csvn-uwsgi stop
fi

Настройка Nginx

Конфигурационный файл, для выбранного нами каталога установки и домена csvn.example.org должен выглядеть следующим образом:


/etc/nginx/vhosts/csvn.example.org.conf:

#
# cSvn server:
#

    server {
        listen 80;
        server_name csvn.example.org;
        return 301 https://csvn.example.org$request_uri;
    }

    server {
        listen 443 ssl;
        server_name csvn.example.org;
        root /var/www/htdocs/csvn;

        charset UTF-8;

        #
        # see:
        #   https://developer.mozilla.org/en-US/docs/Web/Security/HTTP_strict_transport_security ,
        #   https://raymii.org/s/tutorials/HTTP_Strict_Transport_Security_for_Apache_NGINX_and_Lighttpd.html
        #
        # see also: http://classically.me/blogs/how-clear-hsts-settings-major-browsers
        # and do not include includeSubdomains; parameter into line:
        #
        add_header Strict-Transport-Security "max-age=63072000; preload";

        error_log /var/log/nginx/csvn.example.org-error.log;
        access_log /var/log/nginx/csvn.example.org-access.log;

        keepalive_timeout        60;
        ssl_certificate          /etc/letsencrypt/live/csvn.example.org/fullchain.pem;
        ssl_certificate_key      /etc/letsencrypt/live/csvn.example.org/privkey.pem;
        ssl_trusted_certificate  /etc/letsencrypt/live/csvn.example.org/chain.pem;
        ssl_protocols            SSLv3 TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers              "RC4:HIGH:!aNULL:!MD5:!kEDH";

        gzip on;
        gzip_disable "msie6";
        gzip_comp_level 6;
        gzip_min_length 1100;
        gzip_buffers 16 8k;
        gzip_proxied any;
        gzip_types text/plain text/css text/js text/xml text/javascript
                   image/svg+xml image/gif image/jpeg image/png
                   application/json application/x-javascript application/xml application/xml+rss application/javascript
                   font/truetype font/opentype application/font-woff application/font-woff2
                   application/x-font-ttf application/x-font-opentype application/vnd.ms-fontobject application/font-sfnt;

        #
        # Serve static content with nginx
        #

        #
        # Rewrite rules for versioning CSS + JS thtouh filemtime directive
        #
        location ~* ^.+.(css|js)$ {
            rewrite ^(.+).(d+).(css|js)$ $1.$3 last;

            expires 31536000s;

            access_log off;
            log_not_found off;

            add_header Pragma public;
            add_header Cache-Control "max-age=31536000, public";
        }

        #
        # Caching of static files
        #
        location ~* .(eot|gif|gz|gzip|ico|jpg|jpeg|otf|pdf|png|svg|svgz|swf|tar|t?gz|woff|zip)$ {
            expires 31536000s;

            access_log off;
            log_not_found off;

            add_header Pragma public;
            add_header Cache-Control "max-age=31536000, public";
        }

        location ~ ^/favicon.ico$ {
            root /u3/nginx/vhosts/csvn;
            access_log off;
            log_not_found off;
            expires 30d;
        }

        location = /robots.txt {
            allow all;
            log_not_found off;
            access_log off;
        }

        location / {
            try_files $uri @csvn;
        }

        location @csvn {
            gzip off;
            include uwsgi_params;
            uwsgi_modifier1 9;
            uwsgi_pass unix:/run/uwsgi/csvn.sock;
        }
    }

После создания файла /etc/nginx/vhosts/csvn.example.org.conf его необходимо включить в основной конфигурационный файл Nginx:


/etc/nginx/nginx.conf:

    include /etc/nginx/vhosts/csvn.example.org.conf;

После запуска uWsgi и Nginx можно заняться настройкой репозториев используя руководство csvnrc (5).


Заключительная настройка

Все необходимые файлы для работы на стороне web-клиента находятся в каталоге /var/www/htdocs/csvn/.csvn/. Редактируя файл /.csvn/html/header.html и меняя значения переменных в файле /etc/csvnrc, пользователь может сменить favicon.ico, поменять тему подсветки синтаксиса, выбрать изображения для собственных репозиториев, задать ключевые слова для поисковых систем, а также выполнить множество других настроек своего сервера.

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

Посмотреть на рабочую копию cSvn сервера можно здесь.

© Habrahabr.ru