#!/bin/bash
#  net/tool/trac.in - Trac Support

set -e

lib_load 'sys/tool/virtualenv'

######
# Settings

net_tool_trac_config_init() {
	lib_setting_vars trac_host trac_root trac_admin
	lib_setting_vars -ro trac_owner trac_group trac_db
	lib_setting_vars -ro trac_wsgi_script

	lib_setting_arrays -ro trac_site_dirs
	trac_site_dirs=( conf eggs logs data wsgi )
}

net_tool_trac_config_check() {
	export PYTHON_EGG_CACHE="$trac_root/eggs"

	trac_group=${trac_group:-$trac_owner}
	trac_wsgi_script=${trac_wsgi_script:-$trac_root/wsgi/trac.wsgi}
}


######
# Native dependencies

# FIXME: need wsgi deps
trac_server_packages=( libapache2-mod-python libldap2-dev libsasl2-dev )

# $trac_python_packages[] - List of Python packages to run Trac
trac_python_packages=(
		Babel
		Trac
		TracMasterTickets
		https://trac-hacks.org/svn/accountmanagerplugin/trunk
		https://trac-hacks.org/svn/usermanagerplugin/1.2
		python-ldap
		https://trac-hacks.org/svn/ldapacctmngrplugin/trunk/ldapacctmngrplugin
		https://trac-hacks.org/svn/ldapplugin/0.12
		)


######
# Admin

trac_admin() {
	ve_activate "$trac_root"
	run trac-admin $(pwd) "$@"
}


######
# Site

is_site_owner() { [ "$USER" = "$trac_owner" ]; }
is_site_dir() { test -d "${1:-.}/wsgi"; }

trac_site_wsgi() {
	has_args 2 "$@"
	echo "$trac_root/wsgi/$1-$2.py"
}

trac_site_init() {
	# create and change to site directory
	[ -d "$trac_root" ] || run_mkdir "$trac_root"
	run_pushd "$trac_root"
	run_mkdir "${trac_site_dirs[@]}"

	# create/update virtual machine
	(
		ve_create "$trac_root"
		ve_activate "$trac_root"
		ve_install "${trac_python_packages[@]}"
	)  2>&1 | tee logs/init.log
	run_popd
}

trac_site_delete() {
	run rm -rfv "$trac_root"
}

trac_site_datadir() { echo "$trac_root/data"; }


######
# Project Groups

trac_project_groups() {
	local ddir
	ddir=$(trac_site_datadir)
	file_readdir "$ddir"
}

trac_project_groupdir() { has_args 1 "$@"; echo "$(trac_site_datadir)/$1"; }

# for_each_trac_group() - Calls a function ($@) with each project
# group in the current Trac site.
for_each_trac_group() {
	min_args 1 "$@"
	local -a groups
	groups=( $(trac_project_groups) )
	for_each "$*" "${groups[@]}"
}


######
# Projects

trac_projects() {
	local gdir
	gdir=$(trac_project_groupdir "$@")
	file_readdir "$gdir"
}

# for_each_trac_project() - Calls a function ($@) with each project
# in the given project group ($1).
for_each_trac_project() {
	min_args 2 "$@"
	local group=$1
	shift
	local -a projects
	projects=( $(trac_projects "$group") )
	for_each "$*" "${projects[@]}"
}

# trac_project_dir() - Prints name of project directory for given host
# ($1) and project name ($2).
trac_project_dir() {
	has_args 2 "$@"
	echo "$(trac_site_datadir)/$1/$2"
}

# trac_project_run() - Run a command in the given project directory.
# $1 - Project group
# $2 - Project name
trac_project_run() {
	min_args 3 "$@"
	local dir
	dir=$(trac_project_dir "$1" "$2")
	shift 2

	run_in_dir "$dir" "$@"
}


# trac_project_exists() - Checks whether a project eixsts
# $1 - Project group
# $2 - Project name
trac_project_exists() {
	has_args 2 "$@"
	local dir
	dir=$(trac_project_dir "$@")
	[ -f "$dir/VERSION" ]
}

# trac_project_config_file() - Prints project configuration file name
# $1 - Project group
# $2 - Project name
trac_project_config_file() {
	local dir
	dir=$(trac_project_dir "$@")
	echo "$dir/conf/trac.ini"
}
# trac_project_log_file() - Prints project log file name
# $1 - Project group
# $2 - Project name
# $3 - Log name (default: ``trac.log``)
trac_project_log_file() {
	min_max_args 2 3 "$@"
	local dir
	dir=$(trac_project_dir "$1" "$2")
	local file=${3:-trac.log}
	echo "$dir/log/$file"
}


trac_project_new() {
	has_args 3 "$@"
	local host=$1
	local name=$2
	local desc=$3

	! trac_project_exists "$1" "$2" || error "$host/$name: project exists"

	app_echo "$host/$name: creating project directory"

	local pdir
	pdir="$(trac_site_datadir)/$host/$name"
	run_mkdir "$pdir"
	run_pushd "$pdir"

	app_echo "$host/$name: running trac-admin to create project"

	local log
	log=$(cmd_tempfile)
	trac_admin initenv "$desc" "$trac_db" 2>&1 | tee "$log"
	run mv "$log" log/init.log

	run_popd
}

trac_project_delete() {
	has_args 2 "$@"
	local host=$1
	local name=$2
	trac_project_disable "$@"
	local dir
	dir=$(trac_project_dir "$@")
	run rm -rf "$dir"
}

trac_project_enable() {
	has_args 2 "$@"
	local host=$1
	local name=$2
	local wsgi
	wsgi=$(trac_site_wsgi "$@")
	if [ -L "$wsgi" ]; then
		warn "$host/$name: project already enabled"
	else
		run ln -s "$trac_wsgi_script" "$wsgi"
		info "$host/$name: project enabled"
	fi
}

trac_project_disable() {
	has_args 2 "$@"
	local host=$1
	local name=$2
	local wsgi
	wsgi=$(trac_site_wsgi "$@")
	if [ -L "$wsgi" ]; then
		run rm "$wsgi"
		info "$host/$name: project disabled"
	else
		warn "$host/$name: project was not enabled"
	fi
}

######
# Permissions

# trac_project_perm_add() - Grants permissions to a user ($3) for the
# given group ($1) project ($2).
trac_project_perm_add() {
	local pgroup=$1
	local pname=$2
	local puser=$3
	shift 3
	trac_project_run "$pgroup" "$pname" \
		for_each "trac_admin permission add $puser" "$@"
}


######
# Repositories

# trac_repos_dir() - Prints path to a Trac-hosted repository.
# $1 - Group name
# $2 - Project name
# $3 - Repository name
trac_repos_dir() {
	min_max_args 2 3 "$@"

	local pdir
	pdir=$(trac_project_dir "$1" "$2")

	local ppath
	[ -z "$3" ] || ppath="/$3.git"

	echo "$pdir/repos$ppath"
}

# trac_project_repos() - Prints list of repositories
trac_project_repos() {
	local rdir
	rdir=$(trac_repos_dir "$@")
	[ -d "$rdir" ] || return 0
	file_readdir "$rdir" |sed -e 's,\.git,,'
}

# for_each_trac_repo() - Calls a function ($@) with each repository
# in the given group ($1) project ($2).
for_each_trac_repo() {
	min_args 3 "$@"
	local group=$1
	local project=$2
	shift 2
	local -a repos
	repos=( $(trac_project_repos "$group" "$project") )
	for_each "$*" "${repos[@]}"
}

# trac_project_run() - Run a command in the given project directory.
# $1 - Group name
# $2 - Project name
# $3 - Repository name
# $@ - Command to run
trac_repo_run() {
	min_args 4 "$@"

	local dir
	dir=$(trac_repos_dir "$1" "$2" "$3")
	shift 3

	[  -d "$dir" ] || error "$dir: repository does not exist"

	run_in_dir "$dir" "$@"
}

# trac_repo_exists() - Returns success if a repository exists for a project
# $1 - Group name
# $2 - Project name
# $3 - Repository name
trac_repo_exists() { [ -d "$(trac_repos_dir "$@")" ]; }

# trac_repo_clone() - Clones a repository from a URL into a project
# $1 - Group name
# $2 - Project name
# $3 - Repository name
# $4 - Repository URL
trac_repo_clone() {
	has_args 4 "$@"

	local rpath
	rpath=$(trac_repos_dir "$1" "$2" "$3")
	[ ! -d "$rpath" ] || error "$rpath: repository exists"

	lib_load 'sys/tool/git'
	git_clone --bare "$4" "$rpath"
}

# trac_repo_update() - Updates a repository for a project
# $1 - Group name
# $2 - Project name
# $3 - Repository name
trac_repo_update() {
	has_args 3 "$@"
	lib_load 'sys/tool/git'
	trac_repo_run "$@" git_fetch
	trac_repo_sync "$@"
}

# trac_repo_delete() - Deletes a repository from a project
# $1 - Group name
# $2 - Project name
# $3 - Repository name
trac_repo_delete() {
	has_args 3 "$@"

	local rdir
	rdir=$(trac_repos_dir "$@")
	run rm -rf "$rdir"
}

# trac_repo_sync() - Synchronizes the specified project repository
# $1 - Group name
# $2 - Project name
# $3 - Repository name
trac_repo_sync() {
	has_args 3 "$@"
	trac_project_run "$1" "$2" trac_admin repository resync "$3"
}

# trac_repo_hook_init() - Creates a Git repository hook file, taking
# input from `stdin`.
# $1 - Group name
# $2 - Project name
# $3 - Repository name
# $4 - Hook name
trac_repo_hook_init() {
	has_args 4 "$@"

	local rdir
	rdir=$(trac_repos_dir "$1" "$2" "$3")

	local hookfile="$rdir/hooks/$4"
	cat >"$hookfile"
	run chmod a+x "$hookfile"
}

# trac_repo_post_commit() - Runs the post-commit hook to update Trac.
# input from `stdin`.
# $1 - Group name
# $2 - Project name
# $3 - Repository name
# $4 - Revision
trac_repo_post_commit() {
	has_args 4 "$@"
	trac_project_run "$1" "$2" trac_admin changeset added "$3" "$4"
}

# trac_repo_post_receive() - Runs the post-receive hook to update Trac.
# input from `stdin`.
# $1 - Group name
# $2 - Project name
# $3 - Repository name
trac_repo_post_receive() {
	has_args 3 "$@"
	local oldrev newrev refname
	while read oldrev newrev refname; do
		if [ "$oldrev" = 0000000000000000000000000000000000000000 ]; then
			git rev-list --reverse "$newrev" --
		else
			git rev-list --reverse "$newrev" "^$oldrev" --
		fi | xargs trac_repo_post_commit "$@"
	done
}


######
# Cron support

# trac_cron_run() - Runs all periodic Trac tasks
trac_cron_run() {
	for_each_trac_group trac_cron_group_run
}
trac_cron_group_run() {
	for_each_trac_project "$1" trac_cron_project_run "$1"
}
trac_cron_project_run() {
	for_each_trac_repo "$1" "$2" trac_cron_repo_run "$1" "$2"
}
trac_cron_repo_run() {
	trac_repo_update "$1" "$2" "$3"
}


######
# Command Support

# trac_dispatch() - Dispatches tool command after activating virtual
# environment for the site.
# $@ - Command and arguments to dispatch
trac_dispatch() {
	is_site_owner || error "must be run by site owner ($trac_owner)"
	is_site_dir || error "must be run in the trac site directory"
	ve_activate
	cmd_dispatch "$@"
}

View the Developer Guide Index

View the Reference Manual Index


Generated on Fri Jul 28 14:35:53 PDT 2017 by mcsh d14 v0.23.0.