123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181(**************************************************************************)(* *)(* Copyright 2012-2019 OCamlPro *)(* Copyright 2012 INRIA *)(* *)(* All rights reserved. This file is distributed under the terms of the *)(* GNU Lesser General Public License version 2.1, with the special *)(* exception on linking described in the file LICENSE. *)(* *)(**************************************************************************)openOpamTypesopenOpamStd.OpopenOpamProcess.Job.OpmoduletypeVCS=sigvalname:OpamUrl.backendvalexists:dirname->boolvalinit:dirname->url->unitOpamProcess.jobvalfetch:?cache_dir:dirname->?subpath:string->dirname->url->unitOpamProcess.jobvalreset_tree:dirname->url->unitOpamProcess.jobvalpatch_applied:dirname->url->unitOpamProcess.jobvaldiff:dirname->url->filenameoptionOpamProcess.jobvalis_up_to_date:dirname->url->boolOpamProcess.jobvalrevision:dirname->stringoptionOpamProcess.jobvalversioned_files:dirname->stringlistOpamProcess.jobvalvc_dir:dirname->dirnamevalcurrent_branch:dirname->stringoptionOpamProcess.jobvalis_dirty:?subpath:string->dirname->boolOpamProcess.jobvalmodified_files:dirname->stringlistOpamProcess.jobvalget_remote_url:?hash:string->dirname->urloptionOpamProcess.jobendletconvert_path=OpamSystem.get_cygpath_function~command:"rsync"moduleMake(VCS:VCS)=structletname=VCS.nameletfetch_repo_updaterepo_name?cache_dirrepo_rootrepo_url=ifVCS.existsrepo_rootthenOpamProcess.Job.catch(fune->Done(OpamRepositoryBackend.Update_erre))@@fun()->OpamRepositoryBackend.job_textrepo_name"sync"(VCS.fetch?cache_dirrepo_rootrepo_url)@@+fun()->OpamRepositoryBackend.job_textrepo_name"diff"(VCS.diffrepo_rootrepo_url)@@|function|None->OpamRepositoryBackend.Update_empty|Somepatch->OpamRepositoryBackend.Update_patchpatchelseOpamProcess.Job.catch(fune->OpamFilename.rmdirrepo_root;Done(OpamRepositoryBackend.Update_erre))@@fun()->OpamRepositoryBackend.job_textrepo_name"init"(VCS.initrepo_rootrepo_url)@@+fun()->OpamRepositoryBackend.job_textrepo_name"sync"(VCS.fetch?cache_dirrepo_rootrepo_url)@@+fun()->lettmpdir=OpamFilename.Dir.(of_string(to_stringrepo_root^".new"))inOpamFilename.copy_dir~src:repo_root~dst:tmpdir;OpamProcess.Job.catch(fune->OpamFilename.rmdirtmpdir;raisee)@@fun()->VCS.reset_treetmpdirrepo_url@@|fun()->OpamRepositoryBackend.Update_fulltmpdirletrepo_update_completedirnameurl=VCS.patch_applieddirnameurl@@+fun()->Done()letpull_url?cache_dir?subpathdirnamechecksumurl=ifchecksum<>Nonetheninvalid_arg"VC pull_url doesn't allow checksums";OpamProcess.Job.catch(fune->OpamConsole.error"Could not synchronize %s from %S:\n%s"(OpamFilename.Dir.to_stringdirname)(OpamUrl.to_stringurl)(matchewithFailurefw->fw|_->Printexc.to_stringe);Done(Not_available(None,OpamUrl.to_stringurl)))@@fun()->ifVCS.existsdirnamethenVCS.fetch?cache_dir?subpathdirnameurl@@+fun()->VCS.is_up_to_datedirnameurl@@+function|true->Done(Up_to_dateNone)|false->VCS.reset_treedirnameurl@@+fun()->Done(ResultNone)else(OpamFilename.mkdirdirname;VCS.initdirnameurl@@+fun()->VCS.fetch?cache_dir?subpathdirnameurl@@+fun()->VCS.reset_treedirnameurl@@+fun()->Done(ResultNone))letrevisionrepo_root=VCS.revisionrepo_root@@+funr->Done(OpamStd.Option.mapOpamPackage.Version.of_stringr)letsync_dirty?subpathrepo_rootrepo_url=letfilter_subpathfiles=matchsubpathwith|None->files|Somesp->OpamStd.List.filter_map(funf->ifOpamStd.String.remove_prefix~prefix:(sp^Filename.dir_sep)f<>fthenSomefelseNone)filesinpull_url?subpathrepo_rootNonerepo_url@@+funresult->matchOpamUrl.local_dirrepo_urlwith|None->Done(result)|Somedir->VCS.versioned_filesdir@@+funvc_files->VCS.modified_filesdir@@+funvc_dirty_files->letfiles=filter_subpath(List.mapOpamFilename.(remove_prefixdir)(OpamFilename.rec_filesdir))in(* Remove non-listed files from destination *)(* fixme: doesn't clean directories *)letfset=OpamStd.String.Set.of_listfilesinletrm_list=List.filter(funf->letbasename=OpamFilename.remove_prefixrepo_rootfinnot(OpamFilename.(starts_with(VCS.vc_dirrepo_root)f)||OpamStd.String.Set.membasenamefset))(OpamFilename.rec_filesrepo_root)inList.iterOpamFilename.removerm_list;(* We do the list cleaning here because of rsync options: with
`--files-from`, `--exclude` need to be explicitly given directory
descendants, e.g `--exclude _build/**`
*)letexcluded=(* from [OpamLocal.rsync] exclude list *)letexc=[OpamSwitch.external_dirname;"_build";".git";"_darcs";".hg"]inOpamStd.String.Set.filter(funf->List.exists(funprefix->OpamStd.String.starts_with~prefixf)exc)fsetinletvcset=OpamStd.String.Set.of_list(filter_subpathvc_files)inletvc_dirty_set=OpamStd.String.Set.of_list(filter_subpathvc_dirty_files)inletfinal_set=OpamStd.String.Set.Op.(fset--vcset++vc_dirty_set--excluded)inletstdout_file=letf=OpamSystem.temp_file"rsync-files"inletfd=open_outfin(* Using the set here to keep the list file sorted, it helps rsync *)OpamStd.String.Set.iter(funs->output_stringfds;output_charfd'\n')final_set;close_outfd;finletargs=["--files-from";(Lazy.forceconvert_path)stdout_file;]inOpamLocal.rsync_dirs~argsrepo_urlrepo_root@@+funresult->OpamSystem.removestdout_file;Done(matchresultwith|Up_to_date_whenrm_list=[]->Up_to_dateNone|Up_to_date_|Result_->ResultNone|Not_available_asna->na)letget_remote_url=VCS.get_remote_urlend