123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315(*********************************************************************************)(* Stog *)(* *)(* Copyright (C) 2012-2015 INRIA All rights reserved. *)(* Author: Maxence Guesdon, INRIA Saclay *)(* *)(* This program 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, version 3 of the License. *)(* *)(* This program 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 this program; if not, write to the Free Software *)(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA *)(* 02111-1307 USA *)(* *)(* As a special exception, you have permission to link this program *)(* with the OCaml compiler and distribute executables, as long as you *)(* follow the requirements of the GNU GPL in regard to all of the *)(* software in the executable aside from the OCaml compiler. *)(* *)(* Contact: Maxence.Guesdon@inria.fr *)(* *)(*********************************************************************************)(** *)openStog.Types;;openLwt;;moduleXdiff=Xmldiff;;letsleep_duration=2.0;;letdebug=matchSys.getenv"STOG_SERVER_DEBUG"with"1"->funs->Lwt_io.writeLwt_io.stderrs|_->fun_->Lwt.return_unit|exception_->fun_->Lwt.return_unittypestate={stog:stog;stog_modules:(moduleStog.Engine.Module)list;stog_errors:stringlist;stog_warnings:stringlist;doc_dates:floatStog.Path.Map.t;busy:bool;}letrun_stog?docsstate=debug"Running stog\n">>=fun_->letstog=state.stoginleterrors=ref[]inletwarnings=ref[]inletreporterppf=letreportsrclevel~overkmsgf=letk_=over();k()inletwith_lochtagskppffmt=letloc=matchtagswith|None->None|Sometags->Logs.Tag.findStog.Log.loc_tagtagsinletloc=matchlocwith|None->""|Somel->Xtmpl.Xml.string_of_loclinFormat.kfprintfkppf("%a%s @["^^fmt^^"@]@.")Logs.pp_header(level,h)locinmsgf@@fun?header?tagsfmt->letb=Buffer.create256inletppfb=Format.formatter_of_bufferbinletk_x=letstr=Format.pp_print_flushppfb();Buffer.contentsbin(matchlevelwith|Logs.Warning->warnings:=str::!warnings|Logs.Error->errors:=str::!errors|_->());Format.pp_print_stringppfstr;kxinwith_locheadertagsk_ppfbfmtin{Logs.report=report}inLogs.set_reporter(reporter(Format.std_formatter));Lwt.catch(fun()->letmodules=matchdocs,state.stog_moduleswithSome_,((_::_)asl)->l|None,_|_,[]->Stog.Init.init_modulesstoginletstog=matchdocswithNone->Stog.Info.computestog|Some_->stoginletst_docs=matchdocswithNone->Stog.Types.Doc_set.empty|Someset->setinletstog_state={Stog.Engine.st_stog=stog;st_modules=modules;st_docs=st_docs;}inLwt_preemptive.detach(Stog.Engine.run~use_cache:false)stog_state>>=funstog_state->letstate={statewithstog=stog_state.Stog.Engine.st_stog;stog_modules=stog_state.Stog.Engine.st_modules;stog_errors=state.stog_errors@(List.rev!errors);stog_warnings=state.stog_warnings@(List.rev!warnings);}inLwt.returnstate)(function|Stog.Types.Path_trie.Already_presentpath->Stog.Log.err(funm->m"Doc path already present: %s"(String.concat"/"path));Lwt.returnstate|e->letstate={statewithstog_errors=state.stog_errors@(List.rev((Printexc.to_stringe)::!errors));stog_warnings=List.rev!warnings;}inLwt.returnstate)letrecwatch_for_changecurrent_stateon_updateon_error=Lwt.catch(fun()->debug(Printf.sprintf"Thread for %s "(match!current_statewithNone->"??"|Somest->st.stog.stog_dir))>>=fun()->debug(Printf.sprintf"sleeping for %.2f\n"sleep_duration)>>=fun()->Lwt_unix.sleepsleep_duration>>=fun()->debug"watch for changes... ">>=fun_->match!current_statewithNone->watch_for_changecurrent_stateon_updateon_error|Somestatewhenstate.busy->watch_for_changecurrent_stateon_updateon_error|Somestate->letold_stog=state.stoginletdoc_list=Stog.Types.doc_liststate.stoginletread_errors=ref[]inletf(acc_dates,docs,stog)(doc_id,doc)=Stog.Deps.last_dep_date_with_filesstogdoc>>=function|None->Lwt.return(acc_dates,docs,stog)|Somedate->(*prerr_endline ("date for "^file);*)letprev_date=tryStog.Path.Map.finddoc.doc_pathacc_dateswithNot_found->date-.1.inifdate<=prev_datethenLwt.return(acc_dates,docs,stog)elseletdoc=matchdoc.doc_parentwithSome_->(* doc coming from computation of another doc *){docwithdoc_out=None}|None->(** FIXME: Use a Lwt version of Io.doc_of_file *)letfile=Filename.concatstog.stog_dirdoc.doc_srcintryStog.Io.doc_of_filestogfilewithe->letmsg=matchewithFailuremsg|Sys_errormsg->msg|_->Printexc.to_stringeinread_errors:=msg::!read_errors;docinLwt.return(Stog.Path.Map.adddoc.doc_pathdateacc_dates,Stog.Types.Doc_set.adddoc_iddocs,Stog.Types.set_docstogdoc_iddoc)inLwt_list.fold_left_sf(state.doc_dates,Stog.Types.Doc_set.empty,state.stog)doc_list>>=(fun(dates,docs,stog)->letnb_changes=Stog.Types.Doc_set.cardinaldocsindebug(Printf.sprintf"%d elements modified\n"nb_changes)>>=fun()->matchnb_changeswith0->Lwt.return_unit(* do not change current_state *)|_->letstate={statewithstog_errors=List.rev!read_errors;stog_warnings=[];stog=stog;doc_dates=dates;}inrun_stog~docsstate>>=funstate->Lwt_list.iter_s(on_updateold_stogstate.stog)(Stog.Types.Doc_set.elementsdocs)>>=(fun()->current_state:=Somestate;matchstate.stog_errors,state.stog_warningswith[],[]->Lwt.return_unit|errors,warnings->on_error~errors~warnings))>>=fun()->watch_for_changecurrent_stateon_updateon_error)(fune->prerr_endline(Printf.sprintf"watch_for_changes: %s"(Printexc.to_stringe));watch_for_changecurrent_stateon_updateon_error);;letcompute_allstate=lettime=Unix.time()inLwt.catch(fun()->run_stogstate)(fune->prerr_endline(Printexc.to_stringe);Lwt.returnstate)>>=funstate->letdocs=Stog.Types.doc_liststate.stoginletstate={statewithdoc_dates=List.fold_left(funacc(_,doc)->Stog.Path.Map.adddoc.doc_pathtimeacc)state.doc_datesdocs}inLwt.returnstateletwatchstogcurrent_state~on_update~on_error=Lwt.catch(fun()->Lwt_unix.mkdirstog.stog_outdir0o750)(fun_->Lwt.return_unit)>>=fun()->letstate={stog;stog_modules=[];stog_errors=[];stog_warnings=[];doc_dates=Stog.Path.Map.empty;busy=false;}incompute_allstate>>=funstate->current_state:=Somestate;prerr_endline"state set";watch_for_changecurrent_stateon_updateon_errorletrefreshread_stogcurrent_statesend_docon_error=match!current_statewith|None->on_error["No state yet"]|Somestatewhenstate.busy->on_error["Come back later, I'm busy"]|Somestate->matchstate.stog.stog_sourcewith|`File->Lwt.return_unit|`Dir->current_state:=Some{statewithbusy=true};matchread_stog()withexceptione->beginletmsg=matchewith|Failuremsg|Sys_errormsg->msg|_->Printexc.to_stringeincurrent_state:=Some{statewithbusy=false};on_error[msg]end|stog->letstog={stogwithstog_base_url=state.stog.stog_base_url;stog_outdir=state.stog.stog_outdir;}inletstate={statewithstog;stog_errors=[];stog_warnings=[];doc_dates=Stog.Path.Map.empty;busy=false;}incompute_allstate>>=funstate->Lwt_list.iter_s(fun(_,doc)->send_docdoc)(Stog.Types.doc_liststate.stog)>>=fun_->current_state:=Somestate;Lwt.return_unit