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.

187 lines
5.5 KiB

  1. package PPM::Compat;
  2. use strict;
  3. use Data::Dumper;
  4. use XML::Parser;
  5. our $VERSION = '3.00';
  6. use constant PPM_PORT_PERL => 14533;
  7. sub read_ppm_xml {
  8. my ($file, $conf, $reps, $inst, $cmd) = @_;
  9. my $parser = XML::Parser->new(Style => 'Tree');
  10. my $tree = $parser->parsefile($file);
  11. die "Error: node PPMCONFIG not found in ppm.xml"
  12. unless $tree->[0] eq 'PPMCONFIG';
  13. $tree = $tree->[1];
  14. my $parse_elem = sub {
  15. my $ref = shift;
  16. my $tree = shift;
  17. my $key = shift;
  18. my $req = shift;
  19. my $content = shift; $content = 2 unless defined $content;
  20. my $cref = shift;
  21. my $i;
  22. for ($i=0; $i<@$tree; $i++) { last if $tree->[$i] eq $key }
  23. die "error: missing $key element in ppm.xml"
  24. if $req && $i >= @$tree;
  25. return if $i >= @$tree;
  26. $cref->($ref, $key, $content, $tree->[$i+1]) if $cref;
  27. $ref->{$key} = $tree->[$i+1][$content] unless $cref;
  28. };
  29. my $parse_attr = sub {
  30. my $ref = shift;
  31. my $tree = shift;
  32. my $key = shift;
  33. my $req = shift;
  34. my $keephash = shift;
  35. my $cref = shift;
  36. die "error: missing $key attribute in ppm.xml"
  37. if $req && not exists $tree->[0]{$key};
  38. $cref->($ref, $key, $keephash, $tree->[0]{$key}) if $cref;
  39. $ref->{$key} = $keephash ? $tree->[0] : $tree->[0]{$key} unless $cref;
  40. };
  41. $inst->{PPMPRECIOUS} = [];
  42. $parse_elem->($inst, $tree, 'PPMPRECIOUS', 0);
  43. for (split ';', $inst->{PPMPRECIOUS}) {
  44. push @{$inst->{precious}}, $_;
  45. }
  46. delete $inst->{PPMPRECIOUS};
  47. for (my $i=0; $i<@$tree; $i++) {
  48. my $k = $tree->[$i];
  49. my $v = $tree->[$i+1];
  50. if ($k eq 'OPTIONS') {
  51. my $tmp = $^O eq 'MSWin32' ? 'C:\Temp' : '/tmp';
  52. @$conf{qw(BUILDDIR DOWNLOADSTATUS)} = ($tmp, 16384);
  53. $parse_attr->($conf, $v, 'BUILDDIR', 0);
  54. $parse_attr->($conf, $v, 'DOWNLOADSTATUS', 0);
  55. @$conf{qw(tempdir downloadbytes)} =
  56. ($conf->{BUILDDIR}, $conf->{DOWNLOADSTATUS});
  57. delete @$conf{qw(BUILDDIR DOWNLOADSTATUS)};
  58. $cmd->{IGNORECASE} = 1;
  59. $parse_attr->($cmd, $v, 'IGNORECASE', 0);
  60. $cmd->{'case-sensitivity'} = $cmd->{IGNORECASE} ? '0' : '1';
  61. delete $cmd->{IGNORECASE};
  62. $inst->{ROOT} = '';
  63. $parse_attr->($inst, $v, 'ROOT', 0);
  64. $inst->{root} = $inst->{ROOT} if $inst->{ROOT};
  65. delete $inst->{ROOT};
  66. }
  67. elsif ($k eq 'PLATFORM') {
  68. @$inst{qw(CPU OSVALUE OSVERSION)} = ('x86', $^O, '0,0,0,0');
  69. $parse_attr->($inst, $v, 'CPU', 0);
  70. $parse_attr->($inst, $v, 'OSVALUE', 1);
  71. $parse_attr->($inst, $v, 'OSVERSION', 0);
  72. }
  73. elsif ($k eq 'REPOSITORY') {
  74. my %r;
  75. $parse_attr->(\%r, $v, 'LOCATION', 1);
  76. $parse_attr->(\%r, $v, 'NAME', 1);
  77. $parse_attr->(\%r, $v, 'USERNAME', 0);
  78. $parse_attr->(\%r, $v, 'PASSWORD', 0);
  79. fix_location(\$r{LOCATION});
  80. $reps->{$r{NAME}} = {
  81. url => $r{LOCATION},
  82. (defined $r{USERNAME} ? (username => $r{USERNAME}) : ()),
  83. (defined $r{PASSWORD} ? (password => $r{PASSWORD}) : ()),
  84. };
  85. }
  86. elsif ($k eq 'PACKAGE') {
  87. my %r;
  88. $parse_attr->(\%r, $v, 'NAME', 1);
  89. $parse_elem->(\%r, $v, 'LOCATION', 1);
  90. $parse_elem->(\%r, $v, 'INSTPACKLIST', 1);
  91. $parse_elem->(\%r, $v, 'INSTROOT', 1);
  92. $parse_elem->(\%r, $v, 'INSTDATE', 1);
  93. fix_location(\$r{LOCATION});
  94. # Regenerates the PPD: I wish XML::Parser could do this...
  95. my $cb = sub {
  96. my ($ref, $key, $index, $tree) = @_;
  97. my $i;
  98. for ($i=0; $i<@$tree; $i++) { last if $tree->[$i] eq 'SOFTPKG' }
  99. my $ppd = generate_ppd($tree->[$i], $tree->[$i+1]);
  100. $ref->{ppd} = $ppd if $ppd;
  101. };
  102. $parse_elem->(\%r, $v, 'INSTPPD', 1, 2, $cb);
  103. next if ($r{NAME} eq 'libwin32' and $^O ne 'MSWin32');
  104. $inst->{$r{NAME}} = \%r;
  105. }
  106. }
  107. }
  108. sub ppm_repository {
  109. 'http://ppm-ia.ActiveState.com/PPM/ppmserver.plex?urn:/PPM/Server/SQL'
  110. }
  111. sub fix_location {
  112. my $ref = shift;
  113. if ($$ref =~ m{^soap://}i and $$ref =~ m{ActiveState}) {
  114. $$ref = 'http://ppm.ActiveState.com/PPMPackages/5.6';
  115. }
  116. $$ref =~ s{soap://}{http://}i;
  117. if ($$ref =~ m{ActiveState.com/cgibin/PPM/ppmserver.pl\?}i) {
  118. $$ref = ppm_repository();
  119. }
  120. }
  121. sub generate_ppd {
  122. my $tagname = shift;
  123. my $tree = shift;
  124. return undef unless $tagname;
  125. my @lines;
  126. my $line = '<' . $tagname;
  127. if (%{$tree->[0] || {}}) {
  128. for my $key (keys %{$tree->[0]}) {
  129. my $val = $tree->[0]{$key};
  130. $line .= qq{ $key="$val"};
  131. }
  132. }
  133. $line .= '>';
  134. $line .= xml_encode(ref($tree->[2]) ? "\n" : $tree->[2]);
  135. push @lines, $line;
  136. my $start = ref($tree->[2]) ? 1 : 3;
  137. for (my $j=$start; $j<@$tree; $j++) {
  138. next unless $tree->[$j] =~ /^[A-Z]+$/;
  139. push @lines, generate_ppd($tree->[$j], $tree->[$j+1]);
  140. }
  141. push @lines, "</$tagname>\n";
  142. wantarray ? @lines : join '', @lines;
  143. }
  144. sub xml_encode {
  145. local $_ = shift || '';
  146. s/</&lt;/g;
  147. s/>/&gt;/g;
  148. $_;
  149. }
  150. sub batchify {
  151. my $exe = shift;
  152. my $perl = shift || $^X;
  153. my $batch = $exe;
  154. $batch =~ s/\.PL$//;
  155. $batch =~ s/\.pl$//;
  156. if ($^O eq 'MSWin32') {
  157. $batch .= '.bat';
  158. }
  159. # A bug in system() forces us to convert $exe to an 8.3 pathname on
  160. # Windows. Presumably there is no workaround in Unix.
  161. if ($^O eq 'MSWin32') {
  162. require Win32;
  163. $exe = Win32::GetShortPathName($exe);
  164. }
  165. system($perl, $exe, @_);
  166. unlink($exe) || die "can't delete $exe: $!";
  167. return $batch;
  168. }