summaryrefslogtreecommitdiff
path: root/usr/local/sbin/newrepo
blob: 7988117a4fa055e3c985969978c07dac048743c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/perl

use strict;
use warnings;

my( $errorto ) = 'jrayhawk+piny.svcs.cs.pdx.edu@omgwallhack.org'; # Email address to send horrible errors to.
my( $reponame, $email, @errors, $wikilisttempfile, $cgitrctempfile);

if ( ( ! scalar $ARGV[0] ) or ( scalar $ARGV[1] ) or ( $ARGV[0] !~ /^[a-z0-9][a-z0-9+.-]+$/ ) ) {
  print( "Usage: newrepo REPONAME\n" );
  print( "  REPONAME must consist only of lower case letters (a-z), digits (0-9), plus (+) and minus (-) signs, and periods (.).\n" );
  print( "  REPONAME must be at least two characters long and must start with an alphanumeric character.\n" );
  exit( 1 );
} else {
  $reponame = $ARGV[0];
};

# We want to check to see if
#   1) $reponame already exists in some form so we don't try to create it, and
#   2) $reponame is only partially created, in which case we want to email someone who can sanity check and fix it.
open (PASSWD, '/etc/passwd');
while(<PASSWD>) {
  if( $_ =~ /^$ENV{SUDO_USER}:.+?:.+?:.+?:(.+?):/ ) { $email = $1; }; # While we're here, may as well grab the email address.
  if( $_ =~ /^ikiwiki-$reponame:/				) { push( @errors, "user ikiwiki-$reponame already exists!\n"); };
};
close(PASSWD);
open (GROUP, '/etc/group');
while(<GROUP>) {
  if( $_ =~ /^git-$reponame:/					) { push( @errors, "group git-$reponame already exists!\n"); };
};
close(GROUP);
if( -d "/srv/git/$reponame.git"					) { push( @errors, "/srv/git/$reponame.git already exists!\n"); };
if( -d "/srv/ikiwiki/$reponame"					) { push( @errors, "/srv/ikiwiki/$reponame already exists!\n"); };
if( -d "/srv/www/piny.svcs.cs.pdx.edu/$reponame"		) { push( @errors, "/srv/www/piny.svcs.cs.pdx.edu/$reponame already exists!\n"); };
if( -d "/srv/www/cgi.piny.svcs.cs.pdx.edu/repos/$reponame"	) { push( @errors, "/srv/www/cgi.piny.svcs.cs.pdx.edu/repos/$reponame already exists!\n"); };
if( -f "/etc/ikiwiki/piny/$reponame.setup"			) { push( @errors, "/etc/ikiwiki/piny/$reponame.setup already exists!\n"); };
if( -f "/etc/ikiwiki/wikilist.d/$reponame"			) { push( @errors, "/etc/ikiwiki/wikilist.d/$reponame already exists!\n"); };
if( -f "/etc/apache2/piny-available/$reponame"			) { push( @errors, "/etc/apache2/piny-available/$reponame already exists!\n"); };
if( -f "/etc/cgitrc.d/$reponame"			        ) { push( @errors, "/etc/cgitrc.d/$reponame already exists!\n"); };

if( @errors ) {
  if( @errors == 10 ) { # Everything's fine, nothing is broken
    print( "$reponame already exists!\n" );
  } else {              # IT'S ARMAGEDDON
    open ( MAIL, "|/usr/lib/sendmail -t" );
    print( MAIL "To: $errorto\n" );
    print( MAIL "From: newrepo\@piny.svcs.cs.pdx.edu\n" );
    print( MAIL "Subject: Piny error: $ENV{SUDO_USER} found inconsistent $reponame in the creation process!\n" );
    print( MAIL "MIME-Version: 1.0\n" );
    print( MAIL "Content-Type: text/plain; charset=us-ascii\n" );
    print( MAIL "\n" );
    print( MAIL "@errors\n" );
    close( MAIL );
    print( "$reponame already exists but is in an inconsistent state! The Piny admins probably screwed up; they have been notified and will take a look at it.\n" );
  };
  exit( 2 );
};


# CREATE USER/GROUPS
unless( system( "mkdir /srv/git/$reponame.git" ) == 0 ) { # We need a locking or atomic operation as our first to check against simultaneous execution.
  print( "I suspect that you are attempting to create the same repo multiple times simultaneously.\n" );
  exit( 3 );
};
system( "/usr/sbin/addgroup --quiet git-$reponame" );
system( "/usr/sbin/adduser --quiet --system --group --gecos $reponame ikiwiki-$reponame" );
system( "/usr/sbin/adduser --quiet ikiwiki-$reponame git-$reponame | grep -v 'Adding user'" );
system( "/usr/sbin/adduser --quiet $ENV{SUDO_USER} git-$reponame | grep -v 'Adding user '" );

# CREATE REPO
system( "GIT_DIR=/srv/git/$reponame.git /usr/bin/git init --template=/srv/git-template.git --quiet --shared" );
open ( DESC, ">/srv/git/$reponame.git/description" );
print( DESC "$reponame owned by $email" );
close( DESC );
# ln -f post-receive /srv/git/$reponame.git/hooks/ # turn on e-mail commit notices
system( "/bin/chown -R $ENV{SUDO_USER}.git-$reponame /srv/git/$reponame.git/" );
system( "/bin/chown -R ikiwiki-$reponame.ikiwiki-$reponame /srv/git/$reponame.git/hooks/" );
system( "/bin/touch /srv/git/$reponame.git/git-daemon-export-ok" );

# WRITE IKIWIKI SETUP FILE
open ( SETUP, ">/etc/ikiwiki/piny/$reponame.setup" );
print( SETUP
'#!/usr/bin/perl
# Configuration file for ikiwiki.
# Passing this to ikiwiki --setup will make ikiwiki generate wrappers and
# build the wiki.
#
# Remember to re-run ikiwiki --setup any time you edit this file.

use IkiWiki::Setup::Standard {
	wikiname => \'' . $reponame . '\', # PINY
	adminemail => \'' . $email . '\', # PINY
	srcdir => \'/srv/ikiwiki/' . $reponame . '\', # PINY
	destdir => \'/srv/www/piny.svcs.cs.pdx.edu/' . $reponame . '\', # PINY
	url => \'http://piny.svcs.cs.pdx.edu/' . $reponame . '\', # PINY
	cgiurl => \'https://cgi.piny.svcs.cs.pdx.edu/repos/' . $reponame . '/ikiwiki.cgi\', # PINY
	historyurl => \'https://cgi.piny.svcs.cs.pdx.edu/gitweb.cgi?p=' . $reponame . '.git;a=history;f=[[file]]\', # PINY
        diffurl => \'https://cgi.piny.svcs.cs.pdx.edu/gitweb.cgi?p=' . $reponame . ';a=blobdiff;f=doc/[[file]];h=[[sha1_to]];hp=[[sha1_from]];hb=[[sha1_commit]];hpb=[[sha1_parent]]\', # PINY

	templatedir => "/srv/templates",
	underlaydir => "/etc/ikiwiki/share/underlay",

	rcs => "git",
	gitorigin_branch => "origin",
	gitmaster_branch => "master",

	wrappers => [
		{
			cgi => 1,
			wrapper => \'/srv/www/cgi.piny.svcs.cs.pdx.edu/repos/' . $reponame . '/ikiwiki.cgi\', # PINY
			wrappermode => "06755",
                        wrappergroup => \'git-' . $reponame . '\', # PINY
		},
		{
			wrapper => \'/srv/git/' . $reponame . '.git/hooks/post-update\', # PINY
			wrappermode => "06755",
                        wrappergroup => \'git-' . $reponame . '\', # PINY

			notify => 0,
		},
	],

	# Generate rss feeds for blogs?
	rss => 1,
	# Generate atom feeds for blogs?
	atom => 0,
	# Include discussion links on all pages?
	discussion => 0,
	# To exclude files matching a regexp from processing. This adds to
	# the default exclude list.
	#exclude => qr/*\.wav/,
	# To change the extension used for generated html files.
	#htmlext => "htm",
	# Time format (for strftime)
	#timeformat => "%c",
	# Locale to use. Must be a UTF-8 locale.
	#locale => "en_US.UTF-8",
	# Only send cookies over SSL connections.
	sslcookie => 1,
	# Logging settings:
	verbose => 0,
	syslog => 1,
	# To link to user pages in a subdirectory of the wiki.
	#userdir => "users",
	# To create output files named page.html rather than page/index.html.
	usedirs => 1,
	# Simple spam prevention: require an account-creation password.
	#account_creation_password => "example",
	# Use new "!"-prefixed preprocessor directive syntax
	prefix_directives => 1,
	httpauth => 1,
	# To add plugins, list them here.
	add_plugins => [qw{sidebar toc meta table tag httpauth attachment rename remove autoindex map teximg version edittemplate}],
	disable_plugins => [qw{openid passwordauth}],
	teximg_prefix => \'\\documentclass{scrartcl}
\\usepackage[version=3]{mhchem}
\\usepackage{amsmath}
\\usepackage{amsfonts}
\\usepackage{amssymb}
\\pagestyle{empty}
\\newcommand{\unit}[1]{\\ensuremath{\\, \\mathrm{#1}}}
\\begin{document}\',

	teximg_dvipng => 1,

	# For use with the tag plugin, make all tags be located under a
	# base page.
	tagbase => "tag",

	# For use with the search plugin if your estseek.cgi is located
	# somewhere else.
	#estseek => "/usr/lib/estraier/estseek.cgi",
}');
close( SETUP );
open ( WIKILIST, '>>/etc/ikiwiki/wikilist' );
print( WIKILIST "ikiwiki-$reponame /etc/ikiwiki/piny/$reponame.setup\n" );
close( WIKILIST );

# WRITE APACHE CONFIG
open ( APACHE, ">/etc/apache2/piny-available/$reponame" );
print( APACHE '<Directory /srv/www/cgi.piny.svcs.cs.pdx.edu/repos/' . $reponame . '>
	AuthPAM_Enabled on
	AuthGROUP_Enabled on
	AuthPAM_FallThrough off
	AuthBasicAuthoritative off
	AuthType Basic
	AuthName "User access to ' . $reponame . ' repository needed."
	Require group git-' . $reponame . '
</Directory>' );
close( APACHE );
link( "/etc/apache2/piny-available/$reponame", "/etc/apache2/piny-enabled/$reponame");
system( '/etc/init.d/apache2 reload | grep -v "Reloading web server config: apache2."' );


# CREATE IKIWIKI WORKING DIR
system( "/usr/bin/git clone --quiet /srv/git/$reponame /srv/ikiwiki/$reponame" );
mkdir( "/srv/www/piny.svcs.cs.pdx.edu/$reponame" );
mkdir( "/srv/www/cgi.piny.svcs.cs.pdx.edu/repos/$reponame" );
system( "/bin/chown -R ikiwiki-$reponame /srv/ikiwiki/$reponame /srv/www/piny.svcs.cs.pdx.edu/$reponame /srv/www/cgi.piny.svcs.cs.pdx.edu/repos/$reponame" );

open ( WIKILIST, ">/etc/ikiwiki/wikilist.d/$reponame" ); # Maybe someday ikiwiki will support wikilist.d.
print( WIKILIST "ikiwiki-$reponame /etc/ikiwiki/piny/$reponame.setup\n" ); # In the meantime, we fake it.
close( WIKILIST );
$wikilisttempfile = `/bin/mktemp`;
chomp( $wikilisttempfile );
system( "/bin/cat /etc/ikiwiki/wikilist.d/* > $wikilisttempfile" );
chmod ( 0644, $wikilisttempfile );
system( "/bin/mv $wikilisttempfile /etc/ikiwiki/wikilist" ); # This is marginally racy, but the consequences are probably ignorable.

open ( CGITRC, ">/etc/cgitrc.d/$reponame" ); # Maybe someday cgit will support cgitrc.d.
print( CGITRC
"repo.url=$reponame
repo.path=/srv/git/$reponame.git
repo.desc=$reponame
repo.owner=$email

" ); # In the meantime, we fake it.
close( CGITRC );
$cgitrctempfile = `/bin/mktemp`;
chomp( $cgitrctempfile );
system( "/bin/cat /etc/cgitrc.d/* > $cgitrctempfile" );
chmod ( 0644, $cgitrctempfile );
system( "/bin/mv $cgitrctempfile /etc/cgitrepos" ); # This is marginally racy, but the consequences are minor.

# COMPILE
system( "/usr/bin/sudo -u ikiwiki-$reponame /usr/bin/ikiwiki --setup /etc/ikiwiki/piny/$reponame.setup | grep -v 'successfully generated'" );