基于Debian12的SVN和Trac自动安装部署脚本
SVN和Trac自动安装部署脚本使用说明
目录
- 环境要求
- 功能概述
- 安装流程图
- 配置信息
- 插件说明
- 使用方法
- 故障排除
- 最佳实践建议
环境要求
系统要求
- Debian 12 (Bookworm) 操作系统
- 至少1GB内存 (推荐2GB以上)
- 至少10GB可用磁盘空间
- root权限
网络要求
- 互联网连接 (用于下载软件包和插件)
- 可选:固定IP地址或域名 (用于外部访问)
软件依赖
脚本会自动安装以下软件:
- Apache 2.4
- PostgreSQL 最新稳定版
- Python 3.x
- Subversion
- Redis (用于缓存)
- Git (用于插件安装)
功能概述
该脚本提供以下功能:
-
环境准备
- 系统更新
- 依赖包安装
- 环境冲突检测和清理
-
SVN服务器安装
- Subversion安装和配置
- Apache与SVN集成
- 基于Web的SVN访问
- 用户认证和授权管理
-
Trac项目管理系统安装
- Trac核心安装
- PostgreSQL/SQLite数据库配置
- 与SVN集成
- Web界面配置
-
增强插件安装
- 用户管理插件
- LDAP集成认证
- 工作流管理
- 票据模板和统计
- 维基编辑器
- 代码评论系统
- 主题引擎
-
安全配置
- SSL证书生成
- 基本认证
- 权限管理
-
故障修复
- SVN权限修复
- Apache配置修复
- 插件问题诊断
安装流程图
配置信息
SVN配置
- 仓库位置:
/var/svn/repos
- Web访问:
http://svn.example.com/
(可自定义域名) - 认证方式: HTTP基本认证
- 用户文件:
/etc/apache2/dav_svn.passwd
- 授权文件:
/etc/apache2/dav_svn.authz
- 日志位置:
/var/log/apache2/svn_error.log
Trac配置
- 项目位置:
/var/trac/project
- Web访问:
http://trac.example.com/
(可自定义域名) - 数据库: 优先使用PostgreSQL,失败时回退到SQLite
- 认证方式: HTTP基本认证
- 用户文件:
/var/trac/project/htpasswd/trac.htpasswd
- 配置文件:
/var/trac/project/conf/trac.ini
- 日志位置:
/var/log/apache2/trac_error.log
PostgreSQL配置
- 数据库名:
tracdb
- 用户名:
tracadmin
- 密码: 自动生成 (安装完成后显示)
- 优化设置: 根据系统内存自动配置
Apache配置
- 虚拟主机: SVN和Trac各一个
- 模块:
dav
,dav_svn
,wsgi
,ssl
等 - 配置文件:
/etc/apache2/sites-available/svn.conf
/etc/apache2/sites-available/trac.conf
插件说明
插件名称 | 功能描述 | 配置位置 |
---|---|---|
AccountManager | 用户管理、注册、密码重置 | 管理 → 账户 |
TracLDAP | LDAP目录服务集成认证 | trac.ini [ldap] |
TracWorkflowAdmin | 工作流自定义管理 | 管理 → 工作流 |
TracXMLRPC | API访问接口 | 无需配置 |
TracTicketTemplate | 票据模板管理 | 新建票据页面 |
TracTicketStats | 票据统计和图表 | 报表 → 统计 |
TracTags | 标签管理系统 | 全站可用 |
TracWysiwyg | 所见即所得维基编辑器 | 编辑维基页面时 |
TracAnnouncer | 高级通知系统 | trac.ini [announcer] |
TracThemeEngine | 主题定制 | trac.ini [theme] |
TracCodeComments | 代码审查和评论 | 浏览源码时 |
使用方法
基本安装
-
下载脚本到服务器
本页面最下方的代码复制粘贴到自己的文件中。
-
添加执行权限
chmod +x install_svn_trac.sh
-
以root用户运行脚本
sudo ./install_svn_trac.sh
-
按照提示输入SVN和Trac域名
请输入SVN域名 (默认: svn.example.com): svn.your-domain.com 请输入Trac域名 (默认: trac.example.com): trac.your-domain.com
-
如需配置LDAP认证,在提示时选择"y"并输入LDAP服务器信息
-
安装完成后,记录显示的账户信息
SVN修复模式
如果SVN访问出现问题,可以使用修复模式:
sudo ./install_svn_trac.sh fix-svn
访问服务
-
修改本地hosts文件或配置DNS,将域名指向服务器IP
-
访问SVN仓库:
http://svn.your-domain.com/
-
访问Trac项目:
http://trac.your-domain.com/
-
使用安装时创建的管理员账户登录
故障排除
常见问题
-
Apache无法启动
- 检查错误日志:
cat /var/log/apache2/error.log
- 检查配置:
apache2ctl configtest
- 可能原因: 端口冲突、模块缺失、配置错误
- 检查错误日志:
-
SVN访问被拒绝
- 检查权限:
ls -la /var/svn
- 检查认证文件:
cat /etc/apache2/dav_svn.passwd
- 运行修复命令:
./install_svn_trac.sh fix-svn
- 检查权限:
-
Trac插件不工作
- 检查插件安装:
ls -la /opt/trac/plugins
- 检查trac.ini配置:
cat /var/trac/project/conf/trac.ini
- 检查错误日志:
cat /var/log/apache2/trac_error.log
- 检查插件安装:
-
数据库连接失败
- 检查PostgreSQL状态:
systemctl status postgresql
- 测试连接:
su - postgres -c "psql -c '\l'"
- 检查密码: 查看安装日志中的PostgreSQL信息
- 检查PostgreSQL状态:
日志文件位置
- Apache主日志:
/var/log/apache2/error.log
- SVN日志:
/var/log/apache2/svn_error.log
- Trac日志:
/var/log/apache2/trac_error.log
- 安装日志: 脚本运行目录下的
svn_trac_install_*.log
最佳实践建议
-
安全建议
- 在生产环境中,建议使用HTTPS而非HTTP
- 定期更改管理员密码
- 限制对服务器的SSH访问
- 配置防火墙只开放必要端口
-
性能优化
- 对于大型项目,增加服务器内存
- 考虑使用专用的PostgreSQL服务器
- 启用Redis缓存以提高Trac性能
- 定期备份SVN仓库和Trac数据库
-
维护建议
- 定期更新系统和软件包
- 监控磁盘空间使用情况
- 设置日志轮转避免日志文件过大
- 创建定期备份计划
-
扩展建议
- 考虑集成CI/CD系统 (如Jenkins)
- 添加邮件通知功能
- 配置LDAP认证实现单点登录
- 自定义Trac工作流以适应团队流程
附录:环境变量参考
变量名 | 描述 | 默认值 |
---|---|---|
PGDB_PASSWORD | PostgreSQL密码 | 自动生成 |
SVN_ADMIN_PASSWORD | SVN管理员密码 | 自动生成 |
TRAC_ADMIN_PASSWORD | Trac管理员密码 | 自动生成 |
SVN_DOMAIN | SVN域名 | svn.example.com |
TRAC_DOMAIN | Trac域名 | trac.example.com |
其他说明
如有疑问,欢迎联系公众号“大刘讲IT”或QQ709840110
代码
#!/bin/bash
# 确保工作目录存在
ensure_working_directory() {
# 尝试获取当前工作目录
local current_dir
current_dir=$(pwd 2>/dev/null)
# 如果获取失败,切换到一个安全的目录
if [ $? -ne 0 ]; then
echo "警告: 无法获取当前工作目录,切换到/tmp目录"
cd /tmp || cd / || {
echo "严重错误: 无法切换到任何有效目录"
exit 1
}
fi
# 再次检查当前目录是否可访问
if ! pwd &>/dev/null; then
echo "严重错误: 仍然无法访问工作目录,请检查文件系统或权限问题"
exit 1
fi
# 设置安全的工作目录
SAFE_WORKING_DIR=$(pwd)
echo "使用工作目录: $SAFE_WORKING_DIR"
}
# 在脚本开始时调用
ensure_working_directory
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 无颜色
# 日志文件 - 使用绝对路径
LOG_FILE="$SAFE_WORKING_DIR/svn_trac_install_$(date +%Y%m%d_%H%M%S).log"
touch "$LOG_FILE" || {
echo "无法创建日志文件,将使用/tmp目录"
LOG_FILE="/tmp/svn_trac_install_$(date +%Y%m%d_%H%M%S).log"
touch "$LOG_FILE" || {
echo "无法在/tmp创建日志文件,将禁用日志记录"
LOG_FILE="/dev/null"
}
}
# 记录日志的函数
log() {
local message="$1"
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo -e "${timestamp} - ${message}" | tee -a "$LOG_FILE"
}
# 错误处理函数
error_exit() {
log "${RED}错误: $1${NC}"
exit 1
}
# 检查命令是否存在
check_command() {
command -v "$1" >/dev/null 2>&1 || { error_exit "需要 $1 命令,但未找到。请安装后再试。"; }
}
# 检查是否为root用户
check_root() {
if [ "$(id -u)" != "0" ]; then
error_exit "此脚本必须以root用户身份运行"
fi
}
# 检查系统是否为Debian 12
check_debian() {
if [ ! -f /etc/debian_version ]; then
error_exit "此脚本仅适用于Debian系统"
fi
local version=$(cat /etc/debian_version)
if [[ ! $version =~ ^12 ]]; then
log "${YELLOW}警告: 此脚本针对Debian 12优化,当前版本为 $version${NC}"
fi
}
# 更新系统
update_system() {
log "更新系统包列表..."
apt update -y || error_exit "无法更新系统包列表"
log "升级系统包..."
apt upgrade -y || error_exit "无法升级系统包"
log "安装基本工具..."
apt install -y curl wget gnupg2 lsb-release apt-transport-https ca-certificates software-properties-common || error_exit "无法安装基本工具"
}
# 检查并清理冲突环境
check_and_clean_conflicts() {
log "检查可能的环境冲突..."
# 停止可能运行的服务
log "停止可能运行的服务..."
systemctl stop postgresql apache2 redis-server 2>/dev/null || true
# 杀死可能残留的进程
log "杀死可能残留的进程..."
pkill -f apache2 || true
pkill -f postgres || true
pkill -f redis || true
# 检查PostgreSQL
if dpkg -l | grep -q postgresql; then
log "${YELLOW}检测到已安装的PostgreSQL,将卸载...${NC}"
# 删除所有PostgreSQL数据库和用户
if command -v psql &> /dev/null; then
log "尝试删除PostgreSQL数据库和用户..."
su - postgres -c "psql -c \"DROP DATABASE IF EXISTS tracdb;\"" 2>/dev/null || log "${YELLOW}无法删除tracdb数据库${NC}"
su - postgres -c "psql -c \"DROP USER IF EXISTS tracadmin;\"" 2>/dev/null || log "${YELLOW}无法删除tracadmin用户${NC}"
# 断开所有连接
su - postgres -c "psql -c \"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='tracdb';\"" 2>/dev/null || true
fi
# 完全卸载PostgreSQL
apt purge -y postgresql* || log "${YELLOW}无法完全卸载PostgreSQL${NC}"
apt autoremove -y --purge
# 彻底清理PostgreSQL文件和目录
find / -name "*postgres*" -type d -exec rm -rf {} \; 2>/dev/null || true
find / -name "*postgresql*" -type d -exec rm -rf {} \; 2>/dev/null || true
rm -rf /var/lib/postgresql || log "${YELLOW}无法删除PostgreSQL数据目录${NC}"
rm -rf /etc/postgresql || log "${YELLOW}无法删除PostgreSQL配置目录${NC}"
rm -rf /var/log/postgresql || log "${YELLOW}无法删除PostgreSQL日志目录${NC}"
rm -rf /var/run/postgresql || log "${YELLOW}无法删除PostgreSQL运行目录${NC}"
# 清理可能残留的PostgreSQL用户
if id -u postgres &>/dev/null; then
log "${YELLOW}尝试删除postgres系统用户...${NC}"
userdel -rf postgres 2>/dev/null || log "${YELLOW}无法删除postgres用户${NC}"
fi
# 清理可能残留的PostgreSQL组
if getent group postgres &>/dev/null; then
log "${YELLOW}尝试删除postgres系统组...${NC}"
groupdel postgres 2>/dev/null || log "${YELLOW}无法删除postgres组${NC}"
fi
fi
# 检查Apache
if dpkg -l | grep -q apache2; then
log "${YELLOW}检测到已安装的Apache2,将卸载...${NC}"
# 完全卸载Apache及其所有模块
apt purge -y apache2* libapache2* || log "${YELLOW}无法完全卸载Apache2${NC}"
apt autoremove -y --purge
# 彻底清理Apache文件和目录
find / -name "*apache*" -type d -exec rm -rf {} \; 2>/dev/null || true
rm -rf /etc/apache2 || log "${YELLOW}无法删除Apache2配置目录${NC}"
rm -rf /var/www || log "${YELLOW}无法删除Apache2网站目录${NC}"
rm -rf /var/lib/apache2 || log "${YELLOW}无法删除Apache2库目录${NC}"
rm -rf /var/log/apache2 || log "${YELLOW}无法删除Apache2日志目录${NC}"
rm -rf /var/cache/apache2 || log "${YELLOW}无法删除Apache2缓存目录${NC}"
rm -rf /run/apache2 || log "${YELLOW}无法删除Apache2运行目录${NC}"
# 清理可能残留的Apache用户
if id -u www-data &>/dev/null; then
log "${YELLOW}重置www-data用户...${NC}"
# 不删除www-data用户,因为它可能被其他服务使用,但重置其主目录
usermod -d /var/www www-data 2>/dev/null || true
fi
fi
# 检查SVN
if dpkg -l | grep -q subversion; then
log "${YELLOW}检测到已安装的Subversion,将卸载...${NC}"
apt purge -y subversion* || log "${YELLOW}无法卸载Subversion${NC}"
apt autoremove -y --purge
# 彻底清理SVN文件和目录
find / -name "*svn*" -type d -exec rm -rf {} \; 2>/dev/null || true
rm -rf /var/svn || log "${YELLOW}无法完全删除SVN仓库${NC}"
rm -rf /etc/subversion || log "${YELLOW}无法删除Subversion配置目录${NC}"
rm -rf /usr/local/svn || log "${YELLOW}无法删除Subversion本地安装${NC}"
fi
# 检查Trac
if pip3 list 2>/dev/null | grep -q trac; then
log "${YELLOW}检测到已安装的Trac,将卸载...${NC}"
pip3 uninstall -y trac || log "${YELLOW}无法卸载Trac${NC}"
fi
# 清理Trac环境
find / -name "*trac*" -type d -exec rm -rf {} \; 2>/dev/null || true
rm -rf /var/trac || log "${YELLOW}无法完全删除Trac文件${NC}"
rm -rf /opt/trac || log "${YELLOW}无法删除Trac虚拟环境${NC}"
rm -rf /usr/local/trac || log "${YELLOW}无法删除Trac本地安装${NC}"
# 检查Redis
if dpkg -l | grep -q redis; then
log "${YELLOW}检测到已安装的Redis,将卸载...${NC}"
apt purge -y redis* || log "${YELLOW}无法卸载Redis${NC}"
apt autoremove -y --purge
# 彻底清理Redis文件和目录
find / -name "*redis*" -type d -exec rm -rf {} \; 2>/dev/null || true
rm -rf /var/lib/redis || log "${YELLOW}无法删除Redis数据目录${NC}"
rm -rf /etc/redis || log "${YELLOW}无法删除Redis配置目录${NC}"
rm -rf /var/log/redis || log "${YELLOW}无法删除Redis日志目录${NC}"
rm -rf /var/run/redis || log "${YELLOW}无法删除Redis运行目录${NC}"
fi
# 清理Python虚拟环境和包
rm -rf ~/.cache/pip || true
rm -rf /root/.cache/pip || true
# 清理系统临时文件
rm -rf /tmp/* || true
# 清理可能残留的配置文件
rm -f /etc/apt/sources.list.d/pgdg.list || true
# 更新包列表
apt update
log "${GREEN}环境检查完成,已彻底清理可能的冲突${NC}"
# 验证清理结果
log "验证清理结果..."
if dpkg -l | grep -q postgresql; then
log "${RED}警告: PostgreSQL仍然存在,可能需要手动清理${NC}"
fi
if dpkg -l | grep -q apache2; then
log "${RED}警告: Apache2仍然存在,可能需要手动清理${NC}"
fi
if dpkg -l | grep -q subversion; then
log "${RED}警告: Subversion仍然存在,可能需要手动清理${NC}"
fi
if dpkg -l | grep -q redis; then
log "${RED}警告: Redis仍然存在,可能需要手动清理${NC}"
fi
}
# 安装PostgreSQL
install_postgresql() {
log "安装PostgreSQL最新稳定版..."
# 添加PostgreSQL官方仓库
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
apt update
# 安装PostgreSQL最新稳定版
apt install -y postgresql postgresql-contrib || error_exit "无法安装PostgreSQL"
# 确保PostgreSQL服务启动
systemctl enable postgresql
systemctl start postgresql
# 生成随机密码(避免特殊字符)
PGDB_PASSWORD=$(openssl rand -hex 12)
# 创建数据库用户和数据库
log "配置PostgreSQL用户和数据库..."
su - postgres -c "psql -c \"DROP DATABASE IF EXISTS tracdb;\"" || log "${YELLOW}无法删除已存在的tracdb数据库${NC}"
su - postgres -c "psql -c \"DROP USER IF EXISTS tracadmin;\"" || log "${YELLOW}无法删除已存在的tracadmin用户${NC}"
su - postgres -c "psql -c \"CREATE USER tracadmin WITH PASSWORD '$PGDB_PASSWORD';\""
su - postgres -c "psql -c \"CREATE DATABASE tracdb OWNER tracadmin;\""
# 确保tracadmin用户有足够的权限
su - postgres -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE tracdb TO tracadmin;\""
# 优化PostgreSQL配置
log "优化PostgreSQL性能配置..."
# 获取系统内存信息(以KB为单位)
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
# 转换为MB
local mem_total_mb=$((mem_total / 1024))
# 根据系统内存计算合适的配置值
local shared_buffers=$((mem_total_mb / 4))
local effective_cache_size=$((mem_total_mb * 3 / 4))
local work_mem=$((mem_total_mb / 16))
local maintenance_work_mem=$((mem_total_mb / 8))
# 确保最小值
if [ $shared_buffers -lt 128 ]; then shared_buffers=128; fi
if [ $work_mem -lt 4 ]; then work_mem=4; fi
if [ $maintenance_work_mem -lt 16 ]; then maintenance_work_mem=16; fi
# 备份原始配置
cp /etc/postgresql/*/main/postgresql.conf /etc/postgresql/*/main/postgresql.conf.bak
# 应用优化配置
cat > /tmp/pg_config.sql << EOF
ALTER SYSTEM SET shared_buffers = '${shared_buffers}MB';
ALTER SYSTEM SET effective_cache_size = '${effective_cache_size}MB';
ALTER SYSTEM SET work_mem = '${work_mem}MB';
ALTER SYSTEM SET maintenance_work_mem = '${maintenance_work_mem}MB';
ALTER SYSTEM SET random_page_cost = 1.1;
ALTER SYSTEM SET effective_io_concurrency = 200;
ALTER SYSTEM SET max_worker_processes = 8;
ALTER SYSTEM SET max_parallel_workers_per_gather = 4;
ALTER SYSTEM SET max_parallel_workers = 8;
ALTER SYSTEM SET wal_buffers = '16MB';
ALTER SYSTEM SET checkpoint_completion_target = 0.9;
ALTER SYSTEM SET default_statistics_target = 100;
EOF
su - postgres -c "psql -f /tmp/pg_config.sql"
rm /tmp/pg_config.sql
# 修改pg_hba.conf以允许密码认证
PG_HBA_CONF=$(find /etc/postgresql -name pg_hba.conf | head -n 1)
if [ -n "$PG_HBA_CONF" ]; then
# 备份原始配置
cp "$PG_HBA_CONF" "${PG_HBA_CONF}.bak"
# 修改配置允许本地连接使用密码
sed -i 's/local.*all.*all.*peer/local all all md5/' "$PG_HBA_CONF"
sed -i 's/host.*all.*all.*127.0.0.1\/32.*ident/host all all 127.0.0.1\/32 md5/' "$PG_HBA_CONF"
sed -i 's/host.*all.*all.*::1\/128.*ident/host all all ::1\/128 md5/' "$PG_HBA_CONF"
log "${GREEN}已修改PostgreSQL认证配置${NC}"
else
log "${YELLOW}找不到pg_hba.conf文件${NC}"
fi
# 重启PostgreSQL以应用更改
systemctl restart postgresql
# 测试数据库连接
log "测试PostgreSQL连接..."
if su - postgres -c "psql -c \"\\connect tracdb\""; then
log "${GREEN}PostgreSQL连接测试成功${NC}"
else
log "${RED}PostgreSQL连接测试失败${NC}"
fi
log "${GREEN}PostgreSQL安装和优化完成${NC}"
# 保存数据库信息
PGDB_INFO="PostgreSQL用户名: tracadmin\nPostgreSQL密码: $PGDB_PASSWORD\nPostgreSQL数据库: tracdb"
}
# 安装Redis
install_redis() {
log "安装Redis服务器..."
apt install -y redis-server || error_exit "无法安装Redis"
# 优化Redis配置
log "优化Redis配置..."
# 备份原始配置
cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
# 应用优化配置
sed -i 's/^# maxmemory .*/maxmemory 256mb/' /etc/redis/redis.conf
sed -i 's/^# maxmemory-policy .*/maxmemory-policy allkeys-lru/' /etc/redis/redis.conf
# 启用持久化
sed -i 's/^appendonly no/appendonly yes/' /etc/redis/redis.conf
# 重启Redis以应用更改
systemctl restart redis-server
systemctl enable redis-server
log "${GREEN}Redis安装和优化完成${NC}"
}
# 安装Apache和依赖
install_apache() {
log "安装Apache和依赖..."
# 确保完全卸载旧的Apache安装
apt purge -y apache2* libapache2* || log "${YELLOW}无法完全卸载旧的Apache安装${NC}"
rm -rf /etc/apache2 || log "${YELLOW}无法删除Apache配置目录${NC}"
# 安装Apache和必要的模块
apt install -y apache2 apache2-bin apache2-utils || error_exit "无法安装Apache"
# 安装SSL相关模块,特别是mod_socache_shmcb
apt install -y apache2-ssl-dev || log "${YELLOW}无法安装Apache SSL开发包${NC}"
# 确保安装了所有必要的Apache模块
log "安装Apache模块..."
apt install -y libapache2-mod-wsgi-py3 || error_exit "无法安装mod_wsgi模块"
# 安装SVN模块
log "安装SVN的Apache模块..."
apt install -y libapache2-mod-svn || log "${YELLOW}无法安装libapache2-mod-svn,将在安装SVN时再次尝试${NC}"
# 如果mod_python已安装,卸载它
if dpkg -l | grep -q libapache2-mod-python; then
log "${YELLOW}检测到mod_python已安装,正在卸载...${NC}"
apt remove -y libapache2-mod-python
# 确保mod_python模块被禁用
if [ -f "/etc/apache2/mods-enabled/python.load" ]; then
rm -f "/etc/apache2/mods-enabled/python.load"
fi
if [ -f "/etc/apache2/mods-enabled/python.conf" ]; then
rm -f "/etc/apache2/mods-enabled/python.conf"
fi
fi
# 确保mods-enabled目录存在
mkdir -p /etc/apache2/mods-enabled
# 启用必要的模块
log "启用Apache模块..."
# 首先启用socache_shmcb模块(SSL需要)
if [ -f "/usr/sbin/a2enmod" ]; then
/usr/sbin/a2enmod socache_shmcb || log "${YELLOW}无法使用a2enmod启用socache_shmcb模块${NC}"
else
if [ -f "/etc/apache2/mods-available/socache_shmcb.load" ]; then
ln -sf "/etc/apache2/mods-available/socache_shmcb.load" "/etc/apache2/mods-enabled/socache_shmcb.load"
log "${GREEN}已手动启用socache_shmcb模块${NC}"
else
log "${RED}找不到socache_shmcb模块,SSL可能无法正常工作${NC}"
fi
fi
# 定义要启用的模块列表 - 移除dav_svn,将在安装SVN后启用
MODULES=("ssl" "wsgi" "rewrite" "proxy" "proxy_http" "headers" "dav")
# 循环启用每个模块
for module in "${MODULES[@]}"; do
log "启用模块: $module"
if [ -f "/usr/sbin/a2enmod" ]; then
/usr/sbin/a2enmod $module || log "${YELLOW}无法使用a2enmod启用$module模块${NC}"
else
if [ -f "/etc/apache2/mods-available/$module.load" ]; then
ln -sf "/etc/apache2/mods-available/$module.load" "/etc/apache2/mods-enabled/$module.load"
if [ -f "/etc/apache2/mods-available/$module.conf" ]; then
ln -sf "/etc/apache2/mods-available/$module.conf" "/etc/apache2/mods-enabled/$module.conf"
fi
log "${GREEN}已手动启用模块: $module${NC}"
else
log "${YELLOW}模块 $module 不存在,跳过...${NC}"
fi
fi
done
# 优化Apache配置
log "优化Apache配置..."
# 备份原始配置
if [ -f /etc/apache2/apache2.conf ]; then
cp /etc/apache2/apache2.conf /etc/apache2/apache2.conf.bak
else
log "${YELLOW}找不到Apache配置文件,跳过备份...${NC}"
fi
# 确保conf-available目录存在
mkdir -p /etc/apache2/conf-available
mkdir -p /etc/apache2/conf-enabled
# 应用优化配置
cat > /etc/apache2/conf-available/performance.conf << EOF
# Apache性能优化
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 150
MaxConnectionsPerChild 0
</IfModule>
EOF
# 手动启用性能配置
ln -sf /etc/apache2/conf-available/performance.conf /etc/apache2/conf-enabled/performance.conf
log "${GREEN}已启用性能配置${NC}"
# 禁用默认站点,避免冲突
if [ -f /etc/apache2/sites-enabled/000-default.conf ]; then
log "${YELLOW}禁用默认站点配置...${NC}"
rm -f /etc/apache2/sites-enabled/000-default.conf
fi
# 检查Apache配置
if [ -x "/usr/sbin/apache2ctl" ]; then
if ! /usr/sbin/apache2ctl configtest; then
log "${YELLOW}Apache配置存在语法错误,尝试修复...${NC}"
# 检查SSL配置中是否缺少socache_shmcb模块
if grep -q "SSLSessionCache.*shmcb" /etc/apache2/mods-enabled/ssl.conf; then
log "${YELLOW}检测到SSL配置需要socache_shmcb模块,尝试修复...${NC}"
# 修改SSL配置
if [ -f "/etc/apache2/mods-enabled/ssl.conf" ]; then
# 备份原始配置
cp /etc/apache2/mods-enabled/ssl.conf /etc/apache2/mods-enabled/ssl.conf.bak
# 注释掉可能导致问题的行
sed -i 's/^SSLSessionCache/#SSLSessionCache/' /etc/apache2/mods-enabled/ssl.conf
log "${GREEN}已修复SSL配置${NC}"
fi
fi
fi
fi
# 启用Apache服务
systemctl enable apache2
# 尝试启动Apache
if ! systemctl start apache2; then
log "${YELLOW}Apache启动失败,尝试查看错误日志...${NC}"
if [ -f /var/log/apache2/error.log ]; then
tail -n 20 /var/log/apache2/error.log | tee -a "$LOG_FILE"
fi
# 尝试修复常见问题
log "${YELLOW}尝试修复Apache启动问题...${NC}"
# 检查端口冲突
if netstat -tuln | grep -q ':80\s'; then
log "${RED}检测到端口80被占用,尝试停止占用进程...${NC}"
fuser -k 80/tcp || log "${YELLOW}无法停止占用端口80的进程${NC}"
fi
# 再次尝试启动
systemctl start apache2 || log "${RED}Apache仍然无法启动${NC}"
else
log "${GREEN}Apache启动成功${NC}"
fi
# 验证Apache是否正在运行
if systemctl is-active --quiet apache2; then
log "${GREEN}Apache安装和优化完成${NC}"
return 0
else
log "${RED}Apache未能正常运行,但将继续安装过程${NC}"
return 1
fi
}
# 生成SSL证书
generate_ssl_certs() {
local domain=$1
local cert_dir="/etc/ssl/private"
log "为 $domain 生成自签名SSL证书..."
# 确保目录存在
mkdir -p $cert_dir
# 生成私钥和证书
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout $cert_dir/$domain.key \
-out $cert_dir/$domain.crt \
-subj "/C=CN/ST=State/L=City/O=Organization/OU=IT/CN=$domain" \
|| error_exit "无法生成SSL证书"
# 设置适当的权限
chmod 600 $cert_dir/$domain.key
chmod 644 $cert_dir/$domain.crt
log "${GREEN}SSL证书生成完成${NC}"
}
# 安装SVN
install_svn() {
log "安装Subversion..."
apt install -y subversion || error_exit "无法安装Subversion"
# 检查Apache是否已安装
if ! command -v apache2 &> /dev/null; then
log "${YELLOW}Apache可能未正确安装,尝试重新安装...${NC}"
apt update
apt install -y apache2 apache2-utils
fi
# 安装SVN的Apache模块
log "安装SVN的Apache模块..."
apt install -y libapache2-mod-svn || {
log "${RED}无法安装libapache2-mod-svn,尝试替代方法...${NC}"
# 尝试安装旧版本模块名称
apt install -y libapache2-svn || log "${RED}无法安装SVN的Apache模块${NC}"
}
# 确保SVN模块已启用
if [ -f "/usr/sbin/a2enmod" ]; then
log "启用SVN相关模块..."
/usr/sbin/a2enmod dav_svn || log "${YELLOW}无法启用dav_svn模块${NC}"
/usr/sbin/a2enmod authz_svn || log "${YELLOW}无法启用authz_svn模块${NC}"
else
log "${YELLOW}找不到a2enmod命令,尝试手动启用SVN模块...${NC}"
# 手动启用SVN模块
if [ -f "/etc/apache2/mods-available/dav_svn.load" ]; then
ln -sf "/etc/apache2/mods-available/dav_svn.load" "/etc/apache2/mods-enabled/dav_svn.load"
if [ -f "/etc/apache2/mods-available/dav_svn.conf" ]; then
ln -sf "/etc/apache2/mods-available/dav_svn.conf" "/etc/apache2/mods-enabled/dav_svn.conf"
fi
log "${GREEN}已手动启用dav_svn模块${NC}"
else
log "${RED}找不到dav_svn模块,SVN可能无法通过Web访问${NC}"
# 尝试查找模块文件
find /usr -name "*dav_svn*" -type f | while read -r file; do
log "找到可能的SVN模块文件: $file"
done
fi
if [ -f "/etc/apache2/mods-available/authz_svn.load" ]; then
ln -sf "/etc/apache2/mods-available/authz_svn.load" "/etc/apache2/mods-enabled/authz_svn.load"
if [ -f "/etc/apache2/mods-available/authz_svn.conf" ]; then
ln -sf "/etc/apache2/mods-available/authz_svn.conf" "/etc/apache2/mods-enabled/authz_svn.conf"
fi
log "${GREEN}已手动启用authz_svn模块${NC}"
fi
fi
# 创建SVN仓库目录
mkdir -p /var/svn
# 创建一个示例仓库
log "创建示例SVN仓库..."
svnadmin create /var/svn/repos
# 设置权限 - 确保www-data用户有完全访问权限
chown -R www-data:www-data /var/svn
chmod -R 755 /var/svn
# 创建一个简单的README文件
log "初始化示例仓库内容..."
mkdir -p /tmp/svn-import
echo "# 示例SVN仓库" > /tmp/svn-import/README.md
echo "这是一个由安装脚本自动创建的示例仓库。" >> /tmp/svn-import/README.md
echo "创建时间: $(date)" >> /tmp/svn-import/README.md
# 导入示例内容
svn import -m "初始导入" /tmp/svn-import file:///var/svn/repos/trunk
rm -rf /tmp/svn-import
log "配置SVN访问控制..."
# 创建SVN用户文件
SVN_ADMIN_PASSWORD=$(openssl rand -base64 8)
# 使用htpasswd创建密码文件
apt install -y apache2-utils || log "${YELLOW}无法安装apache2-utils,将使用touch创建空密码文件${NC}"
# 确保目录存在
mkdir -p /etc/apache2
# 创建密码文件
if command -v htpasswd &> /dev/null; then
htpasswd -bc /etc/apache2/dav_svn.passwd admin $SVN_ADMIN_PASSWORD
else
log "${YELLOW}找不到htpasswd命令,使用替代方法创建密码文件${NC}"
# 使用openssl创建密码哈希
PASS_HASH=$(openssl passwd -apr1 $SVN_ADMIN_PASSWORD)
echo "admin:$PASS_HASH" > /etc/apache2/dav_svn.passwd
fi
# 确保密码文件权限正确
chmod 640 /etc/apache2/dav_svn.passwd
chown root:www-data /etc/apache2/dav_svn.passwd
# 创建SVN授权文件
log "创建SVN授权文件..."
cat > /etc/apache2/dav_svn.authz << EOF
[groups]
admins = admin
[/]
@admins = rw
* = r
[repos:/]
@admins = rw
* = r
EOF
chmod 644 /etc/apache2/dav_svn.authz
chown root:www-data /etc/apache2/dav_svn.authz
# 检查Apache配置
if command -v apache2ctl &> /dev/null; then
apache2ctl configtest || log "${YELLOW}Apache配置测试失败,可能需要手动修复${NC}"
else
log "${YELLOW}找不到apache2ctl命令,跳过配置测试...${NC}"
fi
# 重启Apache以应用SVN模块
systemctl restart apache2 || log "${YELLOW}无法重启Apache服务${NC}"
log "${GREEN}Subversion安装完成${NC}"
# 保存SVN信息
SVN_INFO="SVN管理员用户名: admin\nSVN管理员密码: $SVN_ADMIN_PASSWORD\nSVN仓库路径: /var/svn/repos"
}
# 修复SVN权限问题
fix_svn_permissions() {
log "修复SVN权限问题..."
# 确保SVN仓库目录存在
if [ ! -d "/var/svn" ]; then
log "${RED}SVN仓库目录不存在,创建目录...${NC}"
mkdir -p /var/svn
fi
# 确保示例仓库存在
if [ ! -d "/var/svn/repos" ]; then
log "${RED}示例SVN仓库不存在,创建仓库...${NC}"
svnadmin create /var/svn/repos
fi
# 设置正确的权限
log "设置SVN仓库权限..."
chown -R www-data:www-data /var/svn
chmod -R 755 /var/svn
# 确保Apache可以访问仓库
usermod -a -G www-data www-data
# 检查SVN模块是否已启用
if [ -f "/usr/sbin/a2enmod" ]; then
log "确保SVN模块已启用..."
/usr/sbin/a2enmod dav_svn
/usr/sbin/a2enmod authz_svn
fi
# 检查密码文件是否存在
if [ ! -f "/etc/apache2/dav_svn.passwd" ]; then
log "${RED}SVN密码文件不存在,创建默认密码文件...${NC}"
SVN_ADMIN_PASSWORD=$(openssl rand -base64 8)
htpasswd -bc /etc/apache2/dav_svn.passwd admin $SVN_ADMIN_PASSWORD
chmod 640 /etc/apache2/dav_svn.passwd
chown root:www-data /etc/apache2/dav_svn.passwd
log "创建了新的SVN管理员密码: $SVN_ADMIN_PASSWORD"
fi
# 检查授权文件是否存在
if [ ! -f "/etc/apache2/dav_svn.authz" ]; then
log "${RED}SVN授权文件不存在,创建默认授权文件...${NC}"
cat > /etc/apache2/dav_svn.authz << EOF
[groups]
admins = admin
[/]
@admins = rw
* = r
[repos:/]
@admins = rw
* = r
EOF
chmod 644 /etc/apache2/dav_svn.authz
chown root:www-data /etc/apache2/dav_svn.authz
fi
# 重启Apache
log "重启Apache服务..."
systemctl restart apache2
log "${GREEN}SVN权限修复完成${NC}"
}
# 安装Python和Trac依赖
install_python_deps() {
log "安装Python和Trac依赖..."
apt install -y python3 python3-pip python3-dev python3-setuptools python3-wheel git || error_exit "无法安装Python和Git"
# 安装LDAP相关依赖
log "安装LDAP相关依赖..."
apt install -y libldap2-dev libsasl2-dev || log "${YELLOW}无法安装LDAP开发库,LDAP认证可能无法正常工作${NC}"
# 安装Python虚拟环境
apt install -y python3-venv || error_exit "无法安装Python虚拟环境"
# 创建虚拟环境
mkdir -p /opt/trac
python3 -m venv /opt/trac/venv
# 安装Trac和依赖
/opt/trac/venv/bin/pip install --upgrade pip
# 安装特定版本的Trac和依赖,避免兼容性问题
/opt/trac/venv/bin/pip install trac==1.4.3 || log "${YELLOW}无法安装指定版本的Trac,尝试安装最新版本...${NC}"
/opt/trac/venv/bin/pip install trac || error_exit "无法安装Trac"
# 安装PostgreSQL适配器
/opt/trac/venv/bin/pip install psycopg2-binary || log "${YELLOW}无法安装psycopg2-binary,Trac将无法使用PostgreSQL${NC}"
# 安装Redis支持
/opt/trac/venv/bin/pip install redis || log "${YELLOW}无法安装Redis Python客户端,Trac将不使用Redis缓存${NC}"
# 创建插件目录
mkdir -p /opt/trac/plugins
cd /opt/trac/plugins || log "${RED}无法切换到插件目录${NC}"
# 安装常用Trac插件
log "安装常用Trac插件..."
# 用户管理插件 - 从PyPI安装
/opt/trac/venv/bin/pip install TracAccountManager || log "${YELLOW}无法安装TracAccountManager插件${NC}"
# LDAP认证插件 - 从源码安装
/opt/trac/venv/bin/pip install python-ldap || log "${YELLOW}无法安装python-ldap库${NC}"
# 尝试从GitHub安装TracLDAP
log "从GitHub安装TracLDAP插件..."
if [ ! -d "/opt/trac/plugins/trac-ldap" ]; then
git clone https://github.com/trac-hacks/trac-ldap.git || log "${YELLOW}无法克隆TracLDAP仓库${NC}"
if [ -d "/opt/trac/plugins/trac-ldap" ]; then
cd /opt/trac/plugins/trac-ldap || log "${RED}无法切换到TracLDAP目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracLDAP插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 安装替代的工作流插件 - TracWorkflowAdmin
log "安装工作流插件(替代方案)..."
if [ ! -d "/opt/trac/plugins/trac-workflowadmin" ]; then
git clone https://github.com/trac-hacks/trac-workflowadmin.git || log "${YELLOW}无法克隆TracWorkflowAdmin仓库${NC}"
if [ -d "/opt/trac/plugins/trac-workflowadmin" ]; then
cd /opt/trac/plugins/trac-workflowadmin || log "${RED}无法切换到TracWorkflowAdmin目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracWorkflowAdmin插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# XML-RPC插件(用于API访问)- 已成功安装,无需修改
/opt/trac/venv/bin/pip install TracXMLRPC || log "${YELLOW}无法安装TracXMLRPC插件${NC}"
# 高级票据管理 - 从GitHub安装
log "安装票据模板插件(替代方案)..."
if [ ! -d "/opt/trac/plugins/trac-tickettemplate" ]; then
git clone https://github.com/trac-hacks/trac-tickettemplate.git || log "${YELLOW}无法克隆TracTicketTemplate仓库${NC}"
if [ -d "/opt/trac/plugins/trac-tickettemplate" ]; then
cd /opt/trac/plugins/trac-tickettemplate || log "${RED}无法切换到TracTicketTemplate目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracTicketTemplate插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 图表插件 - 使用TracTicketStatistics作为替代
log "安装票据统计插件(替代方案)..."
if [ ! -d "/opt/trac/plugins/trac-ticketstats" ]; then
git clone https://github.com/trac-hacks/trac-ticketstats.git || log "${YELLOW}无法克隆TracTicketStats仓库${NC}"
if [ -d "/opt/trac/plugins/trac-ticketstats" ]; then
cd /opt/trac/plugins/trac-ticketstats || log "${RED}无法切换到TracTicketStats目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracTicketStats插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 标签插件 - 从GitHub安装
log "安装标签插件..."
if [ ! -d "/opt/trac/plugins/trac-tags" ]; then
git clone https://github.com/trac-hacks/trac-tags-plugin.git trac-tags || log "${YELLOW}无法克隆TracTags仓库${NC}"
if [ -d "/opt/trac/plugins/trac-tags" ]; then
cd /opt/trac/plugins/trac-tags || log "${RED}无法切换到TracTags目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracTags插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 维基增强插件 - 使用TracWysiwyg作为替代
log "安装维基编辑器插件(替代方案)..."
if [ ! -d "/opt/trac/plugins/trac-wysiwyg" ]; then
git clone https://github.com/trac-hacks/trac-wysiwyg.git || log "${YELLOW}无法克隆TracWysiwyg仓库${NC}"
if [ -d "/opt/trac/plugins/trac-wysiwyg" ]; then
cd /opt/trac/plugins/trac-wysiwyg || log "${RED}无法切换到TracWysiwyg目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracWysiwyg插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 通知插件 - 使用TracAnnouncer作为替代
log "安装通知插件(替代方案)..."
if [ ! -d "/opt/trac/plugins/trac-announcer" ]; then
git clone https://github.com/trac-hacks/trac-announcer.git || log "${YELLOW}无法克隆TracAnnouncer仓库${NC}"
if [ -d "/opt/trac/plugins/trac-announcer" ]; then
cd /opt/trac/plugins/trac-announcer || log "${RED}无法切换到TracAnnouncer目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracAnnouncer插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 安装其他有用的插件
# 主题插件
log "安装主题插件..."
/opt/trac/venv/bin/pip install TracThemeEngine || log "${YELLOW}无法安装TracThemeEngine插件${NC}"
# 代码审查插件
log "安装代码审查插件..."
if [ ! -d "/opt/trac/plugins/trac-code-comments" ]; then
git clone https://github.com/trac-hacks/trac-code-comments.git || log "${YELLOW}无法克隆TracCodeComments仓库${NC}"
if [ -d "/opt/trac/plugins/trac-code-comments" ]; then
cd /opt/trac/plugins/trac-code-comments || log "${RED}无法切换到TracCodeComments目录${NC}"
/opt/trac/venv/bin/pip install -e . || log "${YELLOW}无法安装TracCodeComments插件${NC}"
cd /opt/trac/plugins || log "${RED}无法返回插件目录${NC}"
fi
fi
# 返回原始目录
cd "$SAFE_WORKING_DIR" || log "${YELLOW}无法返回原始工作目录${NC}"
# 设置插件目录权限
chown -R www-data:www-data /opt/trac/plugins
log "${GREEN}Python和Trac依赖安装完成${NC}"
}
# 配置Trac插件
configure_trac_plugins() {
local trac_project_path=$1
log "配置Trac插件..."
# 检查trac.ini文件是否存在
if [ ! -f "$trac_project_path/conf/trac.ini" ]; then
log "${RED}找不到trac.ini文件,无法配置插件${NC}"
return 1
fi
# 备份原始配置
cp "$trac_project_path/conf/trac.ini" "$trac_project_path/conf/trac.ini.bak"
# 添加插件配置
log "启用插件组件..."
cat >> "$trac_project_path/conf/trac.ini" << EOF
[components]
# 用户管理插件
acct_mgr.admin.* = enabled
acct_mgr.api.* = enabled
acct_mgr.db.* = enabled
acct_mgr.htfile.* = enabled
acct_mgr.http.* = enabled
acct_mgr.notification.* = enabled
acct_mgr.pwhash.* = enabled
acct_mgr.register.* = enabled
acct_mgr.web_ui.* = enabled
acct_mgr.guard.* = enabled
# 标签插件
tractags.* = enabled
# 工作流插件
workflowadmin.* = enabled
# XML-RPC插件
tracrpc.* = enabled
# 票据模板插件
tickettemplate.* = enabled
# 票据统计插件
ticketstats.* = enabled
# 维基编辑器插件
tracwysiwyg.* = enabled
# 通知插件
announcer.* = enabled
# 主题插件
themeengine.* = enabled
# 代码评论插件
codecomments.* = enabled
[account-manager]
password_store = HtPasswdStore
password_file = /var/trac/project/htpasswd/trac.htpasswd
account_changes_notify_addresses =
authentication_url =
force_passwd_change = true
hash_method = crypt
htpasswd_hash_type = crypt
htpasswd_file = /var/trac/project/htpasswd/trac.htpasswd
password_format = $apr1$(.+?)$(.+)
refresh_passwd = false
user_lock_max_time = 0
verify_email = true
login_attempt_max_count = 3
login_opt_list = True
persistent_sessions = True
cookie_refresh_interval = 1
[theme]
theme = default
disable_trac_css = false
[ticketstats]
stats_interval = 30
stats_default_interval = 30
EOF
# 配置LDAP认证(如果需要)
read -p "是否配置LDAP认证? (y/n, 默认: n): " CONFIGURE_LDAP
CONFIGURE_LDAP=${CONFIGURE_LDAP:-n}
if [ "$CONFIGURE_LDAP" = "y" ] || [ "$CONFIGURE_LDAP" = "Y" ]; then
log "配置LDAP认证..."
# 获取LDAP配置信息
read -p "LDAP服务器地址 (例如: ldap://ldap.example.com): " LDAP_SERVER
read -p "LDAP基础DN (例如: dc=example,dc=com): " LDAP_BASE_DN
read -p "LDAP绑定DN (例如: cn=admin,dc=example,dc=com): " LDAP_BIND_DN
read -p "LDAP绑定密码: " LDAP_BIND_PASSWORD
read -p "LDAP用户过滤器 (例如: (objectClass=person)): " LDAP_USER_FILTER
# 添加LDAP配置
cat >> "$trac_project_path/conf/trac.ini" << EOF
[ldap]
enable = true
basedn = ${LDAP_BASE_DN}
host = ${LDAP_SERVER}
user_rdn = ${LDAP_BIND_DN}
user_filter = ${LDAP_USER_FILTER}
password = ${LDAP_BIND_PASSWORD}
[components]
ldapplugin.* = enabled
EOF
log "${GREEN}LDAP认证配置完成${NC}"
else
log "跳过LDAP认证配置"
fi
# 配置通知
cat >> "$trac_project_path/conf/trac.ini" << EOF
[notification]
smtp_enabled = false
smtp_server = localhost
smtp_port = 25
smtp_user =
smtp_password =
use_tls = false
smtp_from = trac@localhost
smtp_replyto = trac@localhost
smtp_always_cc =
smtp_always_bcc =
[announcer]
email_enabled = false
email_sender = SmtpEmailSender
smtp_server = localhost
smtp_port = 25
smtp_user =
smtp_password =
use_tls = false
smtp_from = trac-announcer@localhost
smtp_replyto = trac-announcer@localhost
EOF
# 配置工作流
cat >> "$trac_project_path/conf/trac.ini" << EOF
[ticket-workflow]
accept = new,assigned,accepted,reopened -> accepted
accept.operations = set_owner_to_self
accept.permissions = TICKET_MODIFY
leave = * -> *
leave.operations = leave_status
leave.default = 1
reassign = new,assigned,accepted,reopened -> assigned
reassign.operations = set_owner
reassign.permissions = TICKET_MODIFY
reopen = closed -> reopened
reopen.operations = del_resolution
reopen.permissions = TICKET_CREATE
resolve = new,assigned,accepted,reopened -> closed
resolve.operations = set_resolution
resolve.permissions = TICKET_MODIFY
EOF
# 配置代码评论
cat >> "$trac_project_path/conf/trac.ini" << EOF
[codecomments]
comments_path = /var/trac/project/code-comments
enable_email = false
EOF
# 创建代码评论目录
mkdir -p /var/trac/project/code-comments
chown -R www-data:www-data /var/trac/project/code-comments
log "${GREEN}Trac插件配置完成${NC}"
}
# 配置Trac
configure_trac() {
log "配置Trac..."
# 创建Trac项目目录
mkdir -p /var/trac
# 检查是否已存在Trac项目
if [ -d "/var/trac/project" ]; then
log "${YELLOW}检测到已存在的Trac项目,将删除并重新创建...${NC}"
rm -rf /var/trac/project
fi
# 确保目录存在且权限正确
mkdir -p /var/trac
chown -R www-data:www-data /var/trac
# 获取Trac版本信息
TRAC_VERSION=$(/opt/trac/venv/bin/trac-admin --version | head -n 1)
log "Trac版本: $TRAC_VERSION"
# 测试PostgreSQL连接
log "测试PostgreSQL连接..."
if PGPASSWORD="${PGDB_PASSWORD}" psql -h localhost -U tracadmin -d tracdb -c "\l" > /dev/null 2>&1; then
log "${GREEN}PostgreSQL连接测试成功${NC}"
USE_POSTGRES=true
else
log "${YELLOW}PostgreSQL连接测试失败,将使用SQLite作为备选${NC}"
USE_POSTGRES=false
fi
# 创建一个示例Trac项目
log "初始化Trac项目环境..."
# 确保项目目录不存在
rm -rf /var/trac/project
# 尝试不同的数据库连接方式
if [ "$USE_POSTGRES" = true ]; then
log "尝试使用PostgreSQL初始化Trac..."
# 尝试多种PostgreSQL连接字符串格式
DB_CONN_STRINGS=(
"postgres://tracadmin:${PGDB_PASSWORD}@localhost:5432/tracdb"
"postgresql://tracadmin:${PGDB_PASSWORD}@localhost:5432/tracdb"
"postgres://tracadmin:${PGDB_PASSWORD}@localhost/tracdb"
"postgresql://tracadmin:${PGDB_PASSWORD}@localhost/tracdb"
)
INIT_SUCCESS=false
for conn_string in "${DB_CONN_STRINGS[@]}"; do
log "尝试连接字符串: $conn_string"
if /opt/trac/venv/bin/trac-admin /var/trac/project initenv "示例项目" "$conn_string"; then
log "${GREEN}使用连接字符串 '$conn_string' 成功初始化Trac项目${NC}"
INIT_SUCCESS=true
break
fi
done
if [ "$INIT_SUCCESS" = false ]; then
log "${YELLOW}所有PostgreSQL连接尝试均失败,将使用SQLite作为备选...${NC}"
USE_POSTGRES=false
fi
fi
# 如果PostgreSQL连接失败,使用SQLite
if [ "$USE_POSTGRES" = false ]; then
log "使用SQLite初始化Trac..."
# 确保SQLite目录存在
mkdir -p /var/trac/project/db
# 尝试使用SQLite初始化
if ! /opt/trac/venv/bin/trac-admin /var/trac/project initenv "示例项目" "sqlite:db/trac.db"; then
log "${RED}SQLite初始化也失败,尝试手动创建基本环境...${NC}"
# 手动创建Trac环境
mkdir -p /var/trac/project/conf
mkdir -p /var/trac/project/db
mkdir -p /var/trac/project/log
mkdir -p /var/trac/project/plugins
mkdir -p /var/trac/project/htdocs
# 创建空的SQLite数据库文件
touch /var/trac/project/db/trac.db
# 创建最小配置文件
cat > /var/trac/project/conf/trac.ini << EOF
[header_logo]
alt = 示例项目
height = -1
link =
src = site/your_project_logo.png
width = -1
[project]
descr = 示例Trac项目
footer = 访问 <a href="https://trac.edgewall.org/">Trac开源项目</a>
icon = common/trac.ico
name = 示例项目
url =
[trac]
base_url =
database = sqlite:db/trac.db
admin = admin
EOF
# 尝试使用trac-admin初始化数据库
if /opt/trac/venv/bin/trac-admin /var/trac/project upgrade; then
log "${GREEN}成功升级Trac数据库${NC}"
else
log "${RED}无法升级Trac数据库,尝试创建基本表结构...${NC}"
# 尝试使用sqlite3命令行工具创建基本表结构
if command -v sqlite3 &> /dev/null; then
# 安装sqlite3(如果尚未安装)
apt install -y sqlite3
# 创建基本表结构
sqlite3 /var/trac/project/db/trac.db << EOF
CREATE TABLE system (
name TEXT PRIMARY KEY,
value TEXT
);
INSERT INTO system VALUES ('database_version', '45');
CREATE TABLE permission (
username TEXT,
action TEXT,
UNIQUE (username, action)
);
INSERT INTO permission VALUES ('admin', 'TRAC_ADMIN');
EOF
log "${GREEN}已手动创建基本SQLite表结构${NC}"
else
log "${RED}找不到sqlite3命令,无法创建基本表结构${NC}"
fi
fi
log "${YELLOW}已手动创建基本Trac环境${NC}"
else
log "${GREEN}已使用SQLite成功初始化Trac项目${NC}"
fi
PGDB_INFO="$PGDB_INFO\n注意: Trac使用SQLite数据库而非PostgreSQL"
fi
# 设置权限
chown -R www-data:www-data /var/trac
# 创建Trac管理员用户
TRAC_ADMIN_PASSWORD=$(openssl rand -hex 8)
log "配置Trac管理员..."
# 获取trac-admin帮助信息
/opt/trac/venv/bin/trac-admin /var/trac/project help > /tmp/trac-admin-help.txt 2>&1
# 尝试不同的命令格式添加管理员
if grep -q "permission add" /tmp/trac-admin-help.txt; then
log "使用 'permission add' 命令添加管理员权限..."
if /opt/trac/venv/bin/trac-admin /var/trac/project permission add admin TRAC_ADMIN; then
log "${GREEN}成功添加管理员权限${NC}"
else
log "${YELLOW}无法使用permission add命令添加管理员权限,尝试直接修改数据库...${NC}"
# 如果使用SQLite,尝试直接修改数据库
if [ "$USE_POSTGRES" = false ] && command -v sqlite3 &> /dev/null; then
if sqlite3 /var/trac/project/db/trac.db "INSERT OR REPLACE INTO permission VALUES ('admin', 'TRAC_ADMIN');"; then
log "${GREEN}已直接在SQLite数据库中添加管理员权限${NC}"
else
log "${RED}无法在SQLite数据库中添加管理员权限${NC}"
fi
fi
fi
fi
# 手动修改trac.ini文件确保管理员设置存在
log "确保trac.ini中包含管理员设置..."
if [ -f "/var/trac/project/conf/trac.ini" ]; then
# 检查是否已有[trac]部分
if grep -q "^\[trac\]" /var/trac/project/conf/trac.ini; then
# 检查是否已有admin设置
if ! grep -q "^admin = " /var/trac/project/conf/trac.ini; then
# 在[trac]部分添加admin设置
sed -i '/^\[trac\]/a admin = admin' /var/trac/project/conf/trac.ini
log "${GREEN}已在trac.ini中添加管理员设置${NC}"
fi
else
# 添加[trac]部分和admin设置
echo -e "\n[trac]\nadmin = admin" >> /var/trac/project/conf/trac.ini
log "${GREEN}已添加[trac]部分和管理员设置${NC}"
fi
fi
# 创建htpasswd文件用于基本认证
log "创建htpasswd文件用于基本认证..."
mkdir -p /var/trac/project/htpasswd
htpasswd -bc /var/trac/project/htpasswd/trac.htpasswd admin "$TRAC_ADMIN_PASSWORD"
chown -R www-data:www-data /var/trac/project/htpasswd
# 配置Trac插件
configure_trac_plugins "/var/trac/project"
# 创建WSGI脚本目录
mkdir -p /var/trac/project/cgi-bin
# 创建WSGI脚本
cat > /var/trac/project/cgi-bin/trac.wsgi << EOF
import os
import sys
# 设置环境变量
os.environ['PYTHON_EGG_CACHE'] = '/var/trac/project/.egg-cache'
# 添加虚拟环境路径
python_version = '.'.join(map(str, sys.version_info[:2]))
sys.path.insert(0, '/opt/trac/venv/lib/python{}/site-packages'.format(python_version))
# 设置Trac环境路径
trac_env = '/var/trac/project'
os.environ['TRAC_ENV'] = trac_env
# 导入Trac WSGI应用
from trac.web.main import dispatch_request
application = dispatch_request
# 配置Redis缓存(如果可用)
try:
import redis
from trac.web.main import dispatch_request
from trac.web.session import Session
class RedisSession(Session):
def __init__(self, env, req):
super(RedisSession, self).__init__(env, req)
self.redis = redis.Redis(host='localhost', port=6379, db=0)
def _load(self):
sid = self.sid
if sid:
data = self.redis.get('trac:session:' + sid)
if data:
return eval(data)
return {}
def _save(self):
if not self.sid:
self.sid = self._generate_sid()
self.redis.set('trac:session:' + self.sid, repr(self.data))
self.redis.expire('trac:session:' + self.sid, 86400 * 30) # 30天过期
# 替换Session类
trac.web.main.Session = RedisSession
except Exception as e:
# 记录错误但不中断
print("Redis缓存配置失败:", str(e))
EOF
# 设置WSGI脚本权限
chown -R www-data:www-data /var/trac/project/cgi-bin
chmod 755 /var/trac/project/cgi-bin/trac.wsgi
# 创建.egg-cache目录并设置权限
mkdir -p /var/trac/project/.egg-cache
chown www-data:www-data /var/trac/project/.egg-cache
log "${GREEN}Trac配置完成${NC}"
# 保存Trac信息
TRAC_INFO="Trac管理员用户名: admin\nTrac管理员密码: $TRAC_ADMIN_PASSWORD"
}
# 配置Apache虚拟主机
configure_apache_vhosts() {
local svn_domain=$1
local trac_domain=$2
log "配置Apache虚拟主机..."
# 检查Apache是否已安装
if ! command -v apache2 &> /dev/null; then
log "${YELLOW}Apache可能未正确安装,尝试重新安装...${NC}"
apt update
apt install -y apache2 apache2-utils libapache2-mod-wsgi-py3
# 安装SSL相关模块
apt install -y apache2-ssl-dev
fi
# 确保必要的目录存在
mkdir -p /etc/apache2/sites-available
mkdir -p /etc/apache2/sites-enabled
# 确保所有必要的模块都已启用
log "确保所有必要的Apache模块都已启用..."
# 首先启用socache_shmcb模块(SSL需要)
if [ -f "/usr/sbin/a2enmod" ]; then
/usr/sbin/a2enmod socache_shmcb
/usr/sbin/a2enmod ssl
/usr/sbin/a2enmod wsgi
/usr/sbin/a2enmod rewrite
/usr/sbin/a2enmod proxy
/usr/sbin/a2enmod proxy_http
/usr/sbin/a2enmod headers
/usr/sbin/a2enmod dav
/usr/sbin/a2enmod dav_svn
/usr/sbin/a2enmod authz_svn
else
log "${YELLOW}找不到a2enmod命令,尝试手动启用模块...${NC}"
# 手动启用模块
for module in socache_shmcb ssl wsgi rewrite proxy proxy_http headers dav dav_svn authz_svn; do
if [ -f "/etc/apache2/mods-available/$module.load" ]; then
ln -sf "/etc/apache2/mods-available/$module.load" "/etc/apache2/mods-enabled/$module.load"
if [ -f "/etc/apache2/mods-available/$module.conf" ]; then
ln -sf "/etc/apache2/mods-available/$module.conf" "/etc/apache2/mods-enabled/$module.conf"
fi
log "${GREEN}已手动启用模块: $module${NC}"
else
log "${YELLOW}模块 $module 不存在,跳过...${NC}"
fi
done
fi
# 修复SSL配置
if [ -f "/etc/apache2/mods-enabled/ssl.conf" ]; then
# 检查是否有SSLSessionCache配置
if grep -q "SSLSessionCache.*shmcb" /etc/apache2/mods-enabled/ssl.conf; then
# 备份原始配置
cp /etc/apache2/mods-enabled/ssl.conf /etc/apache2/mods-enabled/ssl.conf.bak
# 注释掉可能导致问题的行
sed -i 's/^SSLSessionCache/#SSLSessionCache/' /etc/apache2/mods-enabled/ssl.conf
log "${GREEN}已修复SSL配置${NC}"
fi
fi
# SVN虚拟主机配置 - 修改为更详细的配置
cat > /etc/apache2/sites-available/svn.conf << EOF
<VirtualHost *:80>
ServerName ${svn_domain}
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
# 启用SVN
<Location />
DAV svn
SVNParentPath /var/svn
# 认证设置
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
# 添加SVN特定设置
SVNListParentPath On
SVNAutoversioning On
# 确保权限正确
<IfModule mod_authz_svn.c>
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
</IfModule>
</Location>
# 设置目录权限
<Directory /var/svn>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# 日志设置
ErrorLog \${APACHE_LOG_DIR}/svn_error.log
CustomLog \${APACHE_LOG_DIR}/svn_access.log combined
</VirtualHost>
EOF
# 创建SVN授权文件(如果不存在)
if [ ! -f /etc/apache2/dav_svn.authz ]; then
log "创建SVN授权文件..."
cat > /etc/apache2/dav_svn.authz << EOF
[groups]
admins = admin
[/]
@admins = rw
* = r
EOF
chmod 644 /etc/apache2/dav_svn.authz
chown root:www-data /etc/apache2/dav_svn.authz
fi
# Trac虚拟主机配置(使用HTTP而非HTTPS,避免SSL问题)
cat > /etc/apache2/sites-available/trac.conf << EOF
<VirtualHost *:80>
ServerName ${trac_domain}
# 获取Python版本
WSGIDaemonProcess trac user=www-data group=www-data python-home=/opt/trac/venv
WSGIProcessGroup trac
WSGIScriptAlias / /var/trac/project/cgi-bin/trac.wsgi
<Directory /var/trac/project/cgi-bin>
WSGIApplicationGroup %{GLOBAL}
Require all granted
</Directory>
<Location "/">
AuthType Basic
AuthName "Trac"
AuthUserFile /var/trac/project/htpasswd/trac.htpasswd
Require valid-user
</Location>
ErrorLog \${APACHE_LOG_DIR}/trac_error.log
CustomLog \${APACHE_LOG_DIR}/trac_access.log combined
</VirtualHost>
EOF
# 手动启用站点
ln -sf /etc/apache2/sites-available/svn.conf /etc/apache2/sites-enabled/
ln -sf /etc/apache2/sites-available/trac.conf /etc/apache2/sites-enabled/
# 禁用默认站点,避免冲突
if [ -f /etc/apache2/sites-enabled/000-default.conf ]; then
log "${YELLOW}禁用默认站点配置...${NC}"
rm -f /etc/apache2/sites-enabled/000-default.conf
fi
# 检查Apache配置
if [ -x "/usr/sbin/apache2ctl" ]; then
if ! /usr/sbin/apache2ctl configtest; then
log "${YELLOW}Apache配置存在语法错误,尝试修复...${NC}"
# 显示详细错误
/usr/sbin/apache2ctl -t -D DUMP_MODULES || log "${YELLOW}无法显示Apache模块${NC}"
fi
fi
# 重启Apache
log "重启Apache服务..."
systemctl restart apache2 || {
log "${YELLOW}Apache重启失败,尝试修复...${NC}"
# 显示错误日志
if [ -f /var/log/apache2/error.log ]; then
log "Apache错误日志:"
tail -n 20 /var/log/apache2/error.log
fi
# 尝试使用不同的方法重启Apache
if [ -x "/usr/sbin/apache2ctl" ]; then
/usr/sbin/apache2ctl stop
sleep 2
/usr/sbin/apache2ctl start
else
systemctl stop apache2
sleep 2
systemctl start apache2
fi
}
# 检查Apache是否正在运行
if systemctl is-active --quiet apache2; then
log "${GREEN}Apache服务已成功启动${NC}"
else
log "${RED}Apache服务未能启动${NC}"
fi
log "${GREEN}Apache虚拟主机配置完成${NC}"
}
# 主函数
main() {
# 记录开始时间
START_TIME=$(date +%s)
log "${BLUE}开始安装Trac和SVN...${NC}"
# 检查是否为root用户
check_root
# 检查系统是否为Debian
check_debian
# 提示用户输入域名
log "请输入SVN和Trac域名信息"
read -p "请输入SVN域名 (默认: svn.example.com): " SVN_DOMAIN
SVN_DOMAIN=${SVN_DOMAIN:-svn.example.com}
read -p "请输入Trac域名 (默认: trac.example.com): " TRAC_DOMAIN
TRAC_DOMAIN=${TRAC_DOMAIN:-trac.example.com}
log "SVN域名: ${SVN_DOMAIN}"
log "Trac域名: ${TRAC_DOMAIN}"
# 更新系统
update_system
# 检查并清理冲突环境
check_and_clean_conflicts
# 安装PostgreSQL
install_postgresql
# 安装Redis
install_redis
# 安装Apache和依赖
if ! install_apache; then
log "${YELLOW}Apache安装可能存在问题,但将继续安装过程...${NC}"
fi
# 生成SSL证书
generate_ssl_certs $SVN_DOMAIN
generate_ssl_certs $TRAC_DOMAIN
# 安装SVN
install_svn
# 安装Python和Trac依赖
install_python_deps
# 配置Trac
configure_trac
# 配置Apache虚拟主机
configure_apache_vhosts $SVN_DOMAIN $TRAC_DOMAIN
# 修复SVN权限问题
fix_svn_permissions
# 记录结束时间并计算总用时
END_TIME=$(date +%s)
TOTAL_TIME=$((END_TIME - START_TIME))
HOURS=$((TOTAL_TIME / 3600))
MINUTES=$(( (TOTAL_TIME % 3600) / 60 ))
SECONDS=$((TOTAL_TIME % 60))
# 显示安装信息
log "${GREEN}安装完成!${NC}"
log "总用时: ${HOURS}小时 ${MINUTES}分钟 ${SECONDS}秒"
log "SVN仓库地址: http://${SVN_DOMAIN}/"
log "Trac项目地址: http://${TRAC_DOMAIN}/"
# 显示数据库信息(如果变量存在)
if [ -n "$PGDB_INFO" ]; then
log "PostgreSQL信息:"
echo -e "$PGDB_INFO" | while IFS= read -r line; do log "$line"; done
fi
# 显示SVN信息(如果变量存在)
if [ -n "$SVN_INFO" ]; then
log "SVN信息:"
echo -e "$SVN_INFO" | while IFS= read -r line; do log "$line"; done
fi
# 显示Trac信息(如果变量存在)
if [ -n "$TRAC_INFO" ]; then
log "Trac信息:"
echo -e "$TRAC_INFO" | while IFS= read -r line; do log "$line"; done
fi
# 显示Trac插件信息
log "已安装的Trac插件:"
log "- AccountManager: 用户管理插件,提供用户注册、密码重置等功能"
log "- TracLDAP: LDAP集成认证插件(从GitHub安装)"
log "- TracWorkflowAdmin: 工作流管理插件(替代TracWorkflow)"
log "- TracXMLRPC: XML-RPC接口插件,提供API访问"
log "- TracTicketTemplate: 票据模板插件(从GitHub安装)"
log "- TracTicketStats: 票据统计插件(替代TracTicketCharts)"
log "- TracTags: 标签插件(从GitHub安装)"
log "- TracWysiwyg: 所见即所得维基编辑器(替代TracWikiExtras)"
log "- TracAnnouncer: 高级通知插件(替代TracNotification)"
log "- TracThemeEngine: 主题引擎插件,支持自定义界面"
log "- TracCodeComments: 代码评论插件,支持代码审查"
log "插件使用指南:"
log "1. 登录Trac后,访问 '管理' -> '插件' 页面可以查看和配置已安装的插件"
log "2. 用户管理功能位于 '管理' -> '账户' 菜单下"
log "3. 如需启用LDAP认证,请编辑 /var/trac/project/conf/trac.ini 文件,配置[ldap]部分"
log "4. 所有插件都已安装在 /opt/trac/plugins 目录下,可以根据需要修改"
log "注意: 您可能需要在hosts文件中添加以下条目:"
log "127.0.0.1 ${SVN_DOMAIN}"
log "127.0.0.1 ${TRAC_DOMAIN}"
log "安装日志已保存到: ${LOG_FILE}"
# 检查安装结果
check_installation_result
return 0
}
# 检查安装结果
check_installation_result() {
log "检查安装结果..."
# 检查Apache是否运行
if systemctl is-active --quiet apache2; then
log "${GREEN}Apache服务正在运行${NC}"
else
log "${RED}警告: Apache服务未运行${NC}"
fi
# 检查PostgreSQL是否运行
if systemctl is-active --quiet postgresql; then
log "${GREEN}PostgreSQL服务正在运行${NC}"
else
log "${RED}警告: PostgreSQL服务未运行${NC}"
fi
# 检查SVN仓库是否存在
if [ -d "/var/svn/repos" ]; then
log "${GREEN}SVN仓库已创建${NC}"
else
log "${RED}警告: SVN仓库未创建${NC}"
fi
# 检查Trac环境是否存在
if [ -d "/var/trac/project" ]; then
log "${GREEN}Trac环境已创建${NC}"
else
log "${RED}警告: Trac环境未创建${NC}"
fi
# 检查SVN模块是否已启用
if [ -f "/etc/apache2/mods-enabled/dav_svn.load" ]; then
log "${GREEN}SVN模块已启用${NC}"
else
log "${RED}警告: SVN模块未启用${NC}"
fi
# 检查SVN配置文件
if [ -f "/etc/apache2/sites-enabled/svn.conf" ]; then
log "${GREEN}SVN虚拟主机配置已启用${NC}"
else
log "${RED}警告: SVN虚拟主机配置未启用${NC}"
fi
# 检查Trac插件是否已安装
log "检查Trac插件安装状态..."
# 检查AccountManager插件
if [ -d "/opt/trac/venv/lib/python3.*/site-packages/acct_mgr" ] || [ -f "/opt/trac/venv/lib/python3.*/site-packages/acct_mgr" ]; then
log "${GREEN}AccountManager插件已安装${NC}"
else
log "${YELLOW}警告: AccountManager插件可能未正确安装${NC}"
fi
# 检查从GitHub安装的插件
if [ -d "/opt/trac/plugins/trac-ldap" ]; then
log "${GREEN}TracLDAP插件已安装${NC}"
else
log "${YELLOW}警告: TracLDAP插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-workflowadmin" ]; then
log "${GREEN}TracWorkflowAdmin插件已安装${NC}"
else
log "${YELLOW}警告: TracWorkflowAdmin插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-tickettemplate" ]; then
log "${GREEN}TracTicketTemplate插件已安装${NC}"
else
log "${YELLOW}警告: TracTicketTemplate插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-ticketstats" ]; then
log "${GREEN}TracTicketStats插件已安装${NC}"
else
log "${YELLOW}警告: TracTicketStats插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-tags" ]; then
log "${GREEN}TracTags插件已安装${NC}"
else
log "${YELLOW}警告: TracTags插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-wysiwyg" ]; then
log "${GREEN}TracWysiwyg插件已安装${NC}"
else
log "${YELLOW}警告: TracWysiwyg插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-announcer" ]; then
log "${GREEN}TracAnnouncer插件已安装${NC}"
else
log "${YELLOW}警告: TracAnnouncer插件可能未正确安装${NC}"
fi
if [ -d "/opt/trac/plugins/trac-code-comments" ]; then
log "${GREEN}TracCodeComments插件已安装${NC}"
else
log "${YELLOW}警告: TracCodeComments插件可能未正确安装${NC}"
fi
# 提供故障排除建议
log "如果遇到问题,请检查以下日志文件:"
log "Apache错误日志: /var/log/apache2/error.log"
log "Trac错误日志: /var/log/apache2/trac_error.log"
log "SVN错误日志: /var/log/apache2/svn_error.log"
log "您可以使用以下命令检查Apache状态:"
log "systemctl status apache2"
log "apache2ctl -t"
log "您可以使用以下命令检查PostgreSQL状态:"
log "systemctl status postgresql"
log "su - postgres -c \"psql -c '\\l'\""
log "如果SVN访问出现问题,可以运行以下命令修复:"
log "bash $0 fix-svn"
log "如果需要重新配置Trac插件,可以编辑以下文件:"
log "/var/trac/project/conf/trac.ini"
log "如果插件安装失败,可以尝试手动安装:"
log "cd /opt/trac/plugins && git clone https://github.com/trac-hacks/插件名称.git"
log "cd 插件目录 && /opt/trac/venv/bin/pip install -e ."
}
# 单独修复SVN问题的函数
fix_svn_only() {
log "${BLUE}开始修复SVN问题...${NC}"
# 检查是否为root用户
check_root
# 安装必要的包
apt update
apt install -y apache2 apache2-utils libapache2-mod-svn subversion
# 修复SVN权限
fix_svn_permissions
# 重新配置Apache虚拟主机
read -p "请输入SVN域名 (默认: svn.example.com): " SVN_DOMAIN
SVN_DOMAIN=${SVN_DOMAIN:-svn.example.com}
# SVN虚拟主机配置 - 修改为更详细的配置
cat > /etc/apache2/sites-available/svn.conf << EOF
<VirtualHost *:80>
ServerName ${SVN_DOMAIN}
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
# 启用SVN
<Location />
DAV svn
SVNParentPath /var/svn
# 认证设置
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
# 添加SVN特定设置
SVNListParentPath On
SVNAutoversioning On
# 确保权限正确
<IfModule mod_authz_svn.c>
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
</IfModule>
</Location>
# 设置目录权限
<Directory /var/svn>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# 日志设置
ErrorLog \${APACHE_LOG_DIR}/svn_error.log
CustomLog \${APACHE_LOG_DIR}/svn_access.log combined
</VirtualHost>
EOF
# 启用站点
ln -sf /etc/apache2/sites-available/svn.conf /etc/apache2/sites-enabled/
# 重启Apache
systemctl restart apache2
log "${GREEN}SVN修复完成!${NC}"
log "SVN仓库地址: http://${SVN_DOMAIN}/"
# 显示SVN信息(如果变量存在)
if [ -n "$SVN_ADMIN_PASSWORD" ]; then
log "SVN管理员用户名: admin"
log "SVN管理员密码: $SVN_ADMIN_PASSWORD"
else
log "SVN管理员用户名: admin"
log "SVN管理员密码: 请查看 /etc/apache2/dav_svn.passwd 文件"
fi
log "注意: 您可能需要在hosts文件中添加以下条目:"
log "127.0.0.1 ${SVN_DOMAIN}"
}
# 调用主函数开始安装或修复
# 确保在安全的工作目录中执行
cd "$SAFE_WORKING_DIR" || {
log "${RED}无法切换到安全的工作目录,将使用当前目录${NC}"
}
# 根据参数决定执行什么操作
if [ "$1" = "fix-svn" ]; then
fix_svn_only
else
# 捕获所有错误并记录
main "$@" || {
EXIT_CODE=$?
log "${RED}安装过程失败,退出代码: $EXIT_CODE${NC}"
log "请检查上述日志以获取详细错误信息"
exit $EXIT_CODE
}
fi