(* Various useful functions for handling Fedora packages & rebuilds. *) open ExtString open Printf open Goaljobs open Config (* Get the current version of a package. *) let fedora_verrel pkg branch = shout " cd %s fedpkg verrel " (fedora_repo pkg branch) (* Note most of these assume that the package is already cloned * under ~/d/fedora using: * * cd ~/d/fedora * fedpkg clone -B pkgname *) (* Take a list of Fedora source packages and work out the dependencies * (only within the list of source packages). Returns a list of * (package, [list of deps...]) *) let dependencies branch source_packages = (* For each source package, get the list of binary packages that it * provides. XXX Not sure if this is totally technically correct, but * it seems to work. *) let bin_to_src = List.concat ( List.map ( fun pkg -> let provides = shlines "rpmspec -q --provides %s | awk '{print $1}'" (fedora_specfile pkg branch) in List.map (fun bin -> (bin, pkg)) provides ) source_packages ) in (* For each package, get the list of build requires that appear * elsewhere in the list of packages. *) let mem dep = List.mem dep source_packages in List.map ( fun pkg -> let deps = shlines "rpmspec -q --buildrequires %s | awk '{print $1}'" (fedora_specfile pkg branch) in let deps = List.map ( fun dep -> try List.assoc dep bin_to_src with Not_found -> "xxx" (* filtered out in next line *) ) deps in let deps = Utils.sort_uniq (List.filter mem deps) in (* eprintf "%s <- %s\n" pkg (String.concat " " deps); *) pkg, deps ) source_packages let contains_substring substr str = try ignore (String.find str substr); true with Invalid_string -> false (* Not helped by the fact that the 'koji' tool actively * resists automation: RHBZ#760924. *) (* XXX koji_build_state verrel: If you do a build and it fails, then * do another build without bumping the release field, 'koji buildinfo' * seems to always return the failed build, at least until the second * build completes. This means the code below fails. Unclear how it * can be fixed, but best to always bump the release to avoid the * problem. *) (* 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 -> (* For speed, if a build is complete memoize it. *) let key = sprintf "koji_build_complete_%s" verrel in if memory_exists key then `Complete, None else ( let out = shout "timeout 120 koji buildinfo %s 2>&1 ||:" verrel in if no_such_build out then `No_such_build, None else ( 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, * throw an exception. *) let koji_build = let created_task = Pcre.regexp "Created task: (\\d+)" in let name_or_service_not_known = contains_substring "Name or service not known" in let completed_successfully = contains_substring "completed successfully" in let failed = contains_substring "FAILED" in fun ?(wait = true) ?side_tag pkg branch -> let repodir = fedora_repo pkg branch in let out = shout " cd %s fedpkg build%s%s 2>&1 " repodir (if not wait then " --nowait" else "") (match side_tag with None -> "" | Some t -> " --target " ^ t) in if not wait then ( (* Just check the task was created. *) if not (Pcre.pmatch ~rex:created_task out) then ( failwith "fedpkg build: build failed to start" ) ) else ( 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 ( 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 fun target verrel -> let out = shout "koji wait-repo %s --build=%s 2>&1 ||:" target verrel in if successfully_waited out then () else failwith (sprintf "koji_wait_repo: unknown output: %s" out)