dpb 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. #! /usr/bin/perl
  2. # ex:ts=8 sw=4:
  3. # $OpenBSD: dpb,v 1.121 2016/05/21 12:20:10 espie Exp $
  4. #
  5. # Copyright (c) 2010-2013 Marc Espie <espie@openbsd.org>
  6. #
  7. # Permission to use, copy, modify, and distribute this software for any
  8. # purpose with or without fee is hereby granted, provided that the above
  9. # copyright notice and this permission notice appear in all copies.
  10. #
  11. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  12. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  13. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  14. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  15. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  16. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  17. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  18. use strict;
  19. use warnings;
  20. my $ports1;
  21. use FindBin;
  22. BEGIN {
  23. $ports1 = $ENV{PORTSDIR} || '/usr/ports';
  24. }
  25. use lib ("$ports1/infrastructure/lib", "$FindBin::Bin/../lib");
  26. package main;
  27. use DPB::State;
  28. use DPB::PkgPath;
  29. use DPB::Core;
  30. use DPB::Core::Init;
  31. use DPB::HostProperties;
  32. use DPB::Shell;
  33. use DPB::Host;
  34. use DPB::Vars;
  35. use DPB::PortInfo;
  36. use DPB::Engine;
  37. use DPB::PortBuilder;
  38. use DPB::Reporter;
  39. use OpenBSD::Error;
  40. use DPB::Job;
  41. use DPB::Grabber;
  42. use DPB::Trace;
  43. my $keep_going = 1;
  44. my $starttime = time();
  45. sub show_days
  46. {
  47. my $days = shift;
  48. if ($days == 0) {
  49. return "";
  50. } elsif ($days == 1) {
  51. return "1 day ";
  52. } else {
  53. return "$days days ";
  54. }
  55. }
  56. sub show_time
  57. {
  58. my $secs = int(shift);
  59. my $mn = int($secs/60);
  60. my $hours = int($mn/60);
  61. my $days= int($hours/24);
  62. $secs %= 60;
  63. $mn %= 60;
  64. $hours %= 24;
  65. return show_days($days).sprintf("%02d:%02d:%02d", $hours, $mn, $secs);
  66. }
  67. sub report
  68. {
  69. return DPB::Util->time2string(time)." [$$]".
  70. ($keep_going ? "" : " STOPPED!").
  71. " running for ".show_time(time-$starttime)."\n";
  72. }
  73. sub affinityclass
  74. {
  75. if (DPB::Core::Init->hostcount > 1 ||
  76. DPB::HostProperties->has_mem) {
  77. require DPB::Affinity;
  78. return "DPB::Affinity";
  79. } else {
  80. require DPB::AffinityStub;
  81. return "DPB::AffinityStub";
  82. }
  83. }
  84. my $subdirlist = {};
  85. DPB::Trace->setup(\%SIG);
  86. my $state = DPB::State->new('dpb');
  87. $state->handle_options;
  88. $state->{all} = !$state->is_interactive;
  89. my $default_handling =
  90. sub {
  91. my ($pkgpath, $weight) = @_;
  92. if (defined $weight) {
  93. $state->heuristics->set_weight($pkgpath);
  94. }
  95. $pkgpath->add_to_subdirlist($subdirlist);
  96. $state->{all} = 0;
  97. };
  98. $state->interpret_paths(@{$state->{paths}}, @ARGV,
  99. sub {
  100. &$default_handling(@_);
  101. });
  102. $state->interpret_paths(@{$state->{ipaths}},
  103. sub {
  104. &$default_handling(@_);
  105. my $p = shift;
  106. $p->{wantinstall} = 1;
  107. });
  108. $state->interpret_paths(@{$state->{cpaths}},
  109. sub {
  110. my $p = shift;
  111. $state->{dontclean}{$p->pkgpath} = 1;
  112. });
  113. $state->interpret_paths(@{$state->{xpaths}},
  114. sub {
  115. my $p = shift;
  116. $p->{dontjunk} = 1;
  117. });
  118. if ($state->opt('a')) {
  119. $state->{all} = 1;
  120. }
  121. $state->{build_once} //= $state->{all};
  122. DPB::Core->reap;
  123. $state->handle_build_files;
  124. $state->{builder} = DPB::PortBuilder->new($state);
  125. $state->{affinity} = affinityclass()->new($state, join("/", $state->logdir, "affinity"));
  126. $state->{engine} = DPB::Engine->new($state);
  127. $state->{grabber} = DPB::Grabber->new($state, \&handle_non_waiting_jobs);
  128. my $reporter = DPB::Reporter->new($state, "main", "DPB::Core", $state->engine);
  129. DPB::Trace->set_reporter($reporter);
  130. print "Waiting for hosts to finish STARTUP...";
  131. while (!DPB::Core->avail) {
  132. DPB::Core->reap;
  133. sleep 1;
  134. }
  135. # XXX placeholder
  136. sub reread_config
  137. {
  138. }
  139. my $core = DPB::Core->get;
  140. print "ready on ", $core->hostname, "\n";
  141. if (!$state->{fetch_only} && !$state->{scan_only} &&
  142. DPB::Core::Init->hostcount == 1 && $core->prop->{jobs} == 1) {
  143. $core->clone->mark_ready;
  144. $state->{opt}{e} = 1;
  145. }
  146. my $dump = DPB::Util->make_hot($state->logger->append('dump'));
  147. my $debug = DPB::Util->make_hot($state->logger->append('debug'));
  148. DPB::Trace->set_logger($debug);
  149. sub handle_non_waiting_jobs
  150. {
  151. my $checked = 0;
  152. my $force_report = 0;
  153. my $reaped = DPB::Core->reap;
  154. $keep_going = !-e $state->logdir."/stop";
  155. if (DPB::Core->avail > 1) {
  156. $state->engine->recheck_errors;
  157. }
  158. if (DPB::Core->avail) {
  159. $state->engine->check_buildable;
  160. $checked = 1;
  161. }
  162. while ($keep_going && DPB::Core->avail && $state->engine->can_build) {
  163. $force_report = 1;
  164. if (!$state->engine->start_new_job) {
  165. my $q = $state->engine->{tobuild}{queue};
  166. print $debug "SPINNING ON MAIN\n";
  167. while (my ($k, $v) = each %{$q->{o}}) {
  168. print $debug $k, "=>", $v->logname, "\n";
  169. }
  170. last;
  171. }
  172. }
  173. while ($keep_going && DPB::Core::Fetcher->avail &&
  174. $state->engine->can_fetch) {
  175. if (!$checked) {
  176. $state->engine->check_buildable;
  177. $checked = 1;
  178. }
  179. $force_report = 1;
  180. if (!$state->engine->start_new_fetch) {
  181. print $debug "SPINNING ON FETCH\n";
  182. my $q = $state->engine->{tofetch}{queue};
  183. while (my ($k, $v) = each %{$q->{o}}) {
  184. print $debug $k, "=>", $v->logname, "\n";
  185. }
  186. last;
  187. }
  188. }
  189. DPB::Core->log_concurrency(time(), $state->{concurrent});
  190. DPB::Core->wake_jobs;
  191. if ($state->want_report) {
  192. $reporter->report($force_report);
  193. }
  194. }
  195. sub main_loop
  196. {
  197. while (1) {
  198. while (1) {
  199. handle_non_waiting_jobs();
  200. if (!DPB::Core->running) {
  201. last if !$keep_going;
  202. if (!$state->engine->can_build) {
  203. $state->engine->check_buildable(1);
  204. if (!$state->engine->can_build) {
  205. last;
  206. }
  207. }
  208. }
  209. if (DPB::Core->running) {
  210. DPB::Core->reap_wait;
  211. }
  212. if ($state->{fetch_only}) {
  213. if (!DPB::Core::Fetcher->running &&
  214. (!$keep_going || !$state->engine->can_fetch)) {
  215. $state->engine->check_buildable;
  216. if (!$state->engine->can_fetch) {
  217. last;
  218. }
  219. }
  220. }
  221. }
  222. if ($state->may_ask_for_commands) {
  223. } elsif (!$state->opt('q') || !$state->engine->recheck_errors) {
  224. last;
  225. }
  226. }
  227. }
  228. my $skip = undef;
  229. if (keys %$subdirlist > 0) {
  230. $state->grabber->grab_subdirs($core, $subdirlist, $skip);
  231. }
  232. if ($state->{all} && !$state->{random}) {
  233. # when restarting interrupted dpb,
  234. # find the most important paths first
  235. my $list = $state->engine->find_best($state->{dependencies_log}, 25);
  236. # if we have them, list them before the full ports tree walk.
  237. if (@$list > 0) {
  238. $skip = {};
  239. for my $name (@$list) {
  240. DPB::PkgPath->new($name)->add_to_subdirlist($skip);
  241. }
  242. $state->grabber->grab_subdirs($core, $skip, undef, 1);
  243. }
  244. }
  245. $state->grabber->complete_subdirs($core, $skip);
  246. if ($state->{all}) {
  247. $state->grabber->grab_subdirs($core, undef, $skip);
  248. }
  249. $state->grabber->complete_subdirs($core);
  250. # give back "our" core to the pool.
  251. my $occupied = 0;
  252. $state->grabber->forget_cache;
  253. if ($state->{all}) {
  254. $state->engine->dump_dependencies;
  255. if (!$state->defines('NO_HISTORY')) {
  256. if ($state->grabber->expire_old_distfiles($core,
  257. $state->opt('e'))) {
  258. $occupied = 1;
  259. }
  260. }
  261. }
  262. if (!$state->opt('e') && !$occupied) {
  263. $core->mark_ready;
  264. }
  265. DPB::PkgPath->sanity_check($state);
  266. $state->engine->check_buildable;
  267. if ($state->{scan_only}) {
  268. # very shortened loop
  269. $reporter->report;
  270. if (DPB::Core->running) {
  271. DPB::Core->reap_wait;
  272. }
  273. } else {
  274. # and let's wait for all jobs now.
  275. DPB::Core->start_clock($reporter);
  276. main_loop();
  277. }
  278. $reporter->reset;
  279. DPB::Core->cleanup;
  280. print "Elapsed time=", show_time(time-$starttime),"\n";
  281. print $state->engine->report;
  282. $state->engine->end_dump($state->logger->append('dump'));
  283. $state->engine->smart_dump($state->logger->append('summary'));