(** Read package data from day10's html directory *) let list_package_names ~html_dir = let p_dir = Filename.concat html_dir "p" in if Sys.file_exists p_dir && Sys.is_directory p_dir then Sys.readdir p_dir |> Array.to_list |> List.filter (fun name -> let path = Filename.concat p_dir name in Sys.is_directory path) |> List.sort String.compare else [] let compare_versions v1 v2 = (* Simple version comparison - compare segments numerically where possible *) let parse v = String.split_on_char '.' v |> List.map (fun s -> try `Int (int_of_string s) with _ -> `Str s) in let rec cmp l1 l2 = match l1, l2 with | [], [] -> 0 | [], _ -> -1 | _, [] -> 1 | `Int a :: t1, `Int b :: t2 -> let c = Int.compare a b in if c <> 0 then c else cmp t1 t2 | `Str a :: t1, `Str b :: t2 -> let c = String.compare a b in if c <> 0 then c else cmp t1 t2 | `Int _ :: _, `Str _ :: _ -> -1 | `Str _ :: _, `Int _ :: _ -> 1 in cmp (parse v2) (parse v1) (* Descending order *) let list_package_versions ~html_dir ~name = let pkg_dir = Filename.concat (Filename.concat html_dir "p") name in if Sys.file_exists pkg_dir && Sys.is_directory pkg_dir then Sys.readdir pkg_dir |> Array.to_list |> List.filter (fun version -> let path = Filename.concat pkg_dir version in Sys.is_directory path) |> List.sort compare_versions else [] let list_packages ~html_dir = list_package_names ~html_dir |> List.concat_map (fun name -> list_package_versions ~html_dir ~name |> List.map (fun version -> (name, version))) let package_has_docs ~html_dir ~name ~version = let path = Filename.concat html_dir (Filename.concat "p" (Filename.concat name version)) in Sys.file_exists path && Sys.is_directory path let docs_path ~name ~version = Printf.sprintf "/docs/p/%s/%s/" name version