382 lines
11 KiB
Perl
Executable file
382 lines
11 KiB
Perl
Executable file
#!/usr/bin/perl -w
|
|
#
|
|
# Clone a new sysadmin package from this one.
|
|
#
|
|
|
|
use strict;
|
|
use Getopt::Long qw(:config permute); # allow mixed args.
|
|
use POSIX;
|
|
use File::Copy;
|
|
use FindBin qw($Bin);
|
|
BEGIN{ chdir("$Bin/..") }
|
|
|
|
# You may need libterm-readline-gnu-perl to be installed
|
|
use Term::ReadLine;
|
|
|
|
my $debug = 0;
|
|
my $helpmeplease = 0;
|
|
|
|
GetOptions ('debug!' => \$debug,
|
|
'help' => \$helpmeplease
|
|
);
|
|
|
|
show_usage() if ( $helpmeplease );
|
|
|
|
my $term = new Term::ReadLine 'clone-new-sysadmin';
|
|
if(not exists $INC{'Term/ReadLine/Gnu.pm'}) {
|
|
warn "You may wish to use Ctrl-C to interrupt this program and run the\n"
|
|
. "following command:\n\n\n"
|
|
. " apt-get install libterm-readline-gnu-perl\n\n";
|
|
}
|
|
my $diffs = `git diff-index HEAD 2>/dev/null`;
|
|
if ($? != 0) {
|
|
die "You need git-core installed to use this program.\n\n"
|
|
. "run:\n\n"
|
|
. " apt-get install git-core\n\n";
|
|
} elsif ($diffs) {
|
|
warn "Your checkout has uncommitted changes. These will be bundled\n"
|
|
."into the first commit of your branch.\n";
|
|
}
|
|
|
|
my ( $package_name, $organisation, $new_name, $full_name,
|
|
$user_names, $uid, $gid, $gecos, $junk, $email );
|
|
|
|
# Get the current package name
|
|
my @pwent = getpwuid($<);
|
|
$user_names = $pwent[0];
|
|
$uid = $pwent[2];
|
|
$gid = $pwent[3];
|
|
$gecos = $pwent[4];
|
|
( $full_name, $junk ) = split ",", $gecos ;
|
|
|
|
# Attempt to avoid UID/GID collisions
|
|
$uid = 2500 + int(rand(1500)) if ( $uid <= 1000 );
|
|
$gid = $uid if ( $gid <= 1000 );
|
|
|
|
my @components = split '/', POSIX::getcwd() ;
|
|
$package_name = pop @components;
|
|
$organisation = $package_name;
|
|
$organisation =~ s/-.*$// ;
|
|
$organisation = $term->readline( "Enter the name of the Organisation: ", $organisation );
|
|
|
|
$junk = $full_name;
|
|
$full_name = $term->readline( "Enter the full name of the target sysadmin: ", $full_name );
|
|
if ( $junk ne $full_name ) {
|
|
# Ok, they edited it. Let's try and invent a user name list
|
|
my @name_parts = split /\s+/, lc($full_name) ;
|
|
my $first = $name_parts[0];
|
|
my $last = $name_parts[-1];
|
|
my $initials = "";
|
|
foreach( @name_parts ) {
|
|
$initials .= substr($_, 0,1);
|
|
}
|
|
$user_names = "$first $first".substr($last,0,1)." $initials ".substr($first,0,1)."$last $first.$last ";
|
|
}
|
|
|
|
$new_name = lc( "$organisation-$full_name" );
|
|
$new_name =~ s/\s+\S+.*\s+//;
|
|
$new_name =~ s/ //g;
|
|
print <<EOT ;
|
|
|
|
|
|
The new name should be of the form "organisation-firstnamelastname"
|
|
so that people don't need to be told the name of the package, and
|
|
so we can easily see them grouped in the installed packages listing.
|
|
|
|
EOT
|
|
|
|
$new_name = $term->readline( "Enter the new name for the target package: ", $new_name );
|
|
$user_names = $term->readline( "Preferred usernames (space delimited): ", $user_names );
|
|
$uid = $term->readline( "Preferred UID: ", $uid );
|
|
$gid = $term->readline( "Preferred GID: ", $gid );
|
|
|
|
print <<EOT ;
|
|
|
|
This package can set a shell password (which in turn is used by sudo)
|
|
but requires a GPG key to encrypt to. The email address you provide
|
|
below will be used to locate a suitable public key in the current
|
|
user's keyring. It *can* also be used as the target of an encrypted
|
|
email.
|
|
|
|
The public key you specify here must be available in your default keyring
|
|
(specifically of the user executing this script).
|
|
|
|
Specify "none" to disable password generation and notification.
|
|
|
|
EOT
|
|
|
|
my $default_email = $organisation eq 'positiveinternet'
|
|
? $user_names . '@positive-internet.com'
|
|
: '';
|
|
$default_email =~ s{ (?:.* )?}{}; # remove alternate usernames
|
|
|
|
$email = $term->readline( "Email address to notify/encrypt to: ", $default_email );
|
|
|
|
$email ||= 'none';
|
|
|
|
my $suppress_email_notify = '';
|
|
|
|
if($email ne 'none') {
|
|
print <<EOT ;
|
|
|
|
Do you want an (encrypted) email notification whenever your package is
|
|
installed (if you answer 'no', an encrypted notification will still be
|
|
saved in your home directory but no email will be generated)?
|
|
|
|
EOT
|
|
|
|
my $want_email = $term->readline( "Always send password by email (y/N)? ", 'N');
|
|
if($want_email and $want_email =~ /^y/i) {
|
|
$suppress_email_notify = 'N';
|
|
}
|
|
}
|
|
|
|
printf( "Cloning from %s to %s for %s\n", $package_name, $new_name, $full_name );
|
|
print <<EOTXT ;
|
|
Attempting usernames: $user_names
|
|
Preferred UID/GID: $uid / $gid
|
|
EOTXT
|
|
|
|
|
|
my @exclude_files = (
|
|
'build',
|
|
'.git$',
|
|
'faces/',
|
|
'ssh-keys/(?!.placeholder)',
|
|
'gpg-keys/',
|
|
'preferred_fullname',
|
|
'preferred_names',
|
|
'preferred_uid',
|
|
'preferred_gid',
|
|
'notification_email',
|
|
'suppress_email_notify',
|
|
"debian\\/$package_name\\.",
|
|
'debian\\/tmp$',
|
|
'debian\\/files$',
|
|
'.*~',
|
|
);
|
|
|
|
# If we have a 'preferred_uid' file we won't copy skel
|
|
if ( -f 'preferred_uid' ) {
|
|
push @exclude_files, 'skel/';
|
|
}
|
|
|
|
############################################################
|
|
# copy_files
|
|
############################################################
|
|
my ($url) = map { m{URL: (.*)} ? ($1) : () } `git remote show origin`;
|
|
|
|
$url =~ s|http://(.*?)/|git+ssh://$1/git/private/|;
|
|
|
|
chdir '..';
|
|
system("git", "clone", "--bare", "-l", $package_name, "$new_name/.git") == 0
|
|
or die "git clone failed; rc=$?";
|
|
{
|
|
local($ENV{GIT_DIR})="$new_name/.git";
|
|
my $branch_name = "refs/heads/$new_name";
|
|
system("git", "update-ref", $branch_name, "HEAD");
|
|
system("git", "symbolic-ref", "HEAD", $branch_name);
|
|
system("git", "read-tree", "HEAD");
|
|
system("git", "config", "core.bare", 'false');
|
|
if ( $url ) {
|
|
(system("git", "remote", "add", "origin", $url) == 0)
|
|
or warn "upgrade your git to 1.5+\n";
|
|
system("git", "config", "remote.origin.fetch",
|
|
"+refs/heads/master:refs/heads/origin/master");
|
|
system("git", "config", "remote.origin.push",
|
|
"+$branch_name:$branch_name");
|
|
}
|
|
copy_files_carefully( $package_name, $new_name );
|
|
chdir $new_name;
|
|
}
|
|
|
|
|
|
############################################################
|
|
# customise_files
|
|
############################################################
|
|
my @files = ( 'changelog', 'control', 'README.debian',
|
|
'rules', 'templates', 'config',
|
|
'sysadmin.postinst', 'sysadmin.postrm',
|
|
'.gitignore'
|
|
);
|
|
foreach my $fn ( @files ) {
|
|
print "Customising $fn\n";
|
|
rename "debian/$fn", "debian/$fn.cloned";
|
|
open( OLD, "<", "debian/$fn.cloned" );
|
|
open( NEW, ">", "debian/$fn" );
|
|
while( <OLD> ) {
|
|
s/positiveinternet-userpackage/$new_name/;
|
|
s/$package_name/$new_name/;
|
|
s/__FULL_NAME__/$full_name/g;
|
|
print NEW $_;
|
|
}
|
|
close(NEW);
|
|
close(OLD);
|
|
unlink "debian/$fn.cloned";
|
|
}
|
|
|
|
############################################################
|
|
# dig out gpg key to use
|
|
############################################################
|
|
|
|
# For this, we need to run gpg and extract the public key
|
|
# then re-import it into a new keyring we put into the
|
|
# package. Hackish, but it'll do.
|
|
|
|
if ($email ne "none") {
|
|
system("gpg --export $email > notifyring.gpg");
|
|
if(-s 'notifyring.gpg' == 0) {
|
|
die "\nError: There is no key matching '$email' in yor GnuPG keyring\n"
|
|
. "Package not created.\n";
|
|
}
|
|
} else {
|
|
system("touch notifyring.gpg");
|
|
}
|
|
|
|
############################################################
|
|
# write_preferences
|
|
############################################################
|
|
write_preference( 'preferred_fullname', $full_name );
|
|
write_preference( 'preferred_names', $user_names );
|
|
write_preference( 'preferred_uid', $uid );
|
|
write_preference( 'preferred_gid', $gid );
|
|
write_preference( 'notification_email', $email );
|
|
write_preference( 'suppress_email_notify', $suppress_email_notify );
|
|
|
|
# Ensure appropriate things are marked executable
|
|
chmod 0755, 'debian/rules';
|
|
chmod 0755, 'bin/clone-new-sysadmin';
|
|
|
|
for my $dir ('ssh-keys', 'gpg-keys', 'skel') {
|
|
mkdir $dir unless -d $dir;
|
|
}
|
|
|
|
# check into git
|
|
my @rms = map { chomp; $_ }
|
|
`git diff-index --name-only --diff-filter=D HEAD`;
|
|
system("git", "add", ".");
|
|
system("git", "rm", @rms) if @rms;
|
|
system("git", "commit", "-m", "Cloned package for $full_name using $0");
|
|
|
|
############################################################
|
|
# We're done...
|
|
############################################################
|
|
my $newdir = join( '/', @components) . "/$new_name";
|
|
print <<EOTXT ;
|
|
|
|
OK, the new package framework has been created in:
|
|
|
|
$newdir
|
|
|
|
What you will need to do now, is to copy any keys into the
|
|
ssh-keys subdirectory and any gpg keys into the gpg-keys
|
|
subdirectory. After that you can make any other modifications
|
|
you would like. For a basic starting point it is probably
|
|
sufficient to:
|
|
|
|
cd $newdir
|
|
cp ~/.ssh/id*.pub ssh-keys
|
|
make
|
|
|
|
To create a new version of the package, use "debchange -i" to
|
|
increment the revision number, and comment on what the change
|
|
is that is being made.
|
|
|
|
EOTXT
|
|
|
|
exit 0;
|
|
|
|
|
|
############################################################
|
|
# ONLY SUBROUTINES BELOW HERE
|
|
############################################################
|
|
|
|
|
|
############################################################
|
|
# customise_files - customises a set of files
|
|
# Files/lines to be changed
|
|
# debian/changelog
|
|
# debian/control
|
|
# debian/README.debian
|
|
# debian/rules
|
|
############################################################
|
|
|
|
sub write_preference {
|
|
my $filename = shift;
|
|
my $preference = shift;
|
|
|
|
open( PREF, ">", $filename );
|
|
print PREF $preference;
|
|
close(PREF);
|
|
}
|
|
|
|
############################################################
|
|
# Copy a tree of files carefully
|
|
############################################################
|
|
sub copy_files_carefully {
|
|
my $source = shift;
|
|
my $dest = shift;
|
|
|
|
return if (!defined($dest) || !defined($source) );
|
|
|
|
if ( ! -e $dest ) {
|
|
mkdir $dest;
|
|
}
|
|
print "Copying files in $source\n";
|
|
opendir( SDIR, $source ) or die("Can't open source directory: $!");
|
|
my @files = readdir(SDIR);
|
|
closedir( SDIR );
|
|
|
|
foreach my $fn ( @files ) {
|
|
next if ( $fn eq '.' || $fn eq '..' );
|
|
next if ( exclude_from_copy("$source/$fn") );
|
|
if ( -d "$source/$fn" ) {
|
|
# Recurse to copy the subdirectory
|
|
copy_files_carefully( "$source/$fn", "$dest/$fn" );
|
|
}
|
|
else {
|
|
print "Copying from $source/$fn to $dest/$fn\n" if ( $debug );
|
|
copy( "$source/$fn", "$dest/$fn" );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
############################################################
|
|
# Decide whether this file should be exluded from the copy
|
|
############################################################
|
|
sub exclude_from_copy {
|
|
my $fn = shift;
|
|
|
|
foreach( @exclude_files ) {
|
|
if ( $fn =~ /^$package_name\/$_/ ) {
|
|
print "Excluding $fn\n" if ( $debug );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
# No match, so it must be OK then :-)
|
|
return 0;
|
|
}
|
|
|
|
############################################################
|
|
# Tell the nice user how we do things. Short and sweet.
|
|
############################################################
|
|
sub show_usage {
|
|
print <<OPTHELP;
|
|
|
|
bin/clone-new-sysadmin
|
|
|
|
There are no options - all variables are prompted for.
|
|
|
|
bin/clone-new-sysadmin will clone this package to a new sysadmin
|
|
package, prompting for important information and telling you what
|
|
to do next. It needs to be run from the base source directory
|
|
of an existing package.
|
|
|
|
OPTHELP
|
|
exit 0;
|
|
}
|
|
|
|
|