123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646(******************************************************************************)(* OASIS: architecture for building OCaml libraries and applications *)(* *)(* Copyright (C) 2011-2016, Sylvain Le Gall *)(* Copyright (C) 2008-2011, OCamlCore SARL *)(* *)(* This library is free software; you can redistribute it and/or modify it *)(* under the terms of the GNU Lesser General Public License as published by *)(* the Free Software Foundation; either version 2.1 of the License, or (at *)(* your option) any later version, with the OCaml static compilation *)(* exception. *)(* *)(* This library 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 file COPYING for more *)(* details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this library; if not, write to the Free Software Foundation, *)(* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *)(******************************************************************************)(** Generate standard text files: INSTALL.txt, README.txt
@author Sylvain Le Gall
*)openOASISFileTemplateopenOASISTypesopenOASISUtilsopenOASISValuesopenOASISGettextopenOASISVersionopenOASISPluginopenOASISSchemaopenFormatopenFormatExtletplugin=`Extra,"StdFiles",SomeOASISConf.version_shortletself_id,all_id=Extra.createpluginletmarkdown=OASISFeatures.create"stdfiles_markdown"~pluginOASISFeatures.alpha(fun()->s_"Use markdown comment and replace .txt extensions of standard files by
.md.")typepackage=(* Standalone executable *)|LToolofprog(* Findlib package *)|LFindlibPackageofname*(OASISVersion.comparatoroption)letfacts=[LFindlibPackage("ocaml",None),[(* Tools shipped with OCaml *)"camlp4";"camlp4boot";"camlp4o";"camlp4of";"camlp4of.opt";"camlp4oof";"camlp4oof.opt";"camlp4o.opt";"camlp4orf";"camlp4orf.opt";"camlp4prof";"camlp4r";"camlp4rf";"camlp4rf.opt";"camlp4r.opt";"mkcamlp4";"ocaml";"ocamlbuild";"ocamlbuild.byte";"ocamlbuild.native";"ocamlc";"ocamlc.opt";"ocamlcp";"ocamldebug";"ocamldep";"ocamldep.opt";"ocamldoc";"ocamldoc.opt";"ocamllex";"ocamllex.opt";"ocamlmklib";"ocamlmktop";"ocamlopt";"ocamlopt.opt";"ocamlprof";"ocamlrun";"ocamlyacc";],[(* Libraries shipped with OCaml *)"bigarray";"camlp4";"dbm";"dynlink";"graphics";"labltk";"num";"stdlib";"str";"threads";"unix";];LFindlibPackage("findlib",None),["ocamlfind"],["findlib"];](** Merge 2 versions constraint *)letmerge_version_optver_opt1ver_opt2=matchver_opt1,ver_opt2with|Somev1,Somev2->Some(VAnd(v1,v2))|None,v|v,None->v(** Associate a tool to a findlib package or a tool *)letpackage_of_tool=letmp=MapString.of_list(List.fold_left(funacc(pkg,tools,_)->List.fold_left(funacctool->(tool,pkg)::acc)acctools)[]facts)infuntool->tryMapString.findtoolmpwithNot_found->LTooltool(** Associate a library to a findlib package raw data *)letpackage_of_library=letmp=MapString.of_list(List.fold_left(funacc(pkg,_,libs)->List.fold_left(funacclib->(lib,pkg)::acc)acclibs)[]facts)infunlibver_opt->tryMapString.findlibmpwithNot_found->LFindlibPackage(lib,ver_opt)typet={readme:unix_filenameoption;install:unix_filenameoption;authors:unix_filenameoption;}letpivot_data=data_new_propertypluginletdefault_filenames=letmp=MapString.of_list(["README","README.txt";"INSTALL","INSTALL.txt";"AUTHORS","AUTHORS.txt"])infunfn->tryMapString.findfnmpwithNot_found->failwithf(f_"No default filename for file %s.")fnletgenerator=letfn_enablefnsync=letenable=new_fieldOASISPackage.schemaall_idfn~default:trueboolean(fun()->Printf.sprintf(f_"Enable %s file generation.")fn)pivot_data(funtt'->(synctt')<>None)inletfn=new_fieldOASISPackage.schemaall_id(fn^"Filename")~default:(default_filenamesfn)string_not_empty(fun()->Printf.sprintf(f_"Real filename to use for file %s.")fn)pivot_data(funtt'->matchsynctt'with|Somefn->fn|None->raiseNot_printable)infundata->ifenabledatathenSome(fndata)elseNoneinletreadme=fn_enable"README"(fun_t->t.readme)inletinstall=fn_enable"INSTALL"(fun_t->t.install)inletauthors=fn_enable"AUTHORS"(fun_t->t.authors)infundata->{readme=readmedata;install=installdata;authors=authorsdata;}moduleSetSection=Set.Make(structtypet=sectionletcompare=compareend)letmainctxtpkg=letdata=pkg.schema_datain(** All sections that contains a build_section *)letall_build_sections_set=letall_build_sections=List.rev(List.fold_left(funacc->function|Library(_,bs,_)|Object(_,bs,_)|Executable(_,bs,_)assct->(sct,bs)::acc|SrcRepo_|Flag_|Test_|Doc_->acc)[]pkg.sections)inList.fold_left(funacce->SetSection.addeacc)SetSection.empty(List.rev_mapfstall_build_sections)inletpp_print_sections=(* If a tool/library applies to all sections that can handle a build_depends
or build_tools we can say it is a general depends. In this case, return
is None, otherwise "Some sections".
*)funfmtsections->letis_all_build_sections,sections=ifSetSection.subsetall_build_sections_setsectionsthentrue,SetSection.diffsectionsall_build_sections_setelsefalse,sectionsinifSetSection.is_emptysectionsthen()elsefprintffmt" for %t%a"(funfmt->ifis_all_build_sectionsthenfprintffmt"all,@ ")(pp_print_list(funfmtsct->fprintffmt"%s"(OASISSection.string_of_sectionsct))",@ ")(SetSection.elementssections)inletpp_print_ver_optfmt=may(funver_cmp->fprintffmt" (%a)"pp_print_string(OASISVersion.string_of_comparator(OASISVersion.comparator_reducever_cmp)))inletdepends=letmerge_package_sectionlst(new_pkg,new_sections)=tryletold_pkg,new_pkg,old_sections=matchnew_pkgwith|LTool_astool->tool,tool,List.assoctoollst|LFindlibPackage(nm1,ver_opt1)->beginletres_opt=List.fold_left(funaccpkg->matchacc,pkgwith|None,((LFindlibPackage(nm2,ver_opt2))asold_pkg,sections)->ifnm1=nm2thenSome(old_pkg,LFindlibPackage(nm1,merge_version_optver_opt1ver_opt2),sections)elseacc|_,_->acc)Nonelstinmatchres_optwith|Someres->res|None->raiseNot_foundendinletlst=tryList.remove_assocold_pkglstwithNot_found->lstin(new_pkg,SetSection.unionnew_sectionsold_sections)::lstwithNot_found->(new_pkg,new_sections)::lstinletadd_build_toolsssection=List.fold_left(funlst->function|ExternalTooltool->(package_of_tooltool,ssection)::lst|InternalExecutable_->lst)inletsplit_package_section=List.fold_left(funlst->function|Library(_,bs,_)|Object(_,bs,_)|Executable(_,bs,_)assection->beginletssection=SetSection.singletonsectioninletlst=(* Add build_depends *)List.fold_left(funlst->function|FindlibPackage(fndlb_nm,ver_opt)->letfndlb_root=match(OASISString.nsplitfndlb_nm'.')with|hd::_->hd|_->fndlb_nmin(package_of_libraryfndlb_rootver_opt,ssection)::lst|InternalLibrary_->lst)lstbs.bs_build_dependsin(* Add build_tools *)add_build_toolsssectionlstbs.bs_build_toolsend|Test(_,{test_tools=build_tools})|Doc(_,{doc_build_tools=build_tools})assection->add_build_tools(SetSection.singletonsection)lstbuild_tools|Flag_|SrcRepo_->lst)(* Basic dependencies *)([LFindlibPackage("findlib",pkg.findlib_version),all_build_sections_set;LFindlibPackage("ocaml",pkg.ocaml_version),all_build_sections_set]@(ifOASISFeatures.package_testOASISFeatures.dynrun_for_releasepkgthen[LFindlibPackage("oasis",Some(OASISVersion.VGreaterEqualpkg.oasis_version)),all_build_sections_set]else[]))(* Go through all sections *)pkg.sectionsin(* Merge everything *)List.fold_leftmerge_package_section[]split_package_sectioninletadd_filectxt(fn_opt,important,ppf)=matchfn_optwith|Someunix_fn->beginletrecremove_eol_eofstr=List.fold_left(funstreol->tryremove_eol_eof(OASISString.strip_ends_with~what:eolstr)withNot_found->str)str["\n";"\r"]inletcontent=ppfstr_formatter;(* Trim problematic 2x newline at end of last para, because we
* don't know if there will a following para.
*)remove_eol_eof(flush_str_formatter())inletcomment=ifOASISFeatures.package_testmarkdownpkgthencomment_markdownelsecomment_mlinadd_file{(template_makeunix_fncomment[][(* One line before, one line after to avoid mixing content
* with comment formatting (it causes e.g. pandoc to think
* this is a paragraph.
*)"\n"^content^"\n"][])withimportant=important}ctxtend|None->ctxtinlett=generatordatainletfix_extfnreal_fn_opt=matchreal_fn_optwith|Somereal_fn->ifOASISFeatures.package_testmarkdownpkg&&real_fn=default_filenamesfnthenSome(fn^".md")elseSomereal_fn|None->Noneinlett={readme=fix_ext"README"t.readme;install=fix_ext"INSTALL"t.install;authors=fix_ext"AUTHORS"t.authors;}inList.fold_leftadd_filectxt[(* Generate README.txt *)t.readme,false,(funfmt->pp_open_vboxfmt0;pp_print_titleffmt1"%s - %s"pkg.namepkg.synopsis;may(fundescr->OASISText.pp_printfmtdescr;pp_print_newlinefmt();pp_print_newlinefmt())pkg.description;may(funfn->pp_print_paraffmt"See the file [%s](%s) for building and installation \
instructions."fnfn)t.install;may(pp_print_paraffmt"[Home page](%s)")pkg.homepage;may(pp_print_paraffmt"[Bug reports](%s)")pkg.bugreports;pp_print_titlefmt2"Copyright and license";List.iter(funstr->pp_print_stringfmtstr;pp_print_newlinefmt())pkg.copyrights;ifpkg.copyrights<>[]thenpp_print_newlinefmt();pp_print_parafmt(OASISLicense.legal_disclaimerpkg.namepkg.license);may(funfn->pp_print_paraffmt"See [%s](%s) for more information."fnfn)pkg.license_file;pp_close_boxfmt(););(* Generate INSTALL.txt *)t.install,(OASISFeatures.package_testOASISFeatures.dynrun_for_releasepkg),(funfmt->pp_open_vboxfmt0;fprintffmt"@[This is the INSTALL file for the %s distribution.@]@,@,"pkg.name;pp_print_parafmt"This package uses OASIS to generate its build system. \
See section OASIS for full information.";pp_print_titlefmt1"Dependencies";fprintffmt"@[In order to compile this package, you will need:@]@,";pp_open_vboxfmt0;pp_print_cutfmt();pp_print_list(funfmt(pkg,sections)->fprintffmt"* @[%a%a@]"(funfmt->function|LTools->pp_print_stringfmts|LFindlibPackage(nm,ver_opt)->fprintffmt"%s%a"nmpp_print_ver_optver_opt)pkgpp_print_sectionssections)"@,"fmtdepends;pp_close_boxfmt();pp_print_cutfmt();pp_print_stringfmtStdFilesData.install;pp_close_boxfmt());(* Generate AUTHORS.txt *)t.authors,false,(funfmt->pp_open_vboxfmt0;fprintffmt"@[Authors of %s:@]@,"pkg.name;pp_print_cutfmt();pp_print_list(funfmtstr->pp_print_stringfmt("* "^str))"@,"fmtpkg.OASISTypes.authors;ifpkg.maintainers<>[]thenbeginpp_print_cut2fmt();fprintffmt"@[Current maintainers of %s:@]@,"pkg.name;pp_print_cutfmt();pp_print_list(funfmtstr->pp_print_stringfmt("* "^str))"@,"fmtpkg.maintainersend;pp_close_boxfmt());]letinit()=register_helpplugin{(help_defaultStdFilesData.readme_template_mkd)withhelp_order=50};Extra.register_actself_idmain;register_generator_packageall_idpivot_datagenerator