try ignore (String.find str substr); true
with Invalid_string -> false
-(* Check if a Koji (completed successfully) build exists. *)
(* Not helped by the fact that the 'koji' tool actively
* resists automation: RHBZ#760924.
*)
-let koji_build_exists =
- let state_complete = contains_substring "State: COMPLETE" in
- let state_other = contains_substring "State: " in
+
+(* Get build state. *)
+let rec koji_build_state verrel =
+ fst (koji_build_state_task verrel)
+
+(* Get build state and task ID. *)
+and koji_build_state_task =
+ let state = Pcre.regexp "State: (\\w+)" in
+ let task_id = Pcre.regexp "Task: (\\d+)" in
let no_such_build = contains_substring "No such build" in
fun verrel ->
- (* Once a build is known to be complete, memoize it. *)
+ (* For speed, if a build is complete memoize it. *)
let key = sprintf "koji_build_complete_%s" verrel in
if memory_exists key then
- true
+ `Complete, None
else (
- let rec loop () =
- let out = shout "timeout 120 koji buildinfo %s 2>&1 ||:" verrel in
- if state_complete out then
- true
- else if state_other out then
- false
- else if no_such_build out then
- false
- else (
- eprintf "%s\n" out;
- eprintf "koji_build_exists: unknown output\nretrying ...\n%!";
- loop ()
- )
- in
- let r = loop () in
- memory_set key "1";
- r
+ let out = shout "timeout 120 koji buildinfo %s 2>&1 ||:" verrel in
+ if no_such_build out then
+ failwith (sprintf "koji_build_state_task: %s: no such build" verrel);
+ let state =
+ try
+ let subs = Pcre.exec ~rex:state out in
+ match Pcre.get_substring subs 1 with
+ | "BUILDING" -> `Building
+ | "COMPLETE" -> `Complete
+ | "DELETED" -> `Deleted
+ | "FAILED" -> `Failed
+ | "CANCELED" -> `Canceled
+ | sub ->
+ failwith (sprintf "koji_build_state_task: %s: unknown build state '%s'"
+ verrel sub)
+ with
+ Not_found ->
+ failwith (sprintf "koji_build_state_task: %s: no build state found"
+ verrel) in
+ let task =
+ try
+ let subs = Pcre.exec ~rex:task_id out in
+ Some (int_of_string (Pcre.get_substring subs 1))
+ with
+ Not_found -> None in
+
+ if state == `Complete then
+ memory_set key "1";
+
+ state, task
)
(* Perform a Koji build and wait until it finishes. If it fails,
contains_substring "Name or service not known" in
let completed_successfully = contains_substring "completed successfully" in
let failed = contains_substring "FAILED" in
- fun pkg branch ->
+ fun ?(wait = true) pkg branch ->
let repodir = fedora_repo pkg branch in
- let out = shout "cd %s && fedpkg build 2>&1 ||:" repodir in
- let task_id =
- try
- let subs = Pcre.exec ~rex:created_task out in
- int_of_string (Pcre.get_substring subs 1)
- with Not_found ->
- failwith "could not find task ID in fedpkg build output" in
- let rec loop out =
- if name_or_service_not_known out then (
- let out =
- shout "cd %s && koji watch-task %d 2>&1 ||:" repodir task_id in
- loop out
- )
- else if completed_successfully out then
- ()
- else if failed out then (
- eprintf "%s\n%!" out;
- failwith "koji build failed"
- )
- else
- failwith (sprintf "koji_build: unknown output: %s" out)
+ let out =
+ shout "
+ cd %s
+ fedpkg build%s 2>&1 ||:
+ " repodir (if not wait then " --nowait" else "")
in
- loop out
+ if wait then (
+ let task_id =
+ try
+ let subs = Pcre.exec ~rex:created_task out in
+ int_of_string (Pcre.get_substring subs 1)
+ with Not_found ->
+ failwith "could not find task ID in fedpkg build output" in
+ let rec loop out =
+ if name_or_service_not_known out then (
+ let out =
+ shout "cd %s && koji watch-task %d 2>&1 ||:" repodir task_id in
+ loop out
+ )
+ else if completed_successfully out then
+ ()
+ else if failed out then (
+ eprintf "%s\n%!" out;
+ failwith "koji build failed"
+ )
+ else
+ failwith (sprintf "koji_build: unknown output: %s" out)
+ in
+ loop out
+ )
let koji_wait_repo =
let successfully_waited = contains_substring "Successfully waited" in
(* Perform a complete Fedora OCaml rebuild, in build order. *)
+open Unix
open Printf
open Goaljobs
(* Goal: rebuild all packages. *)
let rec goal all () =
- List.iter (fun pkg -> require (rebuilt pkg)) source_packages
+ List.iter (fun pkg -> require (rebuild_started pkg)) source_packages
(* Goal: That 'package' has been rebuilt and exists in Koji. *)
and rebuilt pkg =
+ let specfile = fedora_specfile pkg branch in
+
+ (* Note: verrel may change as we go along, so don't assign it to
+ * variable.
+ *)
+
+ (* Note the target must be both of these because the old verrel
+ * could exist as a koji build without it having been part of the
+ * rebuild.
+ *)
+ target (file_contains_string specfile rebuild_name &&
+ koji_build_state (fedora_verrel pkg branch) == `Complete);
+
+ (* Start the rebuild. *)
+ require (rebuild_started pkg);
+
+ (* Wait for the build state to reach a conclusion. *)
+ let rec loop () =
+ match koji_build_state (fedora_verrel pkg branch) with
+ | `Building ->
+ sleep 30;
+ loop ()
+ | `Complete ->
+ ()
+ | `Deleted ->
+ failwith (sprintf "rebuild of package %s: deleted" pkg)
+ | `Failed ->
+ failwith (sprintf "rebuild of package %s: failed" pkg)
+ | `Canceled ->
+ failwith (sprintf "rebuild of package %s: canceled" pkg)
+ in
+ loop ();
+
+ (* Wait for the build to appear in Koji repo. *)
+ koji_wait_repo koji_target (fedora_verrel pkg branch)
+
+(* Goal: The rebuild of the package has started, but we haven't waited
+ * for it to finish.
+ *)
+and rebuild_started pkg =
let deps = List.assoc pkg pkg_deps in
let specfile = fedora_specfile pkg branch in
* rebuild.
*)
target (file_contains_string specfile rebuild_name &&
- koji_build_exists (fedora_verrel pkg branch));
+ (match koji_build_state (fedora_verrel pkg branch) with
+ | `Building | `Complete -> true
+ | `Deleted | `Failed | `Canceled -> false));
- (* All dependent packages must have been done first. *)
+ (* All dependent packages must have been fully rebuilt and in the
+ * repo first.
+ *)
List.iter (fun dep -> require (rebuilt dep)) deps;
(* A local test build must succeed. *)
require (local_build_succeeded pkg);
- (* Rebuild the package in Koji. *)
- koji_build pkg branch;
-
- (* Wait for the build to appear in Koji repo. Note verrel may change. *)
- koji_wait_repo koji_target (fedora_verrel pkg branch)
+ (* Rebuild the package in Koji, but don't wait. *)
+ koji_build ~wait:false pkg branch
and local_build_succeeded pkg =
(* The specfile must have been updated. *)