Add libguestfs upstream build rules.
[goaljobs-goals.git] / fedora.ml
1 (* Various useful functions for handling Fedora packages & rebuilds. *)
2
3 open ExtString
4 open Printf
5
6 open Goaljobs
7
8 (* Repo dir, etc. *)
9 let fedora_dir = Sys.getenv "HOME" // "d/fedora"
10 let fedora_repo pkg branch = fedora_dir // pkg // branch
11 let fedora_specfile pkg branch =
12   sprintf "%s/%s.spec" (fedora_repo pkg branch) pkg
13
14 (* Get the current version of a package. *)
15 let fedora_verrel pkg branch =
16   shout "
17     cd %s
18     fedpkg verrel
19   " (fedora_repo pkg branch)
20
21 (* Note most of these assume that the package is already cloned
22  * under ~/d/fedora using:
23  *
24  * cd ~/d/fedora
25  * fedpkg clone -B pkgname
26  *)
27
28 (* Take a list of Fedora source packages and work out the dependencies
29  * (only within the list of source packages).  Returns a list of
30  * (package, [list of deps...])
31  *)
32 let dependencies branch source_packages =
33   (* For each source package, get the list of binary packages that it
34    * provides.  XXX Not sure if this is totally technically correct, but
35    * it seems to work.
36    *)
37   let bin_to_src =
38     List.concat (
39       List.map (
40         fun pkg ->
41           let provides =
42             shlines "rpmspec -q --provides %s | awk '{print $1}'"
43               (fedora_specfile pkg branch) in
44           List.map (fun bin -> (bin, pkg)) provides
45       ) source_packages
46     ) in
47
48   (* For each package, get the list of build requires that appear
49    * elsewhere in the list of packages.
50    *)
51   let mem dep = List.mem dep source_packages in
52
53   List.map (
54     fun pkg ->
55       let deps =
56         shlines "rpmspec -q --buildrequires %s | awk '{print $1}'"
57           (fedora_specfile pkg branch) in
58       let deps = List.map (
59         fun dep ->
60           try List.assoc dep bin_to_src
61           with Not_found -> "xxx" (* filtered out in next line *)
62       ) deps in
63       let deps = Utils.sort_uniq (List.filter mem deps) in
64       (* eprintf "%s <- %s\n" pkg (String.concat " " deps); *)
65       pkg, deps
66   ) source_packages
67
68 let contains_substring substr str =
69   try ignore (String.find str substr); true
70   with Invalid_string -> false
71
72 (* Check if a Koji (completed successfully) build exists. *)
73 (* Not helped by the fact that the 'koji' tool actively
74  * resists automation: RHBZ#760924.
75  *)
76 let koji_build_exists =
77   let state_complete = contains_substring "State: COMPLETE" in
78   let state_other = contains_substring "State: " in
79   let no_such_build = contains_substring "No such build" in
80   fun verrel ->
81     (* Once a build is known to be complete, memoize it. *)
82     let key = sprintf "koji_build_complete_%s" verrel in
83     if memory_exists key then
84       true
85     else (
86       let rec loop () =
87         let out = shout "timeout 120 koji buildinfo %s 2>&1 ||:" verrel in
88         if state_complete out then
89           true
90         else if state_other out then
91           false
92         else if no_such_build out then
93           false
94         else (
95           eprintf "%s\n" out;
96           eprintf "koji_build_exists: unknown output\nretrying ...\n%!";
97           loop ()
98         )
99       in
100       let r = loop () in
101       memory_set key "1";
102       r
103     )
104
105 (* Perform a Koji build and wait until it finishes.  If it fails,
106  * throw an exception.
107  *)
108 let koji_build =
109   let created_task = Pcre.regexp "Created task: (\\d+)" in
110   let name_or_service_not_known =
111     contains_substring "Name or service not known" in
112   let completed_successfully = contains_substring "completed successfully" in
113   let failed = contains_substring "FAILED" in
114   fun pkg branch ->
115     let repodir = fedora_repo pkg branch in
116     let out = shout "cd %s && fedpkg build 2>&1 ||:" repodir in
117     let task_id =
118       try
119         let subs = Pcre.exec ~rex:created_task out in
120         int_of_string (Pcre.get_substring subs 1)
121       with Not_found ->
122         failwith "could not find task ID in fedpkg build output" in
123     let rec loop out =
124       if name_or_service_not_known out then (
125         let out =
126           shout "cd %s && koji watch-task %d 2>&1 ||:" repodir task_id in
127         loop out
128       )
129       else if completed_successfully out then
130         ()
131       else if failed out then (
132         eprintf "%s\n%!" out;
133         failwith "koji build failed"
134       )
135       else
136         failwith (sprintf "koji_build: unknown output: %s" out)
137     in
138     loop out
139
140 let koji_wait_repo =
141   let successfully_waited = contains_substring "Successfully waited" in
142   fun target verrel ->
143     let out = shout "koji wait-repo %s --build=%s 2>&1 ||:" target verrel in
144     if successfully_waited out then
145       ()
146     else
147       failwith (sprintf "koji_wait_repo: unknown output: %s" out)