+(* Copyright (C) 2005, HELM Team.
+ *
+ * This file is part of HELM, an Hypertextual, Electronic
+ * Library of Mathematics, developed at the Computer Science
+ * Department, University of Bologna, Italy.
+ *
+ * HELM is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * HELM is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HELM; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * For details, see the HELM World-Wide-Web page,
+ * http://helm.cs.unibo.it/
+ *)
+
+(* $Id$ *)
+
+open Printf
+
+let debug = false
+let debug_prerr = if debug then prerr_endline else ignore
+
+module HGT = Http_getter_types;;
+module HG = Http_getter;;
+module UM = UriManager;;
+
+
+let strip_xpointer s = Pcre.replace ~pat:"#.*$" s ;;
+
+let safe_buri_of_suri suri =
+ try
+ UM.buri_of_uri (UM.uri_of_string suri)
+ with
+ UM.IllFormedUri _ -> suri
+
+let one_step_depend cache_of_processed_baseuri suri dbtype dbd =
+ let buri = safe_buri_of_suri suri in
+ if Hashtbl.mem cache_of_processed_baseuri buri then
+ []
+ else
+ begin
+ Hashtbl.add cache_of_processed_baseuri buri true;
+ let query =
+ let buri = buri ^ "/" in
+ let buri = HSql.escape dbtype dbd buri in
+ let obj_tbl = MetadataTypes.obj_tbl () in
+ if HSql.isMysql dbtype dbd then
+ sprintf ("SELECT source, h_occurrence FROM %s WHERE "
+ ^^ "h_occurrence REGEXP '"^^
+ "^%s\\([^/]+\\|[^/]+#xpointer.*\\)$"^^"'")
+ obj_tbl buri
+ else
+ begin
+ sprintf ("SELECT source, h_occurrence FROM %s WHERE "
+ ^^ "REGEXP(h_occurrence, '"^^
+ "^%s\\([^/]+\\|[^/]+#xpointer.*\\)$"^^"')")
+ obj_tbl buri
+ (* implementation with vanilla ocaml-sqlite3
+ HLog.debug "Warning SELECT without REGEXP";
+ sprintf
+ ("SELECT source, h_occurrence FROM %s WHERE " ^^
+ "h_occurrence LIKE '%s%%' " ^^ HSql.escape_string_for_like)
+ obj_tbl buri*)
+ end
+ in
+ try
+ let rc = HSql.exec dbtype dbd query in
+ let l = ref [] in
+ HSql.iter rc (
+ fun row ->
+ match row.(0), row.(1) with
+ | Some uri, Some occ when
+ Filename.dirname (strip_xpointer occ) = buri ->
+ l := uri :: !l
+ | _ -> ());
+ let l = List.sort Pervasives.compare !l in
+ HExtlib.list_uniq l
+ with
+ exn -> raise exn (* no errors should be accepted *)
+ end
+
+let db_uris_of_baseuri buri =
+ let dbd = LibraryDb.instance () in
+ let dbtype =
+ if Helm_registry.get_bool "matita.system" then HSql.Library else HSql.User
+ in
+ let query =
+ let buri = buri ^ "/" in
+ let buri = HSql.escape dbtype dbd buri in
+ let obj_tbl = MetadataTypes.name_tbl () in
+ if HSql.isMysql dbtype dbd then
+ sprintf ("SELECT source FROM %s WHERE "
+ ^^ "source REGEXP '^%s[^/]*(#xpointer.*)?$'") obj_tbl buri
+ else
+ begin
+ sprintf ("SELECT source FROM %s WHERE "
+ ^^ "REGEXP(source, '^%s[^/]*\\(#xpointer.*\\)?$')") obj_tbl buri
+ end
+ in
+ try
+ let rc = HSql.exec dbtype dbd query in
+ let l = ref [] in
+ HSql.iter rc (
+ fun row ->
+ match row.(0) with
+ | Some uri when Filename.dirname (strip_xpointer uri) = buri ->
+ l := uri :: !l
+ | _ -> ());
+ let l = List.sort Pervasives.compare !l in
+ HExtlib.list_uniq l
+ with
+ exn -> raise exn (* no errors should be accepted *)
+;;
+
+let close_uri_list cache_of_processed_baseuri uri_to_remove =
+ let dbd = LibraryDb.instance () in
+ let dbtype =
+ if Helm_registry.get_bool "matita.system" then HSql.Library else HSql.User
+ in
+ (* to remove an uri you have to remove the whole script *)
+ let buri_to_remove =
+ HExtlib.list_uniq
+ (List.fast_sort Pervasives.compare
+ (List.map safe_buri_of_suri uri_to_remove))
+ in
+ (* cleand the already visided baseuris *)
+ let buri_to_remove =
+ List.filter
+ (fun buri ->
+ if Hashtbl.mem cache_of_processed_baseuri buri then false
+ else true)
+ buri_to_remove
+ in
+ (* now calculate the list of objects that belong to these baseuris *)
+ let uri_to_remove =
+ try
+ List.fold_left
+ (fun acc buri ->
+ let inhabitants = HG.ls ~local:true (buri ^ "/") in
+ let inhabitants = List.filter
+ (function HGT.Ls_object _ -> true | _ -> false)
+ inhabitants
+ in
+ let inhabitants = List.map
+ (function
+ | HGT.Ls_object e -> buri ^ "/" ^ e.HGT.uri
+ | _ -> assert false)
+ inhabitants
+ in
+ inhabitants @ acc)
+ [] buri_to_remove
+ with HGT.Invalid_URI u ->
+ HLog.error ("We were listing an invalid buri: " ^ u);
+ exit 1
+ in
+ let uri_to_remove_from_db =
+ List.fold_left
+ (fun acc buri ->
+ let dbu = db_uris_of_baseuri buri in
+ dbu @ acc
+ ) [] buri_to_remove
+ in
+ let uri_to_remove = uri_to_remove @ uri_to_remove_from_db in
+ let uri_to_remove =
+ HExtlib.list_uniq (List.sort Pervasives.compare uri_to_remove) in
+ (* now we want the list of all uri that depend on them *)
+ let depend =
+ List.fold_left
+ (fun acc u -> one_step_depend cache_of_processed_baseuri u dbtype dbd @ acc)
+ [] uri_to_remove
+ in
+ let depend =
+ HExtlib.list_uniq (List.fast_sort Pervasives.compare depend)
+ in
+ uri_to_remove, depend
+;;
+
+let rec close_db cache_of_processed_baseuri uris next =
+ match next with
+ | [] -> uris
+ | l ->
+ let uris, next = close_uri_list cache_of_processed_baseuri l in
+ close_db cache_of_processed_baseuri uris next @ uris
+;;
+
+let cleaned_no = ref 0;;
+
+ (** TODO repellent code ... *)
+let moo_root_dir = lazy (
+ let url =
+ List.assoc "cic:/matita/"
+ (List.map
+ (fun pair ->
+ match
+ Str.split (Str.regexp "[ \t\r\n]+") (HExtlib.trim_blanks pair)
+ with
+ | a::b::_ -> a, b
+ | _ -> assert false)
+ (Helm_registry.get_list Helm_registry.string "getter.prefix"))
+ in
+ String.sub url 7 (String.length url - 7))
+;;
+
+let clean_baseuris ?(verbose=true) buris =
+ let cache_of_processed_baseuri = Hashtbl.create 1024 in
+ let dbd = LibraryDb.instance () in
+ let dbtype =
+ if Helm_registry.get_bool "matita.system" then HSql.Library else HSql.User
+ in
+ Hashtbl.clear cache_of_processed_baseuri;
+ let buris = List.map Http_getter_misc.strip_trailing_slash buris in
+ debug_prerr "clean_baseuris called on:";
+ if debug then
+ List.iter debug_prerr buris;
+ let l = close_db cache_of_processed_baseuri [] buris in
+ let l = HExtlib.list_uniq (List.fast_sort Pervasives.compare l) in
+ let l = List.map UriManager.uri_of_string l in
+ debug_prerr "clean_baseuri will remove:";
+ if debug then
+ List.iter (fun u -> debug_prerr (UriManager.string_of_uri u)) l;
+ List.iter
+ (fun baseuri ->
+ try
+ let obj_file =
+ LibraryMisc.obj_file_of_baseuri ~must_exist:false ~writable:true ~baseuri
+ in
+ HExtlib.safe_remove obj_file ;
+ HExtlib.safe_remove
+ (LibraryMisc.lexicon_file_of_baseuri
+ ~must_exist:false ~writable:true ~baseuri) ;
+ HExtlib.rmdir_descend (Filename.chop_extension obj_file)
+ with Http_getter_types.Key_not_found _ -> ())
+ (HExtlib.list_uniq (List.fast_sort Pervasives.compare
+ (List.map (UriManager.buri_of_uri) l @ buris)));
+ List.iter
+ (let last_baseuri = ref "" in
+ fun uri ->
+ let buri = UriManager.buri_of_uri uri in
+ if buri <> !last_baseuri then
+ begin
+ if not (Helm_registry.get_bool "matita.verbose") then
+ (print_endline ("matitaclean " ^ buri ^ "/");flush stdout)
+ else
+ HLog.message ("Removing: " ^ buri ^ "/*");
+ last_baseuri := buri
+ end;
+ LibrarySync.remove_obj uri
+ ) l;
+ if HSql.isMysql dbtype dbd then
+ begin
+ cleaned_no := !cleaned_no + List.length l;
+ if !cleaned_no > 30 && HSql.isMysql dbtype dbd then
+ begin
+ cleaned_no := 0;
+ List.iter
+ (function table ->
+ ignore (HSql.exec dbtype dbd ("OPTIMIZE TABLE " ^ table)))
+ [MetadataTypes.name_tbl (); MetadataTypes.rel_tbl ();
+ MetadataTypes.sort_tbl (); MetadataTypes.obj_tbl();
+ MetadataTypes.count_tbl()]
+ end
+ end