cSvn is a web interface for Subversion repositories. Basis cSvn is CGI-script written in C .
In May 2020, the release of the next version of Apache Subversion 1.14.0 was published . In light of this event, a new, modern web interface was created for viewing Subversion repositories on any device. This is very positive news for those who use centralized version control systems due to the fact that until yesterday there was only one decent web-UI ( WebSVN ), written in PHP and, unfortunately, lagging behind modern requirements.
This article covers installing and configuring cSvn to work with Nginx + uWsgi . Setting up server components is quite simple and practically does not differ from setting up cGit .
On the client side, basic JavaScript is running with no more than 350 lines and a 24K style sheet unpacked. Markdown texts are processed on the server side using the md4c library , which has successfully proven itself in the KDE Plasma project .
Instead of screenshots, it's better to look at a running cSvn server .
It is worth noting that using cSvn, you can view not only your own repositories, but also configure viewing of third-party resources via HTTPS and SVN protocols.
System Requirements
cSvn uses the libpcre2 , md4c , libmagic libraries included in the File package and libxml2 . The server must be installed: Nginx HTTP server , uWsgi server and, of course, Apache Subversion .
Installation of products
The cSvn package has two parts. The first is a regular Linux daemon that is responsible for parsing the / etc / csvnrc configuration file . The second is directly a CGI script that responds to HTTP client requests. Both parts are installed at the same time.
Source texts
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, .
/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, , , , .
The appearance of the interface is determined by a single CSS file and therefore the user can change the theme of the web interface as he needs.
You can view a working copy of the cSvn server here .