structure AptQuery :> APT_QUERY = struct type info = { name : string, section : string, descr : string, installed : bool } fun validName s = CharVector.all (fn ch => Char.isAlphaNum ch orelse ch = #"_" orelse ch = #"-" orelse ch = #".") s andalso (size s > 0 andalso String.sub (s, 0) <> #"-") fun query {node, pkg = name} = let val _ = if validName name then () else raise Fail "Invalid package name" val proc = Unix.execute ("/usr/bin/apt-cache", ["show", name]) val inf = Unix.textInstreamOf proc fun loop (section, descr) = case TextIO.inputLine inf of NONE => (section, descr) | SOME line => if size line >= 9 andalso String.substring (line, 0, 9) = "Section: " then loop (SOME (String.substring (line, 9, size line - 10)), descr) else if size line >= 13 andalso String.substring (line, 0, 13) = "Description: " then loop (section, SOME (String.substring (line, 13, size line - 14))) else loop (section, descr) in case loop (NONE, NONE) of (SOME section, SOME descr) => let val _ = Unix.reap proc val installed = OS.Process.isSuccess (OS.Process.system ("DOMTOOL_USER=hcoop /usr/local/bin/domtool-admin package " ^ Init.nodeName node ^ " " ^ name ^ " >/dev/null 2>/dev/null")) in SOME {name = name, section = section, descr = descr, installed = installed} end | _ => (Unix.reap proc; NONE) end end