removed the top-level directory
This commit is contained in:
14
etc/Makefile.am
Normal file
14
etc/Makefile.am
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
cfgdir=$(CFGDIR)
|
||||
cfg_DATA = codepot.ini codepot.mysql codepot.pgsql codepot.sqlite codepot.a2ldap codepot.httpd
|
||||
cfg_SCRIPTS = start-commit pre-commit post-commit pre-revprop-change post-revprop-change cloc.pl
|
||||
|
||||
perldir=$(CFGDIR)/perl/Codepot
|
||||
perl_SCRIPTS=perl/Codepot/AccessHandler.pm perl/Codepot/AuthenHandler.pm
|
||||
|
||||
EXTRA_DIST = $(cfg_DATA) $(cfg_SCRIPTS) $(perl_SCRIPTS)
|
||||
|
||||
install-data-hook:
|
||||
perl -e 'use Digest::SHA1' 2>/dev/null || \
|
||||
perl -e 'use Digest::SHA' 2>/dev/null && \
|
||||
sed -ri -e 's|Digest::SHA1|Digest::SHA|g' "$(DESTDIR)$(CFGDIR)/perl/Codepot/AccessHandler.pm"
|
580
etc/Makefile.in
Normal file
580
etc/Makefile.in
Normal file
@ -0,0 +1,580 @@
|
||||
# Makefile.in generated by automake 1.16.5 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2021 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
subdir = etc
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/ac/m4/as-ac-expand.m4 \
|
||||
$(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/./config.h
|
||||
CONFIG_CLEAN_FILES = codepot.ini codepot.a2ldap codepot.httpd \
|
||||
pre-commit start-commit post-commit pre-revprop-change \
|
||||
post-revprop-change
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(cfgdir)" "$(DESTDIR)$(perldir)" \
|
||||
"$(DESTDIR)$(cfgdir)"
|
||||
SCRIPTS = $(cfg_SCRIPTS) $(perl_SCRIPTS)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
DATA = $(cfg_DATA)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/codepot.a2ldap.in \
|
||||
$(srcdir)/codepot.httpd.in $(srcdir)/codepot.ini.in \
|
||||
$(srcdir)/post-commit.in $(srcdir)/post-revprop-change.in \
|
||||
$(srcdir)/pre-commit.in $(srcdir)/pre-revprop-change.in \
|
||||
$(srcdir)/start-commit.in
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BINDIR = @BINDIR@
|
||||
CACHEDIR = @CACHEDIR@
|
||||
CFGDIR = @CFGDIR@
|
||||
CSCOPE = @CSCOPE@
|
||||
CTAGS = @CTAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DATADIR = @DATADIR@
|
||||
DATAROOTDIR = @DATAROOTDIR@
|
||||
DEFS = @DEFS@
|
||||
DEPOTDIR = @DEPOTDIR@
|
||||
DOCDIR = @DOCDIR@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
ETAGS = @ETAGS@
|
||||
GREP = @GREP@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LIBDIR = @LIBDIR@
|
||||
LIBEXECDIR = @LIBEXECDIR@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LOCALSTATEDIR = @LOCALSTATEDIR@
|
||||
LOGDIR = @LOGDIR@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PHPEXTDIR = @PHPEXTDIR@
|
||||
PHPEXTINIDIR = @PHPEXTINIDIR@
|
||||
PREFIX = @PREFIX@
|
||||
RM = @RM@
|
||||
RMDIR = @RMDIR@
|
||||
SBINDIR = @SBINDIR@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
SYSCONFDIR = @SYSCONFDIR@
|
||||
VERSION = @VERSION@
|
||||
WWWDIR = @WWWDIR@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build_alias = @build_alias@
|
||||
builddir = @builddir@
|
||||
cachedir = @cachedir@
|
||||
cfgdir = $(CFGDIR)
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
depotdir = @depotdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host_alias = @host_alias@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
logdir = @logdir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
phpextdir = @phpextdir@
|
||||
phpextinidir = @phpextinidir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
wwwdir = @wwwdir@
|
||||
cfg_DATA = codepot.ini codepot.mysql codepot.pgsql codepot.sqlite codepot.a2ldap codepot.httpd
|
||||
cfg_SCRIPTS = start-commit pre-commit post-commit pre-revprop-change post-revprop-change cloc.pl
|
||||
perldir = $(CFGDIR)/perl/Codepot
|
||||
perl_SCRIPTS = perl/Codepot/AccessHandler.pm perl/Codepot/AuthenHandler.pm
|
||||
EXTRA_DIST = $(cfg_DATA) $(cfg_SCRIPTS) $(perl_SCRIPTS)
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign etc/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign etc/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
codepot.ini: $(top_builddir)/config.status $(srcdir)/codepot.ini.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
codepot.a2ldap: $(top_builddir)/config.status $(srcdir)/codepot.a2ldap.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
codepot.httpd: $(top_builddir)/config.status $(srcdir)/codepot.httpd.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
pre-commit: $(top_builddir)/config.status $(srcdir)/pre-commit.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
start-commit: $(top_builddir)/config.status $(srcdir)/start-commit.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
post-commit: $(top_builddir)/config.status $(srcdir)/post-commit.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
pre-revprop-change: $(top_builddir)/config.status $(srcdir)/pre-revprop-change.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
post-revprop-change: $(top_builddir)/config.status $(srcdir)/post-revprop-change.in
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
|
||||
install-cfgSCRIPTS: $(cfg_SCRIPTS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(cfg_SCRIPTS)'; test -n "$(cfgdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(cfgdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(cfgdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
|
||||
done | \
|
||||
sed -e 'p;s,.*/,,;n' \
|
||||
-e 'h;s|.*|.|' \
|
||||
-e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
|
||||
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
|
||||
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
|
||||
if ($$2 == $$4) { files[d] = files[d] " " $$1; \
|
||||
if (++n[d] == $(am__install_max)) { \
|
||||
print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
|
||||
else { print "f", d "/" $$4, $$1 } } \
|
||||
END { for (d in files) print "f", d, files[d] }' | \
|
||||
while read type dir files; do \
|
||||
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(cfgdir)$$dir'"; \
|
||||
$(INSTALL_SCRIPT) $$files "$(DESTDIR)$(cfgdir)$$dir" || exit $$?; \
|
||||
} \
|
||||
; done
|
||||
|
||||
uninstall-cfgSCRIPTS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(cfg_SCRIPTS)'; test -n "$(cfgdir)" || exit 0; \
|
||||
files=`for p in $$list; do echo "$$p"; done | \
|
||||
sed -e 's,.*/,,;$(transform)'`; \
|
||||
dir='$(DESTDIR)$(cfgdir)'; $(am__uninstall_files_from_dir)
|
||||
install-perlSCRIPTS: $(perl_SCRIPTS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(perl_SCRIPTS)'; test -n "$(perldir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(perldir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(perldir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
|
||||
done | \
|
||||
sed -e 'p;s,.*/,,;n' \
|
||||
-e 'h;s|.*|.|' \
|
||||
-e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
|
||||
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
|
||||
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
|
||||
if ($$2 == $$4) { files[d] = files[d] " " $$1; \
|
||||
if (++n[d] == $(am__install_max)) { \
|
||||
print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
|
||||
else { print "f", d "/" $$4, $$1 } } \
|
||||
END { for (d in files) print "f", d, files[d] }' | \
|
||||
while read type dir files; do \
|
||||
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
|
||||
test -z "$$files" || { \
|
||||
echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(perldir)$$dir'"; \
|
||||
$(INSTALL_SCRIPT) $$files "$(DESTDIR)$(perldir)$$dir" || exit $$?; \
|
||||
} \
|
||||
; done
|
||||
|
||||
uninstall-perlSCRIPTS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(perl_SCRIPTS)'; test -n "$(perldir)" || exit 0; \
|
||||
files=`for p in $$list; do echo "$$p"; done | \
|
||||
sed -e 's,.*/,,;$(transform)'`; \
|
||||
dir='$(DESTDIR)$(perldir)'; $(am__uninstall_files_from_dir)
|
||||
install-cfgDATA: $(cfg_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(cfg_DATA)'; test -n "$(cfgdir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(cfgdir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(cfgdir)" || exit 1; \
|
||||
fi; \
|
||||
for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
echo "$$d$$p"; \
|
||||
done | $(am__base_list) | \
|
||||
while read files; do \
|
||||
echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(cfgdir)'"; \
|
||||
$(INSTALL_DATA) $$files "$(DESTDIR)$(cfgdir)" || exit $$?; \
|
||||
done
|
||||
|
||||
uninstall-cfgDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(cfg_DATA)'; test -n "$(cfgdir)" || list=; \
|
||||
files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
|
||||
dir='$(DESTDIR)$(cfgdir)'; $(am__uninstall_files_from_dir)
|
||||
tags TAGS:
|
||||
|
||||
ctags CTAGS:
|
||||
|
||||
cscope cscopelist:
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(SCRIPTS) $(DATA)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(cfgdir)" "$(DESTDIR)$(perldir)" "$(DESTDIR)$(cfgdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-cfgDATA install-cfgSCRIPTS \
|
||||
install-perlSCRIPTS
|
||||
@$(NORMAL_INSTALL)
|
||||
$(MAKE) $(AM_MAKEFLAGS) install-data-hook
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-generic
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-cfgDATA uninstall-cfgSCRIPTS \
|
||||
uninstall-perlSCRIPTS
|
||||
|
||||
.MAKE: install-am install-data-am install-strip
|
||||
|
||||
.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
|
||||
ctags-am distclean distclean-generic distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-cfgDATA \
|
||||
install-cfgSCRIPTS install-data install-data-am \
|
||||
install-data-hook install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-perlSCRIPTS install-ps install-ps-am install-strip \
|
||||
installcheck installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
|
||||
pdf-am ps ps-am tags-am uninstall uninstall-am \
|
||||
uninstall-cfgDATA uninstall-cfgSCRIPTS uninstall-perlSCRIPTS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
install-data-hook:
|
||||
perl -e 'use Digest::SHA1' 2>/dev/null || \
|
||||
perl -e 'use Digest::SHA' 2>/dev/null && \
|
||||
sed -ri -e 's|Digest::SHA1|Digest::SHA|g' "$(DESTDIR)$(CFGDIR)/perl/Codepot/AccessHandler.pm"
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
17089
etc/cloc.pl
Executable file
17089
etc/cloc.pl
Executable file
File diff suppressed because it is too large
Load Diff
80
etc/codepot.a2ldap.in
Normal file
80
etc/codepot.a2ldap.in
Normal file
@ -0,0 +1,80 @@
|
||||
#
|
||||
# This file contains sample configuration to enable LDAP authentication
|
||||
# for subversion webdav access. The actual configuration can be more
|
||||
# complex than this file depending on your requirement.
|
||||
#
|
||||
|
||||
<Location "/svn">
|
||||
DAV svn
|
||||
SVNParentPath "@DEPOTDIR@/svnrepo"
|
||||
#SVNListParentPath on
|
||||
|
||||
Order deny,allow
|
||||
#Deny from all
|
||||
#Satisfy any
|
||||
|
||||
# Uncomment SSLRequireSSL below to disallow non-SSL access.
|
||||
# Note that SSL must be enabled site-wide to use it.
|
||||
# SSLRequireSSL
|
||||
|
||||
AuthType Basic
|
||||
AuthName "@PACKAGE@"
|
||||
|
||||
#
|
||||
# configure authentication below
|
||||
#
|
||||
|
||||
#
|
||||
# Apache version 2.1 or later
|
||||
# mod_authnz_ldap
|
||||
#
|
||||
AuthBasicProvider ldap
|
||||
|
||||
# prevent other authenticatication moudles from authenticating users
|
||||
# if this one fails. Set it to 'off' for 'require valid-user' as it
|
||||
# is handled by mod_authz_user.
|
||||
AuthzLDAPAuthoritative on
|
||||
|
||||
AuthLDAPGroupAttribute memberUid
|
||||
AuthLDAPGroupAttributeIsDN off
|
||||
AuthLDAPRemoteUserIsDN off
|
||||
|
||||
# ldap binding information
|
||||
AuthLDAPURL ldap://127.0.0.1:389/ou=users,dc=sample,dc=net?uid
|
||||
AuthLDAPBindDN cn=admin,dc=sample,dc=net
|
||||
AuthLDAPBindPassword xxxxxxx
|
||||
|
||||
#Require ldap-group cn=users,ou=groups,dc=sample,dc=net
|
||||
|
||||
# Enable find-grained access control using the access file.
|
||||
# The specified file must be located under the repository/conf subdirectory.
|
||||
# AuthzSVNRespsRelativeAccessFile requried subversion 1.7 or later.
|
||||
# If you're using a older version, there are no automatic repostory
|
||||
# protection according to the project type (public/private)
|
||||
# You may have to use AuthzSVNAccessFile for manual control globally
|
||||
# in such a case.
|
||||
# AuthzSVNReposRelativeAccessFile access.conf
|
||||
# Satisfy All
|
||||
|
||||
# allow anynymous/guest for viewing and checking out
|
||||
<Limit GET HEAD OPTIONS REPORT PROPFIND>
|
||||
# Use 'Allow from all' to allow anonymous access.
|
||||
#Allow from all
|
||||
|
||||
# 'Required valid-user' is more strict in that it requires a valid
|
||||
# user name and password. You may create a guest account to supplement
|
||||
# anonymous access.
|
||||
Require valid-user
|
||||
</Limit>
|
||||
|
||||
# require authentication for other operations
|
||||
<LimitExcept GET HEAD OPTIONS REPORT PROPFIND>
|
||||
Require ldap-group cn=coders,ou=groups,dc=sample,dc=net
|
||||
</LimitExcept>
|
||||
|
||||
#
|
||||
# Apache version 2.0.41
|
||||
# mod_auth_ldap
|
||||
#
|
||||
</Location>
|
||||
|
24
etc/codepot.httpd.in
Normal file
24
etc/codepot.httpd.in
Normal file
@ -0,0 +1,24 @@
|
||||
#
|
||||
# This file contains sample configuration to enable subversion
|
||||
# webdav access. The actual configuration can be more complex
|
||||
# than this file depending on your requirement.
|
||||
#
|
||||
|
||||
<Location "/svn">
|
||||
DAV svn
|
||||
SVNParentPath "@DEPOTDIR@/svnrepo"
|
||||
#SVNListParentPath on
|
||||
|
||||
PerlAccessHandler Codepot::AccessHandler
|
||||
PerlAuthenHandler Codepot::AuthenHandler
|
||||
PerlSetEnv CODEPOT_CONFIG_FILE /etc/codepot/codepot.ini
|
||||
|
||||
# Uncomment SSLRequireSSL below to disallow non-SSL access.
|
||||
# Note that SSL must be enabled site-wide to use it.
|
||||
# SSLRequireSSL
|
||||
|
||||
AuthType Basic
|
||||
AuthName "@PACKAGE@"
|
||||
require valid-user
|
||||
</Location>
|
||||
|
390
etc/codepot.ini.in
Normal file
390
etc/codepot.ini.in
Normal file
@ -0,0 +1,390 @@
|
||||
;------------------------------------------------------------------------------
|
||||
; default site language
|
||||
;------------------------------------------------------------------------------
|
||||
default_site_language = "english"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; default site name
|
||||
;------------------------------------------------------------------------------
|
||||
default_site_name = "@PACKAGE@"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; database settings
|
||||
;
|
||||
; database_driver: mysql, mysqli, postgre, oci8, sqlite
|
||||
;
|
||||
; == PDO mysql ==
|
||||
; database_hostname = "localhost"
|
||||
; database_port = ""
|
||||
; database_username = "codepot"
|
||||
; database_password = "codepot"
|
||||
; database_name = "codepot"
|
||||
; database_driver = "mysql"
|
||||
; database_use_pdo = "yes"
|
||||
; database_prefix = ""
|
||||
;
|
||||
; == PDO sqlite ==
|
||||
; database_hostname = "@DEPOTDIR@/codepot.db"
|
||||
; database_port = ""
|
||||
; database_username = ""
|
||||
; database_password = ""
|
||||
; database_name = ""
|
||||
; database_driver = "sqlite"
|
||||
; database_use_pdo = "yes"
|
||||
; database_prefix = ""
|
||||
;
|
||||
; == MySQL ==
|
||||
; database_hostname = "localhost"
|
||||
; database_port = ""
|
||||
; database_username = "codepot"
|
||||
; database_password = "codepot"
|
||||
; database_name = "codepot"
|
||||
; database_driver = "mysql"
|
||||
; database_use_pdo = "no"
|
||||
; database_prefix = ""
|
||||
;
|
||||
; == PostgresSQL ==
|
||||
; database_hostname = ""
|
||||
; database_port = ""
|
||||
; database_username = "codepot"
|
||||
; database_password = "codepot"
|
||||
; database_name = "codepot"
|
||||
; database_driver = "postgre"
|
||||
; database_use_pdo = "no"
|
||||
; database_prefix = ""
|
||||
;
|
||||
; == Oracle
|
||||
; database_hostname = "(DESCRIPTION=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(HOST=192.168.1.126)(PORT=1521))(CONNECT_DATA=(SID=ORCL)))"
|
||||
; database_port = ""
|
||||
; database_username = "scott"
|
||||
; database_password = "tiger"
|
||||
; database_name = ""
|
||||
; database_driver = "oci8"
|
||||
; database_use_pdo = "no"
|
||||
; database_prefix = "cpot_"
|
||||
;------------------------------------------------------------------------------
|
||||
database_hostname = "localhost"
|
||||
database_port = ""
|
||||
database_username = ""
|
||||
database_password = ""
|
||||
database_name = ""
|
||||
database_driver = ""
|
||||
database_use_pdo = "no"
|
||||
database_prefix = ""
|
||||
database_store_gmt = "yes"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; ldap settings
|
||||
;------------------------------------------------------------------------------
|
||||
; The userid format and the password format can contain
|
||||
; ${userid} and ${password} to represent the actual user ID
|
||||
; and the password respectively.
|
||||
;
|
||||
; If ldap_auth_mode is 1, authentication is performed by binding to
|
||||
; a LDAP server specified using ldap_userid_format as a binddn and
|
||||
; ldap_password_format as a password.
|
||||
;
|
||||
; If ldap_auth_mode is 2, it finds a binddn by searching a subtree
|
||||
; under ldap_userid_search_base using ldap_userid_search_filter
|
||||
; after having bound with ldap_admin_binddn and ldap_admin_password.
|
||||
; The binddn found is used for subsequent binding for authentication.
|
||||
; ldap_userid_format is unused in this mode.
|
||||
;
|
||||
; if you want to specify multiple attributes in ldap_insider_attribute_names
|
||||
; separate them with a space.
|
||||
;------------------------------------------------------------------------------
|
||||
ldap_server_uri = "ldap://127.0.0.1:389"
|
||||
ldap_server_protocol_version = "3"
|
||||
ldap_auth_mode = 2
|
||||
ldap_userid_format = "cn=${userid},ou=users,dc=codepot,dc=org"
|
||||
ldap_password_format = "${password}"
|
||||
ldap_admin_binddn = "cn=admin,dc=codepot,dc=org"
|
||||
ldap_admin_password = "admin-password"
|
||||
ldap_userid_search_filter = "(uid=${userid})"
|
||||
ldap_userid_search_base = "ou=users,dc=codepot,dc=org"
|
||||
ldap_mail_attribute_name = ""
|
||||
ldap_insider_attribute_names = "mssfu30posixmemberof memberof"
|
||||
ldap_insider_attribute_value = ""
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; default langage to use. set it to 'auto' to detect it automatically.
|
||||
; available languages are:
|
||||
; english, korean, indonesian
|
||||
;------------------------------------------------------------------------------
|
||||
language = "auto"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Name of the index page. If you want to hide the index page name from
|
||||
; the URL by rewriting it (e.g. mod_rewrite), you have to change this
|
||||
; properly to match the rewriting rule
|
||||
;------------------------------------------------------------------------------
|
||||
index_page = "index.php"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; When set to yes, viewing pages requires a user to sign in.
|
||||
;------------------------------------------------------------------------------
|
||||
signin_compulsory = "no"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Code read access is limited to the specified user type. The types
|
||||
; include anonymous, authenticated, authenticated-insider, member.
|
||||
; This applies to a public project only. Write access to any projects
|
||||
; and read access to a non-public project require membership regardless
|
||||
; of this item.
|
||||
;------------------------------------------------------------------------------
|
||||
code_read_access = "anonymous"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; File read access is limited to the specified user type. The types
|
||||
; include anonymous, authenticated, authenticated-insider, member.
|
||||
; This applies to a public project only. Write access to any projects
|
||||
; and read access to a non-public project require membership regardless
|
||||
; of this item.
|
||||
;------------------------------------------------------------------------------
|
||||
file_read_access = "anonymous"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; When set to yes, non-http access is diverted to https using
|
||||
; the base URL specified in https_base_url. api calls are not affected.
|
||||
;------------------------------------------------------------------------------
|
||||
https_compulsory = "no"
|
||||
https_url = "https://${SERVER_NAME}${REQUEST_URI}"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Command-separated list of subversion base URLs
|
||||
;------------------------------------------------------------------------------
|
||||
; This URL depends on the webdav configuration for subversion repository.
|
||||
; If you have your repository enabled with SSL under /svn, you can set this to
|
||||
; https://${SERVER_NAME}/svn.
|
||||
; You may specify multiple URLs separated with a comma as shown below:
|
||||
; "http://${SERVER_NAME}/svn, https://${SERVER_NAME}/svn"
|
||||
; All specified URLs are shown in the repository list of the project overview
|
||||
; page.
|
||||
; You may use various items available in $_SERVER when composing the URL.
|
||||
; For example, ${HTTP_HOST} maps to $_SERVER{'HTTP_HOST'}.
|
||||
; Additionally, $_SERVER{'REQUEST_PROTOCOL'} added by config/config.php
|
||||
; can be referenced with ${REQUEST_PROTOCOL} and it is resolved to either
|
||||
; http or https.
|
||||
;------------------------------------------------------------------------------
|
||||
;svn_base_url = "${REQUEST_PROTOCOL}://${SERVER_NAME}:${SERVER_PORT}/svn"
|
||||
svn_base_url = "${REQUEST_PROTOCOL}://${HTTP_HOST}/svn"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Login model to use. LdapLoginModel or DbLoginModel.
|
||||
;------------------------------------------------------------------------------
|
||||
;login_model = "LdapLoginModel"
|
||||
login_model = "DbLoginModel"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Comma separated list of system administrator IDs
|
||||
;------------------------------------------------------------------------------
|
||||
; sysadmin_userids = "tom, dick, jane"
|
||||
;------------------------------------------------------------------------------
|
||||
sysadmin_userids = ""
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum file upload size in Kbytes. You may have to adjust PHP settings
|
||||
; for a large value to work.
|
||||
;------------------------------------------------------------------------------
|
||||
max_upload_size = "10000"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of latest projects to show in the front page
|
||||
;------------------------------------------------------------------------------
|
||||
max_latest_projects = "10"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of projects to show in the top projects graph (0 to hide)
|
||||
;------------------------------------------------------------------------------
|
||||
max_top_projects = "10"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of committers to show in the top committers graph (0 to hide)
|
||||
;------------------------------------------------------------------------------
|
||||
max_top_committers = "10"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of projects to show
|
||||
;------------------------------------------------------------------------------
|
||||
max_projects_per_page = "100"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of issues to show
|
||||
;------------------------------------------------------------------------------
|
||||
max_issues_per_page = "50"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of log entries to show per details page
|
||||
;------------------------------------------------------------------------------
|
||||
max_logs_per_page = "50"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of log entries to show in the front page
|
||||
;------------------------------------------------------------------------------
|
||||
max_logs_in_site_home = "20"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Maximum number of log entries to show in the project home page
|
||||
;------------------------------------------------------------------------------
|
||||
max_logs_in_project_home = "10"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; directory to accomodate subversion repositories
|
||||
;------------------------------------------------------------------------------
|
||||
svnrepo_dir = "@DEPOTDIR@/svnrepo"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; directory to store uploaded files
|
||||
;------------------------------------------------------------------------------
|
||||
file_dir = "@DEPOTDIR@/files"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; directory to store issue attachments
|
||||
;------------------------------------------------------------------------------
|
||||
issue_file_dir = "@DEPOTDIR@/issuefiles"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; directory to store wiki attachments
|
||||
;------------------------------------------------------------------------------
|
||||
attachment_dir = "@DEPOTDIR@/attachments"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; directory to store user icons
|
||||
;------------------------------------------------------------------------------
|
||||
usericon_dir = "@DEPOTDIR@/usericons"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; log threshold
|
||||
;------------------------------------------------------------------------------
|
||||
; 0 = Disables logging, Error logging TURNED OFF
|
||||
; 1 = Error Messages (including PHP errors)
|
||||
; 2 = Debug Messages
|
||||
; 3 = Informational Messages
|
||||
; 4 = All Messages
|
||||
;------------------------------------------------------------------------------
|
||||
log_threshold = 0
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; When yes, open a wiki creation page if a non-existent wiki pages is
|
||||
; requested
|
||||
;------------------------------------------------------------------------------
|
||||
create_missing_wiki = "no"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; When yes, a project member can delete a non-empty project containing
|
||||
; wiki pages, file uploads, etc. An empty project can be deleted any time
|
||||
; regardless of this option. A system administrator(sysadmin_userids) is
|
||||
; allowed to delete a non-empty project also regardless of this option.
|
||||
;------------------------------------------------------------------------------
|
||||
force_project_delete = "no"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; When yes, a codepot page can use set_time_limit() to adjust the maximum
|
||||
; execution time to override the global value. For example, the code search
|
||||
; page can take very long if the code repository is very large. You can
|
||||
; set this item to yes to allow such a page to complete its processing.
|
||||
;------------------------------------------------------------------------------
|
||||
allow_set_time_limit = "no"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; When yes, a user must sign in to be able to search code.
|
||||
; When no, an anonymous user can search code.
|
||||
;------------------------------------------------------------------------------
|
||||
signin_for_code_search = "yes"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; customized footer
|
||||
;------------------------------------------------------------------------------
|
||||
; Leave this empty for the default footer message. You can use a HTML tag as
|
||||
; well as a plain text. For example,
|
||||
; footer = "<u>Code Repository</u>"
|
||||
;------------------------------------------------------------------------------
|
||||
footer = ""
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; CLOC command
|
||||
;------------------------------------------------------------------------------
|
||||
; Full path to the CLOC command
|
||||
;------------------------------------------------------------------------------
|
||||
cloc_command_path = "@CFGDIR@/cloc.pl"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; List of README files to show in the code folder view.
|
||||
; The first file found is shown. You can specify multiple file name
|
||||
; separated by a comma.
|
||||
;------------------------------------------------------------------------------
|
||||
code_folder_readme = "README.md,README.wc,README.txt,README"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Email address to use when sending notification emails
|
||||
;------------------------------------------------------------------------------
|
||||
email_sender = ""
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Send notification upon a new commit if yes
|
||||
;------------------------------------------------------------------------------
|
||||
commit_notification = "yes"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Send commit review notification if yes
|
||||
;------------------------------------------------------------------------------
|
||||
commit_review_notification = "yes"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; URL to include when sending a commit notification message.
|
||||
; You can specify multiple urls. in fact, it's a free text.
|
||||
; Replacement is performed for ${REV}, ${AUTHOR}, ${PROJECTID}.
|
||||
;------------------------------------------------------------------------------
|
||||
commit_notification_url = ""
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Send notification upon new issue registration if yes
|
||||
;------------------------------------------------------------------------------
|
||||
issue_notification = "yes"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Codepot sets this revision property to assign a tag to a specific revision.
|
||||
;------------------------------------------------------------------------------
|
||||
svn_tag_property = "codepot:tag"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Subversion read access is limited to the specified user type. The types
|
||||
; include anonymous, authenticated, authenticated-insider, member.
|
||||
; This applies to a public project only. Write access to any projects
|
||||
; and read access to a non-public project require membership regardless
|
||||
; of this item.
|
||||
;------------------------------------------------------------------------------
|
||||
svn_read_access = "member"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Grant subversion read access to public repository if the user id and the
|
||||
; password match this special credential configured. The value must be
|
||||
; a userid and a password separated by a colon. For example,
|
||||
; svnuser:aab08d13-942c-49bc-b6a7-5ca4408b08d6
|
||||
; This credentical takes precedence over non-anonymous svn_read_access mode.
|
||||
;------------------------------------------------------------------------------
|
||||
svn_read_credential = ""
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; The length of a commit message must be as long as this value.
|
||||
;------------------------------------------------------------------------------
|
||||
svn_min_commit_message_length = "0"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Operations on the files under one of svn_restricted_topdirs
|
||||
; are limited. The value can be separated by a comma.
|
||||
; To allow 1 subdirectory under the tags directory, set the followings:
|
||||
; svn_restricted_topdirs = "tags"
|
||||
; svn_restriction_allowed_subdir_depth_min = "0"
|
||||
; svn_restriction_allowed_subdir_depth_max = "1"
|
||||
;------------------------------------------------------------------------------
|
||||
svn_restricted_topdirs = ""
|
||||
svn_restriction_allowed_subdir_depth_min = "0"
|
||||
svn_restriction_allowed_subdir_depth_max = "0"
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Command separated list of user names who can execute /usr/sbin/codepot-user.
|
||||
; Set it to an empty string to allow all users.
|
||||
;------------------------------------------------------------------------------
|
||||
codepot_user_executor = "root"
|
||||
|
281
etc/codepot.mysql
Normal file
281
etc/codepot.mysql
Normal file
@ -0,0 +1,281 @@
|
||||
-- ---------------------------------------------------------
|
||||
-- This file is the Codepot database schema file for MySQL.
|
||||
-- Note this file doesn't mandate which database to use.
|
||||
-- ---------------------------------------------------------
|
||||
|
||||
CREATE TABLE site (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE project (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
name VARCHAR(255) UNIQUE NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
webhooks TEXT NOT NULL,
|
||||
commitable CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
public CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
codecharset VARCHAR(32),
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL
|
||||
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE project_membership (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
userid VARCHAR(32) NOT NULL,
|
||||
priority INTEGER NOT NULL,
|
||||
UNIQUE KEY membership (projectid, userid),
|
||||
KEY userid_index (userid),
|
||||
KEY projectid_index (projectid),
|
||||
CONSTRAINT membership_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE wiki (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
doctype CHAR(1) NOT NULL DEFAULT 'C',
|
||||
columns INT NOT NULL DEFAULT 1,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE KEY wiki_id (projectid, name),
|
||||
|
||||
CONSTRAINT wiki_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE wiki_attachment (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
wikiname VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE KEY wiki_attachment_id (projectid, wikiname, name),
|
||||
|
||||
CONSTRAINT wiki_attachment_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT wiki_attachment_wikiid FOREIGN KEY (projectid,wikiname) REFERENCES wiki(projectid,name)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE issue (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
id BIGINT NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
type VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
owner VARCHAR(255) NOT NULL,
|
||||
priority VARCHAR(32) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
PRIMARY KEY (projectid, id),
|
||||
KEY issue_status_type_summary (projectid, status, type, summary),
|
||||
KEY issue_summary (projectid, summary),
|
||||
|
||||
CONSTRAINT issue_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE issue_file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
md5sum CHAR(32) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE KEY issue_file_list_id (projectid, issueid, filename),
|
||||
UNIQUE KEY (encname),
|
||||
|
||||
CONSTRAINT issue_file_list_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_file_list_issueid FOREIGN KEY (projectid,issueid) REFERENCES issue(projectid,id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE issue_change (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
id BIGINT NOT NULL,
|
||||
sno BIGINT NOT NULL,
|
||||
|
||||
type VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
owner VARCHAR(255) NOT NULL,
|
||||
priority VARCHAR(32) NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
PRIMARY KEY (projectid, id, sno),
|
||||
KEY issue_update_time (projectid, id, updatedon),
|
||||
|
||||
CONSTRAINT issue_change_id FOREIGN KEY (projectid,id) REFERENCES issue(projectid,id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE issue_change_file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
issuesno BIGINT NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE KEY issue_change_file_list_id (projectid, issueid, filename),
|
||||
|
||||
CONSTRAINT issue_change_file_list_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_change_file_list_issueidsno FOREIGN KEY (projectid,issueid,issuesno) REFERENCES issue_change(projectid,id,sno)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE issue_coderev (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
|
||||
codeproid VARCHAR(32) NOT NULL,
|
||||
coderev VARCHAR(64) NOT NULL, -- git commit id is 40 characters. subversion revision is a number.
|
||||
|
||||
UNIQUE KEY issue_coderev_uid(projectid, issueid, codeproid, coderev),
|
||||
|
||||
KEY issue_coderev_codekey (codeproid, coderev),
|
||||
KEY issue_coderev_issuekey (projectid, issueid),
|
||||
|
||||
CONSTRAINT issue_coderev_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_coderev_codeproid FOREIGN KEY (codeproid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
-- Commit message is typically a free text. Its issue reference could be error-prone.
|
||||
-- So i won't have this constraint enforced.
|
||||
-- CONSTRAINT issue_coderev_issueid FOREIGN KEY (projectid,issueid) REFERENCES issue(projectid,id)
|
||||
-- ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE file (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
tag VARCHAR(54) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE KEY file_id (projectid, name),
|
||||
INDEX file_tagged_name (projectid, tag, name),
|
||||
|
||||
CONSTRAINT file_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
md5sum CHAR(32) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
INDEX file_list_id (projectid, name),
|
||||
UNIQUE KEY file_list_fileid (projectid, filename),
|
||||
UNIQUE KEY (encname),
|
||||
|
||||
CONSTRAINT file_list_projectid FOREIGN KEY (projectid,name) REFERENCES file(projectid,name)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE code_review (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
rev BIGINT NOT NULL,
|
||||
sno BIGINT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
|
||||
updatedon DATETIME NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE KEY code_review_id (projectid, rev, sno),
|
||||
|
||||
CONSTRAINT code_review_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE log (
|
||||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
type VARCHAR(16) NOT NULL,
|
||||
action VARCHAR(16) NOT NULL,
|
||||
userid VARCHAR(32) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
createdon DATETIME NOT NULL,
|
||||
INDEX timed_project_type_action (createdon, projectid, type, action)
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE user_settings (
|
||||
userid VARCHAR(32) PRIMARY KEY,
|
||||
code_hide_line_num CHAR(1) NOT NULL,
|
||||
code_hide_metadata CHAR(1) NOT NULL,
|
||||
icon_name VARCHAR(255) UNIQUE NULL,
|
||||
user_summary VARCHAR(255) NULL
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
||||
CREATE TABLE user_account (
|
||||
userid VARCHAR(32) PRIMARY KEY,
|
||||
passwd VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255),
|
||||
enabled CHAR(1) NOT NULL DEFAULT 'N' CHECK(enabled in ('Y', 'N'))
|
||||
) charset=utf8 engine=InnoDB;
|
||||
|
295
etc/codepot.oracle
Normal file
295
etc/codepot.oracle
Normal file
@ -0,0 +1,295 @@
|
||||
-- ------------------------------------------------------------
|
||||
-- This file is the Codepot database schema file for PostreSQL.
|
||||
-- Note this file doesn't mandate which database to use.
|
||||
--
|
||||
-- Assumining "local all all password" in /var/lib/pgsql/data/pg_hba.conf
|
||||
--
|
||||
-- $ sqlplus "scott/tiger@(DESCRIPTION=(ADDRESS=(COMMUNITY=tcp.world)(PROTOCOL=TCP)(HOST=192.168.1.126)(PORT=1521))(CONNECT_DATA=(SID=ORCL)))"
|
||||
-- SQL> @codepot.oracle
|
||||
--
|
||||
--
|
||||
-- DROP SEQUENCE "cpot_log_id_seq";
|
||||
-- DROP TABLE "cpot_user_account";
|
||||
-- DROP TABLE "cpot_user_settings";
|
||||
-- DROP TABLE "cpot_log";
|
||||
-- DROP TABLE "cpot_code_review";
|
||||
-- DROP TABLE "cpot_file";
|
||||
-- DROP TABLE "cpot_issue_change_file_list";
|
||||
-- DROP TABLE "cpot_issue_change";
|
||||
-- DROP TABLE "cpot_issue_file_list";
|
||||
-- DROP TABLE "cpot_issue";
|
||||
-- DROP TABLE "cpot_wiki_attachment";
|
||||
-- DROP TABLE "cpot_wiki";
|
||||
-- DROP TABLE "cpot_project_membership";
|
||||
-- DROP TABLE "cpot_project";
|
||||
-- DROP TABLE "cpot_site";
|
||||
-- ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE "cpot_site" (
|
||||
"id" VARCHAR(32) PRIMARY KEY,
|
||||
"name" VARCHAR(128) NOT NULL,
|
||||
"summary" VARCHAR(255) NOT NULL,
|
||||
"text" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_project" (
|
||||
"id" VARCHAR(32) PRIMARY KEY,
|
||||
"name" VARCHAR(255) UNIQUE NOT NULL,
|
||||
"summary" VARCHAR(255) NOT NULL,
|
||||
"description" CLOB NOT NULL,
|
||||
"webhooks" CLOB NOT NULL,
|
||||
"commitable" CHAR(1) DEFAULT 'Y' NOT NULL,
|
||||
"public" CHAR(1) DEFAULT 'Y' NOT NULL,
|
||||
"codecharset" VARCHAR(32),
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_project_membership" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"userid" VARCHAR(32) NOT NULL,
|
||||
"priority" INTEGER NOT NULL,
|
||||
UNIQUE ("projectid", "userid"),
|
||||
CONSTRAINT membership_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id") ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX cpot_projectid_index ON "cpot_project_membership"("projectid");
|
||||
CREATE INDEX cpot_userid_index ON "cpot_project_membership"("userid");
|
||||
|
||||
CREATE TABLE "cpot_wiki" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"text" CLOB NOT NULL,
|
||||
"doctype" CHAR(1) DEFAULT 'C' NOT NULL,
|
||||
"columns" INT DEFAULT 1 NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "name"),
|
||||
CONSTRAINT wiki_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id")
|
||||
);
|
||||
-- [ NOTE ] oracle defaults to ON DELETE RESTRICT if it is not specified.
|
||||
|
||||
CREATE TABLE "cpot_wiki_attachment" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"wikiname" VARCHAR(255) NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"encname" VARCHAR(255) NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "wikiname", "name"),
|
||||
CONSTRAINT wiki_attachment_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id"),
|
||||
CONSTRAINT wiki_attachment_wikiid FOREIGN KEY ("projectid","wikiname") REFERENCES "cpot_wiki"("projectid","name")
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_issue" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"id" NUMBER(20,0) NOT NULL,
|
||||
"summary" VARCHAR(255) NOT NULL,
|
||||
"description" CLOB NOT NULL,
|
||||
"type" VARCHAR(32) NOT NULL,
|
||||
"status" VARCHAR(32) NOT NULL,
|
||||
"owner" VARCHAR(255) NOT NULL,
|
||||
"priority" VARCHAR(32) NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
PRIMARY KEY ("projectid", "id"),
|
||||
CONSTRAINT issue_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id")
|
||||
);
|
||||
CREATE INDEX cpot_issue_index_1 ON "cpot_issue"("projectid", "status", "type", "summary");
|
||||
CREATE INDEX cpot_issue_index_2 ON "cpot_issue"("projectid", "summary");
|
||||
|
||||
CREATE TABLE "cpot_issue_file_list" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"issueid" NUMBER(20,0) NOT NULL,
|
||||
"filename" VARCHAR(255) NOT NULL,
|
||||
"encname" VARCHAR(255) NOT NULL,
|
||||
"md5sum" CHAR(32) NOT NULL,
|
||||
"description" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "issueid", "filename"),
|
||||
UNIQUE ("encname"),
|
||||
CONSTRAINT issue_file_list_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id"),
|
||||
CONSTRAINT issue_file_list_issueid FOREIGN KEY ("projectid","issueid") REFERENCES "cpot_issue"("projectid","id")
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_issue_change" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"id" NUMBER(20,0) NOT NULL,
|
||||
"sno" NUMBER(20,0) NOT NULL,
|
||||
"type" VARCHAR(32) NOT NULL,
|
||||
"status" VARCHAR(32) NOT NULL,
|
||||
"owner" VARCHAR(255) NOT NULL,
|
||||
"priority" VARCHAR(32) NOT NULL,
|
||||
"comment" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
PRIMARY KEY ("projectid", "id", "sno"),
|
||||
CONSTRAINT issue_update_id FOREIGN KEY ("projectid","id") REFERENCES "cpot_issue"("projectid","id")
|
||||
);
|
||||
|
||||
CREATE INDEX cpot_issue_change_index_1 ON "cpot_issue_change"("projectid", "id", "updatedon");
|
||||
|
||||
CREATE TABLE "cpot_issue_change_file_list" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"issueid" NUMBER(20,0) NOT NULL,
|
||||
"issuesno" NUMBER(20,0) NOT NULL,
|
||||
"filename" VARCHAR(255) NOT NULL,
|
||||
"encname" VARCHAR(255) NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "issueid", "filename"),
|
||||
CONSTRAINT issue_change_file_list_c1 FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id"),
|
||||
CONSTRAINT issue_change_file_list_c2 FOREIGN KEY ("projectid","issueid","issuesno") REFERENCES "cpot_issue_change"("projectid","id","sno")
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_issue_coderev" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"issueid" NUMBER(20,0) NOT NULL,
|
||||
"codeproid" VARCHAR(32) NOT NULL,
|
||||
"coderev" VARCHAR(64) NOT NULL,
|
||||
UNIQUE ("projectid", "issueid", "codeproid", "coderev"),
|
||||
CONSTRAINT issue_coderev_projectid FOREIGN KEY ("projectid") REFERENCES "project"("id"),
|
||||
CONSTRAINT issue_coderev_codeproid FOREIGN KEY ("codeproid") REFERENCES "project"("id")
|
||||
);
|
||||
|
||||
CREATE INDEX issue_coderev_index_1 ON "issue_coderev"("codeproid", "coderev");
|
||||
CREATE INDEX issue_coderev_index_2 ON "issue_coderev"("projectid", "issueid");
|
||||
|
||||
CREATE TABLE "cpot_file" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"tag" VARCHAR(54) NOT NULL,
|
||||
"description" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "name"),
|
||||
CONSTRAINT file_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id")
|
||||
);
|
||||
|
||||
CREATE INDEX cpot_file_index_1 ON "cpot_file"("projectid", "tag", "name");
|
||||
|
||||
CREATE TABLE "cpot_file_list" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"name" VARCHAR(255) NOT NULL,
|
||||
"filename" VARCHAR(255) NOT NULL,
|
||||
"encname" VARCHAR(255) NOT NULL,
|
||||
"md5sum" CHAR(32) NOT NULL,
|
||||
"description" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "filename"),
|
||||
UNIQUE ("encname"),
|
||||
CONSTRAINT file_list_projectid FOREIGN KEY ("projectid","name") REFERENCES "cpot_file"("projectid","name")
|
||||
);
|
||||
|
||||
CREATE INDEX cpot_file_list_index_1 ON "cpot_file_list"("projectid", "name");
|
||||
|
||||
CREATE TABLE "cpot_code_review" (
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"rev" NUMBER(20,0) NOT NULL,
|
||||
"sno" NUMBER(20,0) NOT NULL,
|
||||
"comment" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL,
|
||||
"createdby" VARCHAR(32) NOT NULL,
|
||||
"updatedon" TIMESTAMP NOT NULL,
|
||||
"updatedby" VARCHAR(32) NOT NULL,
|
||||
UNIQUE ("projectid", "rev", "sno"),
|
||||
CONSTRAINT code_review_projectid FOREIGN KEY ("projectid") REFERENCES "cpot_project"("id")
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_log" (
|
||||
"id" NUMBER(20,0) PRIMARY KEY,
|
||||
"projectid" VARCHAR(32) NOT NULL,
|
||||
"type" VARCHAR(16) NOT NULL,
|
||||
"action" VARCHAR(16) NOT NULL,
|
||||
"userid" VARCHAR(32) NOT NULL,
|
||||
"message" CLOB NOT NULL,
|
||||
"createdon" TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX codepopt_log_index_1 ON "cpot_log"("createdon", "projectid", "type", "action");
|
||||
|
||||
CREATE SEQUENCE "cpot_log_id_seq";
|
||||
CREATE OR REPLACE TRIGGER cpot_inc_log_id BEFORE INSERT ON "cpot_log" FOR EACH ROW WHEN (new."id" IS NULL)
|
||||
BEGIN
|
||||
SELECT "cpot_log_id_seq".NEXTVAL INTO :new."id" FROM dual;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE TABLE "cpot_user_settings" (
|
||||
"userid" VARCHAR(32) PRIMARY KEY,
|
||||
"code_hide_line_num" CHAR(1) NOT NULL,
|
||||
"code_hide_metadata" CHAR(1) NOT NULL,
|
||||
"icon_name" VARCHAR(255) UNIQUE NULL,
|
||||
"user_summary" VARCHAR(255) NULL
|
||||
);
|
||||
|
||||
CREATE TABLE "cpot_user_account" (
|
||||
"userid" VARCHAR(32) PRIMARY KEY,
|
||||
"passwd" VARCHAR(255) NOT NULL,
|
||||
"email" VARCHAR(255),
|
||||
"enabled" CHAR(1) DEFAULT 'N' NOT NULL CHECK("enabled" in ('Y', 'N'))
|
||||
);
|
||||
|
||||
CREATE OR REPLACE TRIGGER cpot_upon_project_id_update AFTER UPDATE OF "id" ON "cpot_project" FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE "cpot_project_membership" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_wiki" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_wiki_attachment" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_issue" SET "projectid" = :new."id" WHERE "projectid"= :old."id";
|
||||
UPDATE "cpot_issue_file_list" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_issue_change" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_issue_change_file_list" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_issue_coderev" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_issue_coderev" SET "codeproid" = :new."id" WHERE "codeproid" = :old."id";
|
||||
UPDATE "cpot_file" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
UPDATE "cpot_code_review" SET "projectid" = :new."id" WHERE "projectid" = :old."id";
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE TRIGGER cpot_upon_wiki_name_update AFTER UPDATE OF "name" ON "cpot_wiki" FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE "cpot_wiki_attachment" SET "wikiname" = :new."name" WHERE "projectid" = :old."projectid" AND "wikiname" = :old."name";
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE TRIGGER cpot_upon_issue_id_update AFTER UPDATE OF "id" ON "cpot_issue" FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE "cpot_issue_file_list" SET "issueid" = :new."id" WHERE "projectid" = :old."projectid" AND "issueid" = :old."id";
|
||||
UPDATE "cpot_issue_change" SET "id" = :new."id" WHERE "projectid" = :old."projectid" AND "id" = :old."id";
|
||||
UPDATE "cpot_issue_change_file_list" SET "issueid" = :new."id" WHERE "projectid" = :old."projectid" AND "issueid" = :old."id";
|
||||
UPDATE "cpot_issue_coderev" SET "issueid" = :new."id" WHERE WHERE "projectid" = :old."projectid" AND "issueid" = :old."id";
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE TRIGGER cpot_upon_issue_chsno_update AFTER UPDATE OF "id" ON "cpot_issue_change" FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE "cpot_issue_change_file_list" SET "issuesno" = :new."sno" WHERE "projectid" = :old."projectid" AND "issueid" = :old."id" AND "issuesno" = :old."sno";
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE TRIGGER cpot_upon_file_name_update AFTER UPDATE OF "name" ON "cpot_file" FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE "cpot_file_list" SET "name" = :new."name" WHERE "projectid" = :old."projectid" AND "name" = :old."name";
|
||||
END;
|
||||
/
|
297
etc/codepot.pgsql
Normal file
297
etc/codepot.pgsql
Normal file
@ -0,0 +1,297 @@
|
||||
-- ------------------------------------------------------------
|
||||
-- This file is the Codepot database schema file for PostreSQL.
|
||||
-- Note this file doesn't mandate which database to use.
|
||||
--
|
||||
-- Assumining "local all all password" in /var/lib/pgsql/data/pg_hba.conf
|
||||
--
|
||||
-- $ sudo -u postgres psql
|
||||
-- postgres=# CREATE USER codepot WITH PASSWORD 'codepot';
|
||||
-- postgres=# \du
|
||||
-- postgres=# CREATE DATABASE codepot;
|
||||
-- postgres=# \l
|
||||
-- postgres=# ALTER DATABASE "codepot" OWNER TO codepot;
|
||||
-- postgres=# \l
|
||||
-- postgres=# \q
|
||||
--
|
||||
-- $ psql -U codepot -W codepot
|
||||
-- postgres=# \i codepot.pgsql
|
||||
-- postgres=# \dt
|
||||
-- postgres=# \q
|
||||
-- ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE site (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE project (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
name VARCHAR(255) UNIQUE NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
webhooks TEXT NOT NULL,
|
||||
commitable CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
public CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
codecharset VARCHAR(32),
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE project_membership (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
userid VARCHAR(32) NOT NULL,
|
||||
priority INTEGER NOT NULL,
|
||||
UNIQUE (projectid, userid),
|
||||
CONSTRAINT membership_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
CREATE INDEX projectid_index ON project_membership(projectid);
|
||||
CREATE INDEX userid_index ON project_membership(userid);
|
||||
|
||||
CREATE TABLE wiki (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
doctype CHAR(1) NOT NULL DEFAULT 'C',
|
||||
columns INT NOT NULL DEFAULT 1,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, name),
|
||||
|
||||
CONSTRAINT wiki_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE wiki_attachment (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
wikiname VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, wikiname, name),
|
||||
|
||||
CONSTRAINT wiki_attachment_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT wiki_attachment_wikiid FOREIGN KEY (projectid,wikiname) REFERENCES wiki(projectid,name)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE issue (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
id BIGINT NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
type VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
owner VARCHAR(255) NOT NULL,
|
||||
priority VARCHAR(32) NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
PRIMARY KEY (projectid, id),
|
||||
|
||||
CONSTRAINT issue_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX issue_index_1 ON issue(projectid, status, type, summary);
|
||||
|
||||
CREATE INDEX issue_index_2 ON issue(projectid, summary);
|
||||
|
||||
CREATE TABLE issue_file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
md5sum CHAR(32) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, issueid, filename),
|
||||
UNIQUE (encname),
|
||||
|
||||
CONSTRAINT issue_file_list_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_file_list_issueid FOREIGN KEY (projectid,issueid) REFERENCES issue(projectid,id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE issue_change (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
id BIGINT NOT NULL,
|
||||
sno BIGINT NOT NULL,
|
||||
|
||||
type VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
owner VARCHAR(255) NOT NULL,
|
||||
priority VARCHAR(32) NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
PRIMARY KEY (projectid, id, sno),
|
||||
|
||||
CONSTRAINT issue_update_id FOREIGN KEY (projectid,id) REFERENCES issue(projectid,id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
);
|
||||
|
||||
CREATE INDEX issue_change_index_1 ON issue_change(projectid, id, updatedon);
|
||||
|
||||
CREATE TABLE issue_change_file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
issuesno BIGINT NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, issueid, filename),
|
||||
|
||||
CONSTRAINT issue_change_file_list_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_change_file_list_issueidsno FOREIGN KEY (projectid,issueid,issuesno) REFERENCES issue_change(projectid,id,sno)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE issue_coderev (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
|
||||
codeproid VARCHAR(32) NOT NULL,
|
||||
coderev VARCHAR(64) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, issueid, codeproid, coderev),
|
||||
|
||||
CONSTRAINT issue_coderev_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_coderev_codeproid FOREIGN KEY (codeproid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX issue_coderev_index_1 ON issue_coderev(codeproid, coderev);
|
||||
CREATE INDEX issue_coderev_index_2 ON issue_coderev(projectid, issueid);
|
||||
|
||||
|
||||
CREATE TABLE file (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
tag VARCHAR(54) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, name),
|
||||
|
||||
CONSTRAINT file_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX file_index_1 ON file(projectid, tag, name);
|
||||
|
||||
CREATE TABLE file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
md5sum CHAR(32) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, filename),
|
||||
UNIQUE (encname),
|
||||
|
||||
CONSTRAINT file_list_projectid FOREIGN KEY (projectid,name) REFERENCES file(projectid,name)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX file_list_index_1 ON file(projectid, name);
|
||||
|
||||
CREATE TABLE code_review (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
rev BIGINT NOT NULL,
|
||||
sno BIGINT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
|
||||
createdon TIMESTAMP NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
|
||||
updatedon TIMESTAMP NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
UNIQUE (projectid, rev, sno),
|
||||
|
||||
CONSTRAINT code_review_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE log (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
type VARCHAR(16) NOT NULL,
|
||||
action VARCHAR(16) NOT NULL,
|
||||
userid VARCHAR(32) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
createdon TIMESTAMP NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX log_index_1 ON log(createdon, projectid, type, action);
|
||||
|
||||
CREATE TABLE user_settings (
|
||||
userid VARCHAR(32) PRIMARY KEY,
|
||||
code_hide_line_num CHAR(1) NOT NULL,
|
||||
code_hide_metadata CHAR(1) NOT NULL,
|
||||
icon_name VARCHAR(255) UNIQUE NULL,
|
||||
user_summary VARCHAR(255) NULL
|
||||
);
|
||||
|
||||
CREATE TABLE user_account (
|
||||
userid VARCHAR(32) PRIMARY KEY,
|
||||
passwd VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255),
|
||||
enabled CHAR(1) NOT NULL DEFAULT 'N' CHECK(enabled in ('Y', 'N'))
|
||||
);
|
276
etc/codepot.sqlite
Normal file
276
etc/codepot.sqlite
Normal file
@ -0,0 +1,276 @@
|
||||
-- ---------------------------------------------------------
|
||||
-- This file is the Codepot database schema file for SQLITE.
|
||||
-- ---------------------------------------------------------
|
||||
PRAGMA journal_mode=WAL;
|
||||
PRAGMA foreign_keys=ON;
|
||||
|
||||
CREATE TABLE site (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
name VARCHAR(128) NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE project (
|
||||
id VARCHAR(32) PRIMARY KEY,
|
||||
name VARCHAR(255) UNIQUE NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
webhooks TEXT NOT NULL,
|
||||
commitable CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
public CHAR(1) NOT NULL DEFAULT 'Y',
|
||||
codecharset VARCHAR(32),
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL
|
||||
|
||||
);
|
||||
|
||||
CREATE TABLE project_membership (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
userid VARCHAR(32) NOT NULL,
|
||||
priority INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT membership_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX project_membership_index_1 on project_membership(projectid, userid);
|
||||
CREATE INDEX project_membership_index_2 on project_membership(userid);
|
||||
CREATE INDEX project_membership_index_3 on project_membership(projectid);
|
||||
|
||||
CREATE TABLE wiki (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
text TEXT NOT NULL,
|
||||
doctype CHAR(1) NOT NULL DEFAULT 'C',
|
||||
columns INT NOT NULL DEFAULT 1,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
CONSTRAINT wiki_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX wiki_index on wiki(projectid, name);
|
||||
|
||||
CREATE TABLE wiki_attachment (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
wikiname VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
|
||||
CONSTRAINT wiki_attachment_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT wiki_attachment_wikiid FOREIGN KEY (projectid,wikiname) REFERENCES wiki(projectid,name)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX wiki_attachment_index_1 on wiki_attachment(projectid, wikiname, name);
|
||||
|
||||
CREATE TABLE issue (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
id BIGINT NOT NULL,
|
||||
summary VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
type VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
owner VARCHAR(255) NOT NULL,
|
||||
priority VARCHAR(32) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
PRIMARY KEY (projectid, id),
|
||||
|
||||
CONSTRAINT issue_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE INDEX issue_index_1 ON issue(projectid, status, type, summary);
|
||||
CREATE INDEX issue_index_2 ON issue(projectid, summary);
|
||||
|
||||
CREATE TABLE issue_file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
md5sum CHAR(32) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
CONSTRAINT issue_file_list_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_file_list_issueid FOREIGN KEY (projectid,issueid) REFERENCES issue(projectid,id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX issue_file_list_index_1 on issue_file_list(projectid, issueid, filename);
|
||||
CREATE UNIQUE INDEX issue_file_list_index_2 on issue_file_list(encname);
|
||||
|
||||
CREATE TABLE issue_change (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
id BIGINT NOT NULL,
|
||||
sno BIGINT NOT NULL,
|
||||
|
||||
type VARCHAR(32) NOT NULL,
|
||||
status VARCHAR(32) NOT NULL,
|
||||
owner VARCHAR(255) NOT NULL,
|
||||
priority VARCHAR(32) NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
PRIMARY KEY (projectid, id, sno),
|
||||
|
||||
CONSTRAINT issue_change_id FOREIGN KEY (projectid,id) REFERENCES issue(projectid,id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
);
|
||||
CREATE INDEX issue_change_index_1 ON issue_change(projectid, id, updatedon);
|
||||
|
||||
CREATE TABLE issue_change_file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
issuesno BIGINT NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
CONSTRAINT issue_change_file_list_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_change_file_list_issueidsno FOREIGN KEY (projectid,issueid,issuesno) REFERENCES issue_change(projectid,id,sno)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX issue_change_file_list_index_1 on issue_change_file_list(projectid, issueid, filename);
|
||||
|
||||
CREATE TABLE issue_coderev (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
issueid BIGINT NOT NULL,
|
||||
|
||||
codeproid VARCHAR(32) NOT NULL,
|
||||
coderev VARCHAR(64) NOT NULL, -- git commit id is 40 characters. subversion revision is a number.
|
||||
|
||||
CONSTRAINT issue_coderev_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT issue_coderev_codeproid FOREIGN KEY (codeproid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
-- Commit message is typically a free text. Its issue reference could be error-prone.
|
||||
-- So i won't have this constraint enforced.
|
||||
-- CONSTRAINT issue_coderev_issueid FOREIGN KEY (projectid,issueid) REFERENCES issue(projectid,id)
|
||||
-- ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
|
||||
);
|
||||
CREATE UNIQUE INDEX issue_coderev_index_1 ON issue_coderev(projectid, issueid, codeproid, coderev);
|
||||
CREATE INDEX issue_coderev_index_2 ON issue_coderev(codeproid, coderev);
|
||||
CREATE INDEX issue_coderev_index_3 ON issue_coderev(projectid, issueid);
|
||||
|
||||
CREATE TABLE file (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
tag VARCHAR(54) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
CONSTRAINT file_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX file_index_1 ON file(projectid, name);
|
||||
CREATE INDEX file_index_2 ON file(projectid, tag, name);
|
||||
|
||||
CREATE TABLE file_list (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
filename VARCHAR(255) NOT NULL,
|
||||
encname VARCHAR(255) NOT NULL,
|
||||
md5sum CHAR(32) NOT NULL,
|
||||
description VARCHAR(255) NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
updatedon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
CONSTRAINT file_list_projectid FOREIGN KEY (projectid,name) REFERENCES file(projectid,name)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE INDEX file_list_index_1 ON file_list(projectid, name);
|
||||
CREATE UNIQUE INDEX file_list_index_2 ON file_list(projectid, filename);
|
||||
CREATE UNIQUE INDEX file_list_index_3 ON file_list(encname);
|
||||
|
||||
CREATE TABLE code_review (
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
rev BIGINT NOT NULL,
|
||||
sno BIGINT NOT NULL,
|
||||
comment TEXT NOT NULL,
|
||||
|
||||
createdon DATETIME NOT NULL,
|
||||
createdby VARCHAR(32) NOT NULL,
|
||||
|
||||
updatedon DATETIME NOT NULL,
|
||||
updatedby VARCHAR(32) NOT NULL,
|
||||
|
||||
|
||||
CONSTRAINT code_review_projectid FOREIGN KEY (projectid) REFERENCES project(id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
CREATE UNIQUE INDEX code_review_index_1 ON code_review(projectid, rev, sno);
|
||||
|
||||
CREATE TABLE log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
projectid VARCHAR(32) NOT NULL,
|
||||
type VARCHAR(16) NOT NULL,
|
||||
action VARCHAR(16) NOT NULL,
|
||||
userid VARCHAR(32) NOT NULL,
|
||||
message TEXT NOT NULL,
|
||||
createdon DATETIME NOT NULL
|
||||
);
|
||||
CREATE INDEX log_index_1 ON log(createdon, projectid, type, action);
|
||||
|
||||
CREATE TABLE user_settings (
|
||||
userid VARCHAR(32) PRIMARY KEY,
|
||||
code_hide_line_num CHAR(1) NOT NULL,
|
||||
code_hide_metadata CHAR(1) NOT NULL,
|
||||
icon_name VARCHAR(255) UNIQUE NULL,
|
||||
user_summary VARCHAR(255) NULL
|
||||
);
|
||||
|
||||
CREATE TABLE user_account (
|
||||
userid VARCHAR(32) PRIMARY KEY,
|
||||
passwd VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255),
|
||||
enabled CHAR(1) NOT NULL DEFAULT 'N' CHECK(enabled in ('Y', 'N'))
|
||||
);
|
||||
|
482
etc/perl/Codepot/AccessHandler.pm
Normal file
482
etc/perl/Codepot/AccessHandler.pm
Normal file
@ -0,0 +1,482 @@
|
||||
#
|
||||
# This file is not desinged to be used in conjuntion with other AAA providers.
|
||||
# This file requires to be used alone as shown below for apache httpd2.
|
||||
# You may change AuthName or SVNParentPath.
|
||||
#
|
||||
# <Location "/svn">
|
||||
# DAV svn
|
||||
# SVNParentPath "/var/lib/codepot/svnrepo"
|
||||
# PerlAccessHandler Codepot::AccessHandler
|
||||
# PerlAuthenHandler Codepot::AuthenHandler
|
||||
# PerlSetEnv CODEPOT_CONFIG_FILE /etc/codepot/codepot.ini
|
||||
# AuthType Basic
|
||||
# AuthName "codepot"
|
||||
# require valid-user
|
||||
# </Location>
|
||||
#
|
||||
# If you do not move the handler files to the default library directory,
|
||||
# a switch to indicate the location of the files are needed when loading
|
||||
# the mod_perl module. Somewhere in your httpd configuration, specify
|
||||
# the -Mlib switch.
|
||||
#
|
||||
# LoadModule perl_module modules/mod_perl.so
|
||||
# PerlSwitches -Mlib=/etc/codepot/perl
|
||||
#
|
||||
|
||||
package Codepot::AccessHandler;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Apache2::Access ();
|
||||
use Apache2::RequestUtil ();
|
||||
use Apache2::RequestRec ();
|
||||
use Apache2::Log;
|
||||
use APR::Table;
|
||||
use APR::Base64;
|
||||
|
||||
use Config::Simple;
|
||||
use Net::LDAP;
|
||||
use URI;
|
||||
use DBI;
|
||||
use Digest::SHA;
|
||||
|
||||
use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_UNAUTHORIZED HTTP_INTERNAL_SERVER_ERROR PROXYREQ_PROXY AUTH_REQUIRED);
|
||||
|
||||
sub get_config
|
||||
{
|
||||
my $cfg = new Config::Simple();
|
||||
|
||||
if (!$cfg->read($ENV{'CODEPOT_CONFIG_FILE'}))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $config = {
|
||||
login_model => $cfg->param('login_model'),
|
||||
|
||||
ldap_server_uri => $cfg->param('ldap_server_uri'),
|
||||
ldap_server_protocol_version => $cfg->param('ldap_server_protocol_version'),
|
||||
ldap_auth_mode => $cfg->param('ldap_auth_mode'),
|
||||
ldap_userid_format => $cfg->param('ldap_userid_format'),
|
||||
ldap_password_format => $cfg->param('ldap_password_format'),
|
||||
ldap_admin_binddn => $cfg->param('ldap_admin_binddn'),
|
||||
ldap_admin_password => $cfg->param('ldap_admin_password'),
|
||||
ldap_userid_search_base => $cfg->param('ldap_userid_search_base'),
|
||||
ldap_userid_search_filter => $cfg->param('ldap_userid_search_filter'),
|
||||
ldap_insider_attribute_names => $cfg->param('ldap_insider_attribute_names'),
|
||||
ldap_insider_attribute_value => $cfg->param('ldap_insider_attribute_value'),
|
||||
|
||||
database_hostname => $cfg->param('database_hostname'),
|
||||
database_port => $cfg->param("database_port"),
|
||||
database_username => $cfg->param('database_username'),
|
||||
database_password => $cfg->param('database_password'),
|
||||
database_name => $cfg->param('database_name'),
|
||||
database_driver => $cfg->param('database_driver'),
|
||||
database_prefix => $cfg->param('database_prefix'),
|
||||
|
||||
svn_read_access => $cfg->param('svn_read_access'),
|
||||
svn_read_credential => $cfg->param('svn_read_credential')
|
||||
};
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
|
||||
sub format_string
|
||||
{
|
||||
my ($fmt, $userid, $password) = @_;
|
||||
|
||||
my $out = $fmt;
|
||||
$out =~ s/\$\{userid\}/$userid/g;
|
||||
$out =~ s/\$\{password\}/$password/g;
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub authenticate_ldap
|
||||
{
|
||||
my ($r, $cfg, $userid, $password) = @_;
|
||||
my $binddn;
|
||||
my $passwd;
|
||||
|
||||
my $uri = URI->new($cfg->{ldap_server_uri});
|
||||
my $ldap = Net::LDAP->new(
|
||||
$uri->host,
|
||||
scheme => $uri->scheme,
|
||||
port => $uri->port,
|
||||
version => $cfg->{ldap_server_protocol_version}
|
||||
);
|
||||
if (!defined($ldap))
|
||||
{
|
||||
$r->log_error ('Cannot create LDAP');
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($cfg->{ldap_auth_mode} == 2)
|
||||
{
|
||||
my $f_rootdn = format_string($cfg->{ldap_admin_binddn}, $userid, $password);
|
||||
my $f_rootpw = format_string($cfg->{ldap_admin_password}, $userid, $password);
|
||||
my $f_basedn = format_string($cfg->{ldap_userid_search_base}, $userid, $password);
|
||||
my $f_filter = format_string($cfg->{ldap_userid_search_filter}, $userid, $password);
|
||||
|
||||
my $res = $ldap->bind($f_rootdn, password => $f_rootpw);
|
||||
if ($res->code != Net::LDAP::LDAP_SUCCESS)
|
||||
{
|
||||
$r->log_error ("Cannot bind LDAP as $f_rootdn - " . $res->error());
|
||||
$ldap->unbind();
|
||||
return -1;
|
||||
}
|
||||
|
||||
$res = $ldap->search(base => $f_basedn, scope => 'sub', filter => $f_filter);
|
||||
if ($res->code != Net::LDAP::LDAP_SUCCESS)
|
||||
{
|
||||
$ldap->unbind();
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $entry = $res->entry(0); # get the first entry only
|
||||
if (!defined($entry))
|
||||
{
|
||||
$ldap->unbind();
|
||||
return 0;
|
||||
}
|
||||
|
||||
$binddn = $entry->dn ();
|
||||
}
|
||||
else
|
||||
{
|
||||
$binddn = format_string ($cfg->{ldap_userid_format}, $userid, $password);
|
||||
}
|
||||
|
||||
$passwd = format_string ($cfg->{ldap_password_format}, $userid, $password);
|
||||
my $res = $ldap->bind ($binddn, password => $passwd);
|
||||
if ($res->code != Net::LDAP::LDAP_SUCCESS)
|
||||
{
|
||||
#$r->log_error ("Cannot bind LDAP as $binddn - " . $res->error());
|
||||
$ldap->unbind();
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $authenticated = 1;
|
||||
if ($cfg->{ldap_insider_attribute_names} ne '' && $cfg->{ldap_insider_attribute_value} ne '')
|
||||
{
|
||||
my $attr_str = $cfg->{ldap_insider_attribute_names};
|
||||
$attr_str =~ s/^\s+|\s+$//g;
|
||||
my @attrs = split(/\s+/, $attr_str);
|
||||
|
||||
if (scalar(@attrs) > 0)
|
||||
{
|
||||
#my $f_filter = '(' . $cfg->{ldap_insider_attribute_name} . '=*)';
|
||||
my $f_filter = '(objectClass=*)';
|
||||
|
||||
$res = $ldap->search(base => $binddn, scope => 'base', filter => $f_filter, @attrs);
|
||||
if ($res->code == Net::LDAP::LDAP_SUCCESS)
|
||||
{
|
||||
search_loop:
|
||||
foreach my $entry ($res->entries)
|
||||
{
|
||||
foreach my $a (@attrs)
|
||||
{
|
||||
my @va = $entry->get_value($a);
|
||||
foreach my $v (@va)
|
||||
{
|
||||
if (lc($v) eq lc($cfg->{ldap_insider_attribute_value}))
|
||||
{
|
||||
$authenticated = 2;
|
||||
last search_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$res->abandon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ldap->unbind();
|
||||
return $authenticated;
|
||||
}
|
||||
|
||||
sub authenticate_database
|
||||
{
|
||||
my ($dbh, $prefix, $userid, $password, $qc) = @_;
|
||||
|
||||
my $query = $dbh->prepare("SELECT ${qc}userid${qc},${qc}passwd${qc} FROM ${qc}${prefix}user_account${qc} WHERE ${qc}userid${qc}=? and ${qc}enabled${qc}='Y'");
|
||||
if (!$query || !$query->execute ($userid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
|
||||
if (scalar(@row) <= 0) { return (0, undef); }
|
||||
|
||||
my $db_pw = $row[1];
|
||||
if (length($db_pw) < 10) { return (0, undef); }
|
||||
|
||||
my $hexsalt = substr($db_pw, -10);
|
||||
my $binsalt = pack('H*', $hexsalt);
|
||||
|
||||
my $fmt_pw = '{ssha1}' . Digest::SHA::sha1_hex($password . $binsalt) . $hexsalt;
|
||||
return (($fmt_pw eq $db_pw? 1: 0), undef);
|
||||
}
|
||||
|
||||
sub open_database
|
||||
{
|
||||
my ($cfg) = @_;
|
||||
|
||||
my $dbtype = $cfg->{database_driver};
|
||||
my $dbname = $cfg->{database_name};
|
||||
my $dbhost = $cfg->{database_hostname};
|
||||
my $dbport = $cfg->{database_port};
|
||||
|
||||
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
||||
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
||||
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
||||
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
|
||||
|
||||
my $dbstr;
|
||||
my $dbuser;
|
||||
my $dbpass;
|
||||
if ($dbtype eq 'Oracle')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:";
|
||||
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
||||
$dbpass = '';
|
||||
}
|
||||
elsif ($dbtype eq 'SQLite')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbhost;";
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbname;";
|
||||
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
||||
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
||||
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
$dbstr, $dbuser, $dbpass,
|
||||
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
||||
);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub close_database
|
||||
{
|
||||
my ($dbh) = @_;
|
||||
$dbh->disconnect ();
|
||||
}
|
||||
|
||||
sub is_project_member
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $userid, $qc) = @_;
|
||||
|
||||
my $query = $dbh->prepare("SELECT ${qc}projectid${qc} FROM ${qc}${prefix}project_membership${qc} WHERE ${qc}userid${qc}=? AND ${qc}projectid${qc}=?");
|
||||
if (!$query || !$query->execute ($userid, $projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0)? 1: 0), undef);
|
||||
}
|
||||
|
||||
sub is_project_public
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $qc) = @_;
|
||||
|
||||
my $query = $dbh->prepare("SELECT ${qc}public${qc} FROM ${qc}${prefix}project${qc} WHERE ${qc}id${qc}=?");
|
||||
if (!$query || !$query->execute ($projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0 && $row[0] eq 'Y')? 1: 0), undef);
|
||||
}
|
||||
|
||||
sub is_read_method
|
||||
{
|
||||
my ($method) = @_;
|
||||
|
||||
return $method eq "GET" || $method eq "HEAD" ||
|
||||
$method eq "OPTIONS" || $method eq "REPORT" ||
|
||||
$method eq "PROPFIND";
|
||||
}
|
||||
|
||||
sub __handler
|
||||
{
|
||||
my ($r, $cfg, $dbh) = @_;
|
||||
my $method = uc($r->method());
|
||||
my $is_method_r = is_read_method($method);
|
||||
|
||||
#my ($empty, $base, $repo, $dummy) = split('/', $r->uri(), 4);
|
||||
my @urisegs = split('/', $r->uri());
|
||||
my $repo = $urisegs[2];
|
||||
|
||||
my $author;
|
||||
my $userid = undef;
|
||||
my $password = undef;
|
||||
|
||||
my $public = undef;
|
||||
my $member = undef;
|
||||
my $errmsg = undef;
|
||||
|
||||
my $qc = '';
|
||||
if ($cfg->{database_driver} eq 'oci8') { $qc = '"'; }
|
||||
|
||||
if ($r->proxyreq() == Apache2::Const::PROXYREQ_PROXY)
|
||||
{
|
||||
$author = $r->headers_in->{'Proxy-Authorization'};
|
||||
}
|
||||
else
|
||||
{
|
||||
$author = $r->headers_in->{'Authorization'};
|
||||
}
|
||||
|
||||
if (defined($author))
|
||||
{
|
||||
my ($rc, $pass) = $r->get_basic_auth_pw();
|
||||
if ($rc != Apache2::Const::OK) { return $rc; }
|
||||
|
||||
#$author = APR::Base64::decode((split(/ /,$author))[1]);
|
||||
#($userid,$password) = split(/:/, $author);
|
||||
|
||||
$userid = $r->user();
|
||||
$password = $pass;
|
||||
}
|
||||
|
||||
if (!defined($userid)) { $userid = ""; }
|
||||
if (!defined($password)) { $password = ""; }
|
||||
|
||||
if ($is_method_r)
|
||||
{
|
||||
($public, $errmsg) = is_project_public($dbh, $cfg->{database_prefix}, $repo, $qc);
|
||||
if ($public <= -1)
|
||||
{
|
||||
# failed to contact the authentication server
|
||||
$r->log_error ("Cannot check if a project is public - $errmsg");
|
||||
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
elsif ($public >= 1)
|
||||
{
|
||||
if (lc($cfg->{svn_read_access}) eq 'anonymous')
|
||||
{
|
||||
# grant an anonymous user the read access.
|
||||
if (!defined($userid) || $userid eq '')
|
||||
{
|
||||
# httpd 2.4 emits the following message if the user is not set
|
||||
# AH00027: No authentication done but request not allowed
|
||||
# without authentication for /xxx/xxx. Authentication not configured?
|
||||
$r->user('<codepot-anonymous-user>');
|
||||
}
|
||||
return Apache2::Const::OK;
|
||||
}
|
||||
elsif (defined($cfg->{svn_read_credential}) && $cfg->{svn_read_credential} ne '')
|
||||
{
|
||||
# security loop hole here.
|
||||
my ($c_user, $c_pass) = split(/:/, $cfg->{svn_read_credential});
|
||||
if ($c_user ne '' && $c_pass ne '' && $c_user eq $userid && $c_pass eq $password)
|
||||
{
|
||||
return Apache2::Const::OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $auth = -3;
|
||||
if ($cfg->{login_model} eq 'LdapLoginModel')
|
||||
{
|
||||
$auth = authenticate_ldap($r, $cfg, $userid, $password);
|
||||
}
|
||||
elsif ($cfg->{login_model} eq 'DbLoginModel')
|
||||
{
|
||||
($auth, $errmsg) = authenticate_database($dbh, $cfg->{database_prefix}, $userid, $password, $qc);
|
||||
if ($auth <= -1)
|
||||
{
|
||||
$r->log_error ("Database error - $errmsg");
|
||||
}
|
||||
}
|
||||
if ($auth <= -1)
|
||||
{
|
||||
# failed to contact the authentication server
|
||||
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
elsif ($auth == 0)
|
||||
{
|
||||
# authentication denied
|
||||
$r->note_basic_auth_failure ();
|
||||
return Apache2::Const::HTTP_UNAUTHORIZED;
|
||||
}
|
||||
|
||||
# authentication successful.
|
||||
if ($is_method_r && $public >= 1)
|
||||
{
|
||||
if (lc($cfg->{svn_read_access}) eq 'authenticated')
|
||||
{
|
||||
# grant read access to an authenticated user regardless of membership
|
||||
# this applies to a public project only
|
||||
return Apache2::Const::OK;
|
||||
}
|
||||
elsif (lc($cfg->{svn_read_access}) eq 'authenticated-insider')
|
||||
{
|
||||
if ($auth >= 2) { return Apache2::Const::OK; }
|
||||
}
|
||||
}
|
||||
|
||||
($member, $errmsg) = is_project_member($dbh, $cfg->{database_prefix}, $repo, $userid, $qc);
|
||||
if ($member <= -1)
|
||||
{
|
||||
$r->log_error ("Cannot check project membership - $errmsg");
|
||||
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
elsif ($member == 0)
|
||||
{
|
||||
# access denined
|
||||
return Apache2::Const::FORBIDDEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
# the user is a member of project. access granted.
|
||||
return Apache2::Const::OK;
|
||||
}
|
||||
}
|
||||
|
||||
sub handler: method
|
||||
{
|
||||
my ($class, $r) = @_;
|
||||
my $res;
|
||||
my $cfg;
|
||||
|
||||
$cfg = get_config();
|
||||
if (!defined($cfg))
|
||||
{
|
||||
$r->log_error ('Cannot load configuration');
|
||||
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
my $dbh = open_database($cfg);
|
||||
if (!defined($dbh))
|
||||
{
|
||||
$r->log_error ('Cannot open database - ' . $DBI::errstr);
|
||||
return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
$res = __handler($r, $cfg, $dbh);
|
||||
|
||||
close_database ($dbh);
|
||||
return $res;
|
||||
}
|
||||
|
||||
1;
|
19
etc/perl/Codepot/AuthenHandler.pm
Normal file
19
etc/perl/Codepot/AuthenHandler.pm
Normal file
@ -0,0 +1,19 @@
|
||||
package Codepot::AuthenHandler;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Apache2::Access ();
|
||||
use Apache2::RequestUtil ();
|
||||
use Apache2::RequestRec ();
|
||||
use Apache2::Log;
|
||||
|
||||
use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_UNAUTHORIZED HTTP_INTERNAL_SERVER_ERROR AUTH_REQUIRED);
|
||||
|
||||
use Data::Dumper;
|
||||
sub handler: method
|
||||
{
|
||||
my ($class, $r) = @_;
|
||||
return Apache2::Const::OK;
|
||||
}
|
||||
1;
|
565
etc/post-commit.in
Normal file
565
etc/post-commit.in
Normal file
@ -0,0 +1,565 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
use Config::Simple;
|
||||
use DBI;
|
||||
use File::Basename;
|
||||
use POSIX;
|
||||
|
||||
use SVN::Core;
|
||||
use SVN::Repos;
|
||||
use SVN::Fs;
|
||||
|
||||
use Net::LDAP;
|
||||
use Net::LDAP qw(LDAP_SUCCESS);
|
||||
use URI;
|
||||
use Mail::Sendmail;
|
||||
use LWP::UserAgent;
|
||||
|
||||
my $CFG_FILE = '@CFGDIR@/codepot.ini';
|
||||
my $REPOFS = $ARGV[0];
|
||||
my $REPOBASE = basename($REPOFS);
|
||||
my $REV = $ARGV[1];
|
||||
|
||||
my $QC = '';
|
||||
|
||||
sub get_config
|
||||
{
|
||||
my $cfg = new Config::Simple();
|
||||
|
||||
if (!$cfg->read($CFG_FILE))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $config = {
|
||||
login_model => $cfg->param('login_model'),
|
||||
|
||||
ldap_server_uri => $cfg->param('ldap_server_uri'),
|
||||
ldap_server_protocol_version => $cfg->param('ldap_server_protocol_version'),
|
||||
ldap_auth_mode => $cfg->param('ldap_auth_mode'),
|
||||
ldap_userid_format => $cfg->param('ldap_userid_format'),
|
||||
ldap_password_format => $cfg->param('ldap_password_format'),
|
||||
ldap_admin_binddn => $cfg->param('ldap_admin_binddn'),
|
||||
ldap_admin_password => $cfg->param('ldap_admin_password'),
|
||||
ldap_userid_search_base => $cfg->param('ldap_userid_search_base'),
|
||||
ldap_userid_search_filter => $cfg->param('ldap_userid_search_filter'),
|
||||
ldap_mail_attribute_name => $cfg->param('ldap_mail_attribute_name'),
|
||||
|
||||
database_hostname => $cfg->param("database_hostname"),
|
||||
database_port => $cfg->param("database_port"),
|
||||
database_username => $cfg->param("database_username"),
|
||||
database_password => $cfg->param("database_password"),
|
||||
database_name => $cfg->param("database_name"),
|
||||
database_driver => $cfg->param("database_driver"),
|
||||
database_prefix => $cfg->param("database_prefix"),
|
||||
database_store_gmt => $cfg->param("database_store_gmt"),
|
||||
|
||||
email_sender => $cfg->param("email_sender"),
|
||||
commit_notification => $cfg->param("commit_notification"),
|
||||
commit_notification_url => $cfg->param("commit_notification_url")
|
||||
};
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub open_database
|
||||
{
|
||||
my ($cfg) = @_;
|
||||
|
||||
my $dbtype = $cfg->{database_driver};
|
||||
my $dbname = $cfg->{database_name};
|
||||
my $dbhost = $cfg->{database_hostname};
|
||||
my $dbport = $cfg->{database_port};
|
||||
|
||||
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
||||
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
||||
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
||||
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
|
||||
|
||||
my $dbstr;
|
||||
my $dbuser;
|
||||
my $dbpass;
|
||||
if ($dbtype eq 'Oracle')
|
||||
{
|
||||
$QC = '"';
|
||||
$dbstr = "DBI:$dbtype:";
|
||||
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
||||
$dbpass = '';
|
||||
}
|
||||
elsif ($dbtype eq 'SQLite')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbhost;";
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbname;";
|
||||
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
||||
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
||||
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
$dbstr, $dbuser, $dbpass,
|
||||
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
||||
);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub close_database
|
||||
{
|
||||
my ($dbh) = @_;
|
||||
$dbh->disconnect ();
|
||||
}
|
||||
|
||||
sub find_issue_reference_in_commit_message
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $revision, $commit_message) = @_;
|
||||
|
||||
# find [[#IXXXX]]
|
||||
my @issue_ids = ($commit_message =~ /\[\[#I(\d+)\]\]/g);
|
||||
# find #XXXX
|
||||
my @issue_ids2 = ($commit_message =~ /(^|[^#])#(\d+)(\D|$)/g);
|
||||
|
||||
# find unique issue ids in the findings.
|
||||
my %tmp;
|
||||
@tmp{@issue_ids} = 1;
|
||||
for (my $i = 0; $i < scalar(@issue_ids2); $i += 3)
|
||||
{
|
||||
my $id = @issue_ids2[$i + 1];
|
||||
@tmp{$id} = 1;
|
||||
}
|
||||
my @unique_issue_ids = keys(%tmp);
|
||||
|
||||
$dbh->begin_work ();
|
||||
|
||||
my $query = $dbh->prepare("DELETE FROM ${QC}${prefix}issue_coderev${QC} WHERE ${QC}codeproid${QC}=? AND ${QC}coderev${QC}=?");
|
||||
if (!$query || !$query->execute($projectid, $revision))
|
||||
{
|
||||
my $errstr = $dbh->errstr();
|
||||
if ($query) { $query->finish (); }
|
||||
$dbh->rollback ();
|
||||
return (-1, $errstr);
|
||||
}
|
||||
$query->finish ();
|
||||
|
||||
for my $issue_id(@unique_issue_ids)
|
||||
{
|
||||
my $query = $dbh->prepare("INSERT INTO ${QC}${prefix}issue_coderev${QC} (${QC}projectid${QC},${QC}issueid${QC},${QC}codeproid${QC},${QC}coderev${QC}) VALUES (?,?,?,?)");
|
||||
if ($query)
|
||||
{
|
||||
# ignore errors
|
||||
$query->execute ($projectid, $issue_id, $projectid, $revision);
|
||||
$query->finish ();
|
||||
}
|
||||
}
|
||||
|
||||
$dbh->commit ();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
sub write_commit_log
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $revision, $userid, $store_gmt) = @_;
|
||||
|
||||
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
|
||||
#| id | type | projectid | message | createdon | action | userid |
|
||||
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
|
||||
#| 895 | code | codepot | svn,codepot,72 | 2011-10-10 14:26:43 | commit | hyunghwan.chung |
|
||||
|
||||
my $message = "svn,$projectid,$revision";
|
||||
my $timestamp;
|
||||
|
||||
if (($store_gmt =~ /^\d+?$/ && int($store_gmt) != 0) || (lc($store_gmt) eq 'yes'))
|
||||
{
|
||||
$timestamp = POSIX::strftime('%Y-%m-%d %H:%M:%S', gmtime());
|
||||
}
|
||||
else
|
||||
{
|
||||
$timestamp = POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime());
|
||||
}
|
||||
|
||||
# the PHP side is executing ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS.FF.
|
||||
# do i have to do it here or use the database time (CURRENT_TIMESTAMP) instead?
|
||||
# make sure that you have the same time between the app server and the data server.
|
||||
# to minize side-effect of using the time of data server.
|
||||
#my $createdon = POSIX::strftime ('%Y-%m-%d %H:%M:%S', localtime());
|
||||
|
||||
$dbh->begin_work ();
|
||||
|
||||
#my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}log${QC} (${QC}type${QC},${QC}projectid${QC},${QC}message${QC},${QC}createdon${QC},${QC}action${QC},${QC}userid${QC}) VALUES (?,?,?,?,?,?)");
|
||||
#if (!$query || !$query->execute('code', $projectid, $message, $createdon, 'commit', $userid))
|
||||
|
||||
my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}log${QC} (${QC}type${QC},${QC}projectid${QC},${QC}message${QC},${QC}createdon${QC},${QC}action${QC},${QC}userid${QC}) VALUES (?,?,?,?,?,?)");
|
||||
if (!$query || !$query->execute('code', $projectid, $message, $timestamp, 'commit', $userid))
|
||||
{
|
||||
my $errstr = $dbh->errstr();
|
||||
if ($query) { $query->finish (); }
|
||||
$dbh->rollback ();
|
||||
return (-1, $errstr);
|
||||
}
|
||||
|
||||
$query->finish ();
|
||||
$dbh->commit ();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
sub get_author
|
||||
{
|
||||
my $pool = SVN::Pool->new(undef);
|
||||
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
||||
if (!defined($svn))
|
||||
{
|
||||
print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $fs = $svn->fs();
|
||||
if (!defined($fs))
|
||||
{
|
||||
print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $author = $fs->revision_prop ($REV, 'svn:author');
|
||||
return $author;
|
||||
}
|
||||
|
||||
sub get_commit_message
|
||||
{
|
||||
my $pool = SVN::Pool->new(undef);
|
||||
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
||||
if (!defined($svn))
|
||||
{
|
||||
print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $fs = $svn->fs();
|
||||
if (!defined($fs))
|
||||
{
|
||||
print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $logmsg = $fs->revision_prop($REV, 'svn:log');
|
||||
return $logmsg;
|
||||
}
|
||||
|
||||
|
||||
sub format_string
|
||||
{
|
||||
my ($fmt, $userid, $password) = @_;
|
||||
|
||||
my $out = $fmt;
|
||||
$out =~ s/\$\{userid\}/$userid/g;
|
||||
$out =~ s/\$\{password\}/$password/g;
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub get_author_email_ldap
|
||||
{
|
||||
my ($cfg, $userid) = @_;
|
||||
|
||||
my $uri = URI->new ($cfg->{ldap_server_uri});
|
||||
my $ldap = Net::LDAP->new (
|
||||
$uri->host,
|
||||
scheme => $uri->scheme,
|
||||
port => $uri->port,
|
||||
version => $cfg->{ldap_server_protocol_version}
|
||||
);
|
||||
if (!defined($ldap))
|
||||
{
|
||||
print (STDERR 'Cannot create LDAP');
|
||||
return (-1, undef);
|
||||
}
|
||||
|
||||
my $f_rootdn = format_string($cfg->{ldap_admin_binddn}, $userid, '');
|
||||
my $f_rootpw = format_string($cfg->{ldap_admin_password}, $userid, '');
|
||||
|
||||
my $res = $ldap->bind($f_rootdn, password => $f_rootpw);
|
||||
if ($res->code != LDAP_SUCCESS)
|
||||
{
|
||||
print (STDERR "Cannot bind LDAP as $f_rootdn - " . $res->error());
|
||||
$ldap->unbind();
|
||||
return (-1, undef);
|
||||
}
|
||||
|
||||
|
||||
my $f_basedn = '';
|
||||
my $f_filter = '';
|
||||
|
||||
if ($cfg->{ldap_auth_mode} == 2)
|
||||
{
|
||||
$f_basedn = format_string($cfg->{ldap_userid_search_base}, $userid, '');
|
||||
$f_filter = format_string($cfg->{ldap_userid_search_filter}, $userid, '');
|
||||
|
||||
$res = $ldap->search(base => $f_basedn, scope => 'sub', filter => $f_filter);
|
||||
if ($res->code != LDAP_SUCCESS)
|
||||
{
|
||||
$ldap->unbind();
|
||||
return (-1, undef);
|
||||
}
|
||||
|
||||
my $entry = $res->entry(0); # get the first entry only
|
||||
if (!defined($entry))
|
||||
{
|
||||
$ldap->unbind();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
$f_basedn = $entry->dn();
|
||||
}
|
||||
else
|
||||
{
|
||||
$f_basedn = format_string($cfg->{ldap_userid_format}, $userid, '');
|
||||
}
|
||||
|
||||
$f_filter = '(' . $cfg->{ldap_mail_attribute_name} . '=*)';
|
||||
|
||||
$res = $ldap->search(base => $f_basedn, scope => 'sub', filter => $f_filter);
|
||||
if ($res->code != LDAP_SUCCESS)
|
||||
{
|
||||
$ldap->unbind();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
my $entry = $res->entry(0); # get the first entry only
|
||||
if (!defined($entry))
|
||||
{
|
||||
$ldap->unbind();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
my $xret = 0;
|
||||
my $email = '';
|
||||
my @attrs = $entry->attributes ();
|
||||
foreach my $attr (@attrs)
|
||||
{
|
||||
if ($attr eq $cfg->{ldap_mail_attribute_name})
|
||||
{
|
||||
$email = $entry->get_value ($attr);
|
||||
$xret = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$ldap->unbind();
|
||||
return ($xret, $email);
|
||||
}
|
||||
|
||||
sub get_author_email_db
|
||||
{
|
||||
my ($cfg, $dbh, $prefix, $userid) = @_;
|
||||
|
||||
my $query = $dbh->prepare("SELECT ${QC}email${QC} FROM ${QC}${prefix}user_account${QC} WHERE ${QC}userid${QC}=?");
|
||||
if (!$query || !$query->execute($userid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
if (my @row = $query->fetchrow_array())
|
||||
{
|
||||
return (1, @row[0]);
|
||||
}
|
||||
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
sub email_message_to_project_members
|
||||
{
|
||||
my ($cfg, $dbh, $prefix, $projectid, $subject, $message) = @_;
|
||||
|
||||
my $query = $dbh->prepare("SELECT ${QC}userid${QC} FROM ${QC}${prefix}project_membership${QC} WHERE ${QC}projectid${QC}=?");
|
||||
if (!$query || !$query->execute($projectid))
|
||||
{
|
||||
if ($query) { $query->finish (); }
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @members;
|
||||
while (my @row = $query->fetchrow_array())
|
||||
{
|
||||
push (@members, $row[0]);
|
||||
}
|
||||
$query->finish ();
|
||||
|
||||
my $recipients = '';
|
||||
foreach my $member (@members)
|
||||
{
|
||||
my $xret;
|
||||
my $email;
|
||||
|
||||
if ($cfg->{login_model} eq 'LdapLoginModel')
|
||||
{
|
||||
($xret, $email) = get_author_email_ldap($cfg, $member)
|
||||
}
|
||||
elsif ($cfg->{login_model} eq 'DbLoginModel')
|
||||
{
|
||||
($xret, $email) = get_author_email_db($cfg, $dbh, $prefix, $member);
|
||||
}
|
||||
else
|
||||
{
|
||||
$xret = -2;
|
||||
$email = '';
|
||||
}
|
||||
|
||||
if ($xret >= 1 && defined($email) && length($email) > 0)
|
||||
{
|
||||
if (length($recipients) > 0) { $recipients .= ', '; }
|
||||
$recipients .= $email;
|
||||
}
|
||||
}
|
||||
|
||||
if (length($recipients) <= 0) { return (0, undef); }
|
||||
|
||||
my %mail = (
|
||||
To => $recipients,
|
||||
Subject => $subject,
|
||||
Message => $message
|
||||
);
|
||||
|
||||
if (length($cfg->{email_sender}) > 0)
|
||||
{
|
||||
$mail{From} .= $cfg->{email_sender};
|
||||
}
|
||||
|
||||
Mail::Sendmail::sendmail (%mail);
|
||||
return (1, undef);
|
||||
}
|
||||
|
||||
sub format_commit_url
|
||||
{
|
||||
my ($fmt, $projectid, $author, $rev) = @_;
|
||||
|
||||
my $out = $fmt;
|
||||
$out =~ s/\$\{PROJECTID\}/$projectid/g;
|
||||
$out =~ s/\$\{AUTHOR\}/$author/g;
|
||||
$out =~ s/\$\{REV\}/$rev/g;
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
sub trigger_webhooks
|
||||
{
|
||||
my ($cfg, $dbh, $prefix, $projectid, $commit_message) = @_;
|
||||
|
||||
# find [skip ci], [no ci] or something similar
|
||||
my @skip = ();
|
||||
while ($commit_message =~ /\[(skip|no)[[:space:]]+([[:alpha:]]+)\]/g)
|
||||
{
|
||||
push (@skip, $2);
|
||||
}
|
||||
|
||||
my $query = $dbh->prepare("SELECT ${QC}webhooks${QC} FROM ${QC}${prefix}project${QC} WHERE ${QC}id${QC}=?");
|
||||
if (!$query || !$query->execute($projectid))
|
||||
{
|
||||
if ($query) { $query->finish (); }
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my $webhooks = '';
|
||||
if (my @row = $query->fetchrow_array())
|
||||
{
|
||||
$webhooks = $row[0];
|
||||
}
|
||||
|
||||
my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
|
||||
$ua->timeout (5);
|
||||
foreach my $webhook (split(/\n/ ,$webhooks))
|
||||
{
|
||||
$webhook =~ s/^\s+|\s+$//g;
|
||||
if ($webhook ne '')
|
||||
{
|
||||
my @tmp = split(/[[:space:]]+/, $webhook);
|
||||
my $type = 'ci';
|
||||
my $url = '';
|
||||
if (scalar(@tmp) == 1) { $url = @tmp[0]; }
|
||||
elsif (scalar(@tmp) == 2) { $type = @tmp[0]; $url = @tmp[1]; }
|
||||
else { next; }
|
||||
|
||||
if (grep(/^$type$/, @skip)) { next; }
|
||||
|
||||
## TODO: some formatting on url?
|
||||
my $res = $ua->get($url);
|
||||
if ($res->is_success)
|
||||
{
|
||||
##print $res->decoded_content . "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
##print $res->status_line . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$query->finish ();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------
|
||||
|
||||
my $AUTHOR = get_author();
|
||||
if (!defined($AUTHOR))
|
||||
{
|
||||
print (STDERR "Cannot get author for $REPOBASE $REV\n");
|
||||
exit (1);
|
||||
}
|
||||
chomp ($AUTHOR);
|
||||
|
||||
my $cfg = get_config();
|
||||
if (!defined($cfg))
|
||||
{
|
||||
print (STDERR "Cannot load codepot configuration file\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my $dbh = open_database($cfg);
|
||||
if (!defined($dbh))
|
||||
{
|
||||
printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my $raw_commit_message = get_commit_message();
|
||||
|
||||
find_issue_reference_in_commit_message ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $raw_commit_message);
|
||||
write_commit_log ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $AUTHOR, $cfg->{database_store_gmt});
|
||||
|
||||
if (lc($cfg->{commit_notification}) eq 'yes')
|
||||
{
|
||||
my $commit_subject = "Commit r$REV by $AUTHOR in $REPOBASE";
|
||||
my $commit_message = '';
|
||||
|
||||
if ($cfg->{commit_notification_url} eq '')
|
||||
{
|
||||
$commit_message = $commit_subject;
|
||||
}
|
||||
else
|
||||
{
|
||||
$commit_message = format_commit_url($cfg->{commit_notification_url}, $REPOBASE, $AUTHOR, $REV);
|
||||
}
|
||||
|
||||
if (defined($raw_commit_message))
|
||||
{
|
||||
$commit_message = $commit_message . "\n" . $raw_commit_message;
|
||||
}
|
||||
|
||||
|
||||
email_message_to_project_members ($cfg, $dbh, $cfg->{database_prefix}, $REPOBASE, $commit_subject, $commit_message);
|
||||
}
|
||||
|
||||
trigger_webhooks ($cfg, $dbh, $cfg->{database_prefix}, $REPOBASE, $raw_commit_message);
|
||||
|
||||
close_database ($dbh);
|
||||
|
||||
exit (0);
|
233
etc/post-revprop-change.in
Normal file
233
etc/post-revprop-change.in
Normal file
@ -0,0 +1,233 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
use Config::Simple;
|
||||
use DBI;
|
||||
use File::Basename;
|
||||
use POSIX;
|
||||
|
||||
use SVN::Core;
|
||||
use SVN::Repos;
|
||||
use SVN::Fs;
|
||||
|
||||
my $CFG_FILE = '@CFGDIR@/codepot.ini';
|
||||
my $REPOFS = $ARGV[0];
|
||||
my $REPOBASE = basename($REPOFS);
|
||||
my $REV = $ARGV[1];
|
||||
my $USER = $ARGV[2];
|
||||
my $PROPNAME = $ARGV[3];
|
||||
my $ACTION = $ARGV[4];
|
||||
|
||||
my $QC = '';
|
||||
|
||||
# [STDIN] PROPVAL ** the old property value is passed via STDIN.
|
||||
|
||||
sub get_config
|
||||
{
|
||||
my $cfg = new Config::Simple();
|
||||
|
||||
if (!$cfg->read ($CFG_FILE))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $config = {
|
||||
database_hostname => $cfg->param ("database_hostname"),
|
||||
database_port => $cfg->param ("database_port"),
|
||||
database_username => $cfg->param ("database_username"),
|
||||
database_password => $cfg->param ("database_password"),
|
||||
database_name => $cfg->param ("database_name"),
|
||||
database_driver => $cfg->param ("database_driver"),
|
||||
database_prefix => $cfg->param ("database_prefix"),
|
||||
database_store_gmt => $cfg->param ("database_store_gmt")
|
||||
};
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub open_database
|
||||
{
|
||||
my ($cfg) = @_;
|
||||
|
||||
my $dbtype = $cfg->{database_driver};
|
||||
my $dbname = $cfg->{database_name};
|
||||
my $dbhost = $cfg->{database_hostname};
|
||||
my $dbport = $cfg->{database_port};
|
||||
|
||||
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
||||
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
||||
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
||||
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
|
||||
|
||||
my $dbstr;
|
||||
my $dbuser;
|
||||
my $dbpass;
|
||||
if ($dbtype eq 'Oracle')
|
||||
{
|
||||
$QC = '"';
|
||||
$dbstr = "DBI:$dbtype:";
|
||||
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
||||
$dbpass = '';
|
||||
}
|
||||
elsif ($dbtype eq 'SQLite')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbhost;";
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbname;";
|
||||
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
||||
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
||||
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
$dbstr, $dbuser, $dbpass,
|
||||
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
||||
);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub close_database
|
||||
{
|
||||
my ($dbh) = @_;
|
||||
$dbh->disconnect ();
|
||||
}
|
||||
|
||||
|
||||
sub find_issue_reference_in_commit_message
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $revision, $commit_message) = @_;
|
||||
|
||||
# find [[#IXXXX]]
|
||||
my @issue_ids = ($commit_message =~ /\[\[#I(\d+)\]\]/g);
|
||||
# find #XXXX
|
||||
my @issue_ids2 = ($commit_message =~ /(^|[^#])#(\d+)(\D|$)/g);
|
||||
|
||||
# find unique issue ids in the findings.
|
||||
my %tmp;
|
||||
@tmp{@issue_ids} = 1;
|
||||
for (my $i = 0; $i < scalar(@issue_ids2); $i += 3)
|
||||
{
|
||||
my $id = @issue_ids2[$i + 1];
|
||||
@tmp{$id} = 1;
|
||||
}
|
||||
my @unique_issue_ids = keys(%tmp);
|
||||
|
||||
$dbh->begin_work ();
|
||||
|
||||
my $query = $dbh->prepare ("DELETE FROM ${QC}${prefix}issue_coderev${QC} WHERE ${QC}codeproid${QC}=? AND ${QC}coderev${QC}=?");
|
||||
if (!$query || !$query->execute ($projectid, $revision))
|
||||
{
|
||||
my $errstr = $dbh->errstr();
|
||||
if ($query) { $query->finish (); }
|
||||
$dbh->rollback ();
|
||||
return (-1, $errstr);
|
||||
}
|
||||
$query->finish ();
|
||||
|
||||
for my $issue_id(@unique_issue_ids)
|
||||
{
|
||||
my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}issue_coderev${QC} (${QC}projectid${QC},${QC}issueid${QC},${QC}codeproid${QC},${QC}coderev${QC}) VALUES (?,?,?,?)");
|
||||
if ($query)
|
||||
{
|
||||
# ignore errors
|
||||
$query->execute ($projectid, $issue_id, $projectid, $revision);
|
||||
$query->finish ();
|
||||
}
|
||||
}
|
||||
|
||||
$dbh->commit ();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
sub write_revprop_change_log
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $revision, $userid, $propname, $action, $store_gmt) = @_;
|
||||
|
||||
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
|
||||
#| id | type | projectid | message | createdon | action | userid |
|
||||
#+------+---------+-----------+---------------------------+---------------------+---------------+-----------------+
|
||||
#| 1610 | code | codepot | svn,codepot,98,svn:log,M | 2014-05-16 22:27:36 | revpropchange | hyunghwan.chung |
|
||||
|
||||
my $message = "svn,$projectid,$revision,$propname,$action";
|
||||
my $timestamp;
|
||||
|
||||
if (($store_gmt =~ /^\d+?$/ && int($store_gmt) != 0) || (lc($store_gmt) eq 'yes'))
|
||||
{
|
||||
$timestamp = POSIX::strftime ('%Y-%m-%d %H:%M:%S', gmtime());
|
||||
}
|
||||
else
|
||||
{
|
||||
$timestamp = POSIX::strftime ('%Y-%m-%d %H:%M:%S', localtime());
|
||||
}
|
||||
|
||||
$dbh->begin_work ();
|
||||
|
||||
my $query = $dbh->prepare ("INSERT INTO ${QC}${prefix}log${QC} (${QC}type${QC},${QC}projectid${QC},${QC}message${QC},${QC}createdon${QC},${QC}action${QC},${QC}userid${QC}) VALUES (?,?,?,?,?,?)");
|
||||
if (!$query || !$query->execute ('code', $projectid, $message, $timestamp, 'revpropchange', $userid))
|
||||
{
|
||||
my $errstr = $dbh->errstr();
|
||||
if ($query) { $query->finish (); }
|
||||
$dbh->rollback ();
|
||||
return (-1, $errstr);
|
||||
}
|
||||
|
||||
$query->finish ();
|
||||
$dbh->commit ();
|
||||
return (0, undef);
|
||||
}
|
||||
|
||||
sub get_commit_message
|
||||
{
|
||||
my $pool = SVN::Pool->new(undef);
|
||||
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
||||
if (!defined($svn))
|
||||
{
|
||||
print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $fs = $svn->fs ();
|
||||
if (!defined($fs))
|
||||
{
|
||||
print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $logmsg = $fs->revision_prop ($REV, 'svn:log');
|
||||
return $logmsg;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------
|
||||
|
||||
my $cfg = get_config ();
|
||||
if (!defined($cfg))
|
||||
{
|
||||
print (STDERR "Cannot load codepot configuration file\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my $dbh = open_database ($cfg);
|
||||
if (!defined($dbh))
|
||||
{
|
||||
printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my $raw_commit_message = get_commit_message();
|
||||
|
||||
find_issue_reference_in_commit_message ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $raw_commit_message);
|
||||
write_revprop_change_log ($dbh, $cfg->{database_prefix}, $REPOBASE, $REV, $USER, $PROPNAME, $ACTION, $cfg->{database_store_gmt});
|
||||
close_database ($dbh);
|
||||
|
||||
exit (0);
|
||||
|
725
etc/pre-commit.in
Normal file
725
etc/pre-commit.in
Normal file
@ -0,0 +1,725 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
use Config::Simple;
|
||||
use DBI;
|
||||
use File::Basename;
|
||||
|
||||
use SVN::Core;
|
||||
use SVN::Repos;
|
||||
use SVN::Fs;
|
||||
|
||||
my $CFG_FILE = '@CFGDIR@/codepot.ini';
|
||||
my $REPOFS = $ARGV[0];
|
||||
my $REPOBASE = basename($REPOFS);
|
||||
my $TRANSACTION = $ARGV[1];
|
||||
|
||||
my $QC = '';
|
||||
|
||||
my %SVN_ACTIONS =
|
||||
(
|
||||
'A ' => 'add',
|
||||
'U ' => 'update',
|
||||
'D ' => 'delete',
|
||||
'_U' => 'propset',
|
||||
'UU' => 'update/propset'
|
||||
);
|
||||
|
||||
my %SVN_ACTION_VERBS =
|
||||
(
|
||||
$SVN::Fs::PathChange::modify => 'modify',
|
||||
$SVN::Fs::PathChange::add => 'add',
|
||||
$SVN::Fs::PathChange::delete => 'delete',
|
||||
$SVN::Fs::PathChange::replace => 'replace'
|
||||
);
|
||||
|
||||
sub get_config
|
||||
{
|
||||
my $cfg = new Config::Simple();
|
||||
|
||||
if (!$cfg->read ($CFG_FILE))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $config = {
|
||||
database_hostname => $cfg->param ('database_hostname'),
|
||||
database_port => $cfg->param ("database_port"),
|
||||
database_username => $cfg->param ('database_username'),
|
||||
database_password => $cfg->param ('database_password'),
|
||||
database_name => $cfg->param ('database_name'),
|
||||
database_driver => $cfg->param ('database_driver'),
|
||||
database_prefix => $cfg->param ('database_prefix'),
|
||||
|
||||
svn_min_commit_message_length => $cfg->param ('svn_min_commit_message_length'),
|
||||
svn_restricted_topdirs => $cfg->param('svn_restricted_topdirs'),
|
||||
svn_restriction_allowed_subdir_depth_min => $cfg->param('svn_restriction_allowed_subdir_depth_min'),
|
||||
svn_restriction_allowed_subdir_depth_max => $cfg->param('svn_restriction_allowed_subdir_depth_max')
|
||||
};
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub open_database
|
||||
{
|
||||
my ($cfg) = @_;
|
||||
|
||||
my $dbtype = $cfg->{database_driver};
|
||||
my $dbname = $cfg->{database_name};
|
||||
my $dbhost = $cfg->{database_hostname};
|
||||
my $dbport = $cfg->{database_port};
|
||||
|
||||
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
||||
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
||||
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
||||
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
|
||||
|
||||
my $dbstr;
|
||||
my $dbuser;
|
||||
my $dbpass;
|
||||
if ($dbtype eq 'Oracle')
|
||||
{
|
||||
$QC = '"';
|
||||
$dbstr = "DBI:$dbtype:";
|
||||
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
||||
$dbpass = '';
|
||||
}
|
||||
elsif ($dbtype eq 'SQLite')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbhost;";
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbname;";
|
||||
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
||||
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
||||
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
$dbstr, $dbuser, $dbpass,
|
||||
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
||||
);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub close_database
|
||||
{
|
||||
my ($dbh) = @_;
|
||||
$dbh->disconnect ();
|
||||
}
|
||||
|
||||
sub is_project_member
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $userid) = @_;
|
||||
|
||||
my $query = $dbh->prepare ("SELECT ${QC}projectid${QC} FROM ${QC}${prefix}project_membership${QC} WHERE ${QC}userid${QC}=? AND ${QC}projectid${QC}=?");
|
||||
if (!$query || !$query->execute ($userid, $projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0)? 1: 0), undef);
|
||||
}
|
||||
|
||||
sub is_project_commitable
|
||||
{
|
||||
my ($dbh, $prefix, $projectid) = @_;
|
||||
|
||||
my $query = $dbh->prepare ("SELECT ${QC}commitable${QC} FROM ${QC}${prefix}project${QC} WHERE ${QC}id${QC}=?");
|
||||
if (!$query || !$query->execute ($projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0 && $row[0] eq 'Y')? 1: 0), undef);
|
||||
}
|
||||
|
||||
sub contains_repeated_chars
|
||||
{
|
||||
my ($str, $limit) = @_;
|
||||
|
||||
my $len = length($str);
|
||||
my $lc = '';
|
||||
my $count = 1;
|
||||
|
||||
for (my $i = 0; $i < $len; $i++)
|
||||
{
|
||||
my $c = substr($str, $i, 1);
|
||||
if ($lc eq $c)
|
||||
{
|
||||
$count++;
|
||||
if ($count > $limit) { return 1; }
|
||||
}
|
||||
else
|
||||
{
|
||||
$count = 1;
|
||||
$lc = $c;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub check_commit_message
|
||||
{
|
||||
my ($minlen) = @_;
|
||||
|
||||
my $pool = SVN::Pool->new(undef);
|
||||
#my $config = SVN::Core::config_get_config(undef);
|
||||
#my $fs = eval { SVN::Fs::open ($REPOFS, $config, $pool) };
|
||||
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
||||
if (!defined($svn))
|
||||
{
|
||||
print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
return -1; # error
|
||||
}
|
||||
|
||||
my $fs = $svn->fs ();
|
||||
if (!defined($fs))
|
||||
{
|
||||
print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
return -1; # error
|
||||
}
|
||||
|
||||
my $txn = eval { $fs->open_txn ($TRANSACTION) };
|
||||
if (!defined($txn))
|
||||
{
|
||||
print (STDERR "Cannot open transaction - $TRANSACTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
my $log = $txn->prop ('svn:log');
|
||||
# TODO: block a certain message patterns. create a configuration item
|
||||
# for this
|
||||
#if ($log =~ /[[:punct:]]{5,}/ || $log =~ /[[:alpha:]]{40,}/ || contains_repeated_chars($log, 4))
|
||||
#{
|
||||
# print (STDERR "Commit message rejected\n");
|
||||
# return 0;
|
||||
#}
|
||||
|
||||
$log =~ s/\s{2,}/ /g;
|
||||
$log =~ s/([[:punct:]]{1,2}\s+){3,}/ /g;
|
||||
$log =~ s/[[:punct:]]{3,}/ /g;
|
||||
$log =~ s/^\s+|\s+$//g; # trim leading spaces and trailing spaces
|
||||
if (length($log) < $minlen)
|
||||
{
|
||||
print (STDERR "Commit message too short. meaningful part must be >= $minlen\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($log =~ /^[[:punct:][:space:]]+$/)
|
||||
{
|
||||
print (STDERR "Commit message meaningless\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub restrict_changes_in_directory_old
|
||||
{
|
||||
my ($dir, $min_level, $max_level) = @_;
|
||||
|
||||
my @change_info = `svnlook changed --copy-info -t "${TRANSACTION}" "${REPOFS}"`;
|
||||
|
||||
# 'A ' Item added to repository
|
||||
# 'D ' Item deleted from repository
|
||||
# 'U ' File contents changed
|
||||
# '_U' Properties of item changed; note the leading underscore
|
||||
# 'UU' File contents and properties changed
|
||||
# ------------------------------------------------------------
|
||||
# + on the third column to indicate copy
|
||||
# fourth column is empty.
|
||||
# ------------------------------------------------------------
|
||||
# When copy-info is used, the source of the copy is shown
|
||||
# on the next line aligned at the file name part and
|
||||
# begins with spaces.
|
||||
#
|
||||
# A + y/t/
|
||||
# (from c/:r2)
|
||||
# ------------------------------------------------------------
|
||||
#
|
||||
# Renaming a file in the copied directory looks like this.
|
||||
# D tags/xxx-1.2.3/2/screenrc
|
||||
# A + tags/xxx-1.2.3/2/screenrc.x
|
||||
# (from tags/xxx-1.2.3/2/screenrc:r10)
|
||||
#
|
||||
# If the deletion of the file is disallowed, the whole
|
||||
# transaction is blocked. so I don't need to care about
|
||||
# copied addition.
|
||||
# ------------------------------------------------------------
|
||||
|
||||
foreach my $line(@change_info)
|
||||
{
|
||||
chomp ($line);
|
||||
print (STDERR "... CHANGE INFO => $line\n");
|
||||
}
|
||||
|
||||
my $disallowed = 0;
|
||||
|
||||
while (@change_info) #foreach my $line(@change_info)
|
||||
{
|
||||
my $line = shift (@change_info);
|
||||
chomp ($line);
|
||||
|
||||
if ($line =~ /^(A |U |D |_U|UU) ${dir}\/(.*)$/)
|
||||
{
|
||||
my $action = "${1}";
|
||||
my $affected_file = "${dir}/${2}";
|
||||
my $affected_file_nodir = "${2}";
|
||||
|
||||
my $action_verb = $SVN_ACTIONS{$action};
|
||||
|
||||
if (rindex($affected_file, '/') + 1 == length($affected_file))
|
||||
{
|
||||
# the last character is a slash. so it's a directory.
|
||||
# let's allow most of the operations on a directory.
|
||||
#if ($action eq 'D ')
|
||||
#{
|
||||
my @segs = split ('/', $affected_file_nodir);
|
||||
my $num_segs = scalar(@segs);
|
||||
# NOTE: for a string like abc/def/, split() seems to return 2 segments only.
|
||||
|
||||
if ($affected_file_nodir eq '')
|
||||
{
|
||||
# it is the main directory itself.
|
||||
# allow operation on it.
|
||||
}
|
||||
elsif ($num_segs < $min_level || $num_segs > $max_level)
|
||||
{
|
||||
# disallow deletion if the directory name to be deleted
|
||||
# matches a tag pattern
|
||||
print (STDERR "Disallowed to ${action_verb} a directory - ${affected_file}\n");
|
||||
$disallowed++;
|
||||
}
|
||||
#}
|
||||
}
|
||||
else
|
||||
{
|
||||
print (STDERR "Disallowed to ${action_verb} a file - ${affected_file}\n");
|
||||
$disallowed++;
|
||||
}
|
||||
}
|
||||
elsif ($line =~ /^(A )\+ ${dir}\/(.*)$/)
|
||||
{
|
||||
my $action = "${1}";
|
||||
my $affected_file = "${dir}/${2}";
|
||||
|
||||
# copying
|
||||
#
|
||||
# A + tags/xxx-1.2.3/2/smi.conf.2
|
||||
# (from tags/xxx-1.2.3/2/smi.conf:r10)
|
||||
#
|
||||
my $source_line = shift (@change_info);
|
||||
chomp ($source_line);
|
||||
|
||||
if ($source_line =~ /
|
||||
^ # beginning of string
|
||||
\W* # 0 or more white-spaces
|
||||
\( # opening parenthesis
|
||||
\S+ # 1 or more non-space characters
|
||||
\W+ # 1 or more space characters
|
||||
(.+) # 1 or more characters
|
||||
:r[0-9]+ # :rXXX where XXX is digits
|
||||
\) # closing parenthesis
|
||||
$ # end of string
|
||||
/x)
|
||||
{
|
||||
my $source_file = "${1}";
|
||||
|
||||
if (rindex($affected_file, '/') + 1 != length($affected_file))
|
||||
{
|
||||
# the file beging added by copyiung is not a directory.
|
||||
# it disallows individual file copying.
|
||||
# copy a whole directory at one go.
|
||||
print (STDERR "Disallowed to copy $source_file to $affected_file\n");
|
||||
$disallowed++;
|
||||
}
|
||||
elsif ($source_file =~ /^${dir}\/(.*)$/)
|
||||
{
|
||||
# i don't want to be a copied file or directory to be
|
||||
# a source of another copy operation.
|
||||
print (STDERR "Disallowed to copy $source_file to $affected_file\n");
|
||||
$disallowed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Assume xxx is a directory.
|
||||
# Assume min_level is 1 and max_level is 2.
|
||||
#
|
||||
# If the following two commans are executed,
|
||||
# svn copy trunk/xxx tags/my-4.0.0
|
||||
# svn copy trunk/xxx tags/my-4.0.0/1
|
||||
#
|
||||
# svnlook returns the following text.
|
||||
# A + tags/my-4.0.0/
|
||||
# (from trunk/xxx/:r16)
|
||||
# A + tags/my-4.0.0/1/
|
||||
# (from trunk/xxx/:r16)
|
||||
#
|
||||
# if the script knows that tags/my-4.0.0 is created via copying,
|
||||
# i want this script to prevent copying other sources into it.
|
||||
# this case is not fully handled by this script.
|
||||
|
||||
# TODO: DISALLOW THIS if the parent directory is a copied directory
|
||||
my $pardir = dirname ($affected_file);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#{
|
||||
# print (STDERR "OK ... ${line}\n");
|
||||
#}
|
||||
}
|
||||
|
||||
return ($disallowed > 0)? -1: 0;
|
||||
}
|
||||
|
||||
sub restrict_changes_in_topdirs
|
||||
{
|
||||
my ($min_level, $max_level, @topdirs) = @_;
|
||||
my $disallowed = 0;
|
||||
|
||||
my $pool = SVN::Pool->new(undef);
|
||||
#my $config = SVN::Core::config_get_config(undef);
|
||||
#my $fs = eval { SVN::Fs::open ($REPOFS, $config, $pool) };
|
||||
my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
||||
if (!defined($svn))
|
||||
{
|
||||
print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
return -1; # error
|
||||
}
|
||||
|
||||
my $fs = $svn->fs ();
|
||||
if (!defined($fs))
|
||||
{
|
||||
print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
return -1; # error
|
||||
}
|
||||
|
||||
my $txn = eval { $fs->open_txn ($TRANSACTION) };
|
||||
if (!defined($txn))
|
||||
{
|
||||
print (STDERR "Cannot open transaction - $TRANSACTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
my $root = eval { $txn->root() };
|
||||
if (!defined($root))
|
||||
{
|
||||
print (STDERR "Cannot open root of transaction - $TRANSACTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
my $paths_changed = eval { $root->paths_changed() };
|
||||
if (!defined($paths_changed))
|
||||
{
|
||||
# no change information found. return ok
|
||||
$root->close_root ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach my $affected_file(keys(%$paths_changed))
|
||||
{
|
||||
my $chg = $paths_changed->{$affected_file};
|
||||
my $action = $chg->change_kind();
|
||||
my $action_verb = $SVN_ACTION_VERBS{$action};
|
||||
if (length($action_verb) <= 0) { $action_verb = "work on"; }
|
||||
|
||||
my $is_source_file_dir = 0;
|
||||
my $is_affected_file_dir = eval { $root->is_dir($affected_file) };
|
||||
#$chg->text_mod(), $chg->prop_mod()
|
||||
|
||||
#my $affected_rev_id = eval { SVN::Fs::unparse_id($chg->node_rev_id()) };
|
||||
my $source_file = undef;
|
||||
#my $source_id = undef;
|
||||
|
||||
if ($action == $SVN::Fs::PathChange::add)
|
||||
{
|
||||
$source_file = eval { $root->copied_from($affected_file) };
|
||||
#if ($source_file)
|
||||
#{
|
||||
# $source_id = eval { SVN::Fs::unparse_id($root->node_id($source_file)) };
|
||||
#}
|
||||
}
|
||||
elsif ($action == $SVN::Fs::PathChange::delete)
|
||||
{
|
||||
# when a file is deleted, $root->is_dir() doesn't seem to
|
||||
# return the right type. use the revision root to determine it.
|
||||
my $rev_root = $fs->revision_root($fs->youngest_rev());
|
||||
$is_affected_file_dir = eval { $rev_root->is_dir ($affected_file) };
|
||||
$rev_root->close_root();
|
||||
}
|
||||
|
||||
#print STDERR "@@@@@ [$affected_file] [$action_verb] [$source_file] [$is_source_file_dir] [$is_affected_file_dir]\n";
|
||||
|
||||
foreach my $topdir(@topdirs)
|
||||
{
|
||||
if ($affected_file =~ /^\/${topdir}\/(.*)$/)
|
||||
{
|
||||
# the affected file is located under the given directory.
|
||||
my $affected_file_nodir = "${1}";
|
||||
|
||||
if (defined($source_file))
|
||||
{
|
||||
# it's being copied.
|
||||
if (!$is_affected_file_dir)
|
||||
{
|
||||
# the file beging added by copying is not a directory.
|
||||
# it disallows individual file copying.
|
||||
# copy a whole directory at one go.
|
||||
print (STDERR "Disallowed to copy ${source_file} to ${affected_file}\n");
|
||||
$disallowed++;
|
||||
}
|
||||
elsif ($source_file =~ /^\/${topdir}\/(.*)$/)
|
||||
{
|
||||
# i don't want to be a copied file or directory to be
|
||||
# a source of another copy operation.
|
||||
print (STDERR "Disallowed to copy ${source_file} to ${affected_file}\n");
|
||||
$disallowed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
# TODO: DISALLOW THIS if the parent directory is a copied directory
|
||||
#my $pardir = dirname ($affected_file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($is_affected_file_dir)
|
||||
{
|
||||
my @segs = split ('/', $affected_file_nodir);
|
||||
my $num_segs = scalar(@segs);
|
||||
# NOTE: for a string like abc/def/, split() seems to return 2 segments only.
|
||||
|
||||
if ($affected_file_nodir eq '')
|
||||
{
|
||||
# it is the main directory itself.
|
||||
# allow operation on it.
|
||||
}
|
||||
elsif ($num_segs < $min_level || $num_segs > $max_level)
|
||||
{
|
||||
# disallow deletion if the directory name to be deleted
|
||||
# matches a tag pattern
|
||||
print (STDERR "Disallowed to ${action_verb} a directory - ${affected_file}\n");
|
||||
$disallowed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print (STDERR "Disallowed to ${action_verb} a file - ${affected_file}\n");
|
||||
$disallowed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 'svn rename' within the restricted directory is disallowed because
|
||||
# it splits to deletion and addition. for this reason, you're supposed
|
||||
# to copy from the trunk or branch source again.
|
||||
#
|
||||
# $ svn rename tags/my-1.0.0 tags/my-2.0.0
|
||||
# $ svn commit -m "XXXXXXXXXXXX"
|
||||
# Deleting tags/my-1.0.0
|
||||
# Adding tags/my-2.0.0
|
||||
#
|
||||
|
||||
$root->close_root ();
|
||||
return ($disallowed > 0)? -1: 0;
|
||||
}
|
||||
|
||||
sub restrict_read_only_files()
|
||||
{
|
||||
my $disallowed = 0;
|
||||
|
||||
my $pool = SVN::Pool->new(undef);
|
||||
#my $config = SVN::Core::config_get_config(undef);
|
||||
#my $fs = eval { SVN::Fs::open($REPOFS, $config, $pool) };
|
||||
my $svn = eval { SVN::Repos::open($REPOFS, $pool) };
|
||||
if (!defined($svn))
|
||||
{
|
||||
print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
return -1; # error
|
||||
}
|
||||
|
||||
my $fs = $svn->fs();
|
||||
if (!defined($fs))
|
||||
{
|
||||
print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
return -1; # error
|
||||
}
|
||||
|
||||
my $txn = eval { $fs->open_txn ($TRANSACTION) };
|
||||
if (!defined($txn))
|
||||
{
|
||||
print (STDERR "Cannot open transaction - $TRANSACTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
my $root = eval { $txn->root() };
|
||||
if (!defined($root))
|
||||
{
|
||||
print (STDERR "Cannot open root of transaction - $TRANSACTION\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
my $paths_changed = eval { $root->paths_changed() };
|
||||
if (!defined($paths_changed))
|
||||
{
|
||||
# no change information found. return ok
|
||||
$root->close_root ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $fs_root = $fs->revision_root($fs->youngest_rev());
|
||||
|
||||
foreach my $affected_file(keys(%$paths_changed))
|
||||
{
|
||||
my $chg = $paths_changed->{$affected_file};
|
||||
my $action = $chg->change_kind();
|
||||
my $action_verb = $SVN_ACTION_VERBS{$action};
|
||||
if (length($action_verb) <= 0) { $action_verb = "work on"; }
|
||||
|
||||
## check codepot:readonly only if there is content change.
|
||||
## property-only change is always allowed.
|
||||
## directory addition is probably allowed. ## TODO: prevent this?
|
||||
next if ($action != $SVN::Fs::PathChange::delete && !$chg->text_mod());
|
||||
|
||||
my $file = $affected_file;
|
||||
my $readonly = eval { $fs_root->node_prop($file, 'codepot:readonly') };
|
||||
if ($readonly eq 'yes')
|
||||
{
|
||||
$disallowed = 1;
|
||||
print (STDERR "Unable to $action_verb $file - read-only\n");
|
||||
}
|
||||
elsif ($readonly eq 'no')
|
||||
{
|
||||
## no is set explicitly on the node itself.
|
||||
## don't proceed to check the parent side.
|
||||
## change is granted immediately.
|
||||
## DO NOTHING HERE
|
||||
}
|
||||
else
|
||||
{
|
||||
## check permission in the parent side
|
||||
while ((my $slash = rindex($file, "/")) >= 0)
|
||||
{
|
||||
$file = substr($file, 0, $slash);
|
||||
my $tmp = $file;
|
||||
$tmp = '/' if ($tmp eq '');
|
||||
$readonly = eval { $fs_root->node_prop($tmp, 'codepot:readonly') };
|
||||
if ($readonly eq 'yes')
|
||||
{
|
||||
$disallowed = 1;
|
||||
print (STDERR "Unable to $action_verb $affected_file - $tmp set to read-only\n");
|
||||
}
|
||||
elsif ($readonly eq 'no')
|
||||
{
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$root->close_root ();
|
||||
return ($disallowed > 0)? -1: 0;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------
|
||||
|
||||
my $cfg = get_config ();
|
||||
if (!defined($cfg))
|
||||
{
|
||||
print (STDERR "Cannot load codepot configuration file\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (check_commit_message ($cfg->{svn_min_commit_message_length}) <= 0)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
# TODO: enable per-project settings for topdir restriction
|
||||
my $min_level = $cfg->{svn_restriction_allowed_subdir_depth_min};
|
||||
if (!defined($min_level)) { $min_level = 0; }
|
||||
my $max_level = $cfg->{svn_restriction_allowed_subdir_depth_max};
|
||||
if (!defined($max_level)) { $max_level = 0; }
|
||||
|
||||
my $topdirs = $cfg->{svn_restricted_topdirs};
|
||||
if (defined($topdirs))
|
||||
{
|
||||
my @topdir_array = split (/\s*,\s*/, $topdirs);
|
||||
if (scalar(@topdir_array) > 0)
|
||||
{
|
||||
if (restrict_changes_in_topdirs ($min_level, $max_level, @topdir_array) <= -1)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (restrict_read_only_files() <= -1)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
|
||||
#my $dbh = open_database ($cfg);
|
||||
#if (!defined($dbh))
|
||||
#{
|
||||
# printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
|
||||
# exit (1);
|
||||
#}
|
||||
#
|
||||
#my $member;
|
||||
#my $commitable;
|
||||
#my $errstr;
|
||||
#
|
||||
#($member, $errstr) = is_project_member (
|
||||
# $dbh, $cfg->{database_prefix}, $REPOBASE, $USER);
|
||||
#if ($member <= -1)
|
||||
#{
|
||||
# print (STDERR "Cannot check membership - $errstr\n");
|
||||
# close_database ($dbh);
|
||||
# exit (1);
|
||||
#}
|
||||
#
|
||||
#($commitable, $errstr) = is_project_commitable (
|
||||
# $dbh, $cfg->{database_prefix}, $REPOBASE);
|
||||
#if ($commitable <= -1)
|
||||
#{
|
||||
# print (STDERR "Cannot check commitability - $errstr\n");
|
||||
# close_database ($dbh);
|
||||
# exit (1);
|
||||
#}
|
||||
#
|
||||
#close_database ($dbh);
|
||||
#
|
||||
#if ($member == 0)
|
||||
#{
|
||||
# print (STDERR "$USER doesn't belong to the $REPOBASE project\n");
|
||||
# exit (1);
|
||||
#}
|
||||
#
|
||||
#if ($commitable == 0)
|
||||
#{
|
||||
# print (STDERR "The $REPOBASE project is not commitable\n");
|
||||
# exit (1);
|
||||
#}
|
||||
#
|
||||
exit (0);
|
237
etc/pre-revprop-change.in
Normal file
237
etc/pre-revprop-change.in
Normal file
@ -0,0 +1,237 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
use Config::Simple;
|
||||
use DBI;
|
||||
use File::Basename;
|
||||
|
||||
#use SVN::Core;
|
||||
#use SVN::Repos;
|
||||
#use SVN::Fs;
|
||||
|
||||
my $CFG_FILE = '@CFGDIR@/codepot.ini';
|
||||
my $REPOFS = $ARGV[0];
|
||||
my $REPOBASE = basename($REPOFS);
|
||||
my $REVISION= $ARGV[1];
|
||||
my $USER = $ARGV[2];
|
||||
my $PROPNAME = $ARGV[3];
|
||||
my $ACTION = $ARGV[4];
|
||||
|
||||
my $QC = '';
|
||||
|
||||
sub get_config
|
||||
{
|
||||
my $cfg = new Config::Simple();
|
||||
|
||||
if (!$cfg->read ($CFG_FILE))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $config = {
|
||||
database_hostname => $cfg->param ("database_hostname"),
|
||||
database_port => $cfg->param ("database_port"),
|
||||
database_username => $cfg->param ("database_username"),
|
||||
database_password => $cfg->param ("database_password"),
|
||||
database_name => $cfg->param ("database_name"),
|
||||
database_driver => $cfg->param ("database_driver"),
|
||||
database_prefix => $cfg->param ("database_prefix"),
|
||||
|
||||
svn_min_commit_message_length => $cfg->param ('svn_min_commit_message_length')
|
||||
};
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub open_database
|
||||
{
|
||||
my ($cfg) = @_;
|
||||
|
||||
my $dbtype = $cfg->{database_driver};
|
||||
my $dbname = $cfg->{database_name};
|
||||
my $dbhost = $cfg->{database_hostname};
|
||||
my $dbport = $cfg->{database_port};
|
||||
|
||||
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
||||
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
||||
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
||||
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
|
||||
|
||||
my $dbstr;
|
||||
my $dbuser;
|
||||
my $dbpass;
|
||||
if ($dbtype eq 'Oracle')
|
||||
{
|
||||
$QC = '"';
|
||||
$dbstr = "DBI:$dbtype:";
|
||||
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
||||
$dbpass = '';
|
||||
}
|
||||
elsif ($dbtype eq 'SQLite')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbhost;";
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbname;";
|
||||
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
||||
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
||||
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
$dbstr, $dbuser, $dbpass,
|
||||
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
||||
);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub close_database
|
||||
{
|
||||
my ($dbh) = @_;
|
||||
$dbh->disconnect ();
|
||||
}
|
||||
|
||||
sub is_project_member
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $userid) = @_;
|
||||
|
||||
my $query = $dbh->prepare ("SELECT ${QC}projectid${QC} FROM ${QC}${prefix}project_membership${QC} WHERE ${QC}userid${QC}=? AND ${QC}projectid${QC}=?");
|
||||
if (!$query || !$query->execute ($userid, $projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0)? 1: 0), undef);
|
||||
}
|
||||
|
||||
#sub check_commit_message
|
||||
#{
|
||||
# my ($minlen, $newmsg) = @_;
|
||||
#
|
||||
# my $pool = SVN::Pool->new(undef);
|
||||
# my $svn = eval { SVN::Repos::open ($REPOFS, $pool) };
|
||||
# if (!defined($svn))
|
||||
# {
|
||||
# print (STDERR "Cannot open svn - $REPOFS\n");
|
||||
# return -1; # error
|
||||
# }
|
||||
#
|
||||
# my $fs = $svn->fs ();
|
||||
# if (!defined($fs))
|
||||
# {
|
||||
# print (STDERR "Cannot open fs - $REPOFS\n");
|
||||
# return -1; # error
|
||||
# }
|
||||
#
|
||||
# my $log = $fs->revision_prop ($REVISION, 'svn:log');
|
||||
# $log =~ s/^\s+|\s+$//g; # trim leading spaces and trailing spaces
|
||||
# if (length($log) < $minlen)
|
||||
# {
|
||||
# print (STDERR "[$log] Commit message too short. must be >= $minlen\n");
|
||||
# return 0;
|
||||
# }
|
||||
#
|
||||
# return 1;
|
||||
#}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------
|
||||
|
||||
my $newauthor = undef;
|
||||
|
||||
my $cfg = get_config ();
|
||||
if (!defined($cfg))
|
||||
{
|
||||
print (STDERR "Cannot load codepot configuration file\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
if ($ACTION eq 'D')
|
||||
{
|
||||
if ($PROPNAME eq 'svn:log' || $PROPNAME eq 'svn:author' || $PROPNAME eq 'svn:date')
|
||||
{
|
||||
print (STDERR "Not allowed to delete $PROPNAME\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
elsif ($ACTION eq 'M' || $ACTION eq 'A')
|
||||
{
|
||||
if ($PROPNAME eq 'svn:author')
|
||||
{
|
||||
$newauthor = do { local $/; <STDIN> }; # read <STDIN> as a whole
|
||||
$newauthor =~ s/^\s+|\s+$//g; # trim leading spaces and trailing spaces
|
||||
if ($newauthor eq '')
|
||||
{
|
||||
print (STDERR "Not allowed to empty the author\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
elsif ($PROPNAME eq 'svn:log')
|
||||
{
|
||||
my $minlen = $cfg->{svn_min_commit_message_length};
|
||||
my $newmsg = do { local $/; <STDIN> }; # read <STDIN> as a whole
|
||||
$newmsg =~ s/^\s+|\s+$//g; # trim leading spaces and trailing spaces
|
||||
if (length($newmsg) < $minlen)
|
||||
{
|
||||
print (STDERR "Commit message too short. must be >= $minlen\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $dbh = open_database ($cfg);
|
||||
if (!defined($dbh))
|
||||
{
|
||||
printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my ($member, $errstr) = is_project_member ($dbh, $cfg->{database_prefix}, $REPOBASE, $USER);
|
||||
|
||||
|
||||
if ($member <= -1)
|
||||
{
|
||||
close_database ($dbh);
|
||||
print (STDERR "Cannot check membership of [$USER] in the $REPOBASE project - $errstr\n");
|
||||
exit (1);
|
||||
}
|
||||
elsif ($member == 0)
|
||||
{
|
||||
close_database ($dbh);
|
||||
print (STDERR "[$USER] doesn't belong to the $REPOBASE project\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (defined($newauthor))
|
||||
{
|
||||
# the new author to set must be a member of the project.
|
||||
|
||||
my ($member, $errstr) = is_project_member ($dbh, $cfg->{database_prefix}, $REPOBASE, $newauthor);
|
||||
if ($member <= -1)
|
||||
{
|
||||
close_database ($dbh);
|
||||
print (STDERR "Cannot check membership of [$newauthor] in the $REPOBASE project - $errstr\n");
|
||||
exit (1);
|
||||
}
|
||||
elsif ($member == 0)
|
||||
{
|
||||
close_database ($dbh);
|
||||
print (STDERR "[$newauthor] doesn't belong to the $REPOBASE project\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
close_database ($dbh);
|
||||
exit (0);
|
175
etc/start-commit.in
Normal file
175
etc/start-commit.in
Normal file
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
|
||||
use Config::Simple;
|
||||
use DBI;
|
||||
use File::Basename;
|
||||
|
||||
my $CFG_FILE = '@CFGDIR@/codepot.ini';
|
||||
my $REPOBASE = basename($ARGV[0]);
|
||||
my $USER = $ARGV[1];
|
||||
|
||||
my $QC = '';
|
||||
|
||||
sub get_config
|
||||
{
|
||||
my $cfg = new Config::Simple();
|
||||
|
||||
if (!$cfg->read ($CFG_FILE))
|
||||
{
|
||||
return undef;
|
||||
}
|
||||
|
||||
my $config = {
|
||||
database_hostname => $cfg->param ("database_hostname"),
|
||||
database_port => $cfg->param ("database_port"),
|
||||
database_username => $cfg->param ("database_username"),
|
||||
database_password => $cfg->param ("database_password"),
|
||||
database_name => $cfg->param ("database_name"),
|
||||
database_driver => $cfg->param ("database_driver"),
|
||||
database_prefix => $cfg->param ("database_prefix")
|
||||
};
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
sub open_database
|
||||
{
|
||||
my ($cfg) = @_;
|
||||
|
||||
my $dbtype = $cfg->{database_driver};
|
||||
my $dbname = $cfg->{database_name};
|
||||
my $dbhost = $cfg->{database_hostname};
|
||||
my $dbport = $cfg->{database_port};
|
||||
|
||||
if ($dbtype eq 'postgre') { $dbtype = 'Pg'; }
|
||||
elsif ($dbtype eq 'oci8') { $dbtype = 'Oracle'; }
|
||||
elsif ($dbtype eq 'mysqli') { $dbtype = 'mysql'; }
|
||||
elsif ($dbtype eq 'sqlite') { $dbtype = 'SQLite'; }
|
||||
|
||||
my $dbstr;
|
||||
my $dbuser;
|
||||
my $dbpass;
|
||||
if ($dbtype eq 'Oracle')
|
||||
{
|
||||
$QC = '"';
|
||||
$dbstr = "DBI:$dbtype:";
|
||||
$dbuser = $cfg->{database_username} . '/' . $cfg->{database_password} . '@' . $dbhost;
|
||||
$dbpass = '';
|
||||
}
|
||||
elsif ($dbtype eq 'SQLite')
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbhost;";
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbstr = "DBI:$dbtype:database=$dbname;";
|
||||
if (length($dbhost) > 0) { $dbstr .= "host=$dbhost;"; }
|
||||
if (length($dbport) > 0) { $dbstr .= "port=$dbport;"; }
|
||||
|
||||
$dbuser = $cfg->{database_username};
|
||||
$dbpass = $cfg->{database_password};
|
||||
}
|
||||
|
||||
my $dbh = DBI->connect(
|
||||
$dbstr, $dbuser, $dbpass,
|
||||
{ RaiseError => 0, PrintError => 0, AutoCommit => 0 }
|
||||
);
|
||||
|
||||
return $dbh;
|
||||
}
|
||||
|
||||
sub close_database
|
||||
{
|
||||
my ($dbh) = @_;
|
||||
$dbh->disconnect ();
|
||||
}
|
||||
|
||||
sub is_project_member
|
||||
{
|
||||
my ($dbh, $prefix, $projectid, $userid) = @_;
|
||||
|
||||
my $query = $dbh->prepare ("SELECT ${QC}projectid${QC} FROM ${QC}${prefix}project_membership${QC} WHERE ${QC}userid${QC}=? AND ${QC}projectid${QC}=?");
|
||||
if (!$query || !$query->execute ($userid, $projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0)? 1: 0), undef);
|
||||
}
|
||||
|
||||
sub is_project_commitable
|
||||
{
|
||||
my ($dbh, $prefix, $projectid) = @_;
|
||||
|
||||
my $query = $dbh->prepare ("SELECT ${QC}commitable${QC} FROM ${QC}${prefix}project${QC} WHERE ${QC}id${QC}=?");
|
||||
if (!$query || !$query->execute ($projectid))
|
||||
{
|
||||
return (-1, $dbh->errstr());
|
||||
}
|
||||
|
||||
my @row = $query->fetchrow_array;
|
||||
$query->finish ();
|
||||
return (((scalar(@row) > 0 && $row[0] eq 'Y')? 1: 0), undef);
|
||||
}
|
||||
|
||||
#------------------------------------------------------------
|
||||
# MAIN
|
||||
#------------------------------------------------------------
|
||||
|
||||
my $cfg = get_config ();
|
||||
if (!defined($cfg))
|
||||
{
|
||||
print (STDERR "Cannot load codepot configuration file\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my $dbh = open_database ($cfg);
|
||||
if (!defined($dbh))
|
||||
{
|
||||
printf (STDERR "Cannot open database - %s\n", $DBI::errstr);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
my $member;
|
||||
my $commitable;
|
||||
my $errstr;
|
||||
|
||||
($member, $errstr) = is_project_member (
|
||||
$dbh, $cfg->{database_prefix}, $REPOBASE, $USER);
|
||||
if ($member <= -1)
|
||||
{
|
||||
print (STDERR "Cannot check membership - $errstr\n");
|
||||
close_database ($dbh);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
($commitable, $errstr) = is_project_commitable (
|
||||
$dbh, $cfg->{database_prefix}, $REPOBASE);
|
||||
if ($commitable <= -1)
|
||||
{
|
||||
print (STDERR "Cannot check commitability - $errstr\n");
|
||||
close_database ($dbh);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
close_database ($dbh);
|
||||
|
||||
if ($member == 0)
|
||||
{
|
||||
print (STDERR "$USER doesn't belong to the $REPOBASE project\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if ($commitable == 0)
|
||||
{
|
||||
print (STDERR "The $REPOBASE project is not commitable\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
exit (0);
|
Reference in New Issue
Block a user