ClearCase-ClearPrompt

 view release on metacpan or  search on metacpan

ClearPrompt.pm  view on Meta::CPAN


# Debugging aids. Documented in POD section. These can also be
# controlled via cmds at import time.
if ($ENV{CLEARCASE_CLEARPROMPT_DEBUG} ||
	($ENV{ATRIA_FORCE_GUI} && $ENV{PERL5OPT} && $ENV{PERL5OPT} =~ /-d/)) {
    rerun_in_debug_mode();
} elsif ($ENV{CLEARCASE_CLEARPROMPT_DEBUG_SHELL}) {
    dbg_shell();
}

# Make an attempt to supply a full path to the specified program.
# Else fall back to relying on PATH.
sub ccpath {
    my $name = shift;
    if (MSWIN()) {
	return $name;	# no way to avoid relying on PATH in &^&@$! Windows
    } else {
	return join('/', $ENV{ATRIAHOME} || q(/usr/atria), 'bin', $name);
    }
}

# Generates a random-ish name for a temp file that doesn't yet exist.
# This function makes no pretense of being atomic; it's conceivable,
# though highly unlikely, that the generated filename could be
# taken between the time it's generated and the time it's used.
# The optional parameter becomes a filename extension. The optional
# 2nd parameter overrides the basename part of the generated path.
sub tempname {
    my($custom, $tmpf) = @_;
    # The preferred directory for temp files.
    my $tmpd = MSWIN() ?
	    ($ENV{TEMP} || $ENV{TMP} || ( -d "$ENV{SYSTEMDRIVE}/temp" ?
			      "$ENV{SYSTEMDRIVE}/temp" : $ENV{SYSTEMDRIVE})) :
	    ($ENV{TMPDIR} || '/tmp');
    $tmpd =~ s%\\%/%g;
    my $ext = 'tmp';
    return "$tmpd/$tmpf.$custom.$ext" if $tmpf;
    (my $pkg = lc __PACKAGE__) =~ s/:+/-/g;
    while (1) {
	$tmpf = join('.', "$tmpd/$pkg", $$, int(rand 10000));
	$tmpf .= $custom ? ".$custom.$ext" : ".$ext";
	return $tmpf if ! -f $tmpf;
    }
}

# Run clearprompt with specified args and return what it returned. Uses the
# exact same syntax as the clearprompt executable ('ct man clearprompt')
# except for -outfile <file> which is handled internally here.
sub clearprompt {
    my $mode = shift;
    my @args = @_;
    my $data;

    return 0 if $ENV{ATRIA_WEB_GUI};	# must assume "" or 0 if ccweb interface

    local $!;	# don't mess up errno in the caller's world.

    # Play back responses from the StashFile if it exists and other conditions
    # are satisfied. It seems that CC sets the series id to all zeroes
    # after an error condition (??) so we avoid that case explicitly.
    my $lineno = (caller)[2];
    my $subtext = "from $prog:$lineno";
    if ($TriggerSeries && $ENV{CLEARCASE_SERIES_ID} &&
				    $ENV{CLEARCASE_SERIES_ID} !~ /^[0:.]+$/) {
	(my $sid = $ENV{CLEARCASE_SERIES_ID}) =~ s%:+%-%g;
	$StashFile = tempname($prog, "CLEARCASE_SERIES_ID=$sid");
	if (!$ENV{CLEARCASE_BEGIN_SERIES} && -f $StashFile) {
	    do $StashFile;
	    if ($ENV{CLEARCASE_END_SERIES} &&
				    !$ENV{CLEARCASE_CLEARPROMPT_KEEP_CAPTURE}) {
		# We delay the unlink due to weird  Windows locking behavior
		eval "END { unlink '$StashFile' }";
	    }
	    no strict 'vars';
	    my $data = eval "\$stash$lineno";
	    _automail('PROMPT', "Replay $subtext", "REPLAY:\n",
			    defined($data) ? $data : 'undef');
	    return $data;
	}
    }

    # On Windows we must add an extra level of escaping to any args
    # which might have special chars since all forms of system()
    # appear to go through the %^%@# cmd shell (boo!). This is
    # also handled by Perl 5.6.1, ActiveState build 630 but it will
    # be a long time till we can count on that fix being present.
    if (MSWIN()) {
	for (0..$#args) {
	    my $i = $_;
	    if ($args[$i] =~ /^-(?:pro|ite|def|dfi|dir)/) {
		$args[$i+1] =~ s/"/'/gs;
		$args[$i+1] = qq("$args[$i+1]");
	    }
	}
    }

    # For clearprompt modes in which we get textual data back via a file,
    # derive here a reasonable temp-file name and handle the details
    # of reading the data out of it and unlinking it when done.
    # For other modes, just fire off the cmd and return the status.
    # In a void context, don't wait for the button to be pushed; just
    # "fork" and proceed asynchonously since this is presumably just an
    # informational message.
    # If the cmd took a signal, return undef and leave the signal # in $?.
    if ($mode =~ /text|file|list/) {
	my $outf = tempname($mode);
	my @cmd = (ccpath('clearprompt'), $mode, '-out', $outf, @args);
	print STDERR "+ @cmd\n" if $ClearCase::ClearPrompt::Verbose;
	if (!system(@cmd)) {
	    if (open(OUTFILE, $outf)) {
		local $/ = undef;
		$data = <OUTFILE>;
		$data = '' if !defined $data;
		close(OUTFILE);
	    }
	} else {
	    # If we took a signal, return undef with the signal # in $?. The
	    # clearprompt cmd apparently catches SIGINT and returns 0x400 for
	    # some reason; we fix it here so $? looks like a normal sig2.
	    $? = 2 if $? == 0x400;
	    $data = undef if $? && $? <= 0x80;

ClearPrompt.pm  view on Meta::CPAN

	    }

	    # Then display any stdout we captured in a dialog box.
	    if (defined($tmpout) && -e $tmpout) {
		open(OUT, $tmpout) || warn "$prog: $tmpout: $!";
		my @msg = <OUT>;
		close(OUT);
		if (@msg) {
		    _automail('STDOUT', "Stdout from $prog", @msg);
		    if ($Dialogs{STDOUT}) {
			my $t = "STDOUT\n\n @msg";
			clearprompt(qw(proceed -type o -mask p -pref -pro), $t);
		    }
		}
		if (!$ENV{CLEARCASE_CLEARPROMPT_KEEP_CAPTURE}) {
		    # On Windows, we can't unlink this tempfile while
		    # any asynchronous dialog boxes are still on the
		    # screen due to threading/locking design, so we
		    # give the user some time to read & close them.
		    if (MSWIN()) {
			system(1, qq($^X -e "sleep 30; unlink '$tmpout'"));
		    } else {
			unlink($tmpout) || print "$prog: $tmpout: $!\n";
		    }
		}
	    }
	    # Same as above but for stderr.
	    if (defined($tmperr) && -e $tmperr) {
		my @msg;
		{
		    open(ERR, $tmperr) || warn "$prog: $tmperr: $!";
		    local $^W = 0; # <ERR> gives bogus error with AS build 623
		    @msg = <ERR>;
		    close(ERR);
		}
		if (@msg) {
		    _automail('STDERR', "Stderr from $prog", @msg);
		    if ($Dialogs{STDERR}) {
			my $t = "STDERR\n\n @msg";
			clearprompt(qw(proceed -type o -mask p -pref -pro), $t);
		    }
		}
		if (!$ENV{CLEARCASE_CLEARPROMPT_KEEP_CAPTURE}) {
		    if (MSWIN()) {
			system(1, qq($^X -e "sleep 30; unlink '$tmperr'"));
		    } else {
			unlink($tmperr) || print "$prog: $tmperr: $!\n";
		    }
		}
	    }
	};
	eval "END { endfunc(); }";
    }
}

# This is a pseudo warn() func which is called via the $SIG{__WARN__} hook.
sub cpwarn {
    my @msg = @_;
    # always show line numbers if this dbg flag set
    if ($ENV{CLEARCASE_CLEARPROMPT_SHOW_LINENO}) {
	my($file, $line) = (caller)[1,2];
	chomp $msg[-1];
	push(@msg, " at $file line $line.\n");
    }
    _automail('WARN', "Warning from $prog", @msg);
    if ($ENV{ATRIA_FORCE_GUI} && $Dialogs{WARN}) {
	clearprompt(qw(proceed -type w -mask p -pref -pro), "WARNING\n\n@msg");
	return undef; 	# to keep clearprompt() in void context
    } else {
	warn @msg;
    }
}

# A pseudo die() which can be made to override the caller's builtin.
sub die {
    my @msg = @_;
    # always show line numbers if this dbg flag set
    if ($ENV{CLEARCASE_CLEARPROMPT_SHOW_LINENO}) {
	my($file, $line) = (caller)[1,2];
	chomp $msg[-1];
	push(@msg, " at $file line $line.\n");
    }
    _automail('DIE', "Error from $prog", @msg);
    if ($ENV{ATRIA_FORCE_GUI} && $Dialogs{DIE}) {
	clearprompt(qw(proceed -type e -mask p -pref -pro), "ERROR\n\n@msg");
	exit $! || $?>>8 || 255;	# suppress the msg to stderr
    } else {
	require Carp;
	CORE::die Carp::shortmess(@_);

    }
}

1;

__END__

=head1 NAME

ClearCase::ClearPrompt - Handle clearprompt in a portable, convenient way

=head1 SYNOPSIS

 use ClearCase::ClearPrompt qw(clearprompt);

 # Boolean usage
 my $rc = clearprompt(qw(yes_no -mask y,n -type ok -prompt), 'Well?');

 # Returns text into specified variable (context sensitive).
 my $txt = clearprompt(qw(text -pref -pro), 'Enter text data here: ');

 # Asynchronous usage - show dialog box and continue
 clearprompt(qw(proceed -mask p -type ok -prompt), "You said: $txt");

 # Trigger series (record/replay responses for multiple elements)
 use ClearCase::ClearPrompt qw(clearprompt /TRIGGERSERIES);
 my $txt = clearprompt(qw(text -pref -pro), 'Response for all elems: ');

 # Clean up environment on Windows to use /-style paths:
 use ClearCase::ClearPrompt qw(/ENV);

 # Cause the program to run in the debugger, even in a GUI environment:
 use ClearCase::ClearPrompt qw(/DEBUG);

 # Automatically divert trigger error msgs to clearprompt dialogs
 use ClearCase::ClearPrompt qw(+ERRORS);

 # As above but send error msgs via email instead to user1 and user2
 use ClearCase::ClearPrompt qw(+ERRORS=user1,user2);

 # As above but send msgs to the current user
 use ClearCase::ClearPrompt '+ERRORS=' . ($ENV{LOGNAME} || $ENV{USERNAME});

 # Prompt for a directory (not supported natively by clearprompt cmd)
 use ClearCase::ClearPrompt qw(clearprompt_dir);
 my $dir = clearprompt_dir('/tmp', "Please choose a directory");

=head1 DESCRIPTION



( run in 4.537 seconds using v1.01-cache-2.11-cpan-6de40a662fe )