123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228(*
* 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_setuptypet={user:stringoption;remote:stringoption;local:Fpath.toption;keep_v:booloption;auto_open:booloption;}letof_yaml_exnstr=(* ouch *)letlines=String.cuts~empty:false~sep:"\n"strinletdict()=List.map(funline->matchString.cut~sep:":"linewith|Some(k,v)->String.trimk,String.trimv|_->failwith"invalid format")linesinletdict=dict()inletfindk=trySome(List.assockdict)withNot_found->Noneinletfind_bk=matchfindkwith|None->None|Somes->Some(bool_of_strings)inletvalid=["user";"remote";"local";"auto-open";"keep-v"]inList.iter(fun(k,_)->ifnot(List.memkvalid)thenFmt.failwith"%S is not a valid configuration key."k)dict;letlocal=matchfind"local"with|None->None|Somev->matchFpath.of_stringvwith|Okx->Somex|Error_->Nonein{user=find"user";remote=find"remote";local;auto_open=find_b"auto-open";keep_v=find_b"keep-v"}letof_yamlstr=tryOk(of_yaml_exnstr)withFailures->R.error_msgsletread_stringdefault~descr=letread()=matchread_line()with|""->None|s->print_newline();Somes|exceptionEnd_of_file->print_newline();None|exception(Sys.Breakase)->print_newline();raiseeinFmt.pr"@[<h-0>%s@.[press ENTER to use '%a']@]\n%!"(String.trimdescr)Fmt.(styled`Boldstring)default;matchread()with|None->default|Somes->sletcreate_config~user~remote_repo~local_repopkgsfile=Fmt.pr"%a does not exist!\n\
Please answer a few questions to help me create it for you:\n\n%!"Fpath.ppfile;(matchuserwithSomeu->Oku|None->letpkg=List.hdpkgsinPkg.distrib_user_and_repopkg>>=fun(u,_)->Oku)>>=fundefault_user->letuser=read_stringdefault_user~descr:"What is your GitHub ID?"inletdefault_remote=matchremote_repowith|Somer->r|None->strf"git@github.com:%s/opam-repository"userinletdefault_local=matchlocal_repowith|Somer->Okr|None->Ok(Fpath.(vXdg.home/"git"/"opam-repository"|>to_string))indefault_local>>=fundefault_local->letremote=read_stringdefault_remote~descr:"What is your fork of ocaml/opam-repository? \
(you should have write access)."inletlocal=read_stringdefault_local~descr:"Where on your filesystem did you clone that repository?"inFpath.of_stringlocal>>=funlocal->letv=strf"user: %s\nremote: %s\nlocal: %a\n"userremoteFpath.pplocalinOS.Dir.createFpath.(parentfile)>>=fun_->OS.File.writefilev>>=fun()->Ok{user=Someuser;remote=Someremote;local=Somelocal;auto_open=None;keep_v=None}letconfig_dir()=letcfg=Fpath.(vXdg.config_dir/"dune")inletupgrade()=(* Upgrade from 0.2 to 0.3 format *)letold_d=Fpath.(vXdg.home/".dune")inOS.Dir.existsold_d>>=function|false->Ok()|true->Logs.app(funm->m"Upgrading configuration files: %a => %a"Fpath.ppold_dFpath.ppcfg);OS.Dir.create~path:truecfg>>=fun_->OS.Path.moveold_dFpath.(cfg/"release.yml")inupgrade()>>=fun()->Okcfgletfile()=config_dir()>>|funcfg->Fpath.(cfg/"release.yml")letfind()=file()>>=funfile->OS.File.existsfile>>=funexists->ifexiststhenOS.File.readfile>>=of_yaml>>|funx->SomexelseOkNoneletv~user~remote_repo~local_repopkgs=find()>>=function|Somef->Okf|None->file()>>=create_config~user~remote_repo~local_repopkgsletreset_terminal:(unit->unit)optionref=refNoneletcleanup()=match!reset_terminalwithNone->()|Somef->f()let()=at_exitcleanupletget_token()=letrecaux()=matchread_line()with|""->aux()|s->s|exceptionEnd_of_file->print_newline();aux()|exception(Sys.Breakase)->print_newline();raiseeinaux()letvalidate_tokentoken=lettoken=String.trimtokeninifString.is_emptytoken||String.existsChar.Ascii.is_whitetokenthenError(R.msg"token is malformed")elseOktokenlettoken~dry_run()=config_dir()>>=funcfg->letfile=Fpath.(cfg/"github.token")inOS.File.existsfile>>=funexists->letis_valid=ifexiststhenSos.read_file~dry_runfile>>=validate_tokenelseError(R.msg"does not exist")inmatchis_validwith|Ok_->Okfile|Error(`Msgmsg)->ifdry_runthenOkFpath.(v"${token}")else(leterror=ifexiststhen":"^msgelse" does not exist"inFmt.pr"%a%s!\n\
\n\
To create a new token, please visit:\n\
\n\
\ https://github.com/settings/tokens/new\n\
\n\
And create a token with a nice name and and the %a scope only.\n\
\n\
Copy the token@ here: %!"Fpath.ppfileerrorFmt.(styled`Boldstring)"public_repo";letrecget_valid_token()=matchvalidate_token(get_token())with|Oktoken->token|Error(`Msgmsg)->Fmt.pr"Please try again, %s.%!"msg;get_valid_token()inlettoken=get_valid_token()inOS.Dir.createFpath.(parentfile)>>=fun_->OS.File.write~mode:0o600filetoken>>=fun()->Okfile)letfile=lazy(find())letreadfdefault=Lazy.forcefile>>|function|None->default|Somet->matchftwith|None->default|Someb->bletkeep_vv=ifvthenOktrueelseread(funt->t.keep_v)falseletauto_openv=ifnotvthenOkfalseelseread(funt->t.auto_open)true