123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194(*
* Copyright (c) 2018 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openBos_setuptypeerror=R.msgletroot=matchOS.Dir.current()with|Error(`Msge)->Fmt.failwith"invalid root: %s"e|Okd->dletcurrent_dir?(sandbox=true)()=matchOS.Dir.current()with|Error(`Msge)->Fmt.failwith"invalid current directory: %s"e|Okdir->ifFpath.equaldirrootthenNoneelsematchFpath.relativize~rootdirwith|None->assertfalse|Somed->ifsandboxthenassert(List.hd(Fpath.segsd)="_build");Somedletlast_dir=refrootletpp_cmdppfcmd=letx=Fmt.to_to_stringCmd.ppcmdinletx=String.mapi(fun_->function|'\n'->' '|c->c)xinFmt.stringppfxletshow?sandbox?(action=`Skip)fmt=letpp_actionppf=function|`Skip->Fmt.(styled`Yellowstring)ppf"-:"|`Done->Fmt.(styled`Greenstring)ppf"=>"inletpp_cwdppf()=matchcurrent_dir?sandbox()with|None->()|Somed->ifnot(Fpath.equald!last_dir)then(last_dir:=d;Fmt.pfppf" [in %a]\n"Fmt.(styled`UnderlineFpath.pp)d)inFmt.kstrf(funs->Logs.app(funm->m"%a%a %s"pp_cwd()pp_actionactions);Ok())fmtletrun_gen?err~dry_run?(force=false)?sandbox~defaultvif=ifnotdry_runthenOS.Cmd.run_io?errvi|>felseifnotforcethenlet_=show?sandbox"exec:@[@ %a@]"pp_cmdvinOkdefaultelse(let_=show?sandbox~action:`Done"exec:@[@ %a@]"pp_cmdvinOS.Cmd.run_io?errvi|>f)letrun_quiet~dry_run?(force=false)?sandboxv=letopenOS.Cmdinrun_gen~err:err_null~dry_run~force?sandbox~default:()vin_stdinto_nullletrun~dry_run?(force=false)?sandboxv=letopenOS.Cmdinrun_gen~dry_run~force?sandbox~default:()vin_stdinto_stdoutletrun_out~dry_run?(force=false)?sandbox?err~defaultvf=run_gen?err~dry_run~force?sandbox~defaultvOS.Cmd.in_stdinfletrun_io~dry_run?(force=false)?sandbox~defaultvif=run_gen~dry_run~force?sandbox~defaultvifletrun_status~dry_run?(force=false)?sandboxv=ifnotdry_runthenOS.Cmd.run_statusvelseifnotforcethenlet_=show?sandbox"exec:@[@ %a@]"pp_cmdvinOk(`Exited0)else(let_=show?sandbox~action:`Done"exec:@[@ %a@]"pp_cmdvinOS.Cmd.run_statusv)letdelete_dir~dry_run?(force=false)dir=ifnotdry_runthenOS.Dir.delete~recurse:truedirelse(letdir'=matchcurrent_dir()with|None->dir|Somed->Fpath.(normalize@@d//dir)inifnotforcethenshow"rmdir %a"Fpath.ppdir'else(let_=show~action:`Done"rmdir %a"Fpath.ppdir'inOS.Dir.delete~recurse:truedir))letdelete_path~dry_runp=ifnotdry_runthenOS.Path.delete~recurse:truepelse(letp'=matchcurrent_dir()with|None->p|Somed->Fpath.(normalize@@d//p)inlet_=show~action:`Done"rm %a"Fpath.ppp'inOk())letwrite_file~dry_run?(force=false)pv=ifnotdry_runthenOS.File.writepvelseifnotforcethenshow"write %a"Fpath.pppelse(let_=show~action:`Done"write %a"Fpath.pppinOS.File.writepv)letread_file~dry_runp=ifnotdry_runthenOS.File.readpelsematchOS.File.existspwith|Oktrue->let_=show~action:`Done"read %a"Fpath.pppinOS.File.readp|_->let_=show"read %a"Fpath.pppinOk""letfile_exists~dry_runp=ifnotdry_runthenOS.File.existspelseletaction=matchOS.File.existspwithOktrue->`Done|_->`Skipinlet_=show~action"exists %a"Fpath.pppinOktrueletdir_exists~dry_runp=ifnotdry_runthenOS.Dir.existspelseletaction=matchOS.Dir.existspwithOktrue->`Done|_->`Skipinlet_=show~action"exists %a"Fpath.pppinOktrueletwith_dir~dry_rundirfx=ifnotdry_runthenOS.Dir.with_currentdirfxelsematchOS.Dir.existsdirwith|Oktrue->let_=show~action:`Done"chdir %a"Fpath.ppdirinOS.Dir.with_currentdirfx|_->let_=show"chdir %a"Fpath.ppdirinOk(fx)letmkdir~dry_rundir=ifnotdry_runthenOS.Dir.createdirelsematchOS.Dir.existsdirwith|Oktrue->Oktrue|_->let_=show"mkdir %a"Fpath.ppdirinOkfalseletfile_must_exist~dry_runf=ifnotdry_runthenOS.File.must_existfelselet_=matchOS.File.existsfwith|Oktrue->show~action:`Done"must exists %a"Fpath.ppf|_->show"must exists %a"Fpath.ppfinOkfletouty=matchOS.Cmd.run_outCmd.(v"true")|>OS.Cmd.out_stringwith|Ok(_,x)->y,x|Error_->assertfalseletcp~dry_run~rec_~force~src~dst=letcmd=Cmd.(v"cp"%%onrec_(v"-r")%%onforce(v"-f")%psrc%pdst)inrun~dry_runcmdletrelativize~src~dst=R.of_option~none:(fun()->R.error_msgf"Could define path from %a to %a"Fpath.ppsrcFpath.ppdst)(Fpath.relativize~root:srcdst)