Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
9.2 KiB

  1. #---------------------------------------------------------------------
  2. package PbuildEnv;
  3. #
  4. # Copyright (c) Microsoft Corporation. All rights reserved.
  5. #
  6. # Version:
  7. # 1.00 07/06/2000 JeremyD: inital version
  8. # 1.01 07/13/2000 JeremyD: do as little as possible
  9. # 1.02 07/26/2000 JeremyD: new logging style
  10. # 1.03 10/04/2001 JeremyD: enable per-script debugging with PB_DEBUG
  11. #---------------------------------------------------------------------
  12. use strict;
  13. use vars qw($VERSION);
  14. use lib $ENV{RAZZLETOOLPATH};
  15. use Carp;
  16. use File::Basename;
  17. use Logmsg;
  18. use cklang;
  19. $VERSION = '1.03';
  20. my ($DoNothing, $StartTime);
  21. BEGIN {
  22. # avoid running in a -c syntax check
  23. if ($^C) {
  24. $DoNothing++;
  25. return;
  26. }
  27. # required for logging
  28. $ENV{SCRIPT_NAME} = basename($0);
  29. # save a copy of the command line for logging
  30. my $command_line = join ' ', $0, @ARGV;
  31. # mini command line parser to snoop @ARGV for -l and -?
  32. for (my $i=0; $i<@ARGV; $i++) {
  33. # use the argument to -l to set $ENV{LANG} and then remove
  34. # both items from @ARGV
  35. if ($ARGV[$i] =~ /^[\/-]l(?::(.*))?$/) {
  36. my $lang = $1;
  37. if (!$lang and $ARGV[$i+1] !~ /^[\/-]/) {
  38. $lang = $ARGV[$i+1];
  39. splice @ARGV, $i+1, 1;
  40. }
  41. splice @ARGV, $i, 1;
  42. $ENV{LANG} = $lang;
  43. }
  44. # if a -? is present exit immediately instead of setting
  45. # up the full environment and logs
  46. elsif ($ARGV[$i] =~ /^[\/-]?\?/) {
  47. $DoNothing++;
  48. return;
  49. }
  50. }
  51. # 'usa' is the default language
  52. $ENV{LANG} ||= 'usa';
  53. # validate language, bad languages are fatal
  54. if( lc $ENV{LANG} eq "cov" )
  55. {
  56. if( !$ENV{_COVERAGE_BUILD} )
  57. {
  58. croak "Language $ENV{LANG} is not valid without a proper env var."
  59. }
  60. }
  61. else
  62. {
  63. if (!&cklang::CkLang($ENV{LANG})) {
  64. croak "Language $ENV{LANG} is not listed in codes.txt.";
  65. }
  66. }
  67. # set up a unique value to be used in log file names, this
  68. # has the horrific side effect of making log names unbearably
  69. # long and irritating to type
  70. # BUGBUG: this is not unique enough, multiple instances of
  71. # the same script in the same postbuild will clobber each
  72. # other's file
  73. my $unique_name = "$ENV{SCRIPT_NAME}.$ENV{_BUILDARCH}." .
  74. "$ENV{_BUILDTYPE}.$ENV{LANG}";
  75. # select postbuild dir using our language (usa is a special case)
  76. $ENV{_NTPOSTBLD_BAK} ||= $ENV{_NTPOSTBLD};
  77. $ENV{_NTPOSTBLD} = $ENV{_NTPOSTBLD_BAK};
  78. if (lc($ENV{LANG}) ne 'usa' && lc($ENV{LANG}) ne 'cov' && !$ENV{dont_modify_ntpostbld} ) {
  79. $ENV{_NTPOSTBLD} .= "\\$ENV{LANG}";
  80. }
  81. # select a temp dir using our language
  82. $ENV{TEMP_BAK} ||= $ENV{TEMP};
  83. $ENV{TEMP} = $ENV{TMP} = "$ENV{TEMP_BAK}\\$ENV{LANG}";
  84. # create the directories for our logs if nescessary
  85. # BUGBUG perl mkdir will not recursively create dirs
  86. if (!-d $ENV{TEMP}) { mkdir $ENV{TEMP}, 0777 }
  87. # select the final logfile we will append to when finished
  88. # save the parent logfile to append to
  89. if ($ENV{LOGFILE}) {
  90. $ENV{LOGFILE_BAK} = $ENV{LOGFILE};
  91. }
  92. # this is the outermost script, set the final logfile name and
  93. # clear it
  94. else {
  95. $ENV{LOGFILE_BAK} = "$ENV{TEMP}\\$unique_name.log";
  96. if (-e $ENV{LOGFILE_BAK}) { unlink $ENV{LOGFILE_BAK} }
  97. }
  98. # select the final errfile we will append to when finished
  99. # save the parent errfile to append to
  100. if ($ENV{ERRFILE}) {
  101. $ENV{ERRFILE_BAK} = $ENV{ERRFILE};
  102. }
  103. # we are the top level, select a filename and clear
  104. else {
  105. $ENV{ERRFILE_BAK} = "$ENV{TEMP}\\$unique_name.err";
  106. if (-e $ENV{ERRFILE_BAK}) { unlink $ENV{ERRFILE_BAK} }
  107. }
  108. # we will acutally log to a tempfile during script execution
  109. # we need to clear/create our temporary logging file
  110. $ENV{LOGFILE} = "$ENV{TEMP}\\$unique_name.tmp";
  111. unlink $ENV{LOGFILE};
  112. $ENV{ERRFILE} = "$ENV{TEMP}\\$unique_name.err.tmp";
  113. unlink $ENV{ERRFILE};
  114. # turn on debugging if this script is mentioned by name
  115. # in PB_DEBUG
  116. if (defined $ENV{PB_DEBUG} and
  117. $ENV{PB_DEBUG} =~ /\b\Q$ENV{SCRIPT_NAME}\E\b/i) {
  118. $ENV{DEBUG} = 1;
  119. }
  120. $SIG{__WARN__} = sub {
  121. if ($^S or !defined $^S) { return }
  122. wrnmsg($_[0]);
  123. };
  124. $SIG{__DIE__} = sub {
  125. if ($^S or !defined $^S) { return }
  126. errmsg(Carp::longmess($_[0]));
  127. };
  128. # save the starting time to compute elapsed time in END block
  129. $StartTime = time();
  130. # record the command line in the log
  131. infomsg("START \"$command_line\"" );
  132. }
  133. END {
  134. # avoid running in a -c syntax check
  135. return if $DoNothing;
  136. # compute elasped time and make a nice string out of it
  137. my $elapsed_time = time() - $StartTime;
  138. my $time_string = sprintf("(%d second%s)", $elapsed_time,
  139. ($elapsed_time == 1 ? '' : 's'));
  140. my $error_string = '';
  141. # an error occurred iff this script called Logmsg::errmsg
  142. if (-e $ENV{ERRFILE} and !-z $ENV{ERRFILE}) {
  143. $error_string = "errors encountered";
  144. # force a non-zero exit code, it's bad form to exit with
  145. # 0 when you have an error
  146. $? ||= 1;
  147. }
  148. # for historical reasons an exit code without an errmsg call is
  149. # not an error
  150. elsif ($?) {
  151. $error_string = "nonzero exit code ($?)";
  152. }
  153. # no errmsg calls and exit code 0, clearly success
  154. else {
  155. $error_string = "success";
  156. }
  157. # record the elapsed time and success / failure status in the log
  158. infomsg("END $time_string $error_string");
  159. # at this point all logging is complete, our temporary log and
  160. # error file are now appended back to the log and error file of
  161. # the enclosing script
  162. # save the names of the files we were using temporarily
  163. my $temp_logfile = $ENV{LOGFILE};
  164. my $temp_errfile = $ENV{ERRFILE};
  165. # set the logging environment to the final locations
  166. $ENV{ERRFILE} = $ENV{ERRFILE_BAK};
  167. $ENV{LOGFILE} = $ENV{LOGFILE_BAK};
  168. # append from our temporary log to the final log
  169. open LOGFILE, ">>$ENV{LOGFILE}";
  170. open TMPFILE, $temp_logfile;
  171. print LOGFILE <TMPFILE>;
  172. close LOGFILE;
  173. close TMPFILE;
  174. unlink($temp_logfile);
  175. # append any errors back to the final error log
  176. if (-e $temp_errfile) {
  177. # skip 0 length error files
  178. if (!-z $temp_errfile) {
  179. open ERRFILE, ">>$ENV{ERRFILE}";
  180. open TMPFILE, $temp_errfile;
  181. print ERRFILE <TMPFILE>;
  182. close ERRFILE;
  183. close TMPFILE;
  184. }
  185. unlink($temp_errfile);
  186. }
  187. }
  188. 1;
  189. __END__
  190. =head1 NAME
  191. PbuildEnv - Set up a local environment for postbuild scripts
  192. =head1 SYNOPSIS
  193. use PbuildEnv;
  194. =head1 DESCRIPTION
  195. PbuildEnv sets a BEGIN and END block that provide the nescessary
  196. framework for running a script in the postbuild environment.
  197. Be sure to use this module before any other postbuild specific
  198. modules. Otherwise, some required variables may not be set up before
  199. the other module tries to use them.
  200. At compile time PbuildEnv will parse any language switches on the
  201. command line. The argument to a -l switch will be stored in the
  202. environment variable LANG by PbuildEnv at the time that it is use'd.
  203. The -l and its argument will be removed from @ARGV before control
  204. returns to your program.
  205. PbuildEnv also sets the environment variables LOGFILE and ERRFILE
  206. which are used by Logmsg. You should not use these environment
  207. variables or the files they refer to directly in your program (use
  208. Logmsg).
  209. The TEMP and TMP environment variables have a per-language
  210. subdirectory added to them (default is 'usa'). If your script uses
  211. these variables be aware that you will need to append the language
  212. manually when you are working at the command line. This modification
  213. is to aid having multiple languages postbuilding on the same machine.
  214. used by Logmsg, logs a beginning and ending message with elapsed
  215. time, and propogates errors back to the calling context.
  216. The _NTPOSTBLD environment variable will be set by PbuildEnv. This is
  217. the location of binaries currently being postbuilt. Do not use
  218. _NTTREE in postbuild, this will not be the correct location of
  219. binaries on international builds.
  220. =head1 NOTES
  221. The following issues should be addressed in future versions of this
  222. module.
  223. Does not handle multiple invocations of the same script (within the
  224. same arch / type / language combination) correctly. Unique names
  225. should be created more carefully/randomly to prevent collisions.
  226. Bad languages specified with -l cause a rather ungraceful exit.
  227. During the log appending process no error checking is done. Along
  228. with the uniqueness problem this makes the append logs somewhat less
  229. robust than they should be.
  230. Scripts that return non-zero exit codes but do not call
  231. Logmsg::errmsg will be considered successful by postbuild.cmd.
  232. =head1 AUTHOR
  233. Jeremy Devenport <JeremyD>
  234. =head1 COPYRIGHT
  235. Copyright (c) Microsoft Corporation. All rights reserved.
  236. =cut