DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Untracked file

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
=head1 NAME

B<Moz> - routines for automating CodeWarrior builds, and some extra-curricular activities related to building Mozilla

=head1 SYNOPSIS

    use Moz;

    OpenErrorLog(":::BuildLog");
    StopForErrors();

		$Moz::QUIET = 1;
		InstallFromManifest(":projects:MANIFEST", $dist_dir);

    BuildProjectClean(":projects:SomeProject.mcp", "SomeTarget");
    MakeAlias(":projects:SomeProject.shlb", $dist_dir);

    DontStopForErrors();

    BuildProject(":projects:SomeOtherProject.mcp", "SomeTarget");

=head1 DESCRIPTION

B<Moz> comprises the routines needed to slap CodeWarrior around, force it to build a sequence of projects, report the results, and a few other things.

=cut




package			Moz;
require			Exporter;

@ISA				= qw(Exporter);
@EXPORT			= qw(BuildProject BuildProjectClean OpenErrorLog MakeAlias StopForErrors DontStopForErrors InstallFromManifest SetBuildNumber SetAgentString SetTimeBomb Delay);
@EXPORT_OK	= qw(CloseErrorLog UseCodeWarriorLib QUIET);

	use Cwd;
	use File::Path;
	use ExtUtils::Manifest 'maniread';

	use CodeWarriorLib;

sub current_directory()
	{
		my $current_directory = cwd();
		chop($current_directory) if ( $current_directory =~ m/:$/ );
		return $current_directory;
	}

sub full_path_to($)
	{
		my ($path) = @_;
		if ( $path =~ m/^[^:]+$/ )
			{
				$path = ":" . $path;
			}

		if ( $path =~ m/^:/ )
			{
				$path = current_directory() . $path;
			}

		return $path;
	}

=head2 Setup

Pretty much, everything is taken care of for you.
  However, B<Moz> does use a little compiled AppleScript library (the file CodeWarriorLib) for some of its communcication with CodeWarrior.
  If this library isn't in the same directory as "Moz.pm", then you need to tell B<Moz> where to find it.
  Call C<UseCodeWarriorLib($path_to_CodeWarriorLib)>.
  This routine is not exported by default, nor are you likely to need it.

=cut

sub UseCodeWarriorLib($)
	{
#		($CodeWarriorLib) = @_;
#		$CodeWarriorLib = full_path_to($CodeWarriorLib);
	}

sub activate_CodeWarrior()
	{
#MacPerl::DoAppleScript(<<END_OF_APPLESCRIPT);
#	tell (load script file "$CodeWarriorLib") to ActivateCodeWarrior()
#END_OF_APPLESCRIPT
	}

BEGIN
	{
#		UseCodeWarriorLib(":CodeWarriorLib");
#		activate_CodeWarrior();
		CodeWarriorLib::activate();
	}

$logging								= 0;
$recent_errors_file			= "";
$stop_on_1st_error			= 1;
$QUIET									= 0;



=head2 Logging all the errors and warnings - C<OpenErrorLog($log_file)>, C<CloseErrorLog()>

The warnings and errors generated in the course of building projects can be logged to a file.
Tinderbox uses this facility to show why a remote build failed.

Logging is off by default.
  Start logging at any point in your build process with C<OpenErrorLog($log_file)>.
  Stop with C<CloseErrorLog()>.
  You never need to close the log explicitly, unless you want to just log a couple of projects in the middle of a big list.
  C<CloseErrorLog()> is not exported by default. 

=cut

sub CloseErrorLog()
	{
		if ( $logging )
			{
				close(ERROR_LOG);
				$logging = 0;
				StopForErrors() if $stop_on_1st_error;
			}
	}



sub OpenErrorLog($)
	{
		my ($log_file) = @_;

		CloseErrorLog();
		if ( $log_file )
			{
				$log_file = full_path_to($log_file);

				open(ERROR_LOG, ">$log_file");

				$log_file =~ m/.+:(.+)/;
				$recent_errors_file = full_path_to("$1.part");
				$logging = 1;
			}
	}


=head2 Stopping before it's too late - C<StopForErrors()>, C<DontStopForErrors()>

When building a long list of projects, you decide whether to continue building subsequent projects when one fails.
  By default, your build script will C<die> after the first project that generates an error while building.
  Change this behavior with C<DontStopForErrors()>.
  Re-enable it with C<StopForErrors()>.

=cut

sub StopForErrors()
	{
		$stop_on_1st_error = 1;
		
			# Can't stop for errors unless we notice them.
			# Can't notice them unless we are logging.
			# If the user didn't explicitly request logging, log to a temporary file.

		if ( ! $recent_errors_file )
			{
				OpenErrorLog("${TMPDIR}BuildResults");
			}
	}

sub DontStopForErrors()
	{
		$stop_on_1st_error = 0;		
	}

sub log_message($)
	{
		if ( $logging )
			{
				my ($message) = @_;
				print ERROR_LOG $message;
			}
	}

sub log_message_with_time($)
	{
		if ( $logging )
			{
				my ($message) = @_;
				my $time_stamp = localtime();
				log_message("$message ($time_stamp)\n");
			}
	}

sub log_recent_errors($)
	{
		my ($project_name) = @_;
		my $found_errors = 0;
	
		if ( $logging )
			{
				open(RECENT_ERRORS, "<$recent_errors_file");

				while( <RECENT_ERRORS> )
					{
						if ( /^Error/ || /^CouldnĊt find project file/ )
							{
								$found_errors = 1;
							}
						print ERROR_LOG $_;
					}

				close(RECENT_ERRORS);
				unlink("$recent_errors_file");
			}
		
		if ( $stop_on_1st_error && $found_errors )
			{
				print ERROR_LOG "### Build failed.\n";
				die "### Errors encountered building \"$project_name\".\n";
			}
	}

sub build_project($$$)
	{
		my ($project_path, $target_name, $clean_build) = @_;
		$project_path = full_path_to($project_path);

#		$project_path =~ m/.+:(.+)/;
#		my $project_name = $1;

		log_message_with_time("### Building \"$project_path\"");

			# Check that the given project exists
		if (! -e $project_path)
			{
				print ERROR_LOG "### Build failed.\n";
				die "### Can't find project file \"$project_path\".\n";
			}
		
		print "Building \"$project_path\[$target_name\]\"\n";
		
		$had_errors = CodeWarriorLib::build_project(
			$project_path, $target_name, $recent_errors_file, $clean_build
		);


#		$had_errors =
#MacPerl::DoAppleScript(<<END_OF_APPLESCRIPT);
#	tell (load script file "$CodeWarriorLib") to BuildProject("$project_path", "$project_name", "$target_name", "$recent_errors_file", $clean_build)
#END_OF_APPLESCRIPT

			# Append any errors to the globally accumulated log file
		if ( $had_errors )
			{
				log_recent_errors($project_path);
			}
	}

=head2 Getting CodeWarrior to build projects - C<BuildProject($project, $opt_target)>, C<BuildProjectClean($project, $opt_target)>

C<BuildProject()> and C<BuildProjectClean()> are identical, except that the latter first removes object code.
  In both, CodeWarrior opens the project if it wasn't already open; builds the given (or else current) target; and finally closes
 the project, if it wasn't already open.

=cut

sub BuildProject($;$)
	{
		my ($project_path, $target_name) = @_;
		build_project($project_path, $target_name, 0);
	}

sub BuildProjectClean($;$)
	{
		my ($project_path, $target_name) = @_;
		build_project($project_path, $target_name, 1);
	}


=head2 Miscellaneous

C<MakeAlias($old_file, $new_file)> functions like C<symlink()>, except with better argument defaulting and more explicit error messages.

=cut

sub MakeAlias($$)
	{
		my ($old_file, $new_file) = @_;

			# if the directory to hold $new_file doesn't exist, create it
		if ( ($new_file =~ m/(.+:)/) && !-d $1 )
			{
				mkpath($1);
			}

			# if a leaf name wasn't specified for $new_file, use the leaf from $old_file
		if ( ($new_file =~ m/:$/) && ($old_file =~ m/.+:(.+)/) )
			{
				$new_file .= $1;
			}

		my $message = "Can't create a Finder alias (at \"$new_file\")\n for \"$old_file\"; because ";

		die "$message \"$old_file\" doesn't exist.\n" unless -e $old_file;
		die "$message I won't replace an existing (non-alias) file with an alias.\n" if ( -e $new_file && ! -l $new_file );

			# now: $old_file exists; $new_file doesn't (or else, is an alias already)

		if ( -l $new_file )
			{
					# ...then see if it already points to $old_file
				my $current_target	= full_path_to(readlink($new_file));
				my $new_target			= full_path_to($old_file);

				return if ( $current_target eq $new_target );
					# if the desired alias already exists and points to the right thing, then we're done
				
				unlink $new_file;
			}
		
		symlink($old_file, $new_file) || die "$message symlink returned an unexpected error.\n";
	}
	
	
=pod

C<InstallFromManifest()>

=cut

sub InstallFromManifest($;$)
	{
		my ($manifest_file, $dest_dir) = @_;

		$dest_dir ||= ":";

		$manifest_file =~ m/(.+):/;
		my $source_dir =  $1;

		chop($dest_dir) if $dest_dir =~ m/:$/;

		print "Doing manifest on \"$manifest_file\"\n" unless $QUIET;
		
		my $read = maniread(full_path_to($manifest_file));
		foreach $file (keys %$read)
			{
				next unless $file;

				$subdir = ":";
				if ( $file =~ /:.+:/ )
					{
						$subdir = $&;
					}

				$file = ":$file" unless $file =~ m/^:/;
				MakeAlias("$source_dir$file", "$dest_dir$subdir");
			}
	}

 sub SetBuildNumber
 {

   open (OUTPUT, ">:mozilla:config:build_number") || die "could not open buildnumber";

   open (BDATE, "perl :mozilla:config:bdate.pl|");
   
   while (<BDATE>) {
     print OUTPUT $_;
   }

   close (BDATE);
   close (OUTPUT);

   system ("perl :mozilla:config:aboutime.pl :mozilla:l10n:us:xp:about-all.html :mozilla:config:build_number");

 }

sub SetAgentString
{
	
	open (BDATE, ":mozilla:config:build_number") || die "could not open buildnumber";
	   
	while (<BDATE>) {
		$build_number = $_;
	}
	
	close (BDATE);
	
	open (ORIGFILE, ":mozilla:cmd:macfe:restext:custom.r") || die "no original file";
	open (OUTPUT, ">:mozilla:cmd:macfe:restext:agent.r") || die "no output file";
	
	chop($build_number);
	
	while (<ORIGFILE>) {
	
		$tempstring = $_;
		if ($tempstring =~	"\#define		VERSION_MAJOR_STR") {
			$tempstring = "\#define		VERSION_MAJOR_STR	\"5.0a1-" . $build_number . " Development\"\n";
		}
		print OUTPUT $tempstring;
	}
	
	close (ORIGFILE);
	close (OUTPUT);
	
	unlink (":mozilla:cmd:macfe:restext:custom.r");
	rename (":mozilla:cmd:macfe:restext:agent.r", ":mozilla:cmd:macfe:restext:custom.r");
}

sub SetTimeBomb($$)
		
{
  my ($warn_days, $bomb_days) = @_;
  
  system("perl :mozilla:config:mac-set-timebomb.pl $warn_days $bomb_days");
	
}

sub Delay($)
		
{
  my ($delay_seconds) = @_;

  $now = time;
  
  $exit_time = $now + $delay_seconds;

  while ($exit_time > $now) {
     $now = time;
  }
	
}


1;

=head1 AUTHORS

Scott Collins <scc@netscape.com>, Simon Fraser <sfraser@netscape.com>, Chris Yeh <cyeh@netscape.com>

=head1 SEE ALSO

BuildMozillaDebug.pl (et al), BuildList.pm, CodeWarriorLib (an AppleScript library)

=head1 COPYRIGHT

The contents of this file are subject to the Netscape Public License
Version 1.0 (the "NPL"); you may not use this file except in
compliance with the NPL.  You may obtain a copy of the NPL at
http://www.mozilla.org/NPL/

Software distributed under the NPL is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
for the specific language governing rights and limitations under the
NPL.

The Initial Developer of this code under the NPL is Netscape
Communications Corporation.  Portions created by Netscape are
Copyright (C) 1998 Netscape Communications Corporation.  All Rights
Reserved.

=cut