(* dir.ml - Don Yang (uguu.org) 04/23/06 *) (* Remove duplicates in a sorted list *) let rec uniq_recurse hd tl = match tl with a::b -> if hd = a then uniq_recurse hd b else hd::(uniq_recurse a b) | [] -> [hd];; let uniq x = match x with a::b -> uniq_recurse a b | [] -> [];; (* Find common root in two paths *) let rec common_root a_parts b_parts = match a_parts, b_parts with a_hd::a_tl, b_hd::b_tl -> if a_hd = b_hd then a_hd::(common_root a_tl b_tl) else [] | _, _ -> [];; (* Return a sublist with first few elements removed *) let rec remove_list_prefix prefix_len r = if prefix_len > 0 then remove_list_prefix (prefix_len - 1) (List.tl r) else r;; (* Given two path parts, insert delta to get from first path to second path *) let rec insert_delta_recurse root b_hd b_tl = match b_tl with x::y -> (Path.join_parts (root @ b_hd @ [x])) :: (insert_delta_recurse root (b_hd @ [x]) y) | [] -> [];; let insert_delta a b = let a_parts = Path.split_to_parts a in let b_parts = Path.split_to_parts b in let root = common_root a_parts b_parts in insert_delta_recurse root [] (remove_list_prefix (List.length root) b_parts);; (* Given a list of relative paths, return list of paths with dependents inserted. *) let rec insert_dependents_recurse last_path remaining_paths = match remaining_paths with a::b -> (insert_delta last_path a) @ (insert_dependents_recurse a b) | [] -> [];; let insert_dependents paths = insert_dependents_recurse "" (uniq (List.sort compare paths));; (* Given a list of paths, create all dependents *) let create_forest paths = List.iter (fun d -> try Unix.mkdir d 0o750 with Unix.Unix_error (Unix.EEXIST, _, _) -> ()) (insert_dependents paths);; (* List a directory recursively for all files and attributes *) let rec enumerate_recurse root in_array index = try let file = root ^ Path.separator_str ^ (in_array.(index)) in let s = Unix.stat file in match s.Unix.st_kind with Unix.S_DIR -> List.rev_append ((file, s)::(enumerate_recurse file (Sys.readdir file) 0)) (enumerate_recurse root in_array (index + 1)) | Unix.S_REG -> (file, s)::(enumerate_recurse root in_array (index + 1)) | _ -> (enumerate_recurse root in_array (index + 1)) with Unix.Unix_error _ -> (enumerate_recurse root in_array (index + 1)) | Invalid_argument _ -> [];; let enumerate path = enumerate_recurse path (Sys.readdir path) 0;; (* List top level directory only *) let rec enumerate_no_recurse_r root in_array index = try let file = root ^ Path.separator_str ^ (in_array.(index)) in let s = Unix.stat file in match s.Unix.st_kind with Unix.S_REG | Unix.S_DIR -> (file, s)::(enumerate_no_recurse_r root in_array (index + 1)) | _ -> (enumerate_no_recurse_r root in_array (index + 1)) with Unix.Unix_error _ -> (enumerate_no_recurse_r root in_array (index + 1)) | Invalid_argument _ -> [];; let enumerate_no_recurse path = enumerate_no_recurse_r path (Sys.readdir path) 0;; (* Split file list to two lists *) let rec extract_dirs file_list = match file_list with (file, attr)::rest -> if attr.Unix.st_kind = Unix.S_DIR then file::(extract_dirs rest) else extract_dirs rest | [] -> [];; let rec extract_files file_list = match file_list with (file, attr)::rest -> if attr.Unix.st_kind = Unix.S_REG then (file, attr)::(extract_files rest) else extract_files rest | [] -> [];; let split_file_list file_list = ((extract_dirs file_list), (extract_files file_list));; (* Replace root directories in file list *) let replace_root src_root dst_root file_list = List.map (fun x -> let new_path = Path.replace_root src_root dst_root (fst x) in if new_path = "" then failwith "replace_root failed"; (new_path, (snd x))) file_list;;