File Coverage

lib/UR/Context/Process.pm
Criterion Covered Total %
statement 40 105 38.1
branch 4 36 11.1
condition 0 16 0.0
subroutine 8 23 34.7
pod 15 17 88.2
total 67 197 34.0


line stmt bran cond sub pod time code
1             package UR::Context::Process;
2              
3             =pod
4              
5             =head1 NAME
6              
7             UR::Context::Process - Implements a generic interface to the current application.
8              
9             =head1 SYNOPSIS
10              
11             $name = UR::Context::Process->base_name;
12              
13             $name = UR::Context::Process->prog_name;
14             UR::Context::Process->prog_name($name);
15              
16             $name = UR::Context::Process->pkg_name;
17             UR::Context::Process->pkg_name($name);
18              
19             $name = UR::Context::Process->title;
20             UR::Context::Process->title($name);
21              
22             $version = UR::Context::Process->version;
23             UR::Context::Process->version($version);
24              
25             $author = UR::Context::Process->author;
26             UR::Context::Process->author($author);
27              
28             $author_email = UR::Context::Process->author_email;
29             UR::Context::Process->author_email($author_email);
30              
31             $support_email = UR::Context::Process->support_email;
32             UR::Context::Process->support_email($support_email);
33              
34             $login = UR::Context::Process->real_user_name;
35              
36             =head1 DESCRIPTION
37              
38             This module provides methods to set and retrieve various names
39             associated with the program and the program version number.
40              
41             =cut
42              
43             package UR::Context::Process;
44              
45             our $VERSION = "0.46"; # UR $VERSION;;
46              
47             require 5.006_000;
48              
49 266     266   2657 use strict;
  266         377  
  266         7858  
50 266     266   964 use warnings;
  266         343  
  266         7173  
51 266     266   947 use Sys::Hostname;
  266         298  
  266         15302  
52 266     266   1102 use File::Basename;
  266         358  
  266         265048  
53             require UR;
54              
55             UR::Object::Type->define(
56             class_name => 'UR::Context::Process',
57             is => ['UR::Context'],
58             is_transactional => 0,
59             has => [
60             host_name => { is => 'Text' },
61             process_id => { is => 'Integer' },
62             access_level => { is => 'Text', default_value => '??' },
63             debug_level => { is => 'Integer', default_value => 0 },
64             ],
65             doc => 'A context for a given process.',
66             );
67              
68             =pod
69              
70             =head1 METHODS
71              
72             These methods provide the accessor and set methods for various names
73             associated with an application.
74              
75             =over
76              
77             =item get_current
78              
79             $ctx = UR::Context::Process->get_current();
80              
81             This is the context which represents the current process.
82              
83             Also available as UR::Context->get_process();
84              
85             =back
86              
87             =cut
88              
89              
90             sub get_current {
91 0     0 1 0 return $UR::Context::process;
92             }
93              
94             =pod
95              
96             =over
97              
98             =item has_changes()
99              
100             $bool = UR::Context::Process->has_changes();
101              
102             Returns true if the current process has changes which might be committed back to
103             the underlying context.
104              
105             =back
106              
107             =cut
108              
109             sub has_changes {
110 0     0 1 0 my $self = shift;
111 0         0 my @ns = $self->all_objects_loaded('UR::Namespace');
112 0         0 for my $ns (@ns) {
113 0         0 my @ds = $ns->get_data_sources();
114 0         0 for my $ds (@ds) {
115 0 0       0 return 1 if $ds->has_changes_in_base_context();
116             }
117             }
118 0         0 return;
119             }
120              
121             =pod
122              
123             =over
124              
125             =item _create_for_current_process
126              
127             $ctx = UR::Context::Process->_create_for_current_process(@PARAMS)
128              
129             This is only used internally by UR.
130             It materializes a new object to represent a real process somewhere.
131              
132             TODO: Remove the exception from create(), and allow other processes to be
133             created explicitly w/ the appropriate characteristics.
134              
135             =back
136              
137             =cut
138              
139             sub _create_for_current_process {
140 267     267   573 my $class = shift;
141              
142 267 50       923 die "Process object for the current process already exists!" if $UR::Context::process;
143              
144             #my $rule = $class->define_boolexpr(@_);
145 267         1244 my $rule = UR::BoolExpr->resolve($class, @_);
146            
147 267         2634 my $host_name = Sys::Hostname::hostname();
148            
149 267         2360 my $id = $host_name . "\t" . $$;
150            
151 267         1254 my $self = $class->SUPER::create(id => $id, process_id => $$, host_name => $host_name, $rule->params_list);
152 267         802 return $self;
153             }
154              
155             sub create {
156             # Note that the above method does creation by going straight to SUPER::create()
157             # for the current process only.
158 0     0 1 0 die "Creation of parallel/child processes not yet supported!"
159             }
160              
161             # TODO: the remaining methods are from the old App::Name module.
162             # They currently only work for the current process, and operate as class methods.
163             # They should be re-written to work as class methods on $this_process, or
164             # instance methods on any process. For now, only the class methods are needed.
165              
166             =pod
167              
168             =over
169              
170             =item base_name
171              
172             $name = UR::Context::Process->base_name;
173              
174             This is C.
175              
176             =back
177              
178             =cut
179              
180             our $base_name = basename($0, '.pl');
181 266     266 1 1452 sub base_name { return $base_name }
182              
183             =pod
184              
185             =over
186              
187             =item prog_name
188              
189             $name = UR::Context::Process->prog_name;
190             UR::Context::Process->prog_name($name);
191              
192             This method is used to access and set the name of the program name.
193              
194             This name is used in the output of the C and C
195             subroutines (see L<"version"> and L<"usage">). If given an argument,
196             this method sets the program name and returns the new name or C
197             if unsuccessful.
198              
199             It defaults to C if unspecified.
200              
201             =back
202              
203             =cut
204              
205             our $prog_name;
206             sub prog_name
207             {
208 0     0 1 0 my $class = shift;
209 0         0 my ($name) = @_;
210              
211 0 0       0 if (@_)
212             {
213 0         0 $prog_name = $name;
214             }
215 0   0     0 return $prog_name || $class->base_name;
216             }
217              
218             =pod
219              
220             =over
221              
222             =item pkg_name
223              
224             $name = UR::Context::Process->pkg_name;
225             UR::Context::Process->pkg_name($name);
226              
227             This method is used to access and set the GNU-standard package name
228             for the package to which this program belongs. This is does B
229             refer-to a Perl package. It allows a set of specific programs to be
230             grouped together under a common name, which is used in standard
231             message output, and is used in the output of the C subroutine
232             (see L<"version"> output.
233              
234             If given an argument, this method sets the package name and returns
235             the the new name or C if unsuccessful. Without an argument,
236             the current package name is returned.
237              
238             It defaults to C when unspecified, which in turn
239             defaults to C, which in turn defaults to
240             C.
241              
242             =back
243              
244             =cut
245              
246             # NOTE: this should not use App::Debug because App::Debug::level calls it
247             our $pkg_name;
248             sub pkg_name
249             {
250 0     0 1 0 my $class = shift;
251 0         0 my ($name) = @_;
252              
253 0 0       0 if (@_)
254             {
255 0         0 $pkg_name = $name;
256             }
257 0   0     0 return $pkg_name || $class->prog_name;
258             }
259              
260             =pod
261              
262             =over
263              
264             =item title
265              
266             $name = UR::Context::Process->title;
267             UR::Context::Process->title($name);
268              
269             This gets and sets the "friendly name" for an application. It is
270             often mixed-case, with spaces, and is used in autogenerated
271             documentation, and sometimes as a header in generic GUI components.
272             Without an argument, it returns the current title. If an argument is
273             specified, this method sets the application title and returns the new
274             title or C if unsuccessful.
275              
276             It defaults to C when otherwise unspecified, which
277             in turn defaults to C when unspecified, which in
278             turn defaults to C when unspecified, which
279             defaults to C when unspecified.
280              
281             =back
282              
283             =cut
284              
285             our $title;
286             sub title
287             {
288 0     0 1 0 my $class = shift;
289 0         0 my ($name) = @_;
290              
291 0 0       0 if (@_)
292             {
293 0         0 $title = $name;
294             }
295 0   0     0 return $title || $class->pkg_name;
296             }
297              
298             =pod
299              
300             =over
301              
302             =item version
303              
304             $version = UR::Context::Process->version;
305             UR::Context::Process->version($version);
306              
307             This method is used to access and set the package version. This
308             version is used in the output of the C method (see
309             L). If given an argument, this method
310             sets the package version and returns the version or C if
311             unsuccessful. Without an argument, the current package version is
312             returned.
313              
314             This message defaults to C<$main::VERSION> if not set. Note that
315             C<$main::VERSION> may be C.
316              
317             =back
318              
319             =cut
320              
321             # set/get version
322             # use $main::VERSION for compatibility with non-App animals.
323             sub version
324             {
325 0     0 1 0 my $class = shift;
326 0         0 my ($version) = @_;
327              
328 0 0       0 if (@_)
329             {
330 0         0 $main::VERSION = $version;
331             }
332 0         0 return $main::VERSION;
333             }
334              
335             =pod
336              
337             =over
338              
339             =item author
340              
341             $author = UR::Context::Process->author;
342             UR::Context::Process->author($author);
343              
344             This method is used to access and set the package author. If given an
345             argument, this method sets the package author and returns the author
346             or C if unsuccessful. Without an argument, the current author
347             is returned.
348              
349             =back
350              
351             =cut
352              
353             # set/get author
354             our $author;
355             sub author
356             {
357 0     0 1 0 my $class = shift;
358 0         0 my ($name) = @_;
359              
360 0 0       0 if (@_)
361             {
362 0         0 $author = $name;
363             }
364 0         0 return $author;
365             }
366              
367             =pod
368              
369             =over
370              
371             =item author_email
372              
373             $author_email = UR::Context::Process->author_email;
374             UR::Context::Process->author_email($author_email);
375              
376             This method is used to access and set the package author's email
377             address. This information is used in the output of the C
378             method (see L). If given an argument, this
379             method sets the package author's email address and returns email
380             address or C if unsuccessful. Without an argument, the current
381             email address is returned.
382              
383             =back
384              
385             =cut
386              
387             # set/return author email address
388             our $author_email;
389             sub author_email
390             {
391 0     0 1 0 my $class = shift;
392 0         0 my ($email) = @_;
393              
394 0 0       0 if (@_)
395             {
396 0         0 $author_email = $email;
397             }
398 0         0 return $author_email;
399             }
400              
401             =pod
402              
403             =over
404              
405             =item support_email
406              
407             $support_email = UR::Context::Process->support_email;
408             UR::Context::Process->support_email($support_email);
409              
410             This method is used to access and set the email address to which the
411             user should go for support. This information is used in the output of
412             the C method (see L). If given an
413             argument, this method sets the support email address and returns that
414             email address or C if unsuccessful. Without an argument, the
415             current email address is returned.
416              
417             =back
418              
419             =cut
420              
421             # set/return author email address
422             our $support_email;
423             sub support_email
424             {
425 0     0 1 0 my $class = shift;
426 0         0 my ($email) = @_;
427              
428 0 0       0 if (@_)
429             {
430 0         0 $support_email = $email;
431             }
432 0         0 return $support_email;
433             }
434              
435             =pod
436              
437             =over
438              
439             =item real_user_name
440              
441             $login = UR::Context::Process->real_user_name;
442              
443             This method is used to get the login name of the effective user id of
444             the running script.
445              
446             =back
447              
448             =cut
449              
450             # return the name of the user running the program
451             our $real_user_name;
452             sub real_user_name
453             {
454 0     0 1 0 my $class = shift;
455              
456 0 0       0 if (!$real_user_name)
457             {
458 0 0 0     0 if ($^O eq 'MSWin32' || $^O eq 'cygwin')
459             {
460 0         0 $real_user_name = 'WindowsUser';
461             }
462             else
463             {
464 0   0     0 $real_user_name = getpwuid($<) || getlogin || 'unknown';
465             }
466             }
467 0         0 return $real_user_name;
468             }
469              
470             =pod
471              
472             =over
473              
474             =item fork
475             $pid = UR::Context::Process->fork;
476              
477             Safe fork() wrapper.
478              
479             Handles properly disconnecting database handles if necessary so that data sources in children
480             are still valid. Also ensures that the active UR::Context::process has the child's PID
481             recorded within.
482              
483             =back
484              
485             =cut
486              
487             sub fork
488             {
489 2     2 1 18 my $class = shift;
490              
491 2         24 my @ds = UR::DataSource->is_loaded();
492              
493 2         6 for (grep {defined $_} @ds) {
  4         8  
494 4         34 $_->prepare_for_fork;
495             }
496              
497 2         3558 my $pid = fork();
498              
499 2 50       95 unless(defined $pid) {
500 0         0 Carp::confess('Failed to fork process. ' . $!);
501             }
502              
503 2 100       53 if (!$pid) {
504 1         30 $UR::Context::process = undef;
505 1         75 $UR::Context::process = $class->_create_for_current_process;
506 1         14 for (grep {defined $_} @ds) {
  2         10  
507 2         52 $_->do_after_fork_in_child;
508             }
509             }
510              
511 2         50 for (grep {defined $_} @ds) {
  4         33  
512 4         119 $_->finish_up_after_fork;
513             }
514              
515 2         42 return $pid;
516             }
517              
518             =pod
519              
520             =over
521              
522             =item effective_user_name
523              
524             $login = UR::Context::Process->effective_user_name;
525              
526             This method is used to get the login name of the effective user id of
527             the running script.
528              
529             =back
530              
531             =cut
532              
533             # return the name of the user running the program
534             our $effective_user_name;
535             sub effective_user_name
536             {
537 0     0 1   my $class = shift;
538              
539 0 0         if (!$effective_user_name)
540             {
541 0   0       $effective_user_name = getpwuid($>) || 'unknown';
542             }
543 0           return $effective_user_name;
544             }
545              
546             =pod
547              
548             =over
549              
550             =item original_program_path
551              
552             $path = UR::Context::Process->original_program_path;
553              
554             This method is used to (try to) get the original program path of the running script.
555             This will not change even if the current working directory is changed.
556             (In truth it will find the path at the time UR::Context::Process was used. So, a chdir
557             before that happens will cause incorrect results; in that case, undef will be returned.
558              
559             =back
560              
561             =cut
562              
563             our ($original_program_name, $original_program_dir);
564 266     266   150598 eval '
  266         230899  
  266         11315  
565             use FindBin;
566             $original_program_dir=$FindBin::Bin;
567             $original_program_name=__PACKAGE__->base_name;
568             ';
569              
570             sub original_program_path {
571 0     0 1   my $class=shift;
572              
573 0           my $original_program_dir=$class->original_program_dir;
574 0 0         return unless($original_program_dir);
575              
576 0           my $original_program_name=$class->original_program_name;
577 0 0         return unless($original_program_name);
578              
579 0           return $original_program_dir.q(/).$original_program_name;
580             }
581              
582             sub original_program_dir {
583 0 0   0 0   return unless($original_program_dir);
584 0           return $original_program_dir;
585             }
586              
587             sub original_program_name {
588 0 0   0 0   return unless($original_program_name);
589 0           return $original_program_name;
590             }
591              
592              
593             1;
594              
595             __END__