1 krisbash 1.1 @rem --*-Perl-*--
2 @if "%overbose%" == "" if "%_echo%"=="" echo off
3 setlocal
4 for %%i in (oenvtest.bat) do call %%~$PATH:i
5 perl.exe -x "%~dpnx0" %*
6 goto :eof
7
8 #!perl
9
10 BEGIN {
11 # augment library path for OTOOLS environment
12 if (defined $ENV{"OTOOLS"}) {
13 require "$ENV{'OTOOLS'}\\lib\\perl\\otools.pm"; import otools;
14 }
15
16 # Convert "use strict 'subs'" to the eval below so we don't
17 # break if the user's @INC is set up wrong. You'd be surprised
18 # how often this happens.
19 eval { require strict; import strict 'subs' };
20 }
21
22 krisbash 1.1 require 5.004;
23 die "Unsupported OS ($^O), sorry.\n" if $^O eq "dos";
24
25 sub Usage {
26 my $usage = <<'EOM';
27 NAME
28
29 $name - unpack a buddy build package
30
31 SYNOPSIS
32
33 $name -?
34
35 $name [-A dir] [-B dir] [-d] [-c changelist] [-f] [-l] [-m from to] [-n]
36 [-R resolve-options] [-s] [-u] [-v] [-w] [-x]
37
38 DESCRIPTION
39
40 Unpack the buddy build generated by a previous $pack.
41
42 OPTIONS
43 krisbash 1.1
44 -?
45
46 Displays this help file.
47
48 -A dir
49
50 Directory to use for "after" files. The directory will remain.
51 Must be used in conjunction with -w.
52
53 -B dir
54
55 Directory to use for "before" files. The directory will remain.
56 Must be used in conjunction with -w.
57
58 -d
59
60 Turns on debugging spew.
61
62 -c changelist
63
64 krisbash 1.1 Unpack the package onto the given changelist. If this option
65 is omitted, the default changelist will be used.
66
67 -f
68
69 Unpack even if the changelist is nonempty.
70
71 -l
72
73 List contents of package.
74
75 -m from to
76
77 Unpack (merge) the package into a location possibly different
78 from the one it was built from. "from" and "to" indicate the
79 relationship between the source and target depots. For example,
80 if the original package was built from //depot/branch1/... and
81 you want to unpack to //depot/branch2/... you would specify
82
83 -m //depot/branch1/ //depot/branch2/
84
85 krisbash 1.1 Note the trailing slashes. The remapping is a purely textual
86 one: All paths in the package that begin with "from" are
87 rewritten to begin with "to", hence the importance of the trailing
88 slash to avoid false matches. If you misspell "from" or "to",
89 you are likely to get very strange results.
90
91 The files are unpacked into the current client, which
92 need not be enlisted onto the same server that the package
93 was generated from.
94
95 It is legal for "from" and "to" to be the same path. This
96 results in merging a delta without moving it. See the -M
97 option below.
98
99 May not be combined with the -s or -w switches.
100
101 -M
102
103 Shorthand for "-m // //", which merges a changelist without
104 moving it.
105
106 krisbash 1.1 -n
107
108 Display what would have happened without actually doing
109 it.
110
111 -R resolve-options
112
113 Arbitrary options to pass to "sd resolve3". For example,
114 you could say
115
116 -R -af
117
118 to force automatic mode. For a list of supported options,
119 type
120
121 sd help resolve3
122
123 -s
124
125 Synchronize to the versions of the files that are
126 the bases for the changes contained in the package,
127 krisbash 1.1 but do not unpack them.
128
129 This is a convenient step to perform separately
130 from unpacking because it allows you to perform a
131 pre-build to ensure that the build was not broken
132 before you unpacked the files in the package.
133
134 -u
135
136 Perform the unpack. This switch can be combined with
137 the -s switch to synchronize and unpack in one step.
138
139 The unpack will fail if the changelist is nonempty.
140 Use the "sd change" command to move files in the default
141 changelist to a new changelist. This allows you to use
142 "sd revert -c default ..." to undo the unpack.
143
144 To force the unpack even if the changelist is empty,
145 pass the -f flag. Note that doing so will result in the
146 unpacked files being added to your changelist,
147 which in turn makes reverting the unpack a much more
148 krisbash 1.1 cumbersome operation.
149
150 -v
151
152 Verify that the package will produce results
153 identical to what's on the machine right now.
154 Use this immediately after generating a package as a
155 double-check.
156
157 -w
158
159 View contents of packages using windiff (or whatever your
160 BBDIFF environment variable refers to).
161
162 -x
163
164 Unpack the files as UNIX-style (LF only) rather than
165 Win32-style (CRLF).
166
167 -T
168
169 krisbash 1.1 Preserve the last changed timestamps for all files when
170 unpacking.
171
172 WARNINGS
173
174 warning: filename merge cancelled by user; skipped
175
176 A file in the package needed to be merged, but you abandoned
177 the merge operation ("s" or "q"). The file was left in its original
178 state; the changes were not merged in.
179
180 warning: //depot/.../filename not affected by branch mapping; skipped
181
182 The indicated file in the package is not affected by the
183 from/to mapping, so it was omitted from the merge.
184
185 ERRORS
186
187 error: sd failed; unpack abandoned
188
189 One of the sd commands necessary to complete the unpack failed.
190 krisbash 1.1 The sd error message should have been displayed immediately
191 before this message.
192
193 error: cannot find local copy of //depot/.../filename
194
195 The indicated file in the package could not be found on your
196 enlistment. Perhaps you have not included it in your view.
197
198 internal error: cannot parse output of 'sd have'
199 internal error: Cannot parse output of 'sd opened'
200
201 There was a problem parsing the output of an sd command.
202
203 error: changelist is not empty; use -f -u to unpack anyway
204
205 The changelist is not empty, so the unpack
206 was abandoned. To force unpacking into a nonempty
207 changelist, use the -f switch.
208
209 error: filename is already open on client; to merge, use the -M option
210
211 krisbash 1.1 The specified file is already open. It must be submitted or
212 reverted before the package can be unpacked cleanly.
213
214 Alternatively, you can unpack in "merge" mode, which merges
215 the changes in the package with the version on your machine.
216 Note that this will DESTROY the version on your machine in the
217 process, so back it up (possibly with bbpack) if there's a chance
218 the merge will not go well.
219
220 error: adds in this package already exist on client
221
222 The package contains an "add" operation, but the file already
223 exists. It must be ghosted or deleted before the package can
224 be unpacked.
225
226 error: files to be edited/deleted do not exist on client
227
228 The package contains an "edit" or "delete" operation, but the
229 file does not exist on the client. Perhaps you have not
230 included it in your view.
231
232 krisbash 1.1 error: wrong version of filename on client
233
234 The base version of the file in the package does not match the
235 base version on the client. Use the -s option to synchronize
236 to the version in the package.
237
238 error: filename does not match copy in package
239
240 The verification process (-v) failed.
241
242 error: corrupted package
243
244 An internal consistency check on the package has failed. Either
245 it has been corrupted, or there is a bug in the program.
246
247 error: cannot open filename for writing (reason)
248
249 The specified error occurred attempting to open the indicated
250 file for writing.
251
252 error: filename: errorstring
253 krisbash 1.1
254 The specified error occurred attempting to open the indicated
255 file.
256
257 error: no TEMP directory
258
259 Neither the environment variable TEMP nor TMP could be found.
260
261 error: Too many TEMP### directories
262
263 Unable to create a temporary directory for windiff because there
264 are too many already. Normally, temporary directories are cleaned
265 up automatically when the script terminates, but if the script
266 terminates abnormally, temporary directories may be left behind
267 and need to be cleaned up manually.
268
269 //deport/path/to/file.cpp - must refer to client 'CLIENTNAME'
270 error: sd failed; unpack abandoned
271
272 This is an sd error message. You spelled "depot" wrong ("deport")
273 in the -m command line arguments. As a result, sd thinks you are
274 krisbash 1.1 trying to merge with the file "file.cpp" on the enlistment named
275 "deport", and sd won't let you check out a file on another person's
276 enlistment.
277
278 TIPS
279
280 Brain surgery
281
282 $name stores as much state as possible in the depot itself in order
283 to keep the package small. If your server changes its name, you have
284 to perform brain surgery on the package. Load it up into notepad
285 and look for the _!_END_!_ line. A few lines after the _!_END_!_ will
286 be a
287
288 Source Server Address: oldserver:portnumber
289
290 Change the server address to refer to the new server and new port
291 number.
292
293 NOTE! Use Notepad and not "My Favorite Editor" because who knows
294 what "My Favorite Editor" does to tabs and trailing spaces and
295 krisbash 1.1 that sort of thing.
296
297 REMARKS
298
299 4NT users need to type
300
301 perl -Sx $name.cmd
302
303 instead of just $name.
304
305 ENVIRONMENT
306
307 BBDIFF
308
309 The name of the diff program to use. If not defined, the
310 SDDIFF variable is used to obtain the name of the file difference
311 program. If neither is defined, then "windiff" is used.
312
313 BBUNPACKDEFCMD
314
315 The default command to execute if no command line options are
316 krisbash 1.1 specified. If not defined, then an error message is displayed.
317
318 For example, you might set BBUNPACKDEFCMD=-w to make the default
319 action when running a package to be to view the contents via
320 windiff.
321
322 Since $name runs sd internally, all the SD environment variables
323 also apply.
324
325 BUGS
326
327 Several error messages leak out when you unpack an sd add.
328 (This is happening while verifying that the file about to be
329 added hasn't already been added.)
330
331 If the package contains an "add" command and the file exists
332 on the client but is not under source control, the file is overwritten
333 without warning.
334
335 There are almost certainly other bugs in this script somewhere.
336
337 krisbash 1.1 VERSION
338
339 The package was generated by version 109 of $pack.
340
341 EOM
342 $usage =~ s/\$name/$main::name/g;
343 $usage =~ s/\$pack/$main::pack/g;
344
345 # prevent false positives when searching for the magic cookie
346 $usage =~ s/_!_/__/g;
347 print $usage;
348 }
349
350 sub dprint {
351 print STDERR "# ", @_, "\n" if $main::d;
352 }
353
354 #
355 # $action is optional prefix for printing.
356 # $sharp says whether or not revisions should be kept.
357 # $ary is a ref to an array of [ $file, $rev ].
358 krisbash 1.1 #
359 # We always convert the depot paths to local paths for perf.
360 # (It works around a perf bug in older versions of sds.)
361 #
362 # Returns a ref to an array of strings to pass to -x.
363
364 sub sdarg {
365 my ($action, $sharp, $ary) = @_;
366 my @out = ();
367 my %files;
368 my $rc = "";
369
370 for my $file (@$ary) {
371 my $depot = $file->[0];
372 $files{lc $depot} = $file;
373 push(@out, "$depot\n");
374 }
375
376 # Now convert the results into a list of local paths. Anything
377 # that succeeds, edit it in the %files. Anything that fails to map
378 # gets left alone, and sd will generate the real error later.
379 krisbash 1.1
380 my $tempfile = CreateTempFile(@out);
381 my $curDepot = undef;
382 for my $line (`sd.exe -x $tempfile -s where -T _`) {
383 if ($line =~ m|^info:|) {
384 $curDepot = undef;
385 } elsif ($line =~ m|^info1: depotFile (.*)$|) {
386 $curDepot = $1;
387 } elsif ($line =~ m|^info1: path (.*)$|) {
388 my $curFile = $files{lc $curDepot};
389 if ($curFile) {
390 $curFile->[0] = $1;
391 dprint "$curDepot -> $1";
392 }
393 $curDepot = undef;
394 }
395 }
396 unlink $tempfile;
397
398 # Now rebuild the results based on the localized paths.
399 @out = ();
400 krisbash 1.1 for $file (values %files) {
401 push(@out, $file->[0]);
402 push(@out, "#" . $file->[1]) if $sharp;
403 push(@out, "\n");
404 }
405
406 \@out;
407 }
408
409 #
410 # $action is a command ("sync#", "edit", "add" and "delete")
411 #
412 # The revision number is stripped off the file specification
413 # unless the action itself ends in a # (namely, sync#).
414 #
415 # $ary is a ref to an array of [ $file, $rev ].
416
417 sub sdaction {
418 my ($action, $ary) = @_;
419 my $sharp = $action =~ s/#$//;
420
421 krisbash 1.1 if ($#$ary >= 0) {
422
423 my $args = sdarg($action, $sharp, $ary);
424
425 unless ($main::n) {
426 my $error = 0;
427 my $tempfile = CreateTempFile(@$args);
428 if (open(SD, "sd -x $tempfile -s $action |"))
429 {
430 my $line;
431 while ($line = <SD>) {
432 if ($line =~ /^(\S+): /) {
433 $error = 1 if $1 eq 'error';
434 print $' unless $1 eq 'exit';
435 }
436 }
437 close(SD);
438 }
439 unlink $tempfile;
440 die "error: sd failed; unpack abandoned\n" if $error;
441 }
442 krisbash 1.1 }
443 }
444
445 sub slurpfile {
446 my ($file, $type) = @_;
447 my @file;
448 if ($type =~ /binary|unicode/) {
449 open(B, $file) or die "error: cannot open $file for reading ($!)\n";
450 binmode(B);
451 local($/);
452 push(@file, <B>);
453 close(B);
454 } else {
455 open(I, $file) or die "error: cannot open $file for reading ($!)\n";
456 @file = <I>;
457 close(I);
458 }
459 @file;
460 }
461
462 sub spewfile {
463 krisbash 1.1 my ($file, $ary, $type) = @_;
464 if (!open(O, ">$file")) {
465 # Maybe the parent directory hasn't been created yet
466 my $dir = $file;
467 $dir =~ s/\//\\/g;
468 if ($dir =~ s/[^\\\/]+$//) {
469 system "md \"$dir\"" unless -e $dir; # let cmd.exe do the hard work
470 }
471 open(O, ">$file") or die "error: cannot open $file for writing ($!)\n";
472 }
473 binmode(O) if $main::x || $type =~ /binary|unicode/;
474 print O @$ary;
475 close(O);
476 }
477
478 sub GetUniqueName {
479 my $name = shift;
480 $name =~ s,^[/\\]*,,; # clean out leading slashes
481 $name = substr($name, length($main::CommonPrefix));
482 $name =~ s,^[/\\]*,,; # clean out leading slashes again
483
484 krisbash 1.1 if (defined($main::UniqueNames{lc $name}))
485 {
486 my $i = 1;
487 $i++ while $main::UniqueNames{lc "$name$i"};
488 $name .= $i;
489 }
490 $main::UniqueNames{lc $name} = 1;
491 $name;
492 }
493
494 sub CreateTempFile {
495 my $TEMP = $ENV{"TEMP"} || $ENV{"TMP"};
496 die "error: no TEMP directory" unless $TEMP;
497 $TEMP =~ s/\\$//; # avoid the \\ problem
498
499 $tempfile = "$TEMP\\bbpack.$$";
500 open(T, ">$tempfile") || die "error: Cannot create $tempfile\n";
501 my $success = print T @_;
502 $success = close(T) && $success;
503 unlink $tempfile, die "error: writing $tempfile ($!)\n" unless $success;
504 $tempfile;
505 krisbash 1.1 }
506
507 sub Remap {
508 my $path = shift;
509 if ($path =~ m#^\Q$main::fromDepot\E#i) {
510 substr($path, $[, length($main::fromDepot)) = $main::toDepot;
511 }
512 $path;
513 }
514
515 #
516 # $depotpath, $rev is the file to be edited/added.
517 # $cmd is "edit" or "add" (indicates where basefile comes from)
518 #
519
520 sub ApplyEdit {
521 my ($depotpath, $rev, $cmd, $type, $atime, $mtime) = @_;
522 my $destpath = $depotpath;
523 my $destfile;
524 my $where, $file;
525
526 krisbash 1.1 if ($main::w) {
527 $file = $depotpath; # for the purpose of GetUniqueName
528 } else {
529 $destpath = Remap($depotpath) if $main::m;
530 dprint "$depotpath -> $destpath" if $main::m;
531 local($/) = ""; # "sd where -T" uses paragraphs
532 foreach $line (`sd.exe where -T _ \"$destpath\" 2>&1`) {
533 undef $where, next if $line =~ m|^\.\.\. unmap|m;
534 $where = $1 if $line =~ m|^\.\.\. path (.+)|m;
535 }
536 die "error: cannot find local copy of $destpath\n" unless $where;
537 $destfile = $file = $where;
538 }
539 my @file;
540 my $bias = -1; # perl uses zero-based arrays but diff uses 1-based line numbers
541
542 if ($cmd eq 'add') {
543 @file = ();
544 $file = $destfile if $main::m;
545 } elsif ($cmd eq 'edit') {
546 my $src = $file;
547 krisbash 1.1 if ($main::v || $main::w || $main::m) {
548 dprint "sd$main::ExtraFlags print -q \"$depotpath#$rev\"";
549 $src = "sd$main::ExtraFlags print -q \"$depotpath#$rev\"|";
550 }
551 @file = slurpfile($src, $type);
552 } elsif ($cmd eq 'delete') {
553 if ($main::w) {
554 dprint "sd$main::ExtraFlags print -q \"$depotpath#$rev\"";
555 @file = slurpfile("sd$main::ExtraFlags print -q \"$depotpath#$rev\"|", $type);
556 } else {
557 @file = ();
558 }
559 }
560
561 my $unique;
562 if ($main::w || ($main::m && $cmd eq "edit")) { # Write the original, set up for new
563 $unique = GetUniqueName($file);
564 spewfile("$main::BeforeDir\\$unique", \@file, $type) unless $cmd eq 'add';
565 $file = "$main::AfterDir\\$unique";
566 }
567
568 krisbash 1.1 if ($cmd ne 'delete') {
569 # now read from <DATA> and apply the edits.
570 if ($type =~ /binary|unicode/) {
571 local($/) = "";
572 @file = (unpack("u", scalar(<DATA>)));
573 } else {
574 while (($line = <DATA>) ne "q\n") {
575 if ($line =~ /^a(\d+) (\d+)/) {
576 my @added = ();
577 my $count = $2;
578 while ($count--) {
579 push(@added, scalar(<DATA>));
580 }
581 splice(@file, $1 + $bias + 1, 0, @added); # +1 because it's "add", not "insert"
582 $bias += $2;
583 } elsif ($line =~ /^d(\d+) (\d+)/) {
584 splice(@file, $1 + $bias, $2);
585 $bias -= $2;
586 } else {
587 die "error: corrupted package trying to unpack $depotpath\n".
588 " expected a/d/q but got\n".
589 krisbash 1.1 " $line";
590 }
591 }
592
593 if ($type =~ /_nonewline/) {
594 chomp($file[$#file]);
595 }
596 }
597
598 if ($main::v) {
599 my @file2 = slurpfile($file, $type);
600 join("", @file) eq join("", @file2) or
601 die "error: $file does not match copy in package\n";
602 print "$file is okay\n";
603 } else {
604 spewfile($file, \@file, $type);
605 }
606
607 if ($cmd eq "edit" && $main::m) {
608 dprint "sd resolve3 $main::R \"$main::BeforeDir\\$unique\" \"$main::AfterDir\\$unique\" \"$destfile\" \"$destfile.out\"";
609 system("sd resolve3 $main::R \"$main::BeforeDir\\$unique\" \"$main::AfterDir\\$unique\" \"$destfile\" \"$destfile.out\"");
610 krisbash 1.1 if (-e "$destfile.out") {
611 unlink $destfile;
612 rename "$destfile.out", $destfile;
613 chmod 0666, $destfile;
614 } else {
615 warn "warning: $destfile merge cancelled by user; skipped\n";
616 }
617 unlink "$main::BeforeDir\\$unique";
618 unlink "$main::AfterDir\\$unique";
619 }
620
621 if ($main::T && $atime && $mtime) {
622 utime $atime, $mtime, $destfile;
623 }
624 }
625 }
626
627 sub IsDirectoryEmpty {
628 my $dir = shift;
629 my $empty = 1;
630 if (opendir(D, $dir)) {
631 krisbash 1.1 while ($file = readdir(D)) {
632 $empty = 0, last if $file ne '.' && $file ne '..';
633 }
634 closedir(D);
635 } else {
636 $empty = 0; # Wacky directory, pretend nonempty so we skip it
637 }
638 $empty;
639 }
640
641 $main::NextUniqueDir = 0;
642
643 sub GetNewTempDir {
644 my $TEMP = $ENV{"TEMP"} || $ENV{"TMP"};
645 die "error: no TEMP directory" unless $TEMP;
646
647 $TEMP =~ s/\\$//; # avoid the \\ problem
648
649 # Look for suitable "before" and "after" directories; we'll
650 # call them "bbtmp###".
651
652 krisbash 1.1 $TEMP .= "\\bbtmp";
653
654 while ($main::NextUniqueDir++ < 1000) {
655 my $try = "$TEMP$main::NextUniqueDir";
656 if (!-e $try && mkdir($try, 0777)) {
657 return $try;
658 }
659 if (-d _ && IsDirectoryEmpty($try)) {
660 return $try;
661 }
662 }
663 die "error: Too many ${TEMP}### directories\n";
664 }
665
666 sub CleanDir {
667 my $dir = shift;
668 if (defined($dir) && -e $dir) {
669 system "rd /q /s $dir";
670 }
671 }
672
673 krisbash 1.1 sub AccumulateCommonPrefix {
674 my $file = "/" . lc shift;
675
676 # Remove filename component
677 while ($file =~ s,[/\\][^/\\]*$,,) {
678 last unless defined $main::CommonPrefix;
679 last if substr($main::CommonPrefix, 0, length($file)) eq $file;
680 }
681
682 $main::CommonPrefix = $file;
683 }
684
685 #
686 # Okay, now initialize our globals.
687 #
688
689 $main::name = $0;
690 $main::name =~ s/.*[\/\\:]//;
691 $main::name =~ s/\.(bat|cmd)$//;
692
693 $main::A = 0;
694 krisbash 1.1 $main::B = 0;
695 $main::c = "default";
696 $main::d = 0;
697 $main::f = 0;
698 $main::l = 0;
699 $main::m = 0;
700 $main::n = 0;
701 $main::R = "";
702 $main::s = 0;
703 $main::u = 0;
704 $main::v = 0;
705 $main::w = 0;
706 $main::x = 0;
707 $main::T = 0;
708 $main::anyChanges = 0;
709
710 $main::BeforeDir = undef;
711 $main::AfterDir = undef;
712 %main::UniqueNames = ("" => 1); # preinit to avoid blank name
713 $main::ExtraFlags = "";
714 $main::fromDepot = undef;
715 krisbash 1.1 $main::toDepot = undef;
716 $main::CommonPrefix = undef;
717
718 #
719 # WORKAROUND TO WORK AROUND PERL BUG IN <DATA> HANDLING.
720 # Reopen ourselves and advance to the raw data.
721 #
722 open(DATA, $0);
723 0 until scalar(<DATA>) eq "__END__\n";
724
725 my %PackerProperties;
726
727 {
728 my $line;
729 while (($line = <DATA>) =~ /(.*?): (.*)/) {
730 if ($1 eq "Change Description") {
731 $PackerProperties{$1} .= $2."\n";
732 } else {
733 $PackerProperties{$1} = $2;
734 }
735 }
736 krisbash 1.1 $main::pack = delete $PackerProperties{Packager};
737 die "error: corrupted package\n" unless $line eq "\n" && $main::pack;
738 die "error: your version of perl doesn't support lines longer than 256 characters\n"
739 unless $PackerProperties{"PerlSniffTest"} eq "." x 256;
740 }
741
742 # If there is no command line and there is a BBUNPACKDEFCMD, use that
743 # variable instead.
744
745 if ($#ARGV < 0 && defined $ENV{"BBUNPACKDEFCMD"}) {
746 my $cmd = $ENV{"BBUNPACKDEFCMD"};
747 $cmd =~ s/^\s+//;
748 while ($cmd =~ s/^\s*(?:"([^"]*)"|([^"]\S*))\s*//) {
749 push(@ARGV, $+);
750 }
751 }
752
753 while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
754 my $switch = shift;
755 if ($switch eq '-d') {
756 $main::d++;
757 krisbash 1.1 } elsif ($switch eq '-f') {
758 $main::f++;
759 } elsif ($switch eq '-l') {
760 $main::l++;
761 } elsif ($switch eq '-m') {
762 $main::m++;
763 $main::fromDepot = shift;
764 $main::toDepot = shift;
765
766 if ($main::fromDepot !~ m#^//# ||
767 $main::toDepot !~ m#^//#) {
768 die "-m must be followed by two depot prefixes; type $name -? for help\n";
769 }
770
771 } elsif ($switch eq '-M') {
772 $main::m++;
773 $main::fromDepot = $main::toDepot = '/';
774 } elsif ($switch eq '-c') {
775 $main::c = shift;
776
777 if ($main::c !~ m#^[0-9]#) {
778 krisbash 1.1 die "-c must be followed by a changelist number; type $name -? for help\n";
779 }
780
781 } elsif ($switch eq '-A') {
782 die "only one instance of -A allowed; type $name -? for help\n" if $main::A;
783 $main::A++;
784 $main::AfterDir = shift || die "-A requires an argument; type $name -? for help\n";
785 } elsif ($switch eq '-B') {
786 die "only one instance of -B allowed; type $name -? for help\n" if $main::B;
787 $main::B++;
788 $main::BeforeDir = shift || die "-B requires an argument; type $name -? for help\n";
789 } elsif ($switch eq '-n') {
790 $main::n++;
791 } elsif ($switch eq '-R') {
792 $main::R = shift;
793 } elsif ($switch eq '-s') {
794 $main::s++;
795 } elsif ($switch eq '-u') {
796 $main::u++;
797 } elsif ($switch eq '-v') {
798 $main::v++;
799 krisbash 1.1 } elsif ($switch eq '-w') {
800 $main::w++;
801 } elsif ($switch eq '-x') {
802 $main::x++;
803 } elsif ($switch eq '-T') {
804 $main::T++;
805 } elsif ($switch eq '-?') {
806 Usage(); exit 1;
807 } else {
808 die "Invalid command line switch; type $name -? for help\n";
809 }
810 }
811
812 # Should be no command line options
813 die "Invalid command line; type $main::name -? for help\n" if $#ARGV >= 0;
814
815 die "Must specify an action; type -? for help\n"
816 unless $main::l || $main::s || $main::u || $main::v || $main::w;
817
818 # suppress -w (presumably from registered .bpk extension)
819 # if other actions found
820 krisbash 1.1 $main::w = 0
821 if $main::l || $main::s || $main::u || $main::v;
822
823
824 die "Cannot combine -m with -s\n" if $main::m && $main::s;
825 die "Cannot combine -m with -w\n" if $main::m && $main::w;
826
827 #
828 # -l wants some meta-information about the package.
829 #
830 if ($main::l) {
831 my $key;
832 foreach $key (split(/,/, "Comment,Client name,User name,Date,Change Description")) {
833 #
834 # Make sure to print blank properties for backwards compatability for
835 # anyone who parses the output.
836 #
837 if ($PackerProperties{$key}) {
838 map { print "$key: $_\n"; } split(/\n/, $PackerProperties{$key});
839 } else {
840 print "$key: $PackerProperties{$key}\n";
841 krisbash 1.1 }
842 }
843 print "\n";
844 }
845
846 #
847 # See which files are open on the client. This also establishes whether
848 # the server is up and the user has proper permissions.
849 #
850 my %OpenedFiles;
851
852 if ($main::s || $main::u) {
853 # Intentionally let errors through to stderr
854 # Use -s to suppress stderr if no files are opened
855 foreach my $line (`sd.exe -s opened -c $main::c`) {
856 next if $line =~ m,^warning: , || $line =~ m,^exit: ,;
857 next if $line =~ m!^(error|warning): File\(s\) not opened !;
858 $line =~ m,^info: (//.*?)#(\d+|none),
859 or die "error: Cannot parse output of 'sd opened -c $main::c'\n";
860 $OpenedFiles{$1} = 1;
861 dprint "opened $1#$2";
862 krisbash 1.1 $main::anyChanges = 1 if $' =~ /$main::c/;
863 }
864 }
865
866 die "error: changelist $main::c is not empty; use -f -u to unpack anyway\n"
867 if $main::anyChanges && $main::u && !$main::f;
868
869 #
870 # The -w and -m options require us to set up some directories for unpacking.
871 #
872 if ($main::w || $main::m)
873 {
874 $main::BeforeDir = GetNewTempDir() unless defined $main::BeforeDir;
875 $main::AfterDir = GetNewTempDir() unless defined $main::AfterDir;
876 $main::ExtraFlags = " -p $PackerProperties{'Source Server Address'}";
877 }
878
879 #
880 # Go through each file in the package and perform an appropriate
881 # action on it.
882 #
883 krisbash 1.1
884 {
885 my @sync, @edit, @add, @delete;
886
887 my $line;
888 while (($line = <DATA>) =~ m|^(//.*?)#(\d+) (\S+) (\S+)|) {
889
890 # $1 = depot path
891 # $2 = rev
892 # $3 = action
893 # $4 = filetype (not currently used)
894
895 if ($main::l) {
896 print $line;
897 }
898
899 # If sync'ing or unpacking, then the file had better not be open
900 # since we're the ones who are going to open it.
901
902 die "error: $1 is already open on client; to merge, use the -M option\n"
903 if defined $OpenedFiles{$1} && ($main::s || ($main::u && !$main::m));
904 krisbash 1.1
905 # If sync'ing, add to list of files that need to be sync'd.
906 #
907 # If unpacking, then add to the appropriate list so we know
908 # how to prepare the file for action.
909
910 if ($main::s) {
911 push(@sync, [ $1, $3 eq 'add' ? 'none' : $2 ]);
912 }
913 if ($main::u) {
914
915 my $path = $1;
916 if ($main::m) {
917 $path = Remap($1);
918 }
919
920 if ($path) {
921 if ($3 eq 'edit') {
922 push(@edit, [ $path, $2 ]);
923 } elsif ($3 eq 'add') {
924 push(@add, [ $path, $2 ]);
925 krisbash 1.1 } elsif ($3 eq 'delete') {
926 push(@delete, [ $path, $2 ]);
927 } else {
928 die "error: corrupted package\n";
929 }
930 }
931 }
932
933 AccumulateCommonPrefix($1);
934
935 }
936 die "error: corrupted package\n" unless $line eq "\n";
937
938 $main::CommonPrefix =~ s,^[/\\]+,,; # clean off leading slashes
939
940 if ($main::s || $main::u) {
941
942 #
943 # Make sure that no files being added currently exist.
944 #
945 if ($#add >= 0) {
946 krisbash 1.1 my $args = sdarg(undef, undef, \@add);
947 my $tempfile = CreateTempFile(@$args);
948 if (`sd.exe -x $tempfile have 2>nul`) {
949 unlink $tempfile;
950 die "error: adds in this package already exist on client\n";
951 }
952 unlink $tempfile;
953 }
954
955 #
956 # Make sure that files being edited are the correct versions.
957 #
958 if (($#edit >= 0 || $#delete >= 0) && !$main::s && !$main::m) {
959 my @have = (@edit, @delete);
960 my %have;
961 my $file;
962 my $args = sdarg(undef, undef, \@have);
963 my $tempfile = CreateTempFile(@$args);
964 dprint "sd have @$args";
965 for $file (`sd.exe -x $tempfile have`) {
966 $file =~ m|(//.*?)#(\d+) - (.*)| or die "error: parsing output of 'sd have'\n";
967 krisbash 1.1 dprint "have $1#$2 - $3";
968 #
969 # Store the have under both the depot path and the local path.
970 #
971 $have{lc $1} = $2;
972 $have{lc $3} = $2;
973 }
974 unlink $tempfile;
975 die "error: files to be edited/deleted do not exist on client\n" if $?;
976 for $file (@have) {
977 die "error: wrong version of $file->[0] on client\n"
978 if $have{lc $file->[0]} ne $file->[1];
979 }
980 }
981
982 sdaction("sync#", \@sync);
983 sdaction("edit -c $main::c", \@edit);
984 # Do not do the adds yet; wait until after the edits have been applied
985 sdaction("delete -c $main::c", \@delete);
986 }
987
988 krisbash 1.1 #
989 # Now go extract the actual files.
990 #
991 if (!$main::n && ($main::u || $main::v || $main::w)) {
992 my $line;
993 # " *" because some editors trim trailing spaces
994 while (($line = <DATA>) =~ m|^(//.*?)#(\d+) (\S+) (\S+) *(\d*) *(\d*)|) {
995 ApplyEdit($1, $2, $3, $4, $5, $6);
996 }
997 }
998
999 # Okay, now do the adds now that the output files have been created
1000 sdaction("add -c $main::c", \@add);
1001 }
1002
1003 if ($main::w) {
1004 my $windiff = $ENV{"BBDIFF"} || $ENV{"SDDIFF"} || "windiff";
1005 system("$windiff \"$main::BeforeDir\" \"$main::AfterDir\"");
1006 }
1007
1008 CleanDir($main::BeforeDir) unless $main::B;
1009 krisbash 1.1 CleanDir($main::AfterDir) unless $main::A;
1010
1011 __END__
1012 PerlSniffTest: ................................................................................................................................................................................................................................................................
1013 Packager: bbpack
1014 Client name: GIRISHJO-WIN8-130514165419
1015 User name: REDMOND\girishjo
1016 Source Server Address: TK5SDSERVWIN13.sys-wingroup.ntdev.corp.microsoft.com:2002
1017 Server address: TK5SDSERVWIN13.sys-wingroup.ntdev.corp.microsoft.com:2002
1018 Date: 2013/09/20 18:19:32
1019
1020 //depot/fbl_srv2_obi_mi_dev_r2_r1/admin/wmi/winomi/base/log.c#11 edit text
1021
1022 //depot/fbl_srv2_obi_mi_dev_r2_r1/admin/wmi/winomi/base/log.c#11 edit text 1376954826 1379726281
1023 a198 4
1024 #if defined(CONFIG_OS_WINDOWS)
1025 #include <share.h>
1026 #endif
1027
1028 d208 1
1029 a208 2
1030 krisbash 1.1 _os = _fsopen(path, "a", _SH_DENYWR);
1031 if (_os == NULL)
1032 d215 1
1033 a215 2
1034 _os = _wfsopen(path, L"a", _SH_DENYWR);
1035 if (_os == NULL)
1036 q
|