Fetch.pm 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. # ex:ts=8 sw=4:
  2. # $OpenBSD: Fetch.pm,v 1.12 2017/04/14 16:43:40 espie Exp $
  3. #
  4. # Copyright (c) 2010-2013 Marc Espie <espie@openbsd.org>
  5. #
  6. # Permission to use, copy, modify, and distribute this software for any
  7. # purpose with or without fee is hereby granted, provided that the above
  8. # copyright notice and this permission notice appear in all copies.
  9. #
  10. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. use strict;
  18. use warnings;
  19. package DPB::Task::Checksum;
  20. our @ISA = qw(DPB::Task::Fork);
  21. sub new
  22. {
  23. my ($class, $fetcher, $status) = @_;
  24. bless {fetcher => $fetcher, fetch_status => $status}, $class;
  25. }
  26. sub run
  27. {
  28. my ($self, $core) = @_;
  29. my $job = $core->job;
  30. $job->{logger}->run_as(
  31. sub {
  32. $self->redirect_fh($job->{logfh}, $job->{log});
  33. });
  34. exit(!$job->{file}->checksum($job->{file}->tempfilename));
  35. }
  36. sub finalize
  37. {
  38. my ($self, $core) = @_;
  39. $self->SUPER::finalize($core);
  40. my $job = $core->job;
  41. if ($core->{status} != 0) {
  42. # XXX if we continued, and it failed, then maybe we
  43. # got a stupid error message instead, so retry for
  44. # full size.
  45. if (defined $self->{fetcher}->{initial_sz}) {
  46. $job->{fetcher}->run_as(
  47. sub {
  48. unlink($job->{file}->tempfilename);
  49. });
  50. } else {
  51. shift @{$job->{sites}};
  52. }
  53. return $job->bad_file($self->{fetcher}, $core);
  54. }
  55. $job->{fetcher}->run_as(
  56. sub {
  57. rename($job->{file}->tempfilename, $job->{file}->filename);
  58. });
  59. print {$job->{logfh}} "Renamed to ", $job->{file}->filename, "\n";
  60. $job->{file}->cache;
  61. my $sz = $job->{file}->{sz};
  62. if (defined $self->{fetcher}->{initial_sz}) {
  63. $sz -= $self->{fetcher}->{initial_sz};
  64. }
  65. my $fh = $job->{file}->logger->append("fetch/good");
  66. my $elapsed = $self->{fetcher}->elapsed;
  67. print $fh $self->{fetcher}{site}.$job->{file}->{short}, " in ",
  68. $elapsed, "s ";
  69. if ($elapsed != 0) {
  70. print $fh "(", sprintf("%.2f", $sz / $elapsed / 1024), "KB/s)";
  71. }
  72. print $fh "\n";
  73. close $fh;
  74. return 1;
  75. }
  76. # Fetching stuff is almost a normal job
  77. package DPB::Task::Fetch;
  78. our @ISA = qw(DPB::Task::Clocked);
  79. sub stopped_clock
  80. {
  81. my ($self, $gap) = @_;
  82. # note that we're missing time
  83. $self->{got_suspended}++;
  84. $self->SUPER::stopped_clock($gap);
  85. }
  86. sub new
  87. {
  88. my ($class, $job) = @_;
  89. if (@{$job->{sites}}) {
  90. my $o = bless { site => $job->{sites}[0]}, $class;
  91. my $sz = (stat $job->{file}->tempfilename)[7];
  92. if (defined $sz) {
  93. $o->{initial_sz} = $sz;
  94. }
  95. return $o;
  96. } else {
  97. undef;
  98. }
  99. }
  100. sub run
  101. {
  102. my ($self, $core) = @_;
  103. my $job = $core->job;
  104. my $site = $self->{site};
  105. $site =~ s/^\"(.*)\"$/$1/;
  106. $job->{logger}->run_as(
  107. sub {
  108. $self->redirect($job->{log});
  109. });
  110. if ($job->{file}{sz} == 0) {
  111. print STDERR "No size in distinfo\n";
  112. exit(1);
  113. }
  114. my $ftp = OpenBSD::Paths->ftp;
  115. my @cmd = ('-C', '-o', $job->{file}->tempfilename, '-v',
  116. $site.$job->{file}->{short});
  117. if ($ftp =~ /\s/) {
  118. unshift @cmd, split(/\s+/, $ftp);
  119. } else {
  120. unshift @cmd, $ftp;
  121. }
  122. print STDERR "===> Trying $site\n";
  123. print STDERR join(' ', @cmd), "\n";
  124. # run ftp;
  125. $core->shell->nochroot->exec(@cmd);
  126. }
  127. sub finalize
  128. {
  129. my ($self, $core) = @_;
  130. $self->SUPER::finalize($core);
  131. my $job = $core->job;
  132. if ($job->{file}->checksize($job->{file}->tempfilename)) {
  133. $job->new_checksum_task($self, $core->{status});
  134. } else {
  135. if ($job->{file}{sz} == 0) {
  136. $job->{sites} = [];
  137. return $job->bad_file($self, $core);
  138. }
  139. # Fetch exited okay, but the file is not the right size
  140. if ($core->{status} == 0 ||
  141. # definite error also if file is too large
  142. stat($job->{file}->tempfilename) &&
  143. (stat _)[7] > $job->{file}->{sz}) {
  144. $job->{fetcher}->unlink($job->{file}->tempfilename);
  145. }
  146. # if we got suspended, well, might have to retry same site
  147. if (!$self->{got_suspended}) {
  148. shift @{$job->{sites}};
  149. }
  150. return $job->bad_file($self, $core);
  151. }
  152. }
  153. package DPB::Job::Fetch;
  154. our @ISA = qw(DPB::Job::Normal);
  155. use File::Path;
  156. use File::Basename;
  157. sub new_fetch_task
  158. {
  159. my $self = shift;
  160. my $task = DPB::Task::Fetch->new($self);
  161. if ($task) {
  162. push(@{$self->{tasks}}, $task);
  163. $self->{tries}++;
  164. return 1;
  165. } else {
  166. return 0;
  167. }
  168. }
  169. sub bad_file
  170. {
  171. my ($job, $task, $core) = @_;
  172. my $fh = $job->{file}->logger->append("fetch/bad");
  173. print $fh $task->{site}.$job->{file}->{short}, "\n";
  174. if ($job->new_fetch_task) {
  175. $core->{status} = 0;
  176. return 1;
  177. } else {
  178. $core->{status} = 1;
  179. return 0;
  180. }
  181. }
  182. sub new_checksum_task
  183. {
  184. my ($self, $fetcher, $status) = @_;
  185. push(@{$self->{tasks}}, DPB::Task::Checksum->new($fetcher, $status));
  186. }
  187. sub new
  188. {
  189. my ($class, $file, $e, $fetcher, $logger) = @_;
  190. my $job = bless {
  191. sites => [@{$file->{site}}],
  192. file => $file,
  193. tasks => [],
  194. endcode => $e,
  195. fetcher => $fetcher,
  196. logger => $logger,
  197. log => $file->logger->make_distlogs($file),
  198. }, $class;
  199. $job->{logfh} = $job->{logger}->open('>>', $job->{log});
  200. print {$job->{logfh}} ">>> From ", $file->fullpkgpath, "\n";
  201. $job->{fetcher}->make_path(File::Basename::dirname($file->filename));
  202. $job->{watched} = DPB::Watch->new(
  203. $job->{fetcher}->file($file->tempfilename),
  204. $file->{sz}, undef, $job->{started});
  205. $job->new_fetch_task;
  206. return $job;
  207. }
  208. sub name
  209. {
  210. my $self = shift;
  211. return '<'.$self->{file}->{name}."(#".$self->{tries}.")";
  212. }
  213. sub watched
  214. {
  215. my ($self, $current, $core) = @_;
  216. my $w = $self->{watched};
  217. my $diff = $w->check_change($current);
  218. my $msg = $w->percent_message . $w->frozen_message($diff);
  219. return $self->kill_on_timeout($diff, $core, $msg);
  220. }
  221. sub get_timeout
  222. {
  223. my ($self, $core) = @_;
  224. return $core->fetch_timeout;
  225. }
  226. 1;