source: projects/casparbuster/devel/bin/cbusterize @ 1510

Last change on this file since 1510 was 1510, checked in by bruno, 7 years ago
  • Add build for Ubuntu 12.04 (dual archs) VMs
  • Property svn:executable set to *
File size: 9.8 KB
Line 
1#!/usr/bin/perl -w
2#
3=head1 NAME
4
5cbusterize - Creates the correct CasparBuster structure in your CMS environment
6
7=head1 SYNOPSIS
8
9cbusterize [options] --source /path/to/file/to/CasparBusterize
10
11 Options:
12   --debug  |-d         debug mode
13   --help   |-h         brief help message
14   --man            full documentation
15   --force   |-f            force copy of files, even if they exist
16   --source |-s <file/dir>  directory or files to copy in the CasparBuster tree (',' separated if many)
17   --plugin |-p <plugin name>   plugin defining what to copy in the CasparBuster tree (',' separated if many)
18   --machine|-m <machine>   machine to consider in the subtree
19
20=head1 OPTIONS
21
22=over 4
23
24=item B<--debug>
25
26Enter debug mode. This will print what would be done. No commands are executed,
27so this is safe to use when testing.
28
29=item B<--help>
30
31Print a brief help message and exits.
32
33=item B<--man>
34
35Prints the manual page and exits.
36
37=item B<--machine> I<machine name>
38
39Specify the machine to consider when dealing with the CasparBuster structure.
40The file will be taken from this machine, and a subdirectory named after the machine
41will be used under the basedir to host the directory structure to manage
42
43=item B<--source> I<path>
44
45Specify the path to the source file or directory to manage with CasparBuster. Multiple paths can be specified separated by ','.
46
47=item B<--plugin> I<name>
48
49Specify the name of the plugin to manage with CasparBuster. Multiple plugins can be specified separated by ','.
50A plugin defines a set of files (with their mode and owner), a set of directories (with their mode and owner) and a set of scripts to launch once the files are copied remotely.
51
52=back
53
54=head1 DESCRIPTION
55
56Creates a directory under the machine dir passed as parameter in working
57directory or directory passed as parameter named like the last path
58element of the parameter, and creates the standard CasparBuster setup
59that refers to the parameter path in the new directory, and configuration
60files when possible. It also copies the original config file into the new dir.
61Is reasonably picky about path names, tries to avoid common errors.
62
63Schema looks like:
64
65Base dir
66   |
67   |- machine1 (optional)
68   |     |
69   |     |-- conf dir1
70   |     |       |
71   |     |       |- conf file 1
72   |   [...]    [...]
73   |
74   |- machine2 (optional)
75   |     |
76   |     |-- conf dir2
77   |     |       |
78   |     |       |- conf file 2
79   |   [...]    [...]
80
81Use of machines require use of option -m (if using cbusemachines in cb.conf)
82If not, the conf dirs are directly attached to the base dir
83
84=head1 EXAMPLES
85
86    # this will create the appropriate CasparBuster environment
87    # under the base ~/prj/musique-ancienne.org directory (Cf cbbasedir in cb.conf)
88    # containing the directory victoria2 for this machine
89    # under which it will copy the required structure if needed (/etc/ssh)
90    # to finaly put a copy of the file sshd_conf in it from the victoria2 machine
91
92    cbusterize -m victoria2 -s /etc/ssh/sshd_config
93
94=head1 AUTHOR
95
96=over 4
97
98Bruno Cornec, http://brunocornec.wordpress.com
99
100=back
101
102=head1 LICENSE
103
104Copyright (C) 2012  Bruno Cornec <bruno@project-builder.org>
105Released under the GPLv2 or the Artistic license at your will.
106
107=cut
108use strict;
109use CasparBuster::Version;
110use CasparBuster::Env;
111use CasparBuster::Plugin;
112use File::Basename;
113use File::Path;
114use Getopt::Long;
115use Pod::Usage;
116use Data::Dumper;
117use Net::SSH2;
118use ProjectBuilder::Base;
119use ProjectBuilder::Conf;
120use ProjectBuilder::VCS;
121
122# settings
123my $debug = 0;
124my $help = undef;
125my $man = undef;
126my $source = undef;
127my $machine = undef;
128my $plugin = undef;
129my $quiet = undef;
130my $force = undef;
131my $log = undef;
132my $LOG = undef;
133
134my ($cbver,$cbrev) = cb_version_init();
135my $appname = "cb";
136$ENV{'PBPROJ'} = $appname;
137pb_temp_init();
138
139# Initialize the syntax string
140pb_syntax_init("$appname (aka CasparBuster) Version $cbver-$cbrev\n");
141
142# parse command-line options
143GetOptions(
144    'machine|m=s' => \$machine,
145    'debug|d+'    => \$debug,
146    'help|h'      => \$help,
147    'quiet|q'     => \$quiet,
148    'force|f'     => \$force,
149    'man'         => \$man,
150    'logfile|l=s' => \$log,
151    'source|s=s'  => \$source,
152    'plugin|p=s'  => \$plugin,
153) || pb_syntax(-1,0);
154
155if (defined $help) {
156    pb_syntax(0,1);
157}
158if (defined $man) {
159    pb_syntax(0,2);
160}
161if (defined $quiet) {
162    $debug=-1;
163}
164if (defined $log) {
165    open(LOG,"> $log") || die "Unable to log to $log: $!";
166    $LOG = \*LOG;
167    $debug = 0  if ($debug == -1);
168}
169
170$pbdebug = $debug;
171pb_log_init($debug, $LOG);
172pb_log(0,"Starting cbusterize\n");
173
174# Get conf file in context
175pb_conf_init($appname);
176# The personal one if there is such
177pb_conf_add("$ENV{'HOME'}/.cbrc") if (-f "$ENV{'HOME'}/.cbrc");
178# The system one
179pb_conf_add(cb_env_conffile());
180
181# Get configuration parameters
182my %cb;
183my $cb = \%cb;
184($cb->{'basedir'},$cb->{'usemachines'},$cb->{'cms'}) = pb_conf_get("cbbasedir","cbusemachines","cbcms");
185pb_log(2,"%cb: ",Dumper($cb));
186
187# Check for mandatory params
188pod2usage("Error: --source or --plugin is a mandatory argument\n") if ((not defined $source) && (not defined $plugin));
189pod2usage("Error: --machine is a mandatory argument when configure with cbusemachines = true\n") if (($cb->{'usemachines'}->{$appname} =~ /true/) && (not defined $machine));
190
191if (defined $plugin) {
192    # Load plugins
193    cb_plugin_load();
194}
195
196my $basedir = $cb->{'basedir'}->{$appname};
197eval { $basedir =~ s/(\$ENV.+\})/$1/eeg };
198
199pb_log(1, "DEBUG MODE, not doing anything, just printing\nDEBUG: basedir = $basedir\n");
200pb_log(1, "DEBUG: source = $source\n") if (defined $source);
201pb_log(1, "DEBUG: machine = $machine\n") if (defined $machine);
202
203# Use potentially a remote account if defined
204my $account = undef;
205my $remote = undef;
206($account) = pb_conf_get_if("cbaccount") if (defined $machine);
207$remote = $account->{$machine} if ((defined $account) && (defined $machine) && (defined $account->{$machine}));
208pb_log(1, "DEBUG: remote account1 = $remote\n") if (defined $remote);
209$remote = getpwuid($<) if (not defined $remote);
210pb_log(1, "DEBUG: remote account2 = $remote\n");
211
212# Create basedir if it doesn't exist
213if (not -d $basedir) {
214    if ($debug) {
215        pb_log(1, "DEBUG: Creating recursively directory $basedir\n");
216    } else {
217        pb_mkdir_p($basedir) || die "Unable to recursively create $basedir: $!";
218    }
219}
220
221if (defined $source) {
222    foreach my $f (split(/,/,$source)) {   
223        cb_busterize($f,"true");
224    }
225}
226
227# Now handle plugins if any
228my $cbp = ();
229
230if (defined $plugin) {
231    foreach my $p (split(/,/,$plugin)) {   
232        pb_log(1,"Getting context for plugin $p\n");
233        $cbp = cb_plugin_get($p,$cbp);
234        pb_log(2,"cbp: ".Dumper($cbp)."\n");
235        foreach my $k (keys %{$cbp->{$plugin}->{'dirsandfiles'}}) {
236            cb_busterize($k,"true");
237        }
238        foreach my $k ((keys %{$cbp->{$plugin}->{'dirs'}}),(keys %{$cbp->{$plugin}->{'files'}})) {
239            cb_busterize($k,"false");
240        }
241    }
242}
243
244sub cb_busterize {
245
246my $source = shift;
247my $recur = shift;
248
249pb_log(2,"Entering cb_busterize source: $source\n");
250# Is the source a file or a dir ? Split the source parameter in 2
251my $srcdir = undef;
252my $srcfile = undef;
253my $cmd = undef;
254my $ssh2;
255my $sftp;
256
257if (not defined $machine) {
258    if (-d $source) {
259        $srcdir = $source;
260    } else {
261        $srcdir = dirname($source);
262        $srcfile = basename($source);
263    }
264} else {
265    $ssh2 = Net::SSH2->new();
266    $ssh2->connect($machine);
267    my $hdir = (getpwnam(getpwuid($<)))[7];
268    if ($ssh2->auth_publickey($remote,"$hdir/.ssh/id_dsa.pub","$hdir/.ssh/id_dsa")) {
269        $sftp = $ssh2->sftp;
270        my %dirs = $sftp->stat("$source/.");
271        my $res = 0;
272        $res = -1 if (not defined $dirs{'mode'});
273        pb_log(2,"DEBUG: Found res = $res\n");
274        if ($res == 0) {
275            $srcdir = $source;
276            pb_log(1,"DEBUG: Found remote dir = $source\n");
277        } else {
278            $srcdir = dirname($source);
279            $srcfile = basename($source);
280            pb_log(1,"DEBUG: Found remote file = $source\n");
281        }
282    }
283}
284
285pb_log(1,"DEBUG: Found srcdir = $srcdir\n");
286if (defined $srcfile) {
287    pb_log(1,"DEBUG: Found srcfile = $srcfile\n");
288} else {
289    pb_log(1,"DEBUG: Found no srcfile\n");
290}
291
292# Deduce the target directory from the local structure and the source
293my $target = $basedir;
294$target .= "/$machine" if defined ($machine);
295$target .= "$srcdir";
296
297my $scheme = $cb->{'cms'}->{$appname};
298
299# If both source and target are dirs, then copy into the parent of the target
300$target = basename($target) if ((not defined $srcfile) && (-d $target));
301
302# Create target if it doesn't exist
303if (not -d $target) {
304    if ($debug) {
305        pb_log(1,"DEBUG: Creating recursively directory $target\n");
306    } else {
307        pb_mkdir_p($target) || die "Unable to recursively create $target: $!";
308    }
309    # Add all the dirs in it to VCS (in reverse order)
310    my $tdir = $target;
311    my @tab = ();
312    while ($tdir ne $basedir) {
313        push(@tab,$tdir);
314        $tdir = dirname($tdir);
315        pb_log(3,"tdir is now $tdir\n");
316    }
317    if ($debug) {
318        pb_log(0,"INFO: Added to your $scheme system the dirs: ".join(' ',reverse(@tab))."\n");
319    } else {
320        pb_vcs_add($scheme,reverse(@tab));
321    }
322}
323
324# We need to know where to get the content from
325my $cmdopt = "";
326
327# Recursive if we copy dirs
328$cmdopt = "-r" if (not defined $srcfile);
329
330if (defined $machine) {
331    # TODO replace by $chan->exec + sudo + cat to avoid root access issues
332    $cmd = "scp -p -q $cmdopt $remote\@$machine:\'$source\' $target";
333} else {
334    $cmd = "cp -p $cmdopt $source $target";
335}
336
337# Now add content if not already there
338if (defined $srcfile) {
339    # File case
340    if ((! -f "$target/$srcfile") || (defined $force)) {
341        if ($debug) {
342            pb_log(1,"DEBUG: launching $cmd\n");
343        } else {
344            pb_system($cmd);
345            pb_vcs_add($scheme,"$target/$srcfile");
346            pb_log(0,"INFO: Created $target/$srcfile and added it to your $scheme system\n");
347        }
348    } else {
349        pb_log(0,"INFO: File $target/$srcfile already there\n");
350    }
351} else {
352    # Directory case
353    if ($debug) {
354        if ($recur eq "true") {
355            pb_log(1,"DEBUG: launching $cmd\n");
356        } else {
357            pb_log(1,"DEBUG: mkdir -p $target\n");
358        }
359    } else {
360        if ($recur eq "true") {
361            pb_system($cmd);
362        }
363        pb_vcs_add($scheme,"$target");
364        pb_log(0,"INFO: Created $target and added it to your $scheme system\n");
365    }
366}
367$ssh2->disconnect() if (defined $machine);
368pb_log(2,"Exiting cb_busterize\n");
369}
Note: See TracBrowser for help on using the repository browser.