opam-full-1.2.2/0000755000175000017500000000000012532744757012146 5ustar useruseropam-full-1.2.2/configure0000755000175000017500000050617512517374214014061 0ustar useruser#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for opam 1.2.2. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # # Copyright 2012-2015 OcamlPro SAS ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='opam' PACKAGE_TARNAME='opam' PACKAGE_VERSION='1.2.2' PACKAGE_STRING='opam 1.2.2' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_subst_vars='LTLIBOBJS LIBOBJS hasalldeps OCAML_PKG_jsonm OCAML_PKG_dose3 OCAML_PKG_cudf OCAML_PKG_ocamlgraph OCAML_PKG_cmdliner OCAML_PKG_re_glob OCAML_PKG_re_pcre OCAML_PKG_re_perl OCAML_PKG_re_str OCAML_PKG_re_emacs OCAML_PKG_re OCAML_PKG_extlib OCAML_PKG_unix fetch FETCH OCAMLFIND OCAMLYACC OCAMLLEXDOTOPT OCAMLLEX ocaml_4_02 ocaml_4_01 ocaml_4 AWK OCAMLBUILD OCAMLDOC OCAMLMKLIB OCAMLMKTOP OCAMLDEP OCAML OCAMLOPTDOTOPT OCAMLCDOTOPT OCAMLBEST OCAMLOPT OCAMLLIB OCAMLVERSION OCAMLC OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_version_check enable_certificate_check ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures opam 1.2.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/opam] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of opam 1.2.2:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-version-check Do not check OCaml version --disable-certificate-check Do not check the certificate of OPAM's dependency archives Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF opam configure 1.2.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Copyright 2012-2015 OcamlPro SAS _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by opam $as_me 1.2.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # checking for ocamlc if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlc", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLC"; then ac_cv_prog_OCAMLC="$OCAMLC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLC="${ac_tool_prefix}ocamlc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLC=$ac_cv_prog_OCAMLC if test -n "$OCAMLC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLC" >&5 $as_echo "$OCAMLC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLC"; then ac_ct_OCAMLC=$OCAMLC # Extract the first word of "ocamlc", so it can be a program name with args. set dummy ocamlc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLC"; then ac_cv_prog_ac_ct_OCAMLC="$ac_ct_OCAMLC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLC="ocamlc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLC=$ac_cv_prog_ac_ct_OCAMLC if test -n "$ac_ct_OCAMLC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLC" >&5 $as_echo "$ac_ct_OCAMLC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLC" = x; then OCAMLC="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLC=$ac_ct_OCAMLC fi else OCAMLC="$ac_cv_prog_OCAMLC" fi if test "$OCAMLC" != "no"; then OCAMLVERSION=`$OCAMLC -v | sed -n -e 's|.*version* *\(.*\)$|\1|p'` { $as_echo "$as_me:${as_lineno-$LINENO}: result: OCaml version is $OCAMLVERSION" >&5 $as_echo "OCaml version is $OCAMLVERSION" >&6; } # If OCAMLLIB is set, use it if test "$OCAMLLIB" = ""; then OCAMLLIB=`$OCAMLC -where 2>/dev/null || $OCAMLC -v|tail -1|cut -d ' ' -f 4` else { $as_echo "$as_me:${as_lineno-$LINENO}: result: OCAMLLIB previously set; preserving it." >&5 $as_echo "OCAMLLIB previously set; preserving it." >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: OCaml library path is $OCAMLLIB" >&5 $as_echo "OCaml library path is $OCAMLLIB" >&6; } # checking for ocamlopt if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlopt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlopt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLOPT"; then ac_cv_prog_OCAMLOPT="$OCAMLOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLOPT="${ac_tool_prefix}ocamlopt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLOPT=$ac_cv_prog_OCAMLOPT if test -n "$OCAMLOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLOPT" >&5 $as_echo "$OCAMLOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLOPT"; then ac_ct_OCAMLOPT=$OCAMLOPT # Extract the first word of "ocamlopt", so it can be a program name with args. set dummy ocamlopt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLOPT"; then ac_cv_prog_ac_ct_OCAMLOPT="$ac_ct_OCAMLOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLOPT="ocamlopt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLOPT=$ac_cv_prog_ac_ct_OCAMLOPT if test -n "$ac_ct_OCAMLOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLOPT" >&5 $as_echo "$ac_ct_OCAMLOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLOPT" = x; then OCAMLOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLOPT=$ac_ct_OCAMLOPT fi else OCAMLOPT="$ac_cv_prog_OCAMLOPT" fi OCAMLBEST=byte if test "$OCAMLOPT" = "no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Cannot find ocamlopt; bytecode compilation only." >&5 $as_echo "$as_me: WARNING: Cannot find ocamlopt; bytecode compilation only." >&2;} else TMPVERSION=`$OCAMLOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt discarded." >&5 $as_echo "versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt discarded." >&6; } OCAMLOPT=no else OCAMLBEST=opt fi fi # checking for ocamlc.opt if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlc.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlc.opt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLCDOTOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLCDOTOPT"; then ac_cv_prog_OCAMLCDOTOPT="$OCAMLCDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLCDOTOPT="${ac_tool_prefix}ocamlc.opt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLCDOTOPT=$ac_cv_prog_OCAMLCDOTOPT if test -n "$OCAMLCDOTOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLCDOTOPT" >&5 $as_echo "$OCAMLCDOTOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLCDOTOPT"; then ac_ct_OCAMLCDOTOPT=$OCAMLCDOTOPT # Extract the first word of "ocamlc.opt", so it can be a program name with args. set dummy ocamlc.opt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLCDOTOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLCDOTOPT"; then ac_cv_prog_ac_ct_OCAMLCDOTOPT="$ac_ct_OCAMLCDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLCDOTOPT="ocamlc.opt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLCDOTOPT=$ac_cv_prog_ac_ct_OCAMLCDOTOPT if test -n "$ac_ct_OCAMLCDOTOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLCDOTOPT" >&5 $as_echo "$ac_ct_OCAMLCDOTOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLCDOTOPT" = x; then OCAMLCDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLCDOTOPT=$ac_ct_OCAMLCDOTOPT fi else OCAMLCDOTOPT="$ac_cv_prog_OCAMLCDOTOPT" fi if test "$OCAMLCDOTOPT" != "no"; then TMPVERSION=`$OCAMLCDOTOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlc.opt discarded." >&5 $as_echo "versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlc.opt discarded." >&6; } else OCAMLC=$OCAMLCDOTOPT fi fi # checking for ocamlopt.opt if test "$OCAMLOPT" != "no" ; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlopt.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlopt.opt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLOPTDOTOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLOPTDOTOPT"; then ac_cv_prog_OCAMLOPTDOTOPT="$OCAMLOPTDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLOPTDOTOPT="${ac_tool_prefix}ocamlopt.opt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLOPTDOTOPT=$ac_cv_prog_OCAMLOPTDOTOPT if test -n "$OCAMLOPTDOTOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLOPTDOTOPT" >&5 $as_echo "$OCAMLOPTDOTOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLOPTDOTOPT"; then ac_ct_OCAMLOPTDOTOPT=$OCAMLOPTDOTOPT # Extract the first word of "ocamlopt.opt", so it can be a program name with args. set dummy ocamlopt.opt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLOPTDOTOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLOPTDOTOPT"; then ac_cv_prog_ac_ct_OCAMLOPTDOTOPT="$ac_ct_OCAMLOPTDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLOPTDOTOPT="ocamlopt.opt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLOPTDOTOPT=$ac_cv_prog_ac_ct_OCAMLOPTDOTOPT if test -n "$ac_ct_OCAMLOPTDOTOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLOPTDOTOPT" >&5 $as_echo "$ac_ct_OCAMLOPTDOTOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLOPTDOTOPT" = x; then OCAMLOPTDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLOPTDOTOPT=$ac_ct_OCAMLOPTDOTOPT fi else OCAMLOPTDOTOPT="$ac_cv_prog_OCAMLOPTDOTOPT" fi if test "$OCAMLOPTDOTOPT" != "no"; then TMPVERSION=`$OCAMLOPTDOTOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt.opt discarded." >&5 $as_echo "versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt.opt discarded." >&6; } else OCAMLOPT=$OCAMLOPTDOTOPT fi fi fi fi # checking for ocaml toplevel if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocaml", so it can be a program name with args. set dummy ${ac_tool_prefix}ocaml; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAML+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAML"; then ac_cv_prog_OCAML="$OCAML" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAML="${ac_tool_prefix}ocaml" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAML=$ac_cv_prog_OCAML if test -n "$OCAML"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAML" >&5 $as_echo "$OCAML" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAML"; then ac_ct_OCAML=$OCAML # Extract the first word of "ocaml", so it can be a program name with args. set dummy ocaml; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAML+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAML"; then ac_cv_prog_ac_ct_OCAML="$ac_ct_OCAML" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAML="ocaml" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAML=$ac_cv_prog_ac_ct_OCAML if test -n "$ac_ct_OCAML"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAML" >&5 $as_echo "$ac_ct_OCAML" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAML" = x; then OCAML="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAML=$ac_ct_OCAML fi else OCAML="$ac_cv_prog_OCAML" fi # checking for ocamldep if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamldep", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamldep; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLDEP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLDEP"; then ac_cv_prog_OCAMLDEP="$OCAMLDEP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLDEP="${ac_tool_prefix}ocamldep" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLDEP=$ac_cv_prog_OCAMLDEP if test -n "$OCAMLDEP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLDEP" >&5 $as_echo "$OCAMLDEP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLDEP"; then ac_ct_OCAMLDEP=$OCAMLDEP # Extract the first word of "ocamldep", so it can be a program name with args. set dummy ocamldep; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLDEP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLDEP"; then ac_cv_prog_ac_ct_OCAMLDEP="$ac_ct_OCAMLDEP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLDEP="ocamldep" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLDEP=$ac_cv_prog_ac_ct_OCAMLDEP if test -n "$ac_ct_OCAMLDEP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLDEP" >&5 $as_echo "$ac_ct_OCAMLDEP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLDEP" = x; then OCAMLDEP="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLDEP=$ac_ct_OCAMLDEP fi else OCAMLDEP="$ac_cv_prog_OCAMLDEP" fi # checking for ocamlmktop if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlmktop", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlmktop; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLMKTOP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLMKTOP"; then ac_cv_prog_OCAMLMKTOP="$OCAMLMKTOP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLMKTOP="${ac_tool_prefix}ocamlmktop" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLMKTOP=$ac_cv_prog_OCAMLMKTOP if test -n "$OCAMLMKTOP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLMKTOP" >&5 $as_echo "$OCAMLMKTOP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLMKTOP"; then ac_ct_OCAMLMKTOP=$OCAMLMKTOP # Extract the first word of "ocamlmktop", so it can be a program name with args. set dummy ocamlmktop; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLMKTOP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLMKTOP"; then ac_cv_prog_ac_ct_OCAMLMKTOP="$ac_ct_OCAMLMKTOP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLMKTOP="ocamlmktop" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLMKTOP=$ac_cv_prog_ac_ct_OCAMLMKTOP if test -n "$ac_ct_OCAMLMKTOP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLMKTOP" >&5 $as_echo "$ac_ct_OCAMLMKTOP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLMKTOP" = x; then OCAMLMKTOP="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLMKTOP=$ac_ct_OCAMLMKTOP fi else OCAMLMKTOP="$ac_cv_prog_OCAMLMKTOP" fi # checking for ocamlmklib if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlmklib", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlmklib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLMKLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLMKLIB"; then ac_cv_prog_OCAMLMKLIB="$OCAMLMKLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLMKLIB="${ac_tool_prefix}ocamlmklib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLMKLIB=$ac_cv_prog_OCAMLMKLIB if test -n "$OCAMLMKLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLMKLIB" >&5 $as_echo "$OCAMLMKLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLMKLIB"; then ac_ct_OCAMLMKLIB=$OCAMLMKLIB # Extract the first word of "ocamlmklib", so it can be a program name with args. set dummy ocamlmklib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLMKLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLMKLIB"; then ac_cv_prog_ac_ct_OCAMLMKLIB="$ac_ct_OCAMLMKLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLMKLIB="ocamlmklib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLMKLIB=$ac_cv_prog_ac_ct_OCAMLMKLIB if test -n "$ac_ct_OCAMLMKLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLMKLIB" >&5 $as_echo "$ac_ct_OCAMLMKLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLMKLIB" = x; then OCAMLMKLIB="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLMKLIB=$ac_ct_OCAMLMKLIB fi else OCAMLMKLIB="$ac_cv_prog_OCAMLMKLIB" fi # checking for ocamldoc if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamldoc", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamldoc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLDOC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLDOC"; then ac_cv_prog_OCAMLDOC="$OCAMLDOC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLDOC="${ac_tool_prefix}ocamldoc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLDOC=$ac_cv_prog_OCAMLDOC if test -n "$OCAMLDOC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLDOC" >&5 $as_echo "$OCAMLDOC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLDOC"; then ac_ct_OCAMLDOC=$OCAMLDOC # Extract the first word of "ocamldoc", so it can be a program name with args. set dummy ocamldoc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLDOC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLDOC"; then ac_cv_prog_ac_ct_OCAMLDOC="$ac_ct_OCAMLDOC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLDOC="ocamldoc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLDOC=$ac_cv_prog_ac_ct_OCAMLDOC if test -n "$ac_ct_OCAMLDOC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLDOC" >&5 $as_echo "$ac_ct_OCAMLDOC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLDOC" = x; then OCAMLDOC="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLDOC=$ac_ct_OCAMLDOC fi else OCAMLDOC="$ac_cv_prog_OCAMLDOC" fi # checking for ocamlbuild if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlbuild", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlbuild; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLBUILD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLBUILD"; then ac_cv_prog_OCAMLBUILD="$OCAMLBUILD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLBUILD="${ac_tool_prefix}ocamlbuild" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLBUILD=$ac_cv_prog_OCAMLBUILD if test -n "$OCAMLBUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLBUILD" >&5 $as_echo "$OCAMLBUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLBUILD"; then ac_ct_OCAMLBUILD=$OCAMLBUILD # Extract the first word of "ocamlbuild", so it can be a program name with args. set dummy ocamlbuild; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLBUILD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLBUILD"; then ac_cv_prog_ac_ct_OCAMLBUILD="$ac_ct_OCAMLBUILD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLBUILD="ocamlbuild" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLBUILD=$ac_cv_prog_ac_ct_OCAMLBUILD if test -n "$ac_ct_OCAMLBUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLBUILD" >&5 $as_echo "$ac_ct_OCAMLBUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLBUILD" = x; then OCAMLBUILD="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLBUILD=$ac_ct_OCAMLBUILD fi else OCAMLBUILD="$ac_cv_prog_OCAMLBUILD" fi if test "$OCAMLC" = "no"; then as_fn_error $? "You must install the OCaml compiler" "$LINENO" 5 fi # Check whether --enable-version_check was given. if test "${enable_version_check+set}" = set; then : enableval=$enable_version_check; fi # Check that OCaml version is greater or equal to 3.12.1 for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done if test "x${enable_version_check}" != "xno"; then : # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "3.12.1" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/false/;s/x${ax_compare_version_B}/true/;1q"` if test "$ax_compare_version" = "true" ; then as_fn_error $? "Your version of OCaml: $OCAMLVERSION is not supported" "$LINENO" 5 fi fi # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "4.00.0" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` if test "$ax_compare_version" = "true" ; then : fi ocaml_4="$ax_compare_version" # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "4.01.0" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` if test "$ax_compare_version" = "true" ; then : fi ocaml_4_01="$ax_compare_version" # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. ax_compare_version_A=`echo "$OCAMLVERSION" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version_B=`echo "4.02.0" | sed -e 's/\([0-9]*\)/Z\1Z/g' \ -e 's/Z\([0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/Z\([0-9][0-9][0-9]\)Z/Z0\1Z/g' \ -e 's/[^0-9]//g'` ax_compare_version=`echo "x$ax_compare_version_A x$ax_compare_version_B" | sed 's/^ *//' | sort -r | sed "s/x${ax_compare_version_A}/true/;s/x${ax_compare_version_B}/false/;1q"` if test "$ax_compare_version" = "true" ; then : fi ocaml_4_02="$ax_compare_version" # checking for ocamllex if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamllex", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamllex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLLEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLLEX"; then ac_cv_prog_OCAMLLEX="$OCAMLLEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLLEX="${ac_tool_prefix}ocamllex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLLEX=$ac_cv_prog_OCAMLLEX if test -n "$OCAMLLEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLLEX" >&5 $as_echo "$OCAMLLEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLLEX"; then ac_ct_OCAMLLEX=$OCAMLLEX # Extract the first word of "ocamllex", so it can be a program name with args. set dummy ocamllex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLLEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLLEX"; then ac_cv_prog_ac_ct_OCAMLLEX="$ac_ct_OCAMLLEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLLEX="ocamllex" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLLEX=$ac_cv_prog_ac_ct_OCAMLLEX if test -n "$ac_ct_OCAMLLEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLLEX" >&5 $as_echo "$ac_ct_OCAMLLEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLLEX" = x; then OCAMLLEX="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLLEX=$ac_ct_OCAMLLEX fi else OCAMLLEX="$ac_cv_prog_OCAMLLEX" fi if test "$OCAMLLEX" != "no"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamllex.opt", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamllex.opt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLLEXDOTOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLLEXDOTOPT"; then ac_cv_prog_OCAMLLEXDOTOPT="$OCAMLLEXDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLLEXDOTOPT="${ac_tool_prefix}ocamllex.opt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLLEXDOTOPT=$ac_cv_prog_OCAMLLEXDOTOPT if test -n "$OCAMLLEXDOTOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLLEXDOTOPT" >&5 $as_echo "$OCAMLLEXDOTOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLLEXDOTOPT"; then ac_ct_OCAMLLEXDOTOPT=$OCAMLLEXDOTOPT # Extract the first word of "ocamllex.opt", so it can be a program name with args. set dummy ocamllex.opt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLLEXDOTOPT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLLEXDOTOPT"; then ac_cv_prog_ac_ct_OCAMLLEXDOTOPT="$ac_ct_OCAMLLEXDOTOPT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLLEXDOTOPT="ocamllex.opt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLLEXDOTOPT=$ac_cv_prog_ac_ct_OCAMLLEXDOTOPT if test -n "$ac_ct_OCAMLLEXDOTOPT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLLEXDOTOPT" >&5 $as_echo "$ac_ct_OCAMLLEXDOTOPT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLLEXDOTOPT" = x; then OCAMLLEXDOTOPT="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLLEXDOTOPT=$ac_ct_OCAMLLEXDOTOPT fi else OCAMLLEXDOTOPT="$ac_cv_prog_OCAMLLEXDOTOPT" fi if test "$OCAMLLEXDOTOPT" != "no"; then OCAMLLEX=$OCAMLLEXDOTOPT fi fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlyacc", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlyacc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLYACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLYACC"; then ac_cv_prog_OCAMLYACC="$OCAMLYACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLYACC="${ac_tool_prefix}ocamlyacc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLYACC=$ac_cv_prog_OCAMLYACC if test -n "$OCAMLYACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLYACC" >&5 $as_echo "$OCAMLYACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLYACC"; then ac_ct_OCAMLYACC=$OCAMLYACC # Extract the first word of "ocamlyacc", so it can be a program name with args. set dummy ocamlyacc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLYACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLYACC"; then ac_cv_prog_ac_ct_OCAMLYACC="$ac_ct_OCAMLYACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLYACC="ocamlyacc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLYACC=$ac_cv_prog_ac_ct_OCAMLYACC if test -n "$ac_ct_OCAMLYACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLYACC" >&5 $as_echo "$ac_ct_OCAMLYACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLYACC" = x; then OCAMLYACC="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLYACC=$ac_ct_OCAMLYACC fi else OCAMLYACC="$ac_cv_prog_OCAMLYACC" fi # checking for ocamlfind if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ocamlfind", so it can be a program name with args. set dummy ${ac_tool_prefix}ocamlfind; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OCAMLFIND+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OCAMLFIND"; then ac_cv_prog_OCAMLFIND="$OCAMLFIND" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OCAMLFIND="${ac_tool_prefix}ocamlfind" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OCAMLFIND=$ac_cv_prog_OCAMLFIND if test -n "$OCAMLFIND"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OCAMLFIND" >&5 $as_echo "$OCAMLFIND" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OCAMLFIND"; then ac_ct_OCAMLFIND=$OCAMLFIND # Extract the first word of "ocamlfind", so it can be a program name with args. set dummy ocamlfind; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OCAMLFIND+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OCAMLFIND"; then ac_cv_prog_ac_ct_OCAMLFIND="$ac_ct_OCAMLFIND" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OCAMLFIND="ocamlfind" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OCAMLFIND=$ac_cv_prog_ac_ct_OCAMLFIND if test -n "$ac_ct_OCAMLFIND"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OCAMLFIND" >&5 $as_echo "$ac_ct_OCAMLFIND" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OCAMLFIND" = x; then OCAMLFIND="no" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OCAMLFIND=$ac_ct_OCAMLFIND fi else OCAMLFIND="$ac_cv_prog_OCAMLFIND" fi # Check whether --enable-certificate_check was given. if test "${enable_certificate_check+set}" = set; then : enableval=$enable_certificate_check; fi if test "x${enable_certificate_check}" = "xno"; then : curl_certificate_check=--insecure wget_certificate_check=--no-check-certificate fi for ac_prog in curl wget do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_FETCH+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$FETCH"; then ac_cv_prog_FETCH="$FETCH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_FETCH="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi FETCH=$ac_cv_prog_FETCH if test -n "$FETCH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FETCH" >&5 $as_echo "$FETCH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$FETCH" && break done test -n "$FETCH" || FETCH="no" if test x"$FETCH" = x"curl" ; then fetch="curl $curl_certificate_check -OL" elif test x"$FETCH" = x"wget" ; then fetch="wget $wget_certificate_check" else as_fn_error $? "You must have either curl or wget installed." "$LINENO" 5 fi echo { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package unix" >&5 $as_echo_n "checking for OCaml findlib package unix... " >&6; } unset found unset pkg found=no for pkg in unix ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_unix=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_unix=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package extlib" >&5 $as_echo_n "checking for OCaml findlib package extlib... " >&6; } unset found unset pkg found=no for pkg in extlib ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_extlib=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_extlib=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re" >&5 $as_echo_n "checking for OCaml findlib package re... " >&6; } unset found unset pkg found=no for pkg in re ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_re=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_re=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re.emacs" >&5 $as_echo_n "checking for OCaml findlib package re.emacs... " >&6; } unset found unset pkg found=no for pkg in re.emacs ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_re_emacs=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_re_emacs=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re.str" >&5 $as_echo_n "checking for OCaml findlib package re.str... " >&6; } unset found unset pkg found=no for pkg in re.str ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_re_str=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_re_str=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re.perl" >&5 $as_echo_n "checking for OCaml findlib package re.perl... " >&6; } unset found unset pkg found=no for pkg in re.perl ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_re_perl=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_re_perl=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re.pcre" >&5 $as_echo_n "checking for OCaml findlib package re.pcre... " >&6; } unset found unset pkg found=no for pkg in re.pcre ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_re_pcre=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_re_pcre=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package re.glob" >&5 $as_echo_n "checking for OCaml findlib package re.glob... " >&6; } unset found unset pkg found=no for pkg in re.glob ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_re_glob=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_re_glob=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package cmdliner" >&5 $as_echo_n "checking for OCaml findlib package cmdliner... " >&6; } unset found unset pkg found=no for pkg in cmdliner ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_cmdliner=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_cmdliner=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package ocamlgraph" >&5 $as_echo_n "checking for OCaml findlib package ocamlgraph... " >&6; } unset found unset pkg found=no for pkg in ocamlgraph ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_ocamlgraph=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_ocamlgraph=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package cudf" >&5 $as_echo_n "checking for OCaml findlib package cudf... " >&6; } unset found unset pkg found=no for pkg in cudf ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_cudf=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_cudf=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package dose3" >&5 $as_echo_n "checking for OCaml findlib package dose3... " >&6; } unset found unset pkg found=no for pkg in dose3 dose ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_dose3=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_dose3=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCaml findlib package jsonm" >&5 $as_echo_n "checking for OCaml findlib package jsonm... " >&6; } unset found unset pkg found=no for pkg in jsonm ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: found" >&5 $as_echo "found" >&6; } OCAML_PKG_jsonm=$pkg found=yes break fi done if test "$found" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } OCAML_PKG_jsonm=no fi echo if test "$OCAML_PKG_extlib" = "no" || test "$OCAML_PKG_re" = "no" || test "$OCAML_PKG_cmdliner" = "no" || test "$OCAML_PKG_ocamlgraph" = "no" || test "$OCAML_PKG_cudf" = "no" || test "$OCAML_PKG_dose3" = "no" || test "$OCAML_PKG_jsonm" = "no"; then echo "============================================================================" echo "Some dependencies are missing. If you are just interested in the stand-alone" echo "binaries, run 'make lib-ext' to download and include them." echo "============================================================================" echo hasalldeps="" else hasalldeps="true" fi if test "$prefix" = "NONE"; then prefix=$ac_default_prefix fi ac_config_files="$ac_config_files Makefile.config META src/core/opamVersion.ml" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by opam $as_me 1.2.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ opam config.status 1.2.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; "META") CONFIG_FILES="$CONFIG_FILES META" ;; "src/core/opamVersion.ml") CONFIG_FILES="$CONFIG_FILES src/core/opamVersion.ml" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo bindir="`eval echo ${bindir}`" bindir="`eval echo ${bindir}`" mandir="`eval echo ${mandir}`" mandir="`eval echo ${mandir}`" echo Executables will be installed in ${bindir} echo Manual pages will be installed in ${mandir} opam-full-1.2.2/configure.ac0000644000175000017500000000647112517374212014430 0ustar useruserAC_INIT(opam,1.2.2) AC_COPYRIGHT(Copyright 2012-2015 OcamlPro SAS) AC_CONFIG_MACRO_DIR([m4]) AC_PROG_CC AC_PROG_OCAML if test "$OCAMLC" = "no"; then AC_MSG_ERROR([You must install the OCaml compiler]) fi AC_ARG_ENABLE([version_check], AS_HELP_STRING([--disable-version-check], [Do not check OCaml version]) ) # Check that OCaml version is greater or equal to 3.12.1 AS_IF([test "x${enable_version_check}" != "xno"], [ AX_COMPARE_VERSION( [$OCAMLVERSION], [lt], [3.12.1], AC_MSG_ERROR([Your version of OCaml: $OCAMLVERSION is not supported])) ]) AX_COMPARE_VERSION([$OCAMLVERSION], [ge], [4.00.0]) AC_SUBST(ocaml_4,"$ax_compare_version") AX_COMPARE_VERSION([$OCAMLVERSION], [ge], [4.01.0]) AC_SUBST(ocaml_4_01,"$ax_compare_version") AX_COMPARE_VERSION([$OCAMLVERSION], [ge], [4.02.0]) AC_SUBST(ocaml_4_02,"$ax_compare_version") AC_PROG_OCAMLLEX AC_PROG_OCAMLYACC AC_PROG_FINDLIB AC_ARG_ENABLE([certificate_check], AS_HELP_STRING([--disable-certificate-check], [Do not check the certificate of OPAM's dependency archives]) ) AS_IF([test "x${enable_certificate_check}" = "xno"], [ curl_certificate_check=--insecure wget_certificate_check=--no-check-certificate ]) AC_CHECK_PROGS(FETCH,[curl wget],no) if test x"$FETCH" = x"curl" ; then AC_SUBST(fetch, "curl $curl_certificate_check -OL") elif test x"$FETCH" = x"wget" ; then AC_SUBST(fetch, "wget $wget_certificate_check") else AC_MSG_ERROR([You must have either curl or wget installed.]) fi echo AC_CHECK_OCAML_PKG([unix]) AC_CHECK_OCAML_PKG([extlib]) AC_CHECK_OCAML_PKG([re]) AC_CHECK_OCAML_PKG([re.emacs]) AC_CHECK_OCAML_PKG([re.str]) AC_CHECK_OCAML_PKG([re.perl]) AC_CHECK_OCAML_PKG([re.pcre]) AC_CHECK_OCAML_PKG([re.glob]) AC_CHECK_OCAML_PKG([cmdliner]) AC_CHECK_OCAML_PKG([ocamlgraph]) AC_CHECK_OCAML_PKG([cudf]) AC_CHECK_OCAML_PKG(dose3,dose) AC_CHECK_OCAML_PKG([jsonm]) dnl echo dnl echo "extlib........................ ${OCAML_PKG_extlib}" dnl echo "re............................ ${OCAML_PKG_re}" dnl echo "cmdliner...................... ${OCAML_PKG_cmdliner}" dnl echo "graph......................... ${OCAML_PKG_ocamlgraph}" dnl echo "cudf.......................... ${OCAML_PKG_cudf}" dnl echo "dose3......................... ${OCAML_PKG_dose3}" dnl echo "jsonm......................... ${OCAML_PKG_jsonm}" echo if test "$OCAML_PKG_extlib" = "no" || test "$OCAML_PKG_re" = "no" || test "$OCAML_PKG_cmdliner" = "no" || test "$OCAML_PKG_ocamlgraph" = "no" || test "$OCAML_PKG_cudf" = "no" || test "$OCAML_PKG_dose3" = "no" || test "$OCAML_PKG_jsonm" = "no"; then echo "============================================================================" echo "Some dependencies are missing. If you are just interested in the stand-alone" echo "binaries, run 'make lib-ext' to download and include them." echo "============================================================================" echo AC_SUBST(hasalldeps,"") else AC_SUBST(hasalldeps,"true") fi if test "$prefix" = "NONE"; then prefix=$ac_default_prefix fi AC_CONFIG_FILES( Makefile.config META src/core/opamVersion.ml ) AC_OUTPUT echo bindir="`eval echo ${bindir}`" bindir="`eval echo ${bindir}`" mandir="`eval echo ${mandir}`" mandir="`eval echo ${mandir}`" echo Executables will be installed in ${bindir} echo Manual pages will be installed in ${mandir} opam-full-1.2.2/opam-lib.install0000644000175000017500000001603012517374212015222 0ustar useruserlib: [ "META" "?src/opam-core.a" "src/opam-core.cma" "?src/opam-core.cmxa" "src/core/opamScript.cmi" "src/core/opamScript.mli" "?src/core/opamScript.cmx" "?src/core/opamScript.cmxs" "?src/core/opamScript.cmt" "src/core/opamJson.cmi" "src/core/opamJson.mli" "?src/core/opamJson.cmx" "?src/core/opamJson.cmxs" "?src/core/opamJson.cmti" "src/core/opamMisc.cmi" "src/core/opamMisc.mli" "?src/core/opamMisc.cmx" "?src/core/opamMisc.cmxs" "?src/core/opamMisc.cmti" "src/core/opamGlobals.cmi" "src/core/opamGlobals.mli" "?src/core/opamGlobals.cmx" "?src/core/opamGlobals.cmxs" "?src/core/opamGlobals.cmt" "src/core/opamVersion.cmi" "src/core/opamVersion.mli" "?src/core/opamVersion.cmx" "?src/core/opamVersion.cmxs" "?src/core/opamVersion.cmti" "src/core/opamProcess.cmi" "src/core/opamProcess.mli" "?src/core/opamProcess.cmx" "?src/core/opamProcess.cmxs" "?src/core/opamProcess.cmti" "src/core/opamSystem.cmi" "src/core/opamSystem.mli" "?src/core/opamSystem.cmx" "?src/core/opamSystem.cmxs" "?src/core/opamSystem.cmti" "src/core/opamParallel.cmi" "src/core/opamParallel.mli" "?src/core/opamParallel.cmx" "?src/core/opamParallel.cmxs" "?src/core/opamParallel.cmt" "src/core/opamActionGraph.cmi" "src/core/opamActionGraph.mli" "?src/core/opamActionGraph.cmx" "?src/core/opamActionGraph.cmxs" "?src/core/opamActionGraph.cmt" "src/core/opamFilename.cmi" "src/core/opamFilename.mli" "?src/core/opamFilename.cmx" "?src/core/opamFilename.cmxs" "?src/core/opamFilename.cmti" "src/core/opamSwitch.cmi" "src/core/opamSwitch.mli" "?src/core/opamSwitch.cmx" "?src/core/opamSwitch.cmxs" "?src/core/opamSwitch.cmti" "src/core/opamPackage.cmi" "src/core/opamPackage.mli" "?src/core/opamPackage.cmx" "?src/core/opamPackage.cmxs" "?src/core/opamPackage.cmti" "src/core/opamFormula.cmi" "src/core/opamFormula.mli" "?src/core/opamFormula.cmx" "?src/core/opamFormula.cmxs" "?src/core/opamFormula.cmti" "src/core/opamCompiler.cmi" "src/core/opamCompiler.mli" "?src/core/opamCompiler.cmx" "?src/core/opamCompiler.cmxs" "?src/core/opamCompiler.cmti" "src/core/opamVariable.cmi" "src/core/opamVariable.mli" "?src/core/opamVariable.cmx" "?src/core/opamVariable.cmxs" "?src/core/opamVariable.cmti" "src/core/opamRepositoryName.cmi" "src/core/opamRepositoryName.mli" "?src/core/opamRepositoryName.cmx" "?src/core/opamRepositoryName.cmxs" "?src/core/opamRepositoryName.cmti" "src/core/opamTypes.cmi" "src/core/opamTypes.mli" "?src/core/opamTypes.cmti" "src/core/opamTypesBase.cmi" "src/core/opamTypesBase.mli" "?src/core/opamTypesBase.cmx" "?src/core/opamTypesBase.cmxs" "?src/core/opamTypesBase.cmti" "src/core/opamFormat.cmi" "src/core/opamFormat.mli" "?src/core/opamFormat.cmx" "?src/core/opamFormat.cmxs" "?src/core/opamFormat.cmti" "src/core/opamParser.cmi" "src/core/opamParser.mli" "?src/core/opamParser.cmx" "?src/core/opamParser.cmxs" "?src/core/opamParser.cmti" "src/core/opamLexer.cmi" "src/core/opamLexer.mli" "?src/core/opamLexer.cmx" "?src/core/opamLexer.cmxs" "?src/core/opamLexer.cmt" "src/core/opamLineLexer.cmi" "src/core/opamLineLexer.mli" "?src/core/opamLineLexer.cmx" "?src/core/opamLineLexer.cmxs" "?src/core/opamLineLexer.cmt" "src/core/opamPath.cmi" "src/core/opamPath.mli" "?src/core/opamPath.cmx" "?src/core/opamPath.cmxs" "?src/core/opamPath.cmti" "src/core/opamFile.cmi" "src/core/opamFile.mli" "?src/core/opamFile.cmx" "?src/core/opamFile.cmxs" "?src/core/opamFile.cmti" "src/core/opamRepository.cmi" "src/core/opamRepository.mli" "?src/core/opamRepository.cmx" "?src/core/opamRepository.cmxs" "?src/core/opamRepository.cmti" "src/core/opamFilter.cmi" "src/core/opamFilter.mli" "?src/core/opamFilter.cmx" "?src/core/opamFilter.cmxs" "?src/core/opamFilter.cmti" "?src/opam-solver.a" "src/opam-solver.cma" "?src/opam-solver.cmxa" "src/solver/opamCudf.cmi" "src/solver/opamCudf.mli" "?src/solver/opamCudf.cmx" "?src/solver/opamCudf.cmxs" "?src/solver/opamCudf.cmti" "src/solver/opamHeuristic.cmi" "src/solver/opamHeuristic.mli" "?src/solver/opamHeuristic.cmx" "?src/solver/opamHeuristic.cmxs" "?src/solver/opamHeuristic.cmti" "src/solver/opamSolver.cmi" "src/solver/opamSolver.mli" "?src/solver/opamSolver.cmx" "?src/solver/opamSolver.cmxs" "?src/solver/opamSolver.cmti" "?src/opam-repositories.a" "src/opam-repositories.cma" "?src/opam-repositories.cmxa" "src/repositories/opamHTTP.cmi" "src/repositories/opamHTTP.mli" "?src/repositories/opamHTTP.cmx" "?src/repositories/opamHTTP.cmxs" "?src/repositories/opamHTTP.cmti" "src/repositories/opamLocal.cmi" "src/repositories/opamLocal.mli" "?src/repositories/opamLocal.cmx" "?src/repositories/opamLocal.cmxs" "?src/repositories/opamLocal.cmti" "src/repositories/opamVCS.cmi" "src/repositories/opamVCS.mli" "?src/repositories/opamVCS.cmx" "?src/repositories/opamVCS.cmxs" "?src/repositories/opamVCS.cmti" "src/repositories/opamGit.cmi" "src/repositories/opamGit.mli" "?src/repositories/opamGit.cmx" "?src/repositories/opamGit.cmxs" "?src/repositories/opamGit.cmti" "src/repositories/opamDarcs.cmi" "src/repositories/opamDarcs.mli" "?src/repositories/opamDarcs.cmx" "?src/repositories/opamDarcs.cmxs" "?src/repositories/opamDarcs.cmti" "src/repositories/opamHg.cmi" "src/repositories/opamHg.mli" "?src/repositories/opamHg.cmx" "?src/repositories/opamHg.cmxs" "?src/repositories/opamHg.cmti" "?src/opam-client.a" "src/opam-client.cma" "?src/opam-client.cmxa" "src/client/opamState.cmi" "src/client/opamState.mli" "?src/client/opamState.cmx" "?src/client/opamState.cmxs" "?src/client/opamState.cmti" "src/client/opamAction.cmi" "src/client/opamAction.mli" "?src/client/opamAction.cmx" "?src/client/opamAction.cmxs" "?src/client/opamAction.cmti" "src/client/opamSolution.cmi" "src/client/opamSolution.mli" "?src/client/opamSolution.cmx" "?src/client/opamSolution.cmxs" "?src/client/opamSolution.cmti" "src/client/opamSwitchCommand.cmi" "src/client/opamSwitchCommand.mli" "?src/client/opamSwitchCommand.cmx" "?src/client/opamSwitchCommand.cmxs" "?src/client/opamSwitchCommand.cmti" "src/client/opamConfigCommand.cmi" "src/client/opamConfigCommand.mli" "?src/client/opamConfigCommand.cmx" "?src/client/opamConfigCommand.cmxs" "?src/client/opamConfigCommand.cmti" "src/client/opamRepositoryCommand.cmi" "src/client/opamRepositoryCommand.mli" "?src/client/opamRepositoryCommand.cmx" "?src/client/opamRepositoryCommand.cmxs" "?src/client/opamRepositoryCommand.cmti" "src/client/opamPinCommand.cmi" "src/client/opamPinCommand.mli" "?src/client/opamPinCommand.cmx" "?src/client/opamPinCommand.cmxs" "?src/client/opamPinCommand.cmti" "src/client/opamClient.cmi" "src/client/opamClient.mli" "?src/client/opamClient.cmx" "?src/client/opamClient.cmxs" "?src/client/opamClient.cmti" "src/tools/opam_admin_top.cmi" "src/tools/opam_admin_top.mli" "?src/tools/opam_admin_top.cmti" ] bin: [ "src/opam-admin.top" ] opam-full-1.2.2/META.in0000644000175000017500000000134612517374212013214 0ustar useruserversion = "@PACKAGE_VERSION@" description = "OCaml Package Manager base API" requires = "dose3, cudf, ocamlgraph, unix, re, re.str, re.glob, jsonm" archive(byte) = "opam-core.cma" archive(native) = "opam-core.cmxa" package "repositories" ( version = "@PACKAGE_VERSION@" archive(byte) = "opam-repositories.cma" archive(native) = "opam-repositories.cmxa" requires = "opam-lib" ) package "solver" ( version = "@PACKAGE_VERSION@" archive(byte) = "opam-solver.cma" archive(native) = "opam-solver.cmxa" requires = "opam-lib" ) package "client" ( version = "@PACKAGE_VERSION@" archive(byte) = "opam-client.cma" archive(native) = "opam-client.cmxa" requires = "opam-lib, opam-lib.solver, opam-lib.repositories, cmdliner" ) opam-full-1.2.2/opam0000644000175000017500000000075112517374212013014 0ustar useruseropam-version: "1.2" name: "opam-lib" version: "1.2.2" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Thomas Gazagnaire " "Louis Gesbert " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "https://github.com/ocaml/opam" build: [ ["./configure"] [make] ] depends: [ "ocamlgraph" "cmdliner" "dose" {>= "3.2.2+opam"} "cudf" "re" {>= "1.2.0"} "ocamlfind" "jsonm" ] opam-full-1.2.2/OCamlMakefile0000644000175000017500000010514212517374212014511 0ustar useruser########################################################################### # OCamlMakefile # Copyright (C) 1999- Markus Mottl # # For updates see: # http://www.ocaml.info/home/ocaml_sources.html # ########################################################################### # Modified by damien for .glade.ml compilation # Set these variables to the names of the sources to be processed and # the result variable. Order matters during linkage! ifndef SOURCES SOURCES := foo.ml endif export SOURCES ifndef RES_CLIB_SUF RES_CLIB_SUF := _stubs endif export RES_CLIB_SUF ifndef RESULT RESULT := foo endif export RESULT := $(strip $(RESULT)) export LIB_PACK_NAME ifndef DOC_FILES DOC_FILES := $(filter %.mli, $(SOURCES)) endif export DOC_FILES FIRST_DOC_FILE := $(firstword $(DOC_FILES)) export BCSUFFIX export NCSUFFIX ifndef TOPSUFFIX TOPSUFFIX := .top endif export TOPSUFFIX # Eventually set include- and library-paths, libraries to link, # additional compilation-, link- and ocamlyacc-flags # Path- and library information needs not be written with "-I" and such... # Define THREADS if you need it, otherwise leave it unset (same for # USE_CAMLP4)! export THREADS export VMTHREADS export ANNOTATE export USE_CAMLP4 export INCDIRS export LIBDIRS export EXTLIBDIRS export RESULTDEPS export OCAML_DEFAULT_DIRS export LIBS export CLIBS export CFRAMEWORKS export OCAMLFLAGS export OCAMLNCFLAGS export OCAMLBCFLAGS export OCAMLLDFLAGS export OCAMLNLDFLAGS export OCAMLBLDFLAGS export OCAMLMKLIB_FLAGS ifndef OCAMLCPFLAGS OCAMLCPFLAGS := a endif export OCAMLCPFLAGS ifndef DOC_DIR DOC_DIR := doc endif export DOC_DIR export PPFLAGS export LFLAGS export YFLAGS export IDLFLAGS export OCAMLDOCFLAGS export OCAMLFIND_INSTFLAGS export DVIPSFLAGS export STATIC # Add a list of optional trash files that should be deleted by "make clean" export TRASH ECHO := echo ifdef REALLY_QUIET export REALLY_QUIET ECHO := true LFLAGS := $(LFLAGS) -q YFLAGS := $(YFLAGS) -q endif #################### variables depending on your OCaml-installation SYSTEM := $(shell ocamlc -config 2>/dev/null | grep system | sed 's/system: //') # This may be # - mingw # - mingw64 # - win32 # - cygwin # - some other string means Unix # - empty means ocamlc does not support -config ifeq ($(SYSTEM),$(filter $(SYSTEM),mingw mingw64)) MINGW=1 endif ifeq ($(SYSTEM),win32) MSVC=1 endif ifdef MINGW export MINGW WIN32 := 1 # The default value 'cc' makes 'ocamlc -cc "cc"' raises the error 'The # NTVDM CPU has encountered an illegal instruction'. ifndef CC MNO_CYGWIN := $(shell gcc -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) CC := gcc else MNO_CYGWIN := $(shell $$CC -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) endif # We are compiling with cygwin tools: ifeq ($(MNO_CYGWIN),0) CFLAGS_WIN32 := -mno-cygwin endif # The OCaml C header files use this flag: CFLAGS += -D__MINGW32__ endif ifdef MSVC export MSVC WIN32 := 1 ifndef STATIC CPPFLAGS_WIN32 := -DCAML_DLL endif CFLAGS_WIN32 += -nologo EXT_OBJ := obj EXT_LIB := lib ifeq ($(CC),gcc) # work around GNU Make default value ifdef THREADS CC := cl -MT else CC := cl endif endif ifeq ($(CXX),g++) # work around GNU Make default value CXX := $(CC) endif CFLAG_O := -Fo endif ifdef WIN32 EXT_CXX := cpp EXE := .exe endif ifndef EXT_OBJ EXT_OBJ := o endif ifndef EXT_LIB EXT_LIB := a endif ifndef EXT_CXX EXT_CXX := cc endif ifndef EXE EXE := # empty endif ifndef CFLAG_O CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! endif export CC export CXX export CFLAGS export CXXFLAGS export LDFLAGS export CPPFLAGS ifndef RPATH_FLAG ifdef ELF_RPATH_FLAG RPATH_FLAG := $(ELF_RPATH_FLAG) else RPATH_FLAG := -R endif endif export RPATH_FLAG ifndef MSVC ifndef PIC_CFLAGS PIC_CFLAGS := -fPIC endif ifndef PIC_CPPFLAGS PIC_CPPFLAGS := -DPIC endif endif export PIC_CFLAGS export PIC_CPPFLAGS BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) ifndef OCAMLFIND OCAMLFIND := ocamlfind endif export OCAMLFIND ifndef OCAML OCAML := ocaml endif export OCAML ifndef OCAMLC OCAMLC := ocamlc endif export OCAMLC ifndef OCAMLOPT OCAMLOPT := ocamlopt endif export OCAMLOPT ifndef OCAMLMKTOP OCAMLMKTOP := ocamlmktop endif export OCAMLMKTOP ifndef OCAMLCP OCAMLCP := ocamlcp endif export OCAMLCP ifndef OCAMLDEP OCAMLDEP := ocamldep endif export OCAMLDEP ifndef OCAMLLEX OCAMLLEX := ocamllex endif export OCAMLLEX ifndef OCAMLYACC OCAMLYACC := ocamlyacc endif export OCAMLYACC ifndef OCAMLMKLIB OCAMLMKLIB := ocamlmklib endif export OCAMLMKLIB ifndef OCAML_GLADECC OCAML_GLADECC := lablgladecc2 endif export OCAML_GLADECC ifndef OCAML_GLADECC_FLAGS OCAML_GLADECC_FLAGS := endif export OCAML_GLADECC_FLAGS ifndef CAMELEON_REPORT CAMELEON_REPORT := report endif export CAMELEON_REPORT ifndef CAMELEON_REPORT_FLAGS CAMELEON_REPORT_FLAGS := endif export CAMELEON_REPORT_FLAGS ifndef CAMELEON_ZOGGY CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo endif export CAMELEON_ZOGGY ifndef CAMELEON_ZOGGY_FLAGS CAMELEON_ZOGGY_FLAGS := endif export CAMELEON_ZOGGY_FLAGS ifndef OXRIDL OXRIDL := oxridl endif export OXRIDL ifndef CAMLIDL CAMLIDL := camlidl endif export CAMLIDL ifndef CAMLIDLDLL CAMLIDLDLL := camlidldll endif export CAMLIDLDLL ifndef NOIDLHEADER MAYBE_IDL_HEADER := -header endif export NOIDLHEADER export NO_CUSTOM ifndef CAMLP4 CAMLP4 := camlp4 endif export CAMLP4 ifndef REAL_OCAMLFIND ifdef PACKS ifndef CREATE_LIB ifdef THREADS PACKS += threads endif endif empty := space := $(empty) $(empty) comma := , ifdef PREDS PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) else OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) OCAML_DEP_PACKAGES := endif OCAML_FIND_LINKPKG := -linkpkg REAL_OCAMLFIND := $(OCAMLFIND) endif endif export OCAML_FIND_PACKAGES export OCAML_DEP_PACKAGES export OCAML_FIND_LINKPKG export REAL_OCAMLFIND ifndef OCAMLDOC OCAMLDOC := ocamldoc endif export OCAMLDOC ifndef LATEX LATEX := latex endif export LATEX ifndef DVIPS DVIPS := dvips endif export DVIPS ifndef PS2PDF PS2PDF := ps2pdf endif export PS2PDF ifndef OCAMLMAKEFILE OCAMLMAKEFILE := OCamlMakefile endif export OCAMLMAKEFILE ifndef OCAMLLIBPATH OCAMLLIBPATH := \ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml) endif export OCAMLLIBPATH ifndef OCAML_LIB_INSTALL OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib endif export OCAML_LIB_INSTALL ########################################################################### #################### change following sections only if #################### you know what you are doing! # delete target files when a build command fails .PHONY: .DELETE_ON_ERROR .DELETE_ON_ERROR: # for pedants using "--warn-undefined-variables" export MAYBE_IDL export REAL_RESULT export CAMLIDLFLAGS export THREAD_FLAG export RES_CLIB export MAKEDLL export ANNOT_FLAG export C_OXRIDL export SUBPROJS export CFLAGS_WIN32 export CPPFLAGS_WIN32 INCFLAGS := SHELL := /bin/sh MLDEPDIR := ._d BCDIDIR := ._bcdi NCDIDIR := ._ncdi FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) FILTERED_REP := $(filter %.rep, $(FILTERED)) DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) AUTO_REP := $(FILTERED_REP:.rep=.ml) FILTERED_ZOG := $(filter %.zog, $(FILTERED)) DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) FILTERED_GLADE := $(filter %.glade, $(FILTERED)) DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) FILTERED_ML := $(filter %.ml, $(FILTERED)) DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) FILTERED_MLI := $(filter %.mli, $(FILTERED)) DEP_MLI := $(FILTERED_MLI:.mli=.di) FILTERED_MLL := $(filter %.mll, $(FILTERED)) DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) AUTO_MLL := $(FILTERED_MLL:.mll=.ml) FILTERED_MLY := $(filter %.mly, $(FILTERED)) DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) FILTERED_IDL := $(filter %.idl, $(FILTERED)) DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) ifndef NOIDLHEADER C_IDL += $(FILTERED_IDL:.idl=.h) endif OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED)) DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di) AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL) FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED)) OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.m=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) MLDEPS := $(filter %.d, $(ALL_DEPS)) MLIDEPS := $(filter %.di, $(ALL_DEPS)) BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED)) IMPLO_INTF := $(ALLML:%.mli=%.mli.__) IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ $(basename $(file)).cmi $(basename $(file)).cmo) IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) INTF := $(filter %.cmi, $(IMPLO_INTF)) IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) IMPL_ASM := $(IMPL_CMO:.cmo=.asm) IMPL_S := $(IMPL_CMO:.cmo=.s) OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) EXECS := $(addsuffix $(EXE), \ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) ifdef WIN32 EXECS += $(BCRESULT).dll $(NCRESULT).dll endif CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) ifneq ($(strip $(OBJ_LINK)),) RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) endif ifdef WIN32 DLLSONAME := dll$(CLIB_BASE).dll else DLLSONAME := dll$(CLIB_BASE).so endif NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmti $(BCRESULT).cmo \ $(NCRESULT).cmi $(NCRESULT).cmti $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ $(RES_CLIB) $(IMPL_CMO:.cmo=.cmt) $(IMPL_CMO:.cmo=.cmti) \ $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx \ $(LIB_PACK_NAME).$(EXT_OBJ) ifndef STATIC NONEXECS += $(DLLSONAME) endif ifndef LIBINSTALL_FILES LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) LIBINSTALL_FILES += $(DLLSONAME) endif endif endif export LIBINSTALL_FILES ifdef WIN32 # some extra stuff is created while linking DLLs NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib endif TARGETS := $(EXECS) $(NONEXECS) # If there are IDL-files ifneq ($(strip $(FILTERED_IDL)),) MAYBE_IDL := -cclib -lcamlidl endif ifdef USE_CAMLP4 CAMLP4PATH := \ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4) INCFLAGS := -I $(CAMLP4PATH) CINCFLAGS := -I$(CAMLP4PATH) endif INCFLAGS := $(INCFLAGS) $(INCDIRS:%=-I %) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) ifndef MSVC CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%) ifeq ($(ELF_RPATH), yes) CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) endif endif ifndef PROFILING INTF_OCAMLC := $(OCAMLC) else ifndef THREADS INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) else # OCaml does not support profiling byte code # with threads (yet), therefore we force an error. ifndef REAL_OCAMLC $(error Profiling of multithreaded byte code not yet supported by OCaml) endif INTF_OCAMLC := $(OCAMLC) endif endif ifndef MSVC COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)) ifeq ($(ELF_RPATH),yes) COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) endif else COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \ $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \ $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) " endif CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %') ifdef MSVC ifndef STATIC # MSVC libraries do not have 'lib' prefix CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) endif endif ifneq ($(strip $(OBJ_LINK)),) ifdef CREATE_LIB OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) else OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) endif else OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) endif ifdef LIB_PACK_NAME FOR_PACK_NAME := $(shell echo $(LIB_PACK_NAME) | awk '{print toupper(substr($$0,1,1))substr($$0,2)}') endif # If we have to make byte-code ifndef REAL_OCAMLC BYTE_OCAML := y # EXTRADEPS is added dependencies we have to insert for all # executable files we generate. Ideally it should be all of the # libraries we use, but it's hard to find the ones that get searched on # the path since I don't know the paths built into the compiler, so # just include the ones with slashes in their names. EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLBCFLAGS) endif REAL_OCAMLC := $(INTF_OCAMLC) REAL_IMPL := $(IMPL_CMO) REAL_IMPL_INTF := $(IMPLO_INTF) IMPL_SUF := .cmo DEPFLAGS := MAKE_DEPS := $(MLDEPS) $(BCDEPIS) ifdef CREATE_LIB override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) MAKEDLL := $(DLLSONAME) ALL_LDFLAGS := -dllib $(DLLSONAME) endif endif endif ifndef NO_CUSTOM ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" "" ALL_LDFLAGS += -custom endif endif ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ $(COMMON_LDFLAGS) $(LIBS:%=%.cma) CAMLIDLDLLFLAGS := ifdef THREADS ifdef VMTHREADS THREAD_FLAG := -vmthread else THREAD_FLAG := -thread endif ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS) endif endif endif # we have to make native-code else EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef PROFILING SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) PLDFLAGS := else SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) PLDFLAGS := -p endif ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLNCFLAGS) endif REAL_IMPL := $(IMPL_CMX) REAL_IMPL_INTF := $(IMPLX_INTF) IMPL_SUF := .cmx override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS) DEPFLAGS := -native MAKE_DEPS := $(MLDEPS) $(NCDEPIS) ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) CAMLIDLDLLFLAGS := -opt ifndef CREATE_LIB ALL_LDFLAGS += $(LIBS:%=%.cmxa) else override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) endif ifdef THREADS THREAD_FLAG := -thread ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS) endif endif endif endif export MAKE_DEPS ifdef ANNOTATE ANNOT_FLAG := -annot else endif ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) ifdef make_deps -include $(MAKE_DEPS) PRE_TARGETS := endif ########################################################################### # USER RULES # Call "OCamlMakefile QUIET=" to get rid of all of the @'s. QUIET=@ # generates byte-code (default) byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes bc: byte-code byte-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes bcnl: byte-code-nolink top: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes # generates native-code native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes nc: native-code native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncnl: native-code-nolink # generates byte-code libraries byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" \ CREATE_LIB=yes \ make_deps=yes bcl: byte-code-library # generates native-code libraries native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes ncl: native-code-library ifdef WIN32 # generates byte-code dll byte-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).dll \ REAL_RESULT="$(BCRESULT)" \ make_deps=yes bcd: byte-code-dll # generates native-code dll native-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).dll \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncd: native-code-dll endif # generates byte-code with debugging information debug-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dc: debug-code debug-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcnl: debug-code-nolink # generates byte-code with debugging information (native code) debug-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dnc: debug-native-code debug-native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncnl: debug-native-code-nolink # generates byte-code libraries with debugging information debug-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcl: debug-code-library # generates byte-code libraries with debugging information (native code) debug-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncl: debug-native-code-library # generates byte-code for profiling profiling-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ make_deps=yes pbc: profiling-byte-code # generates native-code profiling-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PROFILING="y" \ make_deps=yes pnc: profiling-native-code # generates byte-code libraries profiling-byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ CREATE_LIB=yes \ make_deps=yes pbcl: profiling-byte-code-library # generates native-code libraries profiling-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" PROFILING="y" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes pncl: profiling-native-code-library # packs byte-code objects pack-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ REAL_RESULT="$(BCRESULT)" \ PACK_LIB=yes make_deps=yes pabc: pack-byte-code # packs native-code objects pack-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PACK_LIB=yes make_deps=yes panc: pack-native-code # generates HTML-documentation htdoc: $(DOC_DIR)/$(RESULT)/html/index.html # generates Latex-documentation ladoc: $(DOC_DIR)/$(RESULT)/latex/doc.tex # generates PostScript-documentation psdoc: $(DOC_DIR)/$(RESULT)/latex/doc.ps # generates PDF-documentation pdfdoc: $(DOC_DIR)/$(RESULT)/latex/doc.pdf # generates all supported forms of documentation doc: htdoc ladoc psdoc pdfdoc ########################################################################### # LOW LEVEL RULES $(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) ifdef WIN32 $(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ -o $@ $(REAL_IMPL) endif %$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) .SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \ .rep .zog .glade ifndef STATIC ifdef MINGW # From OCaml 3.11.0, ocamlmklib is available on windows OCAMLMLIB_EXISTS = $(shell which $(OCAMLMKLIB)) ifeq ($(strip $(OCAMLMLIB_EXISTS)),) $(DLLSONAME): $(OBJ_LINK) $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \ '$(OCAMLLIBPATH)/ocamlrun.a' \ -Wl,--whole-archive \ -Wl,--export-all-symbols \ -Wl,--allow-multiple-definition \ -Wl,--enable-auto-import else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \ $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif else ifdef MSVC $(DLLSONAME): $(OBJ_LINK) link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \ '$(OCAMLLIBPATH)/ocamlrun.lib' else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif endif endif ifndef LIB_PACK_NAME $(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) else # Packing a bytecode library LIB_PACK_NAME_MLI = $(wildcard $(LIB_PACK_NAME).mli) ifeq ($(LIB_PACK_NAME_MLI),) LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi else # $(LIB_PACK_NAME).mli exists, it likely depends on other compiled interfaces LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi: $(REAL_IMPL_INTF) endif ifdef BYTE_OCAML $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL) # Packing into a unit which can be transformed into a library # Remember the .ml's must have been compiled with -for-pack $(LIB_PACK_NAME) else $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx $(OCAMLLDFLAGS) $(REAL_IMPL) endif $(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(LIB_PACK_NAME).cmo $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(filter-out -custom, $(ALL_LDFLAGS)) -o $@ $(LIB_PACK_NAME).cmx endif $(RES_CLIB): $(OBJ_LINK) ifndef MSVC ifneq ($(strip $(OBJ_LINK)),) $(AR) rcs $@ $(OBJ_LINK) endif else ifneq ($(strip $(OBJ_LINK)),) lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) endif endif %.cmi: %.mli $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ fi %.cmi: %$(IMPL_SUF); %$(IMPL_SUF) %.$(EXT_OBJ): %.ml $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ fi .PRECIOUS: %.ml %.ml: %.mll $(OCAMLLEX) $(LFLAGS) $< .PRECIOUS: %.ml %.mli %.ml %.mli: %.mly $(OCAMLYACC) $(YFLAGS) $< $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \ if [ ! -z "$$pp" ]; then \ mv $*.ml $*.ml.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \ cat $*.ml.temporary >> $*.ml; \ rm $*.ml.temporary; \ mv $*.mli $*.mli.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \ cat $*.mli.temporary >> $*.mli; \ rm $*.mli.temporary; \ fi .PRECIOUS: %.ml %.ml: %.rep $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< .PRECIOUS: %.ml %.ml: %.zog $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ .PRECIOUS: %.ml %.ml: %.glade $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ .PRECIOUS: %.ml %.mli %.ml %.mli: %.oxridl $(OXRIDL) $< .PRECIOUS: %.ml %.mli %_stubs.c %.h %.ml %.mli %_stubs.c %.h: %.idl $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ $(CAMLIDLFLAGS) $< $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi %.$(EXT_OBJ): %.c $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \ $(CPPFLAGS) $(CPPFLAGS_WIN32) \ $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $< %.$(EXT_OBJ): %.m $(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ %.$(EXT_OBJ): %.$(EXT_CXX) $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ $(MLDEPDIR)/%.d: %.ml $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(DOC_DIR)/$(RESULT)/html: mkdir -p $@ $(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES) rm -rf $ OpamFilename.Dir.t -> OpamFilename.Dir.t -> OpamFilename.Dir.t download OpamProcess.job val rsync_file: ?args:string list -> OpamFilename.t -> OpamFilename.t -> OpamFilename.t download OpamProcess.job val register: unit -> unit opam-full-1.2.2/src/repositories/opamGit.ml0000644000175000017500000001123212517374212017401 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamFilename.OP open OpamProcess.Job.Op let log fmt = OpamGlobals.log "GIT" fmt module Git : OpamVCS.VCS= struct let exists repo = OpamFilename.exists_dir (repo.repo_root / ".git") let git repo = let dir = OpamFilename.Dir.to_string repo.repo_root in fun ?verbose ?env args -> OpamSystem.make_command ~dir ?verbose ?env "git" args let init repo = let env = Array.append (Unix.environment ()) [| "GIT_AUTHOR_NAME=Opam"; "GIT_AUTHOR_EMAIL=opam@ocaml.org"; "GIT_COMMITTER_NAME=Opam"; "GIT_COMMITTER_EMAIL=opam@ocaml.org" |] in OpamProcess.Job.of_list [ git repo ~env [ "init" ]; git repo ~env [ "remote" ; "add" ; "origin" ; fst repo.repo_address ]; git repo ~env [ "commit" ; "--allow-empty" ; "-m" ; "opam-git-init" ]; ] @@+ function | None -> Done () | Some (_,err) -> OpamSystem.process_error err let remote_ref = "refs/remotes/opam-ref" let fetch repo = let check_and_fix_remote = git repo ~verbose:false [ "config" ; "--get"; "remote.origin.url" ] @@> fun r -> OpamSystem.raise_on_process_error r; let current_remote = match r.OpamProcess.r_stdout with | [url] -> Some url | _ -> None in if current_remote <> Some (fst repo.repo_address) then ( log "Git remote for %s needs updating (was: %s)" (OpamRepository.to_string repo) (OpamMisc.Option.default "" current_remote); OpamProcess.Job.of_list [ git repo ~verbose:false [ "remote" ; "rm" ; "origin" ]; git repo ~verbose:false [ "remote" ; "add" ; "origin"; fst repo.repo_address ] ] @@+ function | None -> Done () | Some (_,err) -> OpamSystem.process_error err ) else Done () in check_and_fix_remote @@+ fun () -> let branch = OpamMisc.Option.default "HEAD" (snd repo.repo_address) in let refspec = Printf.sprintf "+%s:%s" branch remote_ref in git repo [ "fetch" ; "-q"; "origin"; refspec ] @@> fun r -> if OpamProcess.is_success r then Done () else (* fallback to fetching all first (workaround, git 2.1 fails silently on 'fetch HASH' when HASH isn't available locally already) *) OpamProcess.Job.of_list [ git repo [ "fetch" ; "-q"; "origin" ]; git repo [ "fetch" ; "-q"; "origin"; refspec ] ] @@+ function | None -> Done () | Some (_,err) -> OpamSystem.process_error err let revision repo = git repo ~verbose:false [ "rev-parse"; "HEAD" ] @@> fun r -> OpamSystem.raise_on_process_error r; match r.OpamProcess.r_stdout with | [] -> Done "" | full::_ -> if String.length full > 8 then Done (String.sub full 0 8) else Done full let reset repo = git repo [ "reset" ; "--hard"; remote_ref; "--" ] @@> fun r -> if OpamProcess.is_failure r then OpamSystem.internal_error "Git error: %s not found." remote_ref else Done () let diff repo = git repo [ "diff" ; "--name-only" ; "HEAD"; remote_ref; "--" ] @@> fun r -> if OpamProcess.is_failure r then OpamSystem.internal_error "Git error: %s not found." remote_ref else Done (r.OpamProcess.r_stdout <> []) let versionned_files repo = git repo ~verbose:false [ "ls-files" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done r.OpamProcess.r_stdout end module B = OpamVCS.Make(Git) let register () = OpamRepository.register_backend `git (module B: OpamRepository.BACKEND) opam-full-1.2.2/src/repositories/opamDarcs.mli0000644000175000017500000000230012517374212020057 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Darcs repository backend *) val register: unit -> unit opam-full-1.2.2/src/repositories/opamVCS.ml0000644000175000017500000001224512517374212017316 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) let log fmt = OpamGlobals.log "VCS" fmt open OpamTypes open OpamTypesBase open OpamProcess.Job.Op module type VCS = sig val exists: repository -> bool val init: repository -> unit OpamProcess.job val fetch: repository -> unit OpamProcess.job val reset: repository -> unit OpamProcess.job val diff: repository -> bool OpamProcess.job val revision: repository -> string OpamProcess.job val versionned_files: repository -> string list OpamProcess.job end module Make (VCS: VCS) = struct (* Local repos without a branch set actually use the rsync backend, but limited to versionned files *) let is_synched_repo repo = match repo.repo_address with | _, Some _ -> false | addr, None -> not (Re_str.string_match (Re_str.regexp_string "://") addr 0) && OpamFilename.exists_dir (OpamFilename.Dir.of_string addr) let rsync repo = let source_repo = { repo with repo_root = OpamFilename.Dir.of_string (fst repo.repo_address) } in VCS.versionned_files source_repo @@+ fun files -> let stdout_file = let f = OpamSystem.temp_file "rsync-files" in let fd = open_out f in List.iter (fun s -> output_string fd s; output_char fd '\n') files; close_out fd; f in OpamLocal.rsync_dirs ~args:["--files-from"; stdout_file] (OpamFilename.Dir.of_string (fst repo.repo_address)) repo.repo_root @@+ fun dl -> OpamSystem.remove stdout_file; Done dl let init repo = VCS.init repo let pull_repo repo = if is_synched_repo repo then rsync repo else if VCS.exists repo then VCS.fetch repo @@+ fun () -> VCS.diff repo @@+ fun diff -> VCS.reset repo @@+ fun () -> if diff then Done (Result repo.repo_root) else Done (Up_to_date repo.repo_root) else (OpamFilename.mkdir repo.repo_root; VCS.init repo @@+ fun () -> VCS.fetch repo @@+ fun () -> VCS.reset repo @@+ fun () -> Done (Result repo.repo_root)) let repo dirname address = let repo = OpamRepository.default () in { repo with repo_root = dirname; repo_address = address; } let pull_url package dirname checksum remote_url = let () = match checksum with | None -> () | Some _ -> OpamGlobals.note "Skipping checksum for dev package %s" (OpamPackage.to_string package) in let repo = repo dirname remote_url in pull_repo repo @@+ fun r -> OpamGlobals.msg "[%s] %s %s\n" (OpamGlobals.colorise `green (OpamPackage.name_to_string package)) (string_of_address remote_url) (match r with | Result _ -> "updated" | Up_to_date _ -> "already up-to-date" | Not_available _ -> OpamGlobals.colorise `red "unavailable"); Done (download_dir r) let pull_repo repo = pull_repo repo @@+ fun r -> OpamGlobals.msg "[%s] %s %s\n" (OpamGlobals.colorise `blue (OpamRepositoryName.to_string repo.repo_name)) (string_of_address repo.repo_address) (match r with | Result _ -> "updated" | Up_to_date _ -> "already up-to-date" | Not_available _ -> OpamGlobals.colorise `red "unavailable"); Done () let pull_archive repo filename = let dirname = OpamPath.Repository.archives_dir repo in let basename = OpamFilename.basename filename in let local_file = OpamFilename.create dirname basename in if OpamFilename.exists local_file then ( OpamGlobals.msg "[%s] Using %s\n" (OpamGlobals.colorise `blue (OpamRepositoryName.to_string repo.repo_name)) (OpamFilename.prettify local_file); Done (Up_to_date local_file) ) else Done (Not_available (OpamFilename.to_string filename)) let revision repo = let repo = if is_synched_repo repo then (* Actually get the revision at the source *) { repo with repo_root = OpamFilename.Dir.of_string (fst repo.repo_address) } else repo in VCS.revision repo @@+ fun r -> Done (Some (OpamPackage.Version.of_string r)) end opam-full-1.2.2/src/repositories/opamHTTP.mli0000644000175000017500000000250712517374212017613 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Curl repository backend *) open OpamTypes val make_index_tar_gz: repository_root -> unit val make_urls_txt: write:bool -> repository_root -> file_attribute_set val register: unit -> unit opam-full-1.2.2/src/repositories/opamGit.mli0000644000175000017500000000227612517374212017562 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Git repository backend *) val register: unit -> unit opam-full-1.2.2/src/repositories/opamHg.mli0000644000175000017500000000227612517374212017375 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Git repository backend *) val register: unit -> unit opam-full-1.2.2/src/repositories/opamHg.ml0000644000175000017500000000656312517374212017227 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamFilename.OP open OpamProcess.Job.Op let log fmt = OpamGlobals.log "HG" fmt module Hg = struct let exists repo = OpamFilename.exists_dir (repo.repo_root / ".hg") let hg repo = let dir = OpamFilename.Dir.to_string repo.repo_root in fun ?verbose ?env args -> OpamSystem.make_command ~dir ?verbose ?env "hg" args let init repo = hg repo [ "init" ] @@> fun r -> OpamSystem.raise_on_process_error r; OpamFilename.write OpamFilename.OP.(repo.repo_root / ".hg" // "hgrc") (Printf.sprintf "[paths]\ndefault = %s\n" (fst repo.repo_address)); Done () let fetch repo = let check_and_fix_remote = hg repo [ "showconfig" ; "paths.default" ] @@> fun r -> OpamSystem.raise_on_process_error r; if r.OpamProcess.r_stdout <> [fst repo.repo_address] then ( OpamFilename.rmdir OpamFilename.OP.(repo.repo_root / ".hg"); init repo ) else Done () in check_and_fix_remote @@+ fun () -> hg repo [ "pull" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () let revision repo = hg repo [ "id"; "-i" ] @@> fun r -> OpamSystem.raise_on_process_error r; match r.OpamProcess.r_stdout with | [] -> Done "" | full::_ -> if String.length full > 8 then Done (String.sub full 0 8) else Done full let unknown_commit commit = OpamSystem.internal_error "Unknown mercurial revision/branch/bookmark: %s." commit let reset repo = let commit = match snd repo.repo_address with | None -> "tip" | Some c -> c in hg repo [ "update" ; "--clean"; commit ] @@> fun r -> if OpamProcess.is_failure r then unknown_commit commit; Done () let diff repo = let commit = match snd repo.repo_address with | None -> "tip" | Some c -> c in hg repo [ "diff" ; "--stat" ; "-r" ; commit ] @@> fun r -> if OpamProcess.is_failure r then unknown_commit commit; Done (r.OpamProcess.r_stdout <> []) let versionned_files repo = hg repo [ "locate" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done r.OpamProcess.r_stdout end module B = OpamVCS.Make(Hg) let register () = OpamRepository.register_backend `hg (module B: OpamRepository.BACKEND) opam-full-1.2.2/src/repositories/opamVCS.mli0000644000175000017500000000445312517374212017471 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Generic backend for version-control systems. *) open OpamTypes (** Each backend should implement this signature. *) module type VCS = sig (** Test whether the given repository is correctly initialized. *) val exists: repository -> bool (** Init a repository. *) val init: repository -> unit OpamProcess.job (** Fetch changes from upstream. This is supposed to put the changes in a staging area. Be aware that the remote URL might have been changed, so make sure to update accordingly. *) val fetch: repository -> unit OpamProcess.job (** Reset the master branch of the repository to match the remote repository state. *) val reset: repository -> unit OpamProcess.job (** Check whether the staging area is empty. Returns true if not (eg. there is an update pending) *) val diff: repository -> bool OpamProcess.job (** Return the HEAD revision. *) val revision: repository -> string OpamProcess.job (** Returns the list of files under version control *) val versionned_files: repository -> string list OpamProcess.job end (** Create a backend from a [VCS] implementation. *) module Make(VCS: VCS): OpamRepository.BACKEND opam-full-1.2.2/src/repositories/opamLocal.ml0000644000175000017500000001735012517374212017717 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamProcess.Job.Op let log fmt = OpamGlobals.log "RSYNC" fmt let slog = OpamGlobals.slog let rsync_arg = "-rLptgoDrvc" let call_rsync check args = OpamSystem.make_command "rsync" args @@> fun r -> match r.OpamProcess.r_code with | 0 -> Done (Some (OpamMisc.rsync_trim r.OpamProcess.r_stdout)) | 3 | 5 | 10 | 11 | 12 -> (* protocol or file errors *) Done None | 20 -> (* signal *) raise Sys.Break | 23 | 24 -> (* partial, mostly mode, link or perm errors. But may also be a complete error so we do an additional check *) if check () then (OpamGlobals.warning "Rsync partially failed:\n%s" (OpamMisc.itemize ~bullet:"" (fun x -> x) r.OpamProcess.r_stderr); Done (Some (OpamMisc.rsync_trim r.OpamProcess.r_stdout))) else Done None | 30 | 35 -> (* timeouts *) Done None | _ -> OpamSystem.process_error r let rsync ?(args=[]) src dst = log "rsync: src=%s dst=%s" src dst; let remote = String.contains src ':' in let norm d = Filename.concat d "" in if not(remote || Sys.file_exists src) then Done (Not_available src) else if src = dst then Done (Up_to_date []) else if OpamMisc.starts_with ~prefix:(norm src) (norm dst) || OpamMisc.starts_with ~prefix:(norm dst) (norm src) then (OpamGlobals.error "Cannot sync %s into %s: they overlap" src dst; Done (Not_available src)) else ( OpamSystem.mkdir dst; call_rsync (fun () -> not (OpamSystem.dir_is_empty dst)) ( rsync_arg :: args @ [ "--exclude"; ".git"; "--exclude"; "_darcs"; "--exclude"; ".hg"; "--exclude"; ".#*"; "--delete"; src; dst; ]) @@| function | None -> Not_available src | Some [] -> Up_to_date [] | Some lines -> Result lines ) let rsync_dirs ?args src dst = let src_s = (* ensure trailing '/' *) Filename.concat (OpamFilename.Dir.to_string src) "" in let dst_s = OpamFilename.Dir.to_string dst in let remote = String.contains src_s ':' in if not remote then OpamFilename.mkdir src; rsync ?args src_s dst_s @@| function | Not_available s -> Not_available s | Result _ -> if OpamFilename.exists_dir dst then Result dst else Not_available dst_s | Up_to_date _ -> Up_to_date dst let rsync_file ?(args=[]) src dst = let src_s = OpamFilename.to_string src in let dst_s = OpamFilename.to_string dst in log "rsync_file src=%s dst=%s" src_s dst_s; let remote = String.contains src_s ':' in if not (remote || OpamFilename.exists src) then Done (Not_available src_s) else if src_s = dst_s then Done (Up_to_date src) else call_rsync (fun () -> Sys.file_exists dst_s) ( rsync_arg :: args @ [ src_s; dst_s ]) @@| function | None -> Not_available src_s | Some [] -> Up_to_date dst | Some [_] -> if OpamFilename.exists dst then Result dst else Not_available src_s | Some l -> OpamSystem.internal_error "unknown rsync output: {%s}" (String.concat ", " l) module B = struct let pull_file_quiet local_dirname remote_filename = let local_filename = OpamFilename.create local_dirname (OpamFilename.basename remote_filename) in rsync_file remote_filename local_filename let pull_dir_quiet local_dirname remote_dirname = rsync_dirs remote_dirname local_dirname let pull_repo repo = log "pull-repo"; pull_file_quiet repo.repo_root (OpamPath.Repository.remote_repo repo) @@+ fun _ -> pull_dir_quiet (OpamPath.Repository.packages_dir repo) (OpamPath.Repository.remote_packages_dir repo) @@+ fun _ -> pull_dir_quiet (OpamPath.Repository.compilers_dir repo) (OpamPath.Repository.remote_compilers_dir repo) @@+ fun _ -> let archives = OpamFilename.files (OpamPath.Repository.archives_dir repo) in log "archives: %a" (slog (OpamMisc.string_of_list OpamFilename.to_string)) archives; let rec dl_archives = function | [] -> Done () | archive::archives -> match OpamPackage.of_archive archive with | None -> OpamGlobals.msg "Removing %s\n." (OpamFilename.to_string archive); OpamFilename.remove archive; dl_archives archives | Some nv -> let remote_filename = OpamPath.Repository.remote_archive repo nv in rsync_file remote_filename archive @@+ function | Not_available _ -> OpamFilename.remove archive; dl_archives archives | _ -> dl_archives archives in dl_archives archives @@| fun () -> OpamGlobals.msg "[%s] %s synchronized\n" (OpamGlobals.colorise `blue (OpamRepositoryName.to_string repo.repo_name)) (string_of_address repo.repo_address) let pull_url package local_dirname checksum remote_url = let remote_url = string_of_address remote_url in OpamFilename.mkdir local_dirname; let dir = OpamFilename.Dir.to_string local_dirname in let remote_url = if Sys.file_exists remote_url && Sys.is_directory remote_url (* ensure that rsync doesn't recreate a subdir: add trailing '/' *) then Filename.concat remote_url "" else remote_url in rsync remote_url dir @@| fun r -> let r = match r with | Not_available d -> Not_available d | Result _ | Up_to_date _ -> let res x = match r with | Result _ -> Result x | Up_to_date _ -> Up_to_date x | _ -> assert false in if OpamMisc.ends_with ~suffix:"/" remote_url then res (D local_dirname) else match Sys.readdir dir with | [|f|] when not (Sys.is_directory (Filename.concat dir f)) -> let filename = OpamFilename.OP.(local_dirname // f) in if OpamRepository.check_digest filename checksum then res (F filename) else (OpamFilename.remove filename; Not_available remote_url) | _ -> res (D local_dirname) in OpamGlobals.msg "[%s] %s %s\n" (OpamGlobals.colorise `green (OpamPackage.to_string package)) remote_url (string_of_download r); r let pull_archive repo filename = let local_dir = OpamPath.Repository.archives_dir repo in OpamFilename.mkdir local_dir; pull_file_quiet local_dir filename @@| function | Not_available _ as r when !OpamGlobals.verbose_level < 2 -> r | r -> OpamGlobals.msg "[%s] %s %s\n" (OpamGlobals.colorise `blue (OpamRepositoryName.to_string repo.repo_name)) (OpamFilename.to_string filename) (string_of_download r); r let revision _ = Done None end let register () = OpamRepository.register_backend `local (module B: OpamRepository.BACKEND) opam-full-1.2.2/src/repositories/opamDarcs.ml0000644000175000017500000000525412517374212017721 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamFilename.OP open OpamProcess.Job.Op let log fmt = OpamGlobals.log "Darcs" fmt module Darcs = struct let exists repo = OpamFilename.exists_dir (repo.repo_root / "_darcs") let darcs repo = let dir = OpamFilename.Dir.to_string repo.repo_root in fun ?verbose ?env args -> OpamSystem.make_command ~dir ?verbose ?env "darcs" args let init repo = OpamProcess.Job.of_list [ darcs repo [ "init" ]; darcs repo [ "get" ; fst repo.repo_address; "--lazy" ] ] @@+ function | None -> Done () | Some (_,err) -> OpamSystem.process_error err (* With darcs, it is apparently easier to compute a diff between remote and local, without fething at all. So we set fetch to be a no-op. *) let fetch _ = Done () (* Merge is actually a full pull *) let reset repo = darcs repo [ "pull"; fst repo.repo_address; "--all"; "--quiet" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done () (* Difference between remote and local is a 'pull --dry-run' *) let diff repo = darcs repo [ "pull" ; fst repo.repo_address; "--dry-run" ; "--quiet" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done (r.OpamProcess.r_stdout <> []) let revision _ = Done "" let versionned_files repo = darcs repo [ "show" ; "files" ] @@> fun r -> OpamSystem.raise_on_process_error r; Done r.OpamProcess.r_stdout end module B = OpamVCS.Make(Darcs) let register () = OpamRepository.register_backend `darcs (module B: OpamRepository.BACKEND) opam-full-1.2.2/src/repositories/opamHTTP.ml0000644000175000017500000002423012517374212017437 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamMisc.OP open OpamFilename.OP open OpamProcess.Job.Op let log msg = OpamGlobals.log "CURL" msg let slog = OpamGlobals.slog type state = { local_remote : (filename * int * string) filename_map; (* map of local files to address, perms, md5 *) remote_local : filename filename_map; (* reverse map of addresses to local files *) } let state_cache = ref [] let make_index_file path = path // "urls.txt" let make_index_file_new local_path = local_path // "urls.txt.1" let make_index_archive path = path // "index.tar.gz" let local_files repo = let all = OpamPath.Repository.repo repo :: OpamFilename.rec_files (OpamPath.Repository.packages_dir repo) @ OpamFilename.rec_files (OpamPath.Repository.archives_dir repo) @ OpamFilename.rec_files (OpamPath.Repository.compilers_dir repo) in List.filter OpamFilename.exists all (* Generate urls.txt (for opam-admin, or rebuilding if interrupted during update *) let rebuild_local_state ~write repo = let local_index_file = make_index_file repo.repo_root in log "Rebuilding urls.txt at %a" (slog OpamFilename.Dir.to_string) repo.repo_root; let index = List.fold_left (fun set f -> if not (OpamFilename.exists f) then set else let attr = OpamFilename.to_attribute repo.repo_root f in OpamFilename.Attribute.Set.add attr set ) OpamFilename.Attribute.Set.empty (local_files repo) in if write then OpamFile.File_attributes.write local_index_file index; index let state_of_index_file repo index_file = let repo_address = OpamFilename.raw_dir (fst repo.repo_address) in OpamFilename.Attribute.Set.fold (fun r state -> let base = OpamFilename.Attribute.base r in let perm = match OpamFilename.Attribute.perm r with | None -> 0o640 | Some p -> p in let digest = OpamFilename.Attribute.md5 r in let remote = repo_address // OpamFilename.Base.to_string base in let local = OpamFilename.create repo.repo_root base in { remote_local = OpamFilename.Map.add remote local state.remote_local; local_remote = OpamFilename.Map.add local (remote,perm,digest) state.local_remote; } ) index_file { local_remote = OpamFilename.Map.empty; remote_local = OpamFilename.Map.empty; } let get_state repo = try List.assoc repo.repo_address !state_cache with Not_found -> let urls = try OpamFile.File_attributes.read (make_index_file repo.repo_root) with e -> OpamMisc.fatal e; rebuild_local_state ~write:true repo in let state = state_of_index_file repo urls in state_cache := (repo.repo_address, state) :: !state_cache; state let sync_state repo = let old_state = get_state repo in let repo_address = OpamFilename.raw_dir (fst repo.repo_address) in let remote_index_file = make_index_file repo_address in let remote_index_archive = make_index_archive repo_address in let index_file = make_index_file repo.repo_root in let index_file_new = make_index_file_new repo.repo_root in let index_archive = make_index_archive repo.repo_root in OpamFilename.download_as ~compress:true ~overwrite:true remote_index_file index_file_new @@+ fun () -> let urls = OpamFile.File_attributes.read index_file_new in let new_state = state_of_index_file repo urls in let changed_files = OpamFilename.Map.merge (fun _ oldf newf -> match oldf, newf with | Some (_,_,oldck), Some (rem,_,newck) -> if oldck = newck then None else Some (Some rem) | _, None -> Some None | None, Some (rem,_,_) -> Some (Some rem)) old_state.local_remote new_state.local_remote in log "sync repo state: %a file changes" (slog @@ string_of_int @* OpamFilename.Map.cardinal) changed_files; (* Remove the index before making changes, so that it'll be consistently rebuilt in case of interruption *) OpamFilename.remove index_file; (if OpamFilename.Map.cardinal changed_files > 4 then ( log "-> downloading the full archive"; OpamProcess.Job.catch (fun e -> OpamMisc.fatal e; OpamGlobals.msg "Cannot find index.tar.gz on the OPAM repository. \ Initialisation may take some time.\n"; Done false) @@ OpamFilename.download_as ~overwrite:true remote_index_archive index_archive @@+ fun () -> OpamFilename.Map.iter (fun f _ -> if OpamFilename.Map.mem f old_state.local_remote then OpamFilename.remove f) changed_files; OpamFilename.extract_in index_archive repo.repo_root; Done true ) else Done false) @@+ fun got_archive -> (if not got_archive then OpamFilename.Map.fold (fun f remote job -> match remote with | None -> OpamFilename.remove f; job | Some remote -> job @@+ fun () -> OpamFilename.download_as ~overwrite:true remote f) changed_files (Done ()) else Done ()) @@+ fun () -> OpamFilename.move ~src:index_file_new ~dst:index_file; state_cache := (repo.repo_address, new_state) :: (List.remove_assoc repo.repo_address !state_cache); OpamGlobals.msg "[%s] synchronized from %s\n" (OpamGlobals.colorise `blue (OpamRepositoryName.to_string repo.repo_name)) (OpamTypesBase.string_of_address repo.repo_address); Done () let is_up_to_date state local_file = try let _,_,md5 = OpamFilename.Map.find local_file state.local_remote in OpamFilename.exists local_file && not (Sys.is_directory (OpamFilename.to_string local_file)) && md5 = OpamFilename.digest local_file with Not_found -> false let get_checksum state local_file = try let _,_,expected = OpamFilename.Map.find local_file state.local_remote in if OpamFilename.exists local_file && not (Sys.is_directory (OpamFilename.to_string local_file)) then let actual = OpamFilename.digest local_file in Some (actual, expected) else None with Not_found -> None module B = struct let repo repo_root repo_address = { repo_name = OpamRepositoryName.of_string "http"; repo_priority = 0; repo_kind = `http; repo_root; repo_address; } let pull_repo repo = log "pull-repo"; sync_state repo let pull_url package dirname checksum remote_url = let remote_url = OpamTypesBase.string_of_address remote_url in log "pull-file into %a: %s" (slog OpamFilename.Dir.to_string) dirname remote_url; let filename = OpamFilename.of_string remote_url in let base = OpamFilename.basename filename in let local_file = OpamFilename.create dirname base in let check_sum f = match checksum with | None -> false | Some c -> OpamFilename.digest f = c in let files = OpamFilename.files dirname in let uptodate = let found, extra = List.partition (fun f -> f = local_file && check_sum f) files in if extra <> [] && OpamMisc.starts_with (* Just a safeguard *) ~prefix:(OpamFilename.Dir.to_string (OpamPath.root ())) (OpamFilename.Dir.to_string dirname) then (log "Removing stale files in download dir: %a" (slog @@ List.map OpamFilename.to_string @> OpamMisc.pretty_list) extra; List.iter OpamFilename.remove extra); found <> [] in if uptodate then Done (Result (F local_file)) else OpamProcess.Job.catch (fun e -> OpamMisc.fatal e; Done (Not_available remote_url)) @@ OpamFilename.download ~overwrite:true ?checksum filename dirname @@+ fun local_file -> if OpamRepository.check_digest local_file checksum then (OpamGlobals.msg "[%s] %s downloaded\n" (OpamGlobals.colorise `green (OpamPackage.to_string package)) (OpamFilename.to_string filename); Done (Result (F local_file))) else (OpamFilename.remove local_file; Done (Not_available remote_url)) let pull_archive repo filename = log "pull-archive"; let state = get_state repo in let local_file = OpamFilename.Map.find filename state.remote_local in if is_up_to_date state local_file then Done (Up_to_date local_file) else OpamProcess.Job.catch (function | Not_found -> Done (Not_available (OpamFilename.to_string filename)) | e -> raise e) @@ OpamFilename.download_as ~overwrite:true filename local_file @@+ fun () -> OpamGlobals.msg "[%s] %s downloaded\n" (OpamGlobals.colorise `blue (OpamRepositoryName.to_string repo.repo_name)) (OpamFilename.prettify filename); Done (Result local_file) let revision _ = Done None end let make_urls_txt ~write repo_root = rebuild_local_state ~write (OpamRepository.local repo_root) let make_index_tar_gz repo_root = OpamFilename.in_dir repo_root (fun () -> let dirs = [ "version"; "compilers"; "packages"; "repo" ] in match List.filter Sys.file_exists dirs with | [] -> () | d -> OpamSystem.command ("tar" :: "czf" :: "index.tar.gz" :: d) ) let register () = OpamRepository.register_backend `http (module B : OpamRepository.BACKEND) opam-full-1.2.2/src/repositories/repositories.ocp0000644000175000017500000000031012517374212020674 0ustar useruserbegin library "opam-repositories" files = [ "opamHTTP.ml" "opamLocal.ml" "opamVCS.ml" "opamGit.ml" "opamDarcs.ml" "opamHg.ml" ] requires = [ "opam-core" ] end opam-full-1.2.2/src/tools/0000755000175000017500000000000012532744757014075 5ustar useruseropam-full-1.2.2/src/tools/opam_admin.ml0000644000175000017500000000462712517374212016530 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open Cmdliner let default_cmd = let doc = "Administration tool for local repositories." in Term.(ret (pure (`Help (`Pager, None)))), Term.info "opam-admin" ~version:OpamVersion.(to_string current) ~doc let make_repo_cmd = let doc = "Initialize a repo for serving files." in Term.(Opam_mk_repo.(pure process $ args)), Term.info "make" ~doc let check_repo_cmd = let doc = "Check a local repo for errors." in Term.(Opam_repo_check.(pure process $ args)), Term.info "check" ~doc let stats_cmd = let doc = "Compute statistics." in Term.(Opam_stats.(pure process $ pure ())), Term.info "stats" ~doc let depexts_cmd = let doc = "Add external dependencies." in Term.(Opam_depexts_change.(pure process $ args)), Term.info "depexts" ~doc let findlib_cmd = let doc = "Add findlib information." in Term.(Opam_findlib.(pure process $ args)), Term.info "findlib" ~doc let rename_cmd = let doc = "Rename a package." in Term.(Opam_rename.(pure process $ args)), Term.info "rename" ~doc let () = try match Term.eval_choice ~catch:false default_cmd [ make_repo_cmd; check_repo_cmd; stats_cmd; depexts_cmd; findlib_cmd; rename_cmd; ] with | `Error _ -> exit 2 | _ -> exit 0 with | OpamGlobals.Exit i -> exit i opam-full-1.2.2/src/tools/opam_mk_repo.ml0000644000175000017500000004132012517374212017063 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamFilename.OP open OpamPackage.Set.Op let log fmt = OpamGlobals.log "OPAM-MK-REPO" fmt type args = { index: bool; names: string list; gener_digest: bool; dryrun: bool; recurse: bool; resolve: bool; debug: bool; (* option for resolve *) compiler_version: OpamCompiler.Version.t option; switch: OpamSwitch.t option; os_string: string; } let args = let open Cmdliner in (*{[ let all = let doc = "Build all package archives (this is the default unless -i)" in Arg.(value & flag & info ["a";"all"] ~doc) in ]}*) let index = let doc = "Only build indexes, not package archives." in Arg.(value & flag & info ["i";"index"] ~doc) in let gener_digest = let doc = "Automatically correct the wrong archive checksums." in Arg.(value & flag & info ["g";"generate-checksums"] ~doc) in let dryrun = let doc = "Simply display the possible actions instead of executing them." in Arg.(value & flag & info ["d";"dryrun"] ~doc) in let recurse = let doc = "Recurse among the transitive dependencies of the packages and \ download all available versions of the dependencies." in Arg.(value & flag & info ["r";"recursive"] ~doc) in let resolve = let doc = "A more advanced version of `--recursive' that calculates \ a single usable snapshot of the package universe, resulting \ in a single version of each package. If you need more flexibility \ among package versions, you should continue to use `--recursive' \ to download all the archives." in Arg.(value & flag & info ["resolve"] ~doc) in let compiler_version = let doc = "Specify the variable 'ocaml_version' to be used to filter \ packages when using '--resolve'." in Arg.(value & opt (some string) None & info ~doc ["compiler"]) in let switch = let doc = "Specify the variable switch' to be used to filter \ packages when using '--resolve'. (Default: 'compiler_version')" in Arg.(value & opt (some string) None & info ~doc ["switch"]) in let names = let doc = "Names of the packages to include in the repo." in Arg.(value & pos_all string [] & info [] ~docv:"PKG" ~doc) in let debug = let doc = "Display debug messages." in Arg.(value & flag & info ["debug"] ~doc) in Term.( pure (fun index gener_digest dryrun recurse names debug resolve compiler_version switch -> let compiler_version = Option.map OpamCompiler.Version.of_string compiler_version in let switch = match switch with | None -> Option.map (fun cv -> OpamSwitch.of_string (OpamCompiler.Version.to_string cv)) compiler_version | Some switch -> Some (OpamSwitch.of_string switch) in {index; gener_digest; dryrun; recurse; names; debug; resolve; compiler_version; switch; os_string = OpamGlobals.os_string ()}) $index $gener_digest $dryrun $recurse $names $debug $resolve $compiler_version $switch ) let consistent_ocaml_version args opam = match args.compiler_version with | None -> true | Some cv -> let system = OpamCompiler.Version.of_string "system" in let atom (r,v) = match OpamCompiler.Version.to_string v with | "system" -> begin match r with | `Eq -> OpamCompiler.Version.compare cv system = 0 | `Neq -> OpamCompiler.Version.compare cv system <> 0 | _ -> OpamSystem.internal_error "%s is not a valid constraint for the system compiler \ (only '=' and '!=' are valid)." (OpamFormula.string_of_relop r) end | _ -> OpamCompiler.Version.eval_relop r cv v in match OpamFile.OPAM.ocaml_version opam with | None -> true | Some c -> OpamFormula.eval atom c let consistent_os args opam = match OpamFile.OPAM.os opam with | Empty -> true | f -> let atom (b, os) = let ($) = if b then (=) else (<>) in os $ args.os_string in OpamFormula.eval atom f let string str = Some (S str) let bool b = Some (B b) let is_global_conf v = OpamVariable.Full.package v = OpamPackage.Name.global_config let faked_var_resolve args v = let get_global_var v = if not (is_global_conf v) then None else match OpamVariable.to_string (OpamVariable.Full.variable v) with | "ocaml-version" -> begin match args.compiler_version with | None -> None | Some cv -> string (OpamCompiler.Version.to_string cv) end | "opam-version" -> string (OpamVersion.to_string OpamVersion.current) | "preinstalled" -> begin match args.compiler_version with | None -> None | Some cv -> bool (OpamCompiler.Version.to_string cv = "system") end | "switch" -> begin match args.switch with | None -> None | Some s -> string (OpamSwitch.to_string s) end | "arch" -> string (OpamGlobals.arch ()) | _ -> None in try List.fold_left (function None -> (fun (f,v) -> f v) | r -> (fun _ -> r)) None [ OpamState.get_env_var, v; get_global_var, v; ] with Exit -> None let consistent_available_field args opam = OpamFilter.eval_to_bool ~default:false (faked_var_resolve args) (OpamFile.OPAM.available opam) let resolve_deps args index names = let atoms = List.map (fun str -> match OpamPackage.of_string_opt str with | Some nv -> OpamSolution.eq_atom (OpamPackage.name nv) (OpamPackage.version nv) | None -> OpamPackage.Name.of_string str, None) names in let consistent opam = consistent_ocaml_version args opam && consistent_os args opam && consistent_available_field args opam in let opams = List.fold_left (fun opams r -> let f = OpamFilename.create (OpamFilename.cwd ()) (OpamFilename.Attribute.base r) in if OpamFilename.basename f = OpamFilename.Base.of_string "opam" then match OpamPackage.of_dirname (OpamFilename.dirname f) with | Some nv -> let opam = OpamFile.OPAM.read f in if consistent opam then OpamPackage.Map.add nv opam opams else opams | None -> opams else opams) OpamPackage.Map.empty (OpamFilename.Attribute.Set.elements index) in let packages = OpamPackage.Set.of_list (OpamPackage.Map.keys opams) in let requested = OpamPackage.Name.Set.of_list (List.map fst atoms) in let universe = { OpamSolver.empty_universe with u_packages = packages; u_available = packages; (* XXX add a compiler/OS option ? *) u_depends = OpamPackage.Map.map OpamFile.OPAM.depends opams; u_conflicts = OpamPackage.Map.map OpamFile.OPAM.conflicts opams; u_action = Install requested; } in let request = { wish_install = atoms; wish_remove = []; wish_upgrade = []; criteria = `Default; } in match OpamSolver.resolve ~verbose:true universe ~orphans:OpamPackage.Set.empty request with | Success solution -> OpamSolver.ActionGraph.fold_vertex (fun act acc -> match act with | To_change (_, p) -> OpamPackage.Set.add p acc | _ -> acc) (OpamSolver.get_atomic_action_graph solution) OpamPackage.Set.empty | Conflicts cs -> OpamGlobals.error_and_exit "%s" (OpamCudf.string_of_conflict (fun atom -> Printf.sprintf "%s is unavailable" (OpamFormula.string_of_atom atom)) cs) let process ({index; gener_digest; dryrun; recurse; names; debug; resolve} as args) = let () = OpamHTTP.register (); OpamGit.register (); OpamDarcs.register (); OpamLocal.register (); OpamHg.register () in OpamGlobals.debug := !OpamGlobals.debug || debug; let tmp_dirs = [ "tmp"; "log" ] in List.iter (fun dir -> if Sys.file_exists dir then ( OpamGlobals.error "The subdirectory '%s' already exists in the current directory. \n\ Please remove or rename it or run %s in a different folder.\n" dir Sys.argv.(0); exit 1; ) ) tmp_dirs; let () = let checkdir dir = Sys.file_exists dir && Sys.is_directory dir in if not (checkdir "packages" || checkdir "compilers") then OpamGlobals.error_and_exit "No repository found in current directory.\n\ Please make sure there is a \"packages\" or \"compilers\" directory" in let repo = OpamRepository.local (OpamFilename.cwd ()) in let prefixes = OpamRepository.packages_with_prefixes repo in let packages = OpamRepository.packages repo in let mk_packages str = match OpamPackage.of_string_opt str with | Some nv -> OpamPackage.Set.singleton nv | None -> let n = OpamPackage.Name.of_string str in match OpamPackage.Version.Set.elements (OpamPackage.versions_of_name packages n) with | [] -> OpamGlobals.msg "Skipping unknown package %s.\n" str; OpamPackage.Set.empty | versions -> OpamPackage.Set.of_list (List.map (OpamPackage.create n) versions) in let new_packages = List.fold_left (fun accu str -> OpamPackage.Set.union accu (mk_packages str)) OpamPackage.Set.empty names in if names <> [] && OpamPackage.Set.is_empty new_packages then ( OpamGlobals.msg "No package to process.\n"; exit 0 ); (* Read urls.txt *) log "Reading urls.txt"; let local_index_file = OpamFilename.of_string "urls.txt" in let old_index = OpamFile.File_attributes.safe_read local_index_file in let new_index = OpamHTTP.make_urls_txt ~write:(not dryrun) repo.repo_root in let to_remove = OpamFilename.Attribute.Set.diff old_index new_index in let to_add = OpamFilename.Attribute.Set.diff new_index old_index in (* Compute the transitive closure of packages *) let get_dependencies nv = let prefix = OpamPackage.Map.find nv prefixes in let opam_f = OpamPath.Repository.opam repo prefix nv in if OpamFilename.exists opam_f then ( let opam = OpamFile.OPAM.read opam_f in let deps = OpamTypesBase.filter_deps (OpamFile.OPAM.depends opam) in let depopts = OpamTypesBase.filter_deps (OpamFile.OPAM.depopts opam) in OpamFormula.fold_left (fun accu (n,_) -> OpamPackage.Set.union (mk_packages (OpamPackage.Name.to_string n)) accu ) OpamPackage.Set.empty (OpamFormula.ands [deps; depopts]) ) else OpamPackage.Set.empty in let get_transitive_dependencies packages = let rec get_transitive_dependencies_aux visited to_visit = match to_visit with | [] -> visited | nv :: tl -> if OpamPackage.Set.mem nv visited then begin get_transitive_dependencies_aux visited tl end else begin let deps = OpamPackage.Set.elements (get_dependencies nv) in get_transitive_dependencies_aux (* Mark the node as visited. *) (OpamPackage.Set.add nv visited) (* Plan to explore all deps. *) (List.rev_append deps tl) end in get_transitive_dependencies_aux OpamPackage.Set.empty (OpamPackage.Set.elements packages) in let packages = if resolve then resolve_deps args new_index names else if recurse then get_transitive_dependencies new_packages else new_packages in let nv_set_of_remotes remotes = let aux r = OpamFilename.create (OpamFilename.cwd ()) (OpamFilename.Attribute.base r) in let list = List.map aux (OpamFilename.Attribute.Set.elements remotes) in OpamPackage.Set.of_list (OpamMisc.filter_map OpamPackage.of_filename list) in let packages_of_attrs attrs = OpamFilename.Attribute.Set.fold (fun attr nvs -> let f = OpamFilename.raw_dir (OpamFilename.Base.to_string (OpamFilename.Attribute.base attr)) in let path = OpamFilename.to_list_dir f in let rec get_nv = function | [_] | [] -> nvs | pkgdir::(f::_ as subpath)-> match OpamPackage.of_dirname pkgdir with | None -> get_nv subpath | Some nv -> match OpamFilename.Dir.to_string f with | "url" | "files" -> OpamPackage.Set.add nv nvs | _ -> nvs in get_nv path) attrs OpamPackage.Set.empty in let new_index = nv_set_of_remotes new_index in let missing_archive = OpamPackage.Set.filter (fun nv -> let archive = OpamPath.Repository.archive repo nv in not (OpamFilename.exists archive) ) new_index in let to_add = let open OpamPackage.Set.Op in let added_changed = packages_of_attrs to_add in let files_removed = new_index %% packages_of_attrs to_remove in missing_archive ++ added_changed ++ files_removed in let to_remove = nv_set_of_remotes to_remove in let to_add = if OpamPackage.Set.is_empty packages then to_add else packages %% to_add in let to_remove = to_remove -- to_add in let errors = ref [] in if not index then ( (* Remove the old archive files *) if not (OpamPackage.Set.is_empty to_remove) then OpamGlobals.msg "Packages to remove: %s\n" (OpamPackage.Set.to_string to_remove); OpamPackage.Set.iter (fun nv -> let archive = OpamPath.Repository.archive repo nv in OpamGlobals.msg "Removing %s ...\n" (OpamFilename.to_string archive); if not dryrun then OpamFilename.remove archive ) to_remove; (* build the new archives *) if not (OpamPackage.Set.is_empty to_add) then OpamGlobals.msg "Packages to build: %s\n" (OpamPackage.Set.to_string to_add); OpamPackage.Set.iter (fun nv -> let prefix = OpamPackage.Map.find nv prefixes in let local_archive = OpamPath.Repository.archive repo nv in let url_file = OpamPath.Repository.url repo prefix nv in try if not dryrun then OpamFilename.remove local_archive; if OpamFilename.exists url_file && OpamFile.URL.kind (OpamFile.URL.read url_file) = `http then ( OpamGlobals.msg "Building %s\n" (OpamFilename.to_string local_archive); let job = OpamRepository.make_archive ~gener_digest repo prefix nv in if dryrun then OpamProcess.Job.dry_run job else OpamProcess.Job.run job ) with e -> OpamFilename.remove local_archive; errors := (nv, e) :: !errors; OpamMisc.fatal e ) to_add; ); (* Create index.tar.gz *) if not (OpamFilename.exists (repo.repo_root // "index.tar.gz")) || not (OpamPackage.Set.is_empty to_add) || not (OpamPackage.Set.is_empty to_remove) then ( OpamGlobals.msg "Rebuilding index.tar.gz ...\n"; if not dryrun then ( OpamHTTP.make_index_tar_gz repo.repo_root; ) ) else OpamGlobals.msg "OPAM Repository already up-to-date.\n"; if not dryrun then List.iter OpamSystem.remove tmp_dirs; (* Rebuild urls.txt now the archives have been updated *) OpamGlobals.msg "Rebuilding urls.txt\n"; let _index = OpamHTTP.make_urls_txt ~write:(not dryrun) repo.repo_root in if !errors <> [] then ( let display_error (nv, error) = let disp = OpamGlobals.header_error "%s" (OpamPackage.to_string nv) in match error with | OpamSystem.Process_error r -> disp "%s" (OpamProcess.string_of_result ~color:`red r) | OpamSystem.Internal_error s -> OpamGlobals.error " %s" s | _ -> disp "%s" (Printexc.to_string error) in let all_errors = List.map fst !errors in OpamGlobals.error "Got some errors while processing: %s" (OpamMisc.sconcat_map ", " OpamPackage.to_string all_errors); List.iter display_error !errors ) opam-full-1.2.2/src/tools/opam_admin_top.mli0000644000175000017500000000360112517374212017552 0ustar useruser(** Small lib for writing opam-repo admin scripts *) (** The current repo (taken from CWD !) *) val repo : OpamTypes.repository (** All defined packages in the current repo *) val packages : OpamPackage.Set.t (** All defined compilers in the current repo *) val compilers : OpamCompiler.Set.t open OpamFile type 'a action = [`Update of 'a | `Remove | `Keep ] (** Maps on the files of every package. Only changed files are written back to disk. *) val iter_packages_gen: ?quiet:bool -> (OpamPackage.t -> prefix:string option -> opam:OPAM.t -> descr:Descr.t option -> url:URL.t option -> dot_install:Dot_install.t option -> OPAM.t * Descr.t action * URL.t action * Dot_install.t action) -> unit (** Turn a list of glob patterns into a proper filtering function on package names. *) val filter_packages: string list -> (OpamPackage.t -> bool) (** Quicker interface when considering a single type of file *) val iter_packages: ?quiet:bool -> ?filter:(OpamPackage.t -> bool) -> ?f:(OpamPackage.t -> string option -> OPAM.t -> unit) -> ?opam:(OpamPackage.t -> OPAM.t -> OPAM.t) -> ?descr:(OpamPackage.t -> Descr.t -> Descr.t) -> ?url:(OpamPackage.t -> URL.t -> URL.t) -> ?dot_install:(OpamPackage.t -> Dot_install.t -> Dot_install.t) -> unit -> unit (** Similarly for compiler descriptions *) val iter_compilers_gen: ?quiet:bool -> (OpamCompiler.t -> prefix:string option -> comp:Comp.t -> descr:Descr.t option -> Comp.t * Descr.t action) -> unit (** Turn a list of glob patterns into a proper filtering function on compiler names. *) val filter_compilers: string list -> (OpamCompiler.t -> bool) val iter_compilers: ?quiet:bool -> ?filter:(OpamCompiler.t -> bool) -> ?f:(OpamCompiler.t -> string option -> Comp.t -> unit) -> ?comp:(OpamCompiler.t -> Comp.t -> Comp.t) -> ?descr:(OpamCompiler.t -> Descr.t -> Descr.t) -> unit -> unit opam-full-1.2.2/src/tools/opam_repo_check.mli0000644000175000017500000000230712517374212017704 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) type args val args: args Cmdliner.Term.t val process: args -> unit opam-full-1.2.2/src/tools/tools.ocp0000644000175000017500000000101712517374212015723 0ustar useruserbegin program "opam-check" files = [ "opam_check.ml" ] requires = [ "opam-client" ] end begin program "opam-admin" files = [ "opam_mk_repo.ml" "opam_repo_check.ml" "opam_stats.ml" "opam_depexts_change.ml" "opam_findlib.ml" "opam_rename.ml" "opam_admin.ml" ] requires = [ "opam-client" ] end begin program "opam-installer" files = [ "opam_installer.ml" ] requires = [ "opam-client" ] end begin program "opamlfind" files = [ "opamlfind.ml" ] requires = [ "unix" ] end opam-full-1.2.2/src/tools/opam_admin_top.ml0000644000175000017500000001533512517374212017410 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* To be used for quick repo scripts using the toplevel *) open OpamFilename.OP open OpamMisc.OP let identity _ x = x let true_ _ = true let repo = OpamRepository.local (OpamFilename.cwd ()) let packages = OpamRepository.packages repo let compilers = OpamRepository.compilers repo let wopt w f = function | None -> OpamFilename.remove f | Some contents -> w f contents let apply f x prefix y = match f with | None -> () | Some f -> f x prefix y type 'a action = [`Update of 'a | `Remove | `Keep] let to_action f x y = match f with | None -> `Keep | Some f -> match y with | None -> `Keep | Some y -> `Update (f x y) let of_action o = function | `Keep -> o | `Update x -> Some x | `Remove -> None let iter_packages_gen ?(quiet=false) f = let packages = OpamRepository.packages_with_prefixes repo in let changed_pkgs = ref 0 in let changed_files = ref 0 in (** packages *) OpamPackage.Map.iter (fun package prefix -> if not quiet then OpamGlobals.msg "Processing package %s... " (OpamPackage.to_string package); let opam_file = OpamPath.Repository.opam repo prefix package in let opam = OpamFile.OPAM.read opam_file in let descr_file = OpamPath.Repository.descr repo prefix package in let descr = if OpamFilename.exists descr_file then Some (OpamFile.Descr.read descr_file) else None in let url_file = OpamPath.Repository.url repo prefix package in let url = if OpamFilename.exists url_file then Some (OpamFile.URL.read url_file) else None in let dot_install_file = OpamPath.Repository.files repo prefix package // (OpamPackage.Name.to_string (OpamPackage.name package) ^ ".install") in let dot_install = if OpamFilename.exists dot_install_file then Some (OpamFile.Dot_install.read dot_install_file) else None in let opam2, descr2, url2, dot_install2 = f package ~prefix ~opam ~descr ~url ~dot_install in let descr2 = of_action descr descr2 in let url2 = of_action url url2 in let dot_install2 = of_action dot_install dot_install2 in let changed = ref false in let upd () = changed := true; incr changed_files in if opam <> opam2 then (upd (); OpamFile.OPAM.write opam_file opam2); if descr <> descr2 then (upd (); wopt OpamFile.Descr.write descr_file descr2); if url <> url2 then (upd (); wopt OpamFile.URL.write url_file url2); if dot_install <> dot_install2 then (upd (); wopt OpamFile.Dot_install.write dot_install_file dot_install2); if !changed then (incr changed_pkgs; if not quiet then OpamGlobals.msg "\r\027[KUpdated %s\n" (OpamPackage.to_string package)) else if not quiet then OpamGlobals.msg "\r\027[K"; ) packages; if not quiet then OpamGlobals.msg "Done. Updated %d files in %d packages.\n" !changed_files !changed_pkgs let iter_packages ?quiet ?(filter=true_) ?f ?(opam=identity) ?descr ?url ?dot_install () = iter_packages_gen ?quiet (fun p ~prefix ~opam:o ~descr:d ~url:u ~dot_install:i -> if filter p then ( apply f p prefix o; opam p o, to_action descr p d , to_action url p u, to_action dot_install p i ) else o, `Keep, `Keep, `Keep) let iter_compilers_gen ?(quiet=false) f = let compilers = OpamRepository.compilers_with_prefixes repo in let changed_comps = ref 0 in let changed_files = ref 0 in OpamCompiler.Map.iter (fun c prefix -> if not quiet then OpamGlobals.msg "Processing compiler %s... " (OpamCompiler.to_string c); let comp_file = OpamPath.Repository.compiler_comp repo prefix c in let comp = OpamFile.Comp.read comp_file in let descr_file = OpamPath.Repository.compiler_descr repo prefix c in let descr = if OpamFilename.exists descr_file then Some (OpamFile.Descr.read descr_file) else None in let comp2, descr2 = f c ~prefix ~comp ~descr in let descr2 = of_action descr descr2 in let changed = ref false in let upd () = changed := true; incr changed_files in if comp <> comp2 then (upd (); OpamFile.Comp.write comp_file comp2); if descr <> descr2 then (upd (); wopt OpamFile.Descr.write descr_file descr2); if !changed then (incr changed_comps; if not quiet then OpamGlobals.msg "\r\027[KUpdated %s\n" (OpamCompiler.to_string c)) else if not quiet then OpamGlobals.msg "\r\027[K"; ) compilers; if not quiet then OpamGlobals.msg "Done. Updated %d files in %d compiler descriptions.\n" !changed_files !changed_comps let iter_compilers ?quiet ?(filter=true_) ?f ?(comp=identity) ?descr () = iter_compilers_gen ?quiet (fun x ~prefix ~comp:c ~descr:d -> if filter x then ( apply f x prefix c; comp x c, to_action descr x d ) else c, `Keep) let regexps_of_patterns patterns = let contains_dot str = let len = String.length str in let rec aux = function | -1 -> false | i -> str.[i] = '.' || aux (i-1) in aux (len-1) in List.map (fun pattern -> if contains_dot pattern then pattern else pattern ^ ".*" ) patterns |> List.map (fun pattern -> Re.compile (Re_glob.globx pattern)) let filter fn patterns = let regexps = regexps_of_patterns patterns in fun t -> match regexps with | [] -> true | _ -> let str = fn t in List.exists (fun re -> OpamMisc.exact_match re str) regexps let filter_packages = filter OpamPackage.to_string let filter_compilers = filter OpamCompiler.to_string opam-full-1.2.2/src/tools/opam_depexts_change.ml0000644000175000017500000000570212517374212020414 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* Script to check that a given repository is well-typed (or well-parsed) *) open OpamTypes type args = { pkg: name; os: string list; deps: string list; } let package_name = let parse str = try `Ok (OpamPackage.Name.of_string str) with Failure msg -> `Error msg in let print ppf pkg = Format.pp_print_string ppf (OpamPackage.Name.to_string pkg) in parse, print let args = let open Cmdliner in let os = let doc = "Operating system tag" in Arg.(value & opt_all string [] & info ["os"] ~doc) in let deps = let doc = "Extdep tag" in Arg.(value & opt_all string [] & info ["dep"] ~doc) in let pkg = let doc = "OPAM package name" in Arg.(required & pos 1 (some package_name) None & info [] ~doc) in Term.(pure (fun os deps pkg -> { os; deps; pkg }) $ os $ deps $ pkg) let process args = let repo = OpamRepository.local (OpamFilename.cwd ()) in let packages = OpamRepository.packages_with_prefixes repo in (** packages *) OpamPackage.Map.iter (fun package prefix -> OpamGlobals.msg "Processing (package) %s\n" (OpamPackage.to_string package); (** OPAM *) let opam_f = OpamPath.Repository.opam repo prefix package in let opam = OpamFile.OPAM.read opam_f in let pkgname = OpamFile.OPAM.name opam in if pkgname = args.pkg then begin let depexts = let os = OpamMisc.StringSet.of_list args.os in let deps = OpamMisc.StringSet.of_list args.deps in match OpamFile.OPAM.depexts opam with | None -> OpamMisc.StringSetMap.of_list [ os, deps ] | Some depexts' -> (* TODO: Replace existing entry? *) OpamMisc.StringSetMap.add os deps depexts' in let opam = OpamFile.OPAM.with_depexts opam (Some depexts) in OpamFile.OPAM.write opam_f opam; end; ) packages opam-full-1.2.2/src/tools/opam_installer.ml0000644000175000017500000003321712517374212017432 0ustar useruser(**************************************************************************) (* *) (* Copyright 2013 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open Cmdliner type options = { file: OpamFilename.t; pkgname: OpamPackage.Name.t; prefix: OpamFilename.Dir.t; script: bool; mandir: OpamFilename.Dir.t option; libdir: OpamFilename.Dir.t option; stubsdir: OpamFilename.Dir.t option; topdir: OpamFilename.Dir.t option; docdir: OpamFilename.Dir.t option; } (* A wrapper on top of commands to either proceed, or output a script *) type commands = { mkdir: OpamFilename.Dir.t -> unit; rmdir: opt:bool -> OpamFilename.Dir.t -> unit; cp: ?exec:bool -> opt:bool -> src:OpamFilename.t -> dst:OpamFilename.t -> unit -> unit; rm: opt:bool -> OpamFilename.t -> unit; confirm: string -> (unit -> unit) -> unit; } let do_commands project_root = let mkdir d = if not (OpamFilename.exists_dir d) then (OpamGlobals.msg "Creating directory %s\n%!" (OpamFilename.Dir.to_string d); OpamFilename.mkdir d) in let rec rmdir ~opt d = if not (OpamFilename.exists_dir d) then () else if Sys.readdir (OpamFilename.Dir.to_string d) = [||] then (OpamGlobals.msg "Removing empty dir %S\n" (OpamFilename.Dir.to_string d); OpamFilename.rmdir d; let parent = OpamFilename.dirname_dir d in if parent <> d then rmdir ~opt:true parent) else if not opt then OpamGlobals.warning "Directory %S is not empty\n" (OpamFilename.Dir.to_string d) in let cp ?exec ~opt ~src ~dst () = if OpamFilename.exists src then (mkdir (OpamFilename.dirname dst); OpamGlobals.msg "%-32s => %s\n" (OpamFilename.remove_prefix project_root src) (OpamFilename.to_string dst); OpamFilename.install ?exec ~src ~dst ()) else if not opt then OpamGlobals.error "Could not find %S" (OpamFilename.to_string src) in let rm ~opt f = if OpamFilename.exists f then (OpamGlobals.msg "Removing %s\n" (OpamFilename.to_string f); OpamFilename.remove f) else if not opt then OpamGlobals.warning "%S doesn't exist" (OpamFilename.to_string f) in let confirm s f = if OpamGlobals.confirm "%s" s then f () in { mkdir; rmdir; cp; rm; confirm } let script_commands project_root ochan = let made_dirs = ref [] in Printf.fprintf ochan "#!/bin/bash\n"; let mkdir d = if not (List.mem d !made_dirs) then ( Printf.fprintf ochan "mkdir -p %S\n" (OpamFilename.Dir.to_string d); made_dirs := d :: !made_dirs ) in let rmdir ~opt d = let f = OpamFilename.Dir.to_string d in Printf.fprintf ochan "if [ -d %S ]\n" f; Printf.fprintf ochan "then rmdir -p %S 2>/dev/null" f; if not opt then Printf.fprintf ochan " ||\n echo \"Warning: could not remove directory %s\"" f; Printf.fprintf ochan "\nfi\n" in let cp ?exec ~opt ~src ~dst () = mkdir (OpamFilename.dirname dst); let mode = match exec with | Some true -> "-m 0755" | Some false -> "-m 0644" | None -> "" in let src = OpamFilename.remove_prefix project_root src in let dst = OpamFilename.to_string dst in Printf.fprintf ochan "if [ -e %S ]\n" src; Printf.fprintf ochan "then install %s %S %S\n" mode src dst; if not opt then Printf.fprintf ochan "else echo \"Error: %s doesn't exist\"\n" src; Printf.fprintf ochan "fi\n" in let rm ~opt file = let f = OpamFilename.to_string file in Printf.fprintf ochan "if [ -e %S ]; then rm -f %S\n" f f; if not opt then Printf.fprintf ochan "else echo \"Warning: %s doesn't exist\"\n" f; Printf.fprintf ochan "fi\n" in let confirm msg f = Printf.fprintf ochan "read -p %S' [y/n] ' -n 1 -r; echo; if [ \"$REPLY\" = 'y' ]; then\n" msg; f (); Printf.fprintf ochan "fi\n"; in { mkdir; rmdir; cp; rm; confirm } (* [f (dest, file_list, is_exec)] should take care of the processing, where [dest src dst] returns the destination of a file with a ["src" {"dst"}] line in the .install *) let iter_install f instfile o = let module D = OpamPath.Switch in let module S = OpamFile.Dot_install in let dest ?fix dir = let dir = OpamMisc.Option.default dir fix in fun src dst -> OpamFilename.create dir (OpamMisc.Option.default (OpamFilename.basename src) dst) in let dest_global ?fix instdir_f = dest ?fix (instdir_f o.prefix (OpamSwitch.of_string "")) in let dest_pkg ?fix instdir_f = let fix = OpamMisc.Option.map OpamFilename.OP.(fun d -> d / OpamPackage.Name.to_string o.pkgname) fix in dest ?fix (instdir_f o.prefix (OpamSwitch.of_string "") o.pkgname) in List.iter f [ dest_global D.bin, S.bin instfile, true; dest_global D.sbin, S.sbin instfile, true; dest_pkg ?fix:o.libdir D.lib, S.lib instfile, false; dest_pkg ?fix:o.libdir D.lib, S.libexec instfile, true; dest_global ?fix:o.topdir D.toplevel, S.toplevel instfile, false; dest_global ?fix:o.stubsdir D.stublibs, S.stublibs instfile, true; dest_global ?fix:o.mandir D.man_dir, S.man instfile, false; dest_pkg D.share, S.share instfile, false; dest_global D.share_dir,S.share_root instfile, false; dest_pkg D.etc, S.etc instfile, false; dest_pkg ?fix:o.docdir D.doc, S.doc instfile, false; ] let install options = let instfile = OpamFile.Dot_install.safe_read options.file in let project_root = OpamFilename.cwd () in let cmd = if options.script then script_commands project_root stdout else do_commands project_root in let install_files (dest, files, exec) = List.iter (fun (base, dst) -> let src_file = OpamFilename.create project_root base.c in let dst_file = dest src_file dst in cmd.cp ~exec ~opt:base.optional ~src:src_file ~dst:dst_file ()) files in iter_install install_files instfile options; List.iter (fun (src, dst) -> let src_file = OpamFilename.create (OpamFilename.cwd ()) src.c in cmd.confirm (Printf.sprintf "Do you want to install %s to %s ?" (OpamFilename.Base.to_string src.c) (OpamFilename.to_string dst)) (fun () -> cmd.cp ~opt:false ~src:src_file ~dst ()) ) (OpamFile.Dot_install.misc instfile) let uninstall options = let instfile = OpamFile.Dot_install.safe_read options.file in let project_root = OpamFilename.cwd () in let cmd = if options.script then script_commands project_root stdout else do_commands project_root in let dirs_to_remove = ref OpamFilename.Dir.Set.empty in let remove_files (dest, files, _) = List.iter (fun (base, dst) -> let src_file = OpamFilename.create project_root base.c in let dst_file = dest src_file dst in cmd.rm ~opt:base.optional dst_file; dirs_to_remove := OpamFilename.Dir.Set.add (OpamFilename.dirname dst_file) !dirs_to_remove) files in iter_install remove_files instfile options; List.iter (cmd.rmdir ~opt:true) (List.rev (OpamFilename.Dir.Set.elements !dirs_to_remove)); List.iter (fun df -> cmd.rmdir ~opt:false (df options.prefix (OpamSwitch.of_string "") options.pkgname)) OpamPath.Switch.([ lib; share; etc; doc ]); List.iter (fun (_src, dst) -> cmd.confirm (Printf.sprintf "Remove %s ?" (OpamFilename.to_string dst)) (fun () -> cmd.rm ~opt:false dst)) (OpamFile.Dot_install.misc instfile) let options = let file = let doc = "The OPAM .install file to read for installation instructions" in Arg.(value & pos 0 (some string) None & info ~docv:"PKG.install" ~doc []) in let prefix = let doc = "The prefix to install to. You can use \ eg '$$$$PREFIX' to output a relocatable script" in Arg.(value & opt string "/usr/local" & info ~docv:"PREFIX" ~doc ["prefix"]) in let script = let doc = "Don't execute the commands, but output a shell-script \ (experimental)" in Arg.(value & flag & info ~doc ["script"]) in let pkgname = let doc = "Specify the package name. Used to set install directory under \ `share/', etc. \ By default, basename of the .install file" in Arg.(value & opt (some string) None & info ~docv:"NAME" ~doc ["name"]) in let mandir = let doc = "Manpages dir. Relative to $(b,prefix) or absolute. \ By default $(i,$$prefix/man)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["mandir"]) in let libdir = let doc = "OCaml lib dir. Relative to $(b,prefix) or absolute. \ By default $(i,$$prefix/lib) ; sometimes setting this to \ $(i,$$(ocamlc -where)) is preferable." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["libdir"]) in let stubsdir = let doc = "Stubs installation dir. Relative to $(b,prefix) or absolute. \ By default $(i,$$libdir/stublibs)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["stubsdir"]) in let topdir = let doc = "Toplevel install dir. Relative to $(b,prefix) or absolute. \ By default $(i,$$libdir/toplevel)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["topdir"]) in let docdir = let doc = "Documentation dir. Relative to $(b,prefix) or absolute. \ By default $(i,$$prefix/doc)." in Arg.(value & opt (some string) None & info ~docv:"PATH" ~doc ["docdir"]) in let make_options file prefix script name mandir libdir stubsdir topdir docdir = let file = match file with | Some file -> let f = OpamFilename.of_string (file ^ ".install") in if OpamFilename.exists f then f else let f = OpamFilename.of_string file in if OpamFilename.exists f then f else raise (Invalid_argument ("File not found: " ^ file)) | None -> let candidates = OpamFilename.files (OpamFilename.cwd ()) in match List.filter (fun f -> OpamFilename.check_suffix f ".install") candidates with | [f] -> f | [] -> raise (Invalid_argument "No .install file found") | files -> let msg = Printf.sprintf "Please specify a .install file, %s found in current dir" (OpamMisc.pretty_list (List.map (fun f -> OpamFilename.(Base.to_string (basename f))) files)) in raise (Invalid_argument msg) in let prefix = OpamFilename.Dir.of_string prefix in let pkgname = match name with | Some n -> OpamPackage.Name.of_string n | None when OpamFilename.check_suffix file ".install" -> OpamPackage.Name.of_string (OpamFilename.Base.to_string (OpamFilename.basename (OpamFilename.chop_extension file))) | None -> raise (Invalid_argument "Could not guess the package name, please specify `--name'") in let mk_dir = function | None -> None | Some d when Filename.is_relative d -> Some OpamFilename.OP.(prefix / d) | Some d -> Some (OpamFilename.Dir.of_string d) in let mandir = mk_dir mandir in let libdir = mk_dir libdir in let stubsdir = match mk_dir stubsdir, libdir with | None, Some d -> Some OpamFilename.OP.(d / "stubslibs") | d, None | (Some _ as d), _ -> d in let topdir = match mk_dir topdir, libdir with | None, Some d -> Some OpamFilename.OP.(d / "toplevel") | d, None | (Some _ as d), _ -> d in let docdir = mk_dir docdir in { file; prefix; script; pkgname; mandir; libdir; stubsdir; topdir; docdir } in Term.(pure make_options $ file $ prefix $ script $ pkgname $ mandir $ libdir $ stubsdir $ topdir $ docdir) let command = let remove = Arg.(value & vflag false & [ false, Arg.info ["i";"install"] ~doc:"Install the package (the default)"; true, Arg.info ["u";"uninstall";"remove"] ~doc:"Remove the package"; ]) in Term.( pure (fun options remove -> if remove then uninstall options else install options) $ options $ remove) let info = let doc = "Handles (un)installation of package files following instructions from \ OPAM *.install files." in Term.info "opam-installer" ~version:OpamVersion.(to_string current) ~doc let () = try match Term.eval ~catch:false (command,info) with | `Error _ -> exit 2 | _ -> exit 0 with | Invalid_argument s -> prerr_string "ERROR: "; prerr_endline s; exit 2 | OpamGlobals.Exit i -> exit i | e -> OpamGlobals.error "Failure during install"; prerr_string (Printexc.to_string e); exit 1 opam-full-1.2.2/src/tools/opam_rename.ml0000644000175000017500000000712012517374212016676 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 Thomas Gazagnaire *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* Script to add findlib info *) open OpamTypes module StringSet = OpamMisc.StringSet let () = OpamGlobals.root_dir := OpamGlobals.default_opam_dir type args = { src: name; dst: name; } let args = let open Cmdliner in let src = let doc = "Name of the source package." in Arg.(required & pos 0 (some string) None & info ~doc []) in let dst = let doc = "Name of the destination package." in Arg.(required & pos 1 (some string) None & info ~doc []) in Term.(pure (fun src dst -> let src = OpamPackage.Name.of_string src in let dst = OpamPackage.Name.of_string dst in { src; dst } ) $ src $ dst) let state = lazy (OpamState.load_state "opam-admin-findlib") let process args = let repo = OpamRepository.local (OpamFilename.cwd ()) in let packages = OpamRepository.packages_with_prefixes repo in OpamPackage.Map.iter (fun package prefix -> if OpamPackage.name package = args.src then ( let new_pkg = OpamPackage.create args.dst (OpamPackage.version package) in if OpamPackage.Map.mem new_pkg packages then ( OpamGlobals.warning "Cannot rename %s to %s as the package already exists, skipping." (OpamPackage.to_string package) (OpamPackage.to_string new_pkg); ) else ( OpamGlobals.msg "Processing %s\n" (OpamPackage.to_string package); let path = OpamPath.Repository.packages repo prefix package in let new_path = let prefix = match prefix with | None -> None | Some _ -> Some (OpamPackage.Name.to_string args.dst) in OpamPath.Repository.packages repo prefix new_pkg in OpamFilename.move_dir ~src:path ~dst:new_path; (* XXX: do we want to rename the findlib packages as well ?? *) ) ) else ( let opam_f = OpamPath.Repository.opam repo prefix package in let opam = OpamFile.OPAM.read opam_f in let rename (n, c) = if n = args.src then Atom (args.dst, c) else Atom (n, c) in let depends = OpamFormula.map rename (OpamFile.OPAM.depends opam) in let depopts = OpamFormula.map rename (OpamFile.OPAM.depopts opam) in let new_opam = OpamFile.OPAM.with_depends (OpamFile.OPAM.with_depopts opam depopts) depends in if opam <> new_opam then ( OpamGlobals.msg "Processing %s\n" (OpamPackage.to_string package); OpamFile.OPAM.write opam_f new_opam ); )) packages opam-full-1.2.2/src/tools/opam_repo_check.ml0000644000175000017500000000627412517374212017542 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* Script to check that a given repository is well-typed (or well-parsed) *) open OpamFilename.OP type args = { normalize: bool; } let args = let open Cmdliner in let normalize = let doc = "Normalize all files in the repository." in Arg.(value & flag & info ["n";"normalize"] ~doc) in Term.(pure (fun normalize -> { normalize }) $ normalize) let process args = let write f_write fic st = if args.normalize then f_write fic st in let repo = OpamRepository.local (OpamFilename.cwd ()) in let packages = OpamRepository.packages_with_prefixes repo in (** packages *) OpamPackage.Map.iter (fun package prefix -> OpamGlobals.msg "Processing package %s\n" (OpamPackage.to_string package); (** OPAM *) let opam = OpamPath.Repository.opam repo prefix package in write OpamFile.OPAM.write opam (OpamFile.OPAM.read opam); (** Descr *) let descr = OpamPath.Repository.descr repo prefix package in if OpamFilename.exists descr then write OpamFile.Descr.write descr (OpamFile.Descr.read descr); (** URL *) let url = OpamPath.Repository.url repo prefix package in if OpamFilename.exists url then write OpamFile.URL.write url (OpamFile.URL.read url); (** Dot_install *) let dot_install = OpamPath.Repository.files repo prefix package // (OpamPackage.Name.to_string (OpamPackage.name package) ^ ".install") in if OpamFilename.exists dot_install then write OpamFile.Dot_install.write dot_install (OpamFile.Dot_install.read dot_install); ) packages; (** compilers *) let compilers = OpamRepository.compilers_with_prefixes repo in OpamCompiler.Map.iter (fun c prefix -> let comp = OpamPath.Repository.compiler_comp repo prefix c in let descr = OpamPath.Repository.compiler_descr repo prefix c in OpamGlobals.msg "Processing compiler %s\n" (OpamCompiler.to_string c); write OpamFile.Comp.write comp (OpamFile.Comp.read comp); if OpamFilename.exists descr then write OpamFile.Descr.write descr (OpamFile.Descr.read descr); ) compilers opam-full-1.2.2/src/tools/opam_stats.ml0000644000175000017500000001463612517374212016577 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes module Git = struct let exec repo command = OpamFilename.in_dir repo (fun () -> OpamSystem.command command ) let return_one_line repo command = OpamFilename.in_dir repo (fun () -> List.hd (OpamSystem.read_command_output command) ) let return repo command = OpamFilename.in_dir repo (fun () -> (OpamSystem.read_command_output command) ) let commit repo fmt = Printf.kprintf (fun msg -> exec repo [ "git"; "commit"; "-a"; "-m"; msg; "--allow-empty" ] ) fmt let commit_file repo file fmt = Printf.kprintf (fun msg -> if OpamFilename.exists file then let file = OpamFilename.remove_prefix repo file in exec repo [ "git"; "add"; file ]; exec repo [ "git"; "commit"; "-m"; msg; file; "--allow-empty" ]; else OpamGlobals.error_and_exit "Cannot commit %s" (OpamFilename.to_string file); ) fmt let revision repo = return_one_line repo [ "git"; "rev-parse"; "HEAD" ] let commits repo = return repo ["git"; "log"; "master"; "--pretty=format:%H"] let init repo = exec repo ["git"; "init"] let test_tag = "test" let branch repo = exec repo ["git"; "checkout"; "-B"; test_tag] let add repo file = if OpamFilename.exists file then let file = OpamFilename.remove_prefix repo file in exec repo ["git"; "add"; file] let checkout repo hash = exec repo ["git"; "checkout"; hash]; exec repo ["git"; "clean"; "-fdx"] let msg repo commit package fmt = Printf.kprintf (fun str -> OpamGlobals.msg "%-25s %s %-10s %-30s\n" (OpamFilename.Dir.to_string repo) commit (OpamPackage.to_string package) str ) fmt let date repo commit = let r = return_one_line repo [ "git"; "show"; "-s"; "--format=\"%ct\""; commit ] in let r = OpamMisc.strip r in let r = String.sub r 1 (String.length r - 2) in float_of_string r let files repo commit dir = return repo [ "git"; "ls-tree"; commit; dir ^ "/"; "--name-only"; "-r" ] let authors repo commit = return repo ["git"; "shortlog"; "-sne"; "--no-merges"; commit ] end type stats = { commit : string; date : float; authors : string list; packages: package_set; names : name_set; } let compare_stats s1 s2 = int_of_float (s1.date -. s2.date) let rec filter_monotone_loop s0 ge = function | [] -> [] | s :: tl -> if ge s0 s then s :: filter_monotone_loop s ge tl else filter_monotone_loop s0 ge tl let filter_monotone ge = function | [] -> [] | s0 :: tl -> s0 :: filter_monotone_loop s0 ge tl let stats repo = let commits = Git.commits repo in let n = List.length commits in Printf.printf "Commits: %d\n%!" n; let c = ref 0 in let stats = List.map (fun commit -> Printf.printf "\r%d / %d%!" !c n; incr c; let date = Git.date repo commit in let files = Git.files repo commit "packages" in let authors = Git.authors repo commit in let packages = List.fold_left (fun packages f -> if Filename.basename f <> "opam" then packages else match OpamPackage.of_string_opt (Filename.basename (Filename.dirname f)) with | None -> packages | Some nv -> OpamPackage.Set.add nv packages ) OpamPackage.Set.empty files in let names = OpamPackage.Set.fold (fun nv names -> OpamPackage.Name.Set.add (OpamPackage.name nv) names ) packages OpamPackage.Name.Set.empty in { commit; date; authors; packages; names } ) commits in Printf.printf "\n"; let stats = List.sort compare_stats stats in (* Drop the initial zero values. *) let stats = List.filter (fun s -> not(OpamPackage.Set.is_empty s.packages)) stats in (* Because of merges, the number of contributors or packages is not monotone. Filter the list so it is. *) let ge s1 s2 = List.length s1.authors <= List.length s2.authors && OpamPackage.Set.cardinal s1.packages <= OpamPackage.Set.cardinal s2.packages in filter_monotone ge stats let display stats fn ylabel output = let dotfile = output ^ ".dot" in let oc = open_out dotfile in Printf.fprintf oc "#!/usr/bin/gnuplot\n\ set xdata time\n\ set timefmt \"%%s\"\n\ set format x \"%%m/%%Y\"\n\ set term png size 800,400 font \"Arial,10\"\n\ set output \"%s.png\"\n\ unset key\n\ set style data lines\n\ set style fill transparent solid 0.4\n\ set grid\n\ set xlabel 'Time'\n\ set ylabel '%s'\n\ set datafile separator \";\"\n\ plot '-' using 1:($2) with filledcurves below x1 lt rgb 'dark-blue' lw 3\n" output ylabel; List.iter (fun stats -> Printf.fprintf oc "%.0f;%d\n" stats.date (fn stats) ) stats; Printf.fprintf oc "e"; close_out oc; Printf.printf "Generating %s.png ...\n" output; OpamSystem.command ["gnuplot"; dotfile ] let process () = let stats = stats (OpamFilename.cwd ()) in List.iter (fun (fn, ylabel, output) -> display stats fn ylabel output ) [ ((fun s -> List.length s.authors), "Contributors", "contributors"); ((fun s -> OpamPackage.Set.cardinal s.packages), "Packages", "packages"); ((fun s -> OpamPackage.Name.Set.cardinal s.names), "Unique Packages", "unique-packages"); ] opam-full-1.2.2/src/tools/opam_stats.mli0000644000175000017500000000223612517374212016741 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) val process: unit -> unit opam-full-1.2.2/src/tools/opam_check.ml0000644000175000017500000000517412517374212016513 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* Utility helper to check if a given set of packages is installed *) let usage = "opam-check [--root root] [-l label] +" let label = ref "" let spec = Arg.align [ ("--root", Arg.Set_string OpamGlobals.root_dir, " Set opam path"); ("-l" , Arg.Set_string label , " Set a test label"); ("--version", Arg.Unit OpamVersion.message , " Display version information"); ] let packages = ref [] let ano x = packages := x :: !packages let () = OpamGlobals.root_dir := OpamGlobals.default_opam_dir let () = Arg.parse spec ano usage let packages = OpamPackage.Set.of_list (List.map OpamPackage.of_string !packages) let installed () = let root = OpamPath.root () in let config = OpamFile.Config.read (OpamPath.config root) in let version = OpamFile.Config.switch config in let installed = OpamFile.Installed.safe_read (OpamPath.Switch.installed root version) in OpamPackage.Set.filter (fun nv -> OpamPackage.name nv <> OpamPackage.Name.global_config ) installed let () = let installed = installed () in let diff1 = OpamPackage.Set.diff packages installed in let diff2 = OpamPackage.Set.diff installed packages in let diff = OpamPackage.Set.union diff1 diff2 in let label = if !label = "" then "" else Printf.sprintf "[%s] " !label in if not (OpamPackage.Set.is_empty diff) then ( OpamGlobals.error "%swaiting for: %s" label (OpamPackage.Set.to_string diff1); OpamGlobals.error "%sgot: %s" label (OpamPackage.Set.to_string diff2); exit 1 ) opam-full-1.2.2/src/tools/opam_findlib.ml0000644000175000017500000001724212517374212017044 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 Thomas Gazagnaire *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* Script to add findlib info *) open OpamTypes open OpamFilename.OP open OpamMisc.OP module StringSet = OpamMisc.StringSet let () = OpamGlobals.root_dir := OpamGlobals.default_opam_dir type args = { opam_pkgs: string list; findlib_pkgs: string list; infer: bool; install: bool; force: bool; orphans: bool; } let args = let open Cmdliner in let infer = let doc = "Infer the `findlib' file by looking at the contents of the \ `remove` field." in Arg.(value & flag & info ~doc ["infer"]) in let install = let doc = "Try to install the package if is not already installed and no \ previous information is known about that package." in Arg.(value & flag & info ~doc ["install"]) in let force = let doc = "Used in conjunction with `--infer` or `--install` to force \ the installation of packages, even if previous information \ about `findlib' libraries are already known for that package." in Arg.(value & flag & info ~doc ["force"]) in let orphans = let doc = "Display the orphans findlib packages" in Arg.(value & flag & info ~doc ["orphans"]) in let findlib_pkgs = let doc = "Findlib package name" in Arg.(value & opt (list string) [] & info ["pkg"] ~doc ~docv:"FINDLIB-PKGS") in let opam_pkgs = let doc = "OPAM package pattern" in Arg.(value & pos_all string [] & info [] ~doc ~docv:"OPAM-PKG") in Term.(pure (fun infer install force orphans findlib_pkgs opam_pkgs -> { infer; install; force; orphans; findlib_pkgs; opam_pkgs } ) $ infer $ install $ force $ orphans $ findlib_pkgs $ opam_pkgs) let state = lazy (OpamState.load_state "opam-admin-findlib") let installed_findlibs () = let { OpamState.Types.root; switch; _ } = Lazy.force state in let libdir = OpamPath.Switch.lib_dir root switch in let dirs = OpamFilename.dirs libdir in let libs = List.fold_left (fun acc dir -> let file = dir // "META" in if OpamFilename.exists file then let lib = Filename.basename (OpamFilename.Dir.to_string dir) in StringSet.add lib acc else acc ) StringSet.empty dirs in let files = OpamFilename.files libdir in let libs = List.fold_left (fun acc file -> let raw = Filename.basename (OpamFilename.to_string file) in let prefix = "META." in if OpamMisc.starts_with ~prefix raw then let lib = OpamMisc.remove_prefix ~prefix raw in StringSet.add lib acc else acc ) libs files in libs let declared_findlibs repo packages = let aux package acc = try let prefix = OpamPackage.Map.find package packages in let findlib_f = OpamPath.Repository.packages repo prefix package // "findlib" in let findlib = OpamFile.Lines.safe_read findlib_f in let findlib = StringSet.of_list (List.flatten findlib) in StringSet.union acc findlib with Not_found -> acc in let { OpamState.Types.installed } = Lazy.force state in OpamPackage.Set.fold aux installed StringSet.empty let infer_from_remove_command opam = let cmds = OpamFile.OPAM.remove opam in List.fold_left (fun acc (cmd: OpamTypes.command) -> match fst cmd with | (CString "ocamlfind",_) :: l -> let pkgs = OpamMisc.filter_map (function | CString s, _ -> Some s | _ -> None ) (List.tl l) in StringSet.union acc (StringSet.of_list pkgs); | _ -> acc ) StringSet.empty cmds let infer_from_name args package = let { OpamState.Types.root; switch; installed } = Lazy.force state in if args.install && not (OpamPackage.Set.mem package installed) then ( let atom = OpamPackage.name package, Some (`Eq, OpamPackage.version package) in let yes = !OpamGlobals.yes in OpamGlobals.yes := true; (* XXX: we could just install the dependencies, snapshot the build filsystem, install the package and look at the filesystem diff. We don't do this because I think this is not very useful in practice: the current heuristic will work well enough. *) begin try OpamClient.SafeAPI.install [atom] None false with OpamGlobals.Exit _ -> () end; OpamGlobals.yes := yes; ); let name = OpamPackage.name package in let name_str = OpamPackage.Name.to_string name in let meta = OpamPath.Switch.lib root switch name // "META" in let meta_dot = OpamPath.Switch.lib_dir root switch // ("META." ^ name_str) in if OpamFilename.exists meta || OpamFilename.exists meta_dot then StringSet.singleton name_str else StringSet.empty let process args = let repo = OpamRepository.local (OpamFilename.cwd ()) in let packages = OpamRepository.packages_with_prefixes repo in if args.orphans then let orphans = StringSet.diff (installed_findlibs ()) (declared_findlibs repo packages) in match StringSet.elements orphans with | [] -> () | orphans -> OpamGlobals.msg "%s\n" (String.concat "\n" orphans) else if args.infer || args.opam_pkgs <> [] || args.findlib_pkgs <> [] then let regexps = List.map (fun pattern -> if OpamPackage.Map.exists (fun pkg _ -> OpamPackage.Name.to_string (OpamPackage.name pkg) = pattern ) packages then pattern ^ ".*" else pattern ) args.opam_pkgs |> List.map (fun pattern -> Re.compile (Re_glob.globx pattern)) in let should_process package = match regexps with | [] -> true | _ -> let str = OpamPackage.to_string package in List.exists (fun re -> OpamMisc.exact_match re str) regexps in OpamPackage.Map.iter (fun package prefix -> if should_process package then ( let opam_f = OpamPath.Repository.opam repo prefix package in let filename = OpamFilename.dirname opam_f // "findlib" in if OpamFilename.exists filename && not args.force then () else ( OpamGlobals.msg "Processing %s\n" (OpamPackage.to_string package); let opam = OpamFile.OPAM.read opam_f in let pkgs0 = OpamFile.Lines.safe_read filename |> List.flatten |> StringSet.of_list in let pkgs1 = if args.infer then ( StringSet.union (infer_from_name args package) (infer_from_remove_command opam) ) else StringSet.of_list args.findlib_pkgs in let pkgs = StringSet.union pkgs0 pkgs1 in let contents = List.map (fun x -> [x]) (StringSet.elements pkgs) in if contents <> [] then OpamFile.Lines.write filename contents) ) ) packages else OpamGlobals.msg "Nothing to do.\n" opam-full-1.2.2/src/tools/opam_mk_repo.mli0000644000175000017500000000230712517374212017236 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) type args val args: args Cmdliner.Term.t val process: args -> unit opam-full-1.2.2/src/tools/opamlfind.ml0000644000175000017500000000715512517374212016374 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) let ocamlfind_command = if Filename.basename Sys.executable_name = "ocamlfind" then "ocamlfind.real" else "ocamlfind" let pass_on argv = prerr_endline " [go on]"; Unix.execvp ocamlfind_command (Array.concat [ [|ocamlfind_command|]; argv ]) let handle_install args = match args with | [] -> pass_on [||] | package :: args -> let dot_install = package ^ ".install" in if Sys.file_exists dot_install then (Printf.eprintf " %s exists, skipping" dot_install; pass_on (Array.of_list (package::args))) else let isoption s = try s.[0] = '-' with Invalid_argument _ -> false in let rec parse_params forcedll optional dlls files options = function | ("-destdir" | "-metadir" | "-ldconf" | "-patch-version" | "-patch-rmpkg") as arg :: param :: l -> parse_params forcedll optional dlls files ((arg,param)::options) l | "-optional" :: l -> parse_params forcedll true dlls files options l | "-dll" :: l -> parse_params (Some true) optional dlls files options l | "-nodll" :: l -> parse_params (Some false) optional dlls files options l | option :: l when isoption option -> parse_params forcedll optional dlls files ((option,"")::options) l | file :: l -> let isdll = match forcedll with | Some d -> d | None -> Filename.check_suffix file "dll" || Filename.check_suffix file "so" in let dlls, files = if isdll then (file,optional)::dlls, files else dlls, (file,optional)::files in parse_params forcedll optional dlls files options l | [] -> List.rev dlls, List.rev files, List.rev options in let dlls, files, _options = parse_params None false [] [] [] args in (* if try List.assoc "-destdir" rev_options <> opam-lib-dir with Not_found -> false then... *) let oc = open_out dot_install in let printl oc = List.iter (fun (src,opt) -> Printf.fprintf oc " %S\n" (if opt then "?" ^src else src)) in if files <> [] then Printf.fprintf oc "lib: [\n%a]\n" printl files; if dlls <> [] then Printf.fprintf oc "stublibs: [\n%a]\n" printl dlls; close_out oc; Printf.eprintf " %s%s%s generated" (Sys.getcwd ()) Filename.dir_sep dot_install; Printf.eprintf " [skip]\n" let () = prerr_string "[OPAM ocamlfind wrapper]"; if Array.length Sys.argv = 0 then pass_on Sys.argv else match Sys.argv.(0) with | "install" -> let args = List.tl (Array.to_list Sys.argv) in handle_install args | _ -> pass_on Sys.argv opam-full-1.2.2/src/opam.ocp0000644000175000017500000000025412517374212014361 0ustar userusercomp += [ "-g" "-w" "+a-4-9-32-41-44-45-48" "-warn-error" "+1..45-3" "-safe-string" ] link += [ "-g" "-w" "+a-4-9-32-41-44-45-48" "-warn-error" "+1..45-3" "-safe-string" ] opam-full-1.2.2/src/core/0000755000175000017500000000000012532744757013665 5ustar useruseropam-full-1.2.2/src/core/opamGlobals.ml0000644000175000017500000004131212517374212016444 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (* Convention: all the global OPAM variables can be set using environment variables using OPAM *) open OpamCompat let check ?(warn=true) var = ref ( try match String.lowercase (OpamMisc.getenv ("OPAM"^var)) with | "" | "0" | "no" | "false" -> false | "1" | "yes" | "true" -> true | v -> if warn then prerr_endline (OpamMisc.reformat ~indent:10 (Printf.sprintf "[WARNING] Invalid value %S for env variable OPAM%s, assumed \ true." v var)); true with Not_found -> false ) let when_var v = try (match OpamMisc.getenv ("OPAM"^v) with | "always" -> `Always | "never" -> `Never | _ -> `Auto ) with | Not_found -> `Auto let locale_utf8 () = let checkv v = try Some (OpamMisc.ends_with ~suffix:"UTF-8" (OpamMisc.getenv v)) with Not_found -> None in OpamMisc.Option.Op.(checkv "LC_ALL" ++ checkv "LANG" +! false) let dumb_term = try OpamMisc.getenv "TERM" = "dumb" with Not_found -> true let debug = check ~warn:false "DEBUG" let debug_level = try ref (int_of_string (OpamMisc.getenv ("OPAMDEBUG"))) with Not_found | Failure _ -> ref 1 let _ = if !debug_level > 1 then debug := true let verbose = check ~warn:false "VERBOSE" let verbose_level = try ref (int_of_string (OpamMisc.getenv ("OPAMVERBOSE"))) with | Not_found -> ref 0 | Failure _ -> ref 1 let color_when = when_var "COLOR" let color = ref (color_when = `Always || color_when = `Auto && OpamMisc.tty_out && not dumb_term) let disp_status_line_when = when_var "STATUSLINE" let disp_status_line () = disp_status_line_when = `Always || disp_status_line_when = `Auto && OpamMisc.tty_out && (!color || not dumb_term) let keep_build_dir = check "KEEPBUILDDIR" let no_base_packages = check "NOBASEPACKAGES" let no_checksums = check "NOCHECKSUMS" let req_checksums = check "REQUIRECHECKSUMS" let yes = check "YES" let no = check "NO" let strict = check "STRICT" let build_test = check "BUILDTEST" let build_doc = check "BUILDDOC" let show = check "SHOW" let dryrun = check "DRYRUN" let fake = check "FAKE" let print_stats = check "STATS" let utf8_msgs = check "UTF8MSGS" let utf8_when = when_var "UTF8" let utf8 = ref (utf8_when = `Always || utf8_when = `Auto && locale_utf8 () || !utf8_msgs) let autoremove = check "AUTOREMOVE" let do_not_copy_files = check "DONOTCOPYFILES" let sync_archives = check "SYNCARCHIVES" let no_self_upgrade = check ~warn:false "NOSELFUPGRADE" let skip_version_checks = check "SKIPVERSIONCHECKS" let safe_mode = check "SAFE" let lock_retries = try ref (int_of_string (OpamMisc.getenv ("OPAMLOCKRETRIES"))) with Not_found | Failure _ -> ref 5 let pin_kind_auto = check "PINKINDAUTO" let all_parens = ref false (* Value set when opam calls itself *) let self_upgrade_bootstrapping_value = "bootstrapping" let is_self_upgrade = try OpamMisc.getenv "OPAMNOSELFUPGRADE" = self_upgrade_bootstrapping_value with Not_found -> false let jobs = ref ( try Some (int_of_string (OpamMisc.getenv "OPAMJOBS")) with Not_found | Failure _ -> None ) let dl_jobs = ref ( try Some (int_of_string (OpamMisc.getenv "OPAMDOWNLOADJOBS")) with Not_found | Failure _ -> None ) let download_retry = try max 1 (int_of_string (OpamMisc.getenv "OPAMRETRY")) with Not_found | Failure _ -> 3 let cudf_file = ref ( try Some (OpamMisc.getenv "OPAMCUDFFILE") with Not_found -> None ) let solver_timeout = try float_of_string (OpamMisc.getenv "OPAMSOLVERTIMEOUT") with Not_found | Failure _ -> 5. type solver_criteria = [ `Default | `Upgrade | `Fixup ] let default_preferences = function | `Default -> "-count(removed),\ -notuptodate(request),-sum(request,version-lag),\ -count(down),\ -notuptodate(changed),-count(changed),\ -notuptodate(solution),-sum(solution,version-lag)" | `Upgrade -> "-count(down),\ -count(removed),\ -notuptodate(solution),-sum(solution,version-lag),\ -count(new)" | `Fixup -> "-count(changed),\ -notuptodate(solution),-sum(solution,version-lag)" let compat_preferences = function (* Not as good, but for older solver versions *) | `Default -> "-removed,-notuptodate,-changed" | `Upgrade -> "-removed,-notuptodate,-changed" | `Fixup -> "-changed,-notuptodate" let solver_preferences = let get prefs var kind = try (kind, OpamMisc.strip (OpamMisc.getenv var)) :: prefs with Not_found -> prefs in let prefs = [] in let prefs = get prefs "OPAMCRITERIA" `Default in let prefs = get prefs "OPAMUPGRADECRITERIA" `Upgrade in let prefs = get prefs "OPAMFIXUPCRITERIA" `Fixup in ref prefs let get_solver_criteria action = try List.assoc action !solver_preferences with Not_found -> compat_preferences action let default_external_solver = "aspcud" let env_external_solver = try ref (Some (OpamMisc.strip (OpamMisc.getenv "OPAMEXTERNALSOLVER"))) with Not_found -> ref None let external_solver_ref = ref None let use_external_solver = ref (not (!(check "NOASPCUD") || !(check "USEINTERNALSOLVER") || !env_external_solver = Some "")) let external_solver ~input ~output ~criteria = match !external_solver_ref with | Some f -> f ~input ~output ~criteria | None -> raise Not_found let default_repository_name = "default" let default_repository_address = "https://opam.ocaml.org" let download_tool_env = try ref (Some (OpamMisc.getenv "OPAMFETCH")) with Not_found -> ref None let curl_command = try OpamMisc.getenv "OPAMCURL" with Not_found -> "curl" type download_tool = [ | `Wget | `Curl | `Custom of url:string -> out:string -> retry:int -> ?checksum:string -> compress:bool -> string list ] let download_tool = ref None let search_files = ref ["findlib"] let default_build_command = [ [ "./build.sh" ] ] let global_config = "global-config" let system = "system" let switch: [`Env of string | `Command_line of string | `Not_set ] ref = ref ( try `Env (OpamMisc.getenv "OPAMSWITCH") with Not_found -> `Not_set ) let external_tags = ref ([] : string list) let home = try OpamMisc.getenv "HOME" with Not_found -> Sys.getcwd () let default_opam_dir = try OpamMisc.getenv "OPAMROOT" with Not_found -> Filename.concat home ".opam" let root_dir_tmp = Filename.concat (Filename.get_temp_dir_name ()) ("opam-" ^ string_of_int (Unix.getpid ())) let root_dir = ref root_dir_tmp let timer () = if !debug then let t = Sys.time () in fun () -> Sys.time () -. t else fun () -> 0. (* For forked process, we want to get the time since the beginning of the parent process. *) let global_start_time = Unix.gettimeofday () type text_style = [ `bold | `underline | `black | `red | `green | `yellow | `blue | `magenta | `cyan | `white ] (* not nestable *) let colorise (c: text_style) s = if not !color then s else let code = match c with | `bold -> "01" | `underline -> "04" | `black -> "30" | `red -> "31" | `green -> "32" | `yellow -> "33" | `blue -> "1;34" | `magenta -> "35" | `cyan -> "36" | `white -> "37" in Printf.sprintf "\027[%sm%s\027[m" code s let acolor_with_width width c oc s = let str = colorise c s in output_string oc str; match width with | None -> () | Some w -> if String.length str >= w then () else output_string oc (String.make (w-String.length str) ' ') let acolor c oc s = acolor_with_width None c oc s let acolor_w width c oc s = acolor_with_width (Some width) c oc s let timestamp () = let time = Unix.gettimeofday () -. global_start_time in let tm = Unix.gmtime time in let msec = time -. (floor time) in Printf.ksprintf (colorise `blue) "%.2d:%.2d.%.3d" (tm.Unix.tm_hour * 60 + tm.Unix.tm_min) tm.Unix.tm_sec (int_of_float (1000.0 *. msec)) let log section ?(level=1) fmt = if !debug && level <= !debug_level then let () = flush stdout in Printf.fprintf stderr ("%s %a " ^^ fmt ^^ "\n%!") (timestamp ()) (acolor_w 30 `yellow) section else Printf.ifprintf stderr fmt (* Helper to pass stringifiers to log (use [log "%a" (slog to_string) x] rather than [log "%s" (to_string x)] to avoid costly unneeded stringifications *) let slog to_string channel x = output_string channel (to_string x) let error fmt = Printf.ksprintf (fun str -> flush stdout; Printf.eprintf "%a %s\n%!" (acolor `red) "[ERROR]" (OpamMisc.reformat ~start_column:8 ~indent:8 str) ) fmt let warning fmt = Printf.ksprintf (fun str -> flush stdout; Printf.eprintf "%a %s\n%!" (acolor `yellow) "[WARNING]" (OpamMisc.reformat ~start_column:10 ~indent:10 str) ) fmt let note fmt = Printf.ksprintf (fun str -> flush stdout; Printf.eprintf "%a %s\n%!" (acolor `blue) "[NOTE]" (OpamMisc.reformat ~start_column:7 ~indent:7 str) ) fmt let errmsg fmt = flush stdout; Printf.printf (fmt ^^ "%!") exception Exit of int exception Exec of string * string array * string array exception Package_error of string let error_and_exit fmt = Printf.ksprintf (fun str -> error "%s" str; raise (Exit 66) ) fmt let display_messages = ref true let msg fmt = if !display_messages then ( flush stderr; Printf.printf (fmt ^^ "%!") ) else ( Printf.ifprintf stdout fmt ) let formatted_msg ?indent fmt = if !display_messages then ( flush stderr; Printf.ksprintf (fun s -> print_string (OpamMisc.reformat ?indent s); flush stdout) fmt ) else ( Printf.ksprintf ignore fmt ) let status_line fmt = let carriage_delete = "\r\027[K" in let endline = if !debug then "\n" else carriage_delete in if !display_messages && disp_status_line () then ( flush stderr; Printf.kfprintf (fun ch -> output_string ch endline (* unflushed *)) stdout ("%s" ^^ fmt ^^ "%!") carriage_delete ) else Printf.ifprintf stdout fmt let header_width () = 80 let header_msg fmt = let utf8camel = "\xF0\x9F\x90\xAB " in (* UTF-8 *) let padding = "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" in Printf.ksprintf (fun str -> flush stderr; if !display_messages then ( print_char '\n'; let wpad = header_width () - String.length str - 2 in let wpadl = 4 in print_string (colorise `cyan (String.sub padding 0 wpadl)); print_char ' '; print_string (colorise `bold str); print_char ' '; let wpadr = wpad - wpadl - if !utf8_msgs then 4 else 0 in if wpadr > 0 then print_string (colorise `cyan (String.sub padding (String.length padding - wpadr) wpadr)); if wpadr >= 0 && !utf8_msgs then (print_string " "; print_string (colorise `yellow utf8camel)); print_char '\n'; flush stdout; ) ) fmt let header_error fmt = let padding = "#=======================================\ ========================================#" in Printf.ksprintf (fun head fmt -> Printf.ksprintf (fun contents -> output_char stderr '\n'; let wpad = header_width () - String.length head - 8 in let wpadl = 4 in output_string stderr (colorise `red (String.sub padding 0 wpadl)); output_char stderr ' '; output_string stderr (colorise `bold "ERROR"); output_char stderr ' '; output_string stderr (colorise `bold head); output_char stderr ' '; let wpadr = wpad - wpadl in if wpadr > 0 then output_string stderr (colorise `red (String.sub padding (String.length padding - wpadr) wpadr)); output_char stderr '\n'; output_string stderr contents; output_char stderr '\n'; flush stderr; ) fmt ) fmt let editor = lazy ( try OpamMisc.getenv "OPAM_EDITOR" with Not_found -> try OpamMisc.getenv "VISUAL" with Not_found -> try OpamMisc.getenv "EDITOR" with Not_found -> "nano" ) type os = | Darwin | Linux | FreeBSD | OpenBSD | NetBSD | DragonFly | Cygwin | Win32 | Unix | Other of string let os = let os = lazy ( match Sys.os_type with | "Unix" -> begin match OpamMisc.uname_s () with | Some "Darwin" -> Darwin | Some "Linux" -> Linux | Some "FreeBSD" -> FreeBSD | Some "OpenBSD" -> OpenBSD | Some "NetBSD" -> NetBSD | Some "DragonFly" -> DragonFly | _ -> Unix end | "Win32" -> Win32 | "Cygwin" -> Cygwin | s -> Other s ) in fun () -> Lazy.force os let arch = let arch = lazy (OpamMisc.Option.default "Unknown" (OpamMisc.uname_m ())) in fun () -> Lazy.force arch let string_of_os = function | Darwin -> "darwin" | Linux -> "linux" | FreeBSD -> "freebsd" | OpenBSD -> "openbsd" | NetBSD -> "netbsd" | DragonFly -> "dragonfly" | Cygwin -> "cygwin" | Win32 -> "win32" | Unix -> "unix" | Other x -> x let os_string () = string_of_os (os ()) let makecmd = ref (fun () -> match os () with | FreeBSD | OpenBSD | NetBSD | DragonFly -> "gmake" | _ -> "make" ) let log_limit = 10 let log_line_limit = 5 * 80 let default_jobs = 4 let default_dl_jobs = 3 let exit i = raise (Exit i) let confirm ?(default=true) fmt = Printf.ksprintf (fun s -> try if !safe_mode then false else let prompt () = formatted_msg "%s [%s] " s (if default then "Y/n" else "y/N") in if !yes then (prompt (); msg "y\n"; true) else if !no then (prompt (); msg "n\n"; false) else if not OpamMisc.tty_out || os () = Win32 || os () = Cygwin then let rec loop () = prompt (); match String.lowercase (read_line ()) with | "y" | "yes" -> true | "n" | "no" -> false | "" -> default | _ -> loop () in loop () else let open Unix in prompt (); let buf = Bytes.create 1 in let rec loop () = let ans = try if read stdin buf 0 1 = 0 then raise End_of_file else Some (Char.lowercase (Bytes.get buf 0)) with | Unix.Unix_error (Unix.EINTR,_,_) -> None | Unix.Unix_error _ -> raise End_of_file in match ans with | Some 'y' -> print_endline (Bytes.to_string buf); true | Some 'n' -> print_endline (Bytes.to_string buf); false | Some '\n' -> print_endline (if default then "y" else "n"); default | _ -> loop () in let attr = tcgetattr stdin in let reset () = tcsetattr stdin TCSAFLUSH attr; tcflush stdin TCIFLUSH; in try tcsetattr stdin TCSAFLUSH {attr with c_icanon = false; c_echo = false}; tcflush stdin TCIFLUSH; let r = loop () in reset (); r with e -> reset (); raise e with | End_of_file -> msg "%s\n" (if default then "y" else "n"); default | Sys.Break as e -> msg "\n"; raise e ) fmt let read fmt = Printf.ksprintf (fun s -> formatted_msg "%s %!" s; if not !yes || !no || !safe_mode then ( try match read_line () with | "" -> None | s -> Some s with | End_of_file -> msg "\n"; None | Sys.Break as e -> msg "\n"; raise e ) else None ) fmt opam-full-1.2.2/src/core/opamTypes.mli0000644000175000017500000002723112517374212016342 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Common types used by other modules *) (** {2 Error and continuation handling} *) type 'a success = [ `Successful of 'a ] type 'a error = [ | `Error of 'a | `Exception of exn ] type ('a,'b) status = [ 'a success | 'b error ] (** {2 Filenames} *) (** Basenames *) type basename = OpamFilename.Base.t (** Directory names *) type dirname = OpamFilename.Dir.t (** Filenames *) type filename = OpamFilename.t (** Set of files *) type filename_set = OpamFilename.Set.t (** Map of files *) type 'a filename_map = 'a OpamFilename.Map.t (** Generalized file type *) type generic_file = OpamFilename.generic_file = | D of dirname | F of filename (** Download result *) type 'a download = | Up_to_date of 'a | Not_available of string | Result of 'a (** {2 Packages} *) (** Packages are ([name] * [version]) tuple *) type package = OpamPackage.t (** Set of packages *) type package_set = OpamPackage.Set.t (** Map of packages *) type 'a package_map = 'a OpamPackage.Map.t (** Package names *) type name = OpamPackage.Name.t (** Set of package names *) type name_set = OpamPackage.Name.Set.t (** Map of package names *) type 'a name_map = 'a OpamPackage.Name.Map.t (** Package versions *) type version = OpamPackage.Version.t (** Set of package versions *) type version_set = OpamPackage.Version.Set.t (** {2 Compilers} *) (** Compiler names *) type compiler = OpamCompiler.t (** Set of compiler names *) type compiler_set = OpamCompiler.Set.t (** Maps of compiler names *) type 'a compiler_map = 'a OpamCompiler.Map.t (** Compiler versions *) type compiler_version = OpamCompiler.Version.t (** OPAM versions *) type opam_version = OpamVersion.t (** Compiler constraints *) type compiler_constraint = OpamCompiler.Version.constr (** {2 Variables} *) (** Variables *) type variable = OpamVariable.t (** Fully qualified variables (ie. with the name of sections/sub-sections they appear in) *) type full_variable = OpamVariable.Full.t (** Content of user-defined variables *) type variable_contents = OpamVariable.variable_contents = | B of bool | S of string (** A map from variables to their contents (i.e an environment) *) type variable_map = OpamVariable.variable_contents OpamVariable.Map.t (** Opam package flags *) type package_flag = | Pkgflag_LightUninstall (** The package doesn't require downloading to uninstall *) | Pkgflag_AllSwitches (** The package is pervasive on all switches *) | Pkgflag_Verbose (** The package's scripts output is to be displayed to the user *) | Pkgflag_Plugin (** The package is an opam plugin that will install a [opam-] exec, and may be auto-installed when doing [opam ] *) | Pkgflag_Unknown of string (** Used for error reporting, otherwise ignored *) (** Flags on dependencies *) type package_dep_flag = | Depflag_Build | Depflag_Test | Depflag_Doc | Depflag_Dev | Depflag_Unknown of string (** Used for error reporting, otherwise ignored *) (** At some point we want to abstract so that the same functions can be used over CUDF and OPAM packages *) module type GenericPackage = sig include OpamParallel.VERTEX val name_to_string: t -> string val version_to_string: t -> string end (** {2 Formulas} *) (** A generic formula *) type 'a generic_formula = 'a OpamFormula.formula = | Empty | Atom of 'a | Block of 'a generic_formula | And of 'a generic_formula * 'a generic_formula | Or of 'a generic_formula * 'a generic_formula (** Formula atoms *) type atom = OpamFormula.atom (** Formula over versionned packages *) type formula = OpamFormula.t (** Formula over versionned packages *) type ext_formula = package_dep_flag list OpamFormula.ext_package_formula (** AND formulat *) type 'a conjunction = 'a OpamFormula.conjunction (** OR formulat *) type 'a disjunction = 'a OpamFormula.disjunction (** {2 Repositories} *) (** Repository names *) type repository_name = OpamRepositoryName.t (** Maps of repository names *) type 'a repository_name_map = 'a OpamRepositoryName.Map.t (** Repository kind *) type repository_kind = [`http|`local|`git|`darcs|`hg] (** Repository address *) type address = string * string option (** Repository root *) type repository_root = dirname (** Repositories *) type repository = { repo_root : repository_root; repo_name : repository_name; repo_kind : repository_kind; repo_address : address; repo_priority: int; } (** {2 Solver} *) (** The solver answers a list of actions to perform *) type 'a action = (** The package must be installed. The package could have been present or not, but if present, it is another version than the proposed solution. *) | To_change of 'a option * 'a (** The package must be deleted. *) | To_delete of 'a (** The package is already installed, but it must be recompiled. *) | To_recompile of 'a (** The possible causes of an action. *) type 'a cause = | Use of 'a list | Required_by of 'a list | Conflicts_with of 'a list | Upstream_changes | Requested | Unknown (** Solver result *) type solver_result = | Nothing_to_do | OK of package action list (** List of successful actions *) | Aborted | No_solution | Error of package action list * package action list * package action list (** List of successful actions, list of actions with errors, list of remaining undone actions *) (** Solver result *) type ('a, 'b) result = | Success of 'a | Conflicts of 'b type solver_criteria = [ `Default | `Upgrade | `Fixup ] (** Solver request *) type 'a request = { criteria: solver_criteria; wish_install: 'a conjunction; wish_remove : 'a conjunction; wish_upgrade: 'a conjunction; } (** user request action *) type user_action = | Install of name_set (** The 'root' packages to be installed *) | Upgrade of package_set (** The subset of packages to upgrade *) | Reinstall of package_set | Depends | Init | Remove | Switch of name_set (** The 'root' packages to be installed *) | Import of name_set (** The 'root' packages to be installed *) (** Solver universe *) type universe = { u_packages : package_set; u_installed: package_set; u_available: package_set; u_depends : ext_formula package_map; u_depopts : ext_formula package_map; u_conflicts: formula package_map; u_action : user_action; u_installed_roots: package_set; u_pinned : package_set; u_base : package_set; } (** {2 Command line arguments} *) (** Upload arguments *) type upload = { upl_opam : filename; upl_descr : filename; upl_archive: filename; } (** Pinned packages options *) type pin_option = | Version of version | Local of dirname | Git of address | Darcs of address | Hg of address | Http of address (** Pin kind *) type pin_kind = [`version|`http|`git|`darcs|`hg|`local] (** Shell compatibility modes *) type shell = [`fish|`csh|`zsh|`sh|`bash] (** Global configuration option *) type global_config = { complete : bool; switch_eval: bool; } (** User configuration option *) type user_config = { shell : shell; ocamlinit : bool; dot_profile: filename option; } (** {2 Filtered commands} *) type relop = OpamFormula.relop type logop = [ `And | `Or ] type pfxop = [ `Not ] (** Filter *) type filter = | FBool of bool | FString of string | FIdent of (name list * variable * (string * string) option) (** packages, variable name, string converter (val_if_true, val_if_false_or_undef) *) | FOp of filter * relop * filter | FAnd of filter * filter | FOr of filter * filter | FNot of filter | FUndef (** A command argument *) type simple_arg = | CString of string | CIdent of string (** Command argument *) type arg = simple_arg * filter option (** Command *) type command = arg list * filter option (** {2 Untyped generic file format} *) (** Source file positions: filename, line, column *) type pos = filename * int * int (** Base values *) type value = | Bool of pos * bool | Int of pos * int | String of pos * string | Relop of pos * relop * value * value | Prefix_relop of pos * relop * value | Logop of pos * logop * value * value | Pfxop of pos * pfxop * value | Ident of pos * string | List of pos * value list | Group of pos * value list | Option of pos * value * value list | Env_binding of pos * string * value * value (** A file section *) type file_section = { section_kind : string; section_name : string; section_items : file_item list; } (** A file is composed of sections and variable definitions *) and file_item = | Section of pos * file_section | Variable of pos * string * value (** A file is a list of items and the filename *) type file = { file_contents: file_item list; file_name : string; file_format : opam_version; } (** {2 Switches} *) (** Compiler switches *) type switch = OpamSwitch.t (** Set of compiler switches *) type switch_set = OpamSwitch.Set.t (** Map of compile switches *) type 'a switch_map = 'a OpamSwitch.Map.t (** {2 Misc} *) (** The different kinds of locks *) type lock = (** The function does not modify anything, but it needs the state not to change while it is running. *) | Read_lock of (unit -> unit) (** Take the global lock, all subsequent calls to OPAM are blocked. *) | Global_lock of (unit -> unit) (** Take the lock only for [OpamGlobals.current_switch] if it not [None], otherwise for the current lock. We do not pass the switch directly as argument as we might need to read some configuration file and we thus need to take the global loock for a short time. *) | Switch_lock of (unit -> unit) (** Call the function in a global lock, then relax to a switch lock and call the function it returned *) | Global_with_switch_cont_lock of (unit -> switch * (unit -> unit)) (** A line in {i urls.tx} *) type file_attribute = OpamFilename.Attribute.t (** All the lines in {i urls.txt} *) type file_attribute_set = OpamFilename.Attribute.Set.t (** Optional contents *) type 'a optional = { c : 'a; (** Contents *) optional: bool; (** Is the contents optional *) } (** Upgrade statistics *) type stats = { s_install : int; s_reinstall: int; s_upgrade : int; s_downgrade: int; s_remove : int; } (** Environement variables *) type env = (string * string) list (** Environment updates *) type env_updates = (string * string * string) list (** Tags *) type tags = OpamMisc.StringSet.t OpamMisc.StringSetMap.t (** {2 Repository and global states} *) (** Checksums *) type checksums = string list (** {2 JSON} *) type json = OpamJson.t (** {2 Updates} *) type 'a updates = { created: 'a; updated: 'a; deleted: 'a; changed: 'a; } opam-full-1.2.2/src/core/opamRepositoryName.mli0000644000175000017500000000234612517374212020216 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Repository names *) include OpamMisc.ABSTRACT (** Default repository name *) val default: t opam-full-1.2.2/src/core/opamActionGraph.ml0000644000175000017500000001347712517374212017273 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes module type ACTION = sig type package module Pkg : GenericPackage with type t = package include OpamParallel.VERTEX with type t = package action val to_aligned_strings: t list -> string list end let action_strings ?utf8 x = if utf8 = None && !OpamGlobals.utf8 || utf8 = Some true then List.assoc x [`inst, "\xe2\x88\x97 "; `up, "\xe2\x86\x97 "; `down, "\xe2\x86\x98 "; `reinst, "\xe2\x86\xbb "; `rm, "\xe2\x8a\x98 "] else List.assoc x [`inst, "install"; `up, "upgrade"; `down, "downgrade"; `reinst, "recompile"; `rm, "remove"] let action_color c = OpamGlobals.colorise (match c with | `inst | `up -> `green | `rm | `down -> `red | `reinst -> `yellow) module MakeAction (P: GenericPackage) : ACTION with type package = P.t = struct module Pkg = P type package = P.t type t = package action let compare t1 t2 = (* To_change > To_recompile > To_delete *) match t1,t2 with | To_delete p, To_delete q | To_recompile p, To_recompile q -> P.compare p q | To_change (po,p), To_change (qo,q) -> let c = P.compare p q in if c <> 0 then c else OpamMisc.Option.compare P.compare po qo | To_change _, _ | _, To_delete _ -> 1 | _, To_change _ | To_delete _, _ -> -1 let hash = function | To_change (None, p) -> Hashtbl.hash (`C, P.hash p) | To_change (Some p1, p2) -> Hashtbl.hash (`C, P.hash p1, P.hash p2) | To_delete p -> Hashtbl.hash (`D, P.hash p) | To_recompile p -> Hashtbl.hash (`R, P.hash p) let equal t1 t2 = compare t1 t2 = 0 let to_string = function | To_change (None, p) -> Printf.sprintf "%s %s" (action_strings `inst) (P.to_string p) | To_change (Some o, p) -> Printf.sprintf "%s.%s %s %s" (P.name_to_string o) (P.version_to_string o) (action_strings (if P.compare o p < 0 then `up else `down)) (P.version_to_string p) | To_recompile p -> Printf.sprintf "%s %s" (action_strings `reinst) (P.to_string p) | To_delete p -> Printf.sprintf "%s %s" (action_strings `rm) (P.to_string p) let to_aligned_strings l = let code c = if !OpamGlobals.utf8 then action_color c (action_strings c) else "-" in let name p = OpamGlobals.colorise `bold (P.name_to_string p) in let tbl = List.map (function | To_change (None, p) -> [ code `inst; "install"; name p; P.version_to_string p ] | To_change (Some o, p) -> let up = P.compare o p < 0 in [ code (if up then `up else `down); if up then "upgrade" else "downgrade"; name p; Printf.sprintf "%s to %s" (P.version_to_string o) (P.version_to_string p) ] | To_recompile p -> [ code `reinst; "recompile"; name p; P.version_to_string p ] | To_delete p -> [ code `rm; "remove"; name p; P.version_to_string p ]) l in List.map (String.concat " ") (OpamMisc.align_table tbl) let to_json = function | To_change (None, p) -> `O ["install", P.to_json p] | To_change (Some o, p) -> `O ["change", `A [P.to_json o;P.to_json p]] | To_recompile p -> `O ["recompile", P.to_json p] | To_delete p -> `O ["remove", P.to_json p] end module type SIG = sig type package include OpamParallel.GRAPH with type V.t = package OpamTypes.action val reduce: t -> t end module Make (A: ACTION) : SIG with type package = A.package = struct type package = A.package include OpamParallel.MakeGraph(A) module Map = OpamMisc.Map.Make (A.Pkg) (* Turn atomic actions (only install and remove) to higher-level actions (install, remove, up/downgrade, recompile) *) let reduce g = let removals = fold_vertex (fun v acc -> match v with | To_delete p -> OpamMisc.StringMap.add (A.Pkg.name_to_string p) p acc | _ -> acc) g OpamMisc.StringMap.empty in let reduced = ref Map.empty in let g = map_vertex (function | To_change (None, p) as act -> (try let p0 = OpamMisc.StringMap.find (A.Pkg.name_to_string p) removals in let act = if A.Pkg.equal p0 p then To_recompile p else To_change (Some p0, p) in reduced := Map.add p0 act !reduced; act with Not_found -> act) | act -> act) g in Map.iter (fun p act -> let rm_act = To_delete p in iter_pred (fun v -> add_edge g v act) g rm_act; remove_vertex g rm_act ) !reduced; g end opam-full-1.2.2/src/core/opamFilter.mli0000644000175000017500000001061212517374212016456 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Manage filters *) (** Filters are a small language of formulas over strings and booleans used for conditions and text replacements. It has relational operators over strings (using version-number comparison), And, Or and Not boolean operations, dynamic casting (using strings "true" and "false"), and string interpolation. Variables are resolved using a user function returning an option, undefined values are propagated. String interpolation uses the syntax '%{identifier}%' Identifiers have the form {v[package:]var[?str_if_true:str_if_false_or_undef]v}. The last optional part specifies a conversion from boolean to static strings. The syntax [pkg1+pkg2+pkgn:var] is allowed as a shortcut to [pkg1:var & pkg2:var & pkgn:var]. The special variable [pkg:enable] is allowed as a shortcut for [pkg:installed?enable:disable] *) open OpamTypes (** Pretty-print *) val to_string: filter -> string (** Folds on the tree of a filter *) val fold_down_left: ('a -> filter -> 'a) -> 'a -> filter -> 'a (** Returns all the variables appearing in a filter (including the ones within string interpolations *) val variables: filter -> full_variable list (** Type of filter environment. *) type env = full_variable -> variable_contents option (** The type of filter idents with (optionally multiple) qualifying package names and optional string converter *) type fident = name list * variable * (string * string) option (** Rewrites string interpolations within a string *) val expand_string: env -> string -> string (** Computes the value of a filter. May raise [Failure] if [default] isn't provided *) val eval: ?default:variable_contents -> env -> filter -> variable_contents (** Like [to_value] but casts the result to a bool. Raises [Invalid_argument] if not a valid bool and no default supplied. *) val eval_to_bool: ?default:bool -> env -> filter -> bool (** Same as [eval_to_bool], but takes an option as filter and returns always [true] on [None], [false] when the filter is [Undefined]. This is the most common behaviour for using "filters" for filtering *) val opt_eval_to_bool: env -> filter option -> bool (** Like [to_value] but casts the result to a string *) val eval_to_string: ?default:string -> env -> filter -> string (** Wraps a full_variable into a fident accessor *) val ident_of_var: full_variable -> fident (** Resolves a filter ident. Like [eval], may raise Failure if no default is provided *) val ident_value: ?default:variable_contents -> env -> fident -> variable_contents (** Like [ident_value], but casts the result to a string *) val ident_string: ?default:string -> env -> fident -> string (** Like [ident_value], but casts the result to a bool *) val ident_bool: ?default:bool -> env -> fident -> bool (** Rewrites [basename].in to [basename], expanding interpolations *) val expand_interpolations_in_file: env -> basename -> unit (** Processes filters evaluation in a command list: parameter expansion and conditional filtering *) val commands: env -> command list -> string list list (** Process a simpler command, without filters *) val single_command: env -> arg list -> string list (** Extracts variables appearing in a list of commands *) val commands_variables: command list -> full_variable list opam-full-1.2.2/src/core/opamScript.mli0000644000175000017500000000231512517374212016476 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) val complete : string val complete_zsh : string val switch_eval : string opam-full-1.2.2/src/core/opamCompiler.mli0000644000175000017500000000454012517374212017006 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Compiler names and versions *) (** OCaml compiler versions *) module Version: sig include OpamMisc.ABSTRACT (** Compiler constraint *) type constr = (OpamFormula.relop * t) OpamFormula.formula (** Compare OCaml versions *) val compare: t -> t -> int (** Evaluate a relational operator between OCaml versions *) val eval_relop: OpamFormula.relop -> t -> t -> bool end (** Compiler names *) include OpamMisc.ABSTRACT (** Return the compiler version *) val version: t -> Version.t (** Return the current compiler at its currently installed version *) val get_current: unit -> t option (** Return the system compiler at is current version. Warning, this is different from [system] which is a static string with version ["system"] *) val get_system: unit -> t option (** Convert a filename into a compiler name. This function extract [name] from {i /path/to/$name.comp}. *) val of_filename: OpamFilename.t -> t option (** List the compiler available in the global state. *) val list: OpamFilename.Dir.t -> Set.t (** List the compiler available in a directory (and their prefix) *) val prefixes: OpamFilename.Dir.t -> string option Map.t (** System compiler *) val system: t (** Errors *) val unknown: t -> 'a opam-full-1.2.2/src/core/opamGlobals.mli0000644000175000017500000001523112517374212016616 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Convention: all the global OPAM variables can be set using environment variables using OPAM *) val debug : bool ref val debug_level : int ref val verbose : bool ref val verbose_level : int ref val color_when : [> `Always | `Auto | `Never ] val color : bool ref val disp_status_line : unit -> bool val utf8_when : [> `Always | `Auto | `Never ] val utf8 : bool ref val keep_build_dir : bool ref val no_base_packages : bool ref val no_checksums : bool ref val req_checksums : bool ref val yes : bool ref val strict : bool ref val build_test : bool ref val build_doc : bool ref val show : bool ref val dryrun : bool ref val fake : bool ref val print_stats : bool ref val utf8_msgs : bool ref (* val autoremove : bool ref *) val do_not_copy_files : bool ref val sync_archives : bool ref val use_external_solver : bool ref val no_self_upgrade : bool ref val skip_version_checks : bool ref val safe_mode : bool ref val lock_retries : int ref val pin_kind_auto : bool ref (** Tells the printer to write parens everywhere *) val all_parens : bool ref (* Value set when opam calls itself *) val self_upgrade_bootstrapping_value : string val is_self_upgrade : bool val jobs : int option ref val dl_jobs : int option ref val download_retry : int val cudf_file : string option ref val solver_timeout : float type solver_criteria = [ `Default | `Upgrade | `Fixup ] val default_preferences : solver_criteria -> string val compat_preferences : solver_criteria -> string (** Solver preference bindings. Used with List.assoc: first one wins *) val solver_preferences : (solver_criteria * string) list ref (** Get the currently configured solver criteria as a string *) val get_solver_criteria : [ `Default | `Upgrade | `Fixup ] -> string val env_external_solver : string option ref val default_external_solver : string val external_solver_ref : (input:string -> output:string -> criteria:string -> string list) option ref val external_solver : input:string -> output:string -> criteria:string -> string list type download_tool = [ | `Wget | `Curl | `Custom of url:string -> out:string -> retry:int -> ?checksum:string -> compress:bool -> string list ] val download_tool_env: string option ref val download_tool : download_tool option ref val curl_command : string val default_repository_name : string val default_repository_address : string val search_files: string list ref (* val default_build_command : string list list *) val global_config : string val system : string val switch : [ `Command_line of string | `Env of string | `Not_set ] ref val external_tags : string list ref val home : string val default_opam_dir : string val root_dir : string ref (** The initial value of root_dir, set in the tmpdir before initialised *) val root_dir_tmp : string val timer : unit -> unit -> float (* For forked process, we want to get the time since the beginning of the parent process. *) val global_start_time : float type text_style = [ `black | `blue | `bold | `cyan | `green | `magenta | `red | `underline | `white | `yellow ] (** not nestable *) val colorise : text_style -> string -> string val acolor : text_style -> out_channel -> string -> unit val acolor_w : int -> text_style -> out_channel -> string -> unit val timestamp : unit -> string (** [log section ~level fmt args]. Used for debug messages, default level is 1 *) val log : string -> ?level:int -> ('a, out_channel, unit) format -> 'a (** Helper to pass stringifiers to log (use [log "%a" (slog to_string) x] rather than [log "%s" (to_string x)] to avoid costly unneeded stringifications *) val slog : ('a -> string) -> out_channel -> 'a -> unit val error : ('a, unit, string, unit) format4 -> 'a val warning : ('a, unit, string, unit) format4 -> 'a val note : ('a, unit, string, unit) format4 -> 'a (** Message without prefix, reformat or newline, to stderr (useful to continue error messages without repeating "[ERROR]") *) val errmsg : ('a, out_channel, unit, unit, unit, unit) format6 -> 'a (** Raised to exit the program in a clean way. Parameter is the exit code. *) exception Exit of int (** Raised to [exec()] another binary, after making sure finalisations have been made properly. Parameters as per [Unix.execvpe] *) exception Exec of string * string array * string array exception Package_error of string val error_and_exit : ('a, unit, string, 'b) format4 -> 'a val msg : ('a, out_channel, unit, unit) format4 -> 'a val formatted_msg : ?indent:int -> ('a, unit, string, unit) format4 -> 'a val header_msg : ('a, unit, string, unit) format4 -> 'a val header_error : ('a, unit, string, ('b, unit, string, unit) format4 -> 'b) format4 -> 'a (** Display a dynamic status line to stdout, that will be erased on next output. The message should not be wider than screen nor contain newlines. *) val status_line : ('a, out_channel, unit, unit, unit, unit) format6 -> 'a (** Ask the user to press Y/y/N/n to continue (returns a boolean). Defaults to true (yes) if unspecified *) val confirm: ?default:bool -> ('a, unit, string, bool) format4 -> 'a (** Read some input from the user (returns a string option) *) val read: ('a, unit, string, string option) format4 -> 'a val editor : string lazy_t type os = Darwin | Linux | FreeBSD | OpenBSD | NetBSD | DragonFly | Cygwin | Win32 | Unix | Other of string val os : unit -> os val os_string : unit -> string val arch : unit -> string val makecmd : (unit -> string) ref val log_limit : int val log_line_limit : int val default_jobs : int val default_dl_jobs : int val exit : int -> 'a opam-full-1.2.2/src/core/opamCompat.ml.4.010000644000175000017500000000301212517374212016660 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) module Bytes = struct include String let sub_string = sub let empty = "" let of_string x = String.copy x let to_string x = String.copy x let blit_string = String.blit external unsafe_to_string : t -> string = "%identity" external unsafe_of_string : string -> t = "%identity" end module Buffer = struct include Buffer let add_subbytes = add_substring end module Filename = struct include Filename let get_temp_dir_name () = temp_dir_name end opam-full-1.2.2/src/core/opamSwitch.mli0000644000175000017500000000247612517374212016503 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Compiler switches *) include OpamMisc.ABSTRACT (** Default switch *) val default: t (** Display a nice error message when a switch is not installed. *) val not_installed: t -> 'a opam-full-1.2.2/src/core/opamVersion.mli0000644000175000017500000000350312517374212016657 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** OPAM versions *) include OpamMisc.ABSTRACT (** The current OPAM version *) val current: t (** Extracts the major version *) val major: t -> t (** Major+minor version, strips the patch version *) val nopatch: t -> t (** The current OPAM version, truncated (only MAJOR.MINOR) *) val current_nopatch: t (** The 'git' version of OPAM *) val git: unit -> t option (** Side-effect to set the git version later in the build *) val set_git: string -> unit (** The full version (current + git) *) val full: unit -> t (** Magic string, always of length 8 *) val magic: unit -> string (** Display the version message *) val message: unit -> unit (** Version comparison *) val compare: t -> t -> int opam-full-1.2.2/src/core/opamVersion.ml.in0000644000175000017500000000534512517374212017121 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) type t = string let to_string x = x let of_string x = x let to_json x = `String x let compare v w = (* Ignore -xxx suffixes for version comparisons *) let cut s = match OpamMisc.cut_at s '-' with | Some (s,_) -> s | None -> s in Debian.Version.compare (cut v) (cut w) module O = struct type t = string let to_string = to_string let to_json = to_json let compare = compare end module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) let current_raw = "@PACKAGE_VERSION@" let current = of_string current_raw let major v = try let i = String.index v '.' in of_string (String.sub v 0 i) with Not_found -> v let nopatch v = try let i = String.index v '.' in let i = String.index_from v (i+1) '.' in (String.sub v 0 i) with Not_found -> v let current_nopatch = nopatch current_raw let message () = Printf.printf "\n\ %s version %s\n\ \n\ Copyright (C) 2012 OCamlPro - INRIA, 2013-2014 OCamlPro\n\ \n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" Sys.argv.(0) current_raw; exit 0 let gitversion = ref None let set_git s = gitversion := Some s let git () = match !gitversion with | None -> None | Some v -> Some (of_string v) let full () = let git_version = match git () with | None -> "" | Some v -> Printf.sprintf " (%s)" (to_string v) in Printf.sprintf "%s%s" (to_string current) git_version let magic () = let hash = Hashtbl.hash (full ()) in String.sub (Printf.sprintf "%08X" hash) 0 8 opam-full-1.2.2/src/core/opamSystem.ml0000644000175000017500000006150612517374212016354 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamProcess.Job.Op open OpamCompat exception Process_error of OpamProcess.result exception Internal_error of string exception Command_not_found of string exception File_not_found of string let log fmt = OpamGlobals.log "SYSTEM" fmt let internal_error fmt = Printf.ksprintf (fun str -> log "error: %s" str; raise (Internal_error str) ) fmt let process_error r = if r.OpamProcess.r_signal = Some Sys.sigint then raise Sys.Break else raise (Process_error r) let raise_on_process_error r = if OpamProcess.is_failure r then raise (Process_error r) let command_not_found cmd = raise (Command_not_found cmd) module Sys2 = struct (* same as [Sys.is_directory] except for symlinks, which returns always [false]. *) let is_directory file = try Unix.( (lstat file).st_kind = S_DIR ) with Unix.Unix_error _ as e -> raise (Sys_error (Printexc.to_string e)) end let (/) = Filename.concat (* Separator for the PATH variables *) let path_sep = match OpamGlobals.os () with | OpamGlobals.Win32 -> ';' | OpamGlobals.Cygwin | _ -> ':' let temp_basename prefix = Printf.sprintf "%s-%d-%06x" prefix (Unix.getpid ()) (Random.int 0xFFFFFF) let rec mk_temp_dir () = let s = Filename.get_temp_dir_name () / temp_basename "opam" in if Sys.file_exists s then mk_temp_dir () else s let safe_mkdir dir = try log "mkdir %s" dir; Unix.mkdir dir 0o755 with Unix.Unix_error(Unix.EEXIST,_,_) -> () let mkdir dir = let rec aux dir = if not (Sys.file_exists dir) then begin aux (Filename.dirname dir); safe_mkdir dir; end in aux dir (* XXX: won't work on windows *) let remove_dir dir = log "rmdir %s" dir; if Sys.file_exists dir then ( let err = Sys.command (Printf.sprintf "rm -rf %s" dir) in if err <> 0 then internal_error "Cannot remove %s (error %d)." dir err ) let temp_files = Hashtbl.create 1024 let check_remove_temp_dir = ref true let rec temp_file ?dir prefix = let temp_dir = match dir with | None -> let dir = !OpamGlobals.root_dir in if !check_remove_temp_dir && dir = OpamGlobals.root_dir_tmp then ( OpamMisc.at_exit (fun () -> remove_dir OpamGlobals.root_dir_tmp); check_remove_temp_dir := false); dir / "log" | Some d -> d in mkdir temp_dir; let file = temp_dir / temp_basename prefix in if Hashtbl.mem temp_files file then temp_file ?dir prefix else ( Hashtbl.add temp_files file true; file ) let remove_file file = if try ignore (Unix.lstat file); true with Unix.Unix_error _ -> false then ( try log "rm %s" file; Unix.unlink file with Unix.Unix_error _ as e -> internal_error "Cannot remove %s (%s)." file (Printexc.to_string e) ) let string_of_channel ic = let n = 32768 in let s = Bytes.create n in let b = Buffer.create 1024 in let rec iter ic b s = let nread = try input ic s 0 n with End_of_file -> 0 in if nread > 0 then ( Buffer.add_subbytes b s 0 nread; iter ic b s ) in iter ic b s; Buffer.contents b let read file = let ic = try open_in_bin file with Sys_error _ -> raise (File_not_found file) in let s = string_of_channel ic in close_in ic; s let write file contents = mkdir (Filename.dirname file); let oc = try open_out_bin file with Sys_error _ -> raise (File_not_found file) in output_string oc contents; close_out oc let chdir dir = try Unix.chdir dir with Unix.Unix_error _ -> raise (File_not_found dir) let in_dir dir fn = let reset_cwd = let cwd = try Some (Sys.getcwd ()) with Sys_error _ -> None in fun () -> match cwd with | None -> () | Some cwd -> try chdir cwd with File_not_found _ -> () in chdir dir; try let r = fn () in reset_cwd (); r with e -> reset_cwd (); raise e let list kind dir = try in_dir dir (fun () -> let d = Sys.readdir (Sys.getcwd ()) in let d = Array.to_list d in let l = List.filter kind d in List.map (Filename.concat dir) (List.sort compare l) ) with File_not_found _ -> [] let files_with_links = list (fun f -> try not (Sys.is_directory f) with Sys_error _ -> true) let files_all_not_dir = list (fun f -> try not (Sys2.is_directory f) with Sys_error _ -> true) let directories_strict = list (fun f -> try Sys2.is_directory f with Sys_error _ -> false) let directories_with_links = list (fun f -> try Sys.is_directory f with Sys_error _ -> false) let rec_files dir = let rec aux accu dir = let d = directories_with_links dir in let f = files_with_links dir in List.fold_left aux (f @ accu) d in aux [] dir let files dir = files_with_links dir let rec_dirs dir = let rec aux accu dir = let d = directories_with_links dir in List.fold_left aux (d @ accu) d in aux [] dir let dirs dir = directories_with_links dir let dir_is_empty dir = try in_dir dir (fun () -> Sys.readdir (Sys.getcwd ()) = [||]) with File_not_found _ -> false let with_tmp_dir fn = let dir = mk_temp_dir () in try mkdir dir; let e = fn dir in remove_dir dir; e with e -> remove_dir dir; raise e let with_tmp_dir_job fjob = let dir = mk_temp_dir () in mkdir dir; OpamProcess.Job.finally (fun () -> remove_dir dir) (fjob dir) let remove file = if (try Sys2.is_directory file with Sys_error _ -> false) then remove_dir file else remove_file file let getchdir s = let p = try Sys.getcwd () with Sys_error _ -> if Sys.file_exists !OpamGlobals.root_dir then !OpamGlobals.root_dir else Filename.get_temp_dir_name () in chdir s; p let normalize s = getchdir (getchdir s) let real_path p = if Filename.is_relative p then match (try Some (Sys.is_directory p) with Sys_error _ -> None) with | None -> p | Some true -> normalize p | Some false -> let dir = normalize (Filename.dirname p) in match Filename.basename p with | "." -> dir | base -> dir / base else p type command = string list let default_env = Unix.environment () let reset_env = lazy ( let env = OpamMisc.env () in let env = let path_sep_str = String.make 1 path_sep in List.rev_map (fun (k,v as c) -> match k with | "PATH" -> k, String.concat path_sep_str (OpamMisc.reset_env_value path_sep ~prefix:!OpamGlobals.root_dir v) | _ -> c ) env in let env = List.rev_map (fun (k,v) -> k^"="^v) env in Array.of_list env ) let env_var env var = let len = Array.length env in let prefix = var^"=" in let pfxlen = String.length prefix in let rec aux i = if i >= len then "" else let s = env.(i) in if OpamMisc.starts_with ~prefix s then String.sub s pfxlen (String.length s - pfxlen) else aux (i+1) in aux 0 let command_exists = let is_external_cmd name = Filename.basename name <> name in let check_existence ?dir env name = let cmd, args = "/bin/sh", ["-c"; Printf.sprintf "command -v %s" name] in let r = OpamProcess.run (OpamProcess.command ~env ?dir ~name:(temp_file "command") ~verbose:false cmd args) in OpamProcess.cleanup ~force:true r; if OpamProcess.is_success r then match r.OpamProcess.r_stdout with | cmdname::_ -> (* check that we have permission to execute the command *) if is_external_cmd cmdname then let cmdname = match Filename.is_relative cmdname, dir with | true, Some dir -> Filename.concat dir cmdname | _ -> cmdname in (try let open Unix in let uid = getuid() and groups = Array.to_list(getgroups()) in let s = stat cmdname in let cmd_uid = s.st_uid and cmd_gid = s.st_gid and cmd_perms = s.st_perm in let mask = 0o001 lor (if uid = cmd_uid then 0o100 else 0) lor (if List.mem cmd_gid groups then 0o010 else 0) in (cmd_perms land mask) <> 0 with _ -> false) else true | _ -> false else false in let cached_results = Hashtbl.create 17 in fun ?(env=default_env) ?dir name -> if dir <> None && is_external_cmd name then check_existence env ?dir name (* relative command, no caching *) else let path = env_var env "PATH" in try Hashtbl.find (Hashtbl.find cached_results path) name with Not_found -> let r = check_existence env name in (try Hashtbl.add (Hashtbl.find cached_results path) name r with Not_found -> let phash = Hashtbl.create 17 in Hashtbl.add phash name r; Hashtbl.add cached_results path phash); r let runs = ref [] let print_stats () = match !runs with | [] -> () | l -> OpamGlobals.msg "%d external processes called:\n%s%!" (List.length l) (OpamMisc.itemize ~bullet:" " (String.concat " ") l) let log_file ?dir name = match name with | None -> temp_file "log" | Some n -> let dir = OpamMisc.Option.default (Filename.concat !OpamGlobals.root_dir "log") dir in temp_file ~dir n let make_command ?verbose ?(env=default_env) ?name ?text ?metadata ?allow_stdin ?dir ?(check_existence=true) cmd args = let name = log_file ?dir name in let verbose = OpamMisc.Option.default (!OpamGlobals.verbose_level >= 2) verbose in (* Check that the command doesn't contain whitespaces *) if None <> try Some (String.index cmd ' ') with Not_found -> None then OpamGlobals.warning "Command %S contains 1 space" cmd; if not check_existence || command_exists ~env ?dir cmd then OpamProcess.command ~env ~name ?text ~verbose ?metadata ?allow_stdin ?dir cmd args else command_not_found cmd let run_process ?verbose ?(env=default_env) ~name ?metadata ?allow_stdin command = let chrono = OpamGlobals.timer () in runs := command :: !runs; match command with | [] -> invalid_arg "run_process" | cmd :: args -> (* Check that the command doesn't contain whitespaces *) if None <> try Some (String.index cmd ' ') with Not_found -> None then OpamGlobals.warning "Command %S contains 1 space" cmd; if command_exists ~env cmd then ( let verbose = match verbose with | None -> !OpamGlobals.verbose_level >= 2 | Some b -> b in let r = OpamProcess.run (OpamProcess.command ~env ~name ~verbose ?metadata ?allow_stdin cmd args) in let str = String.concat " " (cmd :: args) in log "[%a] (in %.3fs) %s" (OpamGlobals.slog Filename.basename) name (chrono ()) str; r ) else (* Display a user-friendly message if the command does not exist *) command_not_found cmd let command ?verbose ?env ?name ?metadata ?allow_stdin cmd = let name = log_file name in let r = run_process ?verbose ?env ~name ?metadata ?allow_stdin cmd in OpamProcess.cleanup r; raise_on_process_error r let commands ?verbose ?env ?name ?metadata ?(keep_going=false) commands = let name = log_file name in let run = run_process ?verbose ?env ~name ?metadata in let command r0 c = match r0, keep_going with | (`Error _ | `Exception _), false -> r0 | _ -> let r1 = try let r = run c in if OpamProcess.is_success r then `Successful r else `Error r with Command_not_found _ as e -> `Exception e in match r0 with `Start | `Successful _ -> r1 | _ -> r0 in match List.fold_left command `Start commands with | `Start -> () | `Successful r -> OpamProcess.cleanup r | `Error e -> process_error e | `Exception e -> raise e let read_command_output ?verbose ?env ?metadata ?allow_stdin cmd = let name = log_file None in let r = run_process ?verbose ?env ~name ?metadata ?allow_stdin cmd in OpamProcess.cleanup r; raise_on_process_error r; r.OpamProcess.r_stdout (* Return [None] if the command does not exist *) let read_command_output_opt ?verbose ?env cmd = try Some (read_command_output ?verbose ?env cmd) with Command_not_found _ -> None let verbose_for_base_commands () = !OpamGlobals.verbose_level >= 3 let copy src dst = if (try Sys.is_directory src with Sys_error _ -> raise (File_not_found src)) then internal_error "Cannot copy %s: it is a directory." src; if (try Sys.is_directory dst with Sys_error _ -> false) then internal_error "Cannot copy to %s: it is a directory." dst; if Sys.file_exists dst then remove_file dst; mkdir (Filename.dirname dst); command ~verbose:(verbose_for_base_commands ()) ["cp"; src; dst ] let is_exec file = let stat = Unix.stat file in stat.Unix.st_kind = Unix.S_REG && stat.Unix.st_perm land 0o111 <> 0 let install ?exec src dst = if Sys.is_directory src then internal_error "Cannot install %s: it is a directory." src; if (try Sys.is_directory dst with Sys_error _ -> false) then internal_error "Cannot install to %s: it is a directory." dst; mkdir (Filename.dirname dst); let exec = match exec with | Some e -> e | None -> is_exec src in command ("install" :: "-m" :: (if exec then "0755" else "0644") :: [ src; dst ]) module Tar = struct let extensions = [ [ "tar.gz" ; "tgz" ], 'z' ; [ "tar.bz2" ; "tbz" ], 'j' ; [ "tar.xz" ; "txz" ], 'J' ; [ "tar.lzma" ; "tlz" ], 'Y' ] let guess_type f = let ic = open_in f in let c1 = input_char ic in let c2 = input_char ic in close_in ic; match c1, c2 with | '\031', '\139' -> Some 'z' | 'B' , 'Z' -> Some 'j' | '\xfd', '\x37' -> Some 'J' | '\x5d', '\x00' -> Some 'Y' | _ -> None let match_ext file ext = List.exists (Filename.check_suffix file) ext let is_archive f = List.exists (fun suff -> Filename.check_suffix f suff) (List.concat (List.rev_map fst extensions)) let extract_function file = let command c dir = command [ "tar" ; Printf.sprintf "xf%c" c ; file; "-C" ; dir ] in let ext = List.fold_left (fun acc (ext, c) -> match acc with | Some f -> Some f | None -> if match_ext file ext then Some (command c) else None) None extensions in match ext with | Some f -> Some f | None -> match guess_type file with | None -> None | Some c -> Some (command c) end module Zip = struct let is_archive f = Filename.check_suffix f "zip" let extract_function file = Some (fun dir -> command [ "unzip" ; file; "-d"; dir ]) end let is_tar_archive = Tar.is_archive let extract file dst = let _, extract_function = if Zip.is_archive file then "zip", Zip.extract_function else "tar", Tar.extract_function in with_tmp_dir (fun tmp_dir -> match extract_function file with | None -> mkdir dst; copy file (dst/Filename.basename file) | Some f -> f tmp_dir; if Sys.file_exists dst then internal_error "Extracting the archive will overwrite %s." dst; match directories_strict tmp_dir with | [x] -> mkdir (Filename.dirname dst); command [ "mv"; x; dst] | _ -> internal_error "The archive %S contains multiple root directories." file ) let extract_in file dst = if not (Sys.file_exists dst) then internal_error "%s does not exist." file; match Tar.extract_function file with | None -> internal_error "%s is not a valid tar archive." file | Some f -> f dst let link src dst = if Sys.file_exists src then ( mkdir (Filename.dirname dst); if Sys.file_exists dst then remove_file dst; try log "ln -s %s %s" src dst; Unix.symlink src dst with Unix.Unix_error (Unix.EXDEV, _, _) -> (* Fall back to copy if hard links are not supported *) copy src dst ) else internal_error "link: %s does not exist." src type lock = Unix.file_descr * string let flock ?(read=false) file = let max_tries = if !OpamGlobals.safe_mode then 1 else !OpamGlobals.lock_retries in if not read && !OpamGlobals.safe_mode then OpamGlobals.error_and_exit "Write lock attempt in safe mode"; let open_flags, lock_op = if read then [Unix.O_RDONLY], Unix.F_TRLOCK else [Unix.O_RDWR], Unix.F_TLOCK in let fd = Unix.openfile file (Unix.O_CREAT::open_flags) 0o666 in let rec loop attempt = try Unix.lockf fd lock_op 0 with Unix.Unix_error (Unix.EAGAIN,_,_) -> if max_tries > 0 && attempt > max_tries then OpamGlobals.error_and_exit "Timeout trying to acquire %s lock to %S, \ is another opam process running ?" (if read then "read" else "write") file; log "Failed to %s-lock %S. (attempt %d/%d)" (if read then "read" else "write") file attempt max_tries; Unix.sleep 1; loop (attempt + 1) in log "locking %s" file; loop 1; fd, file let funlock (fd,file) = (try (* Unlink file if write lock can be acquired *) Unix.lockf fd Unix.F_TLOCK 0; Unix.unlink file; with Unix.Unix_error _ -> ()); Unix.close fd; (* implies Unix.lockf fd Unix.F_ULOCK 0 *) log "Lock released on %s" file let ocaml_version = lazy ( match read_command_output_opt ~verbose:false [ "ocamlc" ; "-version" ] with | Some (h::_) -> let version = OpamMisc.strip h in log "ocamlc version: %s" version; Some version | Some [] -> internal_error "`ocamlc -version` is empty." | None -> None ) let exists_alongside_ocamlc name = let path = try OpamMisc.getenv "PATH" with Not_found -> "" in let path = OpamMisc.split path path_sep in let ocamlc_dir = List.fold_left (function | None -> fun d -> if Sys.file_exists (d/"ocamlc") then Some d else None | s -> fun _ -> s) None path in match ocamlc_dir with | Some d -> Sys.file_exists (d / name) | None -> false let ocaml_opt_available = lazy (exists_alongside_ocamlc "ocamlc.opt") let ocaml_native_available = lazy (exists_alongside_ocamlc "ocamlopt") let ocaml_natdynlink_available = lazy ( match read_command_output_opt ~verbose:false [ "ocamlc"; "-where" ] with | Some (h::_) -> let libdir = OpamMisc.strip h in Sys.file_exists (libdir / "dynlink.cmxa") | None | Some [] -> false ) (* Reset the path to get the system compiler *) let system command = lazy ( let env = Lazy.force reset_env in match read_command_output_opt ~verbose:false ~env command with | None -> None | Some (h::_) -> Some (OpamMisc.strip h) | Some ([]) -> internal_error "%S is empty." (String.concat " " command) ) let system_ocamlc_where = system [ "ocamlc"; "-where" ] let system_ocamlc_version = system [ "ocamlc"; "-version" ] let choose_download_tool () = match !OpamGlobals.download_tool with | Some t -> t | None -> if OpamGlobals.os () = OpamGlobals.Darwin && command_exists "wget" then `Wget else if command_exists OpamGlobals.curl_command then `Curl else if command_exists "wget" then `Wget else OpamGlobals.error_and_exit "Could not find a suitable download command. Please make sure you have \ either \"curl\" or \"wget\" installed, or specify a custom command \ through variable OPAMFETCH." let download_command = let retry = string_of_int OpamGlobals.download_retry in let wget ~compress:_ ?checksum:_ dir src = let wget_args = [ "--content-disposition"; "--no-check-certificate"; "-t"; retry; src ] in make_command ~dir "wget" wget_args @@> fun r -> raise_on_process_error r; Done () in let curl command ~compress ?checksum:_ dir src = let curl_args = [ "--write-out"; "%{http_code}\\n"; "--insecure"; "--retry"; retry; "--retry-delay"; "2"; ] @ (if compress then ["--compressed"] else []) @ [ "-OL"; src ] in make_command ~dir command curl_args @@> fun r -> raise_on_process_error r; match r.OpamProcess.r_stdout with | [] -> internal_error "curl: empty response while downloading %s" src | l -> let code = List.hd (List.rev l) in try if int_of_string code >= 400 then raise Exit else Done () with e -> OpamMisc.fatal e; internal_error "curl: code %s while downloading %s" code src in let custom dl_cmd ~compress ?checksum dir src = let dst = Filename.basename src in match dl_cmd ~url:src ~out:dst ~retry:OpamGlobals.download_retry ?checksum ~compress with | cmd::args -> make_command ~dir cmd args @@> fun r -> raise_on_process_error r; Done () | [] -> internal_error "Empty custom download command" in lazy ( match choose_download_tool () with | `Wget -> wget | `Curl -> curl OpamGlobals.curl_command | `Custom cust -> custom cust ) let really_download ~overwrite ?(compress=false) ?checksum ~src ~dst = let download = (Lazy.force download_command) in let aux dir = download ~compress ?checksum dir src @@+ fun () -> match list (fun _ -> true) dir with ( [] | _::_::_ ) -> internal_error "Too many downloaded files." | [filename] -> if Sys.file_exists dst then if overwrite then remove dst else internal_error "The downloaded file will overwrite %s." dst; OpamProcess.command ~dir ~verbose:(verbose_for_base_commands ()) "mv" [filename; dst ] @@> fun r -> raise_on_process_error r; Done dst in OpamProcess.Job.catch (function | Internal_error s as e -> OpamGlobals.error "%s" s; raise e | e -> OpamMisc.fatal e; log "Could not download file at %s." src; raise e) (with_tmp_dir_job aux) let download ~overwrite ?compress ?checksum ~filename:src ~dst:dst = if dst = src then Done dst else if Sys.file_exists src then ( if Sys.file_exists dst then if overwrite then remove dst else internal_error "The downloaded file will overwrite %s." dst; OpamProcess.command ~verbose:(verbose_for_base_commands ()) "cp" [src; dst] @@> fun r -> raise_on_process_error r; Done dst ) else really_download ~overwrite ?compress ?checksum ~src ~dst let patch p = let max_trying = 5 in if not (Sys.file_exists p) then (OpamGlobals.error "Patch file %S not found." p; raise Not_found); let patch ~dryrun n = let opts = if dryrun then let open OpamGlobals in match OpamGlobals.os () with | FreeBSD | OpenBSD | NetBSD | DragonFly -> [ "-t"; "-C" ] | Unix | Linux | Darwin -> [ "--dry-run" ] | Win32 | Cygwin (* this is probably broken *) | Other _ -> [ "--dry-run" ] else [] in let verbose = if dryrun then Some false else None in command ?verbose ("patch" :: ("-p" ^ string_of_int n) :: "-i" :: p :: opts) in let rec aux n = if n = max_trying then internal_error "Patch %s does not apply." p else if None = try Some (patch ~dryrun:true n) with e -> OpamMisc.fatal e; None then aux (succ n) else patch ~dryrun:false n in aux 0 let () = let with_opam_info m = let git_version = match OpamVersion.git () with | None -> "" | Some v -> Printf.sprintf " (%s)" (OpamVersion.to_string v) in let opam_version = Printf.sprintf "%s%s" (OpamVersion.to_string OpamVersion.current) git_version in let os = OpamGlobals.os_string () in Printf.sprintf "# %-15s %s\n\ # %-15s %s\n\ %s" "opam-version" opam_version "os" os m in Printexc.register_printer (function | Process_error r -> Some (OpamProcess.string_of_result r) | Internal_error m -> Some (with_opam_info m) | Command_not_found c -> Some (Printf.sprintf "%S: command not found." c) | Sys.Break -> Some "User interruption" | Unix.Unix_error (e, fn, msg) -> let msg = if msg = "" then "" else " on " ^ msg in let error = Printf.sprintf "%s: %S failed%s: %s" Sys.argv.(0) fn msg (Unix.error_message e) in Some (with_opam_info error) | _ -> None ) opam-full-1.2.2/src/core/opamActionGraph.mli0000644000175000017500000000464412517374212017440 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes module type ACTION = sig type package module Pkg: GenericPackage with type t = package include OpamParallel.VERTEX with type t = package action val to_aligned_strings: t list -> string list end module MakeAction (P: GenericPackage) : ACTION with type package = P.t and type t = P.t OpamTypes.action module type SIG = sig type package include OpamParallel.GRAPH with type V.t = package OpamTypes.action (** Reduces a graph of atomic actions (only removals and installs) by turning removal+install to reinstalls or up/down-grades, best for display. Dependency ordering won't be as accurate though, as there is no proper ordering of (reinstall a, reinstall b) if b depends on a. The resulting graph contains at most one action per package name. There is no guarantee however that the resulting graph is acyclic. *) val reduce: t -> t end module Make (A: ACTION) : SIG with type package = A.package (** Some messages that may be used for displaying actions. Single utf8 chars if the corresponding option is set, otherwise words. *) val action_strings: ?utf8:bool -> [ `inst | `rm | `up | `down | `reinst ] -> string (** Colorise string according to the action *) val action_color: [ `inst | `rm | `up | `down | `reinst ] -> string -> string opam-full-1.2.2/src/core/opamTypesBase.ml0000644000175000017500000002134012517374212016757 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes include OpamCompat exception Lexer_error of string let download_map fn = function | Up_to_date f -> Up_to_date (fn f) | Result f -> Result (fn f) | Not_available d -> Not_available d let download_dir = download_map (fun d -> D d) let download_file = download_map (fun f -> F f) let string_of_download = function | Up_to_date _ -> "already up-to-date" | Result _ -> "synchronized" | Not_available _ -> OpamGlobals.colorise `red "unavailable" let string_of_generic_file = function | D d -> OpamFilename.Dir.to_string d | F f -> OpamFilename.to_string f let string_of_address = function | url, None -> url | url, Some c -> Printf.sprintf "%s#%s" url c let address_of_string str = match OpamMisc.cut_at str '#' with | None -> OpamSystem.real_path str, None | Some (a,c) -> OpamSystem.real_path a, Some c let guess_version_control dir = let open OpamFilename in let open OP in if exists_dir (dir / ".git") then Some`git else if exists_dir (dir / ".hg") then Some `hg else if exists_dir (dir / "_darcs") then Some `darcs else None let parse_url (s,c) = let url_kind_of_string = function | "http" | "https" | "ftp" -> `http | "file" -> `local | "git" -> `git | "darcs" -> `darcs | "hg" -> `hg | "rsync" | "ssh" | "scp" | "sftp" -> `local | p -> raise (Invalid_argument (Printf.sprintf "Unsupported protocol %s" p)) in let suffix = try let n = String.rindex s '.' in String.sub s (n+1) (String.length s-n-1) with Not_found -> "" in match suffix with | "git" -> (s,c), `git | "hg" -> (s,c), `hg | _ -> match Re_str.bounded_split (Re_str.regexp_string "://") s 2 with | ["file"|"rsync"|"ssh"|"scp"|"sftp"; address] -> (* strip the leading xx:// *) (address,c), `local | [proto; address] -> (* keep the leading xx:// *) (match OpamMisc.cut_at proto '+' with | Some (proto1,proto2) -> (proto2^"://"^address, c), url_kind_of_string proto1 | None -> (s,c), url_kind_of_string proto) | [address] -> (address,c), `local | _ -> raise (Invalid_argument (Printf.sprintf "Bad url format %S" s)) let string_of_repository_kind = function | `http -> "http" | `local -> "local" | `git -> "git" | `darcs -> "darcs" | `hg -> "hg" let repository_kind_of_string = function | "wget" | "curl" | "http" -> `http | "rsync" | "local" -> `local | "git" -> `git | "darcs" -> `darcs | "hg" -> `hg | s -> OpamGlobals.error_and_exit "%s is not a valid repository kind." s let string_of_shell = function | `fish -> "fish" | `csh -> "csh" | `zsh -> "zsh" | `sh -> "sh" | `bash -> "bash" let pos_null = OpamFilename.of_string "",-1,-1 let string_of_pos (file,line,col) = OpamFilename.prettify file ^ if line >= 0 then ":" ^ string_of_int line ^ if col >= 0 then ":" ^ string_of_int col else "" else "" (* Command line arguments *) let string_of_upload u = Printf.sprintf "opam=%s descr=%s archive=%s" (OpamFilename.to_string u.upl_opam) (OpamFilename.to_string u.upl_descr) (OpamFilename.to_string u.upl_archive) let repository_kind_of_pin_kind = function | `version -> None | (`http|`git|`darcs|`hg|`local as k) -> Some k let pin_of_url (url,kind) = match kind with | `http -> Http url | `git -> Git url | `darcs -> Darcs url | `hg -> Hg url | `local | `version -> failwith "Not a recognised version-control URL" let pin_option_of_string ?kind ?(guess=false) s = match kind with | Some `version -> Version (OpamPackage.Version.of_string s) | None | Some (`http|`git|`hg|`darcs|`local) -> if kind = None && not (String.contains s (Filename.dir_sep.[0])) && String.length s > 0 && '0' <= s.[0] && s.[0] <= '9' then Version (OpamPackage.Version.of_string s) else let s, k = parse_url (address_of_string s) in match kind, k with | Some `version, _ | None, `version -> assert false | Some `http, _ | None, `http -> Http s | Some `git, _ | None, `git -> Git s | Some `hg, _ | None, `hg -> Hg s | Some `darcs, _ | None, `darcs -> Darcs s | Some `local, _ -> Local (OpamFilename.Dir.of_string (fst s)) | None, `local -> let dir = OpamFilename.Dir.of_string (fst s) in if guess then match guess_version_control dir with | Some vc -> pin_of_url (s, vc) | None -> Local dir else Local dir let string_of_pin_kind = function | `version -> "version" | `git -> "git" | `darcs -> "darcs" | `hg -> "hg" | `http -> "http" | `local -> "path" let pin_kind_of_string = function | "version" -> `version | "http" -> `http | "git" -> `git | "darcs" -> `darcs | "hg" -> `hg | "rsync" | "local" | "path" -> `local | s -> OpamGlobals.error_and_exit "%s is not a valid kind of pinning." s let string_of_pin_option = function | Version v -> OpamPackage.Version.to_string v | Http p | Git p | Darcs p | Hg p -> string_of_address p | Local p -> OpamFilename.Dir.to_string p let kind_of_pin_option = function | Version _ -> `version | Http _ -> `http | Git _ -> `git | Darcs _ -> `darcs | Hg _ -> `hg | Local _ -> `local let option fn = function | None -> "" | Some k -> fn k let string_of_relop = OpamFormula.string_of_relop let relop_of_string = OpamFormula.relop_of_string let string_of_logop = function | `And -> "&" | `Or -> "|" let logop_of_string = function | "&" -> `And | "|" -> `Or | _ -> raise (Invalid_argument "logop_of_string") let string_of_pfxop = function | `Not -> "!" let pfxop_of_string = function | "!" -> `Not | _ -> raise (Invalid_argument "pfxop_of_string") let filter_ident_of_string s = match OpamMisc.rcut_at s ':' with | None -> [], OpamVariable.of_string s, None | Some (p,last) -> let get_names s = List.map (fun n -> try OpamPackage.Name.of_string n with Failure _ -> failwith ("Invalid package name "^n)) (OpamMisc.split s '+') in match OpamMisc.rcut_at p '?' with | None -> get_names p, OpamVariable.of_string last, None | Some (p,val_if_true) -> let converter = Some (val_if_true, last) in match OpamMisc.rcut_at p ':' with | None -> [], OpamVariable.of_string p, converter | Some (packages,var) -> get_names packages, OpamVariable.of_string var, converter let filter_deps ?(build=true) ?(test=build && !OpamGlobals.build_test) ?(doc=build && !OpamGlobals.build_doc) = let filter = List.for_all (function | Depflag_Build -> build | Depflag_Test -> test | Depflag_Doc -> doc | Depflag_Dev -> true (* unimplemented *) | Depflag_Unknown _ -> true (* ignored *)) in OpamFormula.formula_of_extended ~filter let action_contents = function | To_change (_, p) | To_recompile p | To_delete p -> p let full_action_contents = function | To_change (Some p1, p2) -> [p1; p2] | To_change (None, p) | To_recompile p | To_delete p -> [p] let string_of_cause to_string = let list_to_string l = match List.map to_string l with | a::b::c::_::_::_ -> Printf.sprintf "%s, %s, %s, etc." a b c | l -> String.concat ", " l in function | Upstream_changes -> "upstream changes" | Use pkgs -> Printf.sprintf "uses %s" (list_to_string pkgs) | Required_by pkgs -> Printf.sprintf "required by %s" (list_to_string pkgs) | Conflicts_with pkgs -> Printf.sprintf "conflicts with %s" (list_to_string pkgs) | Requested -> "" | Unknown -> "" let map_success f = function | Success x -> Success (f x) | Conflicts c -> Conflicts c opam-full-1.2.2/src/core/opamRepository.mli0000644000175000017500000001345112517374212017414 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Mangagement of OPAM repositories. *) open OpamTypes include OpamMisc.ABSTRACT with type t := repository exception Unknown_backend (** Default repository address*) val default_address: address (** Pretty-print *) val to_string: repository -> string (** Compare repositories *) val compare: repository -> repository -> int (** Default repository *) val default: unit -> repository (** Create a local repository on a given path *) val local: dirname -> repository (** Get the list of packages *) val packages: repository -> package_set (** Get the list of packages (and their eventual prefixes) *) val packages_with_prefixes: repository -> string option package_map (** Get the list of all compiler *) val compilers: repository -> compiler_set (** Get the list of compilers (and their eventual prefixes) *) val compilers_with_prefixes: repository -> string option compiler_map (** {2 Repository Collection Operations } *) (** Sort a collection of repositories by priority *) val sort: repository repository_name_map -> repository list (** Generate a package index from a collection of repositories *) val package_index: repository repository_name_map -> (repository_name * string option) package_map (** Generate a compiler index from a collection of repositories *) val compiler_index: repository repository_name_map -> (repository_name * string option) compiler_map (** {2 State} *) (** Get the package archive checksum off an url file *) val url_checksum: OpamFilename.t -> checksums (** Get all the package files *) val package_files: repository -> string option -> package -> archive:bool -> filename list (** Compute a package state (ie. a list of checksums). If [`partial archive], only the checksum of the archive within the url file (instead of the file itself), of the files/ subdirectory, and of the archive if set are returned. *) val package_state: repository -> string option -> package -> [`all|`partial of bool] -> checksums (** Get all the compiler files *) val compiler_files: repository -> string option -> compiler -> filename list (** Compute a compiler state (ie. a list of checksums). *) val compiler_state: repository -> string option -> compiler -> checksums (** {2 Repository backends} *) (** Initialize {i $opam/repo/$repo} *) val init: repository -> unit OpamProcess.job (** Update {i $opam/repo/$repo}. *) val update: repository -> unit OpamProcess.job (** Error and exit on incompatible version *) val check_version: repository -> unit OpamProcess.job (** Backend signature *) module type BACKEND = sig (** [pull_url package local_dir checksum remote_url] pull the contents of [remote_url] into [local_dir]. Can return either a file or a directory. [checksum] is the optional expected checksum. *) val pull_url: package -> dirname -> string option -> address -> generic_file download OpamProcess.job (** [pull_repo] pull the contents of a repository. *) val pull_repo: repository -> unit OpamProcess.job (** [pull_archive repo archive] pull [archive] in the given repository. *) val pull_archive: repository -> filename -> filename download OpamProcess.job (** Return the (optional) revision of a given repository. Only useful for VCS backends. *) val revision: repository -> version option OpamProcess.job end (** Download an url. Several mirrors can be provided, in which case they will be tried in order in case of an error. *) val pull_url: repository_kind -> package -> dirname -> string option -> address list -> generic_file download OpamProcess.job (** Pull and fix the resulting digest *) val pull_url_and_fix_digest: repository_kind -> package -> dirname -> string -> filename -> address list -> generic_file download OpamProcess.job (** [check_digest file expected] check that the [file] digest is the one [expected]. *) val check_digest: filename -> string option -> bool (** Pull an archive in a repository *) val pull_archive: repository -> package -> filename download OpamProcess.job (** Get the optional revision associated to a backend. *) val revision: repository -> version option OpamProcess.job (** [make_archive ?gener_digest repo prefix package] builds the archive for the given [package]. By default, the digest that appears in {i $NAME.$VERSION/url} is not modified, unless [gener_digest] is set. *) val make_archive: ?gener_digest:bool -> repository -> string option -> package -> unit OpamProcess.job (** Register a repository backend *) val register_backend: repository_kind -> (module BACKEND) -> unit (** Find a backend *) val find_backend: repository_kind -> (module BACKEND) (** {2 Misc} *) (** Parallel iterations *) module Parallel: OpamParallel.SIG with type G.V.t = repository opam-full-1.2.2/src/core/opamFile.mli0000644000175000017500000003503312517374212016114 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes (** Functions to read and write OPAM configuration files in a typed way *) (** All Configuration files satisfies this signature *) module type IO_FILE = sig (** File contents *) type t (** Empty file *) val empty: t (** Write some contents to a file *) val write: filename -> t -> unit (** Read file contents. Raise an error if the file does not exist. *) val read: filename -> t (** Read file contents. Return [empty] if the file does not exist. *) val safe_read: filename -> t (** Read from channel. *) val read_from_channel: in_channel -> t (** Write to channel. *) val write_to_channel: out_channel -> t -> unit end (** Lines of space-separated words. *) module Lines: IO_FILE with type t = string list list (** Configuration file: [$opam/config] *) module Config: sig include IO_FILE (** Creation *) val create: switch -> repository_name list -> ?criteria:(OpamTypes.solver_criteria * string) list -> ?solver:(arg list) -> int -> ?download_tool:(arg list) -> int -> t (** OCaml switch updates *) val with_switch : t -> switch -> t (** Repository updates *) val with_repositories: t -> repository_name list -> t (** Update opam-version to the current one *) val with_current_opam_version: t -> t val with_criteria: t -> (solver_criteria * string) list -> t val with_solver: t -> arg list option -> t (** Return the OPAM version *) val opam_version: t -> opam_version (** Return the list of repository *) val repositories: t -> repository_name list (** Return the OCaml switch *) val switch: t -> switch (** Return the number of jobs *) val jobs: t -> int val dl_tool: t -> arg list option (** Return the number of download jobs *) val dl_jobs: t -> int val criteria: t -> (solver_criteria * string) list val solver: t -> arg list option end (** OPAM files *) module OPAM: sig include IO_FILE val empty: t (** Create an opam file *) val create: package -> t (** Create an OPAM package template filled with common options *) val template: package -> t (** Runs several sanity checks on the opam file; returns a list of warnings. [`Error] level should be considered unfit for publication, while [`Warning] are advisory but may be accepted. The int is an identifier for this specific warning/error. *) val validate: t -> (int * [`Warning|`Error] * string) list (** Same as [validate], but operates on a file, which allows catching parse errors too. You can specify an expected name and version *) val validate_file: filename -> (int * [`Warning|`Error] * string) list * t option (** Utility function to print validation results *) val warns_to_string: (int * [`Warning|`Error] * string) list -> string (** Returns true if the given OPAM file contains 'name' or 'version' fields *) val is_explicit: filename -> bool (** Get OPAM version. *) val opam_version: t -> opam_version (** Package name *) val name: t -> name val name_opt: t -> name option (** Package version *) val version: t -> version val version_opt: t -> version option (** Compiler constraint *) val ocaml_version: t -> compiler_constraint option (** OS constraint *) val os: t -> (bool * string) generic_formula (** Availability formula (OS + compiler constraints) *) val available: t -> filter (** Package maintainer(s) *) val maintainer: t -> string list (** File substitutions *) val substs: t -> basename list (** List of environment variables to set-up for the build *) val build_env: t -> (string * string * string) list (** List of command to run for building the package *) val build: t -> command list (** List of command to run for installing the package *) val install: t -> command list (** List of command to run for removing the package *) val remove: t -> command list (** Package dependencies *) val depends: t -> ext_formula (** Optional dependencies *) val depopts: t -> ext_formula (** External dependencies *) val depexts: t -> tags option val with_messages: t -> (string * filter option) list -> t val with_post_messages: t -> (string * filter option) list -> t (** Package conflicts *) val conflicts: t -> formula (** Contents of the 'features' field *) val features: t -> (OpamVariable.t * string * filter) list (** List of exported libraries *) val libraries: t -> (string * filter option) list (** List of exported syntax extensions *) val syntax: t -> (string * filter option) list (** Patches *) val patches: t -> (basename * filter option) list (** Homepage(s) *) val homepage: t -> string list (** Author(s) *) val author: t -> string list (** License(s) *) val license: t -> string list (** API documentation *) val doc: t -> string list (** Classification tags *) val tags: t -> string list (** Commands to build and run the tests *) val build_test: t -> command list (** Commands to build the documentation *) val build_doc: t -> command list (** Messages to display before taking action *) val messages: t -> (string * filter option) list (** Messages to display at end of install *) val post_messages: t -> (string * filter option) list (** Where to post bug reports. *) val bug_reports: t -> string list (** The package flags that are present for this package. *) val flags: t -> package_flag list (** Check the package for the given flag. Allows flags specified through tags for compatibility *) val has_flag: package_flag -> t -> bool (** Sets the opam version *) val with_opam_version: t -> opam_version -> t (** The package source repository address *) val dev_repo: t -> pin_option option (** construct as [name] *) val with_name: t -> name -> t val with_name_opt: t -> name option -> t (** construct as [version] *) val with_version: t -> version -> t val with_version_opt: t -> version option -> t (** Construct as [depends] *) val with_depends : t -> ext_formula -> t (** Construct as [depopts] *) val with_depopts : t -> ext_formula -> t val with_conflicts : t -> formula -> t val with_features : t -> (OpamVariable.t * string * filter) list -> t (** Construct as [build] *) val with_build: t -> command list -> t val with_install: t -> command list -> t (** Construct as [remove] *) val with_remove : t -> command list -> t (** Construct as [libraries] *) val with_libraries : t -> (string * filter option) list -> t (** Replace the [syntax] field of the given OPAM file. *) val with_syntax: t -> (string * filter option) list -> t (** Construct as [substs] *) val with_substs : t -> basename list -> t (** Construct as [compiler_version] *) val with_ocaml_version: t -> compiler_constraint option -> t val with_os: t -> (bool * string) generic_formula -> t val with_available : t -> filter -> t (** Construct as [maintainer] *) val with_maintainer: t -> string list -> t (** Construct as [patches] *) val with_patches: t -> (basename * filter option) list -> t (** Construct using [bug_reports] *) val with_bug_reports: t -> string list -> t (** Construct using [depexts] *) val with_depexts: t -> tags option -> t val with_flags: t -> package_flag list -> t val with_dev_repo: t -> pin_option option -> t (** Convert to OPAM 1.0 *) val to_1_0: file -> file end (** Package descriptions: [$opam/descr/] *) module Descr: sig include IO_FILE (** Create an abstract description file from a string *) val of_string: string -> t (** Return the first line *) val synopsis: t -> string (** Return the body *) val body: t -> string (** Return the full description *) val full: t -> string end (** Compiler aliases: [$opam/aliases] *) module Aliases: IO_FILE with type t = compiler switch_map (** Import/export file. This difference with [installed] is that we are explicit about root packages. *) module Export: IO_FILE with type t = package_set * package_set * pin_option OpamPackage.Name.Map.t (** List of installed packages: [$opam/$oversion/installed] *) module Installed: IO_FILE with type t = package_set (** List of packages explicitly installed by the user: [$opam/$switch/installed.user] *) module Installed_roots: IO_FILE with type t = package_set (** List of packages to reinstall: [$opam/$oversion/reinstall] *) module Reinstall: IO_FILE with type t = package_set (** Compiler version [$opam/compilers/] *) module Comp: sig include IO_FILE (** Create a pre-installed compiler description file *) val create_preinstalled: compiler -> compiler_version -> name list -> (string * string * string) list -> t (** Is it a pre-installed compiler description file *) val preinstalled: t -> bool (** Get OPAM version *) val opam_version: t -> opam_version (** Return the compiler name *) val name: t -> compiler (** Return the compiler version *) val version: t -> compiler_version (** Return the url of the compiler *) val src: t -> address option (** Return the url kind *) val kind: t -> repository_kind (** Return the list of patches to apply *) val patches: t -> filename list (** Options to give to the "./configure" command *) val configure: t -> string list (** Options to give to the "make" command *) val make: t -> string list (** Options to give to build the package. If this one is provided, nothing should be specified for [configure] and [make]. *) val build: t -> command list (** Packages to install immediately after the creation of OCaml *) val packages: t -> formula (** Environment variable to set-up before running commands in the subtree *) val env: t -> (string * string * string) list val with_src: t -> address option -> t val with_patches: t -> filename list -> t val with_configure: t -> string list -> t val with_make: t -> string list -> t val with_build: t -> command list -> t val with_packages: t -> formula -> t (** Convert to OPAM 1.0 *) val to_1_0: file -> file end (** {2 Configuration files} *) (** .install files *) module Dot_install: sig include IO_FILE (** List of files to install in $bin/ *) val bin: t -> (basename optional * basename option) list (** List of files to install in $sbin/ *) val sbin: t -> (basename optional * basename option) list (** List of files to install in $lib/ *) val lib: t -> (basename optional * basename option) list (** List of toplevel files *) val toplevel: t -> (basename optional * basename option) list (** C bindings *) val stublibs: t -> (basename optional * basename option) list (** List of architecture-independent files *) val share: t -> (basename optional * basename option) list (** List of files under the more general share prefix *) val share_root: t -> (basename optional * basename option) list (** List of etc files *) val etc: t -> (basename optional * basename option) list (** List of doc files *) val doc: t -> (basename optional * basename option) list (** Man pages *) val man: t -> (basename optional * basename option) list (** Executable files under lib/ *) val libexec: t -> (basename optional * basename option) list (** List of other files to install *) val misc: t -> (basename optional * filename) list end (** .config files *) module Dot_config: sig include IO_FILE (** Create a new .config file (containing only variables) *) val create: (variable * variable_contents) list -> t (** Top-level variables *) val variable: t -> variable -> variable_contents option (** The list of top-level variables *) val variables: t -> variable list end (** {2 Repository files} *) (** Association between package names and repositories *) module Package_index: IO_FILE with type t = (repository_name * string option) package_map (** Association between compiler names and repositories *) module Compiler_index: IO_FILE with type t = (repository_name * string option) compiler_map (** Repository config: [$opam/repo/$repo/config] *) module Repo_config: IO_FILE with type t = repository (** Pinned package files *) module Pinned: IO_FILE with type t = pin_option name_map (** Repository metadata *) module Repo: sig include IO_FILE val create: ?browse:string -> ?upstream:string -> ?opam_version:string -> ?redirect:(string * filter option) list -> unit -> t (** The minimum OPAM version required for this repository *) val opam_version : t -> OpamVersion.t (** Base URL for browsing packages on the WWW *) val browse: t -> string option (** Base URL for browsing OPAM repository source on the WWW *) val upstream: t -> string option (** Redirections. *) val redirect: t -> (string * filter option) list end (** {2 Substitution files} *) (** {2 Urls for OPAM repositories} *) module URL: sig include IO_FILE val create: repository_kind -> ?mirrors:address list -> address -> t (** URL address *) val url: t -> address val mirrors: t -> address list (** Backend kind (could be curl/rsync/git/darcs/hg at the moment) *) val kind: t -> repository_kind (** Archive checksum *) val checksum: t -> string option (** Constructor *) val with_checksum: t -> string -> t end (** {2 urls.txt file *} *) module File_attributes: IO_FILE with type t = file_attribute_set (** List of filenames *) module Filenames: IO_FILE with type t = filename_set (** Prefix of package directories *) module Prefix: IO_FILE with type t = string name_map (** Display statistics about file access. *) val print_stats: unit -> unit opam-full-1.2.2/src/core/opamPackage.ml0000644000175000017500000001647712517374212016432 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamMisc.OP let log fmt = OpamGlobals.log "PACKAGE" fmt let slog = OpamGlobals.slog module Version = struct type version = string type t = version let to_string x = x let of_string x = x let compare = Debian.Version.compare let to_json x = `String (to_string x) module O = struct type t = version let to_string = to_string let compare = compare let to_json = to_json end module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) end module Name = struct type t = string let to_string x = x let of_string x = String.iter (function | '"'..'~' as c when not (String.contains "!./<=>\\" c) -> () | c -> failwith (Printf.sprintf "Invalid character %c in package name %S" c x)) x; x let global_config = OpamGlobals.global_config let compare n1 n2 = match compare (String.lowercase n1) (String.lowercase n2) with | 0 -> compare n1 n2 | i -> i let to_json x = `String x module O = struct type t = string let to_string = to_string let compare = compare let to_json = to_json end module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) end type t = { name : Name.t; version: Version.t; } let create name version = { name; version } let name_to_string t = Name.to_string t.name let version_to_string t = Version.to_string t.version let name t = t.name let version t = t.version let sep = '.' let of_string_opt s = if OpamMisc.contains s ' ' || OpamMisc.contains s '\n' then None else match OpamMisc.cut_at s sep with | None -> None | Some (n, v) -> try Some { name = Name.of_string n; version = Version.of_string v } with Failure _ -> None let of_string s = match of_string_opt s with | Some x -> x | None -> OpamGlobals.error_and_exit "%s is not a valid versioned package name" s let to_string t = match Version.to_string t.version with | "" -> Name.to_string t.name | _ -> Printf.sprintf "%s%c%s" (Name.to_string t.name) sep (Version.to_string t.version) let compare nv1 nv2 = match Name.compare nv1.name nv2.name with | 0 -> Version.compare nv1.version nv2.version | i -> i let hash nv = Hashtbl.hash nv let equal nv1 nv2 = compare nv1 nv2 = 0 let to_json nv = `O [ ("name", Name.to_json (name nv)); ("version", Version.to_json (version nv)); ] module O = struct type tmp = t type t = tmp let compare = compare let hash = hash let equal = equal let to_string = to_string let to_json = to_json end module Set = OpamMisc.Set.Make (O) module Map = OpamMisc.Map.Make (O) let to_map nv = Set.fold (fun nv map -> let name = name nv in let version = version nv in try Name.Map.add name (Version.Set.add version (Name.Map.find name map)) map with Not_found -> Name.Map.add name (Version.Set.singleton version) map ) nv Name.Map.empty let keys map = Map.fold (fun nv _ set -> Set.add nv set) map Set.empty (* $DIR/$NAME.$VERSION/ *) let of_dirname f = f |> OpamFilename.basename_dir |> OpamFilename.Base.to_string |> of_string_opt (* $DIR/$NAME.$VERSION/opam *) let of_filename f = if OpamFilename.basename f = OpamFilename.Base.of_string "opam" then of_dirname (OpamFilename.dirname f) else None (* $NAME.$VERSION+opam.tar.gz *) let of_archive f = let base = OpamFilename.basename f in match OpamMisc.cut_at (OpamFilename.Base.to_string base) '+' with | None -> None | Some (s,_) -> of_string_opt s let list dir = log "list %a" (slog OpamFilename.Dir.to_string) dir; if OpamFilename.exists_dir dir then ( let files = OpamFilename.rec_files dir in List.fold_left (fun set f -> match of_filename f with | None -> set | Some p -> if not (Set.mem p set) then Set.add p set else let suffix = Filename.concat (to_string p) "opam" in let files = List.filter (OpamFilename.ends_with suffix) files in OpamGlobals.error_and_exit "Multiple definition of package %s in %s:\n%s" (to_string p) (OpamFilename.Dir.to_string dir) (OpamMisc.itemize ~bullet:"" OpamFilename.to_string files); ) Set.empty files ) else Set.empty let prefixes dir = log "prefixes %a" (slog OpamFilename.Dir.to_string) dir; if OpamFilename.exists_dir dir then ( let files = OpamFilename.rec_files dir in List.fold_left (fun map f -> match of_filename f with | None -> map | Some p -> let dirname = OpamFilename.dirname_dir (OpamFilename.dirname f) in let suffix = OpamFilename.Dir.to_string dirname in let prefix = match OpamMisc.remove_prefix ~prefix:(OpamFilename.Dir.to_string dir) suffix with | "" -> None | p -> (* drop the leading '/' from the prefix *) Some String.(sub p 1 (length p - 1)) in Map.add p prefix map ) Map.empty files ) else Map.empty let versions_of_packages nvset = Set.fold (fun nv vset -> Version.Set.add (version nv) vset) nvset Version.Set.empty let has_name nvset n = Set.exists (fun nv -> name nv = n) nvset let names_of_packages nvset = Set.fold (fun nv vset -> Name.Set.add (name nv) vset) nvset Name.Set.empty let packages_of_name nvset n = Set.fold (fun nv set -> if name nv = n then Set.add nv set else set) nvset Set.empty let packages_of_names nvset nameset = Name.Set.fold (fun name acc -> Set.union acc (packages_of_name nvset name)) nameset Set.empty let versions_of_name packages n = versions_of_packages (Set.filter (fun nv -> name nv = n) packages) let max_version set name = let versions = versions_of_name set name in let version = Version.Set.max_elt versions in create name version let unknown name version = match version with | None -> OpamGlobals.error_and_exit "%s is not a valid package." (Name.to_string name) | Some v -> OpamGlobals.error_and_exit "The package %s has no version %s." (Name.to_string name) (Version.to_string v) module Graph = (OpamParallel.MakeGraph (O) : OpamParallel.GRAPH with type V.t = t) opam-full-1.2.2/src/core/opamParallel.ml0000644000175000017500000002775112517374212016630 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamMisc.OP open OpamProcess.Job.Op let log fmt = OpamGlobals.log "PARALLEL" fmt let slog = OpamGlobals.slog exception Aborted module type VERTEX = sig include OpamMisc.OrderedType include Graph.Sig.COMPARABLE with type t := t end module type G = sig include Graph.Sig.I module Vertex: VERTEX with type t = V.t module Topological: sig val fold: (V.t -> 'a -> 'a) -> t -> 'a -> 'a end val has_cycle: t -> bool val scc_list: t -> V.t list list end module type SIG = sig module G : G val iter: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?mutually_exclusive:(G.V.t list list) -> G.t -> unit val map: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?mutually_exclusive:(G.V.t list list) -> G.t -> (G.V.t * 'a) list exception Errors of G.V.t list * (G.V.t * exn) list * G.V.t list exception Cyclic of G.V.t list list end module Make (G : G) = struct module G = G module V = G.Vertex module M = OpamMisc.Map.Make (V) module S = OpamMisc.Set.Make (V) let map_keys m = M.fold (fun k _ s -> S.add k s) m S.empty exception Errors of G.V.t list * (G.V.t * exn) list * G.V.t list exception Cyclic of V.t list list open S.Op (* Returns a map (node -> return value) *) let aux_map ~jobs ~command ?(dry_run=false) ?(mutually_exclusive=[]) g = log "Iterate over %a task(s) with %d process(es)" (slog @@ G.nb_vertex @> string_of_int) g jobs; let mutually_exclusive = List.map S.of_list mutually_exclusive in if G.has_cycle g then ( let sccs = G.scc_list g in let sccs = List.filter (function _::_::_ -> true | _ -> false) sccs in raise (Cyclic sccs) ); let njobs = G.nb_vertex g in let print_status (finished: int) (running: (OpamProcess.t * 'a * string option) M.t) = let texts = OpamMisc.filter_map (fun (_,_,t) -> t) (M.values running) in let rec limit_width acc rem_cols = function | [] -> List.rev acc | t::ts -> let len = OpamMisc.visual_length t in if ts = [] && len < rem_cols then List.rev (t::acc) else if len > rem_cols - 5 then List.rev (Printf.sprintf "%s+%2d" (String.make (rem_cols - 4) ' ') (List.length ts + 1) :: acc) else limit_width (t::acc) (rem_cols - len - 1) ts in let title = Printf.sprintf "Processing %2d/%d:" (finished + M.cardinal running) njobs in let texts = limit_width [] (OpamMisc.terminal_columns ()) (title::texts) in if texts <> [] then OpamGlobals.status_line "%s" (String.concat " " texts) in (* nslots is the number of free slots *) let rec loop (nslots: int) (* number of free slots *) (results: 'b M.t) (running: (OpamProcess.t * 'a * string option) M.t) (ready: S.t) = let mutual_exclusion_set n = List.fold_left (fun acc s -> if S.mem n s then acc ++ s else acc) S.empty mutually_exclusive in let run_seq_command nslots ready n = function | Done r -> log "Job %a finished" (slog (string_of_int @* V.hash)) n; let results = M.add n r results in let running = M.remove n running in if not (M.is_empty running) then print_status (M.cardinal results) running; let new_ready = S.filter (fun n -> List.for_all (fun n -> M.mem n results) (G.pred g n) && S.is_empty (mutual_exclusion_set n %% map_keys running)) (S.of_list (G.succ g n) ++ mutual_exclusion_set n) in loop (nslots + 1) results running (ready ++ new_ready) | Run (cmd, cont) -> log "Next task in job %a: %a" (slog (string_of_int @* V.hash)) n (slog OpamProcess.string_of_command) cmd; if OpamProcess.is_verbose_command cmd || not (OpamGlobals.disp_status_line ()) then OpamMisc.Option.iter (OpamGlobals.msg "%s Command started\n") (OpamProcess.text_of_command cmd); let p = if dry_run then OpamProcess.dry_run_background cmd else OpamProcess.run_background cmd in let running = M.add n (p, cont, OpamProcess.text_of_command cmd) running in print_status (M.cardinal results) running; loop nslots results running ready in let fail node error = log "Exception while computing job %a: %a" (slog (string_of_int @* V.hash)) node (slog V.to_string) node; if error = Sys.Break then OpamGlobals.error "User interruption"; let running = M.remove node running in (* Cleanup *) let errors,pend = if dry_run then [node,error],[] else M.fold (fun n (p,cont,_text) (errors,pend) -> try match OpamProcess.dontwait p with | None -> (* process still running *) OpamProcess.interrupt p; (n,Aborted) :: errors, p::pend | Some result -> match cont result with | Done _ -> errors, pend | Run _ -> (n,Aborted) :: errors, pend with | Unix.Unix_error _ -> errors, pend | e -> (n,e)::errors, pend) running ([node,error],[]) in (try List.iter (fun _ -> ignore (OpamProcess.wait_one pend)) pend with e -> log "%a in sub-process cleanup" (slog Printexc.to_string) e); (* Generate the remaining nodes in topological order *) let remaining = G.Topological.fold (fun n remaining -> if M.mem n results || List.mem_assoc n errors then remaining else n::remaining) g [] in raise (Errors (M.keys results, List.rev errors, List.rev remaining)) in if M.is_empty running && S.is_empty ready then results else if nslots > 0 && not (S.is_empty ready) then (* Start a new process *) let n = S.choose ready in log "Starting job %a (worker %d/%d): %a" (slog (string_of_int @* V.hash)) n (jobs - nslots + 1) jobs (slog V.to_string) n; let pred = G.pred g n in let pred = List.map (fun n -> n, M.find n results) pred in let cmd = try command ~pred n with e -> fail n e in let ready = S.remove n ready -- mutual_exclusion_set n in run_seq_command (nslots - 1) ready n cmd else (* Wait for a process to end *) let processes = M.fold (fun n (p,x,_) acc -> (p,(n,x)) :: acc) running [] in let process,result = if dry_run then OpamProcess.dry_wait_one (List.map fst processes) else try match processes with | [p,_] -> p, OpamProcess.wait p | _ -> OpamProcess.wait_one (List.map fst processes) with e -> fail (fst (snd (List.hd processes))) e in let n,cont = List.assoc process processes in log "Collected task for job %a (ret:%d)" (slog (string_of_int @* V.hash)) n result.OpamProcess.r_code; let next = try cont result with e -> OpamProcess.cleanup result; fail n e in OpamProcess.cleanup result; run_seq_command nslots ready n next in let roots = G.fold_vertex (fun n roots -> if G.in_degree g n = 0 then S.add n roots else roots) g S.empty in loop jobs M.empty M.empty roots let iter ~jobs ~command ?dry_run ?mutually_exclusive g = ignore (aux_map ~jobs ~command ?dry_run ?mutually_exclusive g) let map ~jobs ~command ?dry_run ?mutually_exclusive g = M.bindings (aux_map ~jobs ~command ?dry_run ?mutually_exclusive g) (* Only print the originally raised exception, which should come first. Ignore Aborted exceptions due to other commands termination, and simultaneous exceptions in other command's continuations (unlikely as that would require both commands to have terminated simultaneously) *) let error_printer = function | Errors (_, (_,exc)::_, _) -> Some (Printexc.to_string exc) | _ -> None let () = Printexc.register_printer error_printer end module type GRAPH = sig include Graph.Sig.I include Graph.Oper.S with type g = t module Topological : sig val fold : (V.t -> 'a -> 'a) -> t -> 'a -> 'a val iter : (V.t -> unit) -> t -> unit end module Parallel : SIG with type G.t = t and type G.V.t = vertex module Dot : sig val output_graph : out_channel -> t -> unit end end module MakeGraph (X: VERTEX) = struct module Vertex = X module PG = Graph.Imperative.Digraph.ConcreteBidirectional (Vertex) module Topological = Graph.Topological.Make (PG) module Traverse = Graph.Traverse.Dfs(PG) module Components = Graph.Components.Make(PG) module Parallel = Make (struct include PG module Vertex = Vertex module Topological = Topological include Traverse include Components end) module Dot = Graph.Graphviz.Dot (struct let edge_attributes _ = [] let default_edge_attributes _ = [] let get_subgraph _ = None let vertex_attributes _ = [] let vertex_name v = Printf.sprintf "\"%s\"" (Vertex.to_string v) let default_vertex_attributes _ = [] let graph_attributes _ = [] include PG end) include PG include Graph.Oper.I (PG) end (* Simple polymorphic implem on lists when we don't need full graphs. We piggy-back on the advanced implem using an array and an int-graph *) module IntGraph = MakeGraph(struct type t = int let compare x y = x - y let hash x = x let equal x y = x = y let to_string = string_of_int let to_json x = `Float (float_of_int x) end) let flat_graph_of_array a = let g = IntGraph.create () in Array.iteri (fun i _ -> IntGraph.add_vertex g i) a; g exception Errors = IntGraph.Parallel.Errors let iter ~jobs ~command ?dry_run l = let a = Array.of_list l in let g = flat_graph_of_array a in let command ~pred:_ i = command a.(i) in ignore (IntGraph.Parallel.iter ~jobs ~command ?dry_run g) let map ~jobs ~command ?dry_run l = let a = Array.of_list l in let g = flat_graph_of_array a in let command ~pred:_ i = command a.(i) in let r = IntGraph.Parallel.aux_map ~jobs ~command ?dry_run g in let rec mklist acc n = if n < 0 then acc else mklist (IntGraph.Parallel.M.find n r :: acc) (n-1) in mklist [] (Array.length a - 1) let reduce ~jobs ~command ~merge ~nil ?dry_run l = let a = Array.of_list l in let g = flat_graph_of_array a in let command ~pred:_ i = command a.(i) in let r = IntGraph.Parallel.aux_map ~jobs ~command ?dry_run g in IntGraph.Parallel.M.fold (fun _ -> merge) r nil opam-full-1.2.2/src/core/opamFormula.ml0000644000175000017500000003220612517374212016470 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) type relop = [`Eq|`Neq|`Geq|`Gt|`Leq|`Lt] let string_of_relop = function | `Eq -> "=" | `Neq -> "!=" | `Geq -> ">=" | `Gt -> ">" | `Leq -> "<=" | `Lt -> "<" let relop_of_string = function | "=" -> `Eq | "!=" -> `Neq | ">=" -> `Geq | ">" -> `Gt | "<=" -> `Leq | "<" -> `Lt | x -> raise (Invalid_argument (x ^ " is not a valid relop")) let neg_relop = function | `Eq -> `Neq | `Neq -> `Eq | `Geq -> `Lt | `Gt -> `Leq | `Leq -> `Gt | `Lt -> `Geq type version_constraint = relop * OpamPackage.Version.t type atom = OpamPackage.Name.t * version_constraint option let string_of_atom = function | n, None -> OpamPackage.Name.to_string n | n, Some (r,c) -> Printf.sprintf "%s (%s %s)" (OpamPackage.Name.to_string n) (string_of_relop r) (OpamPackage.Version.to_string c) let short_string_of_atom = function | n, None -> OpamPackage.Name.to_string n | n, Some (`Eq,c) -> Printf.sprintf "%s.%s" (OpamPackage.Name.to_string n) (OpamPackage.Version.to_string c) | n, Some (r,c) -> Printf.sprintf "%s%s%s" (OpamPackage.Name.to_string n) (string_of_relop r) (OpamPackage.Version.to_string c) let string_of_atoms atoms = OpamMisc.sconcat_map " & " short_string_of_atom atoms type 'a conjunction = 'a list let string_of_conjunction string_of_atom c = Printf.sprintf "(%s)" (OpamMisc.sconcat_map " & " string_of_atom c) type 'a disjunction = 'a list let string_of_disjunction string_of_atom c = Printf.sprintf "(%s)" (OpamMisc.sconcat_map " | " string_of_atom c) type 'a cnf = 'a list list let string_of_cnf string_of_atom cnf = let string_of_clause c = Printf.sprintf "(%s)" (OpamMisc.sconcat_map " | " string_of_atom c) in Printf.sprintf "(%s)" (OpamMisc.sconcat_map " & " string_of_clause cnf) type 'a dnf = 'a list list let string_of_dnf string_of_atom cnf = let string_of_clause c = Printf.sprintf "(%s)" (OpamMisc.sconcat_map " & " string_of_atom c) in Printf.sprintf "(%s)" (OpamMisc.sconcat_map " | " string_of_clause cnf) type 'a formula = | Empty | Atom of 'a | Block of 'a formula | And of 'a formula * 'a formula | Or of 'a formula * 'a formula let make_and a b = match a, b with | Empty, r | r, Empty -> r | a, b -> And (a, b) let make_or a b = match a, b with | Empty, r | r, Empty -> r (* we're not assuming Empty is true *) | a, b -> Or (a, b) let string_of_formula string_of_a f = let rec aux ?paren f = let paren = match paren with | Some _ when !OpamGlobals.all_parens -> Some `All | paren -> paren in match f with | Empty -> "0" | Atom a -> let s = string_of_a a in if !OpamGlobals.all_parens then Printf.sprintf "(%s)" s else s | Block x -> Printf.sprintf "(%s)" (aux x) | And(x,y) -> (* And, Or have the same priority, left-associative *) let lpar, rpar = if paren = Some `Or then "(",")" else "","" in Printf.sprintf "%s%s & %s%s" lpar (aux x) (aux ~paren:`And y) rpar | Or(x,y) -> let lpar, rpar = if paren = Some `And then "(",")" else "","" in Printf.sprintf "%s%s | %s%s" lpar (aux x) (aux ~paren:`Or y) rpar in aux f let rec map f = function | Empty -> Empty | Atom x -> f x | And(x,y) -> make_and (map f x) (map f y) | Or(x,y) -> make_or (map f x) (map f y) | Block x -> match map f x with | Empty -> Empty | x -> Block x (* Maps top-down *) let rec map_formula f t = let t = f t in match t with | Block x -> Block (map_formula f x) | And(x,y) -> make_and (map_formula f x) (map_formula f y) | Or(x,y) -> make_or (map_formula f x) (map_formula f y) | x -> x let neg neg_atom = map_formula (function | And(x,y) -> Or(x,y) | Or(x,y) -> And(x,y) | Atom x -> Atom (neg_atom x) | x -> x) let rec iter f = function | Empty -> () | Atom x -> f x | Block x -> iter f x | And(x,y) -> iter f x; iter f y | Or(x,y) -> iter f x; iter f y let rec fold_left f i = function | Empty -> i | Atom x -> f i x | Block x -> fold_left f i x | And(x,y) -> fold_left f (fold_left f i x) y | Or(x,y) -> fold_left f (fold_left f i x) y type version_formula = version_constraint formula type t = (OpamPackage.Name.t * version_formula) formula let rec eval atom = function | Empty -> true | Atom x -> atom x | Block x -> eval atom x | And(x,y) -> eval atom x && eval atom y | Or(x,y) -> eval atom x || eval atom y let check_relop relop c = match relop with | `Eq -> c = 0 | `Neq -> c <> 0 | `Geq -> c >= 0 | `Gt -> c > 0 | `Leq -> c <= 0 | `Lt -> c < 0 let eval_relop relop v1 v2 = check_relop relop (OpamPackage.Version.compare v1 v2) let check (name,cstr) package = name = OpamPackage.name package && match cstr with | None -> true | Some (relop, v) -> eval_relop relop (OpamPackage.version package) v let to_string t = let string_of_constraint (relop, version) = Printf.sprintf "%s %s" (string_of_relop relop) (OpamPackage.Version.to_string version) in let string_of_pkg = function | n, Empty -> OpamPackage.Name.to_string n | n, (Atom _ as c) -> Printf.sprintf "%s %s" (OpamPackage.Name.to_string n) (string_of_formula string_of_constraint c) | n, c -> Printf.sprintf "%s (%s)" (OpamPackage.Name.to_string n) (string_of_formula string_of_constraint c) in string_of_formula string_of_pkg t (* convert a formula to a CNF *) let cnf_of_formula t = let rec mk_left x y = match y with | Block y -> mk_left x y | And (a,b) -> And (mk_left x a, mk_left x b) | Empty -> x | _ -> Or (x,y) in let rec mk_right x y = match x with | Block x -> mk_right x y | And (a,b) -> And (mk_right a y, mk_right b y) | Empty -> y | _ -> mk_left x y in let rec mk = function | Empty -> Empty | Block x -> mk x | Atom x -> Atom x | And (x,y) -> And (mk x, mk y) | Or (x,y) -> mk_right (mk x) (mk y) in mk t (* convert a formula to DNF *) let dnf_of_formula t = let rec mk_left x y = match y with | Block y -> mk_left x y | Or (a,b) -> Or (mk_left x a, mk_left x b) | _ -> And (x,y) in let rec mk_right x y = match x with | Block x -> mk_right x y | Or (a,b) -> Or (mk_right a y, mk_right b y) | _ -> mk_left x y in let rec mk = function | Empty -> Empty | Block x -> mk x | Atom x -> Atom x | Or (x,y) -> Or (mk x, mk y) | And (x,y) -> mk_right (mk x) (mk y) in mk t (* Convert a t an atom formula *) let to_atom_formula (t:t): atom formula = let atom (r,v) = Atom (r, v) in let atoms (x, c) = match cnf_of_formula (map atom c) with | Empty -> Atom (x, None) | cs -> map (fun c -> Atom (x, Some c)) cs in map atoms t (* Convert an atom formula to a t-formula *) let of_atom_formula (a:atom formula): t = let atom (n, v) = match v with | None -> Atom (n, Empty) | Some (r,v) -> Atom (n, Atom (r,v)) in map atom a (* Convert a formula to CNF *) let to_cnf (t : t) = let rec or_formula = function | Atom (x,None) -> [x, None] | Atom (x,Some(r,v)) -> [x, Some(r,v)] | Or(x,y) -> or_formula x @ or_formula y | Empty | Block _ | And _ -> assert false in let rec aux t = match t with | Empty -> [] | Block _ -> assert false | Atom _ | Or _ -> [or_formula t] | And(x,y) -> aux x @ aux y in aux (cnf_of_formula (to_atom_formula t)) (* Convert a formula to DNF *) let to_dnf t = let rec and_formula = function | Atom (x,None) -> [x, None] | Atom (x,Some(r,v)) -> [x, Some(r,v)] | And(x,y) -> and_formula x @ and_formula y | Empty | Block _ | Or _ -> assert false in let rec aux t = match t with | Empty -> [] | Block _ -> assert false | Atom _ | And _ -> [and_formula t] | Or(x,y) -> aux x @ aux y in aux (dnf_of_formula (to_atom_formula t)) let to_conjunction t = match to_dnf t with | [] -> [] | [x] -> x | _ -> OpamGlobals.error_and_exit "%s is not a valid conjunction" (to_string t) let ands l = List.fold_left make_and Empty l let rec ands_to_list = function | Empty -> [] | And (e,f) | Block (And (e,f)) -> ands_to_list e @ ands_to_list f | x -> [x] let of_conjunction c = of_atom_formula (ands (List.rev_map (fun x -> Atom x) c)) let to_disjunction t = match to_cnf t with | [] -> [] | [x] -> x | _ -> OpamGlobals.error_and_exit "%s is not a valid disjunction" (to_string t) let ors l = List.fold_left make_or Empty l let rec ors_to_list = function | Empty -> [] | Or (e,f) | Block (Or (e,f)) -> ors_to_list e @ ors_to_list f | x -> [x] let of_disjunction d = of_atom_formula (ors (List.rev_map (fun x -> Atom x) d)) let atoms t = fold_left (fun accu x -> x::accu) [] (to_atom_formula t) let simplify_version_formula f = (* backported from OWS/WeatherReasons *) let vcomp = OpamPackage.Version.compare in let vmin a b = if vcomp a b <= 0 then a else b in let vmax a b = if vcomp a b >= 0 then a else b in let and_cstrs c1 c2 = match c1, c2 with | (`Gt, a), (`Gt, b) -> [`Gt, vmax a b] | (`Geq,a), (`Geq,b) -> [`Geq, vmax a b] | (`Gt, a), (`Geq,b) | (`Geq,b), (`Gt, a) -> if vcomp a b >= 0 then [(`Gt, a)] else [(`Geq,b)] | (`Lt, a), (`Lt, b) -> [`Lt, vmin a b] | (`Leq,a), (`Leq,b) -> [`Leq, vmin a b] | (`Lt, a), (`Leq,b) | (`Leq,b), (`Lt, a) -> if vcomp a b <= 0 then [`Lt, a] else [`Leq,b] | (`Geq,a), (`Eq, b) | (`Eq, b), (`Geq,a) when vcomp a b <= 0 -> [`Eq, b] | (`Gt, a), (`Eq, b) | (`Eq, b), (`Gt, a) when vcomp a b < 0 -> [`Eq, b] | (`Leq,a), (`Eq, b) | (`Eq, b), (`Leq,a) when vcomp a b >= 0 -> [`Eq, b] | (`Lt, a), (`Eq, b) | (`Eq, b), (`Lt, a) when vcomp a b > 0 -> [`Eq, b] | (`Geq,a), (`Neq,b) | (`Neq,b), (`Geq,a) when vcomp a b > 0 -> [`Geq,a] | (`Gt, a), (`Neq,b) | (`Neq,b), (`Gt, a) when vcomp a b >= 0 -> [`Gt, a] | (`Leq,a), (`Neq,b) | (`Neq,b), (`Leq,a) when vcomp a b < 0 -> [`Leq,a] | (`Lt, a), (`Neq,b) | (`Neq,b), (`Lt, a) when vcomp a b <= 0 -> [`Lt, a] | c1, c2 -> if c1 = c2 then [c1] else [c1;c2] in let or_cstrs c1 c2 = match c1, c2 with | (`Gt, a), (`Gt, b) -> [`Gt, vmin a b] | (`Geq,a), (`Geq,b) -> [`Geq, vmin a b] | (`Gt, a), (`Geq,b) | (`Geq,b), (`Gt, a) -> if vcomp a b < 0 then [`Gt, a] else [`Geq,b] | (`Lt, a), (`Lt, b) -> [`Lt, vmax a b] | (`Leq,a), (`Leq,b) -> [`Leq,vmax a b] | (`Lt, a), (`Leq,b) | (`Leq,b), (`Lt, a) -> if vcomp a b > 0 then [`Lt, a] else [`Leq,b] | (`Geq,a), (`Eq, b) | (`Eq, b), (`Geq,a) when vcomp a b <= 0 -> [`Geq,a] | (`Gt, a), (`Eq, b) | (`Eq, b), (`Gt, a) when vcomp a b < 0 -> [`Gt, a] | (`Leq,a), (`Eq, b) | (`Eq, b), (`Leq,a) when vcomp a b >= 0 -> [`Leq,a] | (`Lt, a), (`Eq, b) | (`Eq, b), (`Lt, a) when vcomp a b > 0 -> [`Lt, a] | (`Geq,a), (`Neq,b) | (`Neq,b), (`Geq,a) when vcomp a b > 0 -> [`Neq,b] | (`Gt, a), (`Neq,b) | (`Neq,b), (`Gt, a) when vcomp a b >= 0 -> [`Neq,b] | (`Leq,a), (`Neq,b) | (`Neq,b), (`Leq,a) when vcomp a b < 0 -> [`Neq,b] | (`Lt, a), (`Neq,b) | (`Neq,b), (`Lt, a) when vcomp a b <= 0 -> [`Neq,b] | c1, c2 -> if c1 = c2 then [c1] else [c1;c2] in let rec add_cstr join c = function | [] -> [c] | c1::r -> match join c c1 with | [c] -> add_cstr join c r | _ -> c1 :: add_cstr join c r in let rec merge mk join fl = let subs,cstrs = List.fold_left (fun (sub,cstrs) fl -> match aux fl with | Atom c -> sub, add_cstr join c cstrs | f -> mk sub f, cstrs) (Empty,[]) fl in List.fold_left (fun f c -> mk f (Atom c)) subs cstrs and aux = function | And _ as f -> merge make_and and_cstrs (ands_to_list f) | Or _ as f -> merge make_or or_cstrs (ors_to_list f) | Block f -> aux f | (Atom _ | Empty) as f -> f in aux f type 'a ext_package_formula = (OpamPackage.Name.t * ('a * version_formula)) formula let formula_of_extended ~filter = map (fun (n, (kws,formula)) -> if filter kws then Atom (n, formula) else Empty) opam-full-1.2.2/src/core/opamJson.mli0000644000175000017500000000577612517374212016161 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) type t = [ `Null | `Bool of bool | `Float of float| `String of string | `A of t list | `O of (string * t) list ] val to_string: t -> string val add: t -> unit val output: unit -> unit val set_output: (string -> unit) -> unit val verbose: unit -> bool (*--------------------------------------------------------------------------- Copyright (c) 2012 Daniel C. Bünzli All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of Daniel C. Bünzli nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------*) opam-full-1.2.2/src/core/opamParallel.mli0000644000175000017500000000751312517374212016773 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) module type VERTEX = sig include OpamMisc.OrderedType include Graph.Sig.COMPARABLE with type t := t end module type G = sig include Graph.Sig.I module Vertex: VERTEX with type t = V.t module Topological: sig val fold: (V.t -> 'a -> 'a) -> t -> 'a -> 'a end val has_cycle: t -> bool val scc_list: t -> V.t list list end (** When one job fails due to an exception, other running jobs are interrupted and reported with this sub-exception in the Errors list *) exception Aborted (** Simply parallel execution of tasks *) (** In the simple iter, map and reduce cases, ints are the indexes of the jobs in the list *) exception Errors of int list * (int * exn) list * int list val iter: jobs:int -> command:('a -> unit OpamProcess.job) -> ?dry_run:bool -> 'a list -> unit val map: jobs:int -> command:('a -> 'b OpamProcess.job) -> ?dry_run:bool -> 'a list -> 'b list val reduce: jobs:int -> command:('a -> 'b OpamProcess.job) -> merge:('b -> 'b -> 'b) -> nil:'b -> ?dry_run:bool -> 'a list -> 'b (** More complex parallelism with dependency graphs *) module type SIG = sig module G : G (** Runs the job [command ~pred v] for every node [v] in a graph, in topological order, using [jobs] concurrent processes. [pred] is the associative list of job results on direct predecessors of [v]. *) val iter: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?mutually_exclusive:(G.V.t list list) -> G.t -> unit (** Same as [iter], but returns the results of all jobs as a [vertex,result] associative list *) val map: jobs:int -> command:(pred:(G.V.t * 'a) list -> G.V.t -> 'a OpamProcess.job) -> ?dry_run:bool -> ?mutually_exclusive:(G.V.t list list) -> G.t -> (G.V.t * 'a) list (** Raised when the [command] functions raised exceptions. Parameters are (successfully traversed nodes, exception nodes and corresponding exceptions, remaining nodes that weren't traversed) *) exception Errors of G.V.t list * (G.V.t * exn) list * G.V.t list (** Raised when the graph to traverse has cycles. Returns the cycles found. *) exception Cyclic of G.V.t list list end module Make (G : G) : SIG with module G = G and type G.V.t = G.V.t module type GRAPH = sig include Graph.Sig.I include Graph.Oper.S with type g = t module Topological : sig val fold : (V.t -> 'a -> 'a) -> t -> 'a -> 'a val iter : (V.t -> unit) -> t -> unit end module Parallel : SIG with type G.t = t and type G.V.t = vertex module Dot : sig val output_graph : out_channel -> t -> unit end end module MakeGraph (V: VERTEX) : GRAPH with type V.t = V.t opam-full-1.2.2/src/core/opamCompiler.ml0000644000175000017500000001007512517374212016635 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamMisc.OP let log fmt = OpamGlobals.log "COMPILER" fmt let slog = OpamGlobals.slog module Version = struct include OpamMisc.Base let of_string str = if OpamMisc.contains str '+' then raise (Invalid_argument "'+' is not allowed in compiler versions"); of_string str type constr = (OpamFormula.relop * t) OpamFormula.formula let compare v1 v2 = Debian.Version.compare (to_string v1) (to_string v2) let eval_relop relop v1 v2 = OpamFormula.check_relop relop (compare v1 v2) end module O = struct type t = { version: Version.t; name : string; } let compare t1 t2 = String.compare t1.name t2.name let to_string t = t.name let of_string str = match OpamMisc.cut_at str '+' with | Some (v,_) -> { name = str; version = Version.of_string v } | None -> { name = str; version = Version.of_string str } let to_json t = `String (to_string t) end include O module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) let get_current () = match Lazy.force OpamSystem.ocaml_version with | None -> None | Some o -> Some (of_string o) let get_system () = match Lazy.force OpamSystem.system_ocamlc_version with | None -> None | Some v -> Some (of_string v) let version t = t.version (* DIR/$NAME.comp *) let of_filename f = if OpamFilename.check_suffix f ".comp" then f |> OpamFilename.chop_extension |> OpamFilename.basename |> OpamFilename.Base.to_string |> of_string |> fun x -> Some x else None let list dir = log "list %a" (slog OpamFilename.Dir.to_string) dir; if OpamFilename.exists_dir dir then ( let files = OpamFilename.rec_files dir in List.fold_left (fun set f -> match of_filename f with | None -> set | Some c -> Set.add c set ) Set.empty files ) else Set.empty let prefixes dir = log "prefixes %a" (slog OpamFilename.Dir.to_string) dir; if OpamFilename.exists_dir dir then ( let files = OpamFilename.rec_files dir in List.fold_left (fun map f -> match of_filename f with | None -> map | Some c -> let suffix = OpamFilename.Dir.to_string (OpamFilename.dirname f) in let prefix = match OpamMisc.remove_prefix ~prefix:(OpamFilename.Dir.to_string dir) suffix with | "" -> None | p -> Some p in Map.add c prefix map ) Map.empty files ) else Map.empty let system = of_string OpamGlobals.system let unknown compiler = if compiler = system then ( let root = if !OpamGlobals.root_dir = OpamGlobals.default_opam_dir then "" else Printf.sprintf " --root=%s" !OpamGlobals.root_dir in OpamGlobals.error_and_exit "No OCaml compiler found in path. You should use:\n\ \n\ \ opam init%s --comp=VERSION\n" root ) else OpamGlobals.error_and_exit "%S is not a valid compiler." (to_string compiler) opam-full-1.2.2/src/core/opamTypesBase.mli0000644000175000017500000001067512517374212017141 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** This module contains basic utility functions and stringifiers for the basic OPAM types present in OpamTypes.ml *) open OpamTypes include module type of OpamCompat (** {2 Exceptions} *) exception Lexer_error of string (** Upcast a downloaded directory. *) val download_dir: dirname download -> generic_file download (** Upcast a downloaded file. *) val download_file: filename download -> generic_file download (** Corresponding user message *) val string_of_download: _ download -> string val string_of_generic_file: generic_file -> string (** Print an address *) val string_of_address: address -> string (** Parse an address *) val address_of_string: string -> address (** Guess an address kind using url suffixes ([.git], etc.) and prefixes ([http://], etc.). Defaults to `local. The returned address is a correct path in case of [file://] *) val parse_url: address -> address * repository_kind (** Scan the given directory for version control *) val guess_version_control: dirname -> [`git|`hg|`darcs] option (** Pretty-print repository kinds. *) val string_of_repository_kind: repository_kind -> string (** Parser of repository kinds. Raise an error if the kind is not valid. *) val repository_kind_of_string: string -> repository_kind (** Extract a package from a package action. *) val action_contents: 'a action -> 'a (** Extract a packages from a package action. This returns all concerned packages, including the old version for an up/down-grade. *) val full_action_contents: 'a action -> 'a list (** Pretty-prints the cause of an action *) val string_of_cause: ('pkg -> string) -> 'pkg cause -> string (** Pretty-print *) val string_of_upload: upload -> string (** Convert a pin kind to a repository kind *) val repository_kind_of_pin_kind: pin_kind -> repository_kind option (** Pretty-printing of pin kinds. *) val pin_kind_of_string: string -> pin_kind (** Parsing of pin kinds *) val string_of_pin_kind: pin_kind -> string (** Read pin options args. If [kind] isn't specified, [guess] is set to [true] and the name isn't explicit, look for VC on the filesystem to get the pinning kind *) val pin_option_of_string: ?kind:pin_kind -> ?guess:bool -> string -> pin_option (** Convert a pin option to a string *) val string_of_pin_option: pin_option -> string (** Get the pin kind from a pin option *) val kind_of_pin_option: pin_option -> pin_kind (** Get a pin_option from address and kind *) val pin_of_url: address * repository_kind -> pin_option (** Pretty-print *) val string_of_shell: shell -> string (** The empty file position *) val pos_null: pos (** Prints a file position *) val string_of_pos: pos -> string val string_of_relop: relop -> string val relop_of_string: string -> relop (** Raises Invalid_argument*) val string_of_logop: logop -> string val logop_of_string: string -> logop (** Raises Invalid_argument*) val string_of_pfxop: pfxop -> string val pfxop_of_string: string -> pfxop (** Raises Invalid_argument*) (** Parses the data suitable for a filter.FIdent from a string. May raise [Failure msg] on bad package names *) val filter_ident_of_string: string -> name list * variable * (string * string) option val filter_deps: ?build:bool -> ?test:bool -> ?doc:bool -> ext_formula -> formula (** Map on a solver result *) val map_success: ('a -> 'b) -> ('a,'fail) result -> ('b,'fail) result opam-full-1.2.2/src/core/opamProcess.ml0000644000175000017500000004403112517374212016500 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) let log ?level fmt = OpamGlobals.log "PROC" ?level fmt let slog = OpamGlobals.slog (** Shell commands *) type command = { cmd: string; args: string list; cmd_text: string option; cmd_dir: string option; cmd_env: string array option; cmd_stdin: bool option; cmd_verbose: bool option; cmd_name: string option; cmd_metadata: (string * string) list option; } let string_of_command c = String.concat " " (c.cmd::c.args) let text_of_command c = c.cmd_text let default_verbose () = !OpamGlobals.verbose_level >= 2 let is_verbose_command c = OpamMisc.Option.default (default_verbose ()) c.cmd_verbose let make_command_text ?(color=`green) str ?(args=[]) cmd = let summary = match List.filter (fun s -> String.length s > 0 && s.[0] <> '-' && not (String.contains s '/') && not (String.contains s '=')) args with | hd::_ -> String.concat " " [cmd; hd] | [] -> cmd in Printf.sprintf "[%s: %s]" (OpamGlobals.colorise color str) summary let command ?env ?verbose ?name ?metadata ?dir ?allow_stdin ?text cmd args = { cmd; args; cmd_env=env; cmd_verbose=verbose; cmd_name=name; cmd_metadata=metadata; cmd_dir=dir; cmd_stdin=allow_stdin; cmd_text=text; } (** Running processes *) type t = { p_name : string; p_args : string list; p_pid : int; p_cwd : string; p_time : float; p_stdout : string option; p_stderr : string option; p_env : string option; p_info : string option; p_metadata: (string * string) list; p_verbose: bool; } let open_flags = [Unix.O_WRONLY; Unix.O_CREAT; Unix.O_APPEND] let output_lines oc lines = List.iter (fun line -> output_string oc line; output_string oc "\n"; flush oc; ) lines; output_string oc "\n"; flush oc let option_map fn = function | None -> None | Some o -> Some (fn o) let option_default d = function | None -> d | Some v -> v let make_info ?code ?signal ~cmd ~args ~cwd ~env_file ~stdout_file ~stderr_file ~metadata () = let b = ref [] in let print name str = b := (name, str) :: !b in let print_opt name = function | None -> () | Some s -> print name s in print "opam-version" (OpamVersion.to_string (OpamVersion.full ())); print "os" (OpamGlobals.os_string ()); print "command" (String.concat " " (cmd :: args)); print "path" cwd; List.iter (fun (k,v) -> print k v) metadata; print_opt "exit-code" (option_map string_of_int code); print_opt "signalled" (option_map string_of_int signal); print_opt "env-file" env_file; print_opt "stdout-file" stdout_file; print_opt "stderr-file" stderr_file; List.rev !b let string_of_info ?(color=`yellow) info = let b = Buffer.create 1024 in List.iter (fun (k,v) -> Printf.bprintf b "%s %-20s %s\n" (OpamGlobals.colorise color "#") (OpamGlobals.colorise color k) v) info; Buffer.contents b (** [create cmd args] create a new process to execute the command [cmd] with arguments [args]. If [stdout_file] or [stderr_file] are set, the channels are redirected to the corresponding files. The outputs are discarded is [verbose] is set to false. The current environment can also be overriden if [env] is set. The environment which is used to run the process is recorded into [env_file] (if set). *) let create ?info_file ?env_file ?(allow_stdin=true) ?stdout_file ?stderr_file ?env ?(metadata=[]) ?dir ~verbose cmd args = let nothing () = () in let tee f = let fd = Unix.openfile f open_flags 0o644 in let close_fd () = Unix.close fd in fd, close_fd in let oldcwd = Sys.getcwd () in let cwd = OpamMisc.Option.default oldcwd dir in OpamMisc.Option.iter Unix.chdir dir; let stdin_fd,close_stdin = if allow_stdin then Unix.stdin, nothing else let fd,outfd = Unix.pipe () in let close_stdin () = Unix.close fd in Unix.close outfd; fd, close_stdin in let stdout_fd, close_stdout = match stdout_file with | None -> Unix.stdout, nothing | Some f -> tee f in let stderr_fd, close_stderr = match stderr_file with | None -> Unix.stderr, nothing | Some f -> tee f in let env = match env with | None -> Unix.environment () | Some e -> e in let time = Unix.gettimeofday () in let () = (* write the env file before running the command*) match env_file with | None -> () | Some f -> let chan = open_out f in let env = Array.to_list env in (* Remove dubious variables *) let env = List.filter (fun line -> not (OpamMisc.contains line '$')) env in output_lines chan env; close_out chan in let () = (* write the info file *) match info_file with | None -> () | Some f -> let chan = open_out f in let info = make_info ~cmd ~args ~cwd ~env_file ~stdout_file ~stderr_file ~metadata () in output_string chan (string_of_info info); close_out chan in let pid = Unix.create_process_env cmd (Array.of_list (cmd :: args)) env stdin_fd stdout_fd stderr_fd in close_stdin (); close_stdout (); close_stderr (); Unix.chdir oldcwd; { p_name = cmd; p_args = args; p_pid = pid; p_cwd = cwd; p_time = time; p_stdout = stdout_file; p_stderr = stderr_file; p_env = env_file; p_info = info_file; p_metadata = metadata; p_verbose = verbose; } type result = { r_code : int; r_signal : int option; r_duration : float; r_info : (string * string) list; r_stdout : string list; r_stderr : string list; r_cleanup : string list; } (* XXX: the function might block for ever for some channels kinds *) let read_lines f = try let ic = open_in f in let lines = ref [] in begin try while true do let line = input_line ic in lines := line :: !lines; done with End_of_file | Sys_error _ -> () end; close_in ic; List.rev !lines with Sys_error _ -> [] (* Compat function (Windows) *) let interrupt p = match OpamGlobals.os () with | OpamGlobals.Win32 -> Unix.kill p.p_pid Sys.sigkill | _ -> Unix.kill p.p_pid Sys.sigint let run_background command = let { cmd; args; cmd_env=env; cmd_verbose=_; cmd_name=name; cmd_metadata=metadata; cmd_dir=dir; cmd_stdin=allow_stdin } = command in let verbose = is_verbose_command command in let allow_stdin = OpamMisc.Option.default false allow_stdin in let env = match env with Some e -> e | None -> Unix.environment () in let file ext = match name with | None -> None | Some n -> let d = if Filename.is_relative n then match dir with | Some d -> d | None -> (Filename.concat !OpamGlobals.root_dir "log") else "" in Some (Filename.concat d (Printf.sprintf "%s.%s" n ext)) in let stdout_file = file "out" in let stderr_file = file "err" in let env_file = file "env" in let info_file = file "info" in create ~env ?info_file ?env_file ?stdout_file ?stderr_file ~verbose ?metadata ~allow_stdin ?dir cmd args let dry_run_background c = { p_name = c.cmd; p_args = c.args; p_pid = -1; p_cwd = OpamMisc.Option.default (Sys.getcwd ()) c.cmd_dir; p_time = Unix.gettimeofday (); p_stdout = None; p_stderr = None; p_env = None; p_info = None; p_metadata = OpamMisc.Option.default [] c.cmd_metadata; p_verbose = is_verbose_command c; } let verbose_print_cmd p = OpamGlobals.msg "%s %s %s%s\n" (OpamGlobals.colorise `yellow "+") p.p_name (OpamMisc.sconcat_map " " (Printf.sprintf "%S") p.p_args) (if p.p_cwd = Sys.getcwd () then "" else Printf.sprintf " (CWD=%s)" p.p_cwd) let verbose_print_out = let pfx = OpamGlobals.colorise `yellow "- " in fun s -> print_string pfx; print_string s; print_char '\n' (** Semi-synchronous printing of the output of a command *) let set_verbose_f, print_verbose_f, isset_verbose_f, stop_verbose_f = let verbose_f = ref None in let stop () = match !verbose_f with | None -> () | Some (ics,_) -> List.iter close_in_noerr ics; verbose_f := None in let set files = stop (); (* implem relies on sigalrm, not implemented on win32. This will fall back to buffered output. *) if OpamGlobals.os () = OpamGlobals.Win32 then () else let ics = List.map (open_in_gen [Open_nonblock;Open_rdonly;Open_text;Open_creat] 0o600) files in let f () = List.iter (fun ic -> try while true do verbose_print_out (input_line ic) done with End_of_file -> flush stdout ) ics in verbose_f := Some (ics, f) in let print () = match !verbose_f with | Some (_, f) -> f () | None -> () in let isset () = !verbose_f <> None in let flush_and_stop () = print (); stop () in set, print, isset, flush_and_stop let set_verbose_process p = if p.p_verbose then let fs = OpamMisc.filter_map (fun x -> x) [p.p_stdout;p.p_stderr] in if fs <> [] then ( verbose_print_cmd p; set_verbose_f fs ) let exit_status p return = let duration = Unix.gettimeofday () -. p.p_time in let stdout = option_default [] (option_map read_lines p.p_stdout) in let stderr = option_default [] (option_map read_lines p.p_stderr) in let cleanup = OpamMisc.filter_map (fun x -> x) [ p.p_info; p.p_env; p.p_stderr; p.p_stdout ] in let code,signal = match return with | Unix.WEXITED r -> Some r, None | Unix.WSIGNALED s | Unix.WSTOPPED s -> None, Some s in if isset_verbose_f () then stop_verbose_f () else if p.p_verbose then (verbose_print_cmd p; List.iter verbose_print_out stdout; List.iter verbose_print_out stderr; flush Pervasives.stdout); let info = make_info ?code ?signal ~cmd:p.p_name ~args:p.p_args ~cwd:p.p_cwd ~metadata:p.p_metadata ~env_file:p.p_env ~stdout_file:p.p_stdout ~stderr_file:p.p_stderr () in { r_code = OpamMisc.Option.default 256 code; r_signal = signal; r_duration = duration; r_info = info; r_stdout = stdout; r_stderr = stderr; r_cleanup = cleanup; } let safe_wait fallback_pid f x = let sh = if isset_verbose_f () then let hndl _ = print_verbose_f () in Some (Sys.signal Sys.sigalrm (Sys.Signal_handle hndl)) else None in let rec aux () = if sh <> None then ignore (Unix.alarm 1); match try f x with | Unix.Unix_error (Unix.EINTR,_,_) -> aux () (* handled signal *) | Unix.Unix_error (Unix.ECHILD,_,_) -> log "Warn: no child to wait for %d" fallback_pid; fallback_pid, Unix.WEXITED 256 with | _, Unix.WSTOPPED _ -> (* shouldn't happen as we don't use WUNTRACED *) aux () | r -> r in let r = aux () in match sh with | Some sh -> ignore (Unix.alarm 0); (* cancels the alarm *) Sys.set_signal Sys.sigalrm sh; r | None -> r let wait p = set_verbose_process p; let _, return = safe_wait p.p_pid (Unix.waitpid []) p.p_pid in exit_status p return let dontwait p = match safe_wait p.p_pid (Unix.waitpid [Unix.WNOHANG]) p.p_pid with | 0, _ -> None | _, return -> Some (exit_status p return) let dead_childs = Hashtbl.create 13 let wait_one processes = if processes = [] then raise (Invalid_argument "wait_one"); if OpamGlobals.os () = OpamGlobals.Win32 then (* No waiting for any child pid on Windows, this is highly sub-optimal but should at least work. Todo: C binding for better behaviour *) let p = List.hd processes in p, wait p else try let p = List.find (fun p -> Hashtbl.mem dead_childs p.p_pid) processes in let return = Hashtbl.find dead_childs p.p_pid in Hashtbl.remove dead_childs p.p_pid; p, exit_status p return with Not_found -> let rec aux () = let pid, return = safe_wait (List.hd processes).p_pid Unix.wait () in try let p = List.find (fun p -> p.p_pid = pid) processes in p, exit_status p return with Not_found -> Hashtbl.add dead_childs pid return; aux () in aux () let dry_wait_one = function | {p_pid = -1; _} as p :: _ -> if p.p_verbose then (verbose_print_cmd p; flush stdout); p, { r_code = 0; r_signal = None; r_duration = 0.; r_info = []; r_stdout = []; r_stderr = []; r_cleanup = []; } | _ -> raise (Invalid_argument "dry_wait_one") let run command = let command = { command with cmd_stdin = OpamMisc.Option.Op.(command.cmd_stdin ++ Some true) } in let p = run_background command in try wait p with e -> match (try dontwait p with _ -> raise e) with | None -> (* still running *) (try interrupt p with Unix.Unix_error _ -> ()); raise e | _ -> raise e let is_failure r = r.r_code <> 0 || r.r_signal <> None let is_success r = not (is_failure r) let safe_unlink f = try Unix.unlink f with Unix.Unix_error _ -> () let cleanup ?(force=false) r = if force || (not !OpamGlobals.debug && is_success r) then List.iter safe_unlink r.r_cleanup let truncate_str = "[...]" (* Truncate long lines *) let truncate_line str = if String.length str <= OpamGlobals.log_line_limit then str else String.sub str 0 (OpamGlobals.log_line_limit - String.length truncate_str) ^ truncate_str (* Take the last [n] elements of [l] (trying to keep an unindented header line for context, like diff) *) let truncate l = let l = List.rev l in let unindented s = String.length s > 0 && s.[0] <> ' ' && s.[0] <> '\t' in let rec cut n acc = function | [] -> acc | [x] when n = 0 -> x :: acc | _ when n = 0 -> truncate_str :: acc | x::l when n = 1 -> (if unindented x then truncate_str :: x :: acc else try List.find unindented l :: truncate_str :: acc with Not_found -> truncate_str :: x :: acc) | x::r -> cut (n-1) (x::acc) r in cut OpamGlobals.log_limit [] l let string_of_result ?(color=`yellow) r = let b = Buffer.create 2048 in let print = Buffer.add_string b in let println str = print str; Buffer.add_char b '\n' in print (string_of_info ~color r.r_info); if r.r_stdout <> [] then print (OpamGlobals.colorise color "### stdout ###\n"); List.iter (fun s -> print (OpamGlobals.colorise color "# "); println s) (truncate r.r_stdout); if r.r_stderr <> [] then print (OpamGlobals.colorise color "### stderr ###\n"); List.iter (fun s -> print (OpamGlobals.colorise color "# "); println s) (truncate r.r_stderr); Buffer.contents b (* Higher-level interface to allow parallelism *) module Job = struct module Op = struct type 'a job = (* Open the variant type *) | Done of 'a | Run of command * (result -> 'a job) (* Parallelise shell commands *) let (@@>) command f = Run (command, f) (* Sequentialise jobs *) let rec (@@+) job1 fjob2 = match job1 with | Done x -> fjob2 x | Run (cmd,cont) -> Run (cmd, fun r -> cont r @@+ fjob2) let (@@|) job f = job @@+ fun x -> Done (f x) end open Op let run = let rec aux = function | Done x -> x | Run (cmd,cont) -> OpamMisc.Option.iter (if OpamGlobals.disp_status_line () then OpamGlobals.status_line "Processing: %s" else OpamGlobals.msg "%s\n") (text_of_command cmd); let r = run cmd in let k = try cont r with e -> cleanup r; raise e in cleanup r; aux k in aux let rec dry_run = function | Done x -> x | Run (_command,cont) -> let result = { r_code = 0; r_signal = None; r_duration = 0.; r_info = []; r_stdout = []; r_stderr = []; r_cleanup = []; } in dry_run (cont result) let rec catch handler = function | Done x -> Done x | Run (cmd,cont) -> let cont r = match try `Cont (cont r) with e -> `Hndl (handler e) with | `Cont job -> catch handler job | `Hndl job -> job in Run (cmd, cont) let ignore_errors ~default ?message job = catch (fun e -> OpamMisc.fatal e; OpamMisc.Option.iter (OpamGlobals.error "%s") message; Done default) job let rec finally fin = function | Done x -> fin (); Done x | Run (cmd,cont) -> Run (cmd, fun r -> finally fin (try cont r with e -> fin (); raise e)) let of_list ?(keep_going=false) l = let rec aux err = function | [] -> Done err | cmd::commands -> let cont = fun r -> if is_success r then aux err commands else if keep_going then aux OpamMisc.Option.Op.(err ++ Some (cmd,r)) commands else Done (Some (cmd,r)) in Run (cmd,cont) in aux None l let rec with_text text = function | Done _ as j -> j | Run (cmd, cont) -> Run ({cmd with cmd_text = Some text}, fun r -> with_text text (cont r)) end type 'a job = 'a Job.Op.job opam-full-1.2.2/src/core/opamFormula.mli0000644000175000017500000001433612517374212016645 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Management of formulas *) (** binary operations (compatible with the Dose type for Cudf operators !) *) type relop = [`Eq|`Neq|`Geq|`Gt|`Leq|`Lt] (** Pretty-printing of relops *) val string_of_relop: relop -> string (** Parsing relops *) val relop_of_string: string -> relop (** Version constraints for OPAM *) type version_constraint = relop * OpamPackage.Version.t (** Formula atoms for OPAM *) type atom = OpamPackage.Name.t * version_constraint option (** Pretty-printing of atoms *) val string_of_atom: atom -> string (** The compact atom format used in requests, "pkgOPvers", with '.' allowed instead of '=' *) val short_string_of_atom: atom -> string (** Prints atoms as a conjunction ("&") using the short format *) val string_of_atoms: atom list -> string (** Checks if a package verifies an atom *) val check: atom -> OpamPackage.t -> bool (** AND formulas *) type 'a conjunction = 'a list (** Pretty print AND formulas *) val string_of_conjunction: ('a -> string) -> 'a conjunction -> string (** OR formulas *) type 'a disjunction = 'a list (** Pretty print OR formulas *) val string_of_disjunction: ('a -> string) -> 'a disjunction -> string (** CNF formulas (Conjunctive Normal Form) *) type 'a cnf = 'a disjunction conjunction (** DNF formulas (Disjunctive Normal Form) *) type 'a dnf = 'a conjunction disjunction (** Pretty print CNF formulas *) val string_of_cnf: ('a -> string) -> 'a cnf -> string (** Pretty print DNF formulas *) val string_of_dnf: ('a -> string) -> 'a dnf -> string (** General formulas *) type 'a formula = | Empty | Atom of 'a | Block of 'a formula | And of 'a formula * 'a formula | Or of 'a formula * 'a formula (** Eval a formula *) val eval: ('a -> bool) -> 'a formula -> bool (** Check a relational operator against an integer from compare *) val check_relop: relop -> int -> bool (** Evaluate a relational operator between versions *) val eval_relop: relop -> OpamPackage.Version.t -> OpamPackage.Version.t -> bool val neg_relop: relop -> relop (** Pretty print a formula *) val string_of_formula: ('a -> string) -> 'a formula -> string (** Convert a list of formulas to an AND-formula ([Empty] formulas are ignored) *) val ands: 'a formula list -> 'a formula (** Converts back an AND-formula to a list (flattens top-level ands) *) val ands_to_list: 'a formula -> 'a formula list (** Convert a list of formulas to an OR-formula ([Empty] formulas are ignored) *) val ors: 'a formula list -> 'a formula (** Converts back an OR-formula to a list (flattens top-level ors) *) val ors_to_list: 'a formula -> 'a formula list (** Map on atoms. Atoms for which the given function returns Empty will be simply removed *) val map: ('a -> 'b formula) -> 'a formula -> 'b formula (** Maps top-down on a formula *) val map_formula: ('a formula -> 'a formula) -> 'a formula -> 'a formula (** Negates a formula (given the function to negate atoms) *) val neg: ('a -> 'a) -> 'a formula -> 'a formula (** Iter function *) val iter: ('a -> unit) -> 'a formula -> unit (** Fold function *) val fold_left: ('a -> 'b -> 'a) -> 'a -> 'b formula -> 'a (** Expressions composed entirely of version constraints *) type version_formula = version_constraint formula (** An atom is: [name] * ([relop] * [version]) formula. Examples of valid formulae: - "foo" \{> "1" & (<"3" | ="5")\} - "foo" \{= "1" | > "4"\} | ("bar" "bouh") *) type t = (OpamPackage.Name.t * version_formula) formula (** Convert a formula to CNF *) val cnf_of_formula: 'a formula -> 'a formula (** Convert a formula to DNF *) val dnf_of_formula: 'a formula -> 'a formula (** Transform a formula where versions can be expressed using formulas to a flat atom formula *) val to_atom_formula: t -> atom formula (** Convert an atom-formula to a t-formula *) val of_atom_formula: atom formula -> t (** Reduces the formula, finding a shorter description of the same version set. Keeps conflicting formula, for documentation, when the set is empty. *) val simplify_version_formula: version_formula -> version_formula (** {2 Atoms} *) (** Return all the atoms *) val atoms: t -> atom list (** Pretty print the formula *) val to_string: t -> string (** Return a conjunction. If the initial formula is not a conjunction, then fail. *) val to_conjunction: t -> atom conjunction (** Return a formula from a conjunction of atoms *) val of_conjunction: atom conjunction -> t (** Return a disjunction. It the initial formula is not a disjunction, then fail. *) val to_disjunction: t -> atom disjunction (** Return a formula from a disjunction of atoms *) val of_disjunction: atom disjunction -> t (** Return an equivalent CNF formula *) val to_cnf: t -> atom cnf (** Return an equivalent DNF formula *) val to_dnf: t -> atom dnf (** Formula over versionned packages with additional flags (used to handle eg. build-deps) *) type 'a ext_package_formula = (OpamPackage.Name.t * ('a * version_formula)) formula (** Turns an extended package formula to a normal formula, by filtering out the packages on the flags of which [filter] returns [false]. *) val formula_of_extended: filter:('a -> bool) -> 'a ext_package_formula -> t opam-full-1.2.2/src/core/opamFormat.ml0000644000175000017500000006233712517374212016323 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamMisc.OP let empty = { file_contents = []; file_name = ""; file_format = OpamVersion.current; } exception Bad_format of pos option * string list * string let bad_format ?pos fmt = Printf.ksprintf (fun str -> raise (Bad_format (pos,[],str))) fmt let add_pos pos = function | Bad_format (None,btl,msg) -> let backtrace = Printexc.get_backtrace () in Bad_format (Some pos, backtrace::btl, msg) | e -> e let string_of_backtrace_list = function | [] | _ when not (Printexc.backtrace_status ()) -> "" | btl -> List.fold_left (fun s bts -> let bt_lines = OpamMisc.split bts '\n' in "\n Backtrace:\n "^(String.concat "\n " bt_lines)^s ) "" btl let string_of_bad_format ?file e = match e, file with | Bad_format (Some pos, btl, msg), _ -> Printf.sprintf "At %s:\n %s%s" (string_of_pos pos) msg (string_of_backtrace_list btl) | Bad_format (None, btl, msg), Some f -> Printf.sprintf "In %s:\n %s%s" (OpamFilename.to_string f) msg (string_of_backtrace_list btl) | Bad_format (None, btl, msg), None -> Printf.sprintf "Input error:\n %s%s" msg (string_of_backtrace_list btl) | _ -> "" let item_pos = function | Section (pos,_) | Variable (pos,_,_) -> pos let protect_item f item = try f item with e -> raise (add_pos (item_pos item) e) let map fn f = let file_contents = List.fold_left (fun accu -> protect_item (function | Section _ as s -> s :: accu | Variable(pos,k,v) -> match fn k v with | Some (k,v) -> Variable(pos,k,v) :: accu | None -> accu )) [] f.file_contents in let file_contents = List.rev file_contents in { f with file_contents } let variables items = let l = List.fold_left (fun accu -> function | Variable (_,k,v) -> (k,v) :: accu | _ -> accu ) [] items in List.rev l let sections items = let l = List.fold_left (fun accu -> function | Section (_,s) -> (s.section_kind, s) :: accu | _ -> accu ) [] items in List.rev l let names items = let tbl = ref OpamMisc.StringMap.empty in let add f = if OpamMisc.StringMap.mem f !tbl then let i = OpamMisc.StringMap.find f !tbl in tbl := OpamMisc.StringMap.add f (i+1) (OpamMisc.StringMap.remove f !tbl) else tbl := OpamMisc.StringMap.add f 1 !tbl in let rec aux items = List.iter (function | Variable (_, f, _) -> add f | Section (_, s) -> aux s.section_items ) items in aux items; !tbl let invalid_fields items fields = let tbl = names items in OpamMisc.StringMap.fold (fun f i accu -> if List.mem f fields && i = 1 then accu else f :: accu ) tbl [] let is_valid items fields = invalid_fields items fields = [] let is_list = function | List _ -> true | _ -> false let value_pos = function | Bool (pos, _) | Int (pos, _) | String (pos, _) | Logop (pos, _, _, _) | Pfxop (pos, _, _) | Relop (pos, _, _, _) | Prefix_relop (pos, _, _) | Ident (pos, _) | List (pos, _) | Group (pos, _) | Option (pos, _, _) | Env_binding (pos, _, _, _) -> pos let protect_value f value = try f value with e -> raise (add_pos (value_pos value) e) let values_pos = function | [] -> None | x::_ -> Some (value_pos x) let protect_values f values = try f values with e -> match values_pos values with | None -> raise e | Some pos -> raise (add_pos pos e) (* Base parsing functions *) let parse_bool = function | Bool (_,b) -> b | x -> bad_format ~pos:(value_pos x) "Expected a bool" let parse_int = function | Int (_,i) -> i | x -> bad_format ~pos:(value_pos x) "Expected an int" let parse_ident = function | Ident (_,i) -> i | x -> bad_format ~pos:(value_pos x) "Expected an ident" let parse_string = function | String (_,s) -> s | x -> bad_format ~pos:(value_pos x) "Expected a string" let parse_list fn = let fn = protect_value fn in function | List (_,s) -> List.rev (List.rev_map fn s) | x -> [fn x] let parse_list_list fn ll = let fn = protect_value fn in match ll with | List (_,l) -> if List.for_all is_list l then List.rev (List.rev_map fn l) else [fn ll] | _ -> [fn ll] let parse_group fn = let fn = protect_value fn in function | Group (_,g) -> List.rev (List.rev_map fn g) | x -> bad_format ~pos:(value_pos x) "Expected a group" let parse_option f g = let f = protect_value f in let g = protect_values g in function | Option (_,k,l) -> f k, Some (g l) | k -> f k, None let parse_single_option f g = let f = protect_value f in let g = protect_value g in function | Option (_,k,[v]) -> f k, Some (g v) | k -> f k, None let parse_string_option f = let f = protect_values f in function | Option (_,k,l) -> parse_string k, Some (f l) | k -> parse_string k, None let parse_string_list = parse_list parse_string let parse_string_pair_of_list = function | [String (_,x); String (_,y)] -> (x,y) | x -> bad_format ?pos:(values_pos x) "Expected a pair of strings" let parse_string_pair = function | List (_,[String (_,x); String (_,y)]) -> (x,y) | x -> bad_format ~pos:(value_pos x) "Expected a pair of strings" let parse_single_string = function | [String (_,x)] -> x | x -> bad_format ?pos:(values_pos x) "Expected a single string" let parse_pair fa fb = let fa = protect_value fa in let fb = protect_value fb in function | List (_,[a; b]) -> (fa a, fb b) | x -> bad_format ~pos:(value_pos x) "Expected a pair" let parse_or fns v = let rec aux = function | [] -> bad_format ~pos:(value_pos v) "Expected %s" (OpamMisc.sconcat_map " or " fst fns) | (_,h)::t -> try h v with Bad_format _ -> aux t in aux fns let make_string str = String (pos_null,str) let make_ident str = Ident (pos_null,str) let make_bool b = Bool (pos_null,b) let make_int i = Int (pos_null,i) let make_list fn l = List (pos_null, List.rev (List.rev_map fn l)) let make_string_list = make_list make_string let make_group fn g = Group (pos_null, List.rev (List.rev_map fn g)) let make_option f g = function | (v, None) -> f v | (v, Some o) -> Option (pos_null, f v, g o) let make_pair fa fb (k,v) = List (pos_null, [fa k; fb v]) let make_string_pair = make_pair make_string make_string (* Printing *) let escape_string s = let len = String.length s in let buf = Buffer.create (len * 2) in for i = 0 to len -1 do match s.[i] with | '\\' | '"' as c -> Buffer.add_char buf '\\'; Buffer.add_char buf c | c -> Buffer.add_char buf c done; Buffer.contents buf let rec format_value fmt = function | Relop (_,op,l,r) -> Format.fprintf fmt "@[%a %s@ %a@]" format_value l (string_of_relop op) format_value r | Logop (_,op,l,r) -> Format.fprintf fmt "@[%a %s@ %a@]" format_value l (string_of_logop op) format_value r | Pfxop (_,op,r) -> Format.fprintf fmt "@[%s%a@]" (string_of_pfxop op) format_value r | Prefix_relop (_,op,r) -> Format.fprintf fmt "@[%s@ %a@]" (string_of_relop op) format_value r | Ident (_,s) -> Format.fprintf fmt "%s" s | Int (_,i) -> Format.fprintf fmt "%d" i | Bool (_,b) -> Format.fprintf fmt "%b" b | String (_,s) -> if String.contains s '\n' then Format.fprintf fmt "@[\"\n%s@\n\"@]" (escape_string s) else Format.fprintf fmt "\"%s\"" (escape_string s) | List (_, l) -> Format.fprintf fmt "@[[@;<0 2>@[%a@]@,]@]" format_values l | Group (_,g) -> Format.fprintf fmt "@[(%a)@]" format_values g | Option(_,v,l) -> Format.fprintf fmt "@[%a@ {@[%a@]}@]" format_value v format_values l | Env_binding (_,op,id,v) -> Format.fprintf fmt "@[[ %a %s@ %a ]@]" format_value id op format_value v and format_values fmt = function | [] -> () | [v] -> format_value fmt v | v::r -> format_value fmt v; Format.pp_print_space fmt (); format_values fmt r let string_of_value v = format_value Format.str_formatter v; Format.flush_str_formatter () let string_of_values vs = format_values Format.str_formatter vs; Format.flush_str_formatter () let rec format_item fmt = function | Variable (_, _, List (_,[])) -> () | Variable (_, _, List (_,[List(_,[])])) -> () | Variable (_, i, List (_,l)) -> if List.exists (function List _ | Option (_,_,_::_) -> true | _ -> false) l then Format.fprintf fmt "@[%s: [@;<0 2>@[%a@]@,]@]" i format_values l else Format.fprintf fmt "@[%s: [@;<0 2>@[%a@]@,]@]" i format_values l | Variable (_, i, v) -> Format.fprintf fmt "@[%s:@ %a@]" i format_value v | Section (_,s) -> Format.fprintf fmt "%s \"%s\" {@[%a@]}" s.section_kind (escape_string s.section_name) format_items s.section_items and format_items fmt is = Format.pp_open_vbox fmt 0; List.iter (fun i -> format_item fmt i; Format.pp_print_cut fmt ()) is; Format.pp_close_box fmt () let string_of_item i = format_item Format.str_formatter i; Format.flush_str_formatter () let string_of_items l = format_items Format.str_formatter l; Format.flush_str_formatter () let rec simplify_items items = List.map (function | Variable (pos, name, List (_, [(String _ | List _) as v])) -> Variable (pos, name, v) | Section (pos, s) -> Section (pos, {s with section_items = simplify_items s.section_items}) | i -> i) items let string_of_file ~simplify f = let items = if simplify then simplify_items f.file_contents else f.file_contents in string_of_items items (* Reading section contents *) let assoc items n parse = try parse (List.assoc n (variables items)) with Not_found -> bad_format "Field %S is missing" n let get_all_section_by_kind items kind = try List.rev_map snd (List.find_all (fun (k,_) -> k=kind) (sections items)) with Not_found -> bad_format "Section kind %S is missing" kind let get_section_by_kind items kind = try snd (List.find (fun (k,_) -> k=kind) (sections items)) with Not_found -> bad_format "Section kind %S is missing" kind let assoc_sections items kind parse = List.rev_map parse (get_all_section_by_kind items kind) let assoc_option items n parse = try Some (parse (List.assoc n (variables items))) with Not_found -> None let assoc_default d items n parse = try parse (List.assoc n (variables items)) with Not_found -> d let assoc_list items n parse = try parse (List.assoc n (variables items)) with Not_found -> [] let assoc_string_list s n = assoc_list s n (parse_list parse_string) let make_section s = Section (pos_null, s) let make_variable (k, v) = Variable (pos_null, k, v) (* Parse any constraint list *) let rec parse_constraints t = let rec aux = function | Prefix_relop (_, op, (String (_,v))) -> Atom (op, OpamPackage.Version.of_string v) | Logop (_, `And, l, r) -> And (aux l, aux r) | Logop (_, `Or, l, r) -> Or (aux l, aux r) | Pfxop (_,`Not,v) -> OpamFormula.neg (fun (op, s) -> (OpamFormula.neg_relop op, s)) (aux v) | Group (_, g) -> Block (parse_constraints g) | x -> bad_format ~pos:(value_pos x) "Expected a list of constraints" in OpamFormula.ands (List.map aux t) let lift_list = function | List (_, l) -> l | x -> [x] let rec make_constraints t = let rec aux = function | Empty -> assert false | Atom (r, v) -> Prefix_relop (pos_null, r, make_string (OpamPackage.Version.to_string v)) | And (x, y) -> Logop (pos_null, `And, aux x, aux y) | Or (x, y) -> Logop (pos_null, `Or, aux x, aux y) | Block g -> Group (pos_null, make_constraints g) in match t with | Empty -> [] | t -> [aux t] let parse_dep_flag = function | Ident (_, "build") -> Depflag_Build | Ident (_, "test") -> Depflag_Test | Ident (_, "doc") -> Depflag_Doc | Ident (_, "dev") -> Depflag_Dev | Ident (_, s) -> Depflag_Unknown s | x -> bad_format ~pos:(value_pos x) "Invalid dependency flag %s, must be an ident" (string_of_value x) let make_dep_flag = function | Depflag_Build -> make_ident "build" | Depflag_Test -> make_ident "test" | Depflag_Doc -> make_ident "doc" | Depflag_Dev -> make_ident "dev" | Depflag_Unknown s -> make_ident s (* Version constraints with additional leading keywords ("build","test"...) *) let rec parse_ext_constraints = function | Ident (_, _) as kw :: r -> let kws, f = parse_ext_constraints r in parse_dep_flag kw :: kws, f | Logop (_, `And, t1, t2) :: r -> parse_ext_constraints (t1::t2::r) | t -> [], parse_constraints t let make_ext_constraints (kws, t) = (* The kws must be aggregated with an '&' to the first constraint, if any *) match make_constraints t, kws with | [], [] -> [] | [], kw::kws -> [List.fold_left (fun acc kw -> Logop (pos_null, `And, make_dep_flag kw, acc)) (make_dep_flag kw) kws] | c::cs, kws -> List.fold_left (fun acc kw -> Logop (pos_null, `And, make_dep_flag kw, acc)) c kws :: cs let parse_package_name ?expected = function | String (pos,n) -> let name = (try OpamPackage.Name.of_string n with | Failure _ -> bad_format ~pos "Invalid package name %s" n) in (match expected with | Some exp when name <> exp -> bad_format ~pos "Unexpected name %s" (OpamPackage.Name.to_string name) | _ -> name) | x -> bad_format ~pos:(value_pos x) "Expected a package name" let parse_package_version ?expected = function | String (pos,n) -> let version = OpamPackage.Version.of_string n in (match expected with | Some exp when version <> exp -> bad_format ~pos "Unexpected version %s" (OpamPackage.Version.to_string version) | _ -> version) | x -> bad_format ~pos:(value_pos x) "Expected a package version" (* parse a list of formulas *) let rec parse_formulas opt ~constraints t = let rec aux = function | String _ as t -> Atom (parse_package_name t, constraints []) | Option (_, t, g) -> Atom (parse_package_name t, constraints g) | Group (_,g) -> Block (parse_formulas opt ~constraints (List (pos_null, g))) | Logop (_, `Or, e1, e2) -> let left = aux e1 in Or (left, aux e2) | Logop (_, `And, e1, e2) -> let left = aux e1 in And (left, aux e2) | x -> bad_format ~pos:(value_pos x) "Expected a formula list of the form [ \"item\" {condition}... ]" in OpamFormula.(if opt then ors else ands) (List.map aux (lift_list t)) let rec make_formulas opt ~constraints t = let name = OpamPackage.Name.to_string in let rec aux = function | Empty -> assert false | Block f -> Group (pos_null, lift_list (make_formulas opt ~constraints f)) | And(e,f) -> Logop (pos_null, `And, aux e, aux f) | Or(e,f) -> Logop (pos_null, `Or, aux e, aux f) | Atom (n, cs) -> match constraints cs with | [] -> make_string (name n) | cs -> Option (pos_null, make_string (name n), cs) in let to_list = OpamFormula.(if opt then ors_to_list else ands_to_list) in List (pos_null, List.map aux (to_list t)) let make_formula = make_formulas false ~constraints:make_constraints let make_ext_formula = make_formulas false ~constraints:make_ext_constraints let parse_formula = parse_formulas false ~constraints:parse_constraints let parse_ext_formula = parse_formulas false ~constraints:parse_ext_constraints let parse_opt_formula = parse_formulas true ~constraints:parse_ext_constraints let make_opt_formula = make_formulas true ~constraints:make_ext_constraints let parse_compiler_version = function | Ident (_,v) when v = OpamCompiler.to_string OpamCompiler.system -> OpamCompiler.Version.of_string v | String (pos,v) -> (try OpamCompiler.Version.of_string v with Invalid_argument msg -> bad_format ~pos "%s" msg) | x -> bad_format ~pos:(value_pos x) "Expected a compiler version" let rec parse_compiler_constraint t = let rec aux = function | Prefix_relop (_, op, v) -> Atom (op, parse_compiler_version v) | Group (_, g) -> Block (parse_compiler_constraint (List (pos_null,g))) | Logop (_, `Or, e1, e2) -> Or (aux e1, aux e2) | Logop (_, `And, e1, e2) -> And (aux e1, aux e2) | Pfxop (_,`Not,v) -> OpamFormula.neg (fun (op, s) -> (OpamFormula.neg_relop op, s)) (aux v) | x -> bad_format ~pos:(value_pos x) "Expected a compiler constraint" in OpamFormula.ors (List.map aux (lift_list t)) let rec make_compiler_constraint t = let rec aux = function | Empty -> assert false | Atom (op, v) -> let system = OpamCompiler.to_string OpamCompiler.system in let v = if OpamCompiler.Version.to_string v = system then make_ident system else make_string (OpamCompiler.Version.to_string v) in Prefix_relop (pos_null,op,v) | Block f -> Group (pos_null, lift_list (make_compiler_constraint f)) | And(e,f) -> Logop (pos_null, `And, aux e, aux f) | Or(e,f) -> Logop (pos_null, `Or, aux e, aux f) in match t with | Empty -> List (pos_null, []) | t -> List (pos_null, List.map aux (OpamFormula.ors_to_list t)) let rec parse_os_constraint l = let rec aux = function | Group (_,g) -> Block (parse_os_constraint (List (pos_null,g))) | String (_,os) -> Atom (true, os) | Logop (_,`And,l,r) -> And (aux l, aux r) | Logop (_,`Or,l,r) -> Or (aux l, aux r) | Pfxop (_,`Not,v) -> OpamFormula.neg (fun (b, s) -> (not b, s)) (aux v) | x -> bad_format ~pos:(value_pos x) "Expected an OS constraint" in OpamFormula.ors (List.map aux (lift_list l)) let rec make_os_constraint l = let rec aux = function | Empty -> assert false | Atom (true , os) -> make_string os | Atom (false, os) -> Pfxop (pos_null, `Not, make_string os) | Block g -> Group (pos_null, lift_list (make_os_constraint g)) | And(e,f) -> Logop (pos_null, `And, aux e, aux f) | Or(e,f) -> Logop (pos_null, `Or, aux e, aux f) in match l with | Empty -> List (pos_null, []) | l -> let l = if !OpamGlobals.all_parens then [l] else OpamFormula.ors_to_list l in List (pos_null, List.map aux l) let parse_env_variable l = let aux = function | Relop (_, `Eq, Ident (_,i), String (_,s)) -> i, "=", s | Env_binding (_, op, Ident (_,i), String (_,s)) -> i, op, s | x -> bad_format ~pos:(value_pos x) "Expected an \"ident = string\" binding" in match l with List (_,[x]) | x -> aux x let make_env_variable (ident, op, string) = Env_binding (pos_null, op, make_ident ident, make_string string) (* Filters *) let parse_filter_ident = function | Ident (pos, s) -> (try FIdent (filter_ident_of_string s) with Failure msg -> bad_format ~pos "%s" msg) | x -> bad_format ~pos:(value_pos x) "Expected a filter ident: \ [pkg[+pkg...]:]varname[?str_if_true:str_if_false_or_undef]" let rec parse_filter l = let rec aux = function | Bool (_,b) -> FBool b | String (_,s) -> FString s | Ident _ as id -> parse_filter_ident id | Group (_,g) -> parse_filter g | Relop (_,op,e,f) -> FOp (aux e, op, aux f) | Pfxop (_,`Not,e) -> FNot (aux e) | Logop(_,`And,e,f)-> FAnd (aux e, aux f) | Logop(_,`Or, e,f)-> FOr (aux e, aux f) | x -> bad_format ~pos:(value_pos x) "Expected a filter expression" in match l with | [] -> FBool true | [Group (_, ([] | _::_::_))] | _::_::_ as x -> bad_format ?pos:(values_pos x) "Expected a single filter expression" | [Group(_,[f])] | [f] -> aux f let lift = function | [x] -> x | l -> let pos = match values_pos l with Some p -> p | None -> pos_null in Group (pos, l) let make_filter f = let rec aux ?paren f = match f with | FString s -> make_string s | FIdent (pkgs,var,converter) -> let s = OpamMisc.sconcat_map ~nil:"" "+" ~right:":" OpamPackage.Name.to_string pkgs ^ OpamVariable.to_string var ^ (match converter with | Some (it,ifu) -> "?"^it^":"^ifu | None -> "") in make_ident s | FBool b -> make_bool b | FOp(e,s,f) -> let f = Relop (pos_null, s, aux e, aux f) in if !OpamGlobals.all_parens then Group (pos_null, [f]) else f | FOr(e,f) -> (* And, Or have the same priority, left-associative *) let f = Logop (pos_null, `Or, aux e, aux ~paren:`Or f) in if !OpamGlobals.all_parens then Group (pos_null, [f]) else (match paren with None | Some `Or -> f | _ -> Group (pos_null, [f])) | FAnd(e,f) -> let f = Logop (pos_null, `And, aux e, aux ~paren:`And f) in if !OpamGlobals.all_parens then Group (pos_null, [f]) else (match paren with None | Some `And -> f | _ -> Group (pos_null, [f])) | FNot f -> let f = Pfxop (pos_null, `Not, aux ~paren:`Not f) in if !OpamGlobals.all_parens then Group (pos_null, [f]) else f | FUndef -> make_ident "#undefined" in [aux f] let make_simple_arg = function | CString s -> make_string s | CIdent s -> make_ident s let make_arg = make_option make_simple_arg make_filter let make_single_command = make_list make_arg let make_command = make_option (make_list make_arg) make_filter let make_commands = make_list make_command let make_libraries = make_list (make_option make_string make_filter) let parse_libraries = parse_list (parse_option parse_string parse_filter) let parse_simple_arg = parse_or [ "ident" , (parse_ident @> fun x -> CIdent x); "string", (parse_string @> fun x -> CString x); ] let parse_arg = parse_option parse_simple_arg parse_filter let parse_single_command = parse_list parse_arg let parse_command = parse_option (parse_list parse_arg) parse_filter let parse_commands = parse_or [ "command" , (fun x -> [parse_command x]); "command-list", parse_list parse_command; ] let parse_message = parse_option (parse_string @> OpamMisc.strip) parse_filter let parse_messages = parse_list parse_message let make_flag = function | Pkgflag_LightUninstall -> make_ident "light-uninstall" | Pkgflag_AllSwitches -> make_ident "all-switches" | Pkgflag_Verbose -> make_ident "verbose" | Pkgflag_Plugin -> make_ident "plugin" | Pkgflag_Unknown s -> make_ident s let parse_flag = function | Ident (_,"light-uninstall") -> Pkgflag_LightUninstall | Ident (_,"all-switches") -> Pkgflag_AllSwitches | Ident (_,"verbose") -> Pkgflag_Verbose | Ident (_,"plugin") -> Pkgflag_Plugin | Ident (_,s) -> Pkgflag_Unknown s | x -> bad_format ~pos:(value_pos x) "Invalid package flag %s, must be an ident" (string_of_value x) (* TAGS *) let parse_string_set = parse_string_list @> OpamMisc.StringSet.of_list let make_string_set = OpamMisc.StringSet.elements @> make_string_list let parse_tag_line = let fn = parse_string_set in parse_pair fn fn let make_tag_line = let fn = make_string_set in make_pair fn fn let parse_tags v = let l = parse_or [ "tag" , (fun x -> [parse_tag_line x]); "tags", (parse_list parse_tag_line); ] v in OpamMisc.StringSetMap.of_list l let make_tags t = let l = OpamMisc.StringSetMap.bindings t in make_list make_tag_line l (* FEATURES *) let parse_features t = let rec aux = function | [] -> [] | id :: opt :: r -> let id = OpamVariable.of_string (parse_ident id) in (match parse_option parse_string parse_filter opt with | doc, Some fil -> (id, doc, fil) :: aux r | _, None -> bad_format ~pos:(value_pos opt) "Expecting a filter definition, e.g. \ `var \"Enable var\" { }'") | t -> bad_format ?pos:(values_pos t) "Bad feature definition, expected \ `var \"Enable var\" { }'" in match t with | List (_, l) -> aux l | _ -> bad_format ~pos:(value_pos t) "Expected a list of feature definitions" let make_features feat = let rec aux = function | [] -> [] | (var,doc,fil) :: r -> make_ident (OpamVariable.to_string var) :: make_option make_string make_filter (doc, Some fil) :: aux r in List (pos_null, aux feat) opam-full-1.2.2/src/core/opamPath.ml0000644000175000017500000001537412517374212015766 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamFilename.OP type t = dirname let root () = OpamFilename.Dir.of_string !OpamGlobals.root_dir let config t = t // "config" let state_cache t = t // "state.cache" let update_cache t = t // "update.cache" let lock t = t // "lock" let aliases t = t // "aliases" let packages_dir t = t / "packages" let packages t nv = packages_dir t / OpamPackage.Name.to_string (OpamPackage.name nv) / OpamPackage.to_string nv let opam t nv = packages t nv // "opam" let url t nv = packages t nv // "url" let descr t nv = packages t nv // "descr" let archives_dir t = t / "archives" let archive t nv = archives_dir t // (OpamPackage.to_string nv ^ "+opam.tar.gz") let files t nv = packages t nv / "files" let compilers_dir t = t / "compilers" let compilers t c = compilers_dir t / OpamCompiler.Version.to_string (OpamCompiler.version c) / OpamCompiler.to_string c let compiler_comp t c = compilers t c // (OpamCompiler.to_string c ^ ".comp") let compiler_descr t c = compilers t c // (OpamCompiler.to_string c ^ ".descr") let package_index t = t / "repo" // "package-index" let compiler_index t = t / "repo" // "compiler-index" let init t = t / "opam-init" let log t = t / "log" let dev_packages_dir t = t / "packages.dev" let dev_package t nv = dev_packages_dir t / OpamPackage.to_string nv let backup_file () = Unix.( let tm = gmtime OpamGlobals.global_start_time in Printf.sprintf "state-%04d%02d%02d%02d%02d%02d.export" (tm.tm_year+1900) tm.tm_mon tm.tm_mday tm.tm_hour tm.tm_min tm.tm_sec ) let backup_dir t = t / "backup" let backup t = backup_dir t // backup_file () module Switch = struct let root t a = t / OpamSwitch.to_string a let lock t a = root t a // "lock" let backup_dir t a = root t a / "backup" let backup t a = backup_dir t a // backup_file () let lib_dir t a = root t a / "lib" let lib t a n = lib_dir t a / OpamPackage.Name.to_string n let stublibs t a = lib_dir t a / "stublibs" let toplevel t a = lib_dir t a / "toplevel" let doc_dir t a = root t a / "doc" let man_dir ?num t a = match num with | None -> root t a / "man" | Some n -> root t a / "man" / ("man" ^ n) let share_dir t a = root t a / "share" let share t a n = share_dir t a / OpamPackage.Name.to_string n let etc_dir t a = root t a / "etc" let etc t a n = etc_dir t a / OpamPackage.Name.to_string n let doc t a n = doc_dir t a / OpamPackage.Name.to_string n let bin t a = root t a / "bin" let sbin t a = root t a / "sbin" let installed t a = root t a // "installed" let installed_roots t a = root t a // "installed.roots" let build_dir t a = root t a / "build" let build t a nv = build_dir t a / OpamPackage.to_string nv let build_ocaml t a = build_dir t a / "ocaml" let build_install t a nv = build t a nv // (OpamPackage.Name.to_string (OpamPackage.name nv) ^ ".install") let build_config t a nv = build t a nv // (OpamPackage.Name.to_string (OpamPackage.name nv) ^ ".config") let install_dir t a = root t a / "install" let install t a n = install_dir t a // (OpamPackage.Name.to_string n ^ ".install") let reinstall t a = root t a // "reinstall" let config_dir t a = root t a / "config" let config t a n = lib t a n // "opam.config" let global_config t a = config_dir t a // "global-config.config" let pinned t a = root t a // "pinned" let dev_packages_dir t a = root t a / "packages.dev" let dev_package t a name = dev_packages_dir t a / OpamPackage.Name.to_string name module Overlay = struct let dir t a = root t a / "overlay" let package t a n = dir t a / OpamPackage.Name.to_string n let opam t a n = package t a n // "opam" let tmp_opam t a n = package t a n // "opam_" let url t a n = package t a n // "url" let descr t a n = package t a n // "descr" let files t a n = package t a n / "files" end end module Repository = struct let root t = t.repo_root let update_cache t = root t // "update.cache" let create root name = root / "repo" / OpamRepositoryName.to_string name let repo t = root t // "repo" let remote_repo t = OpamFilename.raw_dir (fst t.repo_address) // "repo" let raw_config root name = root / "repo" / OpamRepositoryName.to_string name // "config" let config t = root t // "config" let packages_dir t = root t / "packages" let remote_packages_dir t = OpamFilename.raw_dir (fst t.repo_address) / "packages" let packages t prefix nv = match prefix with | None -> packages_dir t / OpamPackage.to_string nv | Some p -> packages_dir t / p / OpamPackage.to_string nv let opam t prefix nv = packages t prefix nv // "opam" let descr t prefix nv = packages t prefix nv // "descr" let url t prefix nv = packages t prefix nv // "url" let files t prefix nv = packages t prefix nv / "files" let archives_dir t = root t / "archives" let archive t nv = archives_dir t // (OpamPackage.to_string nv ^ "+opam.tar.gz") let remote_archive t nv = OpamFilename.raw_dir (fst t.repo_address) / "archives" // (OpamPackage.to_string nv ^ "+opam.tar.gz") let upload_dir t = root t / "upload" let compilers_dir t = root t / "compilers" let remote_compilers_dir t = OpamFilename.raw_dir (fst t.repo_address) / "compilers" let compiler_comp t prefix c = match prefix with | None -> compilers_dir t // (OpamCompiler.to_string c ^ ".comp") | Some p -> compilers_dir t / p // (OpamCompiler.to_string c ^ ".comp") let compiler_descr t prefix c = match prefix with | None -> compilers_dir t // (OpamCompiler.to_string c ^ ".descr") | Some p -> compilers_dir t / p // (OpamCompiler.to_string c ^ ".descr") end opam-full-1.2.2/src/core/opamSwitch.ml0000644000175000017500000000247312517374212016327 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) include OpamMisc.Base let default = of_string OpamGlobals.system let not_installed s = OpamGlobals.error_and_exit "The compiler switch %s is not installed." (to_string s) opam-full-1.2.2/src/core/opamFilename.ml0000644000175000017500000003060312517374212016602 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) module Base = OpamMisc.Base open OpamProcess.Job.Op let log fmt = OpamGlobals.log "FILENAME" fmt let slog = OpamGlobals.slog module Dir = struct include OpamMisc.Base let of_string dirname = let dirname = if dirname = "~" then OpamGlobals.home else if OpamMisc.starts_with ~prefix:("~"^Filename.dir_sep) dirname then Filename.concat OpamGlobals.home (OpamMisc.remove_prefix ~prefix:("~"^Filename.dir_sep) dirname) else dirname in OpamSystem.real_path dirname let to_string dirname = dirname end let raw_dir s = s let with_tmp_dir fn = OpamSystem.with_tmp_dir (fun dir -> fn (Dir.of_string dir)) let with_tmp_dir_job fjob = OpamSystem.with_tmp_dir_job (fun dir -> fjob (Dir.of_string dir)) let rmdir dirname = OpamSystem.remove_dir (Dir.to_string dirname) let cwd () = Dir.of_string (Unix.getcwd ()) let mkdir dirname = OpamSystem.mkdir (Dir.to_string dirname) let cleandir dirname = log "cleandir %a" (slog Dir.to_string) dirname; OpamSystem.remove (Dir.to_string dirname); mkdir dirname let rec_dirs d = let fs = OpamSystem.rec_dirs (Dir.to_string d) in List.rev (List.rev_map Dir.of_string fs) let dirs d = let fs = OpamSystem.dirs (Dir.to_string d) in List.rev (List.rev_map Dir.of_string fs) let dir_is_empty d = OpamSystem.dir_is_empty (Dir.to_string d) let in_dir dirname fn = OpamSystem.in_dir dirname fn let env_of_list l = Array.of_list (List.rev_map (fun (k,v) -> k^"="^v) l) let exec dirname ?env ?name ?metadata ?keep_going cmds = let env = match env with | None -> None | Some l -> Some (env_of_list l) in in_dir dirname (fun () -> OpamSystem.commands ?env ?name ?metadata ?keep_going cmds) let move_dir ~src ~dst = OpamSystem.command ~verbose:(OpamSystem.verbose_for_base_commands ()) [ "mv"; Dir.to_string src; Dir.to_string dst ] let exists_dir dirname = try (Unix.stat (Dir.to_string dirname)).Unix.st_kind = Unix.S_DIR with Unix.Unix_error _ -> false let copy_dir ~src ~dst = if exists_dir dst then OpamSystem.internal_error "Cannot create %s as the directory already exists." (Dir.to_string dst); OpamSystem.command ~verbose:(OpamSystem.verbose_for_base_commands ()) [ "cp"; "-PR"; Dir.to_string src; Dir.to_string dst ] let link_dir ~src ~dst = if exists_dir dst then OpamSystem.internal_error "Cannot link: %s already exists." (Dir.to_string dst) else ( mkdir (Filename.dirname dst); OpamSystem.link (Dir.to_string src) (Dir.to_string dst) ) let basename_dir dirname = Base.of_string (Filename.basename (Dir.to_string dirname)) let dirname_dir dirname = Dir.to_string (Filename.dirname (Dir.of_string dirname)) let to_list_dir dir = let base d = Dir.of_string (Filename.basename (Dir.to_string d)) in let rec aux acc dir = let d = dirname_dir dir in if d <> dir then aux (base dir :: acc) d else base dir :: acc in aux [] dir let (/) d1 s2 = let s1 = Dir.to_string d1 in raw_dir (Filename.concat s1 s2) type t = { dirname: Dir.t; basename: Base.t; } let create dirname basename = let b1 = Filename.dirname (Base.to_string basename) in let b2 = Base.of_string (Filename.basename (Base.to_string basename)) in if basename = b2 then { dirname; basename } else { dirname = dirname / b1; basename = b2 } let of_basename basename = let dirname = Dir.of_string "." in { dirname; basename } let raw str = let dirname = raw_dir (Filename.dirname str) in let basename = Base.of_string (Filename.basename str) in create dirname basename let to_string t = Filename.concat (Dir.to_string t.dirname) (Base.to_string t.basename) let digest t = Digest.to_hex (Digest.file (to_string t)) let touch t = OpamSystem.write (to_string t) "" let chmod t p = Unix.chmod (to_string t) p let of_string s = let dirname = Filename.dirname s in let basename = Filename.basename s in { dirname = Dir.of_string dirname; basename = Base.of_string basename; } let dirname t = t.dirname let basename t = t.basename let read filename = OpamSystem.read (to_string filename) let open_in filename = try open_in (to_string filename) with Sys_error _ -> raise (OpamSystem.File_not_found (to_string filename)) let open_out filename = try open_out (to_string filename) with Sys_error _ -> raise (OpamSystem.File_not_found (to_string filename)) let write filename raw = OpamSystem.write (to_string filename) raw let remove filename = OpamSystem.remove_file (to_string filename) let exists filename = try (Unix.stat (to_string filename)).Unix.st_kind = Unix.S_REG with Unix.Unix_error _ -> false let with_contents fn filename = fn (read filename) let check_suffix filename s = Filename.check_suffix (to_string filename) s let add_extension filename suffix = of_string ((to_string filename) ^ "." ^ suffix) let chop_extension filename = of_string (Filename.chop_extension (to_string filename)) let rec_files d = let fs = OpamSystem.rec_files (Dir.to_string d) in List.rev_map of_string fs let files d = let fs = OpamSystem.files (Dir.to_string d) in List.rev_map of_string fs let copy ~src ~dst = if src <> dst then OpamSystem.copy (to_string src) (to_string dst) let install ?exec ~src ~dst () = if src <> dst then OpamSystem.install ?exec (to_string src) (to_string dst) let move ~src ~dst = if src <> dst then OpamSystem.command ~verbose:(OpamSystem.verbose_for_base_commands ()) [ "mv"; to_string src; to_string dst ] let link ~src ~dst = if src <> dst then OpamSystem.link (to_string src) (to_string dst) let readlink src = if exists src then try of_string (Unix.readlink (to_string src)) with Unix.Unix_error _ -> src else OpamSystem.internal_error "%s does not exist." (to_string src) let is_symlink src = try let s = Unix.lstat (to_string src) in s.Unix.st_kind = Unix.S_LNK with Unix.Unix_error _ -> OpamSystem.internal_error "%s does not exist." (to_string src) let is_exec file = try OpamSystem.is_exec (to_string file) with Unix.Unix_error _ -> OpamSystem.internal_error "%s does not exist." (to_string file) let starts_with dirname filename = OpamMisc.starts_with ~prefix:(Dir.to_string dirname) (to_string filename) let remove_prefix prefix filename = let prefix = let str = Dir.to_string prefix in if str = "" then "" else Filename.concat str "" in let filename = to_string filename in OpamMisc.remove_prefix ~prefix filename let process_in ?root fn src dst = let basename = match root with | None -> basename src | Some r -> if starts_with r src then remove_prefix r src else OpamSystem.internal_error "%s is not a prefix of %s" (Dir.to_string r) (to_string src) in let dst = Filename.concat (Dir.to_string dst) basename in fn ~src ~dst:(of_string dst) let copy_in ?root = process_in ?root copy let link_in = process_in link let extract filename dirname = OpamSystem.extract (to_string filename) (Dir.to_string dirname) let extract_in filename dirname = OpamSystem.extract_in (to_string filename) (Dir.to_string dirname) type generic_file = | D of Dir.t | F of t let extract_generic_file filename dirname = match filename with | F f -> log "extracting %a to %a" (slog to_string) f (slog Dir.to_string) dirname; extract f dirname | D d -> if d <> dirname then ( log "copying %a to %a" (slog Dir.to_string) d (slog Dir.to_string) dirname; copy_dir ~src:d ~dst:dirname ) let ends_with suffix filename = OpamMisc.ends_with ~suffix (to_string filename) let remove_suffix suffix filename = let suffix = Base.to_string suffix in let filename = to_string filename in OpamMisc.remove_suffix ~suffix filename let download ~overwrite ?compress ?checksum filename dirname = mkdir dirname; let dst = to_string (create dirname (basename filename)) in OpamSystem.download ~overwrite ?compress ?checksum ~filename:(to_string filename) ~dst @@+ fun file -> Done (of_string file) let download_as ~overwrite ?(compress=false) ?checksum filename dest = mkdir (dirname dest); OpamSystem.download ~overwrite ~compress ?checksum ~filename:(to_string filename) ~dst:(to_string dest) @@+ fun file -> assert (file = to_string dest); Done () let patch filename dirname = in_dir dirname (fun () -> OpamSystem.patch (to_string filename)) let with_flock ?read file f x = let lock = OpamSystem.flock ?read (to_string file) in try let r = f x in OpamSystem.funlock lock; r with e -> OpamMisc.register_backtrace e; OpamSystem.funlock lock; raise e let checksum f = if exists f then [digest f] else [] let checksum_dir d = if exists_dir d then List.map digest (rec_files d) else [] let prettify_dir d = OpamMisc.prettify_path (Dir.to_string d) let prettify s = OpamMisc.prettify_path (to_string s) let to_json x = `String (to_string x) module O = struct type tmp = t type t = tmp let compare = compare let to_string = to_string let to_json = to_json end module Map = OpamMisc.Map.Make(O) module Set = OpamMisc.Set.Make(O) let copy_files ~src ~dst = let files = rec_files src in List.iter (fun file -> if not !OpamGlobals.do_not_copy_files then let base = remove_prefix src file in let dst_file = create dst (Base.of_string base) in if !OpamGlobals.verbose_level >= 2 then OpamGlobals.msg "Copying %s %s %s/\n" (prettify file) (if exists dst_file then "over" else "to") (prettify_dir dst); copy ~src:file ~dst:dst_file ) files module OP = struct let (/) = (/) let (//) d1 s2 = let d = Filename.dirname s2 in let b = Filename.basename s2 in if d <> "." then create (d1 / d) (Base.of_string b) else create d1 (Base.of_string s2) end module Attribute = struct type t = { base: Base.t; md5 : string; perm: int option; } let base t = t.base let md5 t = t.md5 let perm t = t.perm let create base md5 perm = { base; md5; perm=Some perm } let to_string_list t = let perm = match t.perm with | None -> [] | Some p -> [Printf.sprintf "0o%o" p] in Base.to_string t.base :: t.md5 :: perm let of_string_list = function | [base; md5] -> { base=Base.of_string base; md5; perm=None } | [base;md5; perm] -> { base=Base.of_string base; md5; perm=Some (int_of_string perm) } | k -> OpamSystem.internal_error "remote_file: '%s' is not a valid line." (String.concat " " k) let to_string t = String.concat " " (to_string_list t) let of_string s = of_string_list (OpamMisc.split s ' ') let to_json x = `O ([ ("base" , Base.to_json x.base); ("md5" , `String x.md5)] @ match x. perm with | None -> [] | Some p -> ["perm", `String (string_of_int p)]) module O = struct type tmp = t type t = tmp let to_string = to_string let compare = compare let to_json = to_json end module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) end let to_attribute root file = let basename = Base.of_string (remove_prefix root file) in let perm = let s = Unix.stat (to_string file) in s.Unix.st_perm in let digest = digest file in Attribute.create basename digest perm opam-full-1.2.2/src/core/core.ocp0000644000175000017500000000143712517374212015311 0ustar useruserbegin library "opam-core" sort = false files = [ "opamCompat.ml" "opamScript.ml" "opamJson.ml" "opamMisc.ml" "opamGlobals.ml" "opamVersion.ml" "opamProcess.ml" "opamParallel.ml" "opamSystem.ml" "opamFilename.ml" "opamActionGraph.ml" "opamSwitch.ml" "opamPackage.ml" "opamFormula.ml" "opamCompiler.ml" "opamVariable.ml" "opamRepositoryName.ml" "opamTypes.mli" "opamTypesBase.ml" "opamFormat.ml" "opamParser.mly" "opamLexer.mll" "opamLineLexer.mll" "opamPath.ml" "opamFilter.ml" "opamFile.ml" "opamRepository.ml" ] requires = [ "cudf" "dose3" "dose3.algo" "dose3.common" "dose3.debian" "unix" "ocamlgraph" "re.glob" "re.str" "jsonm" ] end opam-full-1.2.2/src/core/opamFile.ml0000644000175000017500000025125612517374212015752 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamMisc.OP module X = struct module Lines = struct (* Lines of space separated words *) type t = string list list let empty = [] let internal = "lines" let find_escapes s len = let rec aux acc i = if i < 0 then acc else let acc = match s.[i] with | '\\' | ' ' | '\t' | '\n' -> let esc,count = acc in i::esc, count + 1 | _ -> acc in aux acc (i-1) in aux ([],0) (len - 1) let escape_spaces str = let len = String.length str in match find_escapes str len with | [], _ -> str | escapes, n -> let buf = Bytes.create (len + n) in let rec aux i = function | ofs1::(ofs2::_ as r) -> Bytes.blit_string str ofs1 buf (ofs1+i) (ofs2-ofs1); Bytes.set buf (ofs2+i) '\\'; aux (i+1) r | [ofs] -> Bytes.blit_string str ofs buf (ofs+i) (len-ofs); buf | [] -> assert false in Bytes.to_string (aux 0 (0::escapes)) let of_channel (_:filename) ic = OpamLineLexer.main (Lexing.from_channel ic) let to_string (_:filename) (lines: t) = let buf = Buffer.create 1024 in List.iter (fun l -> (match l with | [] -> () | w::r -> Buffer.add_string buf (escape_spaces w); List.iter (fun w -> Buffer.add_char buf ' '; Buffer.add_string buf (escape_spaces w)) r); Buffer.add_string buf "\n" ) lines; Buffer.contents buf end module Syntax = struct type t = file let of_channel (filename:filename) (ic:in_channel) = let lexbuf = Lexing.from_channel ic in let filename = OpamFilename.to_string filename in lexbuf.Lexing.lex_curr_p <- { lexbuf.Lexing.lex_curr_p with Lexing.pos_fname = filename }; OpamParser.main OpamLexer.token lexbuf filename let to_string (t: t) = OpamFormat.string_of_file ~simplify:true t let s_opam_version = "opam-version" let check_opam_version = let already_warned = ref false in fun ?(allow_major=false) f v -> let diff_full = OpamVersion.(compare current v) in if diff_full >= 0 then true else let diff_major = OpamVersion.(compare (major current) (major v)) in if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: %s refers to OPAM %s, this is %s." f.file_name (OpamVersion.to_string v) OpamVersion.(to_string current); if diff_major < 0 && not allow_major then OpamFormat.bad_format ~pos:OpamFormat.(assoc f.file_contents s_opam_version value_pos) "Can't read OPAM %s files yet, this is OPAM %s." (OpamVersion.to_string v) OpamVersion.(to_string current); if not (!already_warned) then OpamGlobals.note "File %s is written for OPAM %s, and this is %s.\n\ It may depend on new features, consider upgrading." f.file_name (OpamVersion.to_string v) OpamVersion.(to_string current); already_warned := true; false (* Prints warnings or fails in strict mode; returns true if permissive mode is enabled *) let check ?allow_major ?(versioned=true) = fun f fields -> if not !OpamGlobals.strict && not !OpamGlobals.debug then true else let f_opam_version = if List.mem s_opam_version fields then OpamFormat.assoc_option f.file_contents s_opam_version (OpamFormat.parse_string @> OpamVersion.of_string) else None in (* Reading a file with a newer minor version triggers permissive mode: silently ignore new fields and try to be more tolerant *) let permissive_mode = match f_opam_version with | Some v -> not (check_opam_version ?allow_major f v) | None -> if versioned then ( if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: %s missing the opam-version field" (OpamMisc.prettify_path f.file_name); OpamGlobals.warning "%s is missing the 'opam-version:' field." (OpamMisc.prettify_path f.file_name); true ) else false in if not permissive_mode && not (OpamFormat.is_valid f.file_contents fields) then let invalids = OpamFormat.invalid_fields f.file_contents fields in let too_many, invalids = List.partition (fun x -> List.mem x fields) invalids in if too_many <> [] then OpamGlobals.warning "In %s:\n duplicate fields %s" f.file_name (OpamMisc.string_of_list (fun x -> x) too_many); let is_, s_ = if List.length invalids <= 1 then "is an", "" else "are", "s" in if invalids <> [] then OpamGlobals.warning "In %s:\n %s %s unknown field%s." f.file_name (OpamMisc.pretty_list invalids) is_ s_; if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: bad fields in %s" f.file_name; false else permissive_mode let to_1_0 file = let file_contents = List.map (function | Variable (pos, v, _) as c -> if v = s_opam_version then Variable (pos,s_opam_version, OpamFormat.make_string "1") else c | c -> c ) file.file_contents in { file with file_contents; file_format = OpamVersion.of_string "1" } end module Prefix = struct let internal = "prefix" type t = string name_map let empty = OpamPackage.Name.Map.empty let of_channel filename ic = let lines = Lines.of_channel filename ic in List.fold_left (fun map -> function | [] -> map | [nv;prefix] -> OpamPackage.Name.Map.add (OpamPackage.Name.of_string nv) prefix map | s -> OpamGlobals.error_and_exit "%S is not a valid prefix line" (String.concat " " s) ) OpamPackage.Name.Map.empty lines let to_string filename s = let lines = OpamPackage.Name.Map.fold (fun nv prefix l -> [OpamPackage.Name.to_string nv; prefix] :: l ) s [] in Lines.to_string filename lines end module Filenames = struct let internal = "filenames" type t = filename_set let empty = OpamFilename.Set.empty let of_channel filename ic = let lines = Lines.of_channel filename ic in let lines = OpamMisc.filter_map (function | [] -> None | [f] -> Some (OpamFilename.of_string f) | s -> OpamGlobals.error_and_exit "%S is not a valid filename" (String.concat " " s) ) lines in OpamFilename.Set.of_list lines let to_string filename s = let lines = List.rev_map (fun f -> [OpamFilename.to_string f]) (OpamFilename.Set.elements s) in Lines.to_string filename lines end module File_attributes = struct let internal = "file_attributes" type t = file_attribute_set let empty = OpamFilename.Attribute.Set.empty let of_channel filename ic = let lines = Lines.of_channel filename ic in let rs = OpamMisc.filter_map (function | [] -> None | [s] -> (* backwards-compat *) Some (OpamFilename.Attribute.of_string_list (OpamMisc.split s ' ')) | l -> Some (OpamFilename.Attribute.of_string_list l) ) lines in OpamFilename.Attribute.Set.of_list rs let to_string filename t = let lines = List.rev_map (fun r -> OpamFilename.Attribute.to_string_list r) (OpamFilename.Attribute.Set.elements t) in Lines.to_string filename lines end module URL = struct let internal = "url" type t = { url : address; mirrors : address list; kind : repository_kind; checksum: string option; } let create kind ?(mirrors=[]) url = { url; mirrors; kind; checksum = None; } let empty = { url = "", None; mirrors = []; kind = `local; checksum= None; } let s_archive = "archive" let s_src = "src" let s_http = "http" let s_checksum = "checksum" let s_git = "git" let s_darcs = "darcs" let s_hg = "hg" let s_local = "local" let s_mirrors = "mirrors" let valid_fields = [ Syntax.s_opam_version; s_archive; s_src; s_http; s_git; s_darcs; s_hg; s_local; s_checksum; s_mirrors; ] let url_and_kind ~src ~archive ~http ~git ~darcs ~hg ~local = let extract = match src, archive, http, git, darcs, hg, local with | None , None , None , None , None , None , None -> None | Some x, None , None , None , None , None , None | None , Some x, None , None , None , None , None -> Some (x, None) | None , None , Some x, None , None , None , None -> Some (x, Some `http) | None , None , None , Some x, None , None , None -> Some (x, Some `git) | None , None , None , None , Some x, None , None -> Some (x, Some `darcs) | None , None , None , None , None , Some x, None -> Some (x, Some `hg) | None , None , None , None , None , None , Some x -> Some (x, Some `local) | _ -> OpamFormat.bad_format "Too many URLS" in match extract with | None -> None | Some (url, kind_opt) -> try let url, kind = parse_url url in Some (url, OpamMisc.Option.default kind kind_opt) with Invalid_argument s -> OpamFormat.bad_format "%s" s let of_channel filename ic = let s = Syntax.of_channel filename ic in let permissive = Syntax.check ~versioned:false s valid_fields in let get f = try OpamFormat.assoc_option s.file_contents f (OpamFormat.parse_string @> address_of_string) with OpamFormat.Bad_format _ when permissive -> None in let archive = get s_archive in let http = get s_http in let src = get s_src in let git = get s_git in let darcs = get s_darcs in let hg = get s_hg in let local = get s_local in let mirrors = OpamFormat.assoc_list s.file_contents s_mirrors (OpamFormat.parse_list (OpamFormat.parse_string @> address_of_string)) in let checksum = OpamFormat.assoc_option s.file_contents s_checksum OpamFormat.parse_string in let url, kind = match url_and_kind ~src ~archive ~http ~git ~darcs ~hg ~local with Some x -> x | None -> OpamFormat.bad_format "URL is missing" in { url; mirrors; kind; checksum } let to_string filename t = let url_name = string_of_repository_kind t.kind in let s = { file_format = OpamVersion.current; file_name = OpamFilename.to_string filename; file_contents = [ OpamFormat.make_variable ( url_name , OpamFormat.make_string (string_of_address t.url)); ] @ ( if t.mirrors = [] then [] else [OpamFormat.make_variable (s_mirrors , OpamFormat.make_list (string_of_address @> OpamFormat.make_string) t.mirrors)] ) @ match t.checksum with | None -> [] | Some c -> [OpamFormat.make_variable (s_checksum, OpamFormat.make_string c)] } in Syntax.to_string s let url t = t.url let mirrors t = t.mirrors let kind t = t.kind let checksum t = t.checksum let with_checksum t checksum = { t with checksum = Some checksum } end module Export = struct let internal = "export" type t = package_set * package_set * pin_option OpamPackage.Name.Map.t let empty = (OpamPackage.Set.empty, OpamPackage.Set.empty, OpamPackage.Name.Map.empty) let of_channel filename ic = let lines = Lines.of_channel filename ic in let state = function | "root" -> `Root | "noroot" | "installed" -> `Installed | "uninstalled" -> `Uninstalled | s -> OpamGlobals.error_and_exit "Invalid installation status (col. 3) in %s: %S" (OpamFilename.to_string filename) s in let add (installed,roots,pinned) n v state p = let name = OpamPackage.Name.of_string n in let nv = OpamPackage.create name (OpamPackage.Version.of_string v) in let installed = if state <> `Uninstalled then OpamPackage.Set.add nv installed else installed in let roots = if state = `Root then OpamPackage.Set.add nv roots else roots in let pinned = match p with | None -> pinned | Some (kind,p) -> OpamPackage.Name.Map.add name (pin_option_of_string ~kind p) pinned in installed, roots, pinned in List.fold_left (fun acc -> function | [] -> acc | [n; v] -> add acc n v `Root None | [n; v; r] -> add acc n v (state r) None | [n; v; r; pk; p] -> add acc n v (state r) (Some (pin_kind_of_string pk,p)) | l -> OpamGlobals.error_and_exit "Invalid line in %s: %S" (OpamFilename.to_string filename) (String.concat " " l) ) (OpamPackage.Set.empty, OpamPackage.Set.empty, OpamPackage.Name.Map.empty) lines let to_string _ (installed, roots, pinned) = let buf = Buffer.create 1024 in let print_pin pin = Printf.sprintf "\t%s\t%s" (string_of_pin_kind (kind_of_pin_option pin)) (string_of_pin_option pin) in OpamPackage.Set.iter (fun nv -> let name = OpamPackage.name nv in Printf.bprintf buf "%s\t%s\t%s%s\n" (OpamPackage.Name.to_string (OpamPackage.name nv)) (OpamPackage.Version.to_string (OpamPackage.version nv)) (if OpamPackage.Set.mem nv roots then "root" else "installed") (try print_pin (OpamPackage.Name.Map.find name pinned) with Not_found -> "") ) installed; let installed_names = OpamPackage.names_of_packages installed in OpamPackage.Name.Map.iter (fun name pin -> if not (OpamPackage.Name.Set.mem name installed_names) then Printf.bprintf buf "%s\t--\tuninstalled\t%s\n" (OpamPackage.Name.to_string name) (print_pin pin) ) pinned; Buffer.contents buf end module Installed = struct let internal = "installed" type t = package_set let empty = OpamPackage.Set.empty let check t = let map = OpamPackage.to_map t in OpamPackage.Name.Map.iter (fun n vs -> if OpamPackage.Version.Set.cardinal vs <> 1 then OpamGlobals.error_and_exit "Multiple versions installed for package %s: %s" (OpamPackage.Name.to_string n) (OpamPackage.Version.Set.to_string vs) ) map let of_channel filename ic = let lines = Lines.of_channel filename ic in let map,_ = List.fold_left (fun (map,i) -> function | [] -> map, i+1 | [name; version] -> OpamPackage.Set.add (OpamPackage.create (OpamPackage.Name.of_string name) (OpamPackage.Version.of_string version)) map, i+1 | s -> OpamGlobals.error "At %s:%d:\n skipped invalid line %S" (OpamFilename.prettify filename) i (String.concat " " s); map, i+1 ) (empty,1) lines in map let to_string _ t = check t; let buf = Buffer.create 1024 in OpamPackage.Set.iter (fun nv -> Printf.bprintf buf "%s %s\n" (OpamPackage.Name.to_string (OpamPackage.name nv)) (OpamPackage.Version.to_string (OpamPackage.version nv))) t; Buffer.contents buf end module Installed_roots = struct include Installed let internal = "installed.roots" end module Reinstall = struct include Installed let internal = "reinstall" end module Repo_index (A : OpamMisc.ABSTRACT) = struct let internal = "repo-index" type t = (repository_name * string option) A.Map.t let empty = A.Map.empty let of_channel filename ic = let lines = Lines.of_channel filename ic in List.fold_left (fun map -> function | [] | [_] -> map | a_s :: repos_s :: prefix -> let a = A.of_string a_s in if A.Map.mem a map then OpamGlobals.error_and_exit "multiple lines for %s" a_s else let repo_name = OpamRepositoryName.of_string repos_s in let prefix = match prefix with | [] -> None | [p] -> Some p | _ -> OpamGlobals.error_and_exit "Too many prefixes" in A.Map.add a (repo_name, prefix) map ) A.Map.empty lines let to_string filename map = let lines = A.Map.fold (fun nv (repo_name, prefix) lines -> let repo_s = OpamRepositoryName.to_string repo_name in let prefix_s = match prefix with | None -> [] | Some p -> [p] in (A.to_string nv :: repo_s :: prefix_s) :: lines ) map [] in Lines.to_string filename (List.rev lines) end module Package_index = Repo_index(OpamPackage) module Compiler_index = Repo_index(OpamCompiler) module Pinned = struct let internal = "pinned" type t = pin_option OpamPackage.Name.Map.t let empty = OpamPackage.Name.Map.empty let of_channel filename ic = let lines = Lines.of_channel filename ic in let add name_s pin map = let name = OpamPackage.Name.of_string name_s in if OpamPackage.Name.Map.mem name map then OpamGlobals.error_and_exit "multiple lines for package %s" name_s else OpamPackage.Name.Map.add name pin map in List.fold_left (fun map -> function | [] -> map | [name_s; x] -> add name_s (pin_option_of_string x) map | [name_s;k;x] -> let kind = Some (pin_kind_of_string k) in add name_s (pin_option_of_string ?kind x) map | _ -> OpamGlobals.error_and_exit "too many pinning options" ) OpamPackage.Name.Map.empty lines let to_string filename map = let lines = OpamPackage.Name.Map.fold (fun name pin lines -> let kind = kind_of_pin_option pin in let l = [ OpamPackage.Name.to_string name; string_of_pin_kind kind; string_of_pin_option pin ] in l :: lines ) map [] in Lines.to_string filename (List.rev lines) end module Repo_config = struct let internal = "repo-config" type t = repository let empty = { repo_name = OpamRepositoryName.of_string ""; repo_address = ("", None); repo_root = OpamFilename.raw_dir ""; repo_kind = `local; repo_priority = 0; } let s_name = "name" let s_kind = "kind" let s_address = "address" let s_priority = "priority" let s_root = "root" let of_channel filename ic = let s = Syntax.of_channel filename ic in let repo_name = OpamFormat.assoc s.file_contents s_name (OpamFormat.parse_string @> OpamRepositoryName.of_string) in let repo_address = OpamFormat.assoc s.file_contents s_address (OpamFormat.parse_string @> address_of_string) in let repo_kind = OpamFormat.assoc s.file_contents s_kind (OpamFormat.parse_string @> repository_kind_of_string) in let repo_priority = OpamFormat.assoc_default 0 s.file_contents s_priority OpamFormat.parse_int in let repo_root = match OpamFormat.assoc_option s.file_contents s_root (OpamFormat.parse_string @> OpamFilename.raw_dir) with None -> OpamPath.Repository.create (OpamPath.root ()) repo_name | Some f -> f in { repo_name; repo_address; repo_kind; repo_priority; repo_root } let to_string filename t = let s = { file_format = OpamVersion.current; file_name = OpamFilename.to_string filename; file_contents = [ OpamFormat.make_variable (s_name , OpamFormat.make_string (OpamRepositoryName.to_string t.repo_name)); OpamFormat.make_variable (s_address , OpamFormat.make_string (string_of_address t.repo_address)); OpamFormat.make_variable (s_kind , OpamFormat.make_string (string_of_repository_kind t.repo_kind)); OpamFormat.make_variable (s_priority, OpamFormat.make_int t.repo_priority); OpamFormat.make_variable (s_root, OpamFormat.make_string (OpamFilename.Dir.to_string t.repo_root)); ] } in Syntax.to_string s end module Descr = struct let internal = "descr" type t = string * string let empty = "", "" let synopsis = fst let body = snd let full (x,y) = x ^ "\n" ^ y let of_channel _ ic = let x = try input_line ic with End_of_file | Sys_error _ -> "" in let y = try OpamSystem.string_of_channel ic with End_of_file | Sys_error _ -> "" in x, y let of_string str = let head, tail = match OpamMisc.cut_at str '\n' with | None -> str, "" | Some (h,t) -> h, t in head, tail let to_string _ = full end module Aliases = struct let internal = "aliases" type t = compiler switch_map let empty = OpamSwitch.Map.empty let to_string filename t = let l = OpamSwitch.Map.fold (fun switch compiler lines -> [OpamSwitch.to_string switch; OpamCompiler.to_string compiler] :: lines ) t [] in Lines.to_string filename l let of_channel filename ic = let l = Lines.of_channel filename ic in List.fold_left (fun map -> function | [] -> map | [switch; comp] -> OpamSwitch.Map.add (OpamSwitch.of_string switch) (OpamCompiler.of_string comp) map | _ -> failwith "switches" ) OpamSwitch.Map.empty l end module Config = struct let internal = "config" type t = { opam_version : opam_version; repositories : repository_name list ; switch : switch; jobs : int; dl_tool : arg list option; dl_jobs : int; criteria : (solver_criteria * string) list; solver : arg list option; } let with_repositories t repositories = { t with repositories } let with_switch t switch = { t with switch } let with_current_opam_version t = { t with opam_version = OpamVersion.current_nopatch } let with_criteria t criteria = { t with criteria } let with_solver t solver = { t with solver } let opam_version t = t.opam_version let repositories t = t.repositories let switch t = t.switch let jobs t = t.jobs let dl_tool t = t.dl_tool let dl_jobs t = t.dl_jobs let criteria t = t.criteria let solver t = t.solver let create switch repositories ?(criteria=[]) ?solver jobs ?download_tool dl_jobs = { opam_version = OpamVersion.current; repositories ; switch ; jobs ; dl_tool = download_tool; dl_jobs ; criteria ; solver } let empty = { opam_version = OpamVersion.current; repositories = []; switch = OpamSwitch.of_string ""; jobs = OpamGlobals.default_jobs; dl_tool = None; dl_jobs = OpamGlobals.default_dl_jobs; criteria = []; solver = None; } let s_opam_version = "opam-version" let s_repositories = "repositories" let s_switch = "switch" let s_switch1 = "alias" let s_switch2 = "ocaml-version" let s_jobs = "jobs" let s_dl_tool = "download-command" let s_dl_jobs = "download-jobs" let s_criteria = "solver-criteria" let s_upgrade_criteria = "solver-upgrade-criteria" let s_fixup_criteria = "solver-fixup-criteria" let s_solver = "solver" let s_cores = "cores" let s_system_version1 = "system_ocaml-version" let s_system_version2 = "system-ocaml-version" let valid_fields = [ s_opam_version; s_repositories; s_switch; s_jobs; s_dl_tool; s_dl_jobs; s_criteria; s_upgrade_criteria; s_fixup_criteria; s_solver; (* these fields are no longer useful, but we keep them for backward compatibility *) s_switch1; s_switch2; s_system_version1; s_system_version2; s_cores; ] let of_channel filename ic = let s = Syntax.of_channel filename ic in let permissive = Syntax.check s valid_fields in let opam_version = OpamFormat.assoc s.file_contents s_opam_version (OpamFormat.parse_string @> OpamVersion.of_string) in let repositories = try OpamFormat.assoc_list s.file_contents s_repositories (OpamFormat.parse_list (OpamFormat.parse_string @> OpamRepositoryName.of_string)) with OpamFormat.Bad_format _ when permissive -> [] in let mk_switch str = OpamFormat.assoc_option s.file_contents str (OpamFormat.parse_string @> OpamSwitch.of_string) in let switch = mk_switch s_switch in let switch1 = mk_switch s_switch1 in let switch2 = mk_switch s_switch2 in let switch = match OpamMisc.Option.Op.(switch ++ switch1 ++ switch2) with | Some v -> v | None -> OpamGlobals.error_and_exit "No current switch defined in %s." (OpamFilename.to_string filename) in let jobs = try let mk str = OpamFormat.assoc_option s.file_contents str OpamFormat.parse_int in match OpamMisc.Option.Op.(mk s_jobs ++ mk s_cores) with | Some i -> i | None -> OpamGlobals.default_jobs with OpamFormat.Bad_format _ when permissive -> OpamGlobals.default_jobs in let dl_tool = try OpamFormat.assoc_option s.file_contents s_dl_tool OpamFormat.parse_single_command with OpamFormat.Bad_format _ when permissive -> None in let dl_jobs = try match OpamFormat.assoc_option s.file_contents s_dl_jobs OpamFormat.parse_int with | Some i -> i | None -> OpamGlobals.default_dl_jobs with OpamFormat.Bad_format _ when permissive -> OpamGlobals.default_dl_jobs in let criteria = let crit kind fld acc = match OpamFormat.assoc_option s.file_contents fld OpamFormat.parse_string with | Some c -> (kind,c)::acc | None -> acc in [] |> crit `Fixup s_fixup_criteria |> crit `Upgrade s_upgrade_criteria |> crit `Default s_criteria in let solver = try OpamFormat.assoc_option s.file_contents s_solver OpamFormat.parse_single_command with OpamFormat.Bad_format _ when permissive -> None in { opam_version; repositories; switch; jobs; dl_tool; dl_jobs; criteria; solver } let to_string filename t = let criteria = let mk kind s acc = try let c = List.assoc kind t.criteria in OpamFormat.make_variable (s, OpamFormat.make_string c) :: acc with Not_found -> acc in [] |> mk `Fixup s_fixup_criteria |> mk `Upgrade s_upgrade_criteria |> mk `Default s_criteria in let solver = match t.solver with | None -> [] | Some s -> [OpamFormat.make_variable (s_solver, OpamFormat.make_single_command s)] in let download_tool = match t.dl_tool with | None -> [] | Some dlt -> [OpamFormat.make_variable (s_dl_tool, OpamFormat.make_single_command dlt)] in let s = { file_format = OpamVersion.current; file_name = OpamFilename.to_string filename; file_contents = [ OpamFormat.make_variable (s_opam_version, OpamFormat.make_string (OpamVersion.to_string t.opam_version)); OpamFormat.make_variable (s_repositories, OpamFormat.make_list (OpamRepositoryName.to_string @> OpamFormat.make_string) t.repositories); OpamFormat.make_variable (s_jobs , OpamFormat.make_int t.jobs); OpamFormat.make_variable (s_dl_jobs , OpamFormat.make_int t.dl_jobs); OpamFormat.make_variable (s_switch, OpamFormat.make_string (OpamSwitch.to_string t.switch)) ] @ criteria @ solver @ download_tool } in Syntax.to_string s end module OPAM = struct let internal = "opam" type t = { opam_version: opam_version; name : OpamPackage.Name.t option; version : OpamPackage.Version.t option; maintainer : string list; substs : basename list; build_env : (string * string * string) list; build : command list; install : command list; remove : command list; depends : ext_formula; depopts : ext_formula; conflicts : formula; features : (OpamVariable.t * string * filter) list; libraries : (string * filter option) list; syntax : (string * filter option) list; patches : (basename * filter option) list; ocaml_version: compiler_constraint option; os : (bool * string) generic_formula; available : filter; homepage : string list; author : string list; license : string list; doc : string list; tags : string list; build_test : command list; build_doc : command list; depexts : tags option; messages : (string * filter option) list; bug_reports : string list; post_messages: (string * filter option) list; flags : package_flag list; dev_repo : pin_option option; } let empty = { opam_version = OpamVersion.current_nopatch; name = None; version = None; maintainer = []; substs = []; build_env = []; build = []; install = []; remove = []; depends = OpamFormula.Empty; depopts = OpamFormula.Empty; conflicts = OpamFormula.Empty; features = []; libraries = []; syntax = []; patches = []; ocaml_version = None; os = Empty; available = FBool true; homepage = []; author = []; license = []; doc = []; tags = []; build_test = []; build_doc = []; depexts = None; messages = []; post_messages = []; bug_reports = []; flags = []; dev_repo = None; } let create nv = let name = Some (OpamPackage.name nv) in let version = Some (OpamPackage.version nv) in { empty with name; version } let s_opam_version = "opam-version" let s_version = "version" let s_name = "name" let s_maintainer = "maintainer" let s_substs = "substs" let s_build = "build" let s_install = "install" let s_build_env = "build-env" let s_remove = "remove" let s_depends = "depends" let s_depopts = "depopts" let s_conflicts = "conflicts" let s_features = "features" let s_libraries = "libraries" let s_syntax = "syntax" let s_ocaml_version = "ocaml-version" let s_patches = "patches" let s_configure_style = "configure-style" let s_os = "os" let s_available = "available" let s_homepage = "homepage" let s_author = "author" let s_authors = "authors" let s_license = "license" let s_doc = "doc" let s_tags = "tags" let s_build_test = "build-test" let s_build_doc = "build-doc" let s_depexts = "depexts" let s_messages = "messages" let s_post_messages = "post-messages" let s_bug_reports = "bug-reports" let s_flags = "flags" let s_dev_repo = "dev-repo" let opam_1_0_fields = [ s_opam_version; s_maintainer; s_substs; s_build; s_remove; s_depends; s_depopts; s_conflicts; s_libraries; s_syntax; s_ocaml_version; s_build_env; s_patches; s_os; s_license; s_authors; s_homepage; s_doc; s_build_test; s_build_doc; s_depexts; s_tags; s_version; s_name; s_configure_style; ] let opam_1_1_fields = [ s_author; s_available; s_messages; s_post_messages; s_bug_reports; ] let opam_1_2_fields = [ s_flags; s_dev_repo; s_install; s_features; ] let to_1_0_fields k v = if List.mem k opam_1_1_fields || List.mem k opam_1_2_fields then if k = s_author then Some (s_authors, v) else None else if k = s_maintainer || k = s_homepage || k = s_license then match v with | List (_,v::_) -> Some (k, v) | v -> Some (k, v) else Some (k, v) let to_1_0 file = let file = OpamFormat.map to_1_0_fields file in Syntax.to_1_0 file let valid_fields = opam_1_0_fields @ opam_1_1_fields @ opam_1_2_fields let check name = function | None -> OpamGlobals.error_and_exit "Invalid OPAM file (missing field %S)" name | Some n -> n let is_explicit filename = try let ic = OpamFilename.open_in filename in try let file = Syntax.of_channel filename ic in let fields = OpamFormat.variables file.file_contents in List.exists (fun (f,_) -> f = s_name || f = s_version) fields with e -> close_in ic; raise e with e -> OpamMisc.fatal e; false let name t = check "name" t.name let name_opt t = t.name let version t = check "version" t.version let version_opt t = t.version let maintainer t = t.maintainer let substs t = t.substs let build t = t.build let install t = t.install let remove t = t.remove let depends t = t.depends let depopts t = t.depopts let conflicts t = t.conflicts let features t = t.features let libraries t = t.libraries let syntax t = t.syntax let ocaml_version t = t.ocaml_version let build_env t = t.build_env let patches t = t.patches let os t = t.os let available t = t.available let homepage t = t.homepage let author t = t.author let license t = t.license let doc t = t.doc let tags t = t.tags let build_doc t = t.build_doc let build_test t = t.build_test let depexts t = t.depexts let messages t = t.messages let post_messages t = t.post_messages let opam_version t = t.opam_version let bug_reports t = t.bug_reports let flags t = t.flags let has_flag f t = List.mem f t.flags || (* Allow in tags for compatibility *) List.mem ("flags:"^OpamFormat.(parse_ident (make_flag f))) t.tags let dev_repo t = t.dev_repo let with_opam_version t opam_version = { t with opam_version } let with_name t name = { t with name = Some name } let with_name_opt t name = { t with name } let with_version t version = { t with version = Some version } let with_version_opt t version = { t with version } let with_depends t depends = { t with depends } let with_depopts t depopts = { t with depopts } let with_conflicts t conflicts = {t with conflicts } let with_features t features = {t with features } let with_build t build = { t with build } let with_install t install = { t with install } let with_remove t remove = { t with remove } let with_libraries t libraries = { t with libraries } let with_syntax t syntax = { t with syntax } let with_substs t substs = { t with substs } let with_ocaml_version t ocaml_version = { t with ocaml_version } let with_os t os = { t with os } let with_available t available = { t with available } let with_maintainer t maintainer = { t with maintainer } let with_patches t patches = { t with patches } let with_bug_reports t bug_reports = { t with bug_reports } let with_depexts t depexts = { t with depexts } let with_messages t messages = { t with messages } let with_post_messages t post_messages = { t with post_messages } let with_flags t flags = { t with flags } let with_dev_repo t dev_repo = {t with dev_repo } let to_string filename t = let make_file = OpamFormat.make_option (OpamFilename.Base.to_string @> OpamFormat.make_string) OpamFormat.make_filter in let option c s f = match c with | None -> [] | Some v -> [ OpamFormat.make_variable (s, f v) ] in let list c s f = match c with | [] -> [] | l -> [ OpamFormat.make_variable (s, f l) ] in let listm c s f = match c with | [] -> [] | l -> [ OpamFormat.make_variable (s, OpamFormat.make_list f l) ] in let formula c s f = match c with | Empty -> [] | x -> [ OpamFormat.make_variable (s, f x) ] in let filter c s f = match c with | FBool true -> [] | x -> [ OpamFormat.make_variable (s, f x) ] in let name_and_version = match OpamPackage.of_filename filename with | Some _ -> [] | None -> option t.name s_name (OpamPackage.Name.to_string @> OpamFormat.make_string) @ option t.version s_version (OpamPackage.Version.to_string @> OpamFormat.make_string) in let s = { file_format = t.opam_version; file_name = OpamFilename.to_string filename; file_contents = [ OpamFormat.make_variable (s_opam_version, (OpamVersion.to_string @> OpamFormat.make_string) t.opam_version); ] @ name_and_version @ list t.maintainer s_maintainer OpamFormat.make_string_list @ list t.author s_authors OpamFormat.make_string_list @ list t.homepage s_homepage OpamFormat.make_string_list @ list t.bug_reports s_bug_reports OpamFormat.make_string_list @ list t.license s_license OpamFormat.make_string_list @ list t.doc s_doc OpamFormat.make_string_list @ list t.tags s_tags OpamFormat.make_string_list @ option t.dev_repo s_dev_repo (string_of_pin_option @> OpamFormat.make_string) @ listm t.substs s_substs (OpamFilename.Base.to_string @> OpamFormat.make_string) @ listm t.build_env s_build_env OpamFormat.make_env_variable @ listm t.build s_build OpamFormat.make_command @ listm t.install s_install OpamFormat.make_command @ listm t.build_test s_build_test OpamFormat.make_command @ listm t.build_doc s_build_doc OpamFormat.make_command @ listm t.remove s_remove OpamFormat.make_command @ formula t.depends s_depends OpamFormat.make_ext_formula @ formula t.depopts s_depopts OpamFormat.make_opt_formula @ option t.depexts s_depexts OpamFormat.make_tags @ formula t.conflicts s_conflicts OpamFormat.make_formula @ list t.features s_features OpamFormat.make_features @ list t.libraries s_libraries OpamFormat.make_libraries @ list t.syntax s_syntax OpamFormat.make_libraries @ list t.patches s_patches (OpamFormat.make_list make_file) @ option t.ocaml_version s_ocaml_version OpamFormat.make_compiler_constraint @ formula t.os s_os OpamFormat.make_os_constraint @ filter t.available s_available (OpamFormat.make_filter @> OpamFormat.make_list (fun x -> x)) @ list t.messages s_messages OpamFormat.(make_list (make_option make_string make_filter)) @ list t.post_messages s_post_messages OpamFormat.(make_list (make_option make_string make_filter)) @ list t.flags s_flags OpamFormat.(make_list make_flag) } in Syntax.to_string s let check_name ?(permissive=false) n s = let name_f = try OpamFormat.assoc_option s s_name (OpamFormat.parse_package_name ?expected:n) with OpamFormat.Bad_format _ when permissive -> None in OpamMisc.Option.Op.(name_f ++ n) let check_version ?(permissive=false) v s = let version_f = try OpamFormat.assoc_option s s_version (OpamFormat.parse_package_version ?expected:v) with OpamFormat.Bad_format _ when permissive -> None in OpamMisc.Option.Op.(version_f ++ v) let of_syntax ?(permissive=false) ?(conservative=false) f nv = let safe default f x y z = try f x y z with | OpamFormat.Bad_format _ as bf when not conservative && not !OpamGlobals.strict -> if not permissive then OpamGlobals.warning "%s" (OpamFormat.string_of_bad_format bf); default in let assoc_option x y z = safe None OpamFormat.assoc_option x y z in let assoc_list x y z = safe [] OpamFormat.assoc_list x y z in let assoc_default dft = safe dft (OpamFormat.assoc_default dft) in let s = f.file_contents in let name = check_name ~permissive (OpamMisc.Option.map OpamPackage.name nv) s in let opam_version = OpamFormat.assoc s s_opam_version (OpamFormat.parse_string @> OpamVersion.of_string) in let version = check_version ~permissive (OpamMisc.Option.map OpamPackage.version nv) s in let maintainer = assoc_list s s_maintainer OpamFormat.parse_string_list in let substs = assoc_list s s_substs (OpamFormat.parse_list (OpamFormat.parse_string @> OpamFilename.Base.of_string)) in let build_env = assoc_list s s_build_env (OpamFormat.parse_list OpamFormat.parse_env_variable) in let build = assoc_list s s_build OpamFormat.parse_commands in let install = assoc_list s s_install OpamFormat.parse_commands in let remove = assoc_list s s_remove OpamFormat.parse_commands in let check_depflags ~pos ext_formula = if conservative then ext_formula else OpamFormula.map (fun (name, (flags, cstr)) -> let known_flags = List.filter (function Depflag_Unknown _ -> false | _ -> true) flags in if not permissive && known_flags <> flags then OpamGlobals.warning "At %s:\n Unknown flags %s ignored for dependency %s" (string_of_pos pos) (OpamMisc.pretty_list (OpamMisc.filter_map (function | Depflag_Unknown s -> Some s | _ -> None) flags)) (OpamPackage.Name.to_string name); Atom (name, (known_flags, cstr))) ext_formula in let depends = assoc_default OpamFormula.Empty s s_depends (fun v -> OpamFormat.parse_ext_formula v |> check_depflags ~pos:(OpamFormat.value_pos v)) in let depopts = let rec cleanup ~pos acc disjunction = List.fold_left (fun acc -> function | OpamFormula.Atom (_, (_,Empty)) as atom -> atom :: acc | OpamFormula.Atom (name, (flags, cstr)) -> OpamGlobals.warning "At %s:\n\ Version constraint (%s) no longer allowed in optional \ dependency (ignored).\n\ Use the 'conflicts' field instead." (string_of_pos pos) (OpamFormula.string_of_formula (fun (r,v) -> OpamFormula.string_of_relop r ^" "^ OpamPackage.Version.to_string v) cstr); OpamFormula.Atom (name, (flags, Empty)) :: acc | f -> OpamGlobals.warning "At %s:\n\ Optional dependencies must be a disjunction. Treated as such." (string_of_pos pos); cleanup ~pos acc (OpamFormula.fold_left (fun acc a -> OpamFormula.Atom a::acc) [] f) ) acc disjunction in assoc_default OpamFormula.Empty s s_depopts @@ fun value -> let f = OpamFormat.parse_opt_formula value |> check_depflags ~pos:(OpamFormat.value_pos value) in if not conservative && not !OpamGlobals.skip_version_checks && OpamVersion.compare opam_version (OpamVersion.of_string "1.2") >= 0 then OpamFormula.ors_to_list f |> cleanup ~pos:(OpamFormat.value_pos value) [] |> List.rev |> OpamFormula.ors else f in let conflicts = assoc_default OpamFormula.Empty s s_conflicts OpamFormat.parse_formula in let features = OpamFormat.assoc_default [] s s_features OpamFormat.parse_features in let libraries = assoc_list s s_libraries OpamFormat.parse_libraries in let syntax = assoc_list s s_syntax OpamFormat.parse_libraries in let ocaml_version = assoc_option s s_ocaml_version OpamFormat.parse_compiler_constraint in let os = assoc_default OpamFormula.Empty s s_os OpamFormat.parse_os_constraint in let available = assoc_default (FBool true) s s_available (OpamFormat.parse_list (fun x -> x) @> OpamFormat.parse_filter) in let parse_file = OpamFormat.parse_option (OpamFormat.parse_string @> OpamFilename.Base.of_string) OpamFormat.parse_filter in let patches = assoc_list s s_patches (OpamFormat.parse_list parse_file) in let homepage = assoc_list s s_homepage OpamFormat.parse_string_list in let author = let x = assoc_list s s_authors OpamFormat.parse_string_list in let y = assoc_list s s_author OpamFormat.parse_string_list in x @ y in let license = assoc_list s s_license OpamFormat.parse_string_list in let doc = assoc_list s s_doc OpamFormat.parse_string_list in let tags = assoc_list s s_tags OpamFormat.parse_string_list in let build_test = assoc_list s s_build_test OpamFormat.parse_commands in let build_doc = assoc_list s s_build_doc OpamFormat.parse_commands in let depexts = assoc_option s s_depexts OpamFormat.parse_tags in let messages = assoc_list s s_messages OpamFormat.parse_messages in let bug_reports = assoc_list s s_bug_reports OpamFormat.parse_string_list in let post_messages = assoc_list s s_post_messages OpamFormat.parse_messages in let flags = let parse v = let allflags = OpamFormat.(parse_list parse_flag v) in if conservative then allflags else let known_flags = List.filter (function Pkgflag_Unknown _ -> false | _ -> true) allflags in if not permissive && known_flags <> allflags then OpamGlobals.warning "At %s:\n Unknown package flags %s ignored" (string_of_pos (OpamFormat.value_pos v)) (OpamMisc.pretty_list (OpamMisc.filter_map (function | Pkgflag_Unknown s -> Some s | _ -> None) allflags)); known_flags in assoc_list s s_flags parse in let dev_repo = assoc_option s s_dev_repo @@ fun v -> OpamFormat.parse_string v |> address_of_string |> (fun addr -> try parse_url addr with | Invalid_argument msg -> OpamFormat.bad_format ~pos:(OpamFormat.value_pos v) "%s" msg) |> (fun url -> try pin_of_url url with | Failure msg -> OpamFormat.bad_format ~pos:(OpamFormat.value_pos v) "%s" msg) |> (function | Git _ | Darcs _ | Hg _ as pin -> pin | Http u -> Git u | _ -> OpamFormat.bad_format ~pos:(OpamFormat.value_pos v) "Unrecognised version-control address") in { opam_version; name; version; maintainer; substs; build; install; remove; depends; depopts; conflicts; features; libraries; syntax; patches; ocaml_version; os; available; build_env; homepage; author; license; doc; tags; build_test; build_doc; depexts; messages; post_messages; bug_reports; flags; dev_repo } let of_channel filename ic = let nv = OpamPackage.of_filename filename in let f = Syntax.of_channel filename ic in let permissive = Syntax.check f valid_fields in of_syntax ~permissive f nv let template nv = let t = create nv in let maintainer = let from_git = try match OpamSystem.read_command_output ["git"; "config"; "--get"; "user.name"], OpamSystem.read_command_output ["git"; "config"; "--get"; "user.email"] with | [name], [email] -> Some [Printf.sprintf "%s <%s>" name email] | _ -> raise Not_found with e -> OpamMisc.fatal e; None in match from_git with | Some u -> u | None -> let email = try Some (Sys.getenv "EMAIL") with Not_found -> None in try let open Unix in let pw = getpwuid (getuid ()) in let email = match email with | Some e -> e | None -> pw.pw_name^"@"^gethostname () in match OpamMisc.split pw.pw_gecos ',' with | name::_ -> [Printf.sprintf "%s <%s>" name email] | _ -> [email] with Not_found -> match email with | Some e -> [e] | None -> [] in { t with maintainer; build = [[CString "./configure", None; CString "--prefix=%{prefix}%", None;], None; [CIdent "make", None], None]; install = [[CIdent "make", None; CString "install", None], None]; remove = [[CString "ocamlfind", None; CString "remove", None; CString (OpamPackage.Name.to_string (OpamPackage.name nv)), None], None]; depends = Atom (OpamPackage.Name.of_string "ocamlfind", ([Depflag_Build], Empty)); author = maintainer; homepage = [""]; license = [""]; dev_repo = Some (Local (OpamFilename.Dir.of_string "")); bug_reports= [""]; } let validate t = let cond num level msg cd = if cd then Some (num, level, msg) else None in let names_of_formula flag f = OpamPackage.Name.Set.of_list @@ List.map fst OpamFormula.( atoms @@ filter_deps ~test:flag ~doc:flag f ) in let all_commands = t.build @ t.install @ t.remove @ t.build_test @ t.build_doc in let all_filters = OpamMisc.filter_map snd t.patches @ OpamMisc.filter_map snd t.messages @ OpamMisc.filter_map snd t.post_messages @ [t.available] @ List.map (fun (_,_,f) -> f) t.features in let all_variables = OpamFilter.commands_variables all_commands @ List.fold_left (fun acc f -> OpamFilter.variables f @ acc) [] all_filters in let all_depends = OpamPackage.Name.Set.union (names_of_formula true t.depends) (names_of_formula true t.depopts) in let warnings = [ cond 20 `Warning "Field 'opam-version' refers to the patch version of opam, should \ be of the form MAJOR.MINOR" (OpamVersion.nopatch t.opam_version <> t.opam_version) ; cond 21 `Error "Field 'opam-version' doesn't match the current version, \ validation may not be accurate" (OpamVersion.compare t.opam_version OpamVersion.current_nopatch <> 0 && OpamVersion.compare t.opam_version OpamVersion.current <> 0); (* cond (t.name = None) "Missing field 'name' or directory in the form 'name.version'"; cond (t.version = None) "Missing field 'version' or directory in the form 'name.version'"; *) cond 22 `Error "Some fields are present but empty; remove or fill them" (t.maintainer = [""] || t.homepage = [""] || t.author = [""] || t.license = [""] || t.doc = [""] || t.tags = [""] || t.bug_reports = [""]); cond 23 `Error "Missing field 'maintainer'" (t.maintainer = []); cond 24 `Error "Field 'maintainer' set to the old default value" (List.mem "contact@ocamlpro.com" t.maintainer && not (List.mem "org:ocamlpro" t.tags)); cond 25 `Error "Missing field 'authors'" (t.author = []); cond 26 `Warning "No field 'install', but a field 'remove': install instructions \ probably part of 'build'. Use the 'install' field or a .install \ file" (t.install = [] && t.build <> [] && t.remove <> []); cond 27 `Warning "No field 'remove' while a field 'install' is present, uncomplete \ uninstallation suspected" (t.install <> [] && t.remove = []); cond 28 `Error "Unknown package flag found" (List.exists (function Pkgflag_Unknown _ -> true | _ -> false) t.flags); cond 29 `Error "Unknown dependency flags in depends or depopts" (OpamFormula.fold_left (fun acc (_, (flags, _)) -> acc || List.exists (function Depflag_Unknown _ -> true | _ -> false) flags) false (OpamFormula.ands [t.depends;t.depopts])); cond 30 `Error "Field 'depopts' contains formulas or version constraints" (List.exists (function | OpamFormula.Atom (_, (_,Empty)) -> false | _ -> true) (OpamFormula.ors_to_list t.depopts)); cond 31 `Error "Fields 'depends' and 'depopts' refer to the same package names" (not OpamPackage.Name.Set.( is_empty @@ inter (names_of_formula false t.depends) (names_of_formula true t.depopts))); cond 32 `Error "Field 'ocaml-version' is deprecated, use 'available' and the \ 'ocaml-version' variable instead" (t.ocaml_version <> None); cond 33 `Error "Field 'os' is deprecated, use 'available' and the 'os' variable \ instead" (t.os <> Empty); cond 34 `Error "Field 'available' contains references to package-local variables. \ It should only be determined from global configuration variables" (List.exists (fun v -> OpamVariable.Full.package v <> OpamPackage.Name.global_config) (OpamFilter.variables t.available)); cond 35 `Error "Missing field 'homepage'" (t.homepage = []); (* cond (t.doc = []) *) (* "Missing field 'doc'"; *) cond 36 `Warning "Missing field 'bug-reports'" (t.bug_reports = []); cond 37 `Warning "Missing field 'dev-repo'" (t.dev_repo = None); (* cond 38 `Warning "Package declares 'depexts', but has no 'post-messages' to help \ the user out when they are missing" (t.depexts <> None && t.post_messages = []); *) cond 39 `Error "Command 'make' called directly, use the built-in variable \ instead" (List.exists (function | (CString "make", _)::_, _ -> true | _ -> false ) all_commands); cond 40 `Warning "Field 'features' is still experimental and not yet to be used on \ the official repo" (t.features <> []); cond 40 `Warning "Package uses flags that aren't recognised by earlier versions in \ the 1.2 branch. At the moment, you should use a tag \"flags:foo\" \ instead for compatibility." (List.exists (function | Pkgflag_LightUninstall | Pkgflag_Unknown _ -> false | _ -> true) t.flags); cond 41 `Warning "Some packages are mentionned in package scripts of features, but \ there is no dependency or depopt toward them" (List.exists (fun v -> let n = OpamVariable.Full.package v in n <> OpamPackage.Name.global_config && Some n <> t.name && not (OpamPackage.Name.Set.mem n all_depends)) all_variables); ] in OpamMisc.filter_map (fun x -> x) warnings let validate_file filename = let warnings, t = try let ic = OpamFilename.open_in filename in let name = OpamMisc.Option.map OpamPackage.name (OpamPackage.of_filename filename) in let version = OpamMisc.Option.map OpamPackage.version (OpamPackage.of_filename filename) in let f = try let f = Syntax.of_channel filename ic in close_in ic; f with e -> close_in ic; raise e in let invalid_fields = OpamFormat.invalid_fields f.file_contents valid_fields in let warnings = List.map (fun f -> 3, `Error, Printf.sprintf "Invalid field: %s" f) invalid_fields in let t, warnings = try Some (of_syntax ~permissive:false ~conservative:true f None), warnings with OpamFormat.Bad_format (pos,_,msg) -> None, warnings @ [ 2, `Error, Printf.sprintf "File format error: %s%s" (match pos with | Some p -> Printf.sprintf "at %s, " (string_of_pos p) | None -> "") msg ] in let warnings = if t = None then warnings else try ignore (check_name name f.file_contents); warnings with OpamFormat.Bad_format (_,_,msg) -> [ 4, `Warning, Printf.sprintf "%s, the directory name or pinning implied %s" msg OpamMisc.Option.Op.((name >>| OpamPackage.Name.to_string) +! "" ) ] in let warnings = if t = None then warnings else try ignore (check_version version f.file_contents); warnings with OpamFormat.Bad_format (_,_,msg) -> [ 5, `Warning, Printf.sprintf "%s, the directory name or pinning implied %s" msg OpamMisc.Option.Op.((version >>| OpamPackage.Version.to_string) +! "" ) ] in close_in ic; warnings, t with | OpamSystem.File_not_found _ -> OpamGlobals.error "%s not found" (OpamFilename.prettify filename); [0, `Error, "File does not exist"], None | Lexer_error _ | Parsing.Parse_error -> [1, `Error, "File does not parse"], None in warnings @ (match t with Some t -> validate t | None -> []), t let warns_to_string ws = OpamMisc.sconcat_map "\n" (fun (n, w, s) -> let ws = match w with | `Warning -> OpamGlobals.colorise `yellow "warning" | `Error -> OpamGlobals.colorise `red "error" in OpamMisc.reformat ~indent:14 (Printf.sprintf " %15s %2d: %s" ws n s)) ws end module Dot_install = struct let internal = ".install" type t = { bin : (basename optional * basename option) list; sbin : (basename optional * basename option) list; lib : (basename optional * basename option) list; toplevel: (basename optional * basename option) list; stublibs: (basename optional * basename option) list; share : (basename optional * basename option) list; share_root: (basename optional * basename option) list; etc : (basename optional * basename option) list; doc : (basename optional * basename option) list; man : (basename optional * basename option) list; libexec : (basename optional * basename option) list; misc : (basename optional * filename) list; } let empty = { lib = []; bin = []; sbin = []; toplevel = []; stublibs = []; misc = []; share = []; share_root = []; etc = []; man = []; libexec = []; doc = []; } let bin t = t.bin let sbin t = t.sbin let lib t = t.lib let toplevel t = t.toplevel let stublibs t = t.stublibs let misc t = t.misc let share t = t.share let share_root t = t.share_root let etc t = t.etc let doc t = t.doc let libexec t = t.libexec let add_man_section_dir src = let file = Filename.basename (OpamFilename.Base.to_string src.c) in let section = let base = if Filename.check_suffix file ".gz" then Filename.chop_suffix file ".gz" else file in try let dot = String.rindex base '.' in if dot < String.length base - 1 then match base.[dot+1] with | '1'..'8' as c -> Printf.sprintf "man%c" c | _ -> raise Not_found else raise Not_found with Not_found -> OpamGlobals.error_and_exit "Manpage %s does not have a recognised suffix, \ and no destination is specified" (OpamFilename.Base.to_string src.c) in OpamFilename.Base.of_string (Filename.concat section file) let man t = List.map (fun (src, dst) -> src, match dst with | Some _ -> dst | None -> Some (add_man_section_dir src) ) t.man let s_lib = "lib" let s_bin = "bin" let s_sbin = "sbin" let s_misc = "misc" let s_toplevel = "toplevel" let s_stublibs = "stublibs" let s_share = "share" let s_share_root = "share_root" let s_etc = "etc" let s_doc = "doc" let s_man = "man" let s_libexec = "libexec" let valid_fields = [ Syntax.s_opam_version; s_lib; s_bin; s_sbin; s_toplevel; s_stublibs; s_misc; s_share; s_share_root; s_etc; s_doc; s_man; s_libexec; ] (* Filenames starting by ? are not always present. *) let optional_of_string str = let mk = OpamFilename.Base.of_string in if String.length str > 0 && str.[0] = '?' then { optional = true; c = mk (String.sub str 1 (String.length str - 1)) } else { optional = false; c = mk str } let string_of_optional t = let o = if t.optional then "?" else "" in Printf.sprintf "%s%s" o (OpamFilename.Base.to_string t.c) let to_string filename t = let open OpamFormat in let mk = make_list (make_option (fun src -> make_string (string_of_optional src)) (fun dst -> [make_string (OpamFilename.Base.to_string dst)])) in let mk_misc = make_list (fun (src,dst) -> make_option (fun src -> make_string (string_of_optional src)) (fun dst -> [make_string (OpamFilename.to_string dst)]) (src, Some dst)) in let s = { file_format = OpamVersion.current; file_name = OpamFilename.to_string filename; file_contents = [ make_variable (s_bin , mk t.bin); make_variable (s_sbin , mk t.sbin); make_variable (s_lib , mk t.lib); make_variable (s_toplevel, mk t.toplevel); make_variable (s_stublibs, mk t.stublibs); make_variable (s_share , mk t.share); make_variable (s_share_root, mk t.share_root); make_variable (s_etc , mk t.etc); make_variable (s_doc , mk t.doc); make_variable (s_man , mk t.man); make_variable (s_libexec , mk t.libexec); make_variable (s_misc , mk_misc t.misc); ] } in Syntax.to_string s let of_channel filename ic = let s = Syntax.of_channel filename ic in let _permissive = Syntax.check ~versioned:false s valid_fields in let src = OpamFormat.parse_string @> optional_of_string in let mk field = let dst = OpamFormat.parse_string @> OpamFilename.Base.of_string in let fn = OpamFormat.parse_single_option src dst in OpamFormat.assoc_list s.file_contents field (OpamFormat.parse_list fn) in let misc = let absolute_filename s = if not (Filename.is_relative s) then OpamFilename.of_string s else OpamSystem.internal_error "%s is not an absolute filename." s in let dst = OpamFormat.parse_string @> absolute_filename in let fn = OpamFormat.parse_pair src dst in OpamFormat.assoc_list s.file_contents s_misc (OpamFormat.parse_list fn) in let bin = mk s_bin in let sbin = mk s_sbin in let lib = mk s_lib in let toplevel = mk s_toplevel in let stublibs = mk s_stublibs in let share = mk s_share in let share_root = mk s_share_root in let etc = mk s_etc in let doc = mk s_doc in let man = mk s_man in let libexec = mk s_libexec in { lib; bin; sbin; misc; toplevel; stublibs; share; share_root; etc; doc; man; libexec } end module Dot_config = struct let internal = ".config" let s str = S str let b bool = B bool type t = (variable * variable_contents) list let create variables = variables let empty = [] let of_channel filename ic = let file = Syntax.of_channel filename ic in let parse_value = OpamFormat.parse_or [ "string", (OpamFormat.parse_string @> s); "bool" , (OpamFormat.parse_bool @> b); ] in let parse_variables items = let l = OpamFormat.variables items in List.rev_map (fun (k,v) -> OpamVariable.of_string k, parse_value v) l in let variables = parse_variables file.file_contents in variables let to_string filename t = let open OpamFormat in let of_value = function | B b -> make_bool b | S s -> make_string s in let of_variables l = List.rev_map (fun (k,v) -> make_variable (OpamVariable.to_string k, of_value v)) l in Syntax.to_string { file_format = OpamVersion.current; file_name = OpamFilename.to_string filename; file_contents = of_variables t } let variables t = List.rev_map fst t let variable t s = try Some (List.assoc s t) with Not_found -> None end module Comp = struct let internal = "comp" type t = { opam_version : opam_version ; name : compiler ; version : compiler_version ; preinstalled : bool; src : address option ; kind : repository_kind ; patches : filename list ; configure : string list ; make : string list ; build : command list ; packages : formula ; env : (string * string * string) list; tags : string list; } let empty = { opam_version = OpamVersion.current; name = OpamCompiler.of_string ""; version = OpamCompiler.Version.of_string ""; src = None; kind = `local; preinstalled = false; patches = []; configure = []; make = []; build = []; packages = OpamFormula.Empty; env = []; tags = []; } let create_preinstalled name version packages env = let mk n = Atom (n, Empty) in let packages = OpamFormula.ands (List.map mk packages) in { empty with name; version; preinstalled = true; packages; env } let s_opam_version = "opam-version" let s_name = "name" let s_version = "version" let s_patches = "patches" let s_configure = "configure" let s_make = "make" let s_build = "build" let s_packages = "packages" let s_env = "env" let s_preinstalled = "preinstalled" let s_tags = "tags" let s_src = "src" let s_http = "http" let s_archive = "archive" let s_git = "git" let s_darcs = "darcs" let s_hg = "hg" let s_local = "local" let opam_1_0_fields = [ s_opam_version; s_name; s_version; s_src; s_patches; s_configure; s_make; s_build; s_packages; s_env; s_preinstalled; s_tags; ] let opam_1_1_fields = [ s_archive; s_http; s_git; s_darcs; s_hg; s_local; ] let to_1_0_fields k v = if List.mem k opam_1_1_fields then if k = s_archive || k = s_http || k = s_git || k = s_darcs || k = s_hg || k = s_local then Some (s_src, v) else None else Some (k, v) let to_1_0 file = let file = OpamFormat.map to_1_0_fields file in Syntax.to_1_0 file let valid_fields = opam_1_0_fields @ opam_1_1_fields let name t = t.name let version t = t.version let patches t = t.patches let configure t = t.configure let make t = t.make let build t = t.build let src t = t.src let kind t = t.kind let opam_version t = t.opam_version let packages t = t.packages let preinstalled t = t.preinstalled let env t = t.env let tags t = t.tags let with_src t src = {t with src} let with_patches t patches = {t with patches} let with_configure t configure = {t with configure} let with_make t make = {t with make} let with_build t build = {t with build} let with_packages t packages = {t with packages} let of_channel filename ic = let file = Syntax.of_channel filename ic in let permissive = Syntax.check file valid_fields in let s = file.file_contents in let opam_version = OpamFormat.assoc s s_opam_version (OpamFormat.parse_string @> OpamVersion.of_string) in let name_d, version_d = match OpamCompiler.of_filename filename with | None -> OpamFormat.bad_format "Filename %S isn't in the form ." (OpamFilename.to_string filename) | Some c -> c, OpamCompiler.version c in let name = try OpamFormat.assoc_default name_d s s_name (OpamFormat.parse_string @> OpamCompiler.of_string) with OpamFormat.Bad_format _ when permissive -> name_d in if name_d <> name then ( OpamGlobals.warning "The file %s contains a bad 'name' field: %s instead of %s" (OpamFilename.to_string filename) (OpamCompiler.to_string name) (OpamCompiler.to_string name_d); if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: bad compiler name" ); let version = try OpamFormat.assoc_default version_d s s_version OpamFormat.parse_compiler_version with OpamFormat.Bad_format _ when permissive -> version_d in if name <> OpamCompiler.system && version_d <> version then ( OpamGlobals.warning "The file %s contains a bad 'version' field: %s instead of %s" (OpamFilename.to_string filename) (OpamCompiler.Version.to_string version) (OpamCompiler.Version.to_string version_d); if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: bad compiler version" ); let address field = try OpamFormat.assoc_option s field (OpamFormat.parse_string @> address_of_string) with OpamFormat.Bad_format _ when permissive -> None in let src = address s_src in let archive = address s_archive in let http = address s_http in let git = address s_git in let darcs = address s_darcs in let hg = address s_hg in let local = address s_local in let src, kind = try match URL.url_and_kind ~src ~archive ~http ~git ~darcs ~hg ~local with Some (u,k) -> Some u, k | None -> None, `http with OpamFormat.Bad_format _ when permissive -> None, `http in let safe dft f x y z = try f x y z with OpamFormat.Bad_format _ when permissive -> dft in let assoc_string_list x y = try OpamFormat.assoc_string_list x y with OpamFormat.Bad_format _ when permissive -> [] in let patches = safe [] OpamFormat.assoc_list s s_patches (OpamFormat.parse_list (OpamFormat.parse_string @> OpamFilename.raw)) in let configure = assoc_string_list s s_configure in let make = assoc_string_list s s_make in let build = safe [] OpamFormat.assoc_list s s_build OpamFormat.parse_commands in let env = safe [] OpamFormat.assoc_list s s_env (OpamFormat.parse_list_list OpamFormat.parse_env_variable) in let packages = safe OpamFormula.Empty (OpamFormat.assoc_default OpamFormula.Empty) s s_packages OpamFormat.parse_formula in let preinstalled = safe false (OpamFormat.assoc_default false) s s_preinstalled OpamFormat.parse_bool in let tags = assoc_string_list s s_tags in if build <> [] && (configure @ make) <> [] && not permissive then OpamGlobals.error_and_exit "%s: You cannot use 'build' and 'make'/'configure' fields at the same time." (OpamFilename.to_string filename); { opam_version; name; version; src; kind; patches; configure; make; build; packages; preinstalled; env; tags; } let to_string filename s = let open OpamFormat in let src = match s.src with | Some x -> Some (string_of_repository_kind s.kind, x) | None -> None in let s = { file_format = s.opam_version; file_name = OpamFilename.to_string filename; file_contents = [ make_variable (s_opam_version, make_string (OpamVersion.to_string s.opam_version)) ] @ ( match OpamCompiler.of_filename filename with | None -> [make_variable (s_name, make_string (OpamCompiler.to_string s.name))] | Some _ -> [] ) @ [ make_variable (s_version, make_string (OpamCompiler.Version.to_string s.version)) ] @ ( match src with | None -> [] | Some (s,c) -> [make_variable (s, make_string (string_of_address c))] ) @ [ make_variable (s_patches, make_list (OpamFilename.to_string @> make_string) s.patches); make_variable (s_configure, make_string_list s.configure); make_variable (s_make, make_string_list s.make); make_variable (s_build, make_commands s.build); make_variable (s_packages, make_formula s.packages); make_variable (s_env, make_list make_env_variable s.env); make_variable (s_tags, make_string_list s.tags); ] @ ( if not s.preinstalled then [] else [ make_variable (s_preinstalled, make_bool s.preinstalled) ]) } in Syntax.to_string s end module Comp_descr = Descr module Subst = struct let internal = "subst" type t = string let empty = "" let of_channel _ ic = OpamSystem.string_of_channel ic let to_string _ t = t end module Repo = struct let internal = "repo" type t = { opam_version : OpamVersion.t; browse : string option; upstream : string option; redirect : (string * filter option) list; } let version_of_maybe_string vs = OpamVersion.of_string begin match vs with | None -> "0.7.5" | Some v -> v end let create ?browse ?upstream ?opam_version ?(redirect=[]) () = { opam_version = version_of_maybe_string opam_version; browse; upstream; redirect; } let empty = create () let s_opam_version = "opam-version" let s_browse = "browse" let s_upstream = "upstream" let s_redirect = "redirect" let valid_fields = [ s_opam_version; s_browse; s_upstream; s_redirect; ] let of_channel filename ic = let s = Syntax.of_channel filename ic in let permissive = Syntax.check ~allow_major:true ~versioned:false s valid_fields in let get f = try OpamFormat.assoc_option s.file_contents f OpamFormat.parse_string with OpamFormat.Bad_format _ when permissive -> None in let opam_version = version_of_maybe_string (get s_opam_version) in let browse = get s_browse in let upstream = get s_upstream in let redirect = try OpamFormat.assoc_list s.file_contents s_redirect (OpamFormat.parse_list (OpamFormat.parse_option OpamFormat.parse_string OpamFormat.parse_filter)) with OpamFormat.Bad_format _ when permissive -> [] in { opam_version; browse; upstream; redirect } let to_string filename t = let opam_version = OpamVersion.to_string t.opam_version in let s = { file_format = t.opam_version; file_name = OpamFilename.to_string filename; file_contents = (OpamFormat.make_variable (s_opam_version, OpamFormat.make_string opam_version)) :: ( match t.upstream with | None -> [] | Some url -> [OpamFormat.make_variable (s_upstream , OpamFormat.make_string url)] ) @ ( match t.browse with | None -> [] | Some url -> [OpamFormat.make_variable (s_browse , OpamFormat.make_string url)] ) @ ( match t.redirect with | [] -> [] | l -> let value = OpamFormat.make_list (OpamFormat.make_option OpamFormat.make_string OpamFormat.make_filter) l in [OpamFormat.make_variable(s_redirect, value)] ); } in Syntax.to_string s let opam_version t = t.opam_version let browse t = t.browse let upstream t = t.upstream let redirect t = t.redirect end end module type F = sig val internal : string type t val empty : t val of_channel : filename -> in_channel -> t val to_string : filename -> t -> string end let read_files = ref [] let write_files = ref [] let print_stats () = let aux kind = function | [] -> () | l -> OpamGlobals.msg "%d files %s:\n %s\n%!" (List.length !read_files) kind (String.concat "\n " l) in aux "read" !read_files; aux "write" !write_files module Make (F : F) = struct let log ?level fmt = OpamGlobals.log (Printf.sprintf "FILE(%s)" F.internal) ?level fmt let slog = OpamGlobals.slog let write f v = let filename = OpamFilename.prettify f in let chrono = OpamGlobals.timer () in OpamFilename.write f (F.to_string f v); write_files := filename :: !write_files; log "Wrote %s in %.3fs" filename (chrono ()) let read f = let filename = OpamFilename.prettify f in read_files := filename :: !read_files; let chrono = OpamGlobals.timer () in try let ic = OpamFilename.open_in f in try let r = F.of_channel f ic in close_in ic; log ~level:3 "Read %s in %.3fs" filename (chrono ()); r with e -> close_in ic; raise e with | OpamSystem.File_not_found s -> OpamSystem.internal_error "File %s does not exist" s | Lexer_error _ | Parsing.Parse_error as e -> if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: aborting" else raise e (* Message already printed *) | e -> OpamMisc.fatal e; OpamGlobals.error "%s" (OpamFormat.string_of_bad_format ~file:f e); if !OpamGlobals.strict then OpamGlobals.exit 66 else raise e let safe_read f = if OpamFilename.exists f then try read f with OpamFormat.Bad_format _ -> OpamGlobals.msg "[skipped]\n"; F.empty else ( log ~level:2 "Cannot find %a" (slog OpamFilename.to_string) f; F.empty ) let dummy_file = OpamFilename.raw "" let read_from_channel ic = try F.of_channel dummy_file ic with | OpamFormat.Bad_format _ as e -> OpamGlobals.error "%s" (OpamFormat.string_of_bad_format e); if !OpamGlobals.strict then OpamGlobals.error_and_exit "Strict mode: aborting" else raise e let write_to_channel oc str = output_string oc (F.to_string dummy_file str) end open X module type IO_FILE = sig type t val empty: t val write: filename -> t -> unit val read : filename -> t val safe_read: filename -> t val read_from_channel: in_channel -> t val write_to_channel: out_channel -> t -> unit end module Lines = struct include Lines include Make (Lines) end module Config = struct include Config include Make (Config) end module Package_index = struct include Package_index include Make (Package_index) end module Compiler_index = struct include Compiler_index include Make (Compiler_index) end module Pinned = struct include Pinned include Make (Pinned) end module Repo = struct include Repo include Make(Repo) end module Repo_config = struct include Repo_config include Make (Repo_config) end module Descr = struct include Descr include Make (Descr) end module Aliases = struct include Aliases include Make (Aliases) end module Reinstall = struct include Reinstall include Make (Reinstall) end module OPAM = struct include OPAM include Make (OPAM) end module Dot_install = struct include Dot_install include Make (Dot_install) end module Dot_config = struct include Dot_config include Make (Dot_config) end module Export = struct include Export include Make(Export) end module Installed = struct include Installed include Make (Installed) end module Installed_roots = struct include Installed_roots include Make (Installed_roots) end module Subst = struct include Subst include Make (Subst) end module Comp = struct include Comp include Make (Comp) end module URL = struct include URL include Make (URL) end module File_attributes = struct include File_attributes include Make(File_attributes) end module Filenames = struct include Filenames include Make(Filenames) end module Prefix = struct include Prefix include Make(Prefix) end opam-full-1.2.2/src/core/opamLexer.mll0000644000175000017500000001067112517374212016320 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) { open OpamParser open OpamTypesBase let newline lexbuf = Lexing.new_line lexbuf let error fmt = Printf.kprintf (fun msg -> raise (Lexer_error msg)) fmt let char_for_backslash = function | 'n' -> '\010' | 'r' -> '\013' | 'b' -> '\008' | 't' -> '\009' | c -> c let char_for_decimal_code lexbuf i = let c = 100 * (Char.code(Lexing.lexeme_char lexbuf i) - 48) + 10 * (Char.code(Lexing.lexeme_char lexbuf (i+1)) - 48) + (Char.code(Lexing.lexeme_char lexbuf (i+2)) - 48) in if (c < 0 || c > 255) then error "illegal escape sequence" ; Char.chr c let char_for_hexadecimal_code lexbuf i = let d1 = Char.code (Lexing.lexeme_char lexbuf i) in let val1 = if d1 >= 97 then d1 - 87 else if d1 >= 65 then d1 - 55 else d1 - 48 in let d2 = Char.code (Lexing.lexeme_char lexbuf (i+1)) in let val2 = if d2 >= 97 then d2 - 87 else if d2 >= 65 then d2 - 55 else d2 - 48 in Char.chr (val1 * 16 + val2) let buffer_rule r lb = let b = Buffer.create 64 in r b lb ; Buffer.contents b } let space = [' ' '\t' '\r'] let alpha = ['a'-'z' 'A'-'Z' '_'] let digit = ['0'-'9'] let char = ['-' '_' '+'] let achar = (alpha | digit | char) let ident = (alpha achar* (':' achar+)?) let relop = ('!'? '=' | [ '<' '>' ] '='?) let logop = ['|' '&'] let pfxop = '!' let envop_char = [ '+' ':' ] let envop = (envop_char '=' | '=' envop_char '='?) let int = ('-'? ['0'-'9']+) rule token = parse | space { token lexbuf } | '\n' { newline lexbuf; token lexbuf } | ":" { COLON } | "{" { LBRACE } | "}" { RBRACE } | "[" { LBRACKET } | "]" { RBRACKET } | "(" { LPAR } | ")" { RPAR } | '\"' { STRING (buffer_rule string lexbuf) } | "(*" { comment 1 lexbuf; token lexbuf } | "#" { comment_line lexbuf; token lexbuf } | "true" { BOOL true } | "false"{ BOOL false } | int { INT (int_of_string (Lexing.lexeme lexbuf)) } | ident { IDENT (Lexing.lexeme lexbuf) } | relop { RELOP (relop_of_string (Lexing.lexeme lexbuf)) } | logop { LOGOP (logop_of_string (Lexing.lexeme lexbuf)) } | pfxop { PFXOP (pfxop_of_string (Lexing.lexeme lexbuf)) } | envop { ENVOP (Lexing.lexeme lexbuf) } | eof { EOF } | _ { let token = Lexing.lexeme lexbuf in error "'%s' is not a valid token" token } and string b = parse | '\"' { () } | '\n' { newline lexbuf ; Buffer.add_char b '\n' ; string b lexbuf } | '\\' { (match escape lexbuf with | Some c -> Buffer.add_char b c | None -> ()); string b lexbuf } | _ as c { Buffer.add_char b c ; string b lexbuf } | eof { error "unterminated string" } and escape = parse | '\n' space * { newline lexbuf; None } | ['\\' '\"' ''' 'n' 'r' 't' 'b' ' '] as c { Some (char_for_backslash c) } | digit digit digit { Some (char_for_decimal_code lexbuf 0) } | 'x' ['0'-'9''a'-'f''A'-'F'] ['0'-'9''a'-'f''A'-'F'] { Some (char_for_hexadecimal_code lexbuf 1) } | "" { error "illegal escape sequence" } and comment n = parse | "*)" { if n > 1 then comment (n-1) lexbuf } | "(*" { comment (n+1)lexbuf } | eof { error "unterminated comment" } | '\n' { newline lexbuf; comment n lexbuf } | _ { comment n lexbuf } and comment_line = parse | [^'\n']* '\n' { newline lexbuf } | [^'\n'] { () } opam-full-1.2.2/src/core/opamFilename.mli0000644000175000017500000001766112517374212016764 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Typed filename manipulation *) (** Basenames *) module Base: OpamMisc.ABSTRACT (** Directory names *) module Dir: OpamMisc.ABSTRACT (** Return the current working directory *) val cwd: unit -> Dir.t (** Remove a directory *) val rmdir: Dir.t -> unit (** Clean the contents of a directory. *) val cleandir: Dir.t -> unit (** Create a directory *) val mkdir: Dir.t -> unit (** List the sub-directory recursively *) val rec_dirs: Dir.t -> Dir.t list val dir_is_empty: Dir.t -> bool (** List the sub-directory (do not recurse) *) val dirs: Dir.t -> Dir.t list (** Evaluate a function in a given directory *) val in_dir: Dir.t -> (unit -> 'a) -> 'a (** Turns an assoc list into an array suitable to be provided as environment *) val env_of_list: (string * string) list -> string array (** Execute a list of commands in a given directory *) val exec: Dir.t -> ?env:(string * string) list -> ?name:string -> ?metadata:(string * string) list -> ?keep_going:bool -> string list list -> unit (** Move a directory *) val move_dir: src:Dir.t -> dst:Dir.t -> unit (** Copy a directory *) val copy_dir: src:Dir.t -> dst:Dir.t -> unit (** Link a directory *) val link_dir: src:Dir.t -> dst:Dir.t -> unit (** Does the directory existsb ? *) val exists_dir: Dir.t -> bool (** Return the parent directory *) val dirname_dir: Dir.t -> Dir.t (** Return the deeper directory name *) val basename_dir: Dir.t -> Base.t (** Turn a full path into a list of directory names *) val to_list_dir: Dir.t -> Dir.t list (** Creation from a raw string (as {i http://}) *) val raw_dir: string -> Dir.t (** Execute a function in a temp directory *) val with_tmp_dir: (Dir.t -> 'a) -> 'a (** Provide an automatically cleaned up temp directory to a job *) val with_tmp_dir_job: (Dir.t -> 'a OpamProcess.job) -> 'a OpamProcess.job include OpamMisc.ABSTRACT (** Generic filename *) type generic_file = | D of Dir.t | F of t (** Create a filename from a Dir.t and a basename *) val create: Dir.t -> Base.t -> t (** Create a file from a basename and the current working directory as dirname *) val of_basename: Base.t -> t (** Creation from a raw string (as {i http://}) *) val raw: string -> t (** Prettify a filename: - replace /path/to/opam/foo by /foo - replace /path/to/home/foo by ~/foo *) val prettify: t -> string (** Prettify a dirname. *) val prettify_dir: Dir.t -> string (** Return the directory name *) val dirname: t -> Dir.t (** Return the base name *) val basename: t -> Base.t (** Retrieves the contents from the hard disk. *) val read: t -> string (** Open a channel from a given file. *) val open_in: t -> in_channel val open_out: t -> out_channel (** Removes everything in [filename] if existed. *) val remove: t -> unit (** Removes everything in [filename] if existed, then write [contents] instead. *) val write: t -> string -> unit (** Returns true if the file exists and is a regular file or a symlink to one *) val exists: t -> bool (** Check whether a file has a given suffix *) val check_suffix: t -> string -> bool (** Add a file extension *) val add_extension: t -> string -> t (** Remove the file extension *) val chop_extension: t -> t (** List all the filenames, recursively *) val rec_files: Dir.t -> t list (** List all the filename. Do not recurse. *) val files: Dir.t -> t list (** Apply a function on the contents of a file *) val with_contents: (string -> 'a) -> t -> 'a (** Copy a file in a directory. If [root] is set, copy also the sub-directories. For instance, [copy_in ~root:"/foo" "/foo/bar/gni" "/toto"] creates ["/toto/bar/gni"]. *) val copy_in: ?root:Dir.t -> t -> Dir.t -> unit (** Move a file *) val move: src:t -> dst:t -> unit (** Symlink a file in a directory *) val link_in: t -> Dir.t -> unit (** Read a symlinked file *) val readlink: t -> t (** Is a symlink ? *) val is_symlink: t -> bool (** Is an executable ? *) val is_exec: t -> bool (** Copy a file *) val copy: src:t -> dst:t -> unit (** Installs a file to a destination. Optionnally set if the destination should be set executable *) val install: ?exec:bool -> src:t -> dst:t -> unit -> unit (** Symlink a file. If symlink is not possible on the system, use copy instead. *) val link: src:t -> dst:t -> unit (** Extract an archive in a given directory (it rewrites the root to match [Dir.t] dir if needed) *) val extract: t -> Dir.t -> unit (** Extract an archive in a given directory (which should already exists) *) val extract_in: t -> Dir.t -> unit (** Extract a generic file *) val extract_generic_file: generic_file -> Dir.t -> unit (** Check whether a filename starts by a given Dir.t *) val starts_with: Dir.t -> t -> bool (** Check whether a filename ends with a given suffix *) val ends_with: string -> t -> bool (** Remove a prefix from a file name *) val remove_prefix: Dir.t -> t -> string (** Remove a suffix from a filename *) val remove_suffix: Base.t -> t -> string (** download a remote file in a given directory. Return the location of the downloaded file if the download is successful. Compress activates http content compression if supported. May break on gzipped files, only use for text files *) val download: overwrite:bool -> ?compress:bool -> ?checksum:string -> t -> Dir.t -> t OpamProcess.job (** same as [download], but with a specified destination filename instead of a directory *) val download_as: overwrite:bool -> ?compress:bool -> ?checksum:string -> t -> t -> unit OpamProcess.job (** Apply a patch to a directory *) val patch: t -> Dir.t -> unit (** Compute the MD5 digest of a file *) val digest: t -> string (** Compute the MD5 digest a file. Return the empty list if the file does not exist. *) val checksum: t -> string list (** Compute the MD5 digest for all files in a directory. *) val checksum_dir: Dir.t -> string list (** Create an empty file *) val touch: t -> unit (** Change file permissions *) val chmod: t -> int -> unit (** File locks *) val with_flock: ?read:bool -> t -> ('a -> 'b) -> 'a -> 'b (** [copy_if_check t src dst] copies all the files from one directory to another. Do nothing if OPAMDONOTCOPYFILE is set to a non-empty value. *) val copy_files: src:Dir.t -> dst:Dir.t -> unit module OP: sig (** Create a new directory *) val (/): Dir.t -> string -> Dir.t (** Create a new filename *) val (//): Dir.t -> string -> t end (** Simple structure to hanle file attributes *) module Attribute: sig include OpamMisc.ABSTRACT val to_string_list: t -> string list val of_string_list: string list -> t (** Get remote filename *) val base: t -> Base.t (** MD5 digest of the remote file *) val md5: t -> string (** File permission *) val perm: t -> int option (** Constructor*) val create: Base.t -> string -> int -> t end (** Convert a filename to an attribute, relatively to a root *) val to_attribute: Dir.t -> t -> Attribute.t opam-full-1.2.2/src/core/opamRepositoryName.ml0000644000175000017500000000232712517374212020044 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) include OpamMisc.Base let default = of_string OpamGlobals.default_repository_name opam-full-1.2.2/src/core/opamFormat.mli0000644000175000017500000002147312517374212016470 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Format of OPAM configuration files. *) open OpamTypes (** The empty file *) val empty : file (** map a file *) val map: (string -> value -> (string * value) option) -> file -> file (** Get all the variable definitions from a list of items *) val variables : file_item list -> (string * value) list (** Get all the sections from a list of items *) val sections : file_item list -> (string * file_section) list (** Check whether a list of items contains only valid variable definitions *) val is_valid : file_item list -> string list -> bool (** Find all the invalid fields *) val invalid_fields : file_item list -> string list -> string list (** {2 Parsing functions} *) (** All the following parsing function raise [Bad_format] in case the input does not have the right format. *) exception Bad_format of pos option * string list * string (** Raise [Bad_format]. *) val bad_format: ?pos:pos -> ('a, unit, string, 'b) format4 -> 'a val string_of_bad_format: ?file:filename -> exn -> string (** Adds a position to a Bad_format exception if it doesn't have one yet *) val add_pos: pos -> exn -> exn (** Get the position out of a value *) val value_pos: value -> pos (** Get the position of the first element out of a value list *) val values_pos: value list -> pos option (** Parse a boolean *) val parse_bool : value -> bool (** Parse an integer *) val parse_int: value -> int (** Parse an ident *) val parse_ident : value -> string (** Parse a string *) val parse_string : value -> string (** Parse a list of 'things' *) val parse_list : (value -> 'a) -> value -> 'a list (** Parse a list of list of 'things' *) val parse_list_list: (value -> 'a) -> value -> 'a list (** Parse a group of 'things' *) val parse_group : (value -> 'a) -> value -> 'a list (** Parse a value and its option of 'things' *) val parse_option : (value -> 'a) -> (value list -> 'b) -> value -> 'a * 'b option (** Parse a value and a single optional value *) val parse_single_option : (value -> 'a) -> (value -> 'b) -> value -> 'a * 'b option (** Parse a string with an optional argument *) val parse_string_option : (value list -> 'a) -> value -> string * 'a option (** Parse a list of strings *) val parse_string_list : value -> string list (** Parse a single string *) val parse_single_string: value list -> string (** Parse a pair of strings *) val parse_pair: (value -> 'a) -> (value -> 'b) -> value -> 'a * 'b (** Try to parse the value using function from the list. All the parsing functions are tried until one succeeds. The first argument is a debug message. *) val parse_or: (string * (value -> 'a)) list -> value -> 'a (** {2 Creation functions} *) (** Create a boolean *) val make_bool : bool -> value (** Create an integer *) val make_int: int -> value (** Create an ident *) val make_ident : string -> value (** Create a string *) val make_string : string -> value (** Create a list of 'things' *) val make_list : ('a -> value) -> 'a list -> value (** Create a list of strings *) val make_string_list: string list -> value (** Create a group of 'things' *) val make_group : ('a -> value) -> 'a list -> value (** Create a value and its optional arguments *) val make_option : ('a -> value) -> ('b -> value list) -> ('a * 'b option) -> value (** Create a pair *) val make_pair: ('a -> value) -> ('b -> value) -> ('a * 'b) -> value (** Create a pair of strings *) val make_string_pair: string * string -> value (** Create a file section *) val make_section: file_section -> file_item (** Create a variable *) val make_variable: (string * value) -> file_item (** {2 Printing functions} *) (** Print a value *) val string_of_value : value -> string (** Print a list of values *) val string_of_values : value list -> string (** Print a file *) val string_of_file: simplify:bool -> file -> string (** {2 Finding functions} *) (** Get the value of a field *) val assoc : file_item list -> string -> (value -> 'a) -> 'a (** Get the value of a field. If the field does not exist, return None *) val assoc_option : file_item list -> string -> (value -> 'a) -> 'a option (** Get the value of a field. If the variable does not exist, return a default value *) val assoc_default : 'a -> file_item list -> string -> (value -> 'a) -> 'a (** Get the value associated to a variable. If the variable does not exists, return [] *) val assoc_list : file_item list -> string -> (value -> 'a list) -> 'a list (** Get the string list associated to a variable. If the variable does not exist, return [] *) val assoc_string_list : file_item list -> string -> string list (** Get one section of a certain kind *) val get_section_by_kind : file_item list -> string -> file_section (** Get all the sections of a certain kind *) val get_all_section_by_kind : file_item list -> string -> file_section list (** Get sections *) val assoc_sections: file_item list -> string -> (file_section -> 'a) -> 'a list (** {2 Formula} *) (** This section is dedicated to the parsing and creatin of dependency and conflict formaulas. It's maybe easier to do that directly in the parser ... *) open OpamTypes val parse_package_name : ?expected:name -> value -> name val parse_package_version : ?expected:version -> value -> version (** Parse package formula where AND are implicit: [x y -> x & y] *) val parse_formula : value -> formula (** Build a formula where AND are implicit. *) val make_formula : formula -> value (** Parse an AND formula where constraints are extended with leading keywords *) val parse_ext_formula : value -> ext_formula (** Make an AND formula where constraints are extended with leading keywords *) val make_ext_formula : ext_formula -> value (** Parse optional package formula where OR are implicit: [x y -> x | y] *) val parse_opt_formula : value -> ext_formula (** Build a formula where OR are implicit. *) val make_opt_formula : ext_formula -> value (** Parse compiler versions *) val parse_compiler_version: value -> compiler_version (** Parse compiler constraints *) val parse_compiler_constraint: value -> compiler_constraint (** Build a compiler constraint *) val make_compiler_constraint: compiler_constraint -> value (** Parse an OS constraint *) val parse_os_constraint: value -> (bool * string) generic_formula (** Build an OS constraint *) val make_os_constraint: (bool * string) generic_formula -> value (** {2 Environment variables} *) (** Parsing *) val parse_env_variable: value -> (string * string * string) (** Making *) val make_env_variable: (string * string * string) -> value (** {2 filter expressions} *) (** Parsing *) val parse_filter: value list -> filter (** Creation *) val make_filter: filter -> value list (** Unfiltered argument list *) val parse_single_command: value -> arg list val make_single_command: arg list -> value (** Parse a command *) val parse_command: value -> command (** Create a command *) val make_command: command -> value (** Parse a list of commands *) val parse_commands: value -> command list (** Create a list of commands *) val make_commands: command list -> value (** Parse a list of commands *) val parse_messages: value -> (string * filter option) list (** Create a list of libraries/syntax *) val make_libraries: (string * filter option) list -> value (** Parse a list of libraries/syntax *) val parse_libraries: value -> (string * filter option) list (** Create a package flag *) val make_flag: package_flag -> value (** Parse a package flag *) val parse_flag: value -> package_flag (** {2 Tags} *) (** Parse tags *) val parse_tags: value -> tags (** Make tags *) val make_tags: tags -> value (** {2 Features} *) (** Parse features list *) val parse_features: value -> (OpamVariable.t * string * filter) list (** Make features list *) val make_features: (OpamVariable.t * string * filter) list -> value opam-full-1.2.2/src/core/opamRepository.ml0000644000175000017500000003255712517374212017253 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamMisc.OP open OpamFilename.OP open OpamProcess.Job.Op let log fmt = OpamGlobals.log "REPOSITORY" fmt let slog = OpamGlobals.slog let compare r1 r2 = match compare r2.repo_priority r1.repo_priority with | 0 -> compare r2.repo_name r1.repo_name | x -> x let to_string r = Printf.sprintf "%s(%d %s %s)" (OpamRepositoryName.to_string r.repo_name) r.repo_priority (string_of_repository_kind r.repo_kind) (string_of_address r.repo_address) let default_address = OpamGlobals.default_repository_address, None let default () = { repo_name = OpamRepositoryName.default; repo_kind = `http; repo_address = default_address; repo_priority = 0; repo_root = OpamPath.Repository.create (OpamPath.root()) OpamRepositoryName.default; } let local dirname = { repo_name = OpamRepositoryName.of_string "local"; repo_root = dirname; repo_address = ("", None); repo_kind = `local; repo_priority = 0; } let to_json r = `O [ ("name", OpamRepositoryName.to_json r.repo_name); ("kind", `String (string_of_repository_kind r.repo_kind)); ] module O = struct type tmp = repository type t = tmp let compare = compare let hash t = Hashtbl.hash (t.repo_name, t.repo_priority) let equal t1 t2 = compare t1 t2 = 0 let to_string = to_string let to_json = to_json end let of_string _ = failwith "TOTO" module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) module type BACKEND = sig val pull_url: package -> dirname -> string option -> address -> generic_file download OpamProcess.job val pull_repo: repository -> unit OpamProcess.job val pull_archive: repository -> filename -> filename download OpamProcess.job val revision: repository -> version option OpamProcess.job end exception Unknown_backend let backends = Hashtbl.create 8 let find_backend r = try Hashtbl.find backends r.repo_kind with Not_found -> raise Unknown_backend let find_backend_by_kind k = try Hashtbl.find backends k with Not_found -> raise Unknown_backend let register_backend name backend = Hashtbl.replace backends name backend (* initialize the current directory *) let init repo = log "init %a" (OpamGlobals.slog to_string) repo; let module B = (val find_backend repo: BACKEND) in OpamFilename.rmdir repo.repo_root; OpamFilename.mkdir repo.repo_root; OpamFile.Repo_config.write (OpamPath.Repository.config repo) repo; OpamFilename.mkdir (OpamPath.Repository.packages_dir repo); OpamFilename.mkdir (OpamPath.Repository.archives_dir repo); OpamFilename.mkdir (OpamPath.Repository.compilers_dir repo); Done () open OpamProcess.Job.Op let pull_url kind package local_dirname checksum remote_url = if !OpamGlobals.req_checksums && checksum = None then OpamGlobals.error_and_exit "Checksum required for %s, but not found in package description.\n\ This may be due to an outdated package description, try running `opam update`.\n\ In case an update does not fix the problem, you can bypass the check by not\n\ passing the `--require-checksums` command line option." (OpamPackage.to_string package); let pull url = let module B = (val find_backend_by_kind kind: BACKEND) in B.pull_url package local_dirname checksum url in let rec attempt = function | [] -> assert false | [url] -> pull url | url::mirrors -> pull url @@+ function | Not_available s -> OpamGlobals.warning "download of %s failed, trying mirror" s; attempt mirrors | r -> Done r in attempt remote_url let revision repo = let kind = repo.repo_kind in let module B = (val find_backend_by_kind kind: BACKEND) in B.revision repo let pull_url_and_fix_digest kind package dirname checksum file url = pull_url kind package dirname None url @@+ function | Not_available _ | Up_to_date _ | Result (D _) as r -> Done r | Result (F f) as r -> let actual = OpamFilename.digest f in if checksum <> actual then ( OpamGlobals.msg "Fixing wrong checksum for %s: current value is %s, setting it to %s.\n" (OpamPackage.to_string package) checksum actual; let u = OpamFile.URL.read file in OpamFile.URL.write file (OpamFile.URL.with_checksum u actual) ); Done r let check_digest filename = function | Some expected when not (!OpamGlobals.no_checksums) -> let actual = OpamFilename.digest filename in if actual = expected then true else (OpamGlobals.error "Bad checksum for %s:\n\ \ - %s [expected result]\n\ \ - %s [actual result]\n\ This may be fixed by running `opam update`.\n" (OpamFilename.to_string filename) expected actual; false) | _ -> true let pull_archive repo nv = let module B = (val find_backend_by_kind repo.repo_kind: BACKEND) in let filename = OpamPath.Repository.remote_archive repo nv in B.pull_archive repo filename let check_version repo = let repo_version = repo |> OpamPath.Repository.repo |> OpamFile.Repo.safe_read |> OpamFile.Repo.opam_version in if not !OpamGlobals.skip_version_checks && OpamVersion.compare repo_version OpamVersion.current > 0 then OpamGlobals.error_and_exit "The current version of OPAM cannot read the repository %S. \n\ You should upgrade to at least version %s.\n" (OpamRepositoryName.to_string repo.repo_name) (OpamVersion.to_string repo_version) else Done () let extract_prefix repo dir nv = let prefix = let prefix = OpamFilename.Dir.to_string (OpamPath.Repository.packages_dir repo) in prefix ^ Filename.dir_sep in let suffix = let suffix = OpamPackage.to_string nv in Filename.dir_sep ^ suffix in let dir = OpamFilename.Dir.to_string dir in OpamMisc.remove_prefix ~prefix (OpamMisc.remove_suffix ~suffix dir) let file f = if OpamFilename.exists f then [f] else [] let dir d = if OpamFilename.exists_dir d then OpamFilename.rec_files d else [] (* Compiler updates *) let compilers_with_prefixes r = OpamCompiler.prefixes (OpamPath.Repository.compilers_dir r) let compilers repo = OpamCompiler.list (OpamPath.Repository.compilers_dir repo) let compiler_files repo prefix c = let comp = OpamPath.Repository.compiler_comp repo prefix c in let descr = OpamPath.Repository.compiler_descr repo prefix c in file comp @ file descr let compiler_state repo prefix c = let fs = compiler_files repo prefix c in List.flatten (List.map OpamFilename.checksum fs) let packages r = OpamPackage.list (OpamPath.Repository.packages_dir r) let packages_with_prefixes r = OpamPackage.prefixes (OpamPath.Repository.packages_dir r) (* Returns the meaningful checksum of a url file. Uses the hash of the remote archive if present, or its address, not the hash of the url file itself which doesn't really matter *) let url_checksum url = let u = OpamFile.URL.safe_read url in if u = OpamFile.URL.empty then [] else match OpamFile.URL.checksum u with | Some cksum -> [cksum] | None -> [Digest.string (string_of_address (OpamFile.URL.url u))] let package_files repo prefix nv ~archive = let opam = OpamPath.Repository.opam repo prefix nv in let descr = OpamPath.Repository.descr repo prefix nv in let url = OpamPath.Repository.url repo prefix nv in let files = OpamPath.Repository.files repo prefix nv in let archive = if archive then file (OpamPath.Repository.archive repo nv) else [] in file opam @ file descr @ file url @ dir files @ archive let package_important_files repo prefix nv ~archive = let url = OpamPath.Repository.url repo prefix nv in let files = OpamPath.Repository.files repo prefix nv in if archive then let archive = OpamPath.Repository.archive repo nv in file url @ dir files @ file archive else file url @ dir files let package_state repo prefix nv all = let fs = match all with | `all -> package_files repo prefix nv ~archive:true | `partial b -> package_important_files repo prefix nv ~archive:b in let url = OpamPath.Repository.url repo prefix nv in let l = List.map (fun f -> if all <> `all && f = url then url_checksum f else OpamFilename.checksum f) fs in List.flatten l (* Sort repositories by priority *) let sort repositories = let repositories = OpamRepositoryName.Map.values repositories in List.sort compare repositories let package_index repositories = log "package-index"; let repositories = sort repositories in List.fold_left (fun map repo -> let packages = packages_with_prefixes repo in OpamPackage.Map.fold (fun nv prefix map -> if OpamPackage.Map.mem nv map then map else OpamPackage.Map.add nv (repo.repo_name, prefix) map ) packages map ) OpamPackage.Map.empty repositories let compiler_index repositories = log "compiler-index"; let repositories = sort repositories in List.fold_left (fun map repo -> let comps = compilers_with_prefixes repo in OpamCompiler.Map.fold (fun comp prefix map -> if OpamCompiler.Map.mem comp map then map else OpamCompiler.Map.add comp (repo.repo_name, prefix) map ) comps map ) OpamCompiler.Map.empty repositories let update repo = log "update %a" (slog to_string) repo; let module B = (val find_backend repo: BACKEND) in B.pull_repo repo let make_archive ?(gener_digest=false) repo prefix nv = let url_file = OpamPath.Repository.url repo prefix nv in let files_dir = OpamPath.Repository.files repo prefix nv in let archive = OpamPath.Repository.archive repo nv in let archive_dir = OpamPath.Repository.archives_dir repo in if not (OpamFilename.exists_dir archive_dir) then OpamFilename.mkdir archive_dir; (* Download the remote file / fetch the remote repository *) let download download_dir = if OpamFilename.exists url_file then ( let url = OpamFile.URL.read url_file in let checksum = OpamFile.URL.checksum url in let remote_url = OpamFile.URL.url url in let mirrors = remote_url :: OpamFile.URL.mirrors url in let kind = OpamFile.URL.kind url in log "downloading %a:%a" (slog string_of_address) remote_url (slog string_of_repository_kind) kind; if not (OpamFilename.exists_dir download_dir) then OpamFilename.mkdir download_dir; match checksum with | Some c when gener_digest -> pull_url_and_fix_digest kind nv download_dir c url_file mirrors @@+ fun f -> Done (Some f) | _ -> pull_url kind nv download_dir checksum mirrors @@+ fun f -> Done (Some f) ) else Done None in (* if we've downloaded a file, extract it, otherwise just copy it *) let extract local_filename extract_dir = match local_filename with | None -> () | Some (Not_available u) -> OpamGlobals.error_and_exit "%s is not available" u | Some ( Result r | Up_to_date r ) -> OpamFilename.extract_generic_file r extract_dir in (* Eventually add /files/* into the extracted dir *) let copy_files extract_dir = if OpamFilename.exists_dir files_dir then ( if not (OpamFilename.exists_dir extract_dir) then OpamFilename.mkdir extract_dir; OpamFilename.copy_files ~src:files_dir ~dst:extract_dir; OpamFilename.Set.of_list (OpamFilename.rec_files extract_dir) ) else OpamFilename.Set.empty in (* Finally create the final archive *) let create_archive files extract_root = if not (OpamFilename.Set.is_empty files) || OpamFilename.exists url_file then ( OpamGlobals.msg "Creating %s.\n" (OpamFilename.to_string archive); OpamFilename.exec extract_root [ [ "tar" ; "czf" ; OpamFilename.to_string archive ; OpamPackage.to_string nv ] ]; Some archive ) else None in OpamFilename.with_tmp_dir_job (fun extract_root -> OpamFilename.with_tmp_dir_job (fun download_dir -> download download_dir @@+ fun local_filename -> let extract_dir = extract_root / OpamPackage.to_string nv in extract local_filename extract_dir; let files = copy_files extract_dir in match create_archive files extract_root with | None | Some _ -> Done () ) ) module Graph = OpamParallel.MakeGraph (O) module Parallel = Graph.Parallel let find_backend = find_backend_by_kind opam-full-1.2.2/src/core/opamMisc.mli0000644000175000017500000002425712517374212016136 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Basic functions *) (** {2 Abstract types} *) (** Collection of abstract values *) module type SET = sig include Set.S (** auto-map *) val map: (elt -> elt) -> t -> t (** Return one element. Fail if the set is not a singleton. *) val choose_one : t -> elt (** Make a set from a list *) val of_list: elt list -> t (** Pretty-print a set *) val to_string: t -> string (** Return a JSON representation of the given set *) val to_json: t -> OpamJson.t (** Find an element in the list *) val find: (elt -> bool) -> t -> elt module Op : sig val (++): t -> t -> t (** Infix set union *) val (--): t -> t -> t (** Infix set difference *) val (%%): t -> t -> t (** Infix set intersection *) end end (** Dictionaries of abstract values *) module type MAP = sig include Map.S (** Pretty-printing *) val to_string: ('a -> string) -> 'a t -> string (** Return a JSON representation of the given map. *) val to_json: ('a -> OpamJson.t) -> 'a t -> OpamJson.t (** Return the values in the map. *) val values: 'a t -> 'a list (** Return the keys in the map. *) val keys: 'a t -> key list (** A key will be in the union of [m1] and [m2] if it is appears either [m1] or [m2], with the corresponding value. If a key appears in both [m1] and [m2], then the resulting value is built using the function given as argument. *) val union: ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t (** Convert an assoc list to a map *) val of_list: (key * 'a) list -> 'a t end (** All abstract types should implement this signature *) module type ABSTRACT = sig (** ABSTRACT type *) type t (** Create an abstract value from a string *) val of_string: string -> t (** Convert an abstract value to a string *) val to_string: t -> string (** Convert an abstract value to a JSON object *) val to_json: t -> OpamJson.t module Set: SET with type elt = t module Map: MAP with type key = t end (** Extended sets and maps *) module type OrderedType = sig include Set.OrderedType val to_string: t -> string val to_json: t -> OpamJson.t end (** Set constructor *) module Set: sig module Make (S: OrderedType): SET with type elt = S.t end (** Map constructor *) module Map: sig module Make (S: OrderedType): MAP with type key = S.t end (** Base module, useful to abstract strings *) module Base: sig type t = string val of_string: string -> t val to_string: t -> string val to_json: t -> OpamJson.t module Map: MAP with type key = string module Set: SET with type elt = string end (** {2 Integer manipulation} *) (** Map of ints *) module IntMap: MAP with type key = int (** Set of ints *) module IntSet: SET with type elt = int (** Convert list items to string and concat. [sconcat_map sep f x] is equivalent to String.concat sep (List.map f x) but tail-rec. *) val sconcat_map: ?left:string -> ?right:string -> ?nil:string -> string -> ('a -> string) -> 'a list -> string (** Display a list of strings *) val string_of_list: ('a -> string) -> 'a list -> string (** Convert a list of items to string as a dashed list *) val itemize: ?bullet:string -> ('a -> string) -> 'a list -> string val string_map: (char -> char) -> string -> string (** Display a pretty list: ["x";"y";"z"] -> "x, y and z". "and" can be changed by specifying [last] *) val pretty_list: ?last:string -> string list -> string (** Removes consecutive duplicates in a list *) val remove_duplicates: 'a list -> 'a list (** {2 String manipulation} *) (** Map of strings *) module StringMap: MAP with type key = string (** Set of strings *) module StringSet: SET with type elt = string (** Set of string sets *) module StringSetSet: SET with type elt = StringSet.t (** Map of string sets *) module StringSetMap: MAP with type key = StringSet.t (** Strip a string *) val strip: string -> string (** Does a string starts with the given prefix ? *) val starts_with: prefix:string -> string -> bool (** Does a string ends with the given suffix ? *) val ends_with: suffix:string -> string -> bool (** Remove a prefix *) val remove_prefix: prefix:string -> string -> string (** Remove a suffix *) val remove_suffix: suffix:string -> string -> string (** Cut a string at the first occurence of the given char *) val cut_at: string -> char -> (string * string) option (** Same as [cut_at], but starts from the right *) val rcut_at: string -> char -> (string * string) option (** Does a string contains the given chars ? *) val contains: string -> char -> bool (** Split a string at occurences of a given characters. Empty strings are skipped. *) val split: string -> char -> string list (** The same as [split], but keep empty strings (leading, trailing or between contiguous delimiters) *) val split_delim: string -> char -> string list (** Returns the length of the string in terminal chars, ignoring ANSI color sequences from OpamGlobals.colorise *) val visual_length: string -> int (** left indenting. [~visual] can be used to indent eg. ANSI colored strings and should correspond to the visible characters of s *) val indent_left: string -> ?visual:string -> int -> string (** right indenting *) val indent_right: string -> ?visual:string -> int -> string (** Pads fields in a table with spaces for alignment. *) val align_table: string list list -> string list list (** Prints a table *) val print_table: out_channel -> sep:string -> string list list -> unit (** Cut a string *) val sub_at: int -> string -> string (** Cut long lines in string according to the terminal width *) val reformat: ?start_column:int -> ?indent:int -> string -> string (** {2 Option} *) module Option: sig val map: ('a -> 'b) -> 'a option -> 'b option val iter: ('a -> unit) -> 'a option -> unit val default: 'a -> 'a option -> 'a val default_map: 'a option -> 'a option -> 'a option val compare: ('a -> 'a -> int) -> 'a option -> 'a option -> int val to_string: ?none:string -> ('a -> string) -> 'a option -> string module Op: sig val (>>=): 'a option -> ('a -> 'b option) -> 'b option val (>>|): 'a option -> ('a -> 'b) -> 'b option val (+!): 'a option -> 'a -> 'a val (++): 'a option -> 'a option -> 'a option end end (** {2 Misc} *) (** Remove from a c-separated list of string the one with the given prefix *) val reset_env_value: prefix:string -> char -> string -> string list (** split a c-separated list of string in two according to the first occurrences of the string with the given [prefix]. The list of elements occurring before is returned in reverse order. If there are other elements with the same [prefix] they are kept in the second list. *) val cut_env_value: prefix:string -> char -> string -> string list * string list (** if rsync -arv return 4 lines, this means that no files have changed *) val rsync_trim: string list -> string list (** Exact regexp matching *) val exact_match: Re.re -> string -> bool (** Filter and map *) val filter_map: ('a -> 'b option) -> 'a list -> 'b list (** Insert a value in an ordered list *) val insert: ('a -> 'a -> int) -> 'a -> 'a list -> 'a list (** Lazy environment variable *) val getenv: string -> string (** Lazy environment *) val env: unit -> (string * string) list (** To use when catching default exceptions: ensures we don't catch fatal errors like C-c. try-with should _always_ (by decreasing order of preference): - either catch specific exceptions - or re-raise the same exception - or call this function on the caught exception *) val fatal: exn -> unit (** Register a backtrace for when you need to process a finalizer (that internally uses exceptions) and then re-raise the same exception. To be printed by pretty_backtrace. *) val register_backtrace: exn -> unit (** Return a pretty-printed backtrace *) val pretty_backtrace: exn -> string (** Prettify a local path (eg. replace /home/me/ by '~') *) val prettify_path: string -> string module OP: sig (** Function application (with lower priority) (predefined in OCaml 4.01+) *) val (@@): ('a -> 'b) -> 'a -> 'b (** Pipe operator -- reverse application (predefined in OCaml 4.01+) *) val (|>): 'a -> ('a -> 'b) -> 'b (** Function composition : (f @* g) x =~ f (g x) *) val (@*): ('b -> 'c) -> ('a -> 'b) -> 'a -> 'c (** Reverse function composition : (f @> g) x =~ g (f x) *) val (@>): ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c end (** true if stdout is bound to a terminal *) val tty_out : bool (** When [stdout] refers to a terminal, query the number of columns. Otherwise return [max_int]. *) val terminal_columns : unit -> int (** Get the output of [uname -s] *) val uname_s: unit -> string option (** Get the output of [uname -m] *) val uname_m: unit -> string option (** Guess the shell compat-mode *) val guess_shell_compat: unit -> [`csh|`zsh|`sh|`bash|`fish] (** Guess the location of .profile *) val guess_dot_profile: [`csh|`zsh|`sh|`bash|`fish] -> string (** Like Pervasives.at_exit but with the possibility to call manually (eg. before exec()) *) val at_exit: (unit -> unit) -> unit (** Calls the functions registered in at_exit *) val exec_at_exit: unit -> unit (** / *) val debug: bool ref opam-full-1.2.2/src/core/opamVariable.mli0000644000175000017500000000352212517374212016760 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** {2 Variable names} *) include OpamMisc.ABSTRACT (** Shortcut to variables *) type variable = t (** Variable contents *) type variable_contents = | B of bool | S of string (** Pretty print of variable contents *) val string_of_variable_contents: variable_contents -> string module Full: sig (** Fully qualified variable. *) include OpamMisc.ABSTRACT (** Create a variable local for a given library/syntax extension *) val create: OpamPackage.Name.t -> variable -> t (** Create a global variable *) val global: variable -> t (** Return the package the variable is defined in *) val package: t -> OpamPackage.Name.t (** Return the variable name *) val variable: t -> variable end opam-full-1.2.2/src/core/opamFilter.ml0000644000175000017500000002312712517374212016312 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamMisc.OP let log ?level fmt = OpamGlobals.log "FILTER" ?level fmt let slog = OpamGlobals.slog type env = full_variable -> variable_contents option type fident = name list * variable * (string * string) option let rec to_string = function | FBool b -> string_of_bool b | FString s -> Printf.sprintf "%S" s | FIdent (pkgs,var,converter) -> OpamMisc.sconcat_map "+" OpamPackage.Name.to_string pkgs ^ (if pkgs <> [] then ":" else "") ^ OpamVariable.to_string var ^ (match converter with | Some (it,ifu) -> "?"^it^":"^ifu | None -> "") | FOp(e,s,f) -> Printf.sprintf "%s %s %s" (to_string e) (string_of_relop s) (to_string f) | FAnd (e,f) -> Printf.sprintf "%s & %s" (to_string e) (to_string f) | FOr (e,f) -> Printf.sprintf "%s | %s" (to_string e) (to_string f) | FNot (FBool _ | FString _ | FIdent _ as e) -> Printf.sprintf "!%s" (to_string e) | FNot e -> Printf.sprintf "!(%s)" (to_string e) | FUndef -> "#undefined" let rec fold_down_left f acc filter = match filter with | FOp(l,_,r) | FAnd(l,r) | FOr(l,r) -> fold_down_left f (fold_down_left f (f acc filter) l) r | FNot(x) -> fold_down_left f (f acc filter) x | x -> f acc x (* ["%{xxx}%"] or ["%{xxx"] if unclosed *) let string_interp_regex = let open Re in let notclose = rep (seq [opt (char '%'); opt (char '}'); diff notnl (set "}%")]) in compile (seq [str "%{"; group notclose; opt (group (str "}%"))]) let fident_variables = function | [], var, _ -> [OpamVariable.Full.global var] | pkgs, var, _ -> List.map (fun n -> OpamVariable.Full.create n var) pkgs (* extracts variables appearing in interpolations in a string*) let string_variables s = let matches = let rec aux acc pos = try let ss = Re.exec ~pos string_interp_regex s in if Re.test ss 2 then aux (Re.get ss 1 :: acc) (fst (Re.get_ofs ss 0) + String.length (Re.get ss 0)) else aux acc (pos+1) with Not_found -> acc in aux [] 0 in List.fold_left (fun acc s -> try fident_variables (filter_ident_of_string s) @ acc with Failure _ -> acc) [] matches let variables filter = fold_down_left (fun acc -> function | FString s -> string_variables s @ acc | FIdent f -> fident_variables f @ acc | _ -> acc) [] filter (* Some cast functions on values *) let value ?default = function | FBool b -> B b | FString s -> S s | FUndef -> (match default with | Some d -> d | None -> failwith "Undefined filter value") | e -> raise (Invalid_argument ("filter value: "^to_string e)) let value_string ?default = function | FBool b -> string_of_bool b | FString s -> s | FUndef -> (match default with | Some d -> d | None -> failwith "Undefined string filter value") | e -> raise (Invalid_argument ("value_string: "^to_string e)) let value_bool ?default = function | FBool b -> b | FString "true" -> true | FString "false" -> false | FUndef -> (match default with | Some d -> d | None -> failwith "Undefined boolean filter value") | e -> (match default with | Some d -> d | None -> raise (Invalid_argument ("value_bool: "^to_string e))) (* Desugars the "enable" pseudo-variable *) let desugar_fident ((packages,var,converter) as fident) = let enable = OpamVariable.of_string "enable" in if packages <> [] && var = enable && converter = None then packages, OpamVariable.of_string "installed", Some ("enable","disable") else fident (* Resolves [FIdent] to string or bool, using its package and converter specification *) let resolve_ident env fident = let open OpamMisc.Option.Op in let packages,var,converter = desugar_fident fident in let bool_of_value = function | B b -> Some b | S s -> try Some (bool_of_string s) with Invalid_argument _ -> None in let resolve name = env (OpamVariable.Full.create name var) in let value_opt : variable_contents option = match packages with | [] -> env (OpamVariable.Full.global var) | [name] -> resolve name | names -> List.fold_left (fun acc name -> if acc = Some false then acc else match resolve name with | Some (B true) -> acc | v -> v >>= bool_of_value) (Some true) names >>| fun b -> B b in match converter with | None -> (match value_opt with | Some (B b) -> FBool b | Some (S s) -> FString s | None -> FUndef) | Some (iftrue, iffalse) -> match value_opt >>= bool_of_value with | Some true -> FString iftrue | Some false -> FString iffalse | None -> FString iffalse (* Resolves ["%{x}%"] string interpolations *) let expand_string env text = let subst str = if not (OpamMisc.ends_with ~suffix:"}%" str) then (log "ERR: Unclosed variable replacement in %S\n" str; str) else let str = String.sub str 2 (String.length str - 4) in resolve_ident env (filter_ident_of_string str) |> value_string ~default:"" in Re_pcre.substitute ~rex:string_interp_regex ~subst text let logop1 op = function | FUndef -> FUndef | e -> try FBool (op (value_bool e)) with Invalid_argument s -> log "ERR: %s" s; FUndef let logop2 op absorb e f = match e, f with | FUndef, x | x, FUndef -> if x = FBool absorb then x else FUndef | f, g -> try FBool (op (value_bool f) (value_bool g)) with Invalid_argument s -> log "ERR: %s" s; FUndef (* Reduce expressions to values *) let rec reduce_aux env = function | FUndef -> FUndef | FBool b -> FBool b | FString s -> FString s | FIdent i -> resolve_ident env i | FOp (e,relop,f) -> (match reduce env e, reduce env f with | FUndef, _ | _, FUndef -> FUndef | e,f -> FBool (OpamFormula.check_relop relop (Debian.Version.compare (value_string e) (value_string f)))) | FAnd (e,f) -> logop2 (&&) false (reduce env e) (reduce env f) | FOr (e,f) -> logop2 (||) true (reduce env e) (reduce env f) | FNot e -> logop1 not (reduce env e) and reduce env e = match reduce_aux env e with | FString s -> FString (expand_string env s) | e -> e let eval ?default env e = value ?default (reduce env e) let eval_to_bool ?default env e = value_bool ?default (reduce env e) let opt_eval_to_bool env opt = match opt with | None -> true | Some e -> value_bool ~default:false (reduce env e) let eval_to_string ?default env e = value_string ?default (reduce env e) let ident_of_var v = let p = OpamVariable.Full.package v in let var = OpamVariable.Full.variable v in if p = OpamPackage.Name.global_config then [], var, None else [p], var, None let ident_value ?default env id = value ?default (resolve_ident env id) let ident_string ?default env id = value_string ?default (resolve_ident env id) let ident_bool ?default env id = value_bool ?default (resolve_ident env id) (* Substitute the file contents *) let expand_interpolations_in_file env file = let f = OpamFilename.of_basename file in let src = OpamFilename.add_extension f "in" in let ic = OpamFilename.open_in src in let oc = OpamFilename.open_out f in let rec aux () = match try Some (input_line ic) with End_of_file -> None with | Some s -> output_string oc (expand_string env s); output_char oc '\n'; aux () | None -> () in aux (); close_in ic; close_out oc (* Apply filters and interpolations to package commands *) let arguments env (a,f) = if opt_eval_to_bool env f then match a with | CString s -> Some (expand_string env s) | CIdent i -> try let fident = filter_ident_of_string i in Some (value_string (resolve_ident env fident)) with Failure msg -> log "ERR in replacement: %s" msg; None else None let command env (l, f) = if opt_eval_to_bool env f then match OpamMisc.filter_map (arguments env) l with | [] -> None | l -> Some l else None let commands env l = OpamMisc.filter_map (command env) l let single_command env l = OpamMisc.filter_map (arguments env) l let simple_arg_variables = function | CString s -> string_variables s | CIdent i -> try fident_variables (filter_ident_of_string i) with Failure _ -> [] let filter_opt_variables = function | None -> [] | Some f -> variables f let argument_variables (a,f) = simple_arg_variables a @ filter_opt_variables f let command_variables (l,f) = List.fold_left (fun acc a -> argument_variables a @ acc) (filter_opt_variables f) l let commands_variables l = List.fold_left (fun acc c -> command_variables c @ acc) [] l opam-full-1.2.2/src/core/opamMisc.ml0000644000175000017500000004335612517374212015766 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamCompat module type SET = sig include Set.S val map: (elt -> elt) -> t -> t val choose_one : t -> elt val of_list: elt list -> t val to_string: t -> string val to_json: t -> OpamJson.t val find: (elt -> bool) -> t -> elt module Op : sig val (++): t -> t -> t val (--): t -> t -> t val (%%): t -> t -> t end end module type MAP = sig include Map.S val to_string: ('a -> string) -> 'a t -> string val to_json: ('a -> OpamJson.t) -> 'a t -> OpamJson.t val values: 'a t -> 'a list val keys: 'a t -> key list val union: ('a -> 'a -> 'a) -> 'a t -> 'a t -> 'a t val of_list: (key * 'a) list -> 'a t end module type ABSTRACT = sig type t val of_string: string -> t val to_string: t -> string val to_json: t -> OpamJson.t module Set: SET with type elt = t module Map: MAP with type key = t end module type OrderedType = sig include Set.OrderedType val to_string: t -> string val to_json: t -> OpamJson.t end let debug = ref false let sconcat_map ?(left="") ?(right="") ?nil sep f = function | [] -> (match nil with Some s -> s | None -> left^right) | l -> let seplen = String.length sep in let strs,len = List.fold_left (fun (strs,len) x -> let s = f x in s::strs, String.length s + seplen + len) ([],String.length left + String.length right - seplen) l in let buf = Bytes.create len in let prepend i s = let slen = String.length s in Bytes.blit_string s 0 buf (i - slen) slen; i - slen in let pos = prepend len right in let pos = prepend pos (List.hd strs) in let pos = List.fold_left (fun pos s -> prepend (prepend pos sep) s) pos (List.tl strs) in let pos = prepend pos left in assert (pos = 0); Bytes.to_string buf let string_of_list f = sconcat_map ~left:"{ " ~right:" }" ~nil:"{}" ", " f let itemize ?(bullet=" - ") f = sconcat_map ~left:bullet ~right:"\n" ~nil:"" ("\n"^bullet) f let string_map f s = let len = String.length s in let b = Bytes.create len in for i = 0 to len - 1 do Bytes.set b i (f s.[i]) done; Bytes.to_string b let rec pretty_list ?(last="and") = function | [] -> "" | [a] -> a | [a;b] -> Printf.sprintf "%s %s %s" a last b | h::t -> Printf.sprintf "%s, %s" h (pretty_list t) let rec remove_duplicates = function | a::(b::_ as r) when a = b -> remove_duplicates r | a::r -> a::remove_duplicates r | [] -> [] let max_print = 100 module Set = struct module Make (O : OrderedType) = struct module S = Set.Make(O) include S let fold f set i = let r = ref i in S.iter (fun elt -> r := f elt !r ) set; !r let choose_one s = match elements s with | [x] -> x | [] -> raise Not_found | _ -> invalid_arg "choose_one" let of_list l = List.fold_left (fun set e -> add e set) empty l let to_string s = if not !debug && S.cardinal s > max_print then Printf.sprintf "%d elements" (S.cardinal s) else let l = S.fold (fun nv l -> O.to_string nv :: l) s [] in string_of_list (fun x -> x) (List.rev l) let map f t = S.fold (fun e set -> S.add (f e) set) t S.empty let find fn s = choose (filter fn s) let to_json t = let elements = S.elements t in let jsons = List.map O.to_json elements in `A jsons module Op = struct let (++) = union let (--) = diff let (%%) = inter end end end module Map = struct module Make (O : OrderedType) = struct module M = Map.Make(O) include M let fold f map i = let r = ref i in M.iter (fun key value-> r:= f key value !r ) map; !r let map f map = fold (fun key value map -> add key (f value) map ) map empty let mapi f map = fold (fun key value map -> add key (f key value) map ) map empty let values map = List.rev (M.fold (fun _ v acc -> v :: acc) map []) let keys map = List.rev (M.fold (fun k _ acc -> k :: acc) map []) let union f m1 m2 = M.fold (fun k v m -> if M.mem k m then M.add k (f v (M.find k m)) (M.remove k m) else M.add k v m ) m1 m2 let to_string string_of_value m = if not !debug && M.cardinal m > max_print then Printf.sprintf "%d elements" (M.cardinal m) else let s (k,v) = Printf.sprintf "%s:%s" (O.to_string k) (string_of_value v) in let l = fold (fun k v l -> s (k,v)::l) m [] in string_of_list (fun x -> x) l let of_list l = List.fold_left (fun map (k,v) -> add k v map) empty l let to_json json_of_value t = let bindings = M.bindings t in let jsons = List.map (fun (k,v) -> `O [ ("key" , O.to_json k); ("value", json_of_value v) ] ) bindings in `A jsons end end module Base = struct type t = string let of_string x = x let to_string x = x let to_json x = `String x module O = struct type t = string let to_string = to_string let compare = compare let to_json = to_json end module Set = Set.Make(O) module Map = Map.Make(O) end let filter_map f l = let rec loop accu = function | [] -> List.rev accu | h :: t -> match f h with | None -> loop accu t | Some x -> loop (x::accu) t in loop [] l module OInt = struct type t = int let compare = compare let to_string = string_of_int let to_json i = `String (string_of_int i) end module IntMap = Map.Make(OInt) module IntSet = Set.Make(OInt) module OString = struct type t = string let compare = compare let to_string x = x let to_json x = `String x end module StringSet = Set.Make(OString) module StringMap = Map.Make(OString) module StringSetSet = Set.Make(StringSet) module StringSetMap = Map.Make(StringSet) module OP = struct let (@@) f x = f x let (|>) x f = f x let (@*) g f x = g (f x) let (@>) f g x = g (f x) end module Option = struct let map f = function | None -> None | Some x -> Some (f x) let iter f = function | None -> () | Some x -> f x let default dft = function | None -> dft | Some x -> x let default_map dft = function | None -> dft | some -> some let compare cmp o1 o2 = match o1,o2 with | None, None -> 0 | Some _, None -> 1 | None, Some _ -> -1 | Some x1, Some x2 -> cmp x1 x2 let to_string ?(none="") f = function | Some x -> f x | None -> none module Op = struct let (>>=) = function | None -> fun _ -> None | Some x -> fun f -> f x let (>>|) opt f = map f opt let (+!) opt dft = default dft opt let (++) = function | None -> fun opt -> opt | some -> fun _ -> some end end let strip str = let p = ref 0 in let l = String.length str in let fn = function | ' ' | '\t' | '\r' | '\n' -> true | _ -> false in while !p < l && fn (String.unsafe_get str !p) do incr p; done; let p = !p in let l = ref (l - 1) in while !l >= p && fn (String.unsafe_get str !l) do decr l; done; String.sub str p (!l - p + 1) let starts_with ~prefix s = let x = String.length prefix in let n = String.length s in n >= x && String.sub s 0 x = prefix let ends_with ~suffix s = let x = String.length suffix in let n = String.length s in n >= x && String.sub s (n - x) x = suffix let remove_prefix ~prefix s = if starts_with ~prefix s then let x = String.length prefix in let n = String.length s in String.sub s x (n - x) else s let remove_suffix ~suffix s = if ends_with ~suffix s then let x = String.length suffix in let n = String.length s in String.sub s 0 (n - x) else s let cut_at_aux fn s sep = try let i = fn s sep in let name = String.sub s 0 i in let version = String.sub s (i+1) (String.length s - i - 1) in Some (name, version) with Invalid_argument _ | Not_found -> None let cut_at = cut_at_aux String.index let rcut_at = cut_at_aux String.rindex let contains s c = try let _ = String.index s c in true with Not_found -> false let split s c = Re_str.split (Re_str.regexp (Printf.sprintf "[%c]+" c)) s let split_delim s c = Re_str.split_delim (Re_str.regexp (Printf.sprintf "[%c]" c)) s let visual_length_substring s ofs len = let rec aux s i = try let i = String.index_from s i '\027' in let j = String.index_from s (i+1) 'm' in if j > ofs + len then 0 else j - i + 1 + aux s (j+1) with Not_found | Invalid_argument _ -> 0 in len - aux s ofs let visual_length s = visual_length_substring s 0 (String.length s) let align_table ll = let rec transpose ll = if List.for_all ((=) []) ll then [] else let col, rest = List.fold_left (fun (col,rest) -> function | hd::tl -> hd::col, tl::rest | [] -> ""::col, []::rest) ([],[]) ll in List.rev col::transpose (List.rev rest) in let columns = transpose ll in let pad n s = let sn = visual_length s in if sn >= n then s else s ^ (String.make (n - sn) ' ') in let align sl = let len = List.fold_left (fun m s -> max m (visual_length s)) 0 sl in List.map (pad len) sl in transpose (List.map align columns) let print_table oc ~sep = List.iter (fun l -> let l = match l with s::l -> output_string oc s; l | [] -> [] in List.iter (fun s -> output_string oc sep; output_string oc s) l; output_char oc '\n') (* Remove from a c-separated list of string the one with the given prefix *) let reset_env_value ~prefix c v = let v = split_delim v c in List.filter (fun v -> not (starts_with ~prefix v)) v (* Split the list in two according to the first occurrence of the string starting with the given prefix. *) let cut_env_value ~prefix c v = let v = split_delim v c in let rec aux before = function | [] -> [], List.rev before | curr::after when starts_with ~prefix curr -> before, after | curr::after -> aux (curr::before) after in aux [] v (* if rsync -arv return 4 lines, this means that no files have changed *) let rsync_trim = function | [] -> [] | _ :: t -> match List.rev t with | _ :: _ :: _ :: l -> List.filter ((<>) "./") l | _ -> [] let exact_match re s = try let subs = Re.exec re s in let subs = Array.to_list (Re.get_all_ofs subs) in let n = String.length s in let subs = List.filter (fun (s,e) -> s=0 && e=n) subs in List.length subs > 0 with Not_found -> false (* XXX: not optimized *) let insert comp x l = let rec aux = function | [] -> [x] | h::t when comp h x < 0 -> h::aux t | l -> x :: l in aux l let env = lazy ( let e = Unix.environment () in List.rev_map (fun s -> match cut_at s '=' with | None -> s, "" | Some p -> p ) (Array.to_list e) ) let getenv n = List.assoc n (Lazy.force env) let env () = Lazy.force env let indent_left s ?(visual=s) nb = let nb = nb - String.length visual in if nb <= 0 then s else s ^ String.make nb ' ' let indent_right s ?(visual=s) nb = let nb = nb - String.length visual in if nb <= 0 then s else String.make nb ' ' ^ s let sub_at n s = if String.length s <= n then s else String.sub s 0 n (** To use when catching default exceptions: ensures we don't catch fatal errors like C-c *) let fatal e = match e with | Sys.Break -> prerr_newline (); raise e | Assert_failure _ | Match_failure _ -> raise e | _ -> () let register_backtrace, get_backtrace = let registered_backtrace = ref None in (fun e -> registered_backtrace := match !registered_backtrace with | Some (e1, _) as reg when e1 == e -> reg | _ -> Some (e, Printexc.get_backtrace ())), (fun e -> match !registered_backtrace with | Some(e1,bt) when e1 == e -> bt | _ -> Printexc.get_backtrace ()) let default_columns = 100 let with_process_in cmd args f = let path = ["/bin";"/usr/bin"] in let cmd = List.find Sys.file_exists (List.map (fun d -> Filename.concat d cmd) path) in let ic = Unix.open_process_in (cmd^" "^args) in try let r = f ic in ignore (Unix.close_process_in ic) ; r with exn -> ignore (Unix.close_process_in ic) ; raise exn let get_terminal_columns () = try (* terminfo *) with_process_in "tput" "cols" (fun ic -> int_of_string (input_line ic)) with Unix.Unix_error _ | Sys_error _ | Failure _ | End_of_file | Not_found -> try (* GNU stty *) with_process_in "stty" "size" (fun ic -> match split (input_line ic) ' ' with | [_ ; v] -> int_of_string v | _ -> failwith "stty") with Unix.Unix_error _ | Sys_error _ | Failure _ | End_of_file | Not_found -> try (* shell envvar *) int_of_string (getenv "COLUMNS") with Not_found | Failure _ -> default_columns let tty_out = Unix.isatty Unix.stdout let terminal_columns = let v = ref (lazy (get_terminal_columns ())) in let () = try Sys.set_signal 28 (* SIGWINCH *) (Sys.Signal_handle (fun _ -> v := lazy (get_terminal_columns ()))) with Invalid_argument _ -> () in fun () -> if tty_out then Lazy.force !v else 80 let reformat ?(start_column=0) ?(indent=0) s = let slen = String.length s in let buf = Buffer.create 1024 in let rec find_nonsp i = if i >= slen then i else match s.[i] with ' ' -> find_nonsp (i+1) | _ -> i in let rec find_split i = if i >= slen then i else match s.[i] with ' ' | '\n' -> i | _ -> find_split (i+1) in let newline i = Buffer.add_char buf '\n'; if i+1 < slen && s.[i+1] <> '\n' then for _i = 1 to indent do Buffer.add_char buf ' ' done in let rec print i col = if i >= slen then () else if s.[i] = '\n' then (newline i; print (i+1) indent) else let j = find_nonsp i in let k = find_split j in let len_visual = visual_length_substring s i (k - i) in if col + len_visual >= terminal_columns () && col > indent then (newline i; Buffer.add_substring buf s j (k - j); print k (indent + len_visual - j + i)) else (Buffer.add_substring buf s i (k - i); print k (col + len_visual)) in print 0 start_column; Buffer.contents buf let itemize ?(bullet=" - ") f = sconcat_map ~left:bullet ~right:"\n" ~nil:"" ("\n"^bullet) (fun s -> reformat ~indent:(String.length bullet) (f s)) let pretty_backtrace e = match get_backtrace e with | "" -> "" | b -> let b = itemize ~bullet:" " (fun x -> x) (split b '\n') in Printf.sprintf "Backtrace:\n%s" b let uname_s () = try with_process_in "uname" "-s" (fun ic -> Some (strip (input_line ic))) with Unix.Unix_error _ | Sys_error _ | Not_found -> None let uname_m () = try with_process_in "uname" "-m" (fun ic -> Some (strip (input_line ic))) with Unix.Unix_error _ | Sys_error _ | Not_found -> None let shell_of_string = function | "tcsh" | "csh" -> `csh | "zsh" -> `zsh | "bash" -> `bash | "fish" -> `fish | _ -> `sh let guess_shell_compat () = try shell_of_string (Filename.basename (getenv "SHELL")) with Not_found -> `sh let guess_dot_profile shell = let home f = try Filename.concat (getenv "HOME") f with Not_found -> f in match shell with | `fish -> List.fold_left Filename.concat (home ".config") ["fish"; "config.fish"] | `zsh -> home ".zshrc" | `bash -> (try List.find Sys.file_exists [ (* Bash looks up these 3 files in order and only loads the first, for LOGIN shells *) home ".bash_profile"; home ".bash_login"; home ".profile"; (* Bash loads .bashrc INSTEAD, for interactive NON login shells only; but it's often included from the above. We may include our variables in both to be sure ; for now we rely on non-login shells inheriting their env from a login shell somewhere... *) ] with Not_found -> (* iff none of the above exist, creating this should be safe *) home ".bash_profile") | `csh -> let cshrc = home ".cshrc" in let tcshrc = home ".tcshrc" in if Sys.file_exists cshrc then cshrc else tcshrc | _ -> home ".profile" let prettify_path s = let aux ~short ~prefix = let prefix = Filename.concat prefix "" in if starts_with ~prefix s then let suffix = remove_prefix ~prefix s in Some (Filename.concat short suffix) else None in try match aux ~short:"~" ~prefix:(getenv "HOME") with | Some p -> p | None -> s with Not_found -> s let registered_at_exit = ref [] let at_exit f = Pervasives.at_exit f; registered_at_exit := f :: !registered_at_exit let exec_at_exit () = List.iter (fun f -> try f () with _ -> ()) !registered_at_exit opam-full-1.2.2/src/core/opamParser.mly0000644000175000017500000000714012517374212016507 0ustar useruser/**************************************************************************/ /* */ /* Copyright 2012-2013 OCamlPro */ /* Copyright 2012 INRIA */ /* */ /* All rights reserved.This file is distributed under the terms of the */ /* GNU Lesser General Public License version 3.0 with linking */ /* exception. */ /* */ /* OPAM 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. */ /* */ /**************************************************************************/ %{ open OpamTypes open OpamTypesBase let get_pos n = let pos = Parsing.rhs_start_pos n in Lexing.(OpamFilename.of_string pos.pos_fname, pos.pos_lnum, pos.pos_cnum - pos.pos_bol) %} %token STRING IDENT %token BOOL %token EOF %token LBRACKET RBRACKET %token LPAR RPAR %token LBRACE RBRACE %token COLON %token INT %token RELOP %token LOGOP %token PFXOP %token ENVOP %left COLON %left ATOM %left LOGOP %nonassoc ENVOP %nonassoc PFXOP %left LBRACE RBRACE %nonassoc RELOP %nonassoc URELOP %start main value %type OpamTypes.file> main %type value %% main: | items EOF { fun file_name -> { file_contents = $1; file_name; file_format = OpamVersion.current } } ; items: | item items { $1 :: $2 } | { [] } ; item: | IDENT COLON value { Variable (get_pos 1, $1, $3) } | IDENT STRING LBRACE items RBRACE { Section (get_pos 1, {section_kind=$1; section_name=$2; section_items= $4}) } ; value: | atom %prec ATOM { $1 } | LPAR values RPAR { Group (get_pos 1,$2) } | LBRACKET values RBRACKET { List (get_pos 1,$2) } | value LBRACE values RBRACE { Option (get_pos 2,$1, $3) } | value LOGOP value { Logop (get_pos 2,$2,$1,$3) } | atom RELOP atom { Relop (get_pos 2,$2,$1,$3) } | atom ENVOP atom { Env_binding (get_pos 1,$2,$1,$3) } | PFXOP value { Pfxop (get_pos 1,$1,$2) } | RELOP atom { Prefix_relop (get_pos 1,$1,$2) } ; values: | { [] } | value values { $1 :: $2 } ; atom: | IDENT { Ident (get_pos 1,$1) } | BOOL { Bool (get_pos 1,$1) } | INT { Int (get_pos 1,$1) } | STRING { String (get_pos 1,$1) } ; %% let error lexbuf exn msg = let curr = lexbuf.Lexing.lex_curr_p in let start = lexbuf.Lexing.lex_start_p in OpamGlobals.error "File %S, line %d, character %d-%d: %s." curr.Lexing.pos_fname start.Lexing.pos_lnum (start.Lexing.pos_cnum - start.Lexing.pos_bol) (curr.Lexing.pos_cnum - curr.Lexing.pos_bol) msg; raise exn let main t l f = try let r = main t l f in Parsing.clear_parser (); r with | Lexer_error msg as e -> Parsing.clear_parser (); error l e msg | Parsing.Parse_error as e -> Parsing.clear_parser (); error l e "parse error" opam-full-1.2.2/src/core/opamVariable.ml0000644000175000017500000000455112517374212016612 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) include OpamMisc.Base type variable = t type variable_contents = | B of bool | S of string let string_of_variable_contents = function | B b -> string_of_bool b | S s -> s module Full = struct type t = { package : OpamPackage.Name.t; variable: variable; } let variable t = t.variable let package t = t.package let create package variable = { package; variable } let global variable = create OpamPackage.Name.global_config variable let of_string s = match OpamMisc.rcut_at s ':' with | None -> create OpamPackage.Name.global_config (of_string s) | Some (p,v) -> let v = of_string v in create (OpamPackage.Name.of_string p) v let to_string t = let prefix = let n = OpamPackage.Name.to_string (package t) in if n = OpamGlobals.global_config then "" else n in let prefix = if prefix = "" then "" else prefix ^ ":" in prefix ^ to_string t.variable let to_json x = `String (to_string x) module O = struct type tmp = t type t = tmp let compare = compare let to_string = to_string let to_json = to_json end module Set = OpamMisc.Set.Make(O) module Map = OpamMisc.Map.Make(O) end opam-full-1.2.2/src/core/opamPath.mli0000644000175000017500000002505412517374212016133 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** The various paths where OPAM configuration files are stored. *) open OpamTypes (** {2 Global paths} *) (** Type of path root *) type t = dirname (** Default root path *) val root: unit -> t (** State cache *) val state_cache: t -> filename (** Update cache *) val update_cache: t -> filename (** lock file *) val lock: t -> filename (** Main configuration file: {i $opam/config} *) val config: t -> filename (** Compiler aliases *) val aliases: t -> filename (** Package directroy {i $opam/packages/} *) val packages_dir: t -> dirname (** Package sub-directory {i $opam/packages/$NAME/$NAME.$VERSION/} *) val packages: t -> package -> dirname (** OPAM files: {i $opam/packages/$NAME/$NAME.$VERSION/opam} *) val opam: t -> package -> filename (** URL files: {i $opam/packages/$NAME/$NAME.$VERSION/url} *) val url: t -> package -> filename (** Additional files: {i $opam/packages/$NAME/$NAME.$VERSION/files} *) val files: t -> package -> dirname (** Temporary folder for dev packages {i $opam/packages.dev/} *) val dev_packages_dir: t -> dirname (** Temporary folder for dev packages {i $opam/packages.dev/$NAME.$VERSION/} *) val dev_package: t -> package -> dirname (** Description file: {i $opam/packages/$NAME/$NAME.$VERSION/descr} *) val descr: t -> package -> filename (** Archives dir *) val archives_dir: t -> dirname (** Archive file: {i $opam/archives/$NAME.$VERSION+opam.tar.gz} *) val archive: t -> package -> filename (** Compiler files: {i $opam/compilers/$VERSION/$COMP.comp} *) val compiler_comp: t -> compiler -> filename (** Compiler description files: {i $opam/compilers/$VERSION/$COMP.descr} *) val compiler_descr: t -> compiler -> filename (** Compiler files: {i $opam/compilers/} *) val compilers_dir: t -> dirname (** Compiler subdir {i $opam/compilers/$VERSION/$COMP} *) val compilers: t -> compiler -> dirname (** Return the repository index: {i $opam/repo/package-index} *) val package_index: t -> filename (** Return the repository index: {i $opam/repo/compiler-index} *) val compiler_index: t -> filename (** Init scripts *) val init: t -> dirname (** Log dir {i $opam/log} *) val log: t -> dirname (** The directory where global backups are stored *) val backup_dir: t -> dirname (** Backup file for state export *) val backup: t -> filename (** Switch related paths *) module Switch: sig (** Root dir: {i $opam/$switch} *) val root: t -> switch -> dirname (** lock file: {i $opam/lock} *) val lock: t -> switch -> filename (** The directory where backups are stored for this switch *) val backup_dir: t -> switch -> dirname (** Backup file for state export *) val backup: t -> switch -> filename (** Library path for a given package: {i $opam/$switch/lib/$name} *) val lib: t -> switch -> name -> dirname (** Library path: {i $opam/$switch/lib} *) val lib_dir: t -> switch -> dirname (** DLL paths *) val stublibs: t -> switch -> dirname (** toplevel path: {i $opam/$switch/lib/toplevel} *) val toplevel: t -> switch -> dirname (** Documentation path for a given package: {i $opam/$switch/doc/$name} *) val doc: t -> switch -> name -> dirname (** Documentation path: {i $opam/$switch/doc/} *) val doc_dir: t -> switch -> dirname (** Shared directory: {i $opam/$switch/share} *) val share_dir: t -> switch -> dirname (** Share directory for a given package: {i $opam/$switch/share/$package} *) val share: t -> switch -> name -> dirname (** Etc directory: {i $opam/$switch/etc} *) val etc_dir: t -> switch -> dirname (** Etc directory for a given package: {i $opam/$switch/etc/$package} *) val etc: t -> switch -> name -> dirname (** Man pages path: {i $opam/$switch/man/}. The optional [num] argument will add a {i manN } suffix if specified *) val man_dir: ?num:string -> t -> switch -> dirname (** Installed binaries: {i $opam/$switch/bin} *) val bin: t -> switch -> dirname (** Installed system binaries: {i $opam/$switch/sbin} *) val sbin: t -> switch -> dirname (** List of installed packages with their version: {i $opam/$switch/installed} *) val installed: t -> switch -> filename (** List of packages explicitly installed by the user: {i $opam/$switch/installed.roots} *) val installed_roots: t -> switch -> filename (** Temporary folders used to decompress and compile the corresponding archives: {i $opam/$switch/build/$packages} *) val build: t -> switch -> package -> dirname (** Temporary folders used to decompress and compile the OCaml compiler: {i $opam/$switch/build/ocaml} *) val build_ocaml: t -> switch -> dirname (** Temporary folder: {i $opam/$switch/build} *) val build_dir: t -> switch -> dirname (** Temporary location of install files: {i $opam/$switch/build/$package/$name.install} *) val build_install: t -> switch -> package -> filename (** Temporary location of config files: {i $opam/$switch/build/$packages/$name.config} *) val build_config: t -> switch -> package -> filename (** Installed files for a given package: {i $opam/$switch/install/$name.install} *) val install: t -> switch -> name -> filename (** Installed files: {i $opam/$switch/install/} *) val install_dir: t -> switch -> dirname (** Packages to reinstall on next upgrade: {i $opam/$switch/reinstall} *) val reinstall: t -> switch -> filename (** Compile and link flags for a given package: {i $opam/$switch/lib/$name/opam.config} *) val config: t -> switch -> name -> filename (** Configuration folder: {i $opam/$switch/config} *) val config_dir: t -> switch -> dirname (** Global config for the switch: {i $opam/$switch/config/global-config.config} *) val global_config: t -> switch -> filename (** Pinned package file: {i $opam/$switch/pinned} *) val pinned: t -> switch -> filename (** Build dir for all pinned packages: {i $opam/$switch/packages.dev/} *) val dev_packages_dir: t -> switch -> dirname (** Build dir for a given pinned package: {i $opam/$switch/packages.dev/$name.$version/} *) val dev_package: t -> switch -> name -> dirname module Overlay: sig (** Switch metadata overlay (over the global metadata): {i $opam/$switch/overlay/} *) val dir: t -> switch -> dirname (** Switch metadata overlay (over the global metadata): {i $opam/$switch/overlay/$name.$version} *) val package: t -> switch -> name -> dirname (** OPAM overlay: {i $opam/$switch/cache/$name.$version/opam} *) val opam: t -> switch -> name -> filename (** OPAM temp overlay (for user editing): {i $opam/$switch/cache/$name.$version/opam_} *) val tmp_opam: t -> switch -> name -> filename (** URL overlay: {i $opam/$switch/overlay/$name.$version/url} *) val url: t -> switch -> name -> filename (** Descr orverlay *) val descr: t -> switch -> name -> filename (** Files overlay *) val files: t -> switch -> name -> dirname end end (** Repository paths *) module Repository: sig (** Repository local path: {i $opam/repo/} *) val create: t -> repository_name -> dirname (** Update cache *) val update_cache: repository -> filename (** Return the repo file *) val repo: repository -> filename (** Remote repo file *) val remote_repo: repository -> filename (** Return the repository config: {i $opam/repo/$repo/config} *) val raw_config: dirname -> repository_name -> filename (** Return the repository config: {i $opam/repo/$repo/config} *) val config: repository -> filename (** Packages folder: {i $opam/repo/$repo/packages} *) val packages_dir: repository -> dirname (** Remote package files: {i $remote/packages} *) val remote_packages_dir: repository -> dirname (** Package folder: {i $opam/repo/$repo/packages/XXX/$NAME.$VERSION} *) val packages: repository -> string option -> package -> dirname (** Return the OPAM file for a given package: {i $opam/repo/$repo/packages/XXX/$NAME.$VERSION/opam} *) val opam: repository -> string option -> package -> filename (** Return the description file for a given package: {i $opam/repo/$repo/packages/XXX/$NAME.VERSION/descr} *) val descr: repository -> string option -> package -> filename (** urls {i $opma/repo/$repo/package/XXX/$NAME.$VERSION/url} *) val url: repository -> string option -> package -> filename (** files {i $opam/repo/$repo/packages/XXX/$NAME.$VERSION/files} *) val files: repository -> string option -> package -> dirname (** Return the archive for a given package: {i $opam/repo/$repo/archives/$NAME.$VERSION.tar.gz} *) val archive: repository -> package -> filename (** Remote archive {i $remote/archives/$NAME.$VERSION.tar.gz} *) val remote_archive: repository -> package -> filename (** Return the archive folder: {i $opam/repo/$repo/archives/} *) val archives_dir: repository -> dirname (** Return the upload folder for a given version: {i $opam/repo/$repo/upload/} *) val upload_dir: repository -> dirname (** Compiler files: {i $opam/repo/$repo/compilers/} *) val compilers_dir: repository -> dirname (** Compiler files: {i $opam/repo/$repo/compilers/XXX/$OVERSION.comp} *) val compiler_comp: repository -> string option -> compiler -> filename (** Compiler description files: {i $opam/repo/$repo/compilers/XXX/$OVERSION.descr} *) val compiler_descr: repository -> string option -> compiler -> filename (** Remote compiler files: {i $remote/compilers} *) val remote_compilers_dir: repository -> dirname end opam-full-1.2.2/src/core/opamCompat.mli.4.020000644000175000017500000000217612517374212017044 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) module Bytes = Bytes module Buffer = Buffer module Filename = Filename opam-full-1.2.2/src/core/opamJson.ml0000644000175000017500000001201612517374212015771 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) include Jsonm (* String conversion *) exception Escape of ((int * int) * (int * int)) * error type t = [ `Null | `Bool of bool | `Float of float| `String of string | `A of t list | `O of (string * t) list ] let json_of_src ?encoding src = let dec d = match decode d with | `Lexeme l -> l | `Error e -> raise (Escape (decoded_range d, e)) | `End | `Await -> assert false in let rec value v k d = match v with | `Os -> obj [] k d | `As -> arr [] k d | `Null | `Bool _ | `String _ | `Float _ as v -> k v d | _ -> assert false and arr vs k d = match dec d with | `Ae -> k (`A (List.rev vs)) d | v -> value v (fun v -> arr (v :: vs) k) d and obj ms k d = match dec d with | `Oe -> k (`O (List.rev ms)) d | `Name n -> value (dec d) (fun v -> obj ((n, v) :: ms) k) d | _ -> assert false in let d = decoder ?encoding src in try `JSON (value (dec d) (fun v _ -> v) d) with | Escape (r, e) -> `Error (r, e) let of_string str: t = match json_of_src (`String str) with | `JSON j -> j | `Error _ -> failwith "json_of_string" let json_to_dst ~minify dst (json:t) = let enc e l = ignore (encode e (`Lexeme l)) in let rec value v k e = match v with | `A vs -> arr vs k e | `O ms -> obj ms k e | `Null | `Bool _ | `Float _ | `String _ as v -> enc e v; k e and arr vs k e = enc e `As; arr_vs vs k e and arr_vs vs k e = match vs with | v :: vs' -> value v (arr_vs vs' k) e | [] -> enc e `Ae; k e and obj ms k e = enc e `Os; obj_ms ms k e and obj_ms ms k e = match ms with | (n, v) :: ms -> enc e (`Name n); value v (obj_ms ms k) e | [] -> enc e `Oe; k e in let e = encoder ~minify dst in let finish e = ignore (encode e `End) in match json with | `A _ | `O _ as json -> value json finish e | _ -> invalid_arg "invalid json text" let to_string (json:t) = let buf = Buffer.create 1024 in json_to_dst ~minify:false (`Buffer buf) json; Buffer.contents buf let json_output = ref None let json_buffer = ref [] let add json = json_buffer := json :: !json_buffer let set_output write = json_output := Some write let verbose () = !json_output <> None let output () = match !json_output with | None -> () | Some write -> let json = `A (List.rev !json_buffer) in write (to_string json) (*--------------------------------------------------------------------------- Copyright (c) 2012 Daniel C. Bünzli All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of Daniel C. Bünzli nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------*) opam-full-1.2.2/src/core/opamLexer.mli0000644000175000017500000000226112517374212016311 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) val token: Lexing.lexbuf -> OpamParser.token opam-full-1.2.2/src/core/opamCompat.ml.4.020000644000175000017500000000217612517374212016673 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) module Bytes = Bytes module Buffer = Buffer module Filename = Filename opam-full-1.2.2/src/core/opamPackage.mli0000644000175000017500000001023312517374212016563 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** {2 Package name and versions} *) (** Versions *) module Version: sig include OpamMisc.ABSTRACT (** Compare two versions using the Debian version scheme *) val compare: t -> t -> int end (** Names *) module Name: sig include OpamMisc.ABSTRACT (** Compare two package names *) val compare: t -> t -> int (** global configuration package *) val global_config: t end (** Package (name x version) pairs *) include OpamMisc.ABSTRACT (** Return the package name *) val name: t -> Name.t (** Return None if [nv] is not a valid package name *) val of_string_opt: string -> t option (** Return the version name *) val version: t -> Version.t (** Create a new pair (name x version) *) val create: Name.t -> Version.t -> t (** To fit in the GenericPackage type, for generic display functions *) val name_to_string: t -> string val version_to_string: t -> string (** Guess the package name from a filename. This function extracts [name] and [version] from {i /path/to/$name.$version/opam} *) val of_filename: OpamFilename.t -> t option (** Guess the package name from a directory name. This function extracts {i $name} and {i $version} from {i /path/to/$name.$version/} *) val of_dirname: OpamFilename.Dir.t -> t option (** Guess the package name from an archive file. This function extract {i $name} and {i $version} from {i /path/to/$name.$version+opam.tar.gz} *) val of_archive: OpamFilename.t -> t option (** Convert a set of pairs to a map [name -> versions] *) val to_map: Set.t -> Version.Set.t Name.Map.t (** Returns the keys in a package map as a package set *) val keys: 'a Map.t -> Set.t (** Extract the versions from a collection of packages *) val versions_of_packages: Set.t -> Version.Set.t (** Return the list of versions for a given package *) val versions_of_name: Set.t -> Name.t -> Version.Set.t (** Extract the naes from a collection of packages *) val names_of_packages: Set.t -> Name.Set.t (** Returns true if the set contains a package with the given name *) val has_name: Set.t -> Name.t -> bool (** Return all the packages with the given name *) val packages_of_name: Set.t -> Name.t -> Set.t (** Return all the packages with one of the given names *) val packages_of_names: Set.t -> Name.Set.t -> Set.t (** Return the maximal available version of a package name from a set. Raises [Not_found] if no such package available. *) val max_version: Set.t -> Name.t -> t (** Compare two packages *) val compare: t -> t -> int (** Are two packages equal ? *) val equal: t -> t -> bool (** Hash a package *) val hash: t -> int (** Return all the package descriptions in a given directory *) val list: OpamFilename.Dir.t -> Set.t (** Return all the package descriptions in the current directory (and their eventual prefixes). *) val prefixes: OpamFilename.Dir.t -> string option Map.t (** {2 Errors} *) (** Unknown package: either the name is unknown, or the version does not exist. *) val unknown: Name.t -> Version.t option -> 'a (** Parallel executions. *) module Graph: OpamParallel.GRAPH with type V.t = t opam-full-1.2.2/src/core/opamLineLexer.mli0000644000175000017500000000226012517374212017120 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) val main: Lexing.lexbuf -> string list list opam-full-1.2.2/src/core/opamProcess.mli0000644000175000017500000001637712517374212016665 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Process handling *) (** The type of shell commands *) type command val command: ?env:string array -> (** env for the comman d*) ?verbose:bool -> (** force verbosity *) ?name:string -> (** title, used to name log files, etc. *) ?metadata:(string*string) list -> (** additional info to log *) ?dir:string -> (** CWD for the command *) ?allow_stdin:bool -> (** whether to forward stdin *) ?text:string -> (** Short text that may be displayed in status *) string -> (** The command itself *) string list -> (** Command-line arguments *) command val string_of_command: command -> string val text_of_command: command -> string option val is_verbose_command: command -> bool (** Returns a label suitable for printing the summary of running commands. First string is the topic (e.g. package), second the action (e.g. command name). Optional command arguments may be used for details (e.g. make action). *) val make_command_text: ?color:OpamGlobals.text_style -> string -> ?args:string list -> string -> string (** The type for processes *) type t = { p_name : string; (** Command name *) p_args : string list; (** Command args *) p_pid : int; (** Process PID *) p_cwd : string; (** Process initial working directory *) p_time : float; (** Process start time *) p_stdout : string option; (** stdout dump file *) p_stderr : string option; (** stderr dump file *) p_env : string option; (** dump environment variables *) p_info : string option; (** dump process info *) p_metadata: (string * string) list; (** Metadata associated to the process *) p_verbose: bool; (** whether output of the process should be displayed *) } (** Process results *) type result = { r_code : int; (** Process exit code, or 256 on error *) r_signal : int option; (** Signal received if the processed was killed *) r_duration : float; (** Process duration *) r_info : (string * string) list; (** Process info *) r_stdout : string list; (** Content of stdout dump file *) r_stderr : string list; (** Content of stderr dump file *) r_cleanup : string list; (** List of files to clean-up *) } (** [run command] synchronously call the command [command.cmd] with arguments [command.args]. It waits until the process is finished. The files [name.info], [name.env], [name.out] and [name.err], with [name = command.cmd_name] are created, and contain the process main description, the environment variables, the standard output and the standard error. Don't forget to call [cleanup result] afterwards *) val run : command -> result (** Same as [run], but doesn't wait. Use wait_one to wait and collect results; Don't forget to call [cleanup result] afterwards *) val run_background: command -> t (** Similar to [run_background], except that no process is created, and a dummy process (suitable for dry_wait_one) is returned. *) val dry_run_background: command -> t (** [wait p] waits for the processus [p] to end and returns its results. Be careful to handle Sys.Break *) val wait: t -> result (** Like [wait], but returns None immediately if the process hasn't ended *) val dontwait: t -> result option (** Wait for the first of the listed processes to terminate, and return its termination status *) val wait_one: t list -> t * result (** Similar to [wait_one] for simulations, to be used with [dry_run_background] *) val dry_wait_one: t list -> t * result (** Send SIGINT to a process (or SIGKILL on Windows) *) val interrupt: t -> unit (** Is the process result a success ? *) val is_success : result -> bool (** Is the process result a failure ? *) val is_failure : result -> bool (** Should be called after process termination, to cleanup temporary files. Leaves artefacts in case OpamGlobals.debug is on and on failure, unless force has been set. *) val cleanup : ?force:bool -> result -> unit (** {2 Misc} *) val read_lines: string -> string list (** Pretty printing of process. *) val string_of_result: ?color:OpamGlobals.text_style -> result -> string (** Higher-level interface to allow parallelism *) module Job: sig (** Open type and add combinators. Meant to be opened *) module Op: sig type 'a job = | Done of 'a | Run of command * (result -> 'a job) (** Stage a shell command with its continuation, eg: {[ command "ls" ["-a"] @@> fun result -> if OpamProcess.is_success result then Done result.r_stdout else failwith "ls" ]} *) val (@@>): command -> (result -> 'a job) -> 'a job (** [job1 @@+ fun r -> job2] appends the computation of tasks in [job2] after [job1] *) val (@@+): 'a job -> ('a -> 'b job) -> 'b job (** [job @@| f] maps [f] on the results of [job]. Equivalent to [job @@+ fun r -> Done (f r)] *) val (@@|): 'a job -> ('a -> 'b) -> 'b job end (** Sequential run of a job *) val run: 'a Op.job -> 'a (** Same as [run] but doesn't actually run any shell command, and feed a dummy result to the cont. *) val dry_run: 'a Op.job -> 'a (** Catch exceptions raised within a job *) val catch: (exn -> 'a Op.job) -> 'a Op.job -> 'a Op.job (** Ignore all non-fatal exceptions raised by job and return default *) val ignore_errors: default:'a -> ?message:string -> 'a Op.job -> 'a Op.job (** Register an exception-safe finaliser in a job. [finally job fin] is equivalent to [catch job (fun e -> fin (); raise e) @@+ fun r -> fin (); Done r] *) val finally: (unit -> unit) -> 'a Op.job -> 'a Op.job (** Converts a list of commands into a job that returns None on success, or the first failed command and its result. Unless [keep_going] is true, stops on first error. *) val of_list: ?keep_going:bool -> command list -> (command * result) option Op.job (** Sets and overrides text of the underlying commands *) val with_text: string -> 'a Op.job -> 'a Op.job end type 'a job = 'a Job.Op.job opam-full-1.2.2/src/core/opamSystem.mli0000644000175000017500000002114712517374212016522 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Low-level untyped system operations *) (** Exception raised when subprocess fails *) exception Process_error of OpamProcess.result exception Command_not_found of string (** raise [Process_error] *) val process_error: OpamProcess.result -> 'a (** raise [Process_error] if the process didn't return 0 *) val raise_on_process_error: OpamProcess.result -> unit (** Exception raised when a computation in the current process fails. *) exception Internal_error of string (** Raise [Internal_error] *) val internal_error: ('a, unit, string, 'b) format4 -> 'a (** [with_tmp_dir fn] executes [fn] in a tempory directory *) val with_tmp_dir: (string -> 'a) -> 'a (** Runs a job with a temp dir that is cleaned up afterwards *) val with_tmp_dir_job: (string -> 'a OpamProcess.job) -> 'a OpamProcess.job (** Returns true if the default verbose level for base commands (cp, mv, etc.) is reached *) val verbose_for_base_commands: unit -> bool (** [copy src dst] copies [src] to [dst]. Remove [dst] before the copy if it is a link. *) val copy: string -> string -> unit (** [install ?exec src dst] copies file [src] as file [dst] using [install]. If [exec], make the resulting file executable (otherwise, look at the permissions of the original file to decide). *) val install: ?exec:bool -> string -> string -> unit (** Checks if a file is an executable (regular file with execution permission) *) val is_exec: string -> bool (** [link src dst] links [src] to [dst]. Remove [dst] if it is a file, not a directory. *) val link: string -> string -> unit (** [real_path p] returns the real path associated to [p]: [..] are expanded and relative paths become absolute. *) val real_path: string -> string (** Return the contents of a channel. *) val string_of_channel: in_channel -> string (** Raised when a file or directory can't be accessed (doesn't exist, bad permissions, etc.) *) exception File_not_found of string (** [read filename] returns the contents of [filename] *) val read: string -> string (** [write filename contents] write [contents] to [filename] *) val write: string -> string -> unit (** [remove filename] removes [filename]. Works whether [filename] is a file or a directory *) val remove: string -> unit (** [remove_file filename] removes [filename]. Works only for normal files (or also at least for symlinks) *) val remove_file: string -> unit (** [remove_dir filename] removes [filename]. Works only for directory (not for symlinks or other files). *) val remove_dir: string -> unit (** Change the current working directory *) val chdir: string -> unit (** [in_dir dir fn] evaluates [fn] in the directory [dir] *) val in_dir: string -> (unit -> 'a) -> 'a (** [files_with_links dir] returns the files in the directory [dir]. Links simulating directory are ignored, others links are returned. *) val files_with_links: string -> string list (** [rec_files dir] returns the list of all files in [dir], recursively. Links behaving like directory are crossed. *) val rec_files: string -> string list (** Return the list of files in the current directory. *) val files: string -> string list (** [rec_dirs dir] return the list list of all directories recursively (going through symbolink links). *) val rec_dirs: string -> string list (** Return the list of directories in the current directory. *) val dirs: string -> string list val dir_is_empty: string -> bool (** Return the version of the current OCaml compiler. If no OCaml compiler is present in the path, then it returns [None]. *) val ocaml_version: string option Lazy.t (** Returns true if the "ocamlopt" is available in the current switch *) val ocaml_native_available: bool Lazy.t (** Returns true if the ".opt" version of the current OCaml compiler is available*) val ocaml_opt_available: bool Lazy.t (** Checks if native dynlink is available with the current OCaml compiler *) val ocaml_natdynlink_available: bool Lazy.t (** Return the path where the system ocamlc library is installed *) val system_ocamlc_where: string option Lazy.t (** Return the version of the system compiler *) val system_ocamlc_version: string option Lazy.t (** [directories_with_links dir] returns the directories in the directory [dir]. Links pointing to directory are also returned. *) val directories_with_links: string -> string list (** Make a comman suitable for OpamProcess.Job. if [verbose], is set, command and output will be displayed (at command end for the latter, if concurrent commands are running). [name] is used for naming log files. [text] is what is displayed in the status line for this command. May raise Command_not_found, unless [check_existence] is set to false (in which case you can end up with a process error instead) *) val make_command: ?verbose:bool -> ?env:string array -> ?name:string -> ?text:string -> ?metadata:(string * string) list -> ?allow_stdin:bool -> ?dir:string -> ?check_existence:bool -> string -> string list -> OpamProcess.command (** OLD COMMAND API, DEPRECATED *) (** a command is a list of words *) type command = string list (** Test whether a command exists in the environment. *) val command_exists: ?env:string array -> ?dir:string -> string -> bool (** [command cmd] executes the command [cmd] in the correct OPAM environment. *) val command: ?verbose:bool -> ?env:string array -> ?name:string -> ?metadata:(string * string) list -> ?allow_stdin:bool -> command -> unit (** [commands cmds] executes the commands [cmds] in the correct OPAM environment. It stops whenever one command fails unless [keep_going] is set to [true]. In this case, the first error is re-raised at the end. *) val commands: ?verbose:bool -> ?env:string array -> ?name:string -> ?metadata:(string * string) list -> ?keep_going:bool -> command list -> unit (** [read_command_output cmd] executes the command [cmd] in the correct OPAM environment and return the lines from stdout if the command exists normally. If the command does not exist or if the command exited with a non-empty exit-code, throw an error. *) val read_command_output: ?verbose:bool -> ?env:string array -> ?metadata:(string * string) list -> ?allow_stdin:bool -> command -> string list (** END *) (** Test whether the file is an archive, by looking as its extension *) val is_tar_archive: string -> bool (** [extract filename dirname] extracts the archive [filename] into [dirname]. [dirname] should not exists and [filename] should contain only one top-level directory.*) val extract: string -> string -> unit (** [extract_in filename dirname] extracts the archive [filename] into [dirname]. [dirname] should already exists. *) val extract_in: string -> string -> unit (** Create a directory. Do not fail if the directory already exist. *) val mkdir: string -> unit (** {2 File locking function} *) type lock (** Acquires a lock on the given file. Retries 5 times max. By default, this is a write lock. *) val flock: ?read:bool -> string -> lock (** Releases an acquired locl *) val funlock: lock -> unit (** {2 Misc} *) (** download compiler sources *) val download: overwrite:bool -> ?compress:bool -> ?checksum:string -> filename:string -> dst:string -> string OpamProcess.job (** Apply a patch file in the current directory. *) val patch: string -> unit (** Create a tempory file in {i ~/.opam/logs/XXX} *) val temp_file: ?dir:string -> string -> string (** Print stats *) val print_stats: unit -> unit (** The separator character for the PATH variable *) val path_sep: char opam-full-1.2.2/src/core/opamCompat.mli.4.010000644000175000017500000000320212517374212017032 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) module Bytes : sig include module type of String val empty : t val of_string : string -> t val to_string : t -> string val sub_string : t -> int -> int -> string val blit_string : string -> int -> t -> int -> int -> unit external unsafe_to_string : t -> string = "%identity" external unsafe_of_string : string -> t = "%identity" end module Buffer : sig include module type of Buffer with type t = Buffer.t val add_subbytes : t -> Bytes.t -> int -> int -> unit end module Filename : sig include module type of Filename val get_temp_dir_name : unit -> string end opam-full-1.2.2/src/core/opamLineLexer.mll0000644000175000017500000000414412517374212017126 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) { type token = | WORD of string | NEWLINE | EOF let word = Buffer.create 57 } let normalchar = [^' ' '\t' '\n' '\\'] rule main = parse | '\n' { Lexing.new_line lexbuf; NEWLINE } | [' ' '\t']+ { main lexbuf } | (normalchar* as w) '\\' { Buffer.reset word ; Buffer.add_string word w; escaped lexbuf } | (normalchar* as w) { WORD w } | eof { EOF } and escaped = parse | (_ normalchar*) as w '\\' { Buffer.add_string word w; escaped lexbuf } | (_ normalchar*) as w { Buffer.add_string word w; WORD (Buffer.contents word) } { let main lexbuf = let rec aux lines words = match main lexbuf with | WORD "" -> aux lines words | WORD s -> aux lines (s::words) | NEWLINE -> let lines = if words = [] then lines else List.rev words::lines in aux lines [] | EOF -> let lines = if words = [] then lines else List.rev words::lines in List.rev lines in aux [] [] } opam-full-1.2.2/src/debug.ocp0000644000175000017500000000004012517374212014504 0ustar userusercomp += [ "-g"] link += [ "-g"] opam-full-1.2.2/src/solver/0000755000175000017500000000000012532744757014247 5ustar useruseropam-full-1.2.2/src/solver/solver.ocp0000644000175000017500000000022512517374212016247 0ustar useruserbegin library "opam-solver" files = [ "opamCudf.ml" "opamHeuristic.ml" "opamSolver.ml" ] requires = [ "opam-core" ] end opam-full-1.2.2/src/solver/opamSolver.mli0000644000175000017500000000743612517374212017077 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** SAT-solver for package dependencies and conflicts *) open OpamTypes module Action : OpamActionGraph.ACTION with type package = package module ActionGraph : OpamActionGraph.SIG with type package = package type solution val empty_universe: universe (** {2 Solver} *) (** Convert a request to a string *) val string_of_request: atom request -> string (** Compute statistics about a solution *) val stats: solution -> stats (** Return the new packages in the solution *) val new_packages: solution -> package_set (** Pretty-printing of statistics *) val string_of_stats: stats -> string (** Is the solution empty ? *) val solution_is_empty: solution -> bool (** Display a solution *) val print_solution: messages:(package -> string list) -> rewrite:(package -> package) -> requested:name_set -> solution -> unit (** Computes an opam->cudf version map from a set of package *) val cudf_versions_map: universe -> package_set -> int OpamPackage.Map.t (** Creates a CUDF universe from an OPAM universe, including the given packages *) val load_cudf_universe: ?depopts:bool -> ?build:bool -> ?test:bool -> ?doc:bool -> universe -> ?version_map:int package_map -> package_set -> Cudf.universe (** Given a description of packages, return a solution preserving the consistency of the initial description. *) val resolve : ?verbose:bool -> universe -> orphans:package_set -> atom request -> (solution, OpamCudf.conflict) result (** Returns the graph of atomic actions (rm, inst) from a solution *) val get_atomic_action_graph : solution -> ActionGraph.t (** Keep only the packages that are installable. *) val installable: universe -> package_set (** Return the topological sort of the transitive dependency closures of a collection of packages.*) val dependencies : depopts:bool -> ?build:bool -> ?test:bool -> ?doc:bool -> installed:bool -> ?unavailable:bool -> universe -> package_set -> package list (** Same as [dependencies] but for reverse dependencies *) val reverse_dependencies : depopts:bool -> ?build:bool -> ?test:bool -> ?doc:bool -> installed:bool -> ?unavailable:bool -> universe -> package_set -> package list (** Check the current set of installed packages in a universe for inconsistencies *) val check_for_conflicts : universe -> OpamCudf.conflict option (** Dumps a cudf file containing all available packages in the given universe, plus version bindings (as '#v2v' comments) for the other ones. *) val dump_universe: universe -> out_channel -> unit (** Filters actions in a solution. Dependents of a removed actions are removed to keep consistency *) val filter_solution: (package -> bool) -> solution -> solution opam-full-1.2.2/src/solver/opamCudf.mli0000644000175000017500000002137712517374212016506 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Cudf interface *) open OpamTypes (** Cudf sets *) module Set: OpamMisc.SET with type elt = Cudf.package (** Cudf maps *) module Map: OpamMisc.MAP with type key = Cudf.package (** Cudf graph *) module Graph: sig (** Graph of cudf packages *) type t (** Build a graph from a CUDF universe *) val of_universe: Cudf.universe -> t (** Return the transitive closure of [g] *) val transitive_closure: t -> t (** Return the transitive closure of dependencies of [set], sorted in topological order. *) val close_and_linearize: t -> Set.t -> Cudf.package list end (** Difference between universes *) module Diff: sig (** Differences between the versions of a given package *) type package = { installed : Set.t; removed : Set.t; reinstalled: Set.t; } (** Difference between universe *) type universe = (Cudf_types.pkgname, package) Hashtbl.t (** Computation of differences between universe *) val diff: Cudf.universe -> Cudf.universe -> universe end (** Cudf action graph *) module ActionGraph: OpamActionGraph.SIG with type package = Cudf.package (** Abstract type that may be returned in case of conflicts *) type conflict (** Return the transitive closure of dependencies of [set], sorted in topological order *) val dependencies: Cudf.universe -> Cudf.package list -> Cudf.package list (** Return the transitive closure of dependencies of [set], sorted in topological order *) val reverse_dependencies: Cudf.universe -> Cudf.package list -> Cudf.package list (** Check if a request is satisfiable and return the reasons why not unless [explain] is set to [false] *) val check_request: ?explain:bool -> version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.universe, conflict) result (** Compute the final universe state using the external solver. *) val get_final_universe: version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.universe, conflict) result (** Compute the list of actions to match the difference between two universe. Remark: the result order is unspecified, ie. need to use [atomic_actions] to get a solution which respects the topological order induced by dependencies. *) val actions_of_diff: Diff.universe -> Cudf.package action list exception Cyclic_actions of Cudf.package action list list (** Computes the actions to process from a solution, from the actions obtained by a simple universe diff. The 'simple' universe should not contain build dependencies and will be used for resolution ; [complete_universe] should include build-deps, it's used to get the dependency ordering of actions. Returns a graph of atomic actions, i.e. only removals and installs. Use [reduce_actions] to reduce it to a graph including reinstall and up/down-grade actions. May raise [Cyclic_actions]. *) val atomic_actions: simple_universe:Cudf.universe -> complete_universe:Cudf.universe -> Cudf.package action list -> ActionGraph.t (** Heuristic to compute the likely cause of all actions in a graph from the set of packages passed in the original request. Assumes a reduced graph. *) val compute_root_causes: ActionGraph.t -> OpamPackage.Name.Set.t -> Cudf.package cause Map.t (** Resolve a CUDF request. The result is either a conflict holding an explanation of the error, or a resulting universe. [~extern] specifies whether the external solver should be used *) val resolve: extern:bool -> version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.universe, conflict) result (** Computes a list of actions to proceed from the result of [resolve]. Note however than the action list is not yet complete: the transitive closure of reinstallations is not yet completed, as it requires to fold over the dependency graph in considering the optional dependencies. The first argument specifies a function that will be applied to the starting universe before computation: useful to re-add orphan packages. *) val to_actions: (Cudf.universe -> Cudf.universe) -> Cudf.universe -> (Cudf.universe, conflict) result -> (Cudf.package action list, conflict) result (** [remove universe name constr] Remove all the packages called [name] satisfying the constraints [constr] in the universe [universe]. *) val remove: Cudf.universe -> Cudf_types.pkgname -> Cudf_types.constr -> Cudf.universe (** Uninstall all the package in the universe. *) val uninstall_all: Cudf.universe -> Cudf.universe (** Install a package in the universe. We don't care about any invariant here (eg. the resulting universe can have mutliple versions of the same package installed). *) val install: Cudf.universe -> Cudf.package -> Cudf.universe (** Remove all the versions of a given package, but the one given as argument. *) val remove_all_uninstalled_versions_but: Cudf.universe -> string -> Cudf_types.constr -> Cudf.universe (** Cudf labels for package fields in the cudf format (use for the field Cudf.pkg_extra and with Cudf.lookup_package_property) *) val s_source: string (** the original OPAM package name (as string) *) val s_source_number: string (** the original OPAM package version (as string) *) val s_reinstall: string (** a package to be reinstalled (a bool) *) val s_installed_root: string (** true if this package belongs to the roots ("installed manually") packages *) val s_pinned: string (** true if the package is pinned to this version *) val s_version_lag: string (** the number of versions of the package since this one*) (** {2 Pretty-printing} *) (** Convert a package constraint to something readable. *) val string_of_vpkgs: Cudf_types.vpkg list -> string val make_conflicts: version_map:int package_map -> Cudf.universe -> Algo.Diagnostic.diagnosis -> ('a, conflict) result val cycle_conflict: version_map:int package_map -> Cudf.universe -> string list list -> ('a, conflict) result (** Convert a conflict to something readable by the user. The first argument should return a string like "lwt<3.2.1 is not available because..." when called on an unavailable package (the reason can't be known this deep in the solver) *) val string_of_conflict: (atom -> string) -> conflict -> string (** Returns three lists of strings: - the final reasons why the request can't be satisfied - the dependency chains explaining it - the cycles in the actions to process (exclusive with the other two) *) val strings_of_conflict: (atom -> string) -> conflict -> string list * string list * string list (** Dumps the given cudf universe to the given channel *) val dump_universe: out_channel -> Cudf.universe -> unit (** Pretty-print atoms *) val string_of_atom: Cudf_types.vpkg -> string (** Pretty-print requests *) val string_of_request: Cudf_types.vpkg request -> string (** Pretty-print the universe *) val string_of_universe: Cudf.universe -> string (** Pretty-print of packages *) val string_of_packages: Cudf.package list -> string (** Convert a cudf package back to an OPAM package *) val cudf2opam: Cudf.package -> package (** Returns the list of packages in a Cudf universe *) val packages: Cudf.universe -> Cudf.package list (** {2 External solver} *) val external_solver_available: unit -> bool (** Runs a test to check the version of the optimisation criteria accepted by the external solver. Result is cached for subsequent queries. *) val check_cudf_version: unit -> [`Compat | `Latest] (** Converts an OPAM request to a Cudf request *) val to_cudf: Cudf.universe -> Cudf_types.vpkg request -> Cudf.preamble * Cudf.universe * Cudf.request opam-full-1.2.2/src/solver/opamHeuristic.ml0000644000175000017500000005427612517374212017417 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamMisc.OP let log fmt = OpamGlobals.log "HEURISTIC" fmt let slog = OpamGlobals.slog type 'a state = 'a list type 'a state_space = 'a array list (* Forget about the changes which are not related to the packages we are interested in. We don't have yet computed the transitive closure of dependencies: we are processing 'raw' actions which come directly from the solver. It shoud be safe to discard install/upgrade action outside of the interesting names; delete actions are using a different code-path, they should not appear here. *) let minimize_actions interesting_names actions = let interesting_names = OpamMisc.StringSet.of_list interesting_names in List.filter (function | To_change (_, p) | To_recompile p -> OpamMisc.StringSet.mem p.Cudf.package interesting_names | To_delete _ -> true ) actions (* A list of [n] zero. *) let zero n = let rec aux acc n = if n > 0 then aux (0 :: acc) (n-1) else acc in aux [] n (* Given a list of bounds, create the least tuple such that the sum of components is equal to n. For instance: init [1;2;1] 3 is [0;2;1] *) let init ~bounds n = let rec aux = function | 0, [] -> Some [] | 0, l -> Some (zero (List.length l)) | _, [] -> None | n, b::t -> if n <= b then Some (n :: zero (List.length t)) else match aux (n-b, t) with | None -> None | Some l -> Some (b::l) in match aux (n, List.rev bounds) with | None -> None | Some l -> Some (List.rev l) (* Given a list of bounds and a tuple, return the next tuple while keeping the sum of components of the tuple constant *) let rec cst_succ ~bounds k l = match l, bounds with | [] , [] -> None | [n], [b] -> if n+1 = k && n < b then Some [k] else None | n::nt, b::bt -> if n >= k then None else ( match cst_succ ~bounds:bt (k-n) nt with | Some s -> Some (n::s) | None -> if n < b then match init ~bounds:bt (k-n-1) with | None -> None | Some l -> Some (n+1 :: l) else None) | _ -> failwith "Bounds and tuple do not have the same size" (* Given a list of bounds and a tuple, return the next tuple *) let succ ~bounds l = let k = List.fold_left (+) 0 l in match cst_succ ~bounds k l with | Some t -> Some t | None -> let k = List.fold_left (+) 0 l in init ~bounds (k+1) let fallback_msg = "You might need to add explicit version constraints to your \ request to get a better answer.\n" (* Brute-force exploration of a given space-state: [is_consistent] is applied on each possible state of the system, where a state is where each pacakge has a fix version. We ensure that we apply [is_consistent] in increasing order regarding the difference between the maximum version and the current version for each package. That is, we apply [is_consistent] first on the state where all packages have the maximum version, then on all the states where all packages have their maximum version but one which has its second maximal version, etc... *) let brute_force ?(verbose=true) ~dump is_consistent state_space = log "brute-force"; let bounds = List.map (fun v -> Array.length v - 1) state_space in List.iter (fun v -> assert (v >= 0)) bounds; let mk_state t = List.map2 (fun vs i -> vs.(i)) state_space t in let t0 = Unix.time () in let count = ref 0 in let interval = 500 in let flush_output () = if verbose && !count >= interval then OpamGlobals.msg " an optimal solution has been found after exploring %d states.\n" !count in (* XXX: need to ensure this is properly transformed into a while-loop. *) let rec aux = function | None -> log "no better solution found"; flush_output (); None | Some t -> let state = mk_state t in dump state; incr count; let t1 = Unix.time () in if verbose && !count mod interval = interval - 1 then OpamGlobals.msg "."; if t1 -. t0 > OpamGlobals.solver_timeout then ( OpamGlobals.msg "The brute-force exploration algorithm timed-out [%d states, %.2gs].\n%s\n" !count OpamGlobals.solver_timeout fallback_msg; None ) else if is_consistent state then Some state else aux (succ ~bounds t) in aux (init ~bounds 0) (* Call the solver to check whether a set of packages is installable. *) let consistent_packages universe packages = let open Algo.Diagnostic in match Algo.Depsolver.edos_coinstall universe packages with | { result = Success _ } -> true | { result = Failure _ } -> false let dump_state = if !OpamGlobals.debug && !OpamGlobals.debug_level > 3 then log "dump-state: %a" (slog (OpamMisc.pretty_list @* (List.map (OpamPackage.to_string @* OpamCudf.cudf2opam)))) else (fun _ -> ()) (* Explore a given [state_space] to find the optimal solution. Ideally the state space should be as small as possible, eg. we rely on previous heuristics to reduce its size. *) let explore ?(verbose=true) universe state_space = log "explore"; let packages_of_state state = let filter p = List.exists (fun s -> s.Cudf.package = p.Cudf.package && s.Cudf.version = p.Cudf.version ) state in Cudf.get_packages ~filter universe in let is_consistent state = let packages = packages_of_state state in consistent_packages universe packages in brute_force ~verbose ~dump:dump_state is_consistent state_space (* Build a solution from a given space-state. If a package appears in the state, the solution has the package installed with the given version. If a package does not appear in the state, but is installed in the given universe, its version stays the same. Otherwise, if a package appears neither in the state nor is installed, it will not appear in the resulting solution. *) exception Not_reachable of OpamCudf.conflict let satisfy pkg constrs = List.exists (fun (n, v) -> n = pkg.Cudf.package && Cudf.version_matches pkg.Cudf.version v ) constrs let actions_of_state ~version_map universe request state = log "actions_of_state %a" (slog OpamCudf.string_of_packages) state; let installed = let filter p = p.Cudf.installed && List.for_all (fun s -> s.Cudf.package <> p.Cudf.package) state && not (satisfy p request.wish_remove) in let packages = Cudf.get_packages ~filter universe in List.rev_map (fun p -> p.Cudf.package, Some (`Eq, p.Cudf.version)) packages in let small_universe = let filter p = p.Cudf.installed || List.exists (fun s -> s.Cudf.package = p.Cudf.package) state in let packages = Cudf.get_packages ~filter universe in Cudf.load_universe packages in let state = List.map (fun p -> p.Cudf.package, Some (`Eq, p.Cudf.version)) state in let request = { request with wish_install = []; wish_upgrade = state @ installed } in match OpamCudf.check_request ~version_map small_universe request with | Conflicts c -> log "not reachable! universe=%a request=%a" (slog OpamCudf.string_of_universe) small_universe (slog OpamCudf.string_of_request) request; raise (Not_reachable c) | Success u -> try let diff = OpamCudf.Diff.diff universe u in let actions = OpamCudf.actions_of_diff diff in let actions = minimize_actions (List.map fst state) actions in actions with Cudf.Constraint_violation s -> OpamGlobals.error_and_exit "constraint violations: %s" s (* Find dependencies and installed & reverse dependencies. *) let find_interesting_names universe request = let filter pkg = satisfy pkg request.wish_upgrade && not (satisfy pkg request.wish_remove) in let packages = Cudf.get_packages ~filter universe in let depends = OpamCudf.dependencies universe packages in let revdepends = let revdepends = OpamCudf.reverse_dependencies universe packages in let filter pkg = pkg.Cudf.installed && filter pkg in List.filter filter revdepends in let set = ref OpamMisc.StringSet.empty in let add p = set := OpamMisc.StringSet.add p.Cudf.package !set in List.iter add depends; List.iter add revdepends; OpamMisc.StringSet.elements !set (* [state_space] returns the packages which will be tested by the brute-force state explorer. As we try to minimize the state to explore for each package, this means: - if the package has a version constraint in the request, that's the only we consider (eg. return only one element for this package name: the version in the constraint) - if the package has no version constraints in the request, or if the package does not appear in the initial request, then return only the versions greater or equals to the one appearing in the given universe. - if the package appears in the 'wish_remove' field we do not try to test it. *) let state_space ?(filters = fun _ -> None) universe wish_remove interesting_names = let universe_packages = Cudf.get_packages universe in (* Return the version associated to a given package in the universe. *) let installed_version_of_name = let tbl = Hashtbl.create 1024 in List.iter (fun p -> if p.Cudf.installed then Hashtbl.add tbl p.Cudf.package p.Cudf.version) universe_packages; function name -> try Some (Hashtbl.find tbl name) with Not_found -> None in let state_space = Hashtbl.create 1024 in let add_state name = if not (Hashtbl.mem state_space name) then let filter = filters name in let packages = Cudf.lookup_packages universe ~filter name in let packages = match installed_version_of_name name with | None -> packages | Some v -> List.filter (fun p -> p.Cudf.version >= v) packages in let packages = List.sort (fun p1 p2 -> compare p2.Cudf.version p1.Cudf.version) packages in let packages = List.filter (fun p -> not (satisfy p wish_remove)) packages in if List.length packages <> 0 then Hashtbl.add state_space name (Array.of_list packages) in List.iter add_state interesting_names; Hashtbl.fold (fun _ states acc -> states :: acc) state_space [] (* Find a possible good state which satisfies a request. The idea is call iteratively this function while refining the constraints of the request until reaching a fix-point. *) let state_of_request ?(verbose=true) ~version_map current_universe request = log "state_of_request"; match OpamCudf.check_request ~explain:false ~version_map current_universe request with | Conflicts _ -> log "state-of-request: %a CONFLICT!" (slog OpamCudf.string_of_request) request; None | Success result_universe -> (* This first [result_universe] is a consistent solution which contains only installed packages fulfilling the initial constraints. It is thus not a complete universe and it is not guaranteed to be optimal. So we extend the result with all the existing packages. *) let result_universe = let installed = Cudf.get_packages result_universe in let current_universe = OpamCudf.uninstall_all current_universe in List.fold_left OpamCudf.install current_universe installed in let all_wishes = request.wish_install @ request.wish_upgrade in let filters name = try List.assoc name all_wishes with Not_found -> log "state-of-request: %s NOT FOUND!" name; None in let state_space = let names = List.map (fun (n,_) -> n) request.wish_upgrade in state_space ~filters result_universe request.wish_remove names in explore ~verbose current_universe state_space let same_state s1 s2 = let sort l = let name p = p.Cudf.package, p.Cudf.version in let cmp p1 p2 = compare (name p1) (name p2) in List.sort cmp l in match s1 with | None -> false | Some s1 -> List.length s1 = List.length s2 && sort s1 = sort s2 (* Refine a request with state constraints. *) let refine state request = log "refine request:%a state:%a" (slog OpamCudf.string_of_request) request (slog OpamCudf.string_of_packages) state; let wish_upgrade = List.rev_map (fun p -> (p.Cudf.package, Some (`Eq, p.Cudf.version))) state in let wish_install = let names = OpamMisc.StringSet.( union (of_list (List.rev_map fst request.wish_install)) (of_list (List.rev_map fst request.wish_upgrade)) ) in let set = OpamMisc.StringSet.filter (fun n -> not (List.mem_assoc n wish_upgrade)) names in List.map (fun n -> (n, None)) (OpamMisc.StringSet.elements set) in { request with wish_install; wish_upgrade } (* Add a package name to the upgrade list. *) let add_to_upgrade request name = { request with wish_upgrade = (name, None) :: request.wish_upgrade } (* Compute the 'implicit' packages, ie. the ones which do not appear in the request but which are in the transitive closure of dependencies, and split them in two categories: already installed (which will be kept as much as possible with the same version) and not installed (which will be installed to the most recent valid version) if they are needed. *) let implicits universe request = let interesting_names = find_interesting_names universe request in let implicit_installed, implicit_not_installed = let implicit = let request_names = OpamMisc.StringSet.of_list (List.map fst request.wish_upgrade) in let all_names = OpamMisc.StringSet.of_list interesting_names in OpamMisc.StringSet.diff all_names request_names in let installed = let filter p = p.Cudf.installed && OpamMisc.StringSet.mem p.Cudf.package implicit in Cudf.get_packages ~filter universe in let not_installed = let filter n = List.for_all (fun p -> p.Cudf.package <> n) installed in let set = OpamMisc.StringSet.filter filter implicit in let list = OpamMisc.StringSet.elements set in (* Favor packages with higher version number to discard deprecated packages. *) let max_version name = let filter p = p.Cudf.package = name in let packages = Cudf.get_packages ~filter universe in List.fold_left (fun v p -> max v p.Cudf.version) min_int packages in let cmp n1 n2 = compare (max_version n1) (max_version n2) in List.sort cmp list in installed, not_installed in log "implicit-installed: %a" (slog OpamCudf.string_of_packages) implicit_installed; log "implicit-not-installed: %a" (slog OpamMisc.pretty_list) implicit_not_installed; implicit_installed, implicit_not_installed (* Remove from the universe all the package versions which are not specified on the command-line. For instance: $ opam install core.109.13.00 will cause all versions of core != 109.13.00 to disapear from the universe. This is causing [Universe.trim] to remove *a lot* of uninstallable packages and will improve the brute-force state exploration results. We also remove all version stricly less than the one installed as we don't downgrade anyway. *) let trim_universe universe request = (* First trim: not very useful, but why not. *) let universe = Algo.Depsolver.trim universe in (* we compute the cone of interesting packages. *) let is_upgrade (n, _) = List.exists (fun (p, _) -> p = n) request.wish_upgrade in let wish_install = List.filter (fun p -> not (is_upgrade p)) request.wish_install in let all_wishes = wish_install @ request.wish_upgrade in let universe = List.fold_left (fun universe (name, constr) -> OpamCudf.remove_all_uninstalled_versions_but universe name constr ) universe all_wishes in let filter pkg = List.exists (fun (n,v) -> n = pkg.Cudf.package && Cudf.version_matches pkg.Cudf.version v ) all_wishes in let packages = Cudf.get_packages ~filter universe in let packages = OpamCudf.dependencies universe packages in (* We manually remove package with invalid constraints (seems that trim does not do it properly). *) let packages = List.filter (fun pkg -> List.for_all (List.exists (fun (name, constr) -> let filter p = p.Cudf.package = name && Cudf.version_matches p.Cudf.version constr in Cudf.get_packages ~filter universe <> [] )) pkg.Cudf.depends ) packages in let universe = Cudf.load_universe packages in (* and we trim again. *) Algo.Depsolver.trim universe (* Various heuristic to transform a solution checker into an optimized solver. *) let optimize ?(verbose=true) ~version_map map_init_u universe request = (* We start be specializing the request. *) let request = let wish_upgrade = List.map (fun (name, constr) -> name, match constr with | Some _ -> constr | None -> match Cudf.get_installed universe name with | [p] -> Some (`Geq, p.Cudf.version) | _ -> None ) request.wish_upgrade in { request with wish_upgrade } in (* We use that request to trim the universe, and keep only the interesting packages. *) let full_universe = universe in let universe = trim_universe universe request in let untrim universe = let open OpamCudf.Set in let open Op in let pkgs = of_list (Cudf.get_packages universe) ++ of_list (Cudf.get_packages ~filter:(fun p -> p.Cudf.installed) full_universe) in Cudf.load_universe (elements pkgs) in log "universe: %a" (slog (OpamMisc.pretty_list @* List.map (OpamPackage.to_string @* OpamCudf.cudf2opam) @* OpamCudf.packages)) universe; (* Upgrade the explicit packages first *) match state_of_request ~verbose ~version_map universe request with | None -> OpamCudf.to_actions map_init_u (untrim universe) (OpamCudf.resolve ~extern:false ~version_map universe request) | Some state -> log "STATE(0) %a" (slog OpamCudf.string_of_packages) state; let request = refine state request in (* strategy where we try keep the installed version before trying an other one. *) let installed_first state p = log "installed-first %s" p.Cudf.package; if consistent_packages universe (p :: state) then ( log "keep %s with the same version" p.Cudf.package; (p :: state) ) else ( let request = refine state request in let request = add_to_upgrade request p.Cudf.package in match state_of_request ~verbose ~version_map universe request with | None -> log "discard %s" p.Cudf.package; state | Some state -> let p = List.find (fun i -> i.Cudf.package = p.Cudf.package) state in log "pick an other version of %s (%d)" p.Cudf.package p.Cudf.version; log "request: %a" (slog OpamCudf.string_of_request) request; log "state: %a" (slog OpamCudf.string_of_packages) state; state ) in (* Try to keep the installed packages in the dependency cone *) let implicit_installed, implicit_not_installed = implicits universe request in let state = List.fold_left installed_first state implicit_installed in log "STATE(1) %a" (slog OpamCudf.string_of_packages) state; (* Minimize the number of new packages to install *) (* XXX: if we want to add an interactive mode, we need to do something here *) (* XXX: if needed we can sort the packages in a more clever order (for instance the size of the dependency cone of packages which are not yet installed). *) let universe, state = List.fold_left (fun (universe, state) name -> let remove_universe = OpamCudf.remove universe name None in if consistent_packages remove_universe state then ( log "%s is not necessary (%a)" name (slog OpamCudf.string_of_packages) state; (remove_universe, state) ) else ( log "adding %s to the request" name; let request = refine state request in let request = add_to_upgrade request name in match state_of_request ~verbose ~version_map universe request with | None -> (universe, state) | Some state -> (universe, state) ) ) (universe, state) implicit_not_installed in (* Finally we check that the already installed packages can still be installed in the new universe. *) let state = let filter p = p.Cudf.installed && List.for_all (fun s -> s.Cudf.package <> p.Cudf.package) state && not (satisfy p request.wish_remove) in let packages = Cudf.get_packages ~filter universe in List.fold_left installed_first state packages in log "STATE(2) %a" (slog OpamCudf.string_of_packages) state; let universe = map_init_u (untrim universe) in Success (actions_of_state ~version_map universe request state) let resolve ?(verbose=true) ~version_map map_init_u universe request = try if request.wish_upgrade <> [] then optimize ~verbose ~version_map map_init_u universe request else let res = OpamCudf.resolve ~extern:false ~version_map universe request in OpamCudf.to_actions map_init_u universe res with Not_reachable c -> Conflicts c opam-full-1.2.2/src/solver/opamSolver.ml0000644000175000017500000005021612517374212016720 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamPackage.Set.Op let log fmt = OpamGlobals.log "SOLVER" fmt let slog = OpamGlobals.slog module Action = OpamActionGraph.MakeAction(OpamPackage) module ActionGraph = OpamActionGraph.Make(Action) type solution = OpamCudf.ActionGraph.t let empty_universe = { u_packages = OpamPackage.Set.empty; u_installed = OpamPackage.Set.empty; u_available = OpamPackage.Set.empty; u_depends = OpamPackage.Map.empty; u_depopts = OpamPackage.Map.empty; u_conflicts = OpamPackage.Map.empty; u_action = Install OpamPackage.Name.Set.empty; u_installed_roots = OpamPackage.Set.empty; u_pinned = OpamPackage.Set.empty; u_base = OpamPackage.Set.empty; } (* Get the optional depencies of a package *) let depopts_of_package universe ?build ?test ?doc package = let opts = try filter_deps ?build ?test ?doc (OpamPackage.Map.find package universe.u_depopts) with Not_found -> Empty in OpamFormula.to_dnf opts let is_installed universe (name,_) = OpamPackage.Set.exists (fun pkg -> OpamPackage.name pkg = name ) universe.u_installed let find_installed universe (name, _) = let pkg = OpamPackage.Set.find (fun pkg -> OpamPackage.name pkg = name ) universe.u_installed in OpamPackage.version pkg let is_available universe wish_remove (name, _ as c) = let version = find_installed universe c in OpamPackage.Set.exists (fun pkg -> OpamPackage.name pkg = name && OpamPackage.version pkg = version ) universe.u_available && List.for_all (fun (n, _) -> n <> name) wish_remove let cudf_versions_map universe packages = log "cudf_versions_map"; let add_referred_to_packages filt acc refmap = OpamPackage.Map.fold (fun _ deps acc -> List.fold_left (fun acc -> function | n, Some (_, v) -> OpamPackage.Set.add (OpamPackage.create n v) acc | _, None -> acc) acc (OpamFormula.atoms (filt deps))) refmap acc in let filt = filter_deps ~build:true ~test:true ~doc:true in let id = fun x -> x in let packages = add_referred_to_packages filt packages universe.u_depends in let packages = add_referred_to_packages filt packages universe.u_depopts in let packages = add_referred_to_packages id packages universe.u_conflicts in let pmap = OpamPackage.to_map packages in OpamPackage.Name.Map.fold (fun name versions acc -> let _, map = OpamPackage.Version.Set.fold (fun version (i,acc) -> let nv = OpamPackage.create name version in i + 1, OpamPackage.Map.add nv i acc) versions (1,acc) in map) pmap OpamPackage.Map.empty let name_to_cudf name = Common.CudfAdd.encode (OpamPackage.Name.to_string name) let atom2cudf _universe (version_map : int OpamPackage.Map.t) (name,cstr) = name_to_cudf name, match cstr with | None -> None | Some (op,v) -> let nv = OpamPackage.create name v in try let cv = OpamPackage.Map.find nv version_map in Some (op, cv) with Not_found -> (* The version for comparison doesn't exist: match to the closest existing version according to the direction of the comparison (this shouldn't happen for any constraint in the universe, now that we compute a full version map, but may still happen for user-provided constraints) *) let all_versions = OpamPackage.Map.filter (fun nv _ -> OpamPackage.name nv = name) version_map in match op with | `Neq -> None (* Always true *) | `Eq -> (* Always false *) Some (`Eq, OpamPackage.Map.cardinal all_versions + 1) | (`Geq | `Gt | `Leq | `Lt) as op -> let sign, result_op = match op with | `Geq | `Gt -> (fun x -> x), `Geq | `Leq | `Lt -> (fun x -> -x), `Leq in let rev_version_map = OpamPackage.Map.fold (fun nv cv acc -> OpamMisc.IntMap.add (sign cv) (OpamPackage.version nv) acc) all_versions OpamMisc.IntMap.empty in let map = OpamMisc.IntMap.filter (fun _ v1 -> sign (OpamPackage.Version.compare v v1) < 0) rev_version_map in if OpamMisc.IntMap.is_empty map then match result_op with | `Geq -> Some (`Gt, max 1 (OpamPackage.Map.cardinal all_versions)) | `Leq -> Some (`Lt, 1) else Some (result_op, sign (fst (OpamMisc.IntMap.min_binding map))) let opam2cudf universe ?(depopts=false) ?build ?test ?doc version_map package = let name = OpamPackage.name package in let version = OpamPackage.version package in let depends = try filter_deps ?build ?test ?doc (OpamPackage.Map.find package universe.u_depends) with Not_found -> Empty in let depends = let opts = depopts_of_package universe package in if depopts then let opts = List.rev_map OpamFormula.of_conjunction opts in And (depends, Or(depends, OpamFormula.ors opts)) else if universe.u_action = Remove || universe.u_action = Depends then depends else (* depopts become hard deps when they are installed *) let mem_installed conj = List.exists (is_installed universe) conj in let opts = List.filter mem_installed opts in let opts = List.rev_map OpamFormula.of_conjunction opts in And (depends, OpamFormula.ands opts) in let conflicts = try OpamPackage.Map.find package universe.u_conflicts with Not_found -> Empty in let conflicts = (* prevents install of multiple versions of the same pkg *) (name, None)::OpamFormula.to_conjunction conflicts in let installed = OpamPackage.Set.mem package universe.u_installed in let base = OpamPackage.Set.mem package universe.u_base in let reinstall = match universe.u_action with | Upgrade reinstall | Reinstall reinstall -> OpamPackage.Set.mem package reinstall | _ -> false in let installed_root = OpamPackage.Set.mem package universe.u_installed_roots in let pinned_to_current_version = OpamPackage.Set.mem package universe.u_pinned in let version_lag = let all_versions = OpamPackage.versions_of_name universe.u_available name in let count,i = OpamPackage.Version.Set.fold (fun v (i,r) -> if v = version then i,i else i+1, r) all_versions (0,0) in count - i in let extras = let e = [ OpamCudf.s_source, `String (OpamPackage.Name.to_string name); OpamCudf.s_source_number, `String (OpamPackage.Version.to_string version); ] in let e = if installed && reinstall then (OpamCudf.s_reinstall, `Bool true)::e else e in let e = if installed_root then (OpamCudf.s_installed_root, `Bool true)::e else e in let e = if pinned_to_current_version then (OpamCudf.s_pinned, `Bool true)::e else if version_lag = 0 then e else (OpamCudf.s_version_lag, `Int version_lag)::e in e in { Cudf.default_package with Cudf. package = name_to_cudf (OpamPackage.name package); version = OpamPackage.Map.find package version_map; depends = List.rev_map (List.rev_map (atom2cudf universe version_map)) (OpamFormula.to_cnf depends); conflicts = List.rev_map (atom2cudf universe version_map) conflicts; installed; keep = if base then `Keep_version else `Keep_none; (* was_installed: reserved for the solver; *) (* provides: unused atm *) pkg_extra = extras; } (* load a cudf universe from an opam one *) let load_cudf_universe ?depopts ?build ?test ?doc opam_universe ?version_map opam_packages = log "Load cudf universe (depopts:%b, build:%b)" (OpamMisc.Option.default false depopts) (OpamMisc.Option.default true build); let version_map = match version_map with | Some vm -> vm | None -> cudf_versions_map opam_universe opam_packages in let cudf_universe = let cudf_packages = (* Doing opam2cudf for every package is inefficient (lots of Set.mem to check if it is installed, etc. Optimise by gathering all info first *) OpamPackage.Set.fold (fun nv list -> opam2cudf opam_universe ?depopts ?build ?test ?doc version_map nv :: list) opam_packages [] in try Cudf.load_universe cudf_packages with Cudf.Constraint_violation s -> OpamGlobals.error_and_exit "Malformed CUDF universe (%s)" s in (* We can trim the universe here to get faster results, but we choose to keep it bigger to get more precise conflict messages. *) (* let universe = Algo.Depsolver.trim universe in *) cudf_universe let string_of_request r = let to_string = OpamFormula.string_of_conjunction OpamFormula.string_of_atom in Printf.sprintf "install:%s remove:%s upgrade:%s" (to_string r.wish_install) (to_string r.wish_remove) (to_string r.wish_upgrade) let map_action f = function | To_change (Some x, y) -> To_change (Some (f x), f y) | To_change (None, y) -> To_change (None, f y) | To_delete y -> To_delete (f y) | To_recompile y -> To_recompile (f y) let map_cause f = function | Upstream_changes -> Upstream_changes | Use l -> Use (List.rev_map f l) | Required_by l -> Required_by (List.rev_map f l) | Conflicts_with l -> Conflicts_with (List.rev_map f l) | Requested -> Requested | Unknown -> Unknown let cudf_to_opam_graph cudf2opam cudf_graph = let size = OpamCudf.ActionGraph.nb_vertex cudf_graph in let opam_graph = ActionGraph.create ~size () in OpamCudf.ActionGraph.iter_vertex (fun package -> ActionGraph.add_vertex opam_graph (map_action cudf2opam package) ) cudf_graph; OpamCudf.ActionGraph.iter_edges (fun p1 p2 -> ActionGraph.add_edge opam_graph (map_action cudf2opam p1) (map_action cudf2opam p2) ) cudf_graph; opam_graph let map_request f r = let f = List.rev_map f in { wish_install = f r.wish_install; wish_remove = f r.wish_remove; wish_upgrade = f r.wish_upgrade; criteria = r.criteria } (* Remove duplicate packages *) (* Add upgrade constraints *) let cleanup_request universe (req:atom request) = let wish_install = List.filter (fun (n,_) -> not (List.mem_assoc n req.wish_upgrade)) req.wish_install in let wish_upgrade = List.rev_map (fun (n,c as pkg) -> if c = None && is_installed universe pkg && is_available universe req.wish_remove pkg then n, Some (`Geq, find_installed universe pkg) else pkg ) req.wish_upgrade in { req with wish_install; wish_upgrade } let cycle_conflict ~version_map univ cycles = OpamCudf.cycle_conflict ~version_map univ (List.map (List.map (fun a -> Action.to_string (map_action OpamCudf.cudf2opam a))) cycles) let resolve ?(verbose=true) universe ~orphans request = log "resolve request=%a" (slog string_of_request) request; let version_map = cudf_versions_map universe (universe.u_available ++ universe.u_installed ++ orphans) in let simple_universe = load_cudf_universe universe ~version_map (universe.u_available ++ universe.u_installed -- orphans) in let request = cleanup_request universe request in let cudf_request = map_request (atom2cudf universe version_map) request in let add_orphan_packages u = load_cudf_universe universe ~version_map (orphans ++ (OpamPackage.Set.of_list (List.map OpamCudf.cudf2opam (Cudf.get_packages u)))) in let resolve u req = if OpamCudf.external_solver_available () then try let resp = OpamCudf.resolve ~extern:true ~version_map u req in OpamCudf.to_actions add_orphan_packages u resp with Failure "opamSolver" -> OpamGlobals.error_and_exit "External solver failure, please fix your installation and check \ %s/config and variable $OPAMEXTERNALSOLVER.\n\ You may also retry with option --use-internal-solver" !OpamGlobals.root_dir else OpamHeuristic.resolve ~verbose ~version_map add_orphan_packages u req in match resolve simple_universe cudf_request with | Conflicts _ as c -> c | Success actions -> let all_packages = universe.u_available ++ orphans in let simple_universe = load_cudf_universe universe ~depopts:true ~build:false ~version_map all_packages in let complete_universe = load_cudf_universe universe ~depopts:true ~build:true ~version_map all_packages in try let atomic_actions = OpamCudf.atomic_actions ~simple_universe ~complete_universe actions in Success atomic_actions with OpamCudf.Cyclic_actions cycles -> cycle_conflict ~version_map complete_universe cycles let get_atomic_action_graph t = cudf_to_opam_graph OpamCudf.cudf2opam t let installable universe = log "trim"; let simple_universe = load_cudf_universe universe universe.u_available in let trimed_universe = (* Algo.Depsolver.trim *) simple_universe in Cudf.fold_packages (fun universe pkg -> OpamPackage.Set.add (OpamCudf.cudf2opam pkg) universe) OpamPackage.Set.empty trimed_universe let filter_dependencies f_direction ~depopts ?build ?test ?doc ~installed ?(unavailable=false) universe packages = if OpamPackage.Set.is_empty packages then [] else let u_packages = packages ++ if installed then universe.u_installed else if unavailable then universe.u_packages else universe.u_available in let version_map = cudf_versions_map universe u_packages in let cudf_universe = load_cudf_universe ~depopts ?build ?test ?doc universe ~version_map u_packages in let cudf_packages = List.rev_map (opam2cudf universe ~depopts ?build ?test ?doc version_map) (OpamPackage.Set.elements packages) in let topo_packages = f_direction cudf_universe cudf_packages in let result = List.rev_map OpamCudf.cudf2opam topo_packages in log "filter_dependencies packages=%a result=%a" (slog OpamPackage.Set.to_string) packages (slog (OpamMisc.string_of_list OpamPackage.to_string)) result; result let dependencies = filter_dependencies OpamCudf.dependencies let reverse_dependencies = filter_dependencies OpamCudf.reverse_dependencies let check_for_conflicts universe = let version_map = cudf_versions_map universe universe.u_packages in let cudf_universe = load_cudf_universe ~depopts:false ~build:true ~test:false ~doc:false ~version_map universe universe.u_packages in let installed = List.rev_map (opam2cudf universe ~depopts:false ~build:true ~test:false ~doc:false version_map) (OpamPackage.Set.elements universe.u_installed) in match Algo.Depsolver.edos_coinstall cudf_universe installed with | { Algo.Diagnostic.result = Algo.Diagnostic.Success _ } -> None | { Algo.Diagnostic.result = Algo.Diagnostic.Failure _ } as c -> match OpamCudf.make_conflicts ~version_map cudf_universe c with | Conflicts cs -> Some cs | _ -> None let new_packages sol = OpamCudf.ActionGraph.fold_vertex (fun action packages -> match action with | To_change (_,p) -> OpamPackage.Set.add (OpamCudf.cudf2opam p) packages | To_recompile _ | To_delete _ -> packages ) sol OpamPackage.Set.empty let stats sol = OpamCudf.ActionGraph.fold_vertex (fun action stats -> match action with | To_change (None, _) -> {stats with s_install = stats.s_install+1} | To_change (Some x, y) -> let c = Common.CudfAdd.compare x y in if c < 0 then {stats with s_upgrade = stats.s_upgrade+1} else if c > 0 then {stats with s_downgrade = stats.s_downgrade+1} else {stats with s_reinstall = stats.s_reinstall+1} | To_recompile _ -> {stats with s_reinstall = stats.s_reinstall+1} | To_delete _ -> {stats with s_remove = stats.s_remove+1}) (OpamCudf.ActionGraph.reduce sol) { s_install=0; s_reinstall=0; s_upgrade=0; s_downgrade=0; s_remove=0 } let string_of_stats stats = let utf = !OpamGlobals.utf8 in let stats = [ stats.s_install; stats.s_reinstall; stats.s_upgrade; stats.s_downgrade; stats.s_remove; ] in let titles = List.map (fun a -> let s = OpamActionGraph.action_strings a in if utf then OpamActionGraph.action_color a s else s) [`inst;`reinst;`up;`down;`rm] in let msgs = List.filter (fun (a,_) -> a <> 0) (List.combine stats titles) in if utf then OpamMisc.sconcat_map " " (fun (n,t) -> Printf.sprintf "%s %s" t (string_of_int n)) msgs else OpamMisc.sconcat_map " | " (fun (n,t) -> Printf.sprintf "%s to %s" (OpamGlobals.colorise `yellow (string_of_int n)) t) msgs let solution_is_empty t = OpamCudf.ActionGraph.is_empty t let print_solution ~messages ~rewrite ~requested t = let dump_cudf sfx t = match !OpamGlobals.cudf_file with | None -> () | Some f -> let filename = Printf.sprintf "%s-actions%s.dot" f sfx in let oc = open_out filename in ActionGraph.Dot.output_graph oc (cudf_to_opam_graph OpamCudf.cudf2opam t); close_out oc in dump_cudf "-full" t; let t = OpamCudf.ActionGraph.reduce t in dump_cudf "" t; let causes = OpamCudf.compute_root_causes t requested in let actions, details = OpamCudf.ActionGraph.Topological.fold (fun a (actions,details) -> let cause = try OpamCudf.Map.find (action_contents a) causes with Not_found -> Unknown in let action = map_action (fun p -> rewrite (OpamCudf.cudf2opam p)) a in let cudf_name p = OpamPackage.name_to_string (OpamCudf.cudf2opam p) in let cause = string_of_cause cudf_name cause in let messages = match a with | To_change(_,p) | To_recompile p -> messages (OpamCudf.cudf2opam p) | To_delete _ -> [] in action :: actions, (cause, messages) :: details ) t ([],[]) in let actions, details = List.rev actions, List.rev details in let actions_str = Action.to_aligned_strings actions in List.iter2 (fun act (cause,messages) -> if cause <> "" then OpamGlobals.msg " %-60s [%s]\n" act cause else OpamGlobals.msg " %s\n" act; List.iter (OpamGlobals.msg " %s\n") messages ) actions_str details let dump_universe universe oc = let version_map = cudf_versions_map universe universe.u_packages in let cudf_univ = load_cudf_universe ~depopts:false universe ~version_map universe.u_available in OpamCudf.dump_universe oc cudf_univ; (* Add explicit bindings to retrieve original versions of non-available packages *) OpamPackage.Map.iter (fun nv i -> if not (OpamPackage.Set.mem nv universe.u_available) then Printf.fprintf oc "#v2v:%s:%d=%s\n" (OpamPackage.name_to_string nv) i (OpamPackage.version_to_string nv) ) version_map let filter_solution filter t = let t = OpamCudf.ActionGraph.copy t in let rec rm iter_deps v = if OpamCudf.ActionGraph.mem_vertex t v then ( iter_deps (rm iter_deps) t v; OpamCudf.ActionGraph.remove_vertex t v ) in OpamCudf.ActionGraph.iter_vertex (function | To_delete nv as a when not (filter (OpamCudf.cudf2opam nv)) -> rm OpamCudf.ActionGraph.iter_pred a | To_change (_, nv) as a when not (filter (OpamCudf.cudf2opam nv)) -> rm OpamCudf.ActionGraph.iter_succ a | _ -> ()) t; t opam-full-1.2.2/src/solver/opamHeuristic.mli0000644000175000017500000001542212517374212017556 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Solver heuristics. *) (** This module tries to turn an efficient solution checker (such as the one provided by the dose3 library, writen by J. Vouillon) into a relatively good solution finder. The method we are using is the following: - We ultimately rely on a brute-force exploration loop, where we iterate over the state-space implicitely, using a monotonous successor function which encodes the optimization criteria we are interested in; - As brute-force exploration is costly, the goal is to provide the exploration function a state-space as small as possible. To do so, we use different kind of constraints that we deduce from the request; - We remove from the state-space every packages and versions that are not needed: we are only considering (i) the installed root packages (with no specific version constraint); (ii) the new packages that the user might have asking to install or upgrade (with some eventual version constraints); and (iii) the transitive closure of (i) and (ii) (with the corresponding version constraints); Finally, we run all this in a loop, until we reach a fix point. We use a timeout to interrupt too long explorations. *) open OpamTypes (** {2 High-level API} *) (** Optimized resolution *) val resolve: ?verbose:bool -> version_map:int OpamPackage.Map.t -> (Cudf.universe -> Cudf.universe) -> Cudf.universe -> Cudf_types.vpkg request -> (Cudf.package action list, OpamCudf.conflict) result (** {2 Internal API} *) (** These functions can be used independently of OPAM, so we document them here. It is not expected than any other file in OPAM use them, though. *) (** A state. In our case, it is a list package we would like to see installed. *) type 'a state = 'a list (** A state space. In our case, it is a collection of available packages: each cell contains all the versions available for one package, ordered by version. *) type 'a state_space = 'a array list (** {4 Integer space} *) (** The hearth of the brute-force algorithm lies here. Wwe want to iterate on the state-space (which can be hudge) and stop the first time we hit a consistant state. This means two things: (i) we don't want to build the full universe before iterating on it; (ii) we need to enumerate the states in a meaningful order, eg. an order which should reflect the optimization criteria we are intersted in. *) (** To overcome this difficulties, we use a monotonous successor function to compute the next state to test from a given valid non-consistent state, see [succ] for more details. *) (** [zero n] returns the tuple with [n] zeros, which is the first state to explore. *) val zero: int -> int state (** Given a list of bounds and a tuple, return the next tuple which satisfies the bounds (each component will be stricly lesser than the bounds). The enumeration respect the following invariant: - it is complete, eg. all the state are enumerated until [None] is returned. - it it monotonous: the sum of components always increase, eg. [|succ x| >= |x|], where [|None|] is [max_int], [|Some x| = |x|] and [|(x_1,...,x_n) = x_1 + ... + x_n|]. That enumeration encodes the heuristic we are trying to implement, which is: we first try to install the 'ideal' state, where all packages are installed with their most recent versions; if this does not work, we try to minimize the distance between the ideal state and the solution we are proposing. *) val succ: bounds:int list -> int state -> int state option (** {4 Polymorphic space} *) (** [explore is_constent state_space] explore a state space by implicitely enumerating all the state in a sensitive order. *) val brute_force: ?verbose:bool -> dump:('a state -> unit) -> ('a state -> bool) -> 'a state_space -> 'a state option (** {4 Package space} *) (** Build a state space from a list of package names. The [filter] option helps to reduce the size of the state-space, which is useful to deal with both user-defined constraints (added on the command line for instance) and refined requests (see below). *) val state_space: ?filters:(Cudf_types.pkgname -> Cudf_types.constr) -> Cudf.universe -> Cudf_types.vpkglist -> Cudf_types.pkgname list -> Cudf.package state_space (** Explore the given package state-space using the [brute_force] strategy. We assume that all the packages belong to the given universe. *) val explore: ?verbose:bool -> Cudf.universe -> Cudf.package state_space -> Cudf.package state option (** Find a possible good state which satisfies a request. The idea is call iteratively this function while refining the constraints in the request until reaching a fix-point. This function tries to minimize the state to explore, based on the request constraints: the more constrained request you have, the smaller the state-space to explore is. Once the state-space is computed using [state_space], it calls [explore] (which will use [brute_force]) to get an approximate solution to the request. *) val state_of_request: ?verbose:bool -> version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> Cudf.package state option (** Convert a state into a series of action (withour the full closure of reinstallations). Raise [Not_reachable] is the state is not reachable. This function is called once we get a consistent state to build a solution than we can propose to the user. *) val actions_of_state: version_map:int OpamPackage.Map.t -> Cudf.universe -> Cudf_types.vpkg request -> Cudf.package state -> Cudf.package action list opam-full-1.2.2/src/solver/opamCudf.ml0000644000175000017500000010560712517374212016334 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase let log fmt = OpamGlobals.log "CUDF" fmt let slog = OpamGlobals.slog (* custom cudf field labels *) let s_source = "opam-name" let s_source_number = "opam-version" let s_reinstall = "reinstall" let s_installed_root = "installed-root" let s_pinned = "pinned" let s_version_lag = "version-lag" let cudf2opam cpkg = let sname = Cudf.lookup_package_property cpkg s_source in let name = OpamPackage.Name.of_string sname in let sver = Cudf.lookup_package_property cpkg s_source_number in let version = OpamPackage.Version.of_string sver in OpamPackage.create name version let cudfnv2opam ?version_map ?cudf_universe (name,v) = let nv = match cudf_universe with | None -> None | Some u -> try Some (cudf2opam (Cudf.lookup_package u (name,v))) with Not_found -> None in match nv with | Some nv -> nv | None -> let name = OpamPackage.Name.of_string (Common.CudfAdd.decode name) in match version_map with | Some vmap -> let nvset = OpamPackage.Map.filter (fun nv cv -> OpamPackage.name nv = name && cv = v) vmap in fst (OpamPackage.Map.choose nvset) | None -> raise Not_found let string_of_action a = let aux pkg = Printf.sprintf "%s.%d" pkg.Cudf.package pkg.Cudf.version in match a with | To_change (None, p) -> Printf.sprintf "install %s" (aux p) | To_change (Some o, p) -> let f action = Printf.sprintf "%s %s to %d" action (aux o) p.Cudf.version in if compare o.Cudf.version p.Cudf.version < 0 then f "upgrade" else f "downgrade" | To_recompile p -> Printf.sprintf "recompile %s" (aux p) | To_delete p -> Printf.sprintf "delete %s" (aux p) let string_of_actions l = OpamMisc.string_of_list (fun a -> " - " ^ string_of_action a) l let string_of_package p = let installed = if p.Cudf.installed then "installed" else "not-installed" in Printf.sprintf "%s.%d(%s)" p.Cudf.package p.Cudf.version installed let string_of_packages l = OpamMisc.string_of_list string_of_package l let to_json p = `O [ ("name", `String p.Cudf.package); ("version", `String (string_of_int p.Cudf.version)); ("installed", `String (string_of_bool p.Cudf.installed)); ] (* Graph of cudf packages *) module Pkg = struct type t = Cudf.package include Common.CudfAdd let to_string = string_of_package let name_to_string t = t.Cudf.package let version_to_string t = string_of_int t.Cudf.version let to_json = to_json end module Action = OpamActionGraph.MakeAction(Pkg) module ActionGraph = OpamActionGraph.Make(Action) exception Cyclic_actions of Action.t list list type conflict_case = | Conflict_dep of (unit -> Algo.Diagnostic.reason list) | Conflict_cycle of string list list type conflict = Cudf.universe * int package_map * conflict_case module Map = OpamMisc.Map.Make(Pkg) module Set = OpamMisc.Set.Make(Pkg) module Graph = struct module PG = struct include Algo.Defaultgraphs.PackageGraph.G let succ g v = try succ g v with e -> OpamMisc.fatal e; [] end module PO = Algo.Defaultgraphs.GraphOper (PG) module Topo = Graph.Topological.Make (PG) let of_universe u = Algo.Defaultgraphs.PackageGraph.dependency_graph u let output g filename = let fd = open_out (filename ^ ".dot") in Algo.Defaultgraphs.PackageGraph.DotPrinter.output_graph fd g; close_out fd let transitive_closure g = PO.O.add_transitive_closure g let close_and_linearize g pkgs = let _, l = Topo.fold (fun pkg (closure, topo) -> if Set.mem pkg closure then Set.union closure (Set.of_list (PG.succ g pkg)), pkg :: topo else closure, topo) g (pkgs, []) in l let mirror = PO.O.mirror include PG end (** Special package used by Dose internally, should generally be filtered out *) let dose_dummy_request = "dose-dummy-request" let is_dose_request cpkg = cpkg.Cudf.package = dose_dummy_request let filter_dependencies f_direction universe packages = let graph = f_direction (Graph.of_universe universe) in let packages = Set.of_list packages in Graph.close_and_linearize graph packages let dependencies = filter_dependencies (fun x -> x) let reverse_dependencies = filter_dependencies Graph.mirror let string_of_atom (p, c) = let const = function | None -> "" | Some (r,v) -> Printf.sprintf " (%s %d)" (OpamFormula.string_of_relop r) v in Printf.sprintf "%s%s" p (const c) let string_of_vpkgs constr = let constr = List.sort (fun (a,_) (b,_) -> String.compare a b) constr in OpamFormula.string_of_conjunction string_of_atom constr let string_of_request r = Printf.sprintf "install:%s remove:%s upgrade:%s criteria:%S" (string_of_vpkgs r.wish_install) (string_of_vpkgs r.wish_remove) (string_of_vpkgs r.wish_upgrade) (OpamGlobals.get_solver_criteria r.criteria) let string_of_universe u = string_of_packages (List.sort Common.CudfAdd.compare (Cudf.get_packages u)) let vpkg2atom cudfnv2opam (name,cstr) = match cstr with | None -> OpamPackage.Name.of_string (Common.CudfAdd.decode name), None | Some (relop,v) -> try let nv = cudfnv2opam (name,v) in OpamPackage.name nv, Some (relop, OpamPackage.version nv) with Not_found -> assert false (* Should be unneeded now that we pass a full version_map along [{ log "Could not find corresponding version in cudf universe: %a" (slog string_of_atom) (name,cstr); let candidates = Cudf.lookup_packages cudf_universe name in let solutions = Cudf.lookup_packages ~filter:cstr cudf_universe name in let module OVS = OpamPackage.Version.Set in let to_version_set l = OVS.of_list (List.map (fun p -> OpamPackage.version (cudf2opam p)) l) in let solutions = to_version_set solutions in let others = OVS.Op.(to_version_set candidates -- solutions) in OpamPackage.Name.of_string (Common.CudfAdd.decode name), match relop, OVS.is_empty solutions, OVS.is_empty others with | _, true, true -> None | `Leq, false, _ | `Lt, false, true -> Some (`Leq, OVS.max_elt solutions) | `Lt, _, false | `Leq, true, false -> Some (`Lt, OVS.min_elt others) | `Geq, false, _ | `Gt, false, true -> Some (`Geq, OVS.min_elt solutions) | `Gt, _, false | `Geq, true, false -> Some (`Gt, OVS.max_elt others) | `Eq, false, _ -> Some (`Eq, OVS.choose solutions) | `Eq, true, _ -> Some (`Eq, OpamPackage.Version.of_string "") | `Neq, false, true -> None | `Neq, _, false -> Some (`Neq, OVS.choose others) }] *) let vpkg2opam cudfnv2opam vpkg = match vpkg2atom cudfnv2opam vpkg with | p, None -> p, Empty | p, Some (relop,v) -> p, Atom (relop, v) let conflict_empty ~version_map univ = Conflicts (univ, version_map, Conflict_dep (fun () -> [])) let make_conflicts ~version_map univ = function | {Algo.Diagnostic.result = Algo.Diagnostic.Failure f} -> Conflicts (univ, version_map, Conflict_dep f) | {Algo.Diagnostic.result = Algo.Diagnostic.Success _} -> raise (Invalid_argument "make_conflicts") let cycle_conflict ~version_map univ cycle = Conflicts (univ, version_map, Conflict_cycle cycle) let arrow_concat = String.concat (OpamGlobals.colorise `yellow " -> ") let print_cycles cycles = Printf.sprintf "The actions to process have cyclic dependencies:\n%s" (OpamMisc.itemize arrow_concat cycles) let strings_of_reason cudfnv2opam (unav_reasons: atom -> string) r = let open Algo.Diagnostic in let is_base cpkg = cpkg.Cudf.keep = `Keep_version in match r with | Conflict (i,j,_) -> if is_dose_request i || is_dose_request j then let a = if is_dose_request i then j else i in if is_dose_request a then [] else if is_base a then let str = Printf.sprintf "Package %s is part of the base for this compiler \ and can't be changed" (OpamPackage.name_to_string (cudf2opam a)) in [str] else let str = Printf.sprintf "Conflicting query for package %s" (OpamPackage.to_string (cudf2opam a)) in [str] else let nva, nvb = let nvi = cudf2opam i in let nvj = cudf2opam j in min nvi nvj, max nvi nvj in if i.Cudf.package = j.Cudf.package then if is_base j then let str = Printf.sprintf "Package %s is part of the base for this compiler \ and can't be changed" (OpamPackage.name_to_string nvb) in [str] else let str = Printf.sprintf "Conflicting version constraints for %s" (OpamPackage.name_to_string nva) in [str] else let str = Printf.sprintf "%s is in conflict with %s" (OpamPackage.to_string nva) (OpamPackage.to_string nvb) in [str] | Missing (p,missing) when is_dose_request p -> (* Requested pkg missing *) List.map (fun p -> unav_reasons (vpkg2atom cudfnv2opam p) ) missing | Missing (_,missing) -> (* Dependencies missing *) List.map (fun m -> unav_reasons (vpkg2atom cudfnv2opam m)) missing | Dependency _ -> [] let make_chains cudfnv2opam depends = let open Algo.Diagnostic in let map_addlist k v map = try Map.add k (v @ Map.find k map) map with Not_found -> Map.add k v map in let roots,notroots,deps,vpkgs = List.fold_left (fun (roots,notroots,deps,vpkgs) -> function | Dependency (i, vpkgl, jl) when not (is_dose_request i) -> Set.add i roots, List.fold_left (fun notroots j -> Set.add j notroots) notroots jl, map_addlist i jl deps, map_addlist i vpkgl vpkgs | Missing (i, vpkgl) when not (is_dose_request i) -> let jl = List.map (fun (package,_) -> {Cudf.default_package with Cudf.package}) vpkgl in Set.add i roots, notroots, map_addlist i jl deps, map_addlist i vpkgl vpkgs | _ -> roots, notroots, deps, vpkgs) (Set.empty,Set.empty,Map.empty,Map.empty) depends in let roots = Set.diff roots notroots in if Set.is_empty roots then [] else let children cpkgs = Set.fold (fun c acc -> List.fold_left (fun m a -> Set.add a m) acc (try Map.find c deps with Not_found -> [])) cpkgs Set.empty in let rec aux constrs direct_deps = if Set.is_empty direct_deps then [[]] else let depnames = Set.fold (fun p set -> OpamMisc.StringSet.add p.Cudf.package set) direct_deps OpamMisc.StringSet.empty in OpamMisc.StringSet.fold (fun name acc -> let name_deps = (* Gather all deps with the given name *) Set.filter (fun p -> p.Cudf.package = name) direct_deps in let name_constrs = List.map (List.filter (fun (n,_) -> n = name)) constrs in let to_opam_constr p = snd (vpkg2opam cudfnv2opam p) in let formula = OpamFormula.ors (List.map (fun conj -> OpamFormula.ands (List.map to_opam_constr conj)) name_constrs) in let formula = OpamFormula.simplify_version_formula formula in let opam_name = OpamPackage.Name.of_string (Common.CudfAdd.decode name) in let formula = Atom (opam_name, formula) in let children_constrs = List.map (fun p -> try Map.find p vpkgs with Not_found -> []) (Set.elements name_deps) in let chains = aux children_constrs (children name_deps) in List.fold_left (fun acc chain -> (formula :: chain) :: acc) acc chains ) depnames [] in let start_constrs = let set = Set.fold (fun p acc -> OpamMisc.StringSet.add p.Cudf.package acc) roots OpamMisc.StringSet.empty in List.map (fun name -> [name,None]) (OpamMisc.StringSet.elements set) in aux start_constrs roots let strings_of_final_reasons cudfnv2opam unav_reasons reasons = let reasons = List.flatten (List.map (strings_of_reason cudfnv2opam unav_reasons) reasons) in OpamMisc.StringSet.(elements (of_list reasons)) let strings_of_chains cudfnv2opam reasons = let chains = make_chains cudfnv2opam reasons in let string_of_chain c = arrow_concat (List.map OpamFormula.to_string c) in List.map string_of_chain chains let strings_of_cycles cycles = List.map arrow_concat cycles let strings_of_conflict unav_reasons = function | univ, version_map, Conflict_dep reasons -> let r = reasons () in let cudfnv2opam = cudfnv2opam ~cudf_universe:univ ~version_map in strings_of_final_reasons cudfnv2opam unav_reasons r, strings_of_chains cudfnv2opam r, [] | _univ, _version_map, Conflict_cycle cycles -> [], [], strings_of_cycles cycles let string_of_conflict unav_reasons conflict = let final, chains, cycles = strings_of_conflict unav_reasons conflict in let b = Buffer.create 1024 in let pr_items b l = List.iter (Printf.bprintf b " - %s\n") l in if cycles <> [] then Printf.bprintf b "The actions to process have cyclic dependencies:\n%a" pr_items cycles; if chains <> [] then Printf.bprintf b "The following dependencies couldn't be met:\n%a" pr_items chains; if final <> [] then Printf.bprintf b "Your request can't be satisfied:\n%a" pr_items final; if final = [] && chains = [] && cycles = [] then (* No explanation found *) Printf.bprintf b "Sorry, no solution found: \ there seems to be a problem with your request.\n"; Buffer.add_string b "\n"; Buffer.contents b let check flag p = try Cudf.lookup_typed_package_property p flag = `Bool true with Not_found -> false let need_reinstall = check s_reinstall let is_installed_root = check s_installed_root let is_pinned = check s_pinned let default_preamble = let l = [ (s_source, `String None) ; (s_source_number, `String None); (s_reinstall, `Bool (Some false)); (s_installed_root, `Bool (Some false)); (s_pinned, `Bool (Some false)); (s_version_lag, `Nat (Some 0)); ] in Common.CudfAdd.add_properties Cudf.default_preamble l let remove universe name constr = let filter p = p.Cudf.package <> name || not (Cudf.version_matches p.Cudf.version constr) in let packages = Cudf.get_packages ~filter universe in Cudf.load_universe packages let uninstall_all universe = let packages = Cudf.get_packages universe in let packages = List.rev_map (fun p -> { p with Cudf.installed = false }) packages in Cudf.load_universe packages let install universe package = let p = Cudf.lookup_package universe (package.Cudf.package, package.Cudf.version) in let p = { p with Cudf.installed = true } in let packages = let filter p = p.Cudf.package <> package.Cudf.package || p.Cudf.version <> package.Cudf.version in Cudf.get_packages ~filter universe in Cudf.load_universe (p :: packages) let remove_all_uninstalled_versions_but universe name constr = let filter p = p.Cudf.installed || p.Cudf.package <> name || Cudf.version_matches p.Cudf.version constr in let packages = Cudf.get_packages ~filter universe in Cudf.load_universe packages let to_cudf univ req = ( default_preamble, univ, { Cudf.request_id = "opam"; install = req.wish_install; remove = req.wish_remove; upgrade = req.wish_upgrade; req_extra = [] } ) let external_solver_name () = match OpamGlobals.external_solver ~input:"" ~output:"" ~criteria:"" with | cmd::_ -> cmd | [] -> raise Not_found let external_solver_exists = lazy ( try let name = external_solver_name () in let ex = OpamSystem.command_exists name in if not ex && !OpamGlobals.use_external_solver && !OpamGlobals.env_external_solver <> None then OpamGlobals.error_and_exit "Your configuration or environment specifies external solver %s, but \ it cannot be found. Fix your installation, your configuration or \ use '--use-internal-solver'." name else ex with Not_found -> false ) let external_solver_available () = !OpamGlobals.use_external_solver && (Lazy.force external_solver_exists) let solver_calls = ref 0 let dump_universe oc univ = Cudf_printer.pp_cudf oc (default_preamble, univ, Cudf.default_request) let dump_cudf_request ~extern ~version_map (_, univ,_ as cudf) criteria = function | None -> None | Some f -> ignore ( version_map: int OpamPackage.Map.t ); incr solver_calls; let filename = Printf.sprintf "%s-%d.cudf" f !solver_calls in let oc = open_out filename in if extern then Printf.fprintf oc "# %s\n" (String.concat " " (OpamGlobals.external_solver ~input:"$in" ~output:"$out" ~criteria)) else Printf.fprintf oc "#internal OPAM solver\n"; Cudf_printer.pp_cudf oc cudf; OpamPackage.Map.iter (fun (pkg:OpamPackage.t) (vnum: int) -> let name = OpamPackage.name_to_string pkg in let version = OpamPackage.version_to_string pkg in Printf.fprintf oc "#v2v:%s:%d=%s\n" name vnum version; ) version_map; close_out oc; Graph.output (Graph.of_universe univ) f; Some filename let dump_cudf_error ~extern ~version_map univ req = let cudf_file = match !OpamGlobals.cudf_file with | Some f -> f | None -> let (/) = Filename.concat in !OpamGlobals.root_dir / "log" / ("solver-error-"^string_of_int (Unix.getpid())) in match dump_cudf_request ~extern (to_cudf univ req) ~version_map (OpamGlobals.get_solver_criteria req.criteria) (Some cudf_file) with | Some f -> f | None -> assert false let dose_solver_callback ~criteria (_,universe,_ as cudf) = let solver_in = OpamFilename.of_string (OpamSystem.temp_file "solver-in") in let solver_out = OpamFilename.of_string (OpamSystem.temp_file "solver-out") in try let _ = let oc = OpamFilename.open_out solver_in in Cudf_printer.pp_cudf oc cudf; close_out oc in OpamSystem.command ~verbose:(!OpamGlobals.debug_level >= 2) (OpamGlobals.external_solver ~input:(OpamFilename.to_string solver_in) ~output:(OpamFilename.to_string solver_out) ~criteria); OpamFilename.remove solver_in; if not (OpamFilename.exists solver_out) then raise (Common.CudfSolver.Error "no output") else if (let ic = OpamFilename.open_in solver_out in try let i = input_line ic in close_in ic; i = "FAIL" with End_of_file -> close_in ic; false) then raise Common.CudfSolver.Unsat else let r = Cudf_parser.load_solution_from_file (OpamFilename.to_string solver_out) universe in OpamFilename.remove solver_out; if Cudf.universe_size (snd r) = 0 && not !OpamGlobals.no_base_packages && Cudf.installed_size universe <> 0 then raise (Common.CudfSolver.Error "empty solution"); r with e -> OpamFilename.remove solver_in; OpamFilename.remove solver_out; raise e let check_cudf_version = let r = lazy ( if external_solver_available () then try log "Checking version of criteria accepted by the external solver"; (* Run with closed stdin to workaround bug in some solver scripts *) match OpamSystem.read_command_output ~verbose:false ~allow_stdin:false [external_solver_name (); "-v"] with | [] -> log "No response from 'solver -v', using compat criteria"; `Compat | s::_ -> match OpamMisc.split s ' ' with | "aspcud"::_::v::_ when Debian.Version.compare v "1.9" >= 0 -> log "Solver is aspcud > 1.9: using latest version criteria"; `Latest | _ -> log "Solver isn't aspcud > 1.9, using compat criteria"; `Compat with OpamSystem.Process_error _ -> log "Solver doesn't know about '-v': using compat criteria"; `Compat else `Compat (* don't care, internal solver doesn't handle them *) ) in fun () -> Lazy.force r let call_external_solver ~version_map univ req = let cudf_request = to_cudf univ req in if Cudf.universe_size univ > 0 then let criteria = OpamGlobals.get_solver_criteria req.criteria in ignore (dump_cudf_request ~extern:true ~version_map cudf_request criteria !OpamGlobals.cudf_file); try Algo.Depsolver.check_request_using ~call_solver:(dose_solver_callback ~criteria) ~criteria ~explain:true cudf_request with e -> OpamMisc.fatal e; OpamGlobals.warning "External solver failed:"; OpamGlobals.errmsg "%s\n" (Printexc.to_string e); failwith "opamSolver" else Algo.Depsolver.Sat(None,Cudf.load_universe []) let check_request ?(explain=true) ~version_map univ req = match Algo.Depsolver.check_request ~explain (to_cudf univ req) with | Algo.Depsolver.Unsat (Some ({Algo.Diagnostic.result = Algo.Diagnostic.Failure _} as r)) -> make_conflicts ~version_map univ r | Algo.Depsolver.Sat (_,u) -> Success (remove u "dose-dummy-request" None) | Algo.Depsolver.Error msg -> let f = dump_cudf_error ~extern:false ~version_map univ req in OpamGlobals.error "Internal solver failed with %s Request saved to %S" msg f; failwith "opamSolver" | Algo.Depsolver.Unsat _ -> (* normally when [explain] = false *) conflict_empty ~version_map univ (* Return the universe in which the system has to go *) let get_final_universe ~version_map univ req = let fail msg = let f = dump_cudf_error ~extern:true ~version_map univ req in OpamGlobals.warning "External solver failed with %s Request saved to %S" msg f; failwith "opamSolver" in match call_external_solver ~version_map univ req with | Algo.Depsolver.Sat (_,u) -> Success (remove u "dose-dummy-request" None) | Algo.Depsolver.Error "(CRASH) Solution file is empty" -> (* XXX Is this still needed with latest dose ? *) Success (Cudf.load_universe []) | Algo.Depsolver.Error str -> fail str | Algo.Depsolver.Unsat r -> let open Algo.Diagnostic in match r with | Some ({result=Failure _} as r) -> make_conflicts ~version_map univ r | Some {result=Success _} -> fail "inconsistent return value." | None -> (* External solver did not provide explanations, hopefully this will *) check_request ~version_map univ req (* A modified version of CudfDiff to handle reinstallations *) module Diff = struct type package = { installed : Set.t; removed : Set.t; reinstalled: Set.t; } type universe = (string, package) Hashtbl.t (* for each pkgname I've the list of all versions that were installed or removed *) let diff univ sol = let pkgnames = OpamMisc.StringSet.of_list (List.rev_map (fun p -> p.Cudf.package) (Cudf.get_packages univ)) in let h = Hashtbl.create (OpamMisc.StringSet.cardinal pkgnames) in let needed_reinstall = Set.of_list (Cudf.get_packages ~filter:need_reinstall univ) in OpamMisc.StringSet.iter (fun pkgname -> let were_installed = Set.of_list (Cudf.get_installed univ pkgname) in let are_installed = Set.of_list (Cudf.get_installed sol pkgname) in let removed = Set.diff were_installed are_installed in let installed = Set.diff are_installed were_installed in let reinstalled = Set.inter are_installed needed_reinstall in let s = { removed; installed; reinstalled } in Hashtbl.add h pkgname s ) pkgnames ; h end (* Transform a diff from current to final state into a list of actions. At this point, we don't know about the root causes of the actions, they will be computed later. *) let actions_of_diff diff = Hashtbl.fold (fun _ s acc -> let add x = x :: acc in let removed = try Some (Set.choose_one s.Diff.removed) with Not_found -> None in let installed = try Some (Set.choose_one s.Diff.installed) with Not_found -> None in let reinstalled = try Some (Set.choose_one s.Diff.reinstalled) with Not_found -> None in match removed, installed, reinstalled with | None , Some p , _ -> add (To_change (None, p)) | Some p , None , _ -> add (To_delete p) | Some p_old, Some p_new , _ -> add (To_change (Some p_old, p_new)) | None , None , Some p -> add (To_recompile p) | None , None , None -> acc ) diff [] let resolve ~extern ~version_map universe request = log "resolve request=%a" (slog string_of_request) request; if extern then get_final_universe ~version_map universe request else check_request ~version_map universe request let to_actions f universe result = let aux u1 u2 = let diff = Diff.diff (f u1) u2 in actions_of_diff diff in map_success (aux universe) result let create_graph filter universe = let pkgs = Cudf.get_packages ~filter universe in let u = Cudf.load_universe pkgs in Graph.of_universe u let find_cycles g = let open ActionGraph in let roots = fold_vertex (fun v acc -> if in_degree g v = 0 then v::acc else acc) g [] in let roots = if roots = [] then fold_vertex (fun v acc -> v::acc) g [] else roots in let rec prefix_find acc v = function | x::_ when x = v -> Some (x::acc) | x::r -> prefix_find (x::acc) v r | [] -> None in let seen = Hashtbl.create 17 in let rec follow v path = match prefix_find [] v path with | Some cycle -> Hashtbl.add seen v (); [cycle@[v]] | None -> if Hashtbl.mem seen v then [] else let path = v::path in Hashtbl.add seen v (); List.fold_left (fun acc s -> follow s path @ acc) [] (succ g v) in List.fold_left (fun cycles root -> follow root [] @ cycles ) [] roots (* Compute the original causes of the actions, from the original set of packages in the user request. In the restricted dependency graph, for each action we find the closest package belonging to the user request and print out the closest neighbour that gets there. This way, if a -> b -> c and the user requests a to be installed, we can print: - install a - install b [required by a] - intall c [required by b] *) let compute_root_causes g requested = let module StringSet = OpamMisc.StringSet in let module StringMap = OpamMisc.StringMap in let requested_pkgnames = OpamPackage.Name.Set.fold (fun n s -> StringSet.add (Common.CudfAdd.encode (OpamPackage.Name.to_string n)) s) requested StringSet.empty in let actions = ActionGraph.fold_vertex (fun a acc -> Map.add (action_contents a) a acc) g Map.empty in let requested_actions = Map.filter (fun pkg _ -> StringSet.mem pkg.Cudf.package requested_pkgnames) actions in let merge_causes (c1,depth1) (c2,depth2) = if c2 = Unknown || depth1 < depth2 then c1, depth1 else if c1 = Unknown || depth2 < depth1 then c2, depth2 else let (@) = List.fold_left (fun l a -> if List.mem a l then l else a::l) in match c1, c2 with | Required_by a, Required_by b -> Required_by (a @ b), depth1 | Use a, Use b -> Use (a @ b), depth1 | Conflicts_with a, Conflicts_with b -> Conflicts_with (a @ b), depth1 | Requested, a | a, Requested | Unknown, a | a, Unknown | Upstream_changes , a | a, Upstream_changes -> a, depth1 | _, c -> c, depth1 in let direct_cause cause consequence dep = match (cause, consequence, dep) with | To_change(_,p), To_change(_,_), `Provides -> Required_by [p] | To_change(_,p), To_change(Some _,_), `Depends -> Use [p] | a, To_recompile _, `Depends -> Use [action_contents a] | _, To_recompile _, `Provides -> Unknown | To_delete p, To_delete _, `Provides -> Use [p] | To_delete p, To_change _, `Provides -> Use [p] | To_recompile p, To_change _, `Provides -> Required_by [p] | _, To_change(None,_), `Depends -> Unknown | _, To_change _, _ -> Upstream_changes | To_change _, To_delete _, `Provides -> Conflicts_with [action_contents cause] | To_recompile p, To_delete _, `Provides -> Conflicts_with [p] | _, _, _ -> Unknown in let get_causes acc roots = let rec aux seen depth pkgname causes = if depth > 100 then (OpamGlobals.error "Internal error computing action causes: sorry, please report."; causes) else let action = Map.find pkgname actions in let seen = Set.add pkgname seen in let propagate causes actions direction = List.fold_left (fun causes act -> let p = action_contents act in if Set.mem p seen then causes else let cause = direct_cause action act direction in if cause = Unknown then causes else try Map.add p (merge_causes (cause,depth) (Map.find p causes)) causes with Not_found -> aux seen (depth + 1) p (Map.add p (cause,depth) causes) ) causes actions in let causes = propagate causes (ActionGraph.pred g action) `Provides in let causes = propagate causes (ActionGraph.succ g action) `Depends in causes in let start = Map.fold (fun k _ acc -> Set.add k acc) roots Set.empty in let acc = Map.union (fun a _ -> a) acc roots in Set.fold (aux start 1) start acc in (* Compute the roots of the action given a condition *) let make_roots causes base_cause f = ActionGraph.fold_vertex (fun act acc -> if Map.mem (action_contents act) causes then acc else if f act then Map.add (action_contents act) (base_cause,0) acc else acc) g Map.empty in let causes = Map.empty in let causes = let roots = if Map.is_empty requested_actions then (* Assume a global upgrade *) make_roots causes Requested (function | To_change (Some p1,p2) when p1.Cudf.version < p2.Cudf.version -> true | _ -> false) else (Map.map (fun _ -> Requested, 0) requested_actions) in get_causes causes roots in let causes = (* Compute causes for remaining upgrades (maybe these could be removed from the actions altogether since they are unrelated to the request ?) *) let roots = make_roots causes Unknown (function | To_change (Some _,_) as act when List.for_all (function To_change _ -> false | _ -> true) (ActionGraph.pred g act) -> true | _ -> false) in get_causes causes roots in let causes = (* Compute causes for packages marked to reinstall *) let roots = make_roots causes Upstream_changes (function To_recompile p -> need_reinstall p | _ -> false) in get_causes causes roots in Map.map fst causes (* Compute a full solution from a set of root actions. This means adding all required reinstallations and computing the graph of dependency of required actions *) let atomic_actions ~simple_universe ~complete_universe root_actions = log "graph_of_actions root_actions=%a" (slog string_of_actions) root_actions; let to_remove, to_install = List.fold_left (fun (rm,inst) a -> match a with | To_change (Some p1,p2) -> Set.add p1 rm, Set.add p2 inst | To_change (None,p) -> rm, Set.add p inst | To_recompile p -> Set.add p rm, Set.add p inst | To_delete p -> Set.add p rm, inst) (Set.empty, Set.empty) root_actions in (* transitively add recompilations *) let to_remove, to_install = let packages = Set.union to_remove to_install in let package_graph = let filter p = p.Cudf.installed || Set.mem p packages in Graph.mirror (create_graph filter simple_universe) in Graph.Topo.fold (fun p (rm,inst) -> let actionned p = Set.mem p rm || Set.mem p inst in if not (actionned p) && List.exists actionned (Graph.pred package_graph p) then Set.add p rm, Set.add p inst else rm, inst) package_graph (to_remove, to_install) in let pkggraph set = create_graph (fun p -> Set.mem p set) complete_universe in (* Build the graph of atomic actions: Removals or installs *) let g = ActionGraph.create () in Set.iter (fun p -> ActionGraph.add_vertex g (To_delete p)) to_remove; Set.iter (fun p -> ActionGraph.add_vertex g (To_change (None,p))) to_install; (* reinstalls and upgrades: remove first *) Set.iter (fun p1 -> try let p2 = Set.find (fun p2 -> p1.Cudf.package = p2.Cudf.package) to_install in ActionGraph.add_edge g (To_delete p1) (To_change (None,p2)) with Not_found -> ()) to_remove; (* uninstall order *) Graph.iter_edges (fun p1 p2 -> ActionGraph.add_edge g (To_delete p1) (To_delete p2) ) (pkggraph to_remove); (* install order *) Graph.iter_edges (fun p1 p2 -> if Set.mem p1 to_install then let cause = if Set.mem p2 to_install then To_change (None, p2) else To_delete p2 in ActionGraph.add_edge g cause (To_change (None, p1)) ) (pkggraph (Set.union to_install to_remove)); (* conflicts *) let conflicts_graph = let filter p = Set.mem p to_remove || Set.mem p to_install in Algo.Defaultgraphs.PackageGraph.conflict_graph (Cudf.load_universe (Cudf.get_packages ~filter complete_universe)) in Algo.Defaultgraphs.PackageGraph.UG.iter_edges (fun p1 p2 -> if Set.mem p1 to_remove && Set.mem p2 to_install then ActionGraph.add_edge g (To_delete p1) (To_change (None, p2)) else if Set.mem p2 to_remove && Set.mem p1 to_install then ActionGraph.add_edge g (To_delete p2) (To_change (None, p1))) conflicts_graph; (* check for cycles *) match find_cycles g with | [] -> g | cycles -> raise (Cyclic_actions cycles) let packages u = Cudf.get_packages u opam-full-1.2.2/src/client/0000755000175000017500000000000012532744757014213 5ustar useruseropam-full-1.2.2/src/client/opamRepositoryCommand.ml0000644000175000017500000005233412517374212021073 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamState.Types open OpamMisc.OP open OpamPackage.Set.Op open OpamProcess.Job.Op let log fmt = OpamGlobals.log "REPOSITORY" fmt let slog = OpamGlobals.slog let update t repo = let max_loop = 10 in (* Recursively traverse redirection links, but stop after 10 steps or if we start to cycle. *) let rec job r n = if n = 0 then (OpamGlobals.warning "%s: Too many redirections, stopping." (OpamRepositoryName.to_string repo.repo_name); Done ()) else let text = OpamProcess.make_command_text ~color:`blue (OpamRepositoryName.to_string repo.repo_name) (string_of_repository_kind repo.repo_kind) in OpamProcess.Job.with_text text @@ OpamRepository.update r @@+ fun () -> if n <> max_loop && r = repo then (OpamGlobals.warning "%s: Cyclic redirections, stopping." (OpamRepositoryName.to_string repo.repo_name); Done ()) else match OpamState.redirect t r with | None -> Done () | Some (new_repo, f) -> OpamFilename.rmdir repo.repo_root; OpamFile.Repo_config.write (OpamPath.Repository.config repo) new_repo; let reason = match f with | None -> "" | Some f -> Printf.sprintf " (%s)" (OpamFilter.to_string f) in OpamGlobals.note "The repository '%s' will be *%s* redirected to %s%s" (OpamRepositoryName.to_string repo.repo_name) ((OpamGlobals.colorise `bold) "permanently") (OpamMisc.prettify_path (string_of_address new_repo.repo_address)) reason; job new_repo (n-1) in job repo max_loop @@+ fun () -> let repo = repo |> OpamPath.Repository.config |> OpamFile.Repo_config.safe_read in OpamRepository.check_version repo @@+ fun () -> Done ( fun t -> { t with repositories = OpamRepositoryName.Map.add repo.repo_name repo t.repositories } ) let print_updated_compilers updates = let print singular plural map = if not (OpamCompiler.Set.is_empty map) then ( if OpamCompiler.Set.cardinal map = 1 then OpamGlobals.msg "%s:\n" singular else OpamGlobals.msg "%s:\n" plural; OpamCompiler.Set.iter (fun comp -> OpamGlobals.msg " - %s\n" (OpamCompiler.to_string comp) ) map ) in print "The following NEW compiler is available" "The following NEW compilers are available" updates.created; print "The following compiler description has been UPDATED" "The following compiler descriptions have been UPDATED" updates.updated; print "The following compiler description has been DELETED" "The following compiler descriptions have been DELETED" updates.deleted let filter_compiler_checksums cs = let keep f = OpamFilename.check_suffix f ".comp" in List.filter keep cs let fix_compiler_descriptions t ~verbose = log "Updating %a/ ...\n" (slog (OpamFilename.prettify_dir @* OpamPath.compilers_dir)) t.root; let global_index = OpamState.compiler_state t in let repo_index = OpamState.compiler_repository_state t in let niet = String.concat ":" in log "global-index: %a" (slog @@ OpamCompiler.Map.to_string niet) global_index; log "repo-index : %a" (slog @@ OpamCompiler.Map.to_string niet) repo_index; let updated_compilers, new_compilers = let updated_compilers = OpamCompiler.Map.fold (fun comp state set -> if not (OpamCompiler.Map.mem comp global_index) || OpamCompiler.Map.find comp global_index <> state then OpamCompiler.Set.add comp set else set ) repo_index OpamCompiler.Set.empty in OpamCompiler.Set.partition (OpamState.is_compiler_installed t) updated_compilers in log "updated-compilers: %a" (slog OpamCompiler.Set.to_string) updated_compilers; log "new-compilers : %a" (slog OpamCompiler.Set.to_string) new_compilers; let deleted_compilers = OpamCompiler.Set.fold (fun comp map -> if comp = OpamCompiler.system (* system *) || OpamCompiler.Map.mem comp repo_index (* OR available *) then map else OpamCompiler.Set.add comp map ) t.compilers OpamCompiler.Set.empty in log "deleted-compilers: %a" (slog OpamCompiler.Set.to_string) deleted_compilers; (* Delete compiler descritions (unless they are still installed) *) OpamCompiler.Set.iter (fun comp -> if not (OpamState.is_compiler_installed t comp) then let dir = OpamPath.compilers t.root comp in OpamFilename.rmdir dir; ) deleted_compilers; (* Update the compiler description *) OpamCompiler.Set.iter (fun comp -> match OpamState.repository_and_prefix_of_compiler t comp with | None -> () | Some (repo, prefix) -> let files = OpamRepository.compiler_files repo prefix comp in let dir = OpamPath.compilers t.root comp in OpamFilename.rmdir dir; OpamFilename.mkdir dir; List.iter (fun file -> OpamFilename.copy_in file dir ) files; ) (OpamCompiler.Set.union updated_compilers new_compilers); let updates = { created = new_compilers; updated = updated_compilers; deleted = deleted_compilers; changed = OpamCompiler.Set.empty; (* we don't reinstall compilers yet *) } in if verbose then print_updated_compilers updates; updates let print_updated_packages t updates = let print singular plural map fn = if not (OpamPackage.Set.is_empty map) then ( if OpamPackage.Set.cardinal map = 1 then OpamGlobals.msg "%s:\n" singular else OpamGlobals.msg "%s:\n" plural; OpamPackage.Set.iter (fun nv -> match fn nv with | None -> OpamGlobals.msg " - %s\n" (OpamPackage.to_string nv) | Some s -> OpamGlobals.msg " - %s [%s]\n" (OpamPackage.to_string nv) s ) map ) in let installed_switches nv = let installed = OpamState.installed_versions t (OpamPackage.name nv) in let installed = try OpamPackage.Map.find nv installed with Not_found -> [] in (* XXX: should never happen *) match installed with | [] -> None | _ -> Some ( Printf.sprintf "%s (%s)" (OpamPackage.Version.to_string (OpamPackage.version nv)) (OpamMisc.pretty_list (List.map OpamSwitch.to_string installed)) ) in let none _ = None in print "The following NEW package is available" "The following NEW packages are available" updates.created none; print "The following package has been CHANGED upstream and needs to be recompiled" "The following packages have been CHANGED upstream and need to be recompiled" updates.changed installed_switches; print "The following package has been UPDATED upstream" "The following packages have been UPDATED upstream" updates.updated none; print "The following package has been DELETED" "The following packages have been DELETED" updates.deleted none let print_updated_dev_packages pinned_packages = let print singular plural map = if not (OpamPackage.Set.is_empty map) then ( if OpamPackage.Set.cardinal map = 1 then OpamGlobals.msg "%s:\n" singular else OpamGlobals.msg "%s:\n" plural; OpamPackage.Set.iter (fun nv -> OpamGlobals.msg " - %s\n" (OpamPackage.to_string nv) ) map ) in print "The following DEV package needs to be upgraded" "The following DEV packages need to be upgraded" pinned_packages (* Check for updates in pinned packages *) let update_dev_packages t ~verbose packages = log "update-dev-packages updates %a" (slog OpamPackage.Set.to_string) packages; let updates = OpamState.update_dev_packages t packages in if verbose then print_updated_dev_packages updates ; updates let filter_package_checksums cs = let keep f = match OpamFilename.Base.to_string (OpamFilename.basename f) with | "opam" | "descr" -> false | _ -> true in List.filter keep cs (* Update the package contents, display the new packages and update reinstall *) let fix_package_descriptions t ~verbose = log "Updating %a/ ...\n" (slog (OpamFilename.prettify_dir @* OpamPath.packages_dir)) t.root; let global_index = OpamState.package_state t in let repo_index = OpamState.package_repository_state t in (* let niet = String.concat ":" in *) (* log "global-index: %s" (OpamPackage.Map.to_string niet global_index); *) (* log "repo-index : %s" (OpamPackage.Map.to_string niet repo_index); *) let updated_packages, new_packages = let updated_packages = OpamPackage.Map.fold (fun nv state set -> try if OpamPackage.Map.find nv global_index <> state then OpamPackage.Set.add nv set else set with Not_found -> OpamPackage.Set.add nv set ) repo_index OpamPackage.Set.empty in OpamPackage.Set.partition (fun nv -> OpamPackage.Map.mem nv global_index ) updated_packages in let all_installed = OpamState.all_installed t in let changed_packages = OpamPackage.Set.inter all_installed updated_packages in let missing_installed_packages = OpamPackage.Set.filter (fun nv -> try match OpamPackage.Map.find nv global_index with | [] -> OpamPackage.Map.mem nv repo_index | _ -> false with Not_found -> true ) all_installed in log "new-packages : %a" (slog OpamPackage.Set.to_string) new_packages; log "updated-packages : %a" (slog OpamPackage.Set.to_string) updated_packages; log "changed-packages : %a" (slog OpamPackage.Set.to_string) changed_packages; log "missing-installed: %a" (slog OpamPackage.Set.to_string) missing_installed_packages; let deleted_packages = t.packages -- OpamPackage.keys repo_index -- OpamState.pinned_packages t in log "deleted-packages: %a" (slog OpamPackage.Set.to_string) deleted_packages; (* Notify only about deleted packages that are installed or were just removed (ie ignore the one that were removed from upstream but still have data locally because they used to be installed) *) let upstream_deleted_packages = OpamPackage.Set.filter (fun nv -> OpamPackage.Set.mem nv all_installed || not (OpamFilename.exists (OpamPath.opam t.root nv))) deleted_packages in (* Remove the deleted packages' data (unless they are still installed) *) OpamPackage.Set.iter (fun nv -> if not (OpamPackage.Set.mem nv all_installed) then ( OpamFilename.rmdir (OpamPath.packages t.root nv); OpamFilename.remove (OpamPath.archive t.root nv); )) deleted_packages; (* that's not a good idea *at all* to enable this hook if you are not in a testing environment *) if !OpamGlobals.sync_archives then OpamParallel.iter ~jobs:(OpamState.dl_jobs t) ~command:(fun nv -> log "download %a" (slog @@ OpamFilename.to_string @* OpamPath.archive t.root) nv; OpamState.download_archive t nv @@+ fun _ -> Done ()) (OpamPackage.Map.keys repo_index); (* Do not recompile a package if only OPAM or descr files have changed. We recompile a package: - if both global and repo states have an archive file and the checksums of important files have changed; - if both global and repo states don't have an archive file and the checksums of important files have changed; - if only one of them have an archive file, if the checksums of the important files without the archive have changed. *) let changed_packages = OpamPackage.Set.filter (fun nv -> let archive_g, checksums_g = OpamState.package_partial_state t nv ~archive:true in let archive_r, checksums_r = OpamState.package_repository_partial_state t nv ~archive:true in if archive_g = archive_r then checksums_g <> checksums_r else let _, checksums_g = OpamState.package_partial_state t nv ~archive:false in let _, checksums_r = OpamState.package_repository_partial_state t nv ~archive:false in checksums_g <> checksums_r ) changed_packages in log "packages-to-reinstall: %a" (slog OpamPackage.Set.to_string) changed_packages; (* Update the package descriptions *) OpamPackage.Set.iter (fun nv -> match OpamState.repository_and_prefix_of_package t nv with | None -> () | Some (repo, prefix) -> let dir = OpamPath.packages t.root nv in if OpamFilename.exists_dir dir then OpamFilename.rmdir dir; if OpamPackage.Set.mem nv all_installed then let root = OpamPath.Repository.packages repo prefix nv in let files = OpamRepository.package_files repo prefix nv ~archive:false in assert (files <> []); OpamFilename.mkdir dir; List.iter (fun file -> OpamFilename.copy_in ~root file dir ) files; OpamFilename.remove (OpamPath.archive t.root nv); OpamFilename.remove (OpamPath.Repository.archive repo nv); ) (OpamPackage.Set.union missing_installed_packages updated_packages); (* Remove archives of non-installed packages (these may no longer be up-to-date) *) OpamPackage.Set.iter (fun nv -> let f = OpamPath.archive t.root nv in if OpamFilename.exists f then (log "Cleaning up obsolete archive %a" (slog OpamFilename.to_string) f; OpamFilename.remove f)) (OpamPackage.keys global_index -- all_installed); (* Display some warnings/errors *) OpamPackage.Set.iter (fun nv -> let file = OpamPath.Switch.Overlay.opam t.root t.switch (OpamPackage.name nv) in let file = if OpamFilename.exists file then file else OpamPath.opam t.root nv in if not (OpamFilename.exists file) then if OpamPackage.Map.mem nv repo_index then OpamGlobals.error_and_exit "fatal: %s is missing" (OpamFilename.prettify file) else let installed = OpamState.installed_versions t (OpamPackage.name nv) in let switches = OpamPackage.Map.find nv installed in let switches_string = OpamMisc.pretty_list (List.map OpamSwitch.to_string switches) in OpamGlobals.warning "%s is installed in %s but it does not have metadata." (OpamPackage.to_string nv) switches_string ) t.installed; let updates = { created = new_packages; updated = OpamPackage.Set.diff updated_packages changed_packages; deleted = upstream_deleted_packages; changed = changed_packages; } in if verbose then print_updated_packages t updates; (* update $opam/$oversion/reinstall for all installed switches *) OpamState.add_to_reinstall ~all:true t updates.changed; updates let compare_repo t r1 r2 = OpamRepository.compare (OpamState.find_repository t r1) (OpamState.find_repository t r2) let update_package_index t = let file = OpamPath.package_index t.root in log "Updating %a ...\n" (slog OpamFilename.prettify) file; let package_index = OpamState.package_index t in OpamFile.Package_index.write file package_index; { t with package_index } let update_compiler_index t = let file = OpamPath.compiler_index t.root in log "Updating %a ...\n" (slog OpamFilename.prettify) file; let compiler_index = OpamState.compiler_index t in OpamFile.Compiler_index.write file compiler_index; { t with compiler_index } (* update the repository config file: ~/.opam/repo//config *) let update_config t repos = log "update-config %a" (slog @@ OpamMisc.pretty_list @* List.map OpamRepositoryName.to_string) repos; let new_config = OpamFile.Config.with_repositories t.config repos in OpamFile.Config.write (OpamPath.config t.root) new_config let fix_descriptions ?(save_cache=true) ?(verbose = !OpamGlobals.verbose_level >= 3) t = let t = update_compiler_index t in let _ = fix_compiler_descriptions t ~verbose in let t = update_package_index t in let _ = fix_package_descriptions t ~verbose in if save_cache then OpamState.rebuild_state_cache () let () = OpamState.fix_descriptions_hook := fix_descriptions (* Remove any remaining of [repo] from OPAM state *) let cleanup t repo = log "cleanup %a" (slog OpamRepositoryName.to_string) repo.repo_name; let repos = OpamRepositoryName.Map.keys t.repositories in update_config t (List.filter ((<>) repo.repo_name) repos); OpamFilename.rmdir repo.repo_root; fix_descriptions t let priority repo_name ~priority = log "repository-priority"; (* 1/ update the config file *) let t = OpamState.load_state ~save_cache:false "repository-priority" in let repo = OpamState.find_repository t repo_name in let config_f = OpamPath.Repository.config repo in let config = let config = OpamFile.Repo_config.read config_f in { config with repo_priority = priority } in OpamFile.Repo_config.write config_f config; (* relink the compiler and package descriptions *) fix_descriptions t let add name kind address ~priority:prio = log "repository-add"; let t = OpamState.load_state "repository-add" in if OpamState.mem_repository t name then OpamGlobals.error_and_exit "%s is already a remote repository" (OpamRepositoryName.to_string name); if kind = `local then ( let repo_dir = OpamFilename.Dir.of_string (string_of_address address) in let pkgdir = OpamPath.packages_dir repo_dir in let compdir = OpamPath.compilers_dir repo_dir in if not (OpamFilename.exists_dir pkgdir) && not (OpamFilename.exists_dir compdir) && not (OpamGlobals.confirm "%S doesn't contain a \"packages\" nor a \"compilers\" directory.\n\ Is it really the directory of your repo ?" (OpamFilename.Dir.to_string repo_dir)) then OpamGlobals.exit 1 ); let prio = match prio with | Some p -> p | None -> if OpamRepositoryName.Map.is_empty t.repositories then 0 else let max_prio = OpamRepositoryName.Map.fold (fun _ { repo_priority } m -> max repo_priority m) t.repositories min_int in 10 + max_prio in let repo = { repo_name = name; repo_kind = kind; repo_address = address; repo_priority = prio; repo_root = OpamPath.Repository.create t.root name; } in OpamProcess.Job.run (OpamRepository.init repo); log "Adding %a" (slog OpamRepository.to_string) repo; let repositories = OpamRepositoryName.Map.add name repo t.repositories in update_config t (OpamRepositoryName.Map.keys repositories); let t = { t with repositories } in OpamState.remove_state_cache (); try let t = OpamProcess.Job.run (update t repo) t in fix_descriptions t with | OpamRepository.Unknown_backend -> cleanup t repo; OpamGlobals.error_and_exit "\"%s\" is not a supported backend" (string_of_repository_kind repo.repo_kind) | _ -> cleanup t repo; OpamGlobals.error_and_exit "Could not fetch repo" let remove name = log "repository-remove"; let t = OpamState.load_state "repository-remove" in let repo = OpamState.find_repository t name in cleanup t repo let set_url name url = log "repository-remove"; let t = OpamState.load_state ~save_cache:false "repository-set-url" in let repo = OpamState.find_repository t name in let url, kind = parse_url url in if repo.repo_kind <> kind then (remove name; add name kind url ~priority:(Some repo.repo_priority)) else (* 1/ update the config file *) let config_f = OpamPath.Repository.config repo in let config = let config = OpamFile.Repo_config.read config_f in { config with repo_address = url } in OpamFile.Repo_config.write config_f config let list ~short = log "repository-list"; let t = OpamState.load_state "repository-list" in if short then List.iter (fun r -> OpamGlobals.msg "%s\n" (OpamRepositoryName.to_string r.repo_name)) (OpamState.sorted_repositories t) else let pretty_print r = OpamGlobals.msg "%4d %-7s %10s %s\n" r.repo_priority (Printf.sprintf "[%s]" (string_of_repository_kind r.repo_kind)) (OpamRepositoryName.to_string r.repo_name) (string_of_address r.repo_address) in let repos = OpamState.sorted_repositories t in List.iter pretty_print repos opam-full-1.2.2/src/client/opamMain.ml0000644000175000017500000000261612517374212016277 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamArg let () = OpamMisc.at_exit (fun () -> flush stderr; flush stdout; if !OpamGlobals.print_stats then ( OpamFile.print_stats (); OpamSystem.print_stats (); ); OpamJson.output () ); run default commands opam-full-1.2.2/src/client/client.ocp0000644000175000017500000000073512517374212016165 0ustar useruserbegin library "opam-client" files = [ "opamState.ml" "opamAction.ml" "opamSolution.ml" "opamSwitchCommand.ml" "opamConfigCommand.ml" "opamRepositoryCommand.ml" "opamPinCommand.ml" "opamClient.ml" ] requires = [ "opam-core" "opam-solver" "opam-repositories" "cmdliner" ] end begin program "opam" files = [ "opamGitVersion.ml" "opamArg.ml" "opamMain.ml" ] requires = [ "opam-client" ] end opam-full-1.2.2/src/client/opamSolution.ml0000644000175000017500000005606412517374212017235 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) let log fmt = OpamGlobals.log "SOLUTION" fmt open OpamTypes open OpamTypesBase open OpamState.Types open OpamProcess.Job.Op module PackageAction = OpamSolver.Action module PackageActionGraph = OpamSolver.ActionGraph let post_message ?(failed=false) state action = match action with | To_delete _ | To_recompile _ -> () | To_change (_,pkg) -> let opam = OpamState.opam state pkg in let messages = OpamFile.OPAM.post_messages opam in let local_variables = OpamVariable.Map.empty in let local_variables = OpamVariable.Map.add (OpamVariable.of_string "success") (Some (B (not failed))) local_variables in let local_variables = OpamVariable.Map.add (OpamVariable.of_string "failure") (Some (B failed)) local_variables in let messages = let filter_env = OpamState.filter_env ~opam ~local_variables state in OpamMisc.filter_map (fun (message,filter) -> if OpamFilter.opt_eval_to_bool filter_env filter then Some (OpamFilter.expand_string filter_env message) else None) messages in let mark = OpamGlobals.colorise (if failed then `red else `green) "=> " in if messages <> [] then ( OpamGlobals.header_msg "%s %s" (OpamPackage.to_string pkg) (if failed then "troubleshooting" else "installed successfully"); List.iter (fun msg -> OpamGlobals.formatted_msg ~indent:(OpamMisc.visual_length mark) "%s%s\n" mark msg) messages ) else if failed && OpamFile.OPAM.depexts opam <> None then ( OpamGlobals.header_msg "%s troobleshooting" (OpamPackage.to_string pkg); OpamGlobals.formatted_msg ~indent:(OpamMisc.visual_length mark) "%sThis package relies on external (system) dependencies that may \ be missing. `opam depext %s' may help you find the correct \ installation for your system.\n" mark (OpamPackage.to_string pkg) ) let check_solution state = function | No_solution -> OpamGlobals.msg "No solution found, exiting\n"; OpamGlobals.exit 3 | Error (success, failed, _remaining) -> List.iter (post_message state) success; List.iter (post_message ~failed:true state) failed; OpamGlobals.exit 4 | OK actions -> List.iter (post_message state) actions | Nothing_to_do -> () | Aborted -> OpamGlobals.exit 0 let sum stats = stats.s_install + stats.s_reinstall + stats.s_remove + stats.s_upgrade + stats.s_downgrade let eq_atom name version = name, Some (`Eq, version) let eq_atom_of_package nv = eq_atom (OpamPackage.name nv) (OpamPackage.version nv) let eq_atoms_of_packages set = List.rev_map eq_atom_of_package (OpamPackage.Set.elements set) let atom_of_package nv = OpamPackage.name nv, None let atoms_of_packages set = List.rev_map (fun n -> n, None) (OpamPackage.Name.Set.elements (OpamPackage.names_of_packages set)) let atom_of_name name = name, None let check_availability ?permissive t set atoms = let available = OpamPackage.to_map set in let check_atom (name, _ as atom) = let exists = try OpamPackage.Version.Set.exists (fun v -> OpamFormula.check atom (OpamPackage.create name v)) (OpamPackage.Name.Map.find name available) with Not_found -> false in if exists then None else if permissive = Some true then Some (OpamState.unknown_package t atom) else Some (OpamState.unavailable_reason t atom) in let errors = OpamMisc.filter_map check_atom atoms in if errors <> [] then (List.iter (OpamGlobals.error "%s") errors; OpamGlobals.exit 66) let sanitize_atom_list ?(permissive=false) t atoms = let packages = OpamPackage.to_map (OpamPackage.Set.union t.packages t.installed) in (* gets back the original capitalization of the package name *) let realname name = let lc_name name = String.lowercase (OpamPackage.Name.to_string name) in let m = OpamPackage.Name.Map.filter (fun p _ -> lc_name name = lc_name p) packages in match OpamPackage.Name.Map.keys m with [name] -> name | _ -> name in let atoms = List.rev_map (fun (name,cstr) -> realname name, cstr) atoms in if permissive then check_availability ~permissive t (OpamPackage.Set.union t.packages t.installed) atoms else check_availability t (OpamPackage.Set.union (Lazy.force t.available_packages) t.installed) atoms; atoms (* Pretty-print errors *) let display_error (n, error) = let f action nv = let disp = OpamGlobals.header_error "while %s %s" action (OpamPackage.to_string nv) in match error with | Sys.Break | OpamParallel.Aborted -> () | Failure s -> disp "%s" s | e -> disp "%s" (Printexc.to_string e) in match n with | To_change (Some o, nv) -> if OpamPackage.Version.compare (OpamPackage.version o) (OpamPackage.version nv) < 0 then f "upgrading to" nv else f "downgrading to" nv | To_change (None, nv) -> f "installing" nv | To_recompile nv -> f "recompiling" nv | To_delete nv -> f "removing" nv (* Prettify errors *) let string_of_errors errors = let actions = List.rev_map fst errors in let packages = List.rev_map action_contents actions in match packages with | [] -> assert false | [h] -> OpamPackage.to_string h | l -> OpamPackage.Set.to_string (OpamPackage.Set.of_list l) let new_variables e = let e = List.filter (fun (_,s,_) -> s="=") e in let e = List.rev_map (fun (v,_,_) -> v) e in OpamMisc.StringSet.of_list e let variable_warnings = ref false let print_variable_warnings t = let variables = ref [] in if not !variable_warnings then ( let warn w = let is_defined s = try let _ = OpamMisc.getenv s in true with Not_found -> false in if is_defined w then variables := w :: !variables in (* 1. Warn about OCAMLFIND variables if it is installed *) let ocamlfind_vars = [ "OCAMLFIND_DESTDIR"; "OCAMLFIND_CONF"; "OCAMLFIND_METADIR"; "OCAMLFIND_COMMANDS"; "OCAMLFIND_LDCONF"; ] in if OpamPackage.Set.exists ( fun nv -> OpamPackage.Name.to_string (OpamPackage.name nv) = "ocamlfind" ) t.installed then List.iter warn ocamlfind_vars; (* 2. Warn about variables possibly set by other compilers *) let new_variables comp = let comp_f = OpamPath.compiler_comp t.root comp in let env = OpamFile.Comp.env (OpamFile.Comp.safe_read comp_f) in new_variables env in let vars = ref OpamMisc.StringSet.empty in OpamSwitch.Map.iter (fun _ comp -> vars := OpamMisc.StringSet.union !vars (new_variables comp) ) t.aliases; vars := OpamMisc.StringSet.diff !vars (new_variables t.compiler); OpamMisc.StringSet.iter warn !vars; if !variables <> [] then ( OpamGlobals.msg "The following variables are set in your environment, it \ is advised to unset them for OPAM to work correctly.\n"; List.iter (OpamGlobals.msg " - %s\n") !variables; if not (OpamGlobals.confirm "Do you want to continue ?") then OpamGlobals.exit 1; ); variable_warnings := true; ) (* Transient state (not flushed to disk) *) type state = { mutable s_installed : package_set; mutable s_installed_roots: package_set; mutable s_reinstall : package_set; } let output_json_solution solution = let to_proceed = PackageActionGraph.Topological.fold (fun a to_proceed -> match a with | To_change(o,p) -> let json = match o with | None -> `O ["install", OpamPackage.to_json p] | Some o -> if OpamPackage.Version.compare (OpamPackage.version o) (OpamPackage.version p) < 0 then `O ["upgrade", `A [OpamPackage.to_json o; OpamPackage.to_json p]] else `O ["downgrade", `A [OpamPackage.to_json o; OpamPackage.to_json p]] in json :: to_proceed | To_recompile p -> let json = `O ["recompile", OpamPackage.to_json p] in json :: to_proceed | To_delete p -> let json = `O ["delete", OpamPackage.to_json p] in json :: to_proceed ) solution [] in OpamJson.add (`A to_proceed) let output_json_actions action_errors = let json_error = function | OpamSystem.Process_error {OpamProcess.r_code; r_duration; r_info; r_stdout; r_stderr} -> `O [ ("process-error", `O [ ("code", `String (string_of_int r_code)); ("duration", `Float r_duration); ("info", `O (List.map (fun (k,v) -> (k, `String v)) r_info)); ("stdout", `A (List.map (fun s -> `String s) r_stdout)); ("stderr", `A (List.map (fun s -> `String s) r_stderr)); ])] | OpamSystem.Internal_error s -> `O [ ("internal-error", `String s) ] | OpamGlobals.Package_error s -> `O [ ("package-error", `String s) ] | e -> `O [ ("exception", `String (Printexc.to_string e)) ] in let json_action (a, e) = `O [ ("package", `String (OpamPackage.to_string (action_contents a))); ("error" , json_error e) ] in List.iter (fun a -> let json = json_action a in OpamJson.add json ) action_errors (* Process the atomic actions in a graph in parallel, respecting graph order, and report to user *) let parallel_apply t action action_graph = log "parallel_apply"; (* We keep an imperative state up-to-date and flush it to disk as soon as an operation terminates *) let state = { s_installed = t.installed; s_installed_roots = t.installed_roots; s_reinstall = t.reinstall; } in let t_ref = ref t in let update_state () = let installed = state.s_installed in let installed_roots = state.s_installed_roots in let reinstall = state.s_reinstall in t_ref := OpamAction.update_metadata t ~installed ~installed_roots ~reinstall in let root_installs = let names = OpamPackage.names_of_packages t.installed_roots in match action with | Init -> OpamPackage.Name.Set.union names (OpamState.base_package_names t) | Install r | Import r | Switch r -> OpamPackage.Name.Set.union names r | Upgrade _ | Reinstall _ -> names | Depends | Remove -> OpamPackage.Name.Set.empty in let add_to_install nv = state.s_installed <- OpamPackage.Set.add nv state.s_installed; state.s_reinstall <- OpamPackage.Set.remove nv state.s_reinstall; if OpamPackage.Name.Set.mem (OpamPackage.name nv) root_installs then state.s_installed_roots <- OpamPackage.Set.add nv state.s_installed_roots; update_state (); if not !OpamGlobals.dryrun then OpamState.install_metadata !t_ref nv in let remove_from_install deleted = let rm = OpamPackage.Set.remove deleted in state.s_installed <- rm state.s_installed; state.s_installed_roots <- rm state.s_installed_roots; state.s_reinstall <- rm state.s_reinstall; update_state () in let cancelled_exn = Failure "cancelled" in (* 1/ fetch needed package archives *) let package_sources, failed_downloads = let sources_needed = OpamAction.sources_needed t action_graph in let sources_list = OpamPackage.Set.elements sources_needed in if sources_list <> [] then OpamGlobals.header_msg "Gathering sources"; let results = OpamParallel.map ~jobs:(OpamState.dl_jobs t) ~command:(OpamAction.download_package t) ~dry_run:!OpamGlobals.dryrun sources_list in List.fold_left2 (fun (sources,failed) nv -> function | `Successful None -> sources, failed | `Successful (Some dl) -> OpamPackage.Map.add nv dl sources, failed | _ -> sources, OpamPackage.Set.add nv failed) (OpamPackage.Map.empty,OpamPackage.Set.empty) sources_list results in let fatal_dl_error = PackageActionGraph.fold_vertex (fun a acc -> acc || match a with | To_delete _ -> false | _ -> OpamPackage.Set.mem (action_contents a) failed_downloads) action_graph false in if fatal_dl_error then OpamGlobals.error_and_exit "The sources of the following couldn't be obtained, aborting:\n%s\ (This may be fixed by running 'opam update')" (OpamMisc.itemize OpamPackage.to_string (OpamPackage.Set.elements failed_downloads)) else if not (OpamPackage.Set.is_empty failed_downloads) then OpamGlobals.warning "The sources of the following couldn't be obtained, they may be \ uncleanly uninstalled:\n%s" (OpamMisc.itemize OpamPackage.to_string (OpamPackage.Set.elements failed_downloads)); (* 2/ process the package actions (installations and removals) *) (* the child job to run on each action *) let job ~pred action = if not (List.for_all (fun (_,r) -> r = None) pred) then Done (Some cancelled_exn) else let t = !t_ref in let nv = action_contents action in let source = try Some (OpamPackage.Map.find nv package_sources) with Not_found -> None in match action with | To_change (_, nv) | To_recompile nv -> (OpamAction.build_and_install_package ~metadata:false t source nv @@+ function | None -> add_to_install nv; Done None | Some exn -> Done (Some exn)) | To_delete nv -> if OpamAction.removal_needs_download t nv then (try OpamAction.extract_package t source nv with e -> OpamMisc.fatal e); OpamProcess.Job.catch (fun e -> OpamMisc.fatal e; Done ()) (OpamAction.remove_package t ~metadata:false nv) @@| fun () -> remove_from_install nv; None in let action_results = OpamGlobals.header_msg "Processing actions"; try let results = PackageActionGraph.Parallel.map ~jobs:(OpamState.jobs t) ~command:job ~dry_run:!OpamGlobals.dryrun action_graph in let successful, failed = List.partition (fun (_,r) -> r = None) results in match failed with | [] -> `Successful () | _::_ -> let failed = List.map (function (act,Some e) -> act, e | _ -> assert false) failed in let cancelled, failed = List.partition (fun (_,e) -> e = cancelled_exn) failed in let act r = List.map fst r in List.iter display_error failed; output_json_actions failed; `Error (Error (act successful, act failed, act cancelled)) with | PackageActionGraph.Parallel.Errors (successful, errors, remaining) -> List.iter display_error errors; output_json_actions errors; `Error (Error (successful, List.map fst errors, remaining)) | e -> `Exception e in let t = !t_ref in (* 3/ Display errors and finalize *) let cleanup_artefacts graph = PackageActionGraph.iter_vertex (function | To_delete nv | To_change (Some nv, _) when not (OpamState.is_pinned t (OpamPackage.name nv)) -> OpamAction.cleanup_package_artefacts t nv (* no-op if reinstalled *) | _ -> ()) graph in match action_results with | `Successful () -> cleanup_artefacts action_graph; OpamGlobals.msg "Done.\n"; OK (PackageActionGraph.fold_vertex (fun a b -> a::b) action_graph []) | `Exception (OpamGlobals.Exit _ | Sys.Break as e) -> OpamGlobals.msg "Aborting.\n"; raise e | `Exception (OpamSolver.ActionGraph.Parallel.Cyclic cycles as e) -> OpamGlobals.error "Cycles found during dependency resolution:\n%s" (OpamMisc.itemize (OpamMisc.sconcat_map (OpamGlobals.colorise `yellow " -> ") OpamSolver.Action.to_string) cycles); raise e | `Exception (OpamSystem.Process_error _ | Unix.Unix_error _ as e) -> OpamGlobals.error "Actions cancelled because of a system error:"; OpamGlobals.errmsg "%s\n" (Printexc.to_string e); raise e | `Exception e -> OpamGlobals.error "Actions cancelled because of %s" (Printexc.to_string e); raise e | `Error err -> match err with | Aborted -> err | Error (successful, failed, remaining) -> let filter_graph g l = if l = [] then PackageActionGraph.create () else let g = PackageActionGraph.copy g in PackageActionGraph.iter_vertex (fun v -> if not (List.mem v l) then PackageActionGraph.remove_vertex g v) g; PackageActionGraph.reduce g in let successful = filter_graph action_graph successful in cleanup_artefacts successful; let failed = filter_graph action_graph failed in let print_actions filter header ?empty actions = let actions = PackageActionGraph.fold_vertex (fun v acc -> if filter v then v::acc else acc) actions [] in let actions = List.sort PackageAction.compare actions in if actions <> [] then OpamGlobals.msg "%s\n%s" header (OpamMisc.itemize ~bullet:" " (fun x -> x) (PackageAction.to_aligned_strings actions)) else match empty with | Some s -> OpamGlobals.msg "%s\n" s | None -> () in OpamGlobals.msg "\n"; OpamGlobals.header_msg "Error report"; print_actions (fun _ -> true) (Printf.sprintf "The following actions were %s" (OpamGlobals.colorise `yellow "aborted")) (filter_graph action_graph remaining); print_actions (fun _ -> true) (Printf.sprintf "The following actions %s" (OpamGlobals.colorise `red "failed")) failed; print_actions (function To_recompile _ -> false | _ -> true) "The following changes have been performed" ~empty:"No changes have been performed" successful; err | _ -> assert false let simulate_new_state state t = let installed = OpamSolver.ActionGraph.Topological.fold (fun action installed -> match action with | To_change(_,p) | To_recompile p -> OpamPackage.Set.add p installed | To_delete p -> OpamPackage.Set.remove p installed ) t state.installed in { state with installed } let print_external_tags t solution = let packages = OpamSolver.new_packages solution in let external_tags = OpamMisc.StringSet.of_list !OpamGlobals.external_tags in let values = OpamPackage.Set.fold (fun nv accu -> let opam = OpamState.opam t nv in match OpamFile.OPAM.depexts opam with | None -> accu | Some alltags -> OpamMisc.StringSetMap.fold (fun tags values accu -> if OpamMisc.StringSet.( (* A \subseteq B <=> (A U B) / B = 0 *) is_empty (diff (union external_tags tags) external_tags) ) then OpamMisc.StringSet.union values accu else accu ) alltags accu ) packages OpamMisc.StringSet.empty in let values = OpamMisc.StringSet.elements values in if values <> [] then OpamGlobals.msg "%s\n" (String.concat " " values) (* Ask confirmation whenever the packages to modify are not exactly the packages in the user request *) let confirmation ?ask requested solution = !OpamGlobals.yes || match ask with | Some false -> true | Some true -> OpamGlobals.confirm "Do you want to continue ?" | None -> let open PackageActionGraph in let solution_packages = fold_vertex (fun v acc -> OpamPackage.Name.Set.add (OpamPackage.name (action_contents v)) acc) solution OpamPackage.Name.Set.empty in OpamPackage.Name.Set.equal requested solution_packages || OpamGlobals.confirm "Do you want to continue ?" (* Apply a solution *) let apply ?ask t action ~requested solution = log "apply"; if OpamSolver.solution_is_empty solution then (* The current state satisfies the request contraints *) Nothing_to_do else ( (* Otherwise, compute the actions to perform *) let stats = OpamSolver.stats solution in let show_solution = ask <> Some false && !OpamGlobals.external_tags = [] in let action_graph = OpamSolver.get_atomic_action_graph solution in if show_solution then ( OpamGlobals.msg "The following actions %s be %s:\n" (if !OpamGlobals.show then "would" else "will") (if !OpamGlobals.dryrun then "simulated" else if !OpamGlobals.fake then "faked" else "performed"); let new_state = simulate_new_state t action_graph in let messages p = let opam = OpamState.opam new_state p in let messages = OpamFile.OPAM.messages opam in OpamMisc.filter_map (fun (s,f) -> if OpamFilter.opt_eval_to_bool (OpamState.filter_env ~opam new_state) f then Some s else None ) messages in let rewrite nv = (* mark pinned packages with a star *) let n = OpamPackage.name nv in if OpamState.is_pinned t n && OpamState.pinned t n = nv then OpamPackage.create n (OpamPackage.Version.of_string (match OpamPackage.version_to_string nv with | "~unknown" -> "*" | v -> v ^ "*")) else nv in OpamSolver.print_solution ~messages ~rewrite ~requested solution; if sum stats >= 2 then OpamGlobals.msg "===== %s =====\n" (OpamSolver.string_of_stats stats); output_json_solution action_graph; ); if !OpamGlobals.external_tags <> [] then ( print_external_tags t solution; Aborted ) else if not !OpamGlobals.show && confirmation ?ask requested action_graph then ( print_variable_warnings t; parallel_apply t action action_graph ) else Aborted ) let resolve ?(verbose=true) t action ~orphans request = OpamSolver.resolve ~verbose (OpamState.universe t action) ~orphans request let resolve_and_apply ?ask t action ~requested ~orphans request = match resolve t action ~orphans request with | Conflicts cs -> log "conflict!"; OpamGlobals.msg "%s" (OpamCudf.string_of_conflict (OpamState.unavailable_reason t) cs); No_solution | Success solution -> apply ?ask t action ~requested solution opam-full-1.2.2/src/client/opamPinCommand.ml0000644000175000017500000003035412517374212017440 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamState.Types open OpamMisc.OP let log fmt = OpamGlobals.log "COMMAND" fmt let slog = OpamGlobals.slog let cleanup_dev_dirs t name = let packages = OpamPackage.packages_of_name t.packages name in OpamPackage.Set.iter (fun nv -> OpamFilename.rmdir (OpamPath.Switch.build t.root t.switch nv); OpamFilename.rmdir (OpamPath.Switch.dev_package t.root t.switch name); ) packages let edit t name = log "pin-edit %a" (slog OpamPackage.Name.to_string) name; let pin = try OpamPackage.Name.Map.find name t.pinned with Not_found -> OpamGlobals.error_and_exit "%s is not pinned." (OpamPackage.Name.to_string name) in let installed_nv = try Some (OpamState.find_installed_package_by_name t name) with Not_found -> None in let file = OpamPath.Switch.Overlay.opam t.root t.switch name in let temp_file = OpamPath.Switch.Overlay.tmp_opam t.root t.switch name in let orig_opam = try Some (OpamFile.OPAM.read file) with e -> OpamMisc.fatal e; None in let version,empty_opam = match orig_opam with | None -> None,true | Some opam -> Some (OpamFile.OPAM.version opam), try opam = OpamFile.OPAM.create (OpamPackage.create name (OpamFile.OPAM.version opam)) with OpamSystem.Internal_error _ -> true in if empty_opam && not (OpamFilename.exists temp_file) then OpamState.add_pinned_overlay ~template:true ?version t name; if not (OpamFilename.exists temp_file) then OpamFilename.copy ~src:file ~dst:temp_file; let rec edit () = try ignore @@ Sys.command (Printf.sprintf "%s %s" (Lazy.force OpamGlobals.editor) (OpamFilename.to_string temp_file)); let warnings,opam_opt = OpamFile.OPAM.validate_file temp_file in let opam = match opam_opt with | None -> OpamGlobals.msg "Invalid opam file:\n%s\n" (OpamFile.OPAM.warns_to_string warnings); failwith "Syntax errors" | Some opam -> opam in let namecheck = match OpamFile.OPAM.name_opt opam with | None -> OpamGlobals.error "Missing \"name: %S\" field." (OpamPackage.Name.to_string name); false | Some n when n <> name -> OpamGlobals.error "Bad \"name: %S\" field, package name is %s" (OpamPackage.Name.to_string n) (OpamPackage.Name.to_string name); false | _ -> true in let versioncheck = match pin, OpamFile.OPAM.version_opt opam with | _, None -> OpamGlobals.error "Missing \"version\" field."; false | Version vpin, Some v when v <> vpin -> OpamGlobals.error "Bad \"version: %S\" field, package is pinned to %s" (OpamPackage.Version.to_string v) (OpamPackage.Version.to_string vpin); false | _ -> true in if not namecheck || not versioncheck then failwith "Bad name/version"; match warnings with | [] -> Some opam | ws -> OpamGlobals.warning "The opam file didn't pass validation:\n%s\n" (OpamFile.OPAM.warns_to_string ws); if OpamGlobals.confirm "Continue anyway ('no' will reedit) ?" then Some opam else edit () with e -> OpamMisc.fatal e; if OpamGlobals.confirm "Errors in %s, retry editing ?" (OpamFilename.to_string file) then edit () else None in match edit () with | None -> if empty_opam then raise Not_found else None | Some new_opam -> OpamFilename.move ~src:temp_file ~dst:file; OpamGlobals.msg "You can edit this file again with \"opam pin edit %s\"\n" (OpamPackage.Name.to_string name); if Some new_opam = orig_opam then ( OpamGlobals.msg "Package metadata unchanged.\n"; None ) else let () = let dir = match pin with | Local dir -> Some dir | Git (a,None) | Darcs (a,None) | Hg (a,None) -> Some (OpamFilename.Dir.of_string a) | Version _ | Git _ | Darcs _ | Hg _ | Http _ -> None in match dir with | Some dir when OpamFilename.exists_dir dir -> let src_opam = OpamMisc.Option.default OpamFilename.OP.(dir // "opam") (OpamState.find_opam_file_in_source name dir) in if OpamGlobals.confirm "Save the new opam file back to %S ?" (OpamFilename.to_string src_opam) then OpamFilename.copy ~src:file ~dst:src_opam | _ -> () in match installed_nv with | None -> None | Some nv -> Some (OpamPackage.version nv = OpamFile.OPAM.version new_opam) let update_set set old cur save = if OpamPackage.Set.mem old set then save (OpamPackage.Set.add cur (OpamPackage.Set.remove old set)) let update_config t name pins = let pin_f = OpamPath.Switch.pinned t.root t.switch in cleanup_dev_dirs t name; OpamFile.Pinned.write pin_f pins let pin name ?version pin_option = log "pin %a to %a" (slog OpamPackage.Name.to_string) name (slog string_of_pin_option) pin_option; let t = OpamState.load_state "pin" in let pin_f = OpamPath.Switch.pinned t.root t.switch in let pin_kind = kind_of_pin_option pin_option in let pins = OpamFile.Pinned.safe_read pin_f in let installed_version = try Some (OpamPackage.version (OpamState.find_installed_package_by_name t name)) with Not_found -> None in let _check = match pin_option with | Version v -> if not (OpamPackage.Set.mem (OpamPackage.create name v) t.packages) then OpamGlobals.error_and_exit "Package %s has no version %s" (OpamPackage.Name.to_string name) (OpamPackage.Version.to_string v); if version <> None && version <> Some v then OpamGlobals.error_and_exit "Inconsistent version request for %s" (OpamPackage.Name.to_string name); | _ -> () in let no_changes = try let current = OpamPackage.Name.Map.find name pins in let no_changes = pin_option = current in if no_changes then OpamGlobals.note "Package %s is already %s-pinned to %s.\n\ This will erase any previous custom definition." (OpamPackage.Name.to_string name) (string_of_pin_kind (kind_of_pin_option current)) (string_of_pin_option current) else OpamGlobals.note "%s is currently %s-pinned to %s." (OpamPackage.Name.to_string name) (string_of_pin_kind (kind_of_pin_option current)) (string_of_pin_option current); if OpamGlobals.confirm "Proceed ?" then (OpamFilename.remove (OpamPath.Switch.Overlay.tmp_opam t.root t.switch name); no_changes) else OpamGlobals.exit 0 with Not_found -> if OpamPackage.Name.Set.mem name (OpamState.base_package_names t) then ( OpamGlobals.warning "Package %s is part of the base packages of this compiler." (OpamPackage.Name.to_string name); if not @@ OpamGlobals.confirm "Are you sure you want to override this and pin it anyway ?" then OpamGlobals.exit 0); false in let pins = OpamPackage.Name.Map.remove name pins in if OpamPackage.Set.is_empty (OpamState.find_packages_by_name t name) && not (OpamGlobals.confirm "Package %s does not exist, create as a %s package ?" (OpamPackage.Name.to_string name) (OpamGlobals.colorise `bold "NEW")) then (OpamGlobals.msg "Aborting.\n"; OpamGlobals.exit 0); log "Adding %a => %a" (slog string_of_pin_option) pin_option (slog OpamPackage.Name.to_string) name; let pinned = OpamPackage.Name.Map.add name pin_option pins in update_config t name pinned; let t = { t with pinned } in OpamState.add_pinned_overlay t ?version name; if not no_changes then OpamGlobals.msg "%s is now %a-pinned to %s\n" (OpamPackage.Name.to_string name) (OpamGlobals.acolor `bold) (string_of_pin_kind pin_kind) (string_of_pin_option pin_option); (match pin_option with | Git (dir, None) | Hg (dir, None) | Darcs (dir, None) when OpamFilename.exists_dir (OpamFilename.Dir.of_string dir) -> OpamGlobals.note "Pinning in mixed mode: OPAM will use tracked files in the current \ working tree from %s. If this is not what you want, pin to a given \ branch (e.g. %s#HEAD)" dir dir | _ -> ()); if not no_changes && installed_version <> None then let nv_v = OpamState.pinned t name in let pin_version = OpamPackage.version nv_v in if installed_version = Some pin_version then if pin_kind = `version then None else Some true else Some false else None let unpin ?state names = log "unpin %a" (slog @@ OpamMisc.sconcat_map " " OpamPackage.Name.to_string) names; let t = match state with | None -> OpamState.load_state "pin" | Some t -> t in let pin_f = OpamPath.Switch.pinned t.root t.switch in let pins, needs_reinstall = List.fold_left (fun (pins, needs_reinstall) name -> try let current = OpamPackage.Name.Map.find name pins in let is_installed = OpamState.is_name_installed t name in let pins = OpamPackage.Name.Map.remove name pins in let needs_reinstall = match current with | Version _ -> needs_reinstall | _ when is_installed -> name::needs_reinstall | _ -> needs_reinstall in if not is_installed then OpamState.remove_overlay t name; OpamGlobals.msg "%s is now %a from %s %s\n" (OpamPackage.Name.to_string name) (OpamGlobals.acolor `bold) "unpinned" (string_of_pin_kind (kind_of_pin_option current)) (string_of_pin_option current); pins, needs_reinstall with Not_found -> OpamGlobals.note "%s is not pinned." (OpamPackage.Name.to_string name); pins, needs_reinstall) (OpamFile.Pinned.safe_read pin_f, []) names in OpamFile.Pinned.write pin_f pins; List.iter (cleanup_dev_dirs t) names; needs_reinstall let list ~short () = log "pin_list"; let t = OpamState.load_state "pin-list" in let pins = OpamFile.Pinned.safe_read (OpamPath.Switch.pinned t.root t.switch) in if short then OpamPackage.Name.Map.iter (fun n _ -> OpamGlobals.msg "%s\n" (OpamPackage.Name.to_string n)) pins else let lines (n,a) = let kind = string_of_pin_kind (kind_of_pin_option a) in let state, extra = try let nv = OpamState.find_installed_package_by_name t n in match OpamState.pinned_opt t n with | None -> OpamGlobals.colorise `red " (invalid)",[] | Some nvp when nvp = nv -> "",[] | _ -> OpamGlobals.colorise `red " (not in sync)", [Printf.sprintf " (installed:%s)" (OpamPackage.version_to_string nv)] with Not_found -> OpamGlobals.colorise `yellow " (uninstalled)", [] in [ OpamPackage.to_string (OpamState.pinned t n); state; OpamGlobals.colorise `blue kind; string_of_pin_option a ] @ extra in let table = List.map lines (OpamPackage.Name.Map.bindings pins) in OpamMisc.print_table stdout ~sep:" " (OpamMisc.align_table table) opam-full-1.2.2/src/client/opamSolution.mli0000644000175000017500000000656612517374212017410 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Applying solver solutions *) open OpamTypes (** Resolve an user request *) val resolve: ?verbose:bool -> OpamState.state -> user_action -> orphans:package_set -> atom request -> (OpamSolver.solution, OpamCudf.conflict) result (** Apply a solution returned by the solver. If [ask] is not specified, prompts the user whenever the solution isn't obvious from the request *) val apply: ?ask:bool -> OpamState.state -> user_action -> requested:OpamPackage.Name.Set.t -> OpamSolver.solution -> solver_result (** Call the solver to get a solution and then call [apply]. If [ask] is not specified, prompts the user whenever the solution isn't obvious from the request *) val resolve_and_apply: ?ask:bool -> OpamState.state -> user_action -> requested:OpamPackage.Name.Set.t -> orphans:package_set -> atom request -> solver_result (** Raise an error if no solution is found or in case of error. *) val check_solution: OpamState.state -> solver_result -> unit (** {2 Atoms} *) (** Return an atom with a strict version constraint *) val eq_atom: name -> version -> atom (** Return a simple atom, with no version constrain, from a package*) val atom_of_package: package -> atom (** Returns an atom with a strict version constraint from a package *) val eq_atom_of_package: package -> atom (** Return a list of simple atoms (ie. with no version constraints) from a set of packages *) val atoms_of_packages: package_set -> atom list (** Return a list of constrained atoms from a set of packages *) val eq_atoms_of_packages: package_set -> atom list (** Checks that the atoms can possibly be verified (individually) in a package set. Displays an error and exits otherwise. [permissive] just changes the error message. *) val check_availability: ?permissive: bool -> OpamState.state -> OpamPackage.Set.t -> atom list -> unit (** Takes a "raw" list of atoms (from the user), and match it to existing packages. Match packages with the wrong capitalisation, and raises errors on non-existing packages, and unavailable ones unless [permissive] is set. Exits with a message on error. *) val sanitize_atom_list: ?permissive: bool -> OpamState.state -> atom list -> atom list (** {2 Stats} *) val sum: stats -> int opam-full-1.2.2/src/client/opamConfigCommand.mli0000644000175000017500000000411412517374212020263 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Configuration commands *) open OpamTypes (** Display the current environment. Booleans csh, sexp and fish set an alternative output (unspecified if more than one is true, sh-style by default). [inplace_path] changes how the PATH variable is updated when there is already an opam entry: either at the same rank, or pushed in front. *) val env: csh:bool -> sexp:bool -> fish:bool -> inplace_path:bool -> unit (** Display the content of all available variables *) val list: name list -> unit (** Display the content of a given variable *) val variable: full_variable -> unit (** Substitute files *) val subst: basename list -> unit (** Update the global and user configuration to use OPAM. *) val setup: user_config option -> global_config option -> unit (** Display the global and user configuration for OPAM. *) val setup_list: shell -> filename -> unit (** Execute a command in a subshell *) val exec: inplace_path:bool -> string list -> unit opam-full-1.2.2/src/client/opamRepositoryCommand.mli0000644000175000017500000000477512517374212021252 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Repository sub-command functions. *) open OpamState.Types open OpamTypes (** Update the given repository from its upstream. Returns a concurrency-safe state update function *) val update: t -> repository -> (OpamState.state -> OpamState.state) OpamProcess.job (** Update the package index. *) val update_package_index: t -> t (** Update the compiler index. *) val update_compiler_index: t -> t (** Update the given dev packages. *) val update_dev_packages: t -> verbose:bool -> package_set -> package_set (** Fix the compiler descriptions and display the changes if [verbose] is set. *) val fix_compiler_descriptions: t -> verbose:bool -> compiler_set updates (** Fix the the package descriptions and display the changes if [verbose] is set. *) val fix_package_descriptions: t -> verbose:bool -> package_set updates (** Fix all the package and compiler descriptions. *) val fix_descriptions: ?save_cache:bool -> ?verbose:bool -> t -> unit (** List the available repositories. *) val list: short:bool -> unit (** Add a new repository. *) val add: repository_name -> repository_kind -> address -> priority:int option -> unit (** Remove a repository. *) val remove: repository_name -> unit (** Set a repository priority. *) val priority: repository_name -> priority:int -> unit (** Change the registered address of a repo *) val set_url: repository_name -> address -> unit opam-full-1.2.2/src/client/opamSwitchCommand.mli0000644000175000017500000000476212517374212020330 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Switch commands. *) open OpamTypes (** Install a new switch. Returns a continuation that must be run to install the packages, but only needs a switch lock. *) val install_cont: quiet:bool -> warning:bool -> update_config:bool -> switch -> compiler -> switch * (unit -> unit) (** Like [install_cont] but runs the continuation already *) val install: quiet:bool -> warning:bool -> update_config:bool -> switch -> compiler -> unit (** Install a compiler's base packages *) val install_packages: switch -> compiler -> unit (** Import a file which contains the packages to install. *) val import: filename option -> unit (** Export a file which contains the installed packages. *) val export: filename option -> unit (** Remove the given compiler switch. *) val remove: switch -> unit (** Switch to the given compiler switch. Returns a continuation like [install] *) val switch_cont: ?compiler:compiler -> quiet:bool -> warning:bool -> switch -> switch * (unit -> unit) (** Like [switch_cont] but runs the continuation already. *) val switch: ?compiler:compiler -> quiet:bool -> warning:bool -> switch -> unit (** Reinstall the given compiler switch. *) val reinstall: switch -> unit (** Display the current compiler switch. *) val show: unit -> unit (** List all the available compiler switches. *) val list: print_short:bool -> installed:bool -> all:bool -> unit opam-full-1.2.2/src/client/opamArg.mli0000644000175000017500000001005312517374212016267 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** OPAM command-line arguments *) open OpamTypes open Cmdliner (** {2 Commands} *) (** Type of commands *) type command = unit Term.t * Term.info (** [run default commdands at_exit] build a binary which takes [commands] as subcommand and [default] as default argument (ie. which will be executed when no subcommand is given). [at_exit] is executed before the program exits. *) val run:command -> command list -> unit (** The default list of commands *) val commands: command list (** opam *) val default: command (** opam init *) val init: command (** opam list *) val list: command (** opam show *) val show: command (** opam search *) val search: command (** opam install *) val install: command (** opam remove *) val remove: command (** opam reinstall *) val reinstall: command (** opam update *) val update: command (** opam upgrade *) val upgrade: command (** opam config *) val config: command (** opam repository *) val repository: command (** opam switch *) val switch: command (** opam pin *) val pin: ?unpin_only:bool -> unit -> command (** opam help *) val help: command (** {2 Flags} *) (** --short *) val print_short_flag: bool Term.t (** --installed-root *) val installed_roots_flag: bool Term.t (** --shell *) val shell_opt: shell Term.t (** --dot-profile *) val dot_profile_flag: filename option Term.t (** --http/ --git/ --local *) val repo_kind_flag: repository_kind option Term.t (** --jobs *) val jobs_flag: int option Term.t (** --json *) val json_flag: string option Term.t (** patterns *) val pattern_list: string list Term.t (** package names *) val name_list: name list Term.t (** parameters *) val param_list: string list Term.t (** {3 Global options} *) (** Abstract type for global options *) type global_options (** Global options *) val global_options: global_options Term.t (** Apply global options *) val apply_global_options: global_options -> unit (** {3 Build options} *) (** Abstract type for build options *) type build_options (** Build options *) val build_options: build_options Term.t (** Applly build options *) val apply_build_options: build_options -> unit (** {3 Converters} *) (** Repository name converter *) val repository_name: repository_name Arg.converter (** Repository address converter *) val address: address Arg.converter (** Filename converter *) val filename: filename Arg.converter (** Dirnam converter *) val dirname: dirname Arg.converter (** Compiler converter *) val compiler: compiler Arg.converter (** Package name converter *) val package_name: name Arg.converter (** {2 Misc} *) (** Enumeration with a default command *) val enum_with_default: (string * ([> `default of string] as 'a)) list -> 'a Arg.converter (** Create an alias for an existing command. [options] can be used to add extra options after the original command in the doc. *) val make_command_alias: unit Term.t * Term.info -> ?options:string -> string -> unit Term.t * Term.info opam-full-1.2.2/src/client/opamGitVersion.mli0000644000175000017500000000223712517374212017654 0ustar useruser(**************************************************************************) (* *) (* Copyright 2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) val version: string option opam-full-1.2.2/src/client/opamSwitchCommand.ml0000644000175000017500000004534612517374212020162 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamState.Types open OpamPackage.Set.Op let log fmt = OpamGlobals.log "SWITCH" fmt let slog = OpamGlobals.slog (* name + state + compiler + description *) (* TODO: add repo *) let list ~print_short ~installed ~all = log "list"; let t = OpamState.load_state "switch-list" in let descr c = if c = OpamCompiler.system then let system_version = match Lazy.force OpamSystem.system_ocamlc_version with | None -> "" | Some v -> v in OpamFile.Descr.of_string (Printf.sprintf "System compiler (%s)" system_version) else OpamFile.Descr.safe_read (OpamPath.compiler_descr t.root c) in let installed_str = "I" in let current_str = "C" in let not_installed_str = "--" in let installed_s = OpamSwitch.Map.fold (fun name comp acc -> let s = if name = t.switch then current_str else installed_str in let n = OpamSwitch.to_string name in let c = OpamCompiler.to_string comp in let d = descr comp in (OpamCompiler.version comp, n, s, c, d) :: acc ) t.aliases [] in let descrs = OpamCompiler.Set.filter (fun comp -> OpamSwitch.Map.for_all (fun s c -> (* it is either not installed *) c <> comp (* or it is installed with an alias name. *) || OpamSwitch.to_string s <> OpamCompiler.to_string comp ) t.aliases ) t.compilers in let officials, patches = OpamCompiler.Set.fold (fun comp (officials, patches) -> try let c = OpamFile.Comp.read (OpamPath.compiler_comp t.root comp) in let version = OpamFile.Comp.version c in if OpamCompiler.Version.to_string version = OpamCompiler.to_string comp then comp :: officials, patches else officials, comp :: patches with OpamFormat.Bad_format _ -> officials, patches ) descrs ([],[]) in let mk l = List.fold_left (fun acc comp -> let c = OpamCompiler.to_string comp in let d = descr comp in (OpamCompiler.version comp, not_installed_str, not_installed_str, c, d) :: acc ) [] l in let to_show = if installed then installed_s else if all then mk officials @ installed_s @ mk patches else mk officials @ installed_s in let to_show = List.sort (fun (v1,_,_,_,_) (v2,_,_,_,_) -> OpamCompiler.Version.compare v1 v2) to_show in let max_name, max_state, max_compiler = List.fold_left (fun (n,s,c) (_,name, state, compiler, _) -> let n = max (String.length name) n in let s = max (String.length state) s in let c = max (String.length compiler) c in (n, s, c) ) (0,0,0) to_show in let print_compiler (_, name, state, compiler, descr) = if print_short then let name = if name = not_installed_str then compiler else name in OpamGlobals.msg "%s\n" name else let bold_current s = if name = OpamSwitch.to_string t.switch then OpamGlobals.colorise `bold s else s in let colored_name = bold_current name in let colored_state = if state = not_installed_str then state else bold_current (OpamGlobals.colorise `blue state) in let colored_compiler = bold_current (OpamGlobals.colorise `yellow compiler) in let colored_descr = bold_current (OpamFile.Descr.synopsis descr) in let colored_body = if !OpamGlobals.verbose then match OpamMisc.strip (OpamFile.Descr.body descr) with | "" -> "" | d -> "\n"^d^"\n" else "" in OpamGlobals.msg "%s %s %s %s%s\n" (OpamMisc.indent_left colored_name ~visual:name max_name) (OpamMisc.indent_right colored_state ~visual:state max_state) (OpamMisc.indent_left colored_compiler ~visual:compiler max_compiler) colored_descr colored_body in List.iter print_compiler to_show; if not installed && not all && not print_short && patches <> [] then OpamGlobals.msg "# %d more patched or experimental compilers, \ use '--all' to show\n" (List.length patches); if not print_short then match !OpamGlobals.switch with | `Env s -> let sys = OpamSwitch.to_string (OpamFile.Config.switch t.config) in if sys <> s && not print_short then (OpamGlobals.msg "\n"; OpamGlobals.note "Current switch is set locally through the OPAMSWITCH variable.\n\ The current global system switch is %s." (OpamGlobals.colorise `bold sys)) | `Not_set -> if not (OpamState.up_to_date_env t) then (OpamGlobals.msg "\n"; OpamGlobals.warning "The environment is not in sync with the current switch.\n\ You should run: %s" (OpamState.eval_string t)) | _ -> () let clear_switch ?(keep_debug=false) t switch = let aliases = OpamSwitch.Map.filter (fun a _ -> a <> switch) t.aliases in OpamFile.Aliases.write (OpamPath.aliases t.root) aliases; let comp_dir = OpamPath.Switch.root t.root switch in if keep_debug && (!OpamGlobals.keep_build_dir || !OpamGlobals.debug) then OpamGlobals.note "Keeping %s despite errors (debug mode), \ you may want to remove it by hand" (OpamFilename.Dir.to_string comp_dir) else try OpamFilename.rmdir comp_dir with OpamSystem.Internal_error _ -> () let remove_t switch ?(confirm = true) t = log "remove switch=%a" (slog OpamSwitch.to_string) switch; let comp_dir = OpamPath.Switch.root t.root switch in if not (OpamFilename.exists_dir comp_dir) then ( OpamGlobals.msg "The compiler switch %s does not exist.\n" (OpamSwitch.to_string switch); OpamGlobals.exit 1; ); if t.switch = switch then ( OpamGlobals.msg "Cannot remove %s as it is the current compiler.\n" (OpamSwitch.to_string switch); OpamGlobals.exit 1; ); if not confirm || OpamGlobals.confirm "Switch %s and all its packages will be wiped. Are you sure ?" (OpamSwitch.to_string switch) then clear_switch t switch let update_global_config t ~warning switch = let t = OpamState.update_switch_config t switch in if warning then OpamState.print_env_warning_at_switch {t with switch} let install_compiler ~quiet switch compiler = log "install %b %a %a" quiet (slog OpamSwitch.to_string) switch (slog OpamCompiler.to_string) compiler; (* Remember the current switch to be able to roll-back *) let t = OpamState.load_state "switch-install-with-packages-1" in (* install the new OCaml version *) try OpamState.install_compiler t ~quiet switch compiler with e -> (* OpamGlobals.error "%s" (Printexc.to_string e); *) clear_switch ~keep_debug:true t switch; OpamFile.Config.write (OpamPath.config t.root) t.config; raise e let install_packages switch compiler = (* install the compiler packages *) OpamGlobals.switch := `Command_line (OpamSwitch.to_string switch); let t = OpamState.load_state "switch-install-with-packages-2" in let comp = OpamFile.Comp.read (OpamPath.compiler_comp t.root compiler) in let to_install = OpamFormula.atoms (OpamFile.Comp.packages comp) in let roots = OpamPackage.Name.Set.of_list (List.map fst to_install) in let bad_packages = OpamMisc.filter_map (fun (n, c) -> if OpamState.is_name_installed t n then ( let nv = OpamState.find_installed_package_by_name t n in if c = Some (`Eq, OpamPackage.version nv) then None else Some (n, Some (OpamPackage.version nv)) ) else None ) to_install in let package_error = function | n, None -> OpamGlobals.error "%s is an invalid package" (OpamPackage.Name.to_string n) | n, Some v -> OpamGlobals.error "%s.%s is not available for the current compiler" (OpamPackage.Name.to_string n) (OpamPackage.Version.to_string v) in match bad_packages with | p::_ -> package_error p; OpamGlobals.exit 10 | [] -> let solution = OpamSolution.resolve t (Switch roots) ~orphans:OpamPackage.Set.empty { wish_install = []; wish_remove = []; wish_upgrade = to_install; criteria = `Default; } in let solution = match solution with | Success s -> s | _ -> OpamGlobals.error_and_exit "Could not resolve set of base packages" in (match OpamSolver.stats solution with | { s_install = _; s_reinstall = 0; s_upgrade = 0; s_downgrade=0; s_remove = 0 } -> () | _ -> OpamGlobals.error_and_exit "Inconsistent resolution of base package installs"); let to_install_pkgs = OpamSolver.new_packages solution in let to_install_names = OpamPackage.names_of_packages to_install_pkgs in if not (!OpamGlobals.no_base_packages) && not (OpamPackage.Name.Set.equal to_install_names roots) then OpamGlobals.error_and_exit "Inconsistent set of base compiler packages: \ %s needed but not included / %s extra" OpamPackage.Name.Set.(to_string (diff to_install_names roots)) OpamPackage.Name.Set.(to_string (diff roots to_install_names)); let result = OpamSolution.apply ~ask:false t (Switch roots) ~requested:roots solution in OpamSolution.check_solution t result let install_cont ~quiet ~warning ~update_config switch compiler = let t = OpamState.load_state "install" in let comp_dir = OpamPath.Switch.root t.root switch in if Sys.file_exists (OpamFilename.Dir.to_string comp_dir) then OpamGlobals.error_and_exit "%S already exists, please choose a different name" (OpamFilename.Dir.to_string comp_dir); let comp_f = OpamPath.compiler_comp t.root compiler in if not (OpamFilename.exists_dir comp_dir) && not (OpamFilename.exists comp_f) then OpamCompiler.unknown compiler; let already_installed = OpamState.is_switch_installed t switch in if already_installed then (let a = OpamSwitch.Map.find switch t.aliases in if a <> compiler then OpamGlobals.error_and_exit "The compiler switch %s is already installed as an alias for %s." (OpamSwitch.to_string switch) (OpamCompiler.to_string a)) else install_compiler ~quiet switch compiler; if update_config then update_global_config ~warning:false t switch; switch, fun () -> (try install_packages switch compiler with e -> clear_switch ~keep_debug:true t switch; OpamFile.Config.write (OpamPath.config t.root) t.config; raise e); if warning && update_config then OpamState.print_env_warning_at_switch {t with switch} let install ~quiet ~warning ~update_config switch compiler = (snd (install_cont ~quiet ~warning ~update_config switch compiler)) () let switch_cont ?compiler ~quiet ~warning switch = log "switch switch=%a" (slog OpamSwitch.to_string) switch; let t = OpamState.load_state "switch-1" in let switch, cont = if OpamState.is_switch_installed t switch then (update_global_config ~warning t switch; switch, fun () -> ()) else let compiler = match compiler with | None -> OpamCompiler.of_string (OpamSwitch.to_string switch) | Some c -> c in install_cont ~quiet ~warning ~update_config:true switch compiler in switch, cont let switch ?compiler ~quiet ~warning switch = (snd (switch_cont ?compiler ~quiet ~warning switch)) () (* Remove from [set] all the packages whose names appear in [filter]. *) let filter_names ~filter set = let names = OpamPackage.names_of_packages filter in OpamPackage.Set.filter (fun nv -> not (OpamPackage.Name.Set.mem (OpamPackage.name nv) names) ) set let import_t importfile t = log "import switch"; let imported, import_roots, import_pins = importfile in let pinned = OpamPackage.Name.Map.merge (fun _ current import -> match current, import with | _, (Some _ as p) -> p | p, None -> p) t.pinned import_pins in let pinned_version name = try Some (OpamPackage.version (OpamPackage.Set.choose_one (OpamPackage.packages_of_name imported name))) with Not_found | Invalid_argument _ -> None in (* Add the imported pins in case they don't exist already *) let available = OpamPackage.Set.fold (fun nv available -> if OpamPackage.Set.mem nv available then available else if OpamPackage.Name.Map.mem (OpamPackage.name nv) import_pins then OpamPackage.Set.add nv available else ( OpamGlobals.warning "%s Skipping." (OpamState.unavailable_reason t (OpamSolution.eq_atom (OpamPackage.name nv) (OpamPackage.version nv))); available ) ) imported (Lazy.force t.available_packages) in let imported = imported %% available in let import_roots = import_roots %% available in let pin_f = OpamPath.Switch.pinned t.root t.switch in let revert_pins () = if not (!OpamGlobals.dryrun || !OpamGlobals.show) then OpamFile.Pinned.write pin_f t.pinned in let t = {t with pinned; available_packages = lazy available; packages = t.packages ++ available } in let solution = try let _ = OpamPackage.Name.Map.iter (fun name _ -> let overlay_dir = OpamPath.Switch.Overlay.package t.root t.switch name in if not (OpamFilename.exists_dir overlay_dir) then OpamState.add_pinned_overlay t ?version:(pinned_version name) name) pinned; if not (OpamPackage.Name.Map.is_empty pinned) then ( OpamGlobals.header_msg "Synchronising pinned packages"; OpamState.update_pinned_packages t (OpamPackage.Name.Set.of_list (OpamPackage.Name.Map.keys pinned)) ) else OpamPackage.Set.empty in let t = if !OpamGlobals.dryrun || !OpamGlobals.show then t else (OpamFile.Pinned.write pin_f pinned; OpamState.load_state "pin-import") in let available = imported %% (Lazy.force t.available_packages ++ t.installed) in let to_import = OpamSolution.eq_atoms_of_packages available @ OpamSolution.atoms_of_packages (imported -- available) in let roots = OpamPackage.names_of_packages import_roots in OpamSolution.resolve_and_apply t (Import roots) ~requested:(OpamPackage.names_of_packages imported) ~orphans:OpamPackage.Set.empty { wish_install = to_import; wish_remove = []; wish_upgrade = []; criteria = `Default; } with e -> revert_pins (); raise e in (match solution with | No_solution | Aborted -> revert_pins () | Error _ | OK _ | Nothing_to_do -> ()); OpamSolution.check_solution t solution; OpamFile.Installed_roots.write (OpamPath.Switch.installed_roots t.root t.switch) OpamPackage.Set.Op.(t.installed_roots ++ import_roots) let export filename = let t = OpamState.load_state "switch-export" in let export = (t.installed, t.installed_roots, t.pinned) in match filename with | None -> OpamFile.Export.write_to_channel stdout export | Some f -> OpamFile.Export.write f export let show () = let t = OpamState.load_state "switch-show" in OpamGlobals.msg "%s\n" (OpamSwitch.to_string t.switch) let reinstall_t t = log "reinstall switch=%a" (slog OpamSwitch.to_string) t.switch; if not (OpamState.is_switch_installed t t.switch) then ( OpamGlobals.msg "The compiler switch %s does not exist.\n" (OpamSwitch.to_string t.switch); OpamGlobals.exit 1; ); let ocaml_version = t.compiler in let export = (t.installed, t.installed_roots, t.pinned) in (* Remove the directory (except the overlays, backups and lock) *) let switch_root = OpamPath.Switch.root t.root t.switch in let keep_dirs = [ OpamPath.Switch.Overlay.dir t.root t.switch; OpamPath.Switch.backup_dir t.root t.switch; ] in let keep_files = [ OpamPath.Switch.lock t.root t.switch; ] in List.iter (fun d -> if not (List.mem d keep_dirs) then OpamFilename.rmdir d) (OpamFilename.dirs switch_root); List.iter (fun f -> if not (List.mem f keep_files) then OpamFilename.remove f) (OpamFilename.files switch_root); OpamState.install_compiler t ~quiet:false t.switch ocaml_version; let t = OpamState.load_state "switch-reinstall-2" in import_t export t let with_backup command f = let t = OpamState.load_state command in let file = OpamPath.backup t.root in OpamFilename.mkdir (OpamPath.backup_dir t.root); OpamFile.Export.write file (t.installed, t.installed_roots, t.pinned); try f t; OpamFilename.remove file (* We might want to keep it even if successful ? *) with | OpamGlobals.Exit 0 as e -> raise e | err -> let t1 = OpamState.load_state "backup-err" in if OpamPackage.Set.equal t.installed t1.installed && OpamPackage.Set.equal t.installed_roots t1.installed_roots then OpamFilename.remove file else Printf.eprintf "The former package state can be restored with \ %s switch import %S%s\n" Sys.argv.(0) (OpamFilename.to_string file) (match !OpamGlobals.switch with | `Command_line sw -> Printf.sprintf " --switch %s" sw | _ -> ""); raise err let reinstall switch = OpamGlobals.switch := `Command_line (OpamSwitch.to_string switch); with_backup "switch-reinstall" reinstall_t let remove switch = with_backup "switch-remove" (remove_t switch) let import filename = with_backup "switch-import" (fun t -> let importfile = match filename with | None -> OpamFile.Export.read_from_channel stdin | Some f -> OpamFile.Export.read f in import_t importfile t) let () = OpamState.switch_reinstall_hook := reinstall opam-full-1.2.2/src/client/opamPinCommand.mli0000644000175000017500000000353612517374212017613 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Pin subcommand. *) open OpamTypes (** Pin a package. Returns [Some is_same_version] if the package should be reinstalled (or upgraded if [is_same_version] is false) *) val pin: name -> ?version:version -> pin_option -> bool option (** Let the user edit a pinned package's opam file. Returns [Some is_same_version] if the package should be rebuilt. raises [Not_found] if no valid opam file is available and the user didn't succeed in producing one. *) val edit: OpamState.state -> name -> bool option (** Unpin packages. Returns the list of packages that should be rebuilt *) val unpin: ?state:OpamState.state -> name list -> name list (** List the pinned packages. *) val list: short:bool -> unit -> unit opam-full-1.2.2/src/client/opamClient.mli0000644000175000017500000001431612517374212017002 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** Client entry-point. *) open OpamTypes (** OPAM API. *) module API: sig (** Initialize the client a consistent state. *) val init: repository -> compiler -> jobs:int -> shell -> filename -> [`ask|`yes|`no] -> unit (** Display all available packages that matches any of the regexps. *) val list: print_short:bool -> filter:[`all|`installed|`roots|`installable] -> order:[`normal|`depends] -> exact_name:bool -> case_sensitive:bool -> ?depends:(atom list) -> ?reverse_depends:bool -> ?recursive_depends:bool -> ?resolve_depends:bool -> ?depopts:bool -> ?depexts:string list -> string list -> unit (** Display a general summary of a collection of packages. *) val info: fields:string list -> raw_opam:bool -> where:bool -> atom list -> unit (** Install the given list of packages. Second argument, if not None, specifies that given packages should be added or removed from the roots. Third argument installs all dependencies but not the packages themselves *) val install: atom list -> bool option -> bool -> unit (** Reinstall the given set of packages. *) val reinstall: atom list -> unit (** Refresh the available packages. *) val update: repos_only:bool -> ?no_stats:bool -> string list -> unit (** Find a consistent state where most of the installed packages are upgraded to their latest version, within the given constraints. An empty list means upgrade all installed packages. *) val upgrade: atom list -> unit (** Recovers from an inconsistent universe *) val fixup: unit -> unit (** Remove the given list of packages. *) val remove: autoremove:bool -> force:bool -> atom list -> unit (** Config API. *) module CONFIG: sig (** Display environment. *) val env: csh:bool -> sexp:bool -> fish:bool -> inplace_path:bool -> unit (** Global and user setup of OPAM. *) val setup: user_config option -> global_config option -> unit (** Display global and user informations about OPAM setup. *) val setup_list: shell -> filename -> unit (** Execute a command in a subshell with the right environment variables. *) val exec: inplace_path:bool -> string list -> unit (** Display variables and their contents. *) val list: name list -> unit (** Display a given variable content. *) val variable: full_variable -> unit (** Substitute files. *) val subst: basename list -> unit end (** Repository API *) module REPOSITORY: sig (** Display the list of repositories. *) val list: short:bool -> unit (** Add a new repository. *) val add: repository_name -> repository_kind -> address -> priority:int option -> unit (** Remove a repository. *) val remove: repository_name -> unit (** Set-up repository priority. *) val priority: repository_name -> priority:int -> unit (** Set-up repository url. *) val set_url: repository_name -> address -> unit end (** Switch API *) module SWITCH: sig (** Set the given switch, installing it if necessary. Take the global file lock. *) val switch: ?compiler:compiler -> quiet:bool -> warning:bool -> switch -> unit (** Install the given compiler. *) val install: quiet:bool -> warning:bool -> update_config:bool -> switch -> compiler -> unit (** Import the packages from a file. If no filename is specified, read stdin. *) val import: filename option -> unit (** Export the packages to a file. If no filename is specified, write to stdout. *) val export: filename option -> unit (** Remove the given compiler. *) val remove: switch -> unit (** Reinstall the given compiler. *) val reinstall: switch -> unit (** List the available compiler descriptions. *) val list: print_short:bool -> installed:bool -> all:bool -> unit (** Display the name of the current compiler. *) val show: unit -> unit end (** Pin API *) module PIN: sig (** Set a package pinning. if [pin_option] is [None], set the package defined upstream. If [action], prompt for install/reinstall as appropriate after pinning. *) val pin: OpamPackage.Name.t -> ?edit:bool -> ?version:version -> ?action:bool -> pin_option option -> unit val edit: ?action:bool -> OpamPackage.Name.t -> unit val unpin: ?action:bool -> OpamPackage.Name.t list -> unit (** List the current pinned packages. *) val list: short:bool -> unit -> unit end end (** Call an unsafe function while taking the global lock. *) val global_lock: (unit -> unit) -> unit (** Call an unsafe function while taking the current switch lock. *) val switch_lock: (unit -> unit) -> unit (** Call an unsafe function while checking that no lock is already held. *) val read_lock: (unit -> unit) -> unit (** Loads state with [command], and calls [f] on it. The loaded state is backed up, and in case of error, a message is displayed on how to revert. *) val with_switch_backup: string -> (OpamState.state -> unit) -> unit (** This version of the API can be used concurrently. *) module SafeAPI: (module type of API) opam-full-1.2.2/src/client/opamState.mli0000644000175000017500000003423412517374212016645 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** OPAM client state *) open OpamTypes (** Client state *) module Types: sig type t = { (** Is the state partial ? TODO: split-up global vs. repository state *) partial: bool; (** The global OPAM root path *) root: OpamPath.t; (** The current active switch *) switch: switch; (** The current compiler name (corresponding to a .comp file) *) compiler: compiler; (** The current version of the compiler *) compiler_version: compiler_version lazy_t; (** The list of OPAM files (excluding the ones that exist purely as overlays) *) opams: OpamFile.OPAM.t package_map; (** The list of repositories *) repositories: OpamFile.Repo_config.t repository_name_map; (** The list of packages *) packages: package_set; (** The list of packages, keeping the one available for the current compiler version *) available_packages: package_set Lazy.t; (** The association list between switch and compiler *) aliases: OpamFile.Aliases.t; (** The list of compiler available to install *) compilers: compiler_set; (** The list of pinned packages *) pinned: OpamFile.Pinned.t; (** The list of installed packages *) installed: OpamFile.Installed.t; (** The list of packages explicitly installed by the user *) installed_roots: OpamFile.Installed_roots.t; (** The list of packages which needs to be reinsalled *) reinstall: OpamFile.Reinstall.t; (** The main configuration file *) config: OpamFile.Config.t; (** Package index *) package_index: OpamFile.Package_index.t; (** Compiler index *) compiler_index: OpamFile.Compiler_index.t; } end type state = Types.t (** Load the client state. The string argument is to identify to call site. *) val load_state: ?save_cache:bool -> string -> state val dump_state: state -> out_channel -> unit (** Rebuild the state cache. *) val rebuild_state_cache: unit -> unit (** Remove the state cache *) val remove_state_cache: unit -> unit (** Load state associated to env variables. All other fields are left empty. *) val load_env_state: string -> state (** Create a universe from the current state *) val universe: state -> user_action -> universe (** {2 Environment} *) (** Get the current environment with OPAM specific additions. If [force_path], the PATH is modified to ensure opam dirs are leading. *) val get_full_env: force_path:bool -> ?opam:OpamFile.OPAM.t -> state -> env (** Get only environment modified by OPAM. If [force_path], the PATH is modified to ensure opam dirs are leading. *) val get_opam_env: force_path:bool -> state -> env (** Update an environment. *) val add_to_env: state -> ?opam:OpamFile.OPAM.t -> env -> (string * string * string) list -> env (** Check if the shell environment is in sync with the current OPAM switch *) val up_to_date_env: state -> bool (** The shell command to run by the user to set his OPAM environement ([eval `opam config env`]) *) val eval_string: state -> string (** Print a warning if the environment is not set-up properly on init. *) val print_env_warning_at_init: state -> user_config -> unit (** Print a warning if the environment is not set-up properly on switch. *) val print_env_warning_at_switch: state -> unit (** {2 Initialisation} *) (** Update the global and user configuration by asking some questions. *) val update_setup_interactive: state -> shell -> filename -> bool (** Display the global and user configuration for OPAM. *) val display_setup: state -> shell -> filename -> unit (** Update the user configuration. *) val update_setup: state -> user_config option -> global_config option -> unit (** {2 Filters} *) (** Lists of available variables and their description *) val global_variable_names: (string * string) list val package_variable_names: (string * string) list (** Check for user-defined variable overwrite. *) val get_env_var: full_variable -> variable_contents option (** The main Filter.env value to be used to resolve variables in filters *) val filter_env: ?opam:OpamFile.OPAM.t -> ?local_variables:((variable_contents option) OpamVariable.Map.t) -> state -> full_variable -> variable_contents option (** {2 Helpers} *) (** Return the OPAM file for the given package *) val opam: state -> package -> OpamFile.OPAM.t (** Return the OPAM file for the given package *) val opam_opt: state -> package -> OpamFile.OPAM.t option (** Return the URL file for the given package *) val url: state -> package -> OpamFile.URL.t option (** Return the Descr file for the given package *) val descr: state -> package -> OpamFile.Descr.t (** Return the Descr file for the given package *) val descr_opt: state -> package -> OpamFile.Descr.t option (** Return the files/ directory overlay for the given package *) val files: state -> package -> dirname option (** Return the compiler description *) val compiler_comp: state -> compiler -> OpamFile.Comp.t (** {2 Repositories} *) (** Pretty print a map of repositories *) val string_of_repositories: OpamFile.Repo_config.t repository_name_map -> string (** Builds a map which says in which repository the latest metadata for a given package are. The function respect the bustom priorities given by the order of [priorities]. *) val package_index: state -> (repository_name * string option) package_map (** Build a map which says in which repository the latest metadata for a given compiler is. *) val compiler_index: state -> (repository_name * string option) compiler_map (** Sort repositories by priority. *) val sorted_repositories: state -> repository list (** Check whether a repository exists. *) val mem_repository: state -> repository_name -> bool (** Find a given repostiory. Exit the program if no such repository name exists. *) val find_repository: state -> repository_name -> repository (** Find a given repostiory. *) val find_repository_opt: state -> repository_name -> repository option (** Check the redirections. *) val redirect: state -> repository -> (repository * filter option) option (** {2 Compilers} *) (** (Re-)install the configuration for a given root and switch *) val install_global_config: dirname -> switch -> unit (** Install the given compiler *) val install_compiler: state -> quiet:bool -> switch -> compiler -> unit (** Write the right compiler switch in ~/.opam/config *) val update_switch_config: state -> switch -> state (** Is a compiler installed ? *) val is_compiler_installed: state -> compiler -> bool (** Is a switch installed ? *) val is_switch_installed: state -> switch -> bool (** Global compiler state *) val compiler_state: state -> checksums compiler_map (** Repository state *) val compiler_repository_state: state -> checksums compiler_map (** Return the active repository for a given compiler *) val repository_and_prefix_of_compiler: state -> compiler -> (repository * string option) option (** {2 Packages} *) (** Check whether a package name is installed *) val is_name_installed: state -> name -> bool (** Return whether a package is installed *) val is_package_installed: state -> package -> bool (** Return the installed package with the right name *) val find_installed_package_by_name: state -> name -> package (** Return all the packages with the given name *) val find_packages_by_name: state -> name -> package_set (** Return all packages satisfying one of the given atoms from a state *) val packages_of_atoms: state -> atom list -> package_set (** Return a map from package names to package installed version *) val installed_map: state -> version name_map (** A few historical package names used as base for compilers (base-xxx) *) val static_base_packages: name list (** Return the installed base packages of the current compiler *) val base_packages: state -> package_set (** Return the names of packages marked as "base" in the current compiler description *) val base_package_names: state -> name_set (** Return all the collection of installed packages, for all the available packages *) val all_installed: state -> package_set (** Return a map containing the switch where a given package is installed. *) val installed_versions: state -> name -> switch list package_map (** Returns a timestamp when the given package was last installed *) val installed_timestamp: state -> name -> float (** Returns a message about an atom that doesn't exist *) val unknown_package: state -> atom -> string (** Returns an explanation why a package is not currently available *) val unavailable_reason: state -> atom -> string (** Download the OPAM-package archive ($name.$version+opam.tar.gz) *) val download_archive: state -> package -> filename option OpamProcess.job (** Download the upstream archive, add the eventual additional files and return the directory. *) val download_upstream: state -> package -> dirname -> generic_file download option OpamProcess.job (** Global package state. *) val package_state: state -> checksums package_map (** Global & partial package state. *) val package_partial_state: state -> package -> archive:bool -> bool * checksums (** Repository state *) val package_repository_state: state -> checksums package_map (** Repository & partial package state. *) val package_repository_partial_state: state -> package -> archive:bool -> bool * checksums (** Get the active repository for a given package *) val repository_of_package: state -> package -> repository option (** Get the active repository for a given package *) val repository_and_prefix_of_package: state -> package -> (repository * string option) option (** Add the given packages to the set of package to reinstall. If [all] is set, this is done for ALL the switches (useful when a package change upstream for instance). If not, only the reinstall state of the current switch is changed. *) val add_to_reinstall: state -> all:bool -> package_set -> unit (** Return the files for a given package *) val copy_files: state -> package -> dirname -> unit (** Copy the repository metadata into the global state. *) val install_metadata: state -> package -> unit (** Remove some metadata from the global state if they are not used anymore. *) val remove_metadata: state -> package_set -> unit (** {2 Development packages} *) (** Get all the development packages. This include the one locally pinned (for the current switch) and the global dev packages. *) val dev_packages: state -> package_set (** [update_dev_packages t] checks for upstream changes for packages first in the switch cache and then in the global cache. Return the packages whose contents have changed upstream. Side-effect: update the reinstall files. *) val update_dev_packages: state -> package_set -> package_set (** Updates a dev or pinned package from its upstream; returns true if changed, false otherwise *) val update_dev_package: state -> package -> bool OpamProcess.job (** A subset of update_dev_packages that only takes packages names and only works on pinned packages. Also updates reinstall files *) val update_pinned_packages: state -> name_set -> package_set (** Updates a dev pinned package from its upstream; returns true if changed, false otherwise *) val update_pinned_package: state -> ?fixed_version:version -> name -> bool OpamProcess.job (** Check whether a package is a development package *) val is_dev_package: state -> package -> bool (** Looks up an 'opam' file for the given named package in a source directory *) val find_opam_file_in_source: name -> dirname -> filename option (** {2 Configuration files} *) (** Return the .config file for the given package *) val dot_config: state -> name -> OpamFile.Dot_config.t (** {2 Locks} *) (** Apply a function while taking the right locks *) val check: lock -> unit (** {2 Pinned packages} *) (** Is the package name pinned ? *) val is_pinned: state -> name -> bool (** Is the package locally pinned ? (ie. not a version pinning) *) val is_locally_pinned: state -> name -> bool (** Returns the versionned pinned package. @raise Not_found if not pinned *) val pinned: state -> name -> package (** Returns the versionned pinned package, or [None] if not pinned *) val pinned_opt: state -> name -> package option (** The set of pinned packages in the state (warning: costly) *) val pinned_packages: state -> package_set (** Return the URL file associated with a locally pinned package. *) val url_of_locally_pinned_package: state -> name -> OpamFile.URL.t (** {2 Overlays} *) (** Add overlay files for a pinned package. If no definition is found use a minimal OPAM file unless [template] is set to [true]. *) val add_pinned_overlay: ?template:bool -> ?version:version -> state -> name -> unit (** Remove all overlay files *) val remove_overlay: state -> name -> unit (** {2 System compilers} *) (** Create {i $opam/compilers/system.com}. Takes the global root as argument. *) val create_system_compiler_description: dirname -> unit (** {2 Jobs} *) val jobs: state -> int (** {2 Download Jobs} *) val dl_jobs: state -> int (** / **) (** Switch reinstall hook. *) val switch_reinstall_hook: (switch -> unit) ref (** Update hook *) val fix_descriptions_hook: (?save_cache:bool -> ?verbose:bool -> state -> unit) ref opam-full-1.2.2/src/client/opamArg.ml0000644000175000017500000025144212517374212016127 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open Cmdliner (* Global options *) type global_options = { debug : bool; debug_level: int; verbose: int; quiet : bool; color : bool; switch : string option; yes : bool; strict : bool; root : dirname; no_base_packages: bool; git_version : bool; external_solver : string option; use_internal_solver : bool; cudf_file : string option; solver_preferences : string option; no_self_upgrade : bool; safe_mode : bool; } let self_upgrade_exe opamroot = OpamFilename.OP.(opamroot // "opam", opamroot // "opam.version") let switch_to_updated_self debug opamroot = let updated_self, updated_self_version = self_upgrade_exe opamroot in let updated_self_str = OpamFilename.to_string updated_self in let updated_self_version_str = OpamFilename.to_string updated_self_version in if updated_self_str <> Sys.executable_name && OpamFilename.exists updated_self && OpamFilename.is_exec updated_self && OpamFilename.exists updated_self_version then let no_version = OpamVersion.of_string "" in let update_version = try let s = OpamSystem.read updated_self_version_str in let s = let len = String.length s in if len > 0 && s.[len-1] = '\n' then String.sub s 0 (len-1) else s in OpamVersion.of_string s with e -> OpamMisc.fatal e; no_version in if update_version = no_version then OpamGlobals.error "%s exists but cannot be read, disabling self-upgrade." updated_self_version_str else if OpamVersion.compare update_version OpamVersion.current <= 0 then OpamGlobals.warning "Obsolete OPAM self-upgrade package v.%s found, \ not using it (current system version is %s)." (OpamVersion.to_string update_version) (OpamVersion.to_string OpamVersion.current) else ( if OpamVersion.git () <> None then OpamGlobals.warning "Using OPAM self-upgrade to %s while the system \ OPAM is a development version (%s)" (OpamVersion.to_string update_version) (OpamVersion.to_string (OpamVersion.full ())); (if debug || !OpamGlobals.debug then Printf.eprintf "!! %s found, switching to it !!\n%!" updated_self_str; let env = Array.append [|"OPAMNOSELFUPGRADE="^OpamGlobals.self_upgrade_bootstrapping_value|] (Unix.environment ()) in try OpamMisc.exec_at_exit (); Unix.execve updated_self_str Sys.argv env with e -> OpamMisc.fatal e; OpamGlobals.error "Couldn't run the upgraded opam %s found at %s. \ Continuing with %s from the system." (OpamVersion.to_string update_version) updated_self_str (OpamVersion.to_string OpamVersion.current))) let create_global_options git_version debug debug_level verbose quiet color switch yes strict root no_base_packages external_solver use_internal_solver cudf_file solver_preferences no_self_upgrade safe_mode = let debug, debug_level = match debug, debug_level with | _, Some lvl -> true, lvl | true, None -> true, 1 | false, None -> false, 0 in if not (no_self_upgrade) then switch_to_updated_self debug root; (* do this asap, don't waste time *) if not safe_mode && Unix.getuid () = 0 then OpamGlobals.warning "Running as root is not recommended"; let verbose = List.length verbose in { git_version; debug; debug_level; verbose; quiet; color; switch; yes; strict; root; no_base_packages; external_solver; use_internal_solver; cudf_file; solver_preferences; no_self_upgrade; safe_mode; } let apply_global_options o = if o.git_version then ( begin match OpamGitVersion.version with | None -> () | Some v -> OpamGlobals.msg "%s\n%!" v end; exit 0 ); OpamGlobals.debug := not o.safe_mode && !OpamGlobals.debug || o.debug; OpamGlobals.debug_level := max !OpamGlobals.debug_level o.debug_level; OpamMisc.debug := !OpamGlobals.debug; OpamGlobals.verbose := (not o.quiet) && (!OpamGlobals.verbose || o.verbose > 0); OpamGlobals.verbose_level := max !OpamGlobals.verbose_level o.verbose; OpamGlobals.color := o.color; begin match o.switch with | None -> () | Some s -> OpamGlobals.switch := `Command_line s end; OpamGlobals.root_dir := OpamFilename.Dir.to_string o.root; OpamGlobals.yes := !OpamGlobals.yes || o.yes; OpamGlobals.strict := !OpamGlobals.strict || o.strict; OpamGlobals.no_base_packages := !OpamGlobals.no_base_packages || o.no_base_packages; OpamGlobals.env_external_solver := OpamMisc.Option.Op.(o.external_solver ++ !OpamGlobals.env_external_solver); OpamGlobals.use_external_solver := !OpamGlobals.use_external_solver && not o.use_internal_solver && !OpamGlobals.env_external_solver <> Some ""; OpamGlobals.cudf_file := OpamMisc.Option.Op.(o.cudf_file ++ !OpamGlobals.cudf_file); OpamGlobals.no_self_upgrade := !OpamGlobals.no_self_upgrade || o.no_self_upgrade; OpamGlobals.safe_mode := o.safe_mode; match o.solver_preferences with | None -> () | Some prefs -> OpamGlobals.solver_preferences := [`Default,prefs; `Upgrade,prefs; `Fixup,prefs] (* Build options *) type build_options = { keep_build_dir: bool; make : string option; no_checksums : bool; req_checksums : bool; build_test : bool; build_doc : bool; show : bool; dryrun : bool; fake : bool; external_tags : string list; jobs : int option; json : string option; } let create_build_options keep_build_dir make no_checksums req_checksums build_test build_doc show dryrun external_tags fake jobs json = { keep_build_dir; make; no_checksums; req_checksums; build_test; build_doc; show; dryrun; external_tags; fake; jobs; json } let json_update = function | None -> () | Some f -> let write str = OpamFilename.write (OpamFilename.of_string f) str in OpamJson.set_output write let apply_build_options b = OpamGlobals.keep_build_dir := !OpamGlobals.keep_build_dir || b.keep_build_dir; OpamGlobals.no_checksums := !OpamGlobals.no_checksums || b.no_checksums; OpamGlobals.req_checksums := !OpamGlobals.req_checksums || b.req_checksums; OpamGlobals.build_test := !OpamGlobals.build_test || b.build_test; OpamGlobals.build_doc := !OpamGlobals.build_doc || b.build_doc; OpamGlobals.show := !OpamGlobals.show || b.show; OpamGlobals.dryrun := !OpamGlobals.dryrun || b.dryrun; OpamGlobals.external_tags := b.external_tags; OpamGlobals.fake := b.fake; json_update b.json; OpamGlobals.jobs := begin match b.jobs with | None -> !OpamGlobals.jobs | Some j -> Some j end; match b.make with | None -> () | Some s -> OpamGlobals.makecmd := (fun () -> s) let when_enum = [ "always", `Always; "never", `Never; "auto", `Auto ] (* Help sections common to all commands *) let global_option_section = "COMMON OPTIONS" let help_sections = [ `S global_option_section; `P "These options are common to all commands."; `S "ENVIRONMENT VARIABLES"; `P "OPAM makes use of the environment variables listed here. Boolean \ variables should be set to \"0\", \"no\" of \"false\" to disable, \ \"1\", \"yes\" or \"true\" to enable."; (* Alphabetical order *) `P "$(i,OPAMCOLOR), when set to $(i,always) or $(i,never), sets a default \ value for the --color option."; `P ("$(i,OPAMCRITERIA) specifies user $(i,preferences) for dependency solving.\ The default value is "^OpamGlobals.default_preferences `Default^". \ See also option --criteria"); `P "$(i,OPAMCURL) can be used to select a given 'curl' program. See \ $(i,OPAMFETCH) for more options."; `P "$(i,OPAMDEBUG) see options `--debug' and `--debug-level'."; `P "$(i,OPAMDOWNLOADJOBS) sets the maximum number of simultaneous downloads."; `P "$(i,OPAMEXTERNALSOLVER) see option `--solver'."; `P "$(i,OPAMFETCH) specifies how to download files: either `wget', `curl' or \ a custom command where variables $(b,%{url}%), $(b,%{out}%), \ $(b,%{retries}%), $(b,%{compress}%) and $(b,%{checksum}%) will \ be replaced. Overrides the \ 'download-command' value from the main config file."; `P "$(i,OPAMJOBS) sets the maximum number of parallel workers to run."; `P "$(i,OPAMLOCKRETRIES) sets the number of tries after which OPAM gives up \ acquiring its lock and fails. <= 0 means infinite wait."; `P "$(i,OPAMNO) answer no to any question asked."; `P "$(i,OPAMNOASPCUD) see option `--no-aspcud'."; `P "$(i,OPAMNOSELFUPGRADE) see option `--no-self-upgrade'."; `P "$(i,OPAMPINKINDAUTO) if set, version control systems are detected when \ pinning to a local path."; `P "$(i,OPAMREQUIRECHECKSUMS) see option `--require-checksums'."; `P "$(i,OPAMRETRY) sets the number of tries before failing downloads."; `P "$(i,OPAMROOT) see option `--root'. This is automatically set by \ `opam config env --root=DIR' when DIR is non-default or OPAMROOT is \ already defined."; `P "$(i,OPAMSAFE) see option `--safe'"; `P "$(i,OPAMSKIPVERSIONCHECKS) bypasses some version checks. Unsafe, for \ compatibility testing only."; `P "$(i,OPAMSOLVERTIMEOUT) change the time allowance of the internal solver."; `P ("$(i,OPAMSTATUSLINE) display a dynamic status line showing what's \ currently going on on the terminal. \ (one of "^Arg.doc_alts_enum when_enum^")"); `P "$(i,OPAMSWITCH) see option `--switch'. Automatically set by \ `opam config env --switch=SWITCH'."; `P ("$(i,OPAMUPGRADECRITERIA) specifies user $(i,preferences) for dependency \ solving when performing an upgrade. Overrides $(i,OPAMCRITERIA) in \ upgrades if both are set.\ The default value is "^OpamGlobals.default_preferences `Upgrade^ ". See also option --criteria"); `P "$(i,OPAMUSEINTERNALSOLVER) see option `--use-internal-solver'."; `P ("$(i,OPAMUTF8) use UTF8 characters in output \ (one of "^Arg.doc_alts_enum when_enum^ "). By default `auto', which is determined from the locale)."); `P "$(i,OPAMUTF8MSGS) use extended UTF8 characters (camels) in OPAM \ messages. Implies $(i,OPAMUTF8). This is set by default on OSX only."; `P "$(i,OPAMVAR_var) overrides the contents of the variable $(i,var) when \ substituting `%{var}%` strings in `opam` files."; `P "$(i,OPAMVAR_package_var) overrides the contents of the variable \ $(i,package:var) when substituting `%{package:var}%` strings in \ `opam` files."; `P "$(i,OPAMVERBOSE) see option `--verbose'."; `P "$(i,OPAMYES) see option `--yes'."; `S "FURTHER DOCUMENTATION"; `P (Printf.sprintf "See %s." OpamGlobals.default_repository_address); `S "AUTHORS"; `P "Thomas Gazagnaire "; `Noblank; `P "Anil Madhavapeddy "; `Noblank; `P "Fabrice Le Fessant "; `Noblank; `P "Frederic Tuong "; `Noblank; `P "Louis Gesbert "; `Noblank; `P "Vincent Bernardoff "; `Noblank; `P "Guillem Rieu "; `Noblank; `P "Roberto Di Cosmo "; `S "BUGS"; `P "Check bug reports at https://github.com/ocaml/opam/issues."; ] (* Converters *) let pr_str = Format.pp_print_string let repository_name = let parse str = `Ok (OpamRepositoryName.of_string str) in let print ppf name = pr_str ppf (OpamRepositoryName.to_string name) in parse, print let address = let parse str = `Ok (address_of_string str) in let print ppf address = pr_str ppf (string_of_address address) in parse, print let filename = let parse str = `Ok (OpamFilename.of_string str) in let print ppf filename = pr_str ppf (OpamFilename.to_string filename) in parse, print let dirname = let parse str = `Ok (OpamFilename.Dir.of_string str) in let print ppf dir = pr_str ppf (OpamFilename.prettify_dir dir) in parse, print let compiler = let parse str = `Ok (OpamCompiler.of_string str) in let print ppf comp = pr_str ppf (OpamCompiler.to_string comp) in parse, print let package_name = let parse str = try `Ok (OpamPackage.Name.of_string str) with Failure msg -> `Error msg in let print ppf pkg = pr_str ppf (OpamPackage.Name.to_string pkg) in parse, print (* name * version option *) let package = let parse str = let re = Re_str.regexp "\\([^>=<.!]+\\)\\(\\.\\(.+\\)\\)?" in try if not (Re_str.string_match re str 0) then failwith "bad_format"; let name = OpamPackage.Name.of_string (Re_str.matched_group 1 str) in let version_opt = try Some (OpamPackage.Version.of_string (Re_str.matched_group 3 str)) with Not_found -> None in `Ok (name, version_opt) with Failure _ -> `Error "bad package format" in let print ppf (name, version_opt) = match version_opt with | None -> pr_str ppf (OpamPackage.Name.to_string name) | Some v -> pr_str ppf (OpamPackage.Name.to_string name ^"."^ OpamPackage.Version.to_string v) in parse, print (* name * version constraint *) let atom = let parse str = let re = Re_str.regexp "\\([^>=<.!]+\\)\\(>=?\\|<=?\\|=\\|\\.\\|!=\\)\\(.*\\)" in try if not (Re_str.string_match re str 0) then failwith "no_version"; let sname = Re_str.matched_group 1 str in let sop = Re_str.matched_group 2 str in let sversion = Re_str.matched_group 3 str in let name = OpamPackage.Name.of_string sname in let sop = if sop = "." then "=" else sop in let op = OpamFormula.relop_of_string sop in (* may raise Invalid_argument *) let version = OpamPackage.Version.of_string sversion in `Ok (name, Some (op, version)) with Failure _ | Invalid_argument _ -> try `Ok (OpamPackage.Name.of_string str, None) with Failure msg -> `Error msg in let print ppf atom = pr_str ppf (OpamFormula.short_string_of_atom atom) in parse, print let enum_with_default sl: 'a Arg.converter = let parse, print = Arg.enum sl in let parse s = match parse s with | `Ok _ as x -> x | _ -> `Ok (`default s) in parse, print (* Helpers *) let mk_flag ?section flags doc = let doc = Arg.info ?docs:section ~doc flags in Arg.(value & flag & doc) let mk_opt ?section ?vopt flags value doc conv default = let doc = Arg.info ?docs:section ~docv:value ~doc flags in Arg.(value & opt ?vopt conv default & doc) let mk_tristate_opt ?section flags value doc auto default = let doc = Arg.info ?docs:section ~docv:value ~doc flags in let arg = Arg.(value & opt (enum when_enum) default & doc) in let to_bool = function | `Always -> true | `Never -> false | `Auto -> auto () in Term.(pure to_bool $ arg) let mk_subdoc ?(defaults=[]) commands = let bold s = Printf.sprintf "$(b,%s)" s in let it s = Printf.sprintf "$(i,%s)" s in `S "COMMANDS" :: (List.map (function | "", name -> `P (Printf.sprintf "Without argument, defaults to %s." (bold name)) | arg, default -> `I (it arg, Printf.sprintf "With a %s argument, defaults to %s %s." (it arg) (bold default) (it arg)) ) defaults) @ List.map (fun (cs,_,args,d) -> let cmds = OpamMisc.sconcat_map ", " bold cs ^ " " ^ OpamMisc.sconcat_map " " it args in `I (cmds, d) ) commands @ [`S "OPTIONS"] (* Ensures options get after commands *) let mk_subcommands_aux my_enum commands = let command = let doc = Arg.info ~docv:"COMMAND" [] in let commands = List.fold_left (fun acc (cs,f,_,_) -> List.map (fun c -> c,f) cs @ acc) [] commands in Arg.(value & pos 0 (some & my_enum commands) None & doc) in let params = let doc = Arg.info ~doc:"Optional parameters." [] in Arg.(value & pos_right 0 string [] & doc) in command, params let mk_subcommands commands = mk_subcommands_aux Arg.enum commands let mk_subcommands_with_default commands = mk_subcommands_aux enum_with_default commands let bad_subcommand command subcommands usersubcommand userparams = match usersubcommand with | None -> `Error (false, Printf.sprintf "Missing subcommand. Valid subcommands are %s." (OpamMisc.pretty_list (List.flatten (List.map (fun (a,_,_,_) -> a) subcommands)))) | Some (`default cmd) -> `Error (true, Printf.sprintf "Invalid %s subcommand %S" command cmd) | Some usersubcommand -> let exe = Filename.basename Sys.executable_name in match List.find_all (fun (_,cmd,_,_) -> cmd = usersubcommand) subcommands with | [name::_, _, args, _doc] -> let usage = Printf.sprintf "%s %s [OPTION]... %s %s" exe command name (String.concat " " args) in if List.length userparams < List.length args then `Error (false, Printf.sprintf "%s: Missing argument.\nUsage: %s\n" exe usage) else `Error (false, Printf.sprintf "%s: Too many arguments.\nUsage: %s\n" exe usage) | _ -> `Error (true, Printf.sprintf "Invalid %s subcommand" command) let term_info title ~doc ~man = let man = man @ help_sections in Term.info ~sdocs:global_option_section ~docs:"COMMANDS" ~doc ~man title let arg_list name doc conv = let doc = Arg.info ~docv:name ~doc [] in Arg.(value & pos_all conv [] & doc) let nonempty_arg_list name doc conv = let doc = Arg.info ~docv:name ~doc [] in Arg.(non_empty & pos_all conv [] & doc) (* Common flags *) let print_short_flag = mk_flag ["s";"short"] "Output raw lists of names, one per line, skipping any details." let installed_roots_flag = mk_flag ["installed-roots"] "Display only the installed roots." let shell_opt = let enum = [ "bash",`bash; "sh",`sh; "csh",`csh; "zsh",`zsh; "fish",`fish; ] in mk_opt ["shell"] "SHELL" (Printf.sprintf "Sets the configuration mode for OPAM environment appropriate for \ $(docv). One of %s." (Arg.doc_alts_enum enum)) (Arg.enum enum) (OpamMisc.guess_shell_compat ()) let dot_profile_flag = mk_opt ["dot-profile"] "FILENAME" "Name of the configuration file to update instead of \ $(i,~/.profile) or $(i,~/.zshrc) based on shell detection." (Arg.some filename) None let repo_kind_flag = let main_kinds = [ "http" , `http; "local", `local; "git" , `git; "darcs", `darcs; "hg" , `hg; ] in let aliases_kinds = [ "wget" , `http; "curl" , `http; "rsync", `local; ] in mk_opt ["k";"kind"] "KIND" (Printf.sprintf "Specify the kind of the repository to be used (%s)." (Arg.doc_alts_enum main_kinds)) Arg.(some (enum (main_kinds @ aliases_kinds))) None let jobs_flag = mk_opt ["j";"jobs"] "JOBS" "Set the maximal number of concurrent jobs to use. You can also set it using \ the $(b,\\$OPAMJOBS) environment variable." Arg.(some int) None let pattern_list = arg_list "PATTERNS" "List of package patterns." Arg.string let nonempty_pattern_list = nonempty_arg_list "PATTERNS" "List of package patterns." Arg.string let name_list = arg_list "PACKAGES" "List of package names." package_name let atom_list = arg_list "PACKAGES" "List of package names, with an optional version or constraint, \ e.g `pkg', `pkg.1.0' or `pkg>=0.5'." atom let nonempty_atom_list = nonempty_arg_list "PACKAGES" "List of package names, with an optional version or constraint, \ e.g `pkg', `pkg.1.0' or `pkg>=0.5'." atom let param_list = arg_list "PARAMS" "List of parameters." Arg.string (* Options common to all commands *) let global_options = let section = global_option_section in let git_version = mk_flag ~section ["git-version"] "Print the git version if it exists and exit." in let debug = mk_flag ~section ["debug"] "Print debug message to stderr. \ This is equivalent to setting $(b,\\$OPAMDEBUG) to \"true\"." in let debug_level = mk_opt ~section ["debug-level"] "LEVEL" "Like `--debug', but allows specifying the debug level (`--debug' \ sets it to 1). Equivalent to setting $(b,\\$OPAMDEBUG) to a positive \ integer." Arg.(some int) None in let verbose = Arg.(value & flag_all & info ~docs:section ["v";"verbose"] ~doc: "Be more verbose, show package sub-commands and their output. \ Repeat to see more. Repeating $(i,n) times is equivalent to \ setting $(b,\\$OPAMVERBOSE) to \"$(i,n)\".") in let quiet = mk_flag ~section ["q";"quiet"] "Be quiet when installing a new compiler." in let color = mk_tristate_opt ~section ["color"] "WHEN" (Printf.sprintf "Colorize the output. $(docv) must be %s." (Arg.doc_alts_enum when_enum)) (fun () -> Unix.isatty Unix.stdout) OpamGlobals.color_when in let switch = mk_opt ~section ["switch"] "SWITCH" "Use $(docv) as the current compiler switch. \ This is equivalent to setting $(b,\\$OPAMSWITCH) to $(i,SWITCH)." Arg.(some string) None in let yes = mk_flag ~section ["y";"yes"] "Disable interactive mode and answer yes \ to all questions that would otherwise be \ asked to the user. \ This is equivalent to setting $(b,\\$OPAMYES) to \"true\"." in let strict = mk_flag ~section ["strict"] "Fail whenever an error is found in a package definition \ or a configuration file. The default is to continue silently \ if possible." in let root = mk_opt ~section ["root"] "ROOT" "Use $(docv) as the current root path. \ This is equivalent to setting $(b,\\$OPAMROOT) to $(i,ROOT)." dirname (OpamFilename.Dir.of_string OpamGlobals.default_opam_dir) in let no_base_packages = mk_flag ~section ["no-base-packages"] "Do not install base packages (useful for testing purposes). \ This is equivalent to setting $(b,\\$OPAMNOBASEPACKAGES) to a non-empty \ string." in let use_internal_solver = mk_flag ~section ["no-aspcud"; "use-internal-solver"] "Force use of internal heuristics, even if an external solver is available." in let external_solver = mk_opt ~section ["solver"] "CMD" ("Specify the name of the external dependency $(i,solver). \ The default value is "^OpamGlobals.default_external_solver^ ". Either 'aspcud', 'packup' or a custom command that may contain \ the variables %{input}%, %{output}% and %{criteria}%") Arg.(some string) None in let solver_preferences = mk_opt ~section ["criteria"] "CRITERIA" ("Specify user $(i,preferences) for dependency solving for this run. \ Overrides both $(b,\\$OPAMCRITERIA) and $(b,\\$OPAMUPGRADECRITERIA). \ For details on the supported language, and the external solvers available, see \ $(i, http://opam.ocaml.org/doc/Specifying_Solver_Preferences.html). \ A general guide to using solver preferences can be found at \ $(i, http://www.dicosmo.org/Articles/usercriteria.pdf). \ The default value is "^OpamGlobals.default_preferences `Upgrade^ " for upgrades, and "^OpamGlobals.default_preferences `Default^" otherwise.") Arg.(some string) None in let cudf_file = mk_opt ~section ["cudf"] "FILENAME" "Debug option: Save the CUDF requests sent to the solver to \ $(docv)-.cudf." Arg.(some string) None in let no_self_upgrade = mk_flag ~section ["no-self-upgrade"] "OPAM will replace itself with a newer binary found \ at $(b,OPAMROOT/opam) if present. This disables this behaviour." in let safe_mode = mk_flag ~section ["safe"] "Make sure nothing will be automatically updated or rewritten. Useful \ for calling from completion scripts, for example. Will fail whenever \ such an operation is needed ; also avoids waiting for locks, skips \ interactive questions and overrides the OPAMDEBUG variable." in Term.(pure create_global_options $git_version $debug $debug_level $verbose $quiet $color $switch $yes $strict $root $no_base_packages $external_solver $use_internal_solver $cudf_file $solver_preferences $no_self_upgrade $safe_mode) let json_flag = mk_opt ["json"] "FILENAME" "Save the result output of an OPAM run in a computer-readable file" Arg.(some string) None (* Options common to all build commands *) let build_options = let keep_build_dir = mk_flag ["b";"keep-build-dir"] "Keep the build directory. \ This is equivalent to setting $(b,\\$OPAMKEEPBUILDDIR) to \"true\"." in let no_checksums = mk_flag ["no-checksums"] "Do not verify the checksum of downloaded archives.\ This is equivalent to setting $(b,\\$OPAMNOCHECKSUMS) to \"true\"." in let req_checksums = mk_flag ["require-checksums"] "Reject the installation of packages that don't provide a checksum for the upstream archives. \ This is equivalent to setting $(b,\\$OPAMREQUIRECHECKSUMS) to \"true\"." in let build_test = mk_flag ["t";"build-test"] "Build and $(b,run) the package unit-tests. \ This is equivalent to setting $(b,\\$OPAMBUILDTEST) to \"true\"." in let build_doc = mk_flag ["d";"build-doc"] "Build the package documentation. \ This is equivalent to setting $(b,\\$OPAMBUILDDOC) to \"true\"." in let make = mk_opt ["m";"make"] "MAKE" "Use $(docv) as the default 'make' command." Arg.(some string) None in let show = mk_flag ["show-actions"] "Call the solver and display the actions. Don't perform any changes." in let dryrun = mk_flag ["dry-run"] "Simulate the command, but don't actually perform any changes." in let external_tags = mk_opt ["e";"external"] "TAGS" "Display the external packages associated to the given tags. \ This is deprecated, use `opam list --external' instead" Arg.(list string) [] in let fake = mk_flag ["fake"] "This option registers the actions into the OPAM database, without \ actually performing them. \ WARNING: This option is dangerous and likely to break your OPAM \ environment. You probably want `--dry-run'. You've been warned." in Term.(pure create_build_options $keep_build_dir $make $no_checksums $req_checksums $build_test $build_doc $show $dryrun $external_tags $fake $jobs_flag $json_flag) let init_dot_profile shell dot_profile = match dot_profile with | Some n -> n | None -> OpamFilename.of_string (OpamMisc.guess_dot_profile shell) module Client = OpamClient.SafeAPI type command = unit Term.t * Term.info (* INIT *) let init_doc = "Initialize OPAM state." let init = let doc = init_doc in let man = [ `S "DESCRIPTION"; `P "The $(b,init) command creates a fresh client state. This initializes OPAM \ configuration in $(i,~/.opam) (or the given $(b,--root)) and configures \ the initial remote package repository."; `P "Once the fresh client has been created, OPAM will ask the user if he wants \ $(i,~/.profile) (or $(i,~/.zshrc), etc. depending on his shell) and $(i,~/.ocamlinit) \ to be updated. \ If $(b,--auto-setup) is used, OPAM will modify the configuration files automatically, \ without asking the user. If $(b,--no-setup) is used, OPAM will *NOT* modify \ anything outside of $(i,~/.opam)."; `P "Additional repositories can be added later by using the $(b,opam repository) command."; `P "The state of repositories can be synchronized by using $(b,opam update)."; `P "The user and global configuration files can be setup later by using $(b,opam config setup)."; ] in let jobs = mk_opt ["j";"jobs"] "JOBS" "Number of jobs to use when building packages." Arg.int OpamGlobals.default_jobs in let compiler = mk_opt ["compiler"] "VERSION" "Which compiler version to use." compiler OpamCompiler.system in let repo_name = let doc = Arg.info ~docv:"NAME" ~doc:"Name of the repository." [] in Arg.(value & pos ~rev:true 1 repository_name OpamRepositoryName.default & doc) in let repo_address = let doc = Arg.info ~docv:"ADDRESS" ~doc:"Address of the repository." [] in Arg.(value & pos ~rev:true 0 address OpamRepository.default_address & doc) in let no_setup = mk_flag ["n";"no-setup"] "Do not update the global and user configuration options to setup OPAM." in let auto_setup = mk_flag ["a";"auto-setup"] "Automatically setup all the global and user configuration options for OPAM." in let init global_options build_options repo_kind repo_name repo_address compiler jobs no_setup auto_setup shell dot_profile_o = (* Create the dir in current directory so that it can be made absolute *) OpamFilename.mkdir global_options.root; apply_global_options global_options; apply_build_options build_options; let repo_priority = 0 in let repo_address, repo_kind2 = parse_url repo_address in let repo_kind = OpamMisc.Option.default repo_kind2 repo_kind in let repository = { repo_root = OpamPath.Repository.create (OpamPath.root ()) repo_name; repo_name; repo_kind; repo_address; repo_priority } in let update_config = if no_setup then `no else if auto_setup then `yes else `ask in let dot_profile = init_dot_profile shell dot_profile_o in Client.init repository compiler ~jobs shell dot_profile update_config in Term.(pure init $global_options $build_options $repo_kind_flag $repo_name $repo_address $compiler $jobs $no_setup $auto_setup $shell_opt $dot_profile_flag), term_info "init" ~doc ~man (* LIST *) let list_doc = "Display the list of available packages." let list = let doc = list_doc in let man = [ `S "DESCRIPTION"; `P "This command displays the list of installed packages when called \ without argument, or the list of available packages matching the \ given pattern."; `P "Unless the $(b,--short) switch is used, the output format displays one \ package per line, and each line contains the name of the package, the \ installed version or -- if the package is not installed, and a short \ description. In color mode, root packages (eg. manually installed) are \ underlined."; `P "The full description can be obtained by doing $(b,opam show ). \ You can search through the package descriptions using the $(b,opam search) \ command." ] in let all = mk_flag ["a";"all"] "List all the packages which can be installed on the system. This is \ the default when a query argument is supplied." in let installed = mk_flag ["i";"installed"] "List installed packages only. This is the the default when no argument \ is supplied. With `--resolve', means \"compute a solution from the \ currently installed packages\" instead." in let unavailable = mk_flag ["A";"unavailable"] "List all packages, even those which can't be installed on the system" in let sort = mk_flag ["sort";"S"] "Sort the packages in dependency order." in let depends_on = let doc = "List only packages that depend on one of (comma-separated) $(docv)." in Arg.(value & opt (list atom) [] & info ~doc ~docv:"PACKAGES" ["depends-on"]) in let required_by = let doc = "List only the dependencies of (comma-separated) $(docv)." in Arg.(value & opt (list atom) [] & info ~doc ~docv:"PACKAGES" ["required-by"]) in let resolve = let doc = "Restrict to a solution to install (comma-separated) $(docv), $(i,i.e.) \ a consistent set of packages including those. This is subtly different \ from `--required-by --recursive`, which is more predictable and can't \ fail, but lists all dependencies independently without ensuring \ consistency. \ Without `--installed`, the answer is self-contained and independent of \ the current installation. With `--installed', it's computed from the \ set of currently installed packages. \ `--unavailable` further makes the solution independent from the \ currently pinned packages, architecture, and compiler version. \ The combination with `--depopts' is not supported." in Arg.(value & opt (list atom) [] & info ~doc ~docv:"PACKAGES" ["resolve"]) in let recursive = mk_flag ["recursive"] "With `--depends-on' and `--required-by', display all transitive \ dependencies rather than just direct dependencies." in let depopts = mk_flag ["depopts"] "Include optional dependencies in dependency requests." in let depexts = mk_opt ["e";"external"] "TAGS" ~vopt:(Some []) "Instead of displaying the packages, display their external dependencies \ that are associated with any subset of the given $(i,TAGS) (OS, \ distribution, etc.). \ Common tags include `debian', `x86', `osx', `homebrew', `source'... \ Without $(i,TAGS), display the tags and all associated external \ dependencies. \ Rather than using this directly, you should probably head for the \ `depext' plugin, that can infer your system's tags and handle \ the system installations. Run `opam depext'." Arg.(some & list string) None in let list global_options print_short all installed installed_roots unavailable sort depends_on required_by resolve recursive depopts depexts packages = apply_global_options global_options; let filter = match unavailable, all, installed, installed_roots with | true, false, false, false -> Some `all | false, true, false, false -> Some `installable | false, false, true, false -> Some `installed | false, false, _, true -> Some `roots | false, false, false, false -> if depends_on = [] && required_by = [] && resolve = [] && packages = [] then Some `installed else Some `installable | _ -> None in let order = if sort then `depends else `normal in match filter, (depends_on, required_by, resolve) with | Some filter, (depends, [], [] | [], depends, [] | [], [], depends) -> Client.list ~print_short ~filter ~order ~exact_name:true ~case_sensitive:false ~depends ~reverse_depends:(depends_on <> []) ~resolve_depends:(resolve <> []) ~recursive_depends:recursive ~depopts ?depexts packages; `Ok () | None, _ -> `Error (true, "Conflicting filters: only one of --all, --installed and \ --installed-roots may be given at a time") | _ -> (* That would be fairly doable with a change of interface if needed *) `Error (true, "Sorry, only one of --depends-on, --required-by and \ --resolve are allowed at a time") in Term.ret Term.(pure list $global_options $print_short_flag $all $installed $installed_roots_flag $unavailable $sort $depends_on $required_by $resolve $recursive $depopts $depexts $pattern_list), term_info "list" ~doc ~man (* SEARCH *) let search = let doc = "Search into the package list." in let man = [ `S "DESCRIPTION"; `P "This command displays the list of available packages that match one of \ the package patterns specified as arguments."; `P "Unless the $(b,--short) flag is used, the output format is the same as the \ $(b,opam list) command. It displays one package per line, and each line \ contains the name of the package, the installed version or -- if the package \ is not installed, and a short description."; `P "The full description can be obtained by doing $(b,opam show )."; ] in let installed = mk_flag ["i";"installed"] "Search among installed packages only." in let case_sensitive = mk_flag ["c";"case-sensitive"] "Force the search in case sensitive mode." in let search global_options print_short installed installed_roots case_sensitive pkgs = apply_global_options global_options; let filter = match installed, installed_roots with | _, true -> `roots | true, _ -> `installed | _ -> `all in let order = `normal in Client.list ~print_short ~filter ~order ~exact_name:false ~case_sensitive pkgs in Term.(pure search $global_options $print_short_flag $installed $installed_roots_flag $case_sensitive $pattern_list), term_info "search" ~doc ~man (* SHOW *) let show_doc = "Display information about specific packages." let show = let doc = show_doc in let man = [ `S "DESCRIPTION"; `P "This command displays the information block for the selected \ package(s)."; `P "The information block consists of the name of the package, \ the installed version if this package is installed in the currently \ selected compiler, the list of available (installable) versions, and a \ complete description."; `P "$(b,opam list) can be used to display the list of \ available packages as well as a short description for each."; ] in let fields = let doc = Arg.info ~docv:"FIELDS" ~doc:"Only display these fields. You can specify multiple fields by separating them with commas." ["f";"field"] in Arg.(value & opt (list string) [] & doc) in let raw = mk_flag ["raw"] "Print the raw opam file for this package" in let where = mk_flag ["where"] "Print the location of the opam file used for this package" in let pkg_info global_options fields raw where packages = apply_global_options global_options; Client.info ~fields ~raw_opam:raw ~where packages in Term.(pure pkg_info $global_options $fields $raw $where $nonempty_atom_list), term_info "show" ~doc ~man (* CONFIG *) let config_doc = "Display configuration options for packages." let config = let doc = config_doc in let commands = [ ["env"] , `env , [], "Return the environment variables PATH, MANPATH, OCAML_TOPLEVEL_PATH \ and CAML_LD_LIBRARY_PATH according to the currently selected \ compiler. The output of this command is meant to be evaluated by a \ shell, for example by doing $(b,eval `opam config env`)."; ["setup"] , `setup , [], "Configure global and user parameters for OPAM. Use $(b, opam config setup) \ to display more options. Use $(b,--list) to display the current configuration \ options. You can use this command to automatically update: (i) user-configuration \ files such as ~/.profile and ~/.ocamlinit; and (ii) global-configaration files \ controlling which shell scripts are loaded on startup, such as auto-completion. \ These configuration options can be updated using: $(b,opam config setup --global) \ to setup the global configuration files stored in $(b,~/.opam/opam-init/) and \ $(b,opam config setup --user) to setup the user ones. \ To modify both the global and user configuration, use $(b,opam config setup --all)."; ["exec"] , `exec , ["[--] COMMAND"; "[ARG]..."], "Execute $(i,COMMAND) with the correct environment variables. \ This command can be used to cross-compile between switches using \ $(b,opam config exec --switch=SWITCH -- COMMAND ARG1 ... ARGn)"; ["var"] , `var , ["VAR"], "Return the value associated with variable $(i,VAR). Package variables can \ be accessed with the syntax $(i,pkg:var)."; ["list"] , `list , ["[PACKAGE]..."], "Without argument, prints a documented list of all available variables. With \ $(i,PACKAGE), lists all the variables available for these packages."; ["subst"] , `subst , ["FILE..."], "Substitute variables in the given files. The strings $(i,%{var}%) are \ replaced by the value of variable $(i,var) (see $(b,var))."; ["report"] , `report , [], "Prints a summary of your setup, useful for bug-reports."; ["cudf-universe"], `cudf, ["[FILE]"], "Outputs the current available package universe in CUDF format."; ["pef-universe"], `pef, ["[FILE]"], "Outputs the current available package universe in PEF format."; ] in let man = [ `S "DESCRIPTION"; `P "This command uses OPAM state to output information on how to use \ installed libraries, update the $(b,PATH), and substitute \ variables used in OPAM packages."; `P "Apart from $(b,opam config env), most of these commands are used \ by OPAM internally, and are of limited interest for the casual \ user."; ] @ mk_subdoc commands in let command, params = mk_subcommands commands in let all_doc = "Enable all the global and user configuration options." in let global_doc = "Enable all the global configuration options." in let user_doc = "Enable all the user configuration options." in let ocamlinit_doc = "Modify ~/.ocamlinit to make `#use \"topfind\"` works in the toplevel." in let profile_doc = "Modify ~/.profile (or ~/.zshrc, etc., depending on your shell) to \ setup an OPAM-friendly environment when starting a new shell." in let no_complete_doc = "Do not load the auto-completion scripts in the environment." in let no_eval_doc = "Do not install `opam-switch-eval` to switch & eval using a single command." in let dot_profile_doc = "Select which configuration file to update (default is ~/.profile)." in let list_doc = "List the current configuration." in let sexp_doc = "Display environment variables as an s-expression" in let inplace_path_doc= "When updating the PATH variable, replace any pre-existing OPAM path \ in-place rather than putting the new path in front. This means programs \ installed in OPAM that were shadowed will remain so after \ $(b,opam config env)" in let profile = mk_flag ["profile"] profile_doc in let ocamlinit = mk_flag ["ocamlinit"] ocamlinit_doc in let no_complete = mk_flag ["no-complete"] no_complete_doc in let no_switch_eval = mk_flag ["no-switch-eval"] no_eval_doc in let all = mk_flag ["a";"all"] all_doc in let user = mk_flag ["u";"user"] user_doc in let global = mk_flag ["g";"global"] global_doc in let list = mk_flag ["l";"list"] list_doc in let sexp = mk_flag ["sexp"] sexp_doc in let inplace_path = mk_flag ["inplace-path"] inplace_path_doc in let config global_options command shell sexp inplace_path dot_profile_o list all global user profile ocamlinit no_complete no_switch_eval params = apply_global_options global_options; match command, params with | Some `env, [] -> `Ok (Client.CONFIG.env ~csh:(shell=`csh) ~sexp ~fish:(shell=`fish) ~inplace_path) | Some `setup, [] -> let user = all || user in let global = all || global in let profile = user || profile in let ocamlinit = user || ocamlinit in let complete = global && not no_complete in let switch_eval = global && not no_switch_eval in let dot_profile = init_dot_profile shell dot_profile_o in if list then `Ok (Client.CONFIG.setup_list shell dot_profile) else if profile || ocamlinit || complete || switch_eval then let dot_profile = if profile then Some dot_profile else None in let user = if user then Some { shell; ocamlinit; dot_profile } else None in let global = if global then Some { complete; switch_eval } else None in `Ok (Client.CONFIG.setup user global) else `Ok (OpamGlobals.msg "usage: opam config setup [options]\n\ \n\ Main options\n\ \ -l, --list %s\n\ \ -a, --all %s\n\ \ --shell=\n\ \ Configure assuming the given shell.\n\ \n\ User configuration\n\ \ -u, --user %s\n\ \ --ocamlinit %s\n\ \ --profile %s\n\ \ --dot-profile FILE %s\n\ \n\ Global configuration\n\ \ -g,--global %s\n\ \ --no-complete %s\n\ \ --no-switch-eval %s\n\n" list_doc all_doc user_doc ocamlinit_doc profile_doc dot_profile_doc global_doc no_complete_doc no_eval_doc) | Some `exec, (_::_ as c) -> `Ok (Client.CONFIG.exec ~inplace_path c) | Some `list, params -> (try `Ok (Client.CONFIG.list (List.map OpamPackage.Name.of_string params)) with Failure msg -> `Error (false, msg)) | Some `var, [var] -> (try `Ok (Client.CONFIG.variable (OpamVariable.Full.of_string var)) with Failure msg -> `Error (false, msg)) | Some `subst, (_::_ as files) -> `Ok (Client.CONFIG.subst (List.map OpamFilename.Base.of_string files)) | Some `pef, params -> let opam_state = OpamState.load_state "config-universe" in let dump oc = OpamState.dump_state opam_state oc in (match params with | [] -> `Ok (dump stdout) | [file] -> let oc = open_out file in dump oc; close_out oc; `Ok () | _ -> bad_subcommand "config" commands command params) | Some `cudf, params -> let opam_state = OpamState.load_state "config-universe" in let opam_univ = OpamState.universe opam_state Depends in let dump oc = OpamSolver.dump_universe opam_univ oc in (match params with | [] -> `Ok (dump stdout) | [file] -> let oc = open_out file in dump oc; close_out oc; `Ok () | _ -> bad_subcommand "config" commands command params) | Some `report, [] -> ( let print label fmt = Printf.printf ("# %-15s "^^fmt^^"\n") label in Printf.printf "# OPAM config report\n"; print "opam-version" "%s " (OpamVersion.to_string (OpamVersion.full ())); print "self-upgrade" "%s" (if OpamGlobals.is_self_upgrade then OpamFilename.prettify (fst (self_upgrade_exe (OpamPath.root()))) else "no"); print "os" "%s" (OpamGlobals.os_string ()); try let state = OpamState.load_state "config-report" in print "external-solver" "%s" (if OpamCudf.external_solver_available () then String.concat " " (OpamGlobals.external_solver ~input:"$in" ~output:"$out" ~criteria:"$criteria") else "no"); print "criteria" "%s" (try List.assoc `Default !OpamGlobals.solver_preferences with Not_found -> try let cfg = OpamFile.Config.read (OpamPath.config (OpamPath.root())) in List.assoc `Default (OpamFile.Config.criteria cfg) with | e -> OpamMisc.fatal e; match OpamCudf.check_cudf_version () with | `Latest -> OpamGlobals.default_preferences `Default ^ "*" | `Compat -> OpamGlobals.compat_preferences `Default ^ "*"); let open OpamState.Types in let nprint label n = if n <> 0 then [Printf.sprintf "%d (%s)" n label] else [] in print "jobs" "%d" (OpamState.jobs state); print "repositories" "%s" OpamRepositoryName.Map.( let nhttp, nlocal, nvcs = fold (fun _ {repo_kind=k} (nhttp, nlocal, nvcs) -> match k with | `http -> nhttp+1, nlocal, nvcs | `local -> nhttp, nlocal+1, nvcs | _ -> nhttp, nlocal, nvcs+1) state.repositories (0,0,0) in let has_default = exists (fun _ {repo_address} -> repo_address = OpamRepository.default_address) state.repositories in String.concat ", " (Printf.sprintf "%d%s (http)" nhttp (if has_default then "*" else "") :: nprint "local" nlocal @ nprint "version-controlled" nvcs) ); print "pinned" "%s" OpamPackage.Name.Map.( if is_empty state.pinned then "0" else let nver, nlocal, nvc = fold (fun _ p (nver, nlocal, nvc) -> match p with | Version _ -> nver+1, nlocal, nvc | Local _ -> nver, nlocal+1, nvc | _ -> nver, nlocal, nvc+1) state.pinned (0,0,0) in String.concat ", " (nprint "version" nver @ nprint "path" nlocal @ nprint "version control" nvc) ); print "current-switch" "%s%s" (OpamSwitch.to_string state.switch) (if (OpamFile.Comp.preinstalled (OpamFile.Comp.read (OpamPath.compiler_comp state.root state.compiler))) then "*" else ""); let index_file = OpamFilename.to_string (OpamPath.package_index state.root) in let u = Unix.gmtime (Unix.stat index_file).Unix.st_mtime in Unix.(print "last-update" "%04d-%02d-%02d %02d:%02d" (1900 + u.tm_year) (1 + u.tm_mon) u.tm_mday u.tm_hour u.tm_min); `Ok () with e -> print "read-state" "%s" (Printexc.to_string e); `Ok ()) | command, params -> bad_subcommand "config" commands command params in Term.ret ( Term.(pure config $global_options $command $shell_opt $sexp $inplace_path $dot_profile_flag $list $all $global $user $profile $ocamlinit $no_complete $no_switch_eval $params) ), term_info "config" ~doc ~man (* INSTALL *) let install_doc = "Install a list of packages." let install = let doc = install_doc in let man = [ `S "DESCRIPTION"; `P "This command installs one or more packages to the currently selected \ compiler. To install packages for another compiler, you need to switch \ compilers using $(b,opam switch). You can remove installed packages with \ $(b,opam remove), and list installed packages with $(b,opam list -i). \ See $(b,opam pin) as well to understand how to manage package versions."; `P "This command makes OPAM use the dependency solver to compute the \ transitive closure of dependencies to be installed, and will also handle \ conflicts. If the dependency solver returns more than one \ solution, OPAM will arbitrarily select the first one. If dependencies \ are to be installed, OPAM will confirm if the installation should \ proceed."; ] in let add_to_roots = let root = Some true, Arg.info ["set-root"] ~doc:"Mark given packages as installed roots. This is the default \ for newly manually-installed packages." in let unroot = Some false, Arg.info ["unset-root"] ~doc:"Mark given packages as \"installed automatically\"." in Arg.(value & vflag None[root; unroot]) in let deps_only = Arg.(value & flag & info ["deps-only"] ~doc:"Install all its dependencies, but don't actually install the \ package.") in let install global_options build_options add_to_roots deps_only atoms = apply_global_options global_options; apply_build_options build_options; Client.install atoms add_to_roots deps_only in Term.(pure install $global_options $build_options $add_to_roots $deps_only $nonempty_atom_list), term_info "install" ~doc ~man (* REMOVE *) let remove_doc = "Remove a list of packages." let remove = let doc = remove_doc in let man = [ `S "DESCRIPTION"; `P "This command uninstalls one or more packages currently \ installed in the currently selected compiler switch. To remove packages \ installed in another compiler, you need to switch compilers using \ $(b,opam switch) or use the $(b,--switch) flag. This command is the \ inverse of $(b,opam-install)."; ] in let autoremove = mk_flag ["a";"auto-remove"] "Remove all the packages which have not been explicitly installed and \ which are not necessary anymore. It is possible to prevent the removal of an \ already-installed package by running $(b,opam install ). This flag \ can also be set using the $(b,\\$OPAMAUTOREMOVE) configuration variable." in let force = mk_flag ["force"] "Execute the remove commands of given packages directly, even if they are \ not considered installed by OPAM." in let remove global_options build_options autoremove force atoms = apply_global_options global_options; apply_build_options build_options; Client.remove ~autoremove ~force atoms in Term.(pure remove $global_options $build_options $autoremove $force $atom_list), term_info "remove" ~doc ~man (* REINSTALL *) let reinstall = let doc = "Reinstall a list of packages." in let man = [ `S "DESCRIPTION"; `P "This command removes the given packages and the ones \ that depend on them, and reinstalls the same versions." ] in let reinstall global_options build_options atoms = apply_global_options global_options; apply_build_options build_options; Client.reinstall atoms in Term.(pure reinstall $global_options $build_options $nonempty_atom_list), term_info "reinstall" ~doc ~man (* UPDATE *) let update_doc = "Update the list of available packages." let update = let doc = update_doc in let man = [ `S "DESCRIPTION"; `P "This command updates each repository that has been previously set up \ by the $(b,opam init) or $(b,opam repository) commands. The list of packages \ that can be upgraded will be printed out, and the user can use \ $(b,opam upgrade) to upgrade them."; ] in let repos_only = mk_flag ["R"; "repositories"] "Only update repositories, not development packages." in let sync = mk_flag ["sync-archives"] "Always sync the remote archives files. This is not \ a good idea to enable this, unless your really know \ what your are doing: this flag will make OPAM try to \ download the archive files for ALL the available \ packages." in let upgrade = mk_flag ["u";"upgrade"] "Automatically run $(b,opam upgrade) after the update." in let name_list = arg_list "NAMES" "List of repository or development package names." Arg.string in let update global_options jobs json names repos_only sync upgrade = apply_global_options global_options; json_update json; OpamGlobals.sync_archives := sync; OpamGlobals.jobs := jobs; Client.update ~repos_only ~no_stats:upgrade names; if upgrade then (OpamGlobals.msg "\n"; Client.upgrade []) in Term.(pure update $global_options $jobs_flag $json_flag $name_list $repos_only $sync $upgrade), term_info "update" ~doc ~man (* UPGRADE *) let upgrade_doc = "Upgrade the installed package to latest version." let upgrade = let doc = upgrade_doc in let man = [ `S "DESCRIPTION"; `P "This command upgrades the installed packages to their latest available \ versions. More precisely, this command calls the dependency solver to \ find a consistent state where $(i,most) of the installed packages are \ upgraded to their latest versions."; ] in let fixup = mk_flag ["fixup"] "Recover from a broken state (eg. missing dependencies, two conflicting \ packages installed together...). This requires that you have an \ external solver installed (aspcud, cudf-services.irill.org, ...)" in let upgrade global_options build_options fixup atoms = apply_global_options global_options; apply_build_options build_options; if fixup then if atoms <> [] then `Error (true, Printf.sprintf "--fixup doesn't allow extra arguments") else `Ok (Client.fixup ()) else `Ok (Client.upgrade atoms) in Term.(ret (pure upgrade $global_options $build_options $fixup $atom_list)), term_info "upgrade" ~doc ~man (* REPOSITORY *) let repository_doc = "Manage OPAM repositories." let repository = let doc = repository_doc in let commands = [ ["add"] , `add , ["NAME"; "ADDRESS"], "Add the repository at address $(i,ADDRESS) to the list of repositories \ used by OPAM, under $(i,NAME). It will have highest priority unless \ $(b,--priority) is specified."; ["remove"] , `remove , ["NAME"], "Remove the repository $(i,NAME) from the list of repositories used by OPAM."; ["list"] , `list , [], "List all repositories used by OPAM."; ["priority"] , `priority, ["NAME"; "PRIORITY"], "Change the priority of repository named $(i,NAME) to $(i,PRIORITY)."; ["set-url"] , `set_url, ["NAME"; "ADDRESS"], "Change the URL associated with $(i,NAME)"; ] in let man = [ `S "DESCRIPTION"; `P "This command is used to manage OPAM repositories. To synchronize OPAM \ with the last versions of the packages available in remote \ repositories, use $(b,opam update)."; ] @ mk_subdoc ~defaults:["","list"] commands in let command, params = mk_subcommands commands in let priority = mk_opt ["p";"priority"] "INT" "Set the repository priority (bigger is better)" Arg.(some int) None in let repository global_options command kind priority short params = apply_global_options global_options; match command, params with | Some `add, [name;address] -> let name = OpamRepositoryName.of_string name in let address = address_of_string address in let address, kind2 = parse_url address in let kind = OpamMisc.Option.default kind2 kind in `Ok (Client.REPOSITORY.add name kind address ~priority) | (None | Some `list), [] -> `Ok (Client.REPOSITORY.list ~short) | Some `priority, [name; p] -> let name = OpamRepositoryName.of_string name in let priority = try int_of_string p with Failure _ -> OpamGlobals.error_and_exit "%s is not an integer." p in `Ok (Client.REPOSITORY.priority name ~priority) | Some `set_url, [name; address] -> let name = OpamRepositoryName.of_string name in let url = address_of_string address in `Ok (Client.REPOSITORY.set_url name url) | Some `remove, [name] -> let name = OpamRepositoryName.of_string name in `Ok (Client.REPOSITORY.remove name) | command, params -> bad_subcommand "repository" commands command params in Term.ret Term.(pure repository $global_options $command $repo_kind_flag $priority $print_short_flag $params), term_info "repository" ~doc ~man (* SWITCH *) let switch_doc = "Manage multiple installation of compilers." let switch = let doc = switch_doc in let commands = [ ["install"] , `install , ["SWITCH"], "Install the given compiler. The command fails if the switch is \ already installed (e.g. it will not transparently switch to the \ installed compiler switch, as with $(b,set))."; ["set"] , `set , ["SWITCH"], "Set the currently active switch, installing it if needed."; ["remove"] , `remove , ["SWITCH"], "Remove the given compiler."; ["export"] , `export , ["FILE"], "Save the current switch state to a file."; ["import"] , `import , ["FILE"], "Import a saved switch state."; ["reinstall"] , `reinstall, ["SWITCH"], "Reinstall the given compiler switch. This will also reinstall all \ packages."; ["list"] , `list , [], "List compilers. \ By default, lists installed and `standard' compilers. Use `--all' to get \ the list of all installable compilers.\n\ The first column displays the switch name (if any), the second one \ the switch state (C = current, I = installed, -- = not installed), \ the third one the compiler name and the last one the compiler \ description. To switch to an already installed compiler alias (with \ state = I), use $(b,opam switch ). If you want to use a new \ compiler , use $(b,opam switch ): this will download, \ compile and create a fresh and independent environment where new \ packages can be installed. If you want to create a new compiler alias \ (for instance because you already have this compiler version installed), \ use $(b,opam switch --alias-of ). In case \ and are the same, this is equivalent to $(b,opam switch )."; ["show"] , `current , [], "Show the current compiler."; ] in let man = [ `S "DESCRIPTION"; `P "This command allows one to switch between different compiler versions, \ installing the compiler if $(b,opam switch) is used to switch to that \ compiler for the first time. The different compiler versions are \ totally independent from each other, meaning that OPAM maintains a \ separate state (e.g. list of installed packages...) for each."; `P "See the documentation of $(b,opam switch list) to see the compilers which \ are available, and how to switch or to install a new one." ] @ mk_subdoc ~defaults:["","list";"SWITCH","set"] commands in let command, params = mk_subcommands_with_default commands in let alias_of = mk_opt ["A";"alias-of"] "COMP" "The name of the compiler description which will be aliased." Arg.(some string) None in let no_warning = mk_flag ["no-warning"] "Do not display any warning related to environment variables." in let no_switch = mk_flag ["no-switch"] "Only install the compiler switch, without switching to it. If the compiler \ switch is already installed, then do nothing." in let installed = mk_flag ["i";"installed"] "List installed compiler switches only." in let all = mk_flag ["a";"all"] "List all the compilers which can be installed on the system." in let switch global_options build_options command alias_of print_short installed all no_warning no_switch params = apply_global_options global_options; apply_build_options build_options; let mk_comp alias = match alias_of with | None -> OpamCompiler.of_string alias | Some comp -> OpamCompiler.of_string comp in let warning = not no_warning in match command, params with | None , [] | Some `list, [] -> Client.SWITCH.list ~print_short ~installed ~all; `Ok () | Some `install, [switch] -> Client.SWITCH.install ~quiet:global_options.quiet ~warning ~update_config:(not no_switch) (OpamSwitch.of_string switch) (mk_comp switch); `Ok () | Some `export, [filename] -> Client.SWITCH.export (if filename = "-" then None else Some (OpamFilename.of_string filename)); `Ok () | Some `import, [filename] -> Client.SWITCH.import (if filename = "-" then None else Some (OpamFilename.of_string filename)); `Ok () | Some `remove, switches -> List.iter (fun switch -> Client.SWITCH.remove (OpamSwitch.of_string switch)) switches; `Ok () | Some `reinstall, [switch] -> Client.SWITCH.reinstall (OpamSwitch.of_string switch); `Ok () | Some `current, [] -> Client.SWITCH.show (); `Ok () | Some `set, [switch] | Some `default switch, [] -> Client.SWITCH.switch ?compiler:(if alias_of = None then None else Some (mk_comp switch)) ~quiet:global_options.quiet ~warning (OpamSwitch.of_string switch); `Ok () | command, params -> bad_subcommand "switch" commands command params in Term.(ret (pure switch $global_options $build_options $command $alias_of $print_short_flag $installed $all $no_warning $no_switch $params)), term_info "switch" ~doc ~man (* PIN *) let pin_doc = "Pin a given package to a specific version or source." let pin ?(unpin_only=false) () = let doc = pin_doc in let commands = [ ["list"] , `list, [], "Lists pinned packages."; ["add"] , `add , ["PACKAGE"; "TARGET"], "Pins package $(i,PACKAGE) to $(i,TARGET), which may be a version, a path, \ or a URL. \ $(i,PACKAGE) can be omitted if $(i,TARGET) is a local path containing a \ package description with a name. $(i,TARGET) can be replaced by \ `--dev-repo' if a package by that name is already known. \ OPAM will infer the kind of pinning from the format of $(i,TARGET), using \ $(b,path) pinning by default, unless you use an explicit $(b,--kind) \ option. \ Pins to version control systems may target a specific branch or commit \ using $(b,#branch) e.g. $(b,git://host/me/pkg#testing). When they don't, \ in the special case of version-controlled pinning to a local path, OPAM \ will use \"mixed mode\": it will only use version-controlled files, but \ at their current, on-disk version. \ If $(i,PACKAGE) is not a known package name, a new package by that name \ will be locally created. \ The package version may be specified by using the format \ $(i,NAME).$(i,VERSION) for $(PACKAGE), in the source opam file, or with \ $(b,edit)."; ["remove"] , `remove, ["NAMES"], "Unpins packages $(b,NAMES), restoring their definition from the \ repository, if any."; ["edit"] , `edit, ["NAME"], "Opens an editor giving you the opportunity to \ change the opam file that OPAM will locally use for pinned package \ $(b,NAME), including its version. \ To simply change the pinning target, use $(b,add). \ The chosen editor is determined from environment variables \ $(b,OPAM_EDITOR), $(b,VISUAL) or $(b,EDITOR), in order."; ] in let man = [ `S "DESCRIPTION"; `P "This command allows local customisation of the packages in a given \ switch. A package can be pinned to a specific upstream version, to \ a path containing its source, to a version-controlled location or to \ a URL. If a file `NAME.opam' with $(i,NAME) matching the package \ name, or just `opam', is found at the root of the pinned source, it \ will be used as the package's definition, overriding its previous \ definition if any. If a directory by one of these names is found, \ its contents will be used, also overriding other package metadata \ (`descr', extra `files' subdirectory...)" ] @ mk_subdoc ~defaults:["","list"] commands in let command, params = if unpin_only then Term.pure (Some `remove), Arg.(value & pos_all string [] & Arg.info []) else mk_subcommands commands in let edit = mk_flag ["e";"edit"] "With $(opam pin add), edit the opam file as with \ `opam pin edit' after pinning." in let kind = let main_kinds = [ "version", `version; "path" , `local; "http" , `http; "git" , `git; "darcs" , `darcs; "hg" , `hg; "auto" , `auto; ] in let help = Printf.sprintf "Sets the kind of pinning. Must be one of %s. \ If unset, is inferred from the format of the target, defaulting \ to $(i,path). If $(i,auto) or $(i,OPAMPINKINDAUTO) is set, a local \ path will be searched for version control and the pinning kind set \ accordingly. This is expected to become the default in a next version." (Arg.doc_alts_enum main_kinds) in let doc = Arg.info ~docv:"KIND" ~doc:help ["k";"kind"] in let kinds = main_kinds @ [ "local" , `local; "rsync" , `local; ] in Arg.(value & opt (some & enum kinds) None & doc) in let no_act = mk_flag ["n";"no-action"] "Just record the new pinning status, and don't prompt for \ (re)installation or removal of affected packages." in let dev_repo = mk_flag ["dev-repo"] "Pin to the upstream package source for the latest \ development version" in let guess_name path = let open OpamFilename.OP in if not (OpamFilename.exists_dir path) then raise Not_found else let opamf = path / "opam" // "opam" in let opamf = if OpamFilename.exists opamf then opamf else path // "opam" in if OpamFilename.exists opamf then try match OpamFile.OPAM.(name_opt (read opamf)) with | Some name -> name | None -> raise Not_found with e -> OpamMisc.fatal e; raise Not_found else match Array.fold_left (fun acc f -> if OpamMisc.ends_with ~suffix:".opam" f then if acc = None then Some (OpamMisc.remove_suffix ~suffix:".opam" f) else raise Not_found (* multiple .opam files *) else acc) None (Sys.readdir (OpamFilename.Dir.to_string path)) with | Some base -> OpamPackage.Name.of_string base | None -> raise Not_found in let pin global_options kind edit no_act dev_repo print_short command params = apply_global_options global_options; let action = not no_act in let kind, guess = match kind with | Some `auto -> None, true | Some (#pin_kind as k) -> Some k, false | None -> None, !OpamGlobals.pin_kind_auto in match command, params with | Some `list, [] | None, [] -> `Ok (Client.PIN.list ~short:print_short ()) | Some `remove, names -> let names,errs = List.fold_left (fun (names,errs) n -> match (fst package_name) n with | `Ok name -> name::names,errs | `Error e -> names,e::errs) ([],[]) names in (match errs with | [] -> `Ok (Client.PIN.unpin ~action names) | es -> `Error (false, String.concat "\n" es)) | Some `edit, [n] -> (match (fst package_name) n with | `Ok name -> `Ok (Client.PIN.edit ~action name) | `Error e -> `Error (false, e)) | Some `add, [nv] when dev_repo -> (match (fst package) nv with | `Ok (name,version) -> `Ok (Client.PIN.pin name ~edit ?version ~action None) | `Error e -> `Error (false, e)) | Some `add, [path] when not dev_repo -> (try let name = guess_name (OpamFilename.Dir.of_string path) in let pin_option = pin_option_of_string ?kind ~guess path in `Ok (Client.PIN.pin name ~edit ~action (Some pin_option)) with Not_found -> `Error (false, Printf.sprintf "No valid package description found at path %s.\n\ Please supply at least a package name \ (e.g. `opam pin add NAME PATH')" path)) | Some `add, [n; target] -> (match (fst package) n with | `Ok (name,version) -> let pin_option = pin_option_of_string ?kind ~guess target in `Ok (Client.PIN.pin name ?version ~edit ~action (Some pin_option)) | `Error e -> `Error (false, e)) | command, params -> bad_subcommand "pin" commands command params in Term.ret Term.(pure pin $global_options $kind $edit $no_act $dev_repo $print_short_flag $command $params), term_info "pin" ~doc ~man (* SOURCE *) let source_doc = "Get the source of an OPAM package." let source = let doc = source_doc in let man = [ `S "DESCRIPTION"; `P "Downloads the source for a given package to a local directory \ for development, bug fixing or documentation purposes." ] in let atom = Arg.(required & pos 0 (some atom) None & info ~docv:"PACKAGE" [] ~doc:"A package name with an optional version constraint") in let dev_repo = mk_flag ["dev-repo"] "Get the latest version-controlled source rather than the \ release archive" in let pin = mk_flag ["pin"] "Pin the package to the downloaded source (see `opam pin')." in let dir = mk_opt ["dir"] "DIR" "The directory where to put the source." Arg.(some dirname) None in let source global_options atom dev_repo pin dir = apply_global_options global_options; let open OpamState.Types in let t = OpamState.load_state "source" in let nv = try OpamPackage.Set.max_elt (OpamPackage.Set.filter (OpamFormula.check atom) t.packages) with Not_found -> OpamGlobals.error_and_exit "No package matching %s found." (OpamFormula.short_string_of_atom atom) in let dir = match dir with | Some d -> d | None -> let dirname = if dev_repo then OpamPackage.name_to_string nv else OpamPackage.to_string nv in OpamFilename.OP.(OpamFilename.cwd () / dirname) in let open OpamFilename in if exists_dir dir then OpamGlobals.error_and_exit "Directory %s already exists. Please remove it or use option `--dir'" (Dir.to_string dir); let opam = OpamState.opam t nv in if dev_repo then ( match OpamFile.OPAM.dev_repo opam with | None -> OpamGlobals.error_and_exit "Version-controlled repo for %s unknown \ (\"dev-repo\" field missing from metadata)" (OpamPackage.to_string nv) | Some pin -> let address = match pin with | Git p | Darcs p | Hg p -> p | _ -> OpamGlobals.error_and_exit "Bad \"dev_repo\" field %S for %s" (string_of_pin_option pin) (OpamPackage.to_string nv) in let kind = match repository_kind_of_pin_kind (kind_of_pin_option pin) with | Some k -> k | None -> assert false in mkdir dir; let text = OpamProcess.make_command_text (OpamPackage.name_to_string nv) (string_of_repository_kind kind) in match OpamProcess.Job.run (OpamProcess.Job.with_text text (OpamRepository.pull_url kind nv dir None [address])) with | Not_available u -> OpamGlobals.error_and_exit "%s is not available" u | Result _ | Up_to_date _ -> OpamGlobals.formatted_msg "Successfully fetched %s development repo to ./%s/\n" (OpamPackage.name_to_string nv) (OpamPackage.name_to_string nv) ) else ( OpamGlobals.formatted_msg "Downloading archive of %s...\n" (OpamPackage.to_string nv); match OpamProcess.Job.run (OpamAction.download_package t nv) with | `Error () -> OpamGlobals.error_and_exit "Download failed" | `Successful s -> (try OpamAction.extract_package t s nv with Failure _ -> ()); move_dir ~src:(OpamPath.Switch.build t.root t.switch nv) ~dst:dir; OpamGlobals.formatted_msg "Successfully extracted to %s\n" (Dir.to_string dir); if OpamState.find_opam_file_in_source (OpamPackage.name nv) dir = None then OpamFile.OPAM.write OP.(dir // "opam") (OpamFile.OPAM.with_substs (OpamFile.OPAM.with_patches opam []) []) ); if pin then let kind = if dev_repo then match OpamFile.OPAM.dev_repo opam with | Some pin -> kind_of_pin_option pin | None -> `local else `local in let pin_option = pin_option_of_string ~kind (OpamFilename.Dir.to_string dir) in Client.PIN.pin (OpamPackage.name nv) (Some pin_option) in Term.(pure source $global_options $atom $dev_repo $pin $dir), term_info "source" ~doc ~man (* LINT *) let lint_doc = "Checks and validate package description ('opam') files." let lint = let doc = lint_doc in let man = [ `S "DESCRIPTION"; `P "Given an $(i,opam) file, performs several quality checks on it and \ outputs recommendations, warnings or errors on stderr." ] in let file = Arg.(value & pos 0 file Filename.current_dir_name & info ~docv:"FILE" [] ~doc:"Name of the opam file to check, or directory \ containing it. Current directory if unspecified") in let normalise = mk_flag ["normalise"] "Output a normalised version of the opam file to stdout" in let short = mk_flag ["short";"s"] "Only print the warning/error numbers, space-separated, if any" in let lint global_options file normalise short = apply_global_options global_options; let opam_f = if Sys.is_directory file then OpamFilename.OP.(OpamFilename.Dir.of_string file // "opam") else OpamFilename.of_string file in if OpamFilename.exists opam_f then try let warnings,opam = OpamFile.OPAM.validate_file opam_f in let failed = List.exists (function _,`Error,_ -> true | _ -> false) warnings in if short then (if warnings <> [] then OpamGlobals.msg "%s\n" (OpamMisc.sconcat_map " " (fun (n,_,_) -> string_of_int n) warnings)) else if warnings = [] then OpamGlobals.msg "%s: %s\n" (OpamFilename.prettify opam_f) (OpamGlobals.colorise `green "Passed.") else OpamGlobals.msg "%s found in %s:\n%s\n" (if failed then "Errors" else "Warnings") (OpamFilename.prettify opam_f) (OpamFile.OPAM.warns_to_string warnings); if normalise then OpamMisc.Option.iter (OpamFile.OPAM.write_to_channel stdout) opam; if failed then OpamGlobals.exit 1 with | Parsing.Parse_error | Lexer_error _ | OpamFormat.Bad_format _ -> OpamGlobals.msg "File format error\n"; OpamGlobals.exit 1 else (OpamGlobals.error_and_exit "No opam file found at %s" (OpamFilename.to_string opam_f)) in Term.(pure lint $global_options $file $normalise $short), term_info "lint" ~doc ~man (* HELP *) let help = let doc = "Display help about OPAM and OPAM commands." in let man = [ `S "DESCRIPTION"; `P "Prints help about OPAM commands."; `P "Use `$(mname) help topics' to get the full list of help topics."; ] in let topic = let doc = Arg.info [] ~docv:"TOPIC" ~doc:"The topic to get help on." in Arg.(value & pos 0 (some string) None & doc ) in let help man_format cmds topic = match topic with | None -> `Help (`Pager, None) | Some topic -> let topics = "topics" :: cmds in let conv, _ = Cmdliner.Arg.enum (List.rev_map (fun s -> (s, s)) topics) in match conv topic with | `Error e -> `Error (false, e) | `Ok t when t = "topics" -> List.iter print_endline cmds; `Ok () | `Ok t -> `Help (man_format, Some t) in Term.(ret (pure help $Term.man_format $Term.choice_names $topic)), Term.info "help" ~doc ~man let default = let doc = "source-based OCaml package management" in let man = [ `S "DESCRIPTION"; `P "OPAM is a package manager for OCaml. It uses the powerful mancoosi \ tools to handle dependencies, including support for version \ constraints, optional dependencies, and conflict management."; `P "It has support for different remote repositories such as HTTP, rsync, git, \ darcs and mercurial. It handles multiple OCaml versions concurrently, and is \ flexible enough to allow you to use your own repositories and packages \ in addition to the central ones it provides."; `P "Use either $(b,opam --help) or $(b,opam help ) \ for more information on a specific command."; ] @ help_sections in let usage global_options = apply_global_options global_options; OpamGlobals.formatted_msg "usage: opam [--version]\n\ \ [--help]\n\ \ []\n\ \n\ The most commonly used opam commands are:\n\ \ init %s\n\ \ list %s\n\ \ show %s\n\ \ install %s\n\ \ remove %s\n\ \ update %s\n\ \ upgrade %s\n\ \ config %s\n\ \ repository %s\n\ \ switch %s\n\ \ pin %s\n\ \n\ See 'opam help ' for more information on a specific command.\n" init_doc list_doc show_doc install_doc remove_doc update_doc upgrade_doc config_doc repository_doc switch_doc pin_doc in Term.(pure usage $global_options), Term.info "opam" ~version:(OpamVersion.to_string OpamVersion.current) ~sdocs:global_option_section ~doc ~man let make_command_alias cmd ?(options="") name = let term, info = cmd in let orig = Term.name info in let doc = Printf.sprintf "An alias for $(b,%s%s)." orig options in let man = [ `S "DESCRIPTION"; `P (Printf.sprintf "$(b,$(mname) %s) is an alias for $(b,$(mname) %s%s)." name orig options); `P (Printf.sprintf "See $(b,$(mname) %s --help) for details." orig); ] in term, Term.info name ~docs:"COMMAND ALIASES" ~doc ~man let commands = [ init; list; search; show; make_command_alias show "info"; install; remove; make_command_alias remove "uninstall"; reinstall; update; upgrade; config; repository; make_command_alias repository "remote"; switch; pin (); make_command_alias (pin ~unpin_only:true ()) ~options:" remove" "unpin"; source; lint; help; ] (* Handle git-like plugins *) let check_and_run_external_commands () = match Array.to_list Sys.argv with | [] | [_] -> () | opam :: name :: args -> if not (OpamMisc.starts_with ~prefix:"-" name) && List.for_all (fun (_,info) -> Term.name info <> name) commands then (* No such command, check if there is a matching plugin *) let command = opam ^ "-" ^ name in let t = OpamState.load_env_state "plugins" in let env = OpamState.get_full_env ~force_path:false t in let env = Array.of_list (List.rev_map (fun (k,v) -> k^"="^v) env) in if OpamSystem.command_exists ~env command then let argv = Array.of_list (command :: args) in raise (OpamGlobals.Exec (command, argv, env)) else if OpamFilename.exists (OpamPath.config (OpamPath.root())) then (* Look for a corresponding package *) let t = OpamState.load_state "plugins-inst" in let open OpamState.Types in try let pkgname = OpamPackage.Name.of_string name in let candidates = Lazy.force t.available_packages in let nv = OpamPackage.max_version candidates pkgname in let opam = OpamPackage.Map.find nv t.opams in if OpamFile.OPAM.has_flag Pkgflag_Plugin opam && not (OpamState.is_name_installed t pkgname) && OpamGlobals.confirm "OPAM plugin %s is not installed. \ Install it on the current switch?" name then (Client.install [pkgname,None] None false; OpamGlobals.header_msg "Carrying on to \"%s\"" (String.concat " " (Array.to_list Sys.argv)); OpamGlobals.msg "\n"; let argv = Array.of_list (command :: args) in raise (OpamGlobals.Exec (command, argv, env))) with Not_found -> () let run default commands = OpamMisc.Option.iter OpamVersion.set_git OpamGitVersion.version; OpamGlobals.root_dir := OpamGlobals.default_opam_dir; Sys.catch_break true; let () = try Sys.set_signal Sys.sigpipe (Sys.Signal_handle (fun _ -> ())) with Invalid_argument _ -> () in try check_and_run_external_commands (); match Term.eval_choice ~catch:false default commands with | `Error _ -> exit 1 | _ -> exit 0 with | OpamGlobals.Exit 0 -> () | OpamGlobals.Exec (cmd,args,env) -> OpamMisc.exec_at_exit (); Unix.execvpe cmd args env | e -> flush stdout; flush stderr; if !OpamGlobals.verbose then Printf.eprintf "'%s' failed.\n" (String.concat " " (Array.to_list Sys.argv)); let exit_code = ref 1 in begin match e with | OpamGlobals.Exit i -> exit_code := i; if !OpamGlobals.debug && i <> 0 then Printf.eprintf "%s" (OpamMisc.pretty_backtrace e) | OpamSystem.Internal_error _ -> Printf.eprintf "%s" (Printexc.to_string e) | OpamSystem.Process_error result -> Printf.eprintf "%s Command %S failed:\n%s\n" (OpamGlobals.colorise `red "[ERROR]") (try List.assoc "command" result.OpamProcess.r_info with | Not_found -> "") (Printexc.to_string e); Printf.eprintf "%s" (OpamMisc.pretty_backtrace e); | Sys.Break | OpamParallel.Errors (_, (_, Sys.Break)::_, _) -> exit_code := 130 | Failure msg -> Printf.eprintf "Fatal error: %s\n" msg; Printf.eprintf "%s" (OpamMisc.pretty_backtrace e); | _ -> Printf.eprintf "Fatal error:\n%s\n" (Printexc.to_string e); Printf.eprintf "%s" (OpamMisc.pretty_backtrace e); end; exit !exit_code opam-full-1.2.2/src/client/opamClient.ml0000644000175000017500000022403312517374212016630 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamState.Types open OpamMisc.OP open OpamPackage.Set.Op open OpamFilename.OP let log fmt = OpamGlobals.log "CLIENT" fmt let slog = OpamGlobals.slog let s_not_installed = "--" type package_details = { name: name; current_version: version; installed_version: version option; synopsis: string Lazy.t; descr: string Lazy.t; tags: string list; syntax: string list Lazy.t; libraries: string list Lazy.t; others: string list Lazy.t; (* words in lines in files *) } let details_of_package t name versions = let installed_version = try Some (OpamPackage.version (OpamPackage.Set.find (fun nv -> OpamPackage.name nv = name) t.installed)) with Not_found -> None in let current_version = match installed_version with | Some v when OpamPackage.Version.Set.mem v versions -> v | _ -> OpamPackage.Version.Set.max_elt versions in let nv = OpamPackage.create name current_version in let descr_f = lazy ( OpamState.descr t nv ) in let synopsis = lazy ( OpamFile.Descr.synopsis (Lazy.force descr_f) ) in let descr = lazy ( OpamFile.Descr.full (Lazy.force descr_f) ) in let opam = OpamState.opam t nv in let tags = OpamFile.OPAM.tags opam in let syntax = lazy ( OpamMisc.filter_map (fun (s,filter) -> if OpamFilter.opt_eval_to_bool (OpamState.filter_env ~opam t) filter then Some s else None) (OpamFile.OPAM.syntax opam)) in let libraries = lazy ( OpamMisc.filter_map (fun (s,filter) -> if OpamFilter.opt_eval_to_bool (OpamState.filter_env ~opam t) filter then Some s else None) (OpamFile.OPAM.libraries opam)) in let others = lazy ( match OpamState.repository_and_prefix_of_package t nv with | None -> [] | Some (repo, prefix) -> List.fold_left (fun acc filename -> let file = OpamPath.Repository.packages repo prefix nv // filename in let file = OpamFile.Lines.safe_read file in List.flatten file @ acc ) [] !OpamGlobals.search_files ) in { name; current_version; installed_version; synopsis; descr; tags; syntax; libraries; others; } let details_of_package_regexps t packages ~exact_name ~case_sensitive regexps = log "names_of_regexp regexps=%a" (slog @@ OpamMisc.string_of_list (fun x -> x)) regexps; (* the regexp can also simply be a package. *) let fix_versions = let fix_packages = OpamMisc.filter_map OpamPackage.of_string_opt regexps in OpamPackage.to_map (packages %% (OpamPackage.Set.of_list fix_packages)) in let regexps = OpamMisc.filter_map (fun str -> let re = match OpamPackage.of_string_opt str with | Some nv -> if OpamPackage.Set.mem nv packages then let name = OpamPackage.Name.to_string (OpamPackage.name nv) in Re_glob.globx name else Re_glob.globx str | None -> Re_glob.globx str in let re = if case_sensitive then re else Re.no_case re in try Some (Re.compile re) with Re_glob.Parse_error -> OpamGlobals.error "%S is not a valid package descriptor." str; None ) regexps in let exact_match str = List.exists (fun re -> OpamMisc.exact_match re str) regexps in let partial_match str = List.exists (fun re -> Re.execp re str) regexps in let partial_matchs strs = List.exists partial_match strs in let packages_map = OpamPackage.to_map packages in let packages_map = OpamPackage.Name.Map.fold (fun name versions map -> let versions = try OpamPackage.Version.Set.inter versions (OpamPackage.Name.Map.find name fix_versions) with Not_found -> versions in if OpamPackage.Version.Set.is_empty versions then map else OpamPackage.Name.Map.add name (details_of_package t name versions) map ) packages_map OpamPackage.Name.Map.empty in (* Filter the list of packages, depending on user predicates *) let packages_map = OpamPackage.Name.Map.filter (fun name { synopsis; descr; tags; syntax; libraries; others } -> regexps = [] || exact_match (OpamPackage.Name.to_string name) || not exact_name && (partial_match (OpamPackage.Name.to_string name) || partial_match (Lazy.force synopsis) || partial_match (Lazy.force descr) || partial_matchs tags || partial_matchs (Lazy.force libraries) || partial_matchs (Lazy.force syntax) || partial_matchs (Lazy.force others)) ) packages_map in packages_map let with_switch_backup command f = let t = OpamState.load_state command in let file = OpamPath.Switch.backup t.root t.switch in OpamFilename.mkdir (OpamPath.Switch.backup_dir t.root t.switch); OpamFile.Export.write file (t.installed, t.installed_roots, t.pinned); try f t; OpamFilename.remove file (* We might want to keep it even if successful ? *) with | OpamGlobals.Exit 0 as e -> raise e | err -> OpamMisc.register_backtrace err; let t1 = OpamState.load_state "switch-backup-err" in if OpamPackage.Set.equal t.installed t1.installed && OpamPackage.Set.equal t.installed_roots t1.installed_roots then OpamFilename.remove file else (prerr_string (OpamMisc.reformat (Printf.sprintf "\nThe former state can be restored with:\n \ %s switch import %S\n%!" Sys.argv.(0) (OpamFilename.prettify file)))); raise err module API = struct (* Prints a list of package details in the 'opam list' format *) let print_list t ~uninst_versions ~short ~shortv ~order names = let get_version info = if uninst_versions then Some (info.current_version) else info.installed_version in let max_n, max_v = (* for alignment *) OpamPackage.Name.Map.fold (fun name info (max_n, max_v) -> let max_n = max max_n (String.length (OpamPackage.Name.to_string name)) in let v_str = match get_version info with | None -> s_not_installed | Some v -> OpamPackage.Version.to_string v in let max_v = max max_v (String.length v_str) in max_n, max_v ) names (0,0) in let names = OpamPackage.Name.Map.bindings names in let names = match order with | `normal -> names | `depends -> let universe = OpamState.universe t Depends in let packages_info = List.map (fun (name, info) -> (OpamPackage.create name info.current_version, info) ) names in let packages = let packages = OpamPackage.Set.of_list (List.map fst packages_info) in OpamSolver.dependencies ~depopts:true ~installed:false ~unavailable:true universe packages in List.fold_left (fun acc nv -> try (OpamPackage.name nv, List.assoc nv packages_info) :: acc with Not_found -> acc ) [] packages in let roots = OpamPackage.names_of_packages t.installed_roots in List.iter ( if short then fun (name, d) -> let name_str = if shortv then OpamPackage.to_string (OpamPackage.create name d.current_version) else OpamPackage.Name.to_string name in let colored_name = if OpamPackage.Name.Set.mem name roots then OpamGlobals.colorise `underline name_str else name_str in Printf.printf "%s\n" colored_name else let synop_len = let col = OpamMisc.terminal_columns () in max 0 (col - max_n - max_v - 4) in fun (name, info) -> let version = get_version info in let name_str = OpamPackage.Name.to_string name in let colored_name = if !OpamGlobals.color && OpamPackage.Name.Set.mem name roots then OpamGlobals.colorise `underline name_str else name_str in let sversion, colored_version, pinned = match version with | None -> s_not_installed, OpamGlobals.colorise `cyan s_not_installed, "" | Some v -> let vs = OpamPackage.Version.to_string v in if OpamState.pinned_opt t name = Some (OpamPackage.create name v) then vs, OpamGlobals.colorise `blue vs, OpamGlobals.colorise `blue " (pinned)" else if info.installed_version <> Some v then vs, OpamGlobals.colorise `cyan vs, "" else vs, OpamGlobals.colorise `magenta vs, "" in Printf.printf "%s %s%s %s\n" (OpamMisc.indent_left colored_name ~visual:name_str max_n) (OpamMisc.indent_right colored_version ~visual:sversion max_v) pinned (OpamMisc.sub_at synop_len (Lazy.force info.synopsis)) ) names let list ~print_short ~filter ~order ~exact_name ~case_sensitive ?(depends=[]) ?(reverse_depends=false) ?(recursive_depends=false) ?(resolve_depends=false) ?(depopts=false) ?depexts regexp = let t = OpamState.load_state "list" in let depends_mode = depends <> [] in let get_version name = (* We're generally not interested in the aggregated deps for all versions of the package. Take installed or max version only when there is no version constraint *) try OpamState.find_installed_package_by_name t name with Not_found -> try OpamPackage.max_version (Lazy.force t.available_packages) name with Not_found -> OpamPackage.max_version t.packages name in let depends_atoms = let atoms = OpamSolution.sanitize_atom_list ~permissive:true t depends in if resolve_depends then atoms else List.map (function | _, Some _ as atom -> atom | n, None -> try OpamSolution.eq_atom n (OpamPackage.version (get_version n)) with Not_found -> n, None) atoms in let depends = OpamState.packages_of_atoms t depends_atoms in let packages = if not depends_mode then t.packages else if resolve_depends then let universe = let u = OpamState.universe t Depends in match filter with | `all -> { u with u_available = u.u_packages } | `installed -> u | _ -> { u with u_installed = OpamPackage.Set.empty; u_installed_roots = OpamPackage.Set.empty } in let req = { wish_install = depends_atoms; wish_upgrade = []; wish_remove = []; criteria = `Default } in match OpamSolver.resolve universe ~orphans:OpamPackage.Set.empty req with | Success s -> OpamSolver.new_packages s | Conflicts cs -> if not print_short then OpamGlobals.msg "No solution%s for %s:\n%s" (if depopts then " including optional dependencies" else "") (OpamFormula.string_of_atoms depends_atoms) (OpamCudf.string_of_conflict (OpamState.unavailable_reason t) cs); OpamGlobals.exit 1 else if recursive_depends then let universe = OpamState.universe t Depends in let deps = if reverse_depends then OpamSolver.reverse_dependencies else OpamSolver.dependencies in deps ~depopts ~installed:(filter=`installed) ~unavailable:(filter<>`installable) universe depends |> OpamPackage.Set.of_list else if reverse_depends then let is_dependent_on deps nv = let opam = OpamState.opam t nv in let formula = filter_deps (OpamFile.OPAM.depends opam) in let formula = if depopts then OpamFormula.ands [formula; filter_deps (OpamFile.OPAM.depopts opam)] else formula in let depends_on nv = let name = OpamPackage.name nv in let v = OpamPackage.version nv in List.exists (fun (n,_) -> name = n) (OpamFormula.atoms formula) && OpamFormula.eval (fun (n,cstr) -> n <> name || OpamFormula.eval (fun (relop,vref) -> OpamFormula.eval_relop relop v vref) cstr) formula in OpamPackage.Set.for_all depends_on deps in OpamPackage.Set.filter (is_dependent_on depends) t.packages else let deps nv = let opam = OpamState.opam t nv in let deps = OpamState.packages_of_atoms t @@ OpamFormula.atoms @@ filter_deps @@ OpamFile.OPAM.depends opam in if depopts then deps ++ (OpamState.packages_of_atoms t @@ OpamFormula.atoms @@ filter_deps @@ OpamFile.OPAM.depopts opam) else deps in OpamPackage.Set.fold (fun nv acc -> acc ++ deps nv) depends OpamPackage.Set.empty in let depends = (* Filter to keep only the relevant versions *) if resolve_depends then packages %% depends ++ depends %% t.installed else depends in let packages = if resolve_depends then packages else packages %% match filter with | `all -> t.packages | `installed -> t.installed | `roots -> t.installed_roots | `installable -> t.installed ++ OpamSolver.installable (OpamState.universe t Depends) in let packages = if resolve_depends then packages else if depexts <> None then packages ++ depends else if depends_mode then packages -- depends else packages in let details = details_of_package_regexps t packages ~exact_name ~case_sensitive regexp in if not print_short && not (OpamPackage.Set.is_empty packages) && OpamPackage.Name.Map.is_empty details then OpamGlobals.msg "No packages found.\n"; match depexts with | Some tags_list -> let required_tags = OpamMisc.StringSet.of_list tags_list in let packages = OpamPackage.Name.Map.fold (fun name details acc -> let nv = OpamPackage.create name details.current_version in OpamPackage.Set.add nv acc) details OpamPackage.Set.empty in if not print_short then OpamGlobals.msg "# Known external dependencies for %s %s%s\n" (OpamMisc.pretty_list @@ List.map (OpamGlobals.colorise `bold @* OpamPackage.to_string) @@ OpamPackage.Set.elements packages) (if tags_list <> [] then "on " else "") (OpamGlobals.colorise `cyan @@ String.concat "," tags_list); let depexts = OpamPackage.Set.fold (fun nv acc -> let opam = OpamState.opam t nv in match OpamFile.OPAM.depexts opam with | None -> acc | Some tags -> OpamMisc.StringSetMap.fold (fun tags values acc -> if tags_list = [] then let line = Printf.sprintf "%s: %s" (String.concat " " (OpamMisc.StringSet.elements tags)) (String.concat " " (OpamMisc.StringSet.elements values)) in OpamMisc.StringSet.add line acc else if OpamMisc.StringSet.for_all (fun tag -> OpamMisc.StringSet.mem tag required_tags) tags then OpamMisc.StringSet.union acc values else acc) tags acc) packages OpamMisc.StringSet.empty in OpamGlobals.msg "%s\n" @@ String.concat "\n" @@ OpamMisc.StringSet.elements depexts | None -> let print_header () = if resolve_depends then OpamGlobals.msg "# Consistent installation providing %s %s\n" (OpamMisc.pretty_list @@ List.map (OpamGlobals.colorise `bold @* OpamPackage.to_string) @@ OpamPackage.Set.elements depends) (if filter = `installed then "from current install" else "from scratch") else let kind = match filter with | `roots | `installed -> "Installed" | `all -> "Existing" | _ -> "Available" in let results = if not depends_mode then "" else Printf.sprintf " %s %s %s" (if recursive_depends then "recursively" else "directly") (if reverse_depends then "depending on" else "required by") (OpamMisc.pretty_list ~last:"or" @@ List.map (OpamGlobals.colorise `bold @* OpamPackage.to_string) @@ OpamPackage.Set.elements depends) in OpamGlobals.msg "# %s packages%s for %s:\n" kind results (OpamSwitch.to_string t.switch) in if not print_short && OpamPackage.Name.Map.cardinal details > 0 then print_header (); print_list t ~uninst_versions:depends_mode ~short:print_short ~shortv:resolve_depends ~order details; if regexp <> [] && OpamPackage.Name.Map.is_empty details then OpamGlobals.exit 1 let info ~fields ~raw_opam ~where atoms = let t = OpamState.load_state "info" in let atoms = OpamSolution.sanitize_atom_list t ~permissive:true atoms in let details = let map = OpamPackage.to_map (OpamState.packages_of_atoms t atoms) in OpamPackage.Name.Map.mapi (details_of_package t) map in let show_fields = List.length fields <> 1 in let print_one name { current_version; tags; syntax; libraries } = (* Compute the installed versions, for each switch *) let installed = OpamState.installed_versions t name in let installed_str = let one (nv, aliases) = Printf.sprintf "%s [%s]" (OpamPackage.Version.to_string (OpamPackage.version nv)) (String.concat " " (List.map OpamSwitch.to_string aliases)) in String.concat ", " (List.map one (OpamPackage.Map.bindings installed)) in let nv = OpamPackage.create name current_version in let opam = OpamState.opam t nv in let opam_f () = (* The above gives the opam structure, but the location of the orig file is lost: re-compute *) let overlay = OpamPath.Switch.Overlay.opam t.root t.switch name in if OpamFilename.exists overlay && OpamFile.OPAM.(version (read overlay)) = current_version then overlay else let global = OpamPath.opam t.root nv in if OpamFilename.exists global then global else match OpamState.repository_and_prefix_of_package t nv with | Some (repo,pfx) -> OpamPath.Repository.opam repo pfx nv | None -> OpamSystem.internal_error "opam file location for %s not found" (OpamPackage.to_string nv) in if where then OpamGlobals.msg "%s\n" (OpamFilename.to_string (opam_f ())); (* where does it come from (eg. which repository) *) let repository = let repo = match OpamState.repository_of_package t nv with | None -> [] | Some r -> [ "repository", OpamRepositoryName.to_string r.repo_name ] in try let pin = OpamPackage.Name.Map.find name t.pinned in let kind = kind_of_pin_option pin in let revision = match repository_kind_of_pin_kind kind with | Some kind -> let repo = OpamRepository.default () in let repo = {repo with repo_kind = kind; repo_root = OpamPath.Switch.dev_package t.root t.switch name; repo_address = address_of_string @@ string_of_pin_option pin} in (match OpamProcess.Job.run (OpamRepository.revision repo) with | Some v -> Printf.sprintf " (%s)" (OpamPackage.Version.to_string v) | None -> "") | None -> "" in (if kind = `version then repo else []) @ ["pinned", (string_of_pin_kind kind) ^ revision] with Not_found -> repo in let url = match OpamState.url t nv with | None -> [] | Some u -> let kind = string_of_repository_kind (OpamFile.URL.kind u) in let url = string_of_address (OpamFile.URL.url u) in let mirrors = OpamMisc.string_of_list string_of_address (OpamFile.URL.mirrors u) in let checksum = OpamFile.URL.checksum u in [ "upstream-url" , url ] @ (if OpamFile.URL.mirrors u = [] then [] else [ "upstream-mirrors" , mirrors ]) @ [ "upstream-kind", kind ] @ match checksum with | None -> [] | Some c -> [ "upstream-checksum", c ] in (* All the version of the package *) let versions = OpamPackage.versions_of_name t.packages name in let installed_version = match OpamPackage.Map.cardinal installed with | 0 -> [ "installed-version" , "" ] | 1 -> [ "installed-version" , installed_str ] | _ -> [ "installed-versions", installed_str ] in let available_versions = let strings = List.map OpamPackage.Version.to_string (OpamPackage.Version.Set.elements versions) in match strings with | [] -> [] | [v] -> [ "available-version" , v ] | l -> [ "available-versions", String.concat ", " l ] in let mk empty to_string name field = let v = field opam in if empty = v then [] else [name, to_string v] in let strings = mk [] (String.concat ", ") in let formula = mk Empty OpamFormula.to_string in let option f = mk None (function None -> "" | Some x -> f x) in let author = strings "author" OpamFile.OPAM.author in let homepage = strings "homepage" OpamFile.OPAM.homepage in let bug_reports = strings "bug-reports" OpamFile.OPAM.bug_reports in let dev_repo = option string_of_pin_option "dev-repo" OpamFile.OPAM.dev_repo in let license = strings "license" OpamFile.OPAM.license in let doc = strings "doc" OpamFile.OPAM.doc in let tags = strings "tags" (fun _ -> tags) in let depends = formula "depends" (filter_deps @* OpamFile.OPAM.depends) in let depopts = formula "depopts" (filter_deps @* OpamFile.OPAM.depopts) in let libraries = strings "libraries" (fun _ -> Lazy.force libraries) in let syntax = strings "syntax" (fun _ -> Lazy.force syntax) in let os = mk Empty (OpamFormula.string_of_formula (fun (t,s) -> if t then s else "!"^s)) "os" OpamFile.OPAM.os in let descr = let d = OpamState.descr t nv in ["description", OpamFile.Descr.full d] in let version = OpamPackage.version nv in let all_fields = [ "package", OpamPackage.Name.to_string name ] @ [ "version", OpamPackage.Version.to_string version ] @ repository @ url @ homepage @ bug_reports @ dev_repo @ author @ license @ doc @ tags @ libraries @ syntax @ depends @ depopts @ os @ installed_version @ available_versions @ descr in let all_fields = match fields with | [] when not (raw_opam || where) -> all_fields | f -> List.filter (fun (d,_) -> List.mem d f) all_fields in List.iter (fun (f, desc) -> if show_fields then OpamGlobals.msg "%s " (OpamGlobals.colorise `blue (Printf.sprintf "%20s:" f)); OpamGlobals.msg "%s\n" desc ) all_fields; if raw_opam then OpamFile.OPAM.write_to_channel stdout opam in OpamPackage.Name.Map.iter print_one details (* When packages are removed from upstream, they normally disappear from the 'available' packages set and can't be seen by the solver anymore. This is a problem for several reasons, so we compute the set of orphan packages here: - they are checked for conflicts with the user request - they are re-added to the universe if (transitively) unrelated to the request (the [changes] parameter) - they are otherwise put in [wish_remove] in case we use the internal solver This function separates full orphans (no version of the package available anymore) from orphan versions, because they have a different impact on the request (needs version change VS needs uninstall). See also preprocess_request and check_conflicts *) let orphans ?changes ?(transitive=false) t = let all = t.packages ++ t.installed in let allnames = OpamPackage.names_of_packages all in let universe = OpamState.universe t (Reinstall OpamPackage.Set.empty) in (* Basic definition of orphan packages *) let orphans = t.installed -- Lazy.force t.available_packages in (* Restriction to the request-related packages *) let orphans = match changes with | None -> orphans | Some ch -> if OpamPackage.Set.is_empty orphans then orphans else let recompile_cone = OpamPackage.Set.of_list @@ OpamSolver.reverse_dependencies ~depopts:true ~installed:true ~unavailable:true universe ch in orphans %% recompile_cone in (* Pinned versions of packages remain always available *) let orphans = orphans -- OpamState.pinned_packages t in (* Splits between full orphans (no version left) and partial ones *) let full_partition orphans = let orphan_names = (* names for which there is no version left *) OpamPackage.Name.Set.diff allnames (OpamPackage.names_of_packages (all -- orphans)) in OpamPackage.Set.partition (fun nv -> OpamPackage.Name.Set.mem (OpamPackage.name nv) orphan_names) orphans in let full_orphans, orphan_versions = full_partition orphans in (* Closure *) let full_orphans, orphan_versions = if not transitive then full_orphans, orphan_versions else let rec add_trans full_orphans orphan_versions = (* fixpoint to check all packages with no available version *) let new_orphans = OpamPackage.Set.of_list @@ OpamSolver.reverse_dependencies ~depopts:false ~installed:false ~unavailable:true universe full_orphans in let full, versions = full_partition (new_orphans++orphan_versions) in if OpamPackage.Set.equal full_orphans full then full, versions else add_trans full versions in add_trans full_orphans orphan_versions in (* Installed packages outside the set of changes are otherwise safe: re-add them to the universe *) let t = if changes = None then t else let available_packages = lazy (Lazy.force t.available_packages ++ (t.installed -- orphans)) in { t with available_packages } in log "Orphans: full %a, versions %a" (slog @@ OpamPackage.Name.Set.to_string @* OpamPackage.names_of_packages) full_orphans (slog OpamPackage.Set.to_string) orphan_versions; t, full_orphans, orphan_versions (* The internal "solver" needs some rewrites of the requests, to make them more explicit. This has no effect when using the external solver. *) let preprocess_request t full_orphans orphan_versions request = if OpamCudf.external_solver_available () then request else let { wish_install; wish_remove; wish_upgrade; criteria } = request in (* Convert install to upgrade when necessary, request roots installed *) let eqnames, neqnames = List.partition (function (_,Some(`Eq,_)) -> true | _ -> false) wish_install in let add_wish_install = List.rev_append eqnames (OpamSolution.atoms_of_packages (t.installed_roots %% Lazy.force t.available_packages)) in let base_packages = let comp = OpamState.compiler_comp t t.compiler in OpamFormula.to_conjunction (OpamFile.Comp.packages comp) in let base_packages = List.map (fun atom -> try OpamPackage.Set.find (OpamFormula.check atom) t.installed |> OpamSolution.eq_atom_of_package with Not_found -> atom) base_packages in let wish_install = List.rev_append add_wish_install wish_install in let wish_install = List.rev_append base_packages wish_install in let uninstalled_eqnames = List.filter (fun (name,_) -> not (OpamState.is_name_installed t name)) eqnames in let wish_upgrade = List.rev_append neqnames wish_upgrade in let wish_upgrade = List.rev_append uninstalled_eqnames wish_upgrade in (* Remove orphans *) let wish_remove = OpamSolution.atoms_of_packages full_orphans @ OpamSolution.eq_atoms_of_packages orphan_versions @ wish_remove in let available = Lazy.force t.available_packages -- orphan_versions -- full_orphans in let still_available ?(up=false) (name,_ as atom) = let installed = if up then try Some (OpamPackage.version @@ OpamPackage.Set.choose_one @@ OpamPackage.packages_of_name t.installed name) with Not_found -> None else None in OpamPackage.Set.exists (fun p -> OpamFormula.check atom p && match installed with Some i -> OpamPackage.version p >= i | None -> true) available in let upgradeable, non_upgradeable = List.partition (still_available ~up:true) wish_upgrade in let wish_install = List.filter still_available (non_upgradeable @ wish_install) in let wish_upgrade = List.filter (still_available ~up:true) upgradeable in let nrequest = { wish_install; wish_remove; wish_upgrade; criteria } in log "Preprocess request: %a => %a" (slog OpamSolver.string_of_request) request (slog OpamSolver.string_of_request) nrequest; nrequest (* Splits a list of atoms into the installed and uninstalled ones*) let get_installed_atoms t atoms = List.fold_left (fun (packages, not_installed) atom -> try let nv = OpamPackage.Set.find (OpamFormula.check atom) t.installed in nv :: packages, not_installed with Not_found -> packages, atom :: not_installed) ([],[]) atoms (* Check atoms for pinned packages, and update them. Returns the state that may have been reloaded if there were changes *) let update_dev_packages_t atoms t = let to_update = List.fold_left (fun to_update (name,_) -> match OpamState.pinned_opt t name with | None -> to_update | Some nv -> OpamPackage.Set.add nv to_update) OpamPackage.Set.empty atoms in if OpamPackage.Set.is_empty to_update then t else ( OpamGlobals.header_msg "Synchronising pinned packages"; try let updated = OpamState.update_dev_packages t to_update in if OpamPackage.Set.is_empty updated then t else OpamState.load_state "reload-dev-package-updated" with e -> OpamMisc.fatal e; t ) let compute_upgrade_t atoms t = let names = OpamPackage.Name.Set.of_list (List.rev_map fst atoms) in if atoms = [] then let to_reinstall = t.reinstall %% t.installed in let t, full_orphans, orphan_versions = orphans ~transitive:true t in let to_upgrade = t.installed -- full_orphans -- orphan_versions in let to_install = t.installed -- full_orphans in let requested = OpamPackage.Name.Set.empty in let action = Upgrade to_reinstall in requested, action, OpamSolution.resolve t action ~orphans:(full_orphans ++ orphan_versions) (preprocess_request t full_orphans orphan_versions { wish_install = OpamSolution.atoms_of_packages to_install; wish_remove = []; wish_upgrade = OpamSolution.atoms_of_packages to_upgrade; criteria = `Upgrade; }) else let atoms = List.map (function | (n,None) -> (* force strict update for unchanged, non dev or pinned packages (strict update makes no sense for pinned packages which have a fixed version) *) (try let nv = OpamState.find_installed_package_by_name t n in if OpamState.is_dev_package t nv || OpamState.is_pinned t n || OpamPackage.Set.mem nv t.reinstall then (n, None) else let atom = (n, Some (`Gt, OpamPackage.version nv)) in if OpamPackage.Set.exists (OpamFormula.check atom) (Lazy.force t.available_packages) then atom else (n, None) with Not_found -> (n,None)) | atom -> atom ) atoms in let to_reinstall = OpamPackage.Set.filter (fun nv -> OpamPackage.Name.Set.mem (OpamPackage.name nv) names) t.reinstall in let to_upgrade, not_installed = List.fold_left (fun (packages, not_installed) (n,_ as atom) -> try let nv = OpamPackage.Set.find (fun nv -> OpamPackage.name nv = n) t.installed in OpamPackage.Set.add nv packages, not_installed with Not_found -> packages, atom :: not_installed) (OpamPackage.Set.empty,[]) atoms in if not_installed <> [] then OpamGlobals.note "%s %s not installed, ignored.\n" (OpamMisc.pretty_list (List.rev_map OpamFormula.short_string_of_atom not_installed)) (match not_installed with [_] -> "is" | _ -> "are"); let t, full_orphans, orphan_versions = orphans ~changes:to_upgrade t in let to_remove = to_upgrade %% full_orphans in let to_upgrade = to_upgrade -- full_orphans in let requested = names in let action = Upgrade to_reinstall in let upgrade_atoms = (* packages corresponds to the currently installed versions. Not what we are interested in, recover the original atom constraints *) List.map (fun nv -> let name = OpamPackage.name nv in try name, List.assoc name atoms with Not_found -> name, None) (OpamPackage.Set.elements to_upgrade) in requested, action, OpamSolution.resolve t action ~orphans:(full_orphans ++ orphan_versions) (preprocess_request t full_orphans orphan_versions { wish_install = []; wish_remove = OpamSolution.atoms_of_packages to_remove; wish_upgrade = upgrade_atoms; criteria = `Default; }) let upgrade_t ?ask atoms t = log "UPGRADE %a" (slog @@ function [] -> "" | a -> OpamFormula.string_of_atoms a) atoms; match compute_upgrade_t atoms t with | requested, _action, Conflicts cs -> log "conflict!"; if not (OpamPackage.Name.Set.is_empty requested) then (OpamGlobals.msg "%s" (OpamCudf.string_of_conflict (OpamState.unavailable_reason t) cs); OpamGlobals.exit 3); let reasons, chains, cycles = OpamCudf.strings_of_conflict (OpamState.unavailable_reason t) cs in if cycles <> [] then begin OpamGlobals.error "Dependency errors in the upgrade actions. Please update, and \ report the following to the package maintainers if the error \ persists:"; OpamGlobals.errmsg "%s\n%s\n" (OpamMisc.itemize (fun x -> x) cycles) "You may try upgrading packages individually to work around this." end else begin OpamGlobals.warning "Upgrade is not possible because of conflicts or packages that \ are no longer available:"; OpamGlobals.errmsg "%s" (OpamMisc.itemize (fun x -> x) reasons); if chains <> [] then OpamGlobals.errmsg "The following dependencies are in cause:\n%s" (OpamMisc.itemize (fun x -> x) chains); if OpamCudf.external_solver_available () then OpamGlobals.errmsg "\nYou may run \"opam upgrade --fixup\" to let OPAM fix the \ current state.\n" end; OpamGlobals.exit 3 | requested, action, Success solution -> let result = OpamSolution.apply ?ask t action ~requested solution in if result = Nothing_to_do then ( let to_check = if OpamPackage.Name.Set.is_empty requested then t.installed else OpamPackage.packages_of_names t.installed requested in let latest = OpamPackage.Name.Set.fold (fun name acc -> OpamPackage.Set.add (OpamPackage.max_version t.packages name) acc) (OpamPackage.names_of_packages to_check) OpamPackage.Set.empty in let notuptodate = latest -- to_check in if OpamPackage.Set.is_empty notuptodate then OpamGlobals.msg "Already up-to-date.\n" else (let hdmsg = "Everything as up-to-date as possible" in let unav = notuptodate -- Lazy.force t.available_packages in let unopt = notuptodate %% Lazy.force t.available_packages in let base = OpamPackage.packages_of_names unopt (OpamState.base_package_names t) in let unopt = unopt -- base in if !OpamGlobals.verbose && not (OpamPackage.Set.is_empty unav) then OpamGlobals.formatted_msg "%s.\n\ The following newer versions couldn't be installed:\n%s" hdmsg (OpamMisc.itemize (fun p -> OpamState.unavailable_reason t (OpamSolution.eq_atom (OpamPackage.name p) (OpamPackage.version p))) (OpamPackage.Set.elements unav)) else OpamGlobals.formatted_msg "%s (run with --verbose to show unavailable upgrades).\n" hdmsg; if not (OpamPackage.Set.is_empty unopt) then (OpamGlobals.formatted_msg "The following would require downgrades or uninstalls, but \ you may upgrade them explicitly:\n%s" (OpamMisc.itemize OpamPackage.to_string (OpamPackage.Set.elements unopt))); ) ); OpamSolution.check_solution t result let upgrade names = with_switch_backup "upgrade" @@ fun t -> let atoms = OpamSolution.sanitize_atom_list t names in let t = update_dev_packages_t atoms t in upgrade_t atoms t let fixup_t t = log "FIXUP"; if not (OpamCudf.external_solver_available ()) then (OpamGlobals.formatted_msg "Sorry, \"--fixup\" is not available without an external solver. \ You'll have to select the packages to change or remove by hand, \ or install aspcud or another solver on your system.\n"; OpamGlobals.exit 1) else let t, full_orphans, orphan_versions = orphans ~transitive:true t in let action = Upgrade OpamPackage.Set.empty in let all_orphans = full_orphans ++ orphan_versions in let resolve pkgs = pkgs, OpamSolution.resolve t action ~orphans:all_orphans { wish_install = OpamSolution.atoms_of_packages pkgs; wish_remove = []; wish_upgrade = []; criteria = `Fixup; } in let is_success = function | _, Success _ -> true | _, Conflicts cs -> log "conflict: %a" (slog (OpamCudf.string_of_conflict @@ OpamState.unavailable_reason t)) cs; false in let requested, solution = let s = log "fixup-1/ keep installed packages with orphaned versions and roots"; resolve (t.installed_roots -- full_orphans ++ orphan_versions) in if is_success s then s else let s = log "fixup-2/ keep just roots"; resolve (t.installed_roots -- full_orphans) in if is_success s then s else let s = log "fixup-3/ keep packages with orphaned versions"; resolve orphan_versions in if is_success s then s else let s = log "fixup-4/ last resort: no constraints. This should never fail"; resolve OpamPackage.Set.empty in s (* Could still fail with uninstallable base packages actually, but we can only fix so far *) in let result = match solution with | Conflicts cs -> (* ouch... *) OpamGlobals.msg "%s" (OpamCudf.string_of_conflict (OpamState.unavailable_reason t) cs); No_solution | Success solution -> let _, req_rm, _ = orphans ~transitive:false t in OpamSolution.apply ~ask:true t action ~requested:(OpamPackage.names_of_packages (requested ++ req_rm)) solution in OpamSolution.check_solution t result let fixup () = with_switch_backup "fixup" fixup_t let update ~repos_only ?(no_stats=false) names = let t = OpamState.load_state ~save_cache:true "update" in log "UPDATE %a" (slog @@ String.concat ", ") names; let repositories = if names = [] then t.repositories else let aux r _ = List.mem (OpamRepositoryName.to_string r) names in OpamRepositoryName.Map.filter aux t.repositories in let repositories_need_update = not (OpamRepositoryName.Map.is_empty repositories) in let dev_packages = if repos_only then OpamPackage.Set.empty else if names = [] then t.installed %% OpamState.dev_packages t else OpamPackage.Set.filter (fun nv -> let name = OpamPackage.Name.to_string (OpamPackage.name nv) in let pkg = OpamPackage.to_string nv in List.exists (fun s -> s = name || s = pkg) names ) (OpamState.dev_packages t) in let dev_packages_need_update = not (OpamPackage.Set.is_empty dev_packages) in let valid_repositories = OpamMisc.StringSet.of_list (List.rev_map OpamRepositoryName.to_string (OpamRepositoryName.Map.keys repositories)) in let valid_pinned_packages = OpamMisc.StringSet.of_list (List.rev_map OpamPackage.Name.to_string (OpamPackage.Name.Map.keys t.pinned)) in let unknown_names, not_pinned = if names = [] then [], [] else let all = OpamMisc.StringSet.of_list names in let valid_names = OpamMisc.StringSet.of_list (List.rev_map (OpamPackage.name @> OpamPackage.Name.to_string) (OpamPackage.Set.elements t.packages)) in let open OpamMisc.StringSet.Op in let unknown_names = all -- valid_repositories -- valid_names in let not_pinned = (all %% valid_names) -- valid_pinned_packages -- valid_repositories -- (OpamPackage.Set.fold (fun nv acc -> OpamMisc.StringSet.add (OpamPackage.name_to_string nv) acc) dev_packages OpamMisc.StringSet.empty) in OpamMisc.StringSet.elements unknown_names, OpamMisc.StringSet.elements not_pinned in begin let valid_repositories = match OpamMisc.StringSet.elements valid_repositories with | [] -> "" | [s] -> Printf.sprintf " Valid repository is %s." s | l -> Printf.sprintf " Valid repositories are %s." (OpamMisc.pretty_list l) in match unknown_names with | [] -> () | [s] -> OpamGlobals.error_and_exit "Cannot update the repository %s.%s" s valid_repositories | _ -> OpamGlobals.error_and_exit "Cannot update the repositories %s.%s" (OpamMisc.pretty_list unknown_names) valid_repositories end; begin let valid_pinned_packages = match OpamMisc.StringSet.elements valid_pinned_packages with | [] -> "" | [s] -> Printf.sprintf "Only %s is currently pinned.\n" s | l -> Printf.sprintf "The currently pinned packages are %s.\n" (OpamMisc.pretty_list l) in match not_pinned with | [] -> () | [s] -> OpamGlobals.msg "Cannot update the package %s because it is not pinned.\n%s" s valid_pinned_packages | _ -> OpamGlobals.msg "Cannot update %s because none are pinned.%s\n" (OpamMisc.pretty_list not_pinned) valid_pinned_packages end; if repositories_need_update then ( OpamGlobals.header_msg "Updating package repositories"; let repos = OpamRepositoryName.Map.values repositories in let command repo = OpamProcess.Job.ignore_errors ~default:(fun t -> t) ~message:("Could not update repository " ^ OpamRepositoryName.to_string repo.repo_name) @@ OpamRepositoryCommand.update t repo in let t = OpamParallel.reduce ~jobs:(OpamState.dl_jobs t) ~command ~merge:(fun f1 f2 x -> f1 (f2 x)) ~nil:(fun x -> x) repos t in let t, compiler_updates = let t = OpamRepositoryCommand.update_compiler_index t in t, OpamRepositoryCommand.fix_compiler_descriptions t ~verbose:(!OpamGlobals.verbose_level >= 2) in let package_updates = let t = OpamRepositoryCommand.update_package_index t in OpamRepositoryCommand.fix_package_descriptions t ~verbose:(!OpamGlobals.verbose_level >= 2) in (* If necessary, output a JSON file *) if OpamJson.verbose () then let json to_json update = `O [ ("created", to_json update.created); ("updated", to_json update.updated); ("deleted", to_json update.deleted); ("changed", to_json update.changed); ] in let updates = `O [ "package-updates" , (json OpamPackage.Set.to_json package_updates); "compiler-updates", (json OpamCompiler.Set.to_json compiler_updates); ] in OpamJson.add updates; ); if dev_packages_need_update then ( OpamGlobals.header_msg "Synchronizing development packages"; let updates = OpamRepositoryCommand.update_dev_packages ~verbose:!OpamGlobals.verbose t dev_packages in let json = `O [ "dev-packages-update", OpamPackage.Set.to_json updates ] in OpamJson.add json ); OpamState.rebuild_state_cache (); log "dry-upgrade"; let broken_state_message ~need_fixup conflicts = let reasons, chains, _cycles = OpamCudf.strings_of_conflict (OpamState.unavailable_reason t) conflicts in OpamGlobals.warning "A conflict was detected in your installation. \ This can be caused by updated constraints or conflicts in your \ installed packages:\n%s" (OpamMisc.itemize (fun x -> x) reasons); if chains <> [] then ( OpamGlobals.formatted_msg "The following dependencies are in cause:\n"; List.iter (OpamGlobals.msg " - %s\n") chains); OpamGlobals.formatted_msg "\nYou should run \"opam upgrade%s\" to resolve the situation.\n" (if need_fixup && OpamCudf.external_solver_available () then " --fixup" else "") in if not no_stats then let t = OpamState.load_state ~save_cache:false "dry-upgrade" in let universe = OpamState.universe t (Upgrade OpamPackage.Set.empty) in match OpamSolver.check_for_conflicts universe with | Some cs -> let need_fixup = match compute_upgrade_t [] t with | _, _, Success _ -> false | _, _, Conflicts _ -> true in broken_state_message ~need_fixup cs | None -> match compute_upgrade_t [] t with | _, _, Success upgrade -> let stats = OpamSolver.stats upgrade in if OpamSolution.sum stats > 0 then OpamGlobals.msg "\nUpdates available for %s, apply them with 'opam upgrade':\n\ ===== %s =====\n" (OpamSwitch.to_string t.switch) (OpamSolver.string_of_stats stats) | _, _, Conflicts cs -> log "State isn't broken but upgrade fails: something might be wrong."; broken_state_message ~need_fixup:true cs let init repo compiler ~jobs shell dot_profile update_config = log "INIT %a" (slog OpamRepository.to_string) repo; let root = OpamPath.root () in let config_f = OpamPath.config root in let dot_profile_o = Some dot_profile in let user = { shell; ocamlinit = true; dot_profile = dot_profile_o } in let root_empty = not (OpamFilename.exists_dir root) || OpamFilename.dir_is_empty root in let update_setup t = let updated = match update_config with | `ask -> OpamState.update_setup_interactive t shell dot_profile | `no -> false | `yes -> let global = { complete = true; switch_eval = true } in OpamState.update_setup t (Some user) (Some global); true in if updated then OpamState.print_env_warning_at_switch t else OpamState.print_env_warning_at_init t user in if OpamFilename.exists config_f then ( OpamGlobals.msg "OPAM has already been initialized."; ) else ( if not root_empty then ( OpamGlobals.warning "%s exists and is not empty" (OpamFilename.Dir.to_string root); if not (OpamGlobals.confirm "Proceed ?") then OpamGlobals.exit 1); try (* Check for the external dependencies *) let check_external_dep name = OpamSystem.command_exists name in OpamGlobals.msg "Checking for available remotes: "; let repo_types = ["rsync", "rsync and local"; "git", "git"; "hg", "mercurial"; "darcs", "darcs"] in let available_repos, unavailable_repos = List.partition (check_external_dep @* fst) repo_types in OpamGlobals.msg "%s.%s\n" (match available_repos with | [] -> "none" | r -> String.concat ", " (List.map snd r)) (if unavailable_repos = [] then " Perfect!" else "\n" ^ OpamMisc.itemize (fun (cmd,msg) -> Printf.sprintf "you won't be able to use %s repositories unless you \ install the %s command on your system." msg (OpamGlobals.colorise `bold cmd)) unavailable_repos); if not (check_external_dep (OpamGlobals.default_external_solver)) then OpamGlobals.warning "Recommended external solver %s not found." (OpamGlobals.colorise `bold (OpamGlobals.default_external_solver)); let advised_deps = [!OpamGlobals.makecmd(); "m4"; "cc"] in (match List.filter (not @* check_external_dep) advised_deps with | [] -> () | missing -> OpamGlobals.warning "Recommended dependencies -- \ most packages rely on these:\n%s" (OpamMisc.itemize (OpamGlobals.colorise `bold) missing)); let required_deps = ["curl or wget", check_external_dep OpamGlobals.curl_command || check_external_dep "wget" || (match !OpamGlobals.download_tool with | Some (`Custom f) -> (match f ~url:"" ~out:"-" ~retry:1 ~checksum:"" ~compress:false with | cmd::_ -> check_external_dep cmd | [] -> false) | _ -> false); "patch", check_external_dep "patch"; "tar", check_external_dep "tar"; "unzip", check_external_dep "unzip" ] in (match List.filter (not @* snd) required_deps with | [] -> () | missing -> OpamGlobals.error_and_exit "Missing dependencies -- \ the following commands are required for OPAM to operate:\n%s" (OpamMisc.itemize (OpamGlobals.colorise `bold @* fst) missing)); (* Create (possibly empty) configuration files *) let switch = if compiler = OpamCompiler.system then OpamSwitch.default else OpamSwitch.of_string (OpamCompiler.to_string compiler) in (* Create ~/.opam/compilers/system.comp *) OpamState.create_system_compiler_description root; (* Create ~/.opam/config *) let config = OpamFile.Config.create switch [repo.repo_name] jobs OpamGlobals.default_dl_jobs in OpamFile.Config.write config_f config; (* Create ~/.opam/aliases *) OpamFile.Aliases.write (OpamPath.aliases root) (OpamSwitch.Map.singleton switch compiler); (* Init repository *) OpamFile.Package_index.write (OpamPath.package_index root) OpamPackage.Map.empty; OpamFile.Compiler_index.write (OpamPath.compiler_index root) OpamCompiler.Map.empty; OpamFile.Repo_config.write (OpamPath.Repository.config repo) repo; OpamProcess.Job.run (OpamRepository.init repo); OpamState.install_global_config root switch; (* Init global dirs *) OpamFilename.mkdir (OpamPath.packages_dir root); OpamFilename.mkdir (OpamPath.compilers_dir root); (* Load the partial state, and update the global state *) log "updating repository state"; let t = OpamState.load_state ~save_cache:false "init-1" in OpamGlobals.header_msg "Fetching repository information"; let t = OpamProcess.Job.run (OpamRepositoryCommand.update t repo) t in OpamRepositoryCommand.fix_descriptions t ~save_cache:false ~verbose:false; (* Load the partial state, and install the new compiler if needed *) log "updating package state"; let switch = OpamSwitch.of_string (OpamCompiler.to_string compiler) in let quiet = (compiler = OpamCompiler.system) in OpamState.install_compiler t ~quiet switch compiler; (* Finally, load the complete state and install the compiler packages *) log "installing compiler packages"; OpamSwitchCommand.install_packages switch compiler with e -> OpamGlobals.error "Initialisation failed"; OpamGlobals.errmsg "%s\n" (Printexc.to_string e); if not !OpamGlobals.debug && root_empty then OpamFilename.rmdir root; raise e); let t = OpamState.load_state "init" in update_setup t (* Checks a request for [atoms] for conflicts with the orphan packages *) let check_conflicts t atoms = let changes = OpamState.packages_of_atoms t atoms in let t, full_orphans, orphan_versions = orphans ~changes t in (* packages which still have local data are OK for install/reinstall *) let has_no_local_data nv = not (OpamFilename.exists_dir (OpamPath.packages t.root nv)) in let full_orphans, full_orphans_with_local_data = OpamPackage.Set.partition has_no_local_data full_orphans in let orphan_versions, orphan_versions_with_local_data = OpamPackage.Set.partition has_no_local_data orphan_versions in let available = lazy (t.packages -- full_orphans -- orphan_versions) in let orphans = full_orphans ++ orphan_versions in let conflict_atoms = List.filter (fun (name,_ as a) -> not (OpamState.is_pinned t name) && OpamPackage.Set.exists (OpamFormula.check a) orphans && (*optim*) not (OpamPackage.Set.exists (OpamFormula.check a) (* real check *) (Lazy.force available))) atoms in if conflict_atoms <> [] then OpamGlobals.error_and_exit "Sorry, these packages are no longer available \ from the repositories: %s" (OpamMisc.pretty_list (List.map OpamFormula.string_of_atom conflict_atoms)) else {t with available_packages = lazy (Lazy.force t.available_packages ++ full_orphans_with_local_data ++ orphan_versions_with_local_data )}, full_orphans, orphan_versions let install_t ?ask atoms add_to_roots deps_only t = log "INSTALL %a" (slog OpamFormula.string_of_atoms) atoms; let names = OpamPackage.Name.Set.of_list (List.rev_map fst atoms) in let t, full_orphans, orphan_versions = check_conflicts t atoms in let pkg_skip, pkg_new = get_installed_atoms t atoms in (* Add the packages to the list of package roots and display a warning for already installed package roots. *) let current_roots = t.installed_roots in let t = List.fold_left (fun t nv -> if OpamPackage.Set.mem nv t.installed then match add_to_roots with | None -> OpamGlobals.note "Package %s is already installed (current version is %s)." (OpamPackage.Name.to_string (OpamPackage.name nv)) (OpamPackage.Version.to_string (OpamPackage.version nv)); t | Some true -> if OpamPackage.Set.mem nv t.installed_roots then OpamGlobals.note "Package %s is already installed as a root." (OpamPackage.Name.to_string (OpamPackage.name nv)); { t with installed_roots = OpamPackage.Set.add nv t.installed_roots } | Some false -> if OpamPackage.Set.mem nv t.installed_roots then { t with installed_roots = OpamPackage.Set.remove nv t.installed_roots } else (OpamGlobals.note "Package %s is already marked as 'installed automatically'." (OpamPackage.Name.to_string (OpamPackage.name nv)); t) else t ) t pkg_skip in if t.installed_roots <> current_roots then ( let diff = t.installed_roots -- current_roots in if not (OpamPackage.Set.is_empty diff) then let diff = OpamPackage.Set.elements diff in let diff = List.rev (List.rev_map OpamPackage.to_string diff) in OpamGlobals.msg "Adding %s to the list of installed roots.\n" (OpamMisc.pretty_list diff) else ( let diff = current_roots -- t.installed_roots in let diff = OpamPackage.Set.elements diff in let diff = List.rev (List.rev_map OpamPackage.to_string diff) in OpamGlobals.msg "Removing %s from the list of installed roots.\n" (OpamMisc.pretty_list diff) ); let file = OpamPath.Switch.installed_roots t.root t.switch in OpamFile.Installed_roots.write file t.installed_roots; ); OpamSolution.check_availability t (Lazy.force t.available_packages) atoms; if pkg_new <> [] then ( let request = preprocess_request t full_orphans orphan_versions { wish_install = atoms; wish_remove = []; wish_upgrade = []; criteria = `Default; } in let action = if add_to_roots = Some false || deps_only then Install OpamPackage.Name.Set.empty else Install names in let solution = OpamSolution.resolve t action ~orphans:(full_orphans ++ orphan_versions) request in let solution = match solution with | Conflicts cs -> log "conflict!"; OpamGlobals.msg "%s" (OpamCudf.string_of_conflict (OpamState.unavailable_reason t) cs); No_solution | Success solution -> let solution = if deps_only then OpamSolver.filter_solution (fun nv -> not (OpamPackage.Name.Set.mem (OpamPackage.name nv) names)) solution else solution in OpamSolution.apply ?ask t action ~requested:names solution in OpamSolution.check_solution t solution ) let install names add_to_roots deps_only = with_switch_backup "install" @@ fun t -> let atoms = OpamSolution.sanitize_atom_list ~permissive:true t names in let t = update_dev_packages_t atoms t in install_t atoms add_to_roots deps_only t let remove_t ?ask ~autoremove ~force atoms t = log "REMOVE autoremove:%b %a" autoremove (slog OpamFormula.string_of_atoms) atoms; let t, full_orphans, orphan_versions = let changes = if autoremove then None else Some (OpamState.packages_of_atoms t atoms) in orphans ?changes t in let nothing_to_do = ref true in let atoms = List.filter (fun (n,_) -> if n = OpamPackage.Name.global_config then ( OpamGlobals.msg "Package %s can not be removed.\n" (OpamPackage.Name.to_string OpamPackage.Name.global_config); false ) else true ) atoms in let packages, not_installed = get_installed_atoms t atoms in if not_installed <> [] then ( if force then let force_remove atom = let candidates = OpamPackage.Set.filter (OpamFormula.check atom) t.packages in try let nv = OpamPackage.max_version candidates (fst atom) in OpamGlobals.note "Forcing removal of (uninstalled) %s" (OpamPackage.to_string nv); OpamProcess.Job.run (OpamAction.remove_package ~metadata:false t nv); OpamAction.cleanup_package_artefacts t nv; nothing_to_do := false with Not_found -> OpamGlobals.error "No package %s found for (forced) removal.\n" (OpamFormula.short_string_of_atom atom) in List.iter force_remove not_installed else OpamGlobals.note "%s %s not installed.\n" (OpamMisc.pretty_list (List.map OpamFormula.short_string_of_atom not_installed)) (match not_installed with [_] -> "is" | _ -> "are") ); if autoremove || packages <> [] then ( let packages = OpamPackage.Set.of_list packages in let universe = OpamState.universe t Remove in let to_remove = OpamPackage.Set.of_list (OpamSolver.reverse_dependencies ~depopts:false ~installed:true universe packages) in let to_keep = (if autoremove then t.installed_roots else t.installed) -- to_remove -- full_orphans -- orphan_versions in let to_keep = OpamPackage.Set.of_list (OpamSolver.dependencies ~depopts:true ~installed:true universe to_keep) in (* to_keep includes the depopts, because we don't want to autoremove them. But that may re-include packages that we wanted removed, so we need to remove them again *) let to_keep = to_keep -- to_remove in let requested = OpamPackage.names_of_packages packages in let to_remove = if autoremove then let to_remove = t.installed -- to_keep in if atoms = [] then to_remove else (* restrict to the dependency cone of removed pkgs *) to_remove %% (OpamPackage.Set.of_list (OpamSolver.dependencies ~depopts:true ~installed:true universe to_remove)) else to_remove in let solution = OpamSolution.resolve_and_apply ?ask t Remove ~requested ~orphans:(full_orphans ++ orphan_versions) { wish_install = OpamSolution.eq_atoms_of_packages to_keep; wish_remove = OpamSolution.atoms_of_packages to_remove; wish_upgrade = []; criteria = `Default; } in OpamSolution.check_solution t solution ) else if !nothing_to_do then OpamGlobals.msg "Nothing to do.\n" let remove ~autoremove ~force names = with_switch_backup "remove" @@ fun t -> let atoms = OpamSolution.sanitize_atom_list t names in remove_t ~autoremove ~force atoms t let reinstall_t ?ask ?(force=false) atoms t = log "reinstall %a" (slog OpamFormula.string_of_atoms) atoms; let reinstall, not_installed = get_installed_atoms t atoms in let to_install = if not_installed <> [] then if force || (OpamGlobals.warning "%s %s not installed." (OpamMisc.pretty_list (List.map OpamFormula.short_string_of_atom not_installed)) (match not_installed with [_] -> "is" | _ -> "are"); OpamGlobals.confirm "Install ?") then not_installed else OpamGlobals.exit 1 else [] in let reinstall = OpamPackage.Set.of_list reinstall in let atoms = to_install @ OpamSolution.eq_atoms_of_packages reinstall in let t, full_orphans, orphan_versions = check_conflicts t atoms in let requested = OpamPackage.Name.Set.of_list (List.rev_map fst atoms) in let request = preprocess_request t full_orphans orphan_versions { wish_install = atoms; wish_remove = []; wish_upgrade = []; criteria = `Fixup; } in let solution = OpamSolution.resolve_and_apply ?ask t (Reinstall reinstall) ~requested ~orphans:(full_orphans ++ orphan_versions) request in OpamSolution.check_solution t solution let reinstall names = with_switch_backup "reinstall" @@ fun t -> let atoms = OpamSolution.sanitize_atom_list t names in let t = update_dev_packages_t atoms t in reinstall_t atoms t module PIN = struct open OpamPinCommand let post_pin_action t name = let nv = try Some (OpamState.pinned t name) with Not_found -> None in try match nv with | Some nv -> let v = OpamPackage.version nv in OpamGlobals.msg "%s needs to be %sinstalled.\n" (OpamPackage.Name.to_string name) (if OpamPackage.has_name t.installed name then "re" else ""); if OpamPackage.Set.mem nv t.installed then reinstall_t ~ask:true [name, Some (`Eq,v)] t (* same version *) else install_t ~ask:true [name, Some (`Eq,v)] None false t (* != version or new *) | None -> try let nv = OpamPackage.max_version t.installed name in if OpamPackage.has_name (Lazy.force t.available_packages) name then (OpamGlobals.msg "%s needs to be reinstalled.\n" (OpamPackage.Name.to_string name); if OpamPackage.Set.mem nv (Lazy.force t.available_packages) then reinstall_t ~ask:true [name, Some (`Eq, OpamPackage.version nv)] t else upgrade_t ~ask:true [name, Some (`Neq, OpamPackage.version nv)] t) else (OpamGlobals.msg "%s needs to be removed.\n" (OpamPackage.to_string nv); (* Package no longer available *) remove_t ~ask:true ~autoremove:false ~force:false [name, None] t) with Not_found -> () with e -> OpamGlobals.note "Pinning command successful, but your installed packages \ may be out of sync."; raise e let get_upstream t name = try let nv = OpamPackage.max_version t.packages name in match OpamState.opam_opt t nv with | None -> raise Not_found | Some o -> match OpamFile.OPAM.dev_repo o with | None -> raise Not_found | Some pin -> pin with Not_found -> OpamGlobals.error_and_exit "\"dev-repo\" field missing in %s metadata, you'll need to specify \ the pinning location" (OpamPackage.Name.to_string name) let pin name ?(edit=false) ?version ?(action=true) pin_option_opt = let pin_option = match pin_option_opt with | Some o -> o | None -> let t = OpamState.load_state "pin-get-upstream" in get_upstream t name in let needs_reinstall = pin name ?version pin_option in with_switch_backup "pin-reinstall" @@ fun t -> OpamGlobals.msg "\n"; let updated = OpamProcess.Job.run (OpamState.update_pinned_package t ?fixed_version:version name) in if not updated then (ignore (unpin ~state:t [name]); OpamGlobals.exit 1); OpamGlobals.msg "\n"; let opam_f = OpamPath.Switch.Overlay.opam t.root t.switch name in let empty_opam = OpamFile.OPAM.( empty = with_name_opt (with_version_opt (read opam_f) None) None ) in let needs_reinstall2 = if edit || empty_opam then try OpamPinCommand.edit t name with Not_found -> (OpamGlobals.error "No valid metadata available."; ignore (unpin ~state:t [name]); OpamGlobals.exit 1) else None in if action then let t = OpamState.load_state "pin-reinstall-2" in if not (OpamPackage.has_name t.installed name) || needs_reinstall <> None || needs_reinstall2 <> None then post_pin_action t name let edit ?(action=true) name = with_switch_backup "pin-edit" @@ fun t -> match edit t name with | None -> () | Some true -> if action then post_pin_action t name | Some false -> (* Version changed: reload the state to ensure consistency *) let t = OpamState.load_state "pin-edit-2" in if action then post_pin_action t name let unpin ?(action=true) names = let reinstall = unpin names in if action && reinstall <> [] then with_switch_backup "pin-reinstall" @@ fun t -> let t,atoms = List.fold_left (fun (t,atoms) name -> try let nv = OpamPackage.max_version t.installed name in let avail = Lazy.force t.available_packages in if OpamPackage.Set.mem nv avail then {t with reinstall = OpamPackage.Set.add nv t.reinstall}, (name, Some (`Eq, OpamPackage.version nv))::atoms else t, (name, None)::atoms with Not_found -> t, atoms ) (t,[]) names in upgrade_t ~ask:true atoms t let list = list end module REPOSITORY = OpamRepositoryCommand module CONFIG = OpamConfigCommand module SWITCH = OpamSwitchCommand end let read_lock f = OpamState.check (Read_lock f) let switch_lock f = OpamState.check (Switch_lock f) let global_lock f = OpamState.check (Global_lock f) let global_then_switch_lock f = OpamState.check (Global_with_switch_cont_lock f) (** We protect each main functions with a lock depending on its access on some read/write data. *) module SafeAPI = struct let init = API.init let list ~print_short ~filter ~order ~exact_name ~case_sensitive ?depends ?reverse_depends ?recursive_depends ?resolve_depends ?depopts ?depexts pkg_str = read_lock (fun () -> API.list ~print_short ~filter ~order ~exact_name ~case_sensitive ?depends ?reverse_depends ?recursive_depends ?resolve_depends ?depopts ?depexts pkg_str ) let info ~fields ~raw_opam ~where regexps = read_lock (fun () -> API.info ~fields ~raw_opam ~where regexps) let install names add_to_roots deps_only = switch_lock (fun () -> API.install names add_to_roots deps_only) let reinstall names = switch_lock (fun () -> API.reinstall names) let upgrade names = switch_lock (fun () -> API.upgrade names) let fixup () = switch_lock API.fixup let remove ~autoremove ~force names = switch_lock (fun () -> API.remove ~autoremove ~force names) let update ~repos_only ?no_stats repos = global_lock (fun () -> API.update ~repos_only ?no_stats repos) module CONFIG = struct let env ~csh ~sexp ~fish ~inplace_path = API.CONFIG.env ~csh ~sexp ~fish ~inplace_path let setup local global = global_lock (fun () -> API.CONFIG.setup local global) let setup_list shell dot_profile = read_lock (fun () -> API.CONFIG.setup_list shell dot_profile) let exec ~inplace_path command = API.CONFIG.exec ~inplace_path command let list names = read_lock (fun () -> API.CONFIG.list names) let variable var = read_lock (fun () -> API.CONFIG.variable var) let subst files = read_lock (fun () -> API.CONFIG.subst files) end module REPOSITORY = struct let list ~short = read_lock (fun () -> API.REPOSITORY.list ~short) let add name kind address ~priority = global_lock (fun () -> API.REPOSITORY.add name kind address ~priority) let remove name = global_lock (fun () -> API.REPOSITORY.remove name) let priority name ~priority = global_lock (fun () -> API.REPOSITORY.priority name ~priority) let set_url name address = global_lock (fun () -> API.REPOSITORY.set_url name address) end module SWITCH = struct let switch ?compiler ~quiet ~warning name = global_then_switch_lock (fun () -> API.SWITCH.switch_cont ?compiler ~quiet ~warning name) let install ~quiet ~warning ~update_config switch ocaml_version = global_then_switch_lock (fun () -> API.SWITCH.install_cont ~quiet ~warning ~update_config switch ocaml_version) let import filename = switch_lock (fun () -> API.SWITCH.import filename) let export filename = read_lock (fun () -> API.SWITCH.export filename) let remove switch = global_lock (fun () -> API.SWITCH.remove switch) let reinstall switch = global_then_switch_lock (fun () -> switch, (fun () -> API.SWITCH.reinstall switch)) let list ~print_short ~installed ~all = read_lock (fun () -> API.SWITCH.list ~print_short ~installed ~all) let show () = read_lock API.SWITCH.show end module PIN = struct let pin name ?edit ?version ?action pin_option = switch_lock (fun () -> API.PIN.pin name ?edit ?version ?action pin_option) let edit ?action name = switch_lock (fun () -> API.PIN.edit ?action name) let unpin ?action names = switch_lock (fun () -> API.PIN.unpin ?action names) let list ~short () = read_lock (fun () -> API.PIN.list ~short ()) end end opam-full-1.2.2/src/client/opamAction.mli0000644000175000017500000000546012517374212017001 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) (** OPAM actions *) open OpamTypes open OpamState.Types (** Downloads the source for a package to the local cache. Returns the file or dir downloaded, or None if the download failed. *) val download_package: t -> package -> [ `Error of unit | `Successful of generic_file option ] OpamProcess.job (** Extracts and patches the source of a package *) val extract_package: t -> generic_file option -> package -> unit (** Build and install a package from its downloaded source. Returns [None] on success, [Some exn] on error. *) val build_and_install_package: t -> metadata:bool -> generic_file option -> package -> exn option OpamProcess.job (** Find out if the package source is needed for uninstall *) val removal_needs_download: t -> package -> bool (** Remove a package. *) val remove_package: t -> metadata:bool -> ?keep_build:bool -> ?silent:bool -> package -> unit OpamProcess.job (** Removes auxiliary files related to a package, after checking that they're not needed (even in other switches) *) val cleanup_package_artefacts: t -> package -> unit (* (** Remove all the packages from a solution. This includes the package to delete, to upgrade and to recompile. Return the updated state and set of all deleted packages. *) val remove_all_packages: t -> metadata:bool -> OpamSolver.solution -> (t * package_set) * [ `Successful of unit | `Exception of exn ] *) (** Compute the set of packages which will need to be downloaded to apply a solution *) val sources_needed: t -> OpamSolver.ActionGraph.t -> package_set (** Update package metadata *) val update_metadata: t -> installed:package_set -> installed_roots:package_set -> reinstall:package_set -> t opam-full-1.2.2/src/client/opamState.ml0000644000175000017500000033355112517374212016500 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamTypesBase open OpamMisc.OP open OpamProcess.Job.Op open OpamFilename.OP open OpamPackage.Set.Op let log fmt = OpamGlobals.log "STATE" fmt let slog = OpamGlobals.slog let () = OpamHTTP.register (); OpamGit.register (); OpamDarcs.register(); OpamLocal.register (); OpamHg.register () let switch_reinstall_hook = ref (fun _ -> assert false) module Types = struct type t = { partial: bool; root: OpamPath.t; switch: switch; compiler: compiler; compiler_version: compiler_version lazy_t; opams: OpamFile.OPAM.t package_map; repositories: OpamFile.Repo_config.t repository_name_map; packages: package_set; available_packages: package_set Lazy.t; aliases: OpamFile.Aliases.t; compilers: compiler_set; pinned: OpamFile.Pinned.t; installed: OpamFile.Installed.t; installed_roots: OpamFile.Installed_roots.t; reinstall: OpamFile.Reinstall.t; config: OpamFile.Config.t; package_index: OpamFile.Package_index.t; compiler_index: OpamFile.Compiler_index.t; } end type state = Types.t open Types let string_of_repositories r = OpamMisc.string_of_list OpamRepositoryName.to_string (OpamRepositoryName.Map.keys r) let print_state t = let packages p = if OpamPackage.Set.cardinal p <= 20 then OpamPackage.Set.to_string p else Printf.sprintf "%d packages" (OpamPackage.Set.cardinal p) in log "ROOT : %a" (slog OpamFilename.Dir.to_string) t.root; log "SWITCH : %a" (slog OpamSwitch.to_string) t.switch; log "COMPILER : %a" (slog OpamCompiler.to_string) t.compiler; log "COMPILERS : %a" (slog OpamCompiler.Set.to_string) t.compilers; log "REPOS : %a" (slog string_of_repositories) t.repositories; log "PACKAGES : %a" (slog packages) t.packages; log "INSTALLED : %a" (slog OpamPackage.Set.to_string) t.installed; log "ROOTS : %a" (slog OpamPackage.Set.to_string) t.installed_roots; log "REINSTALL : %a" (slog OpamPackage.Set.to_string) t.reinstall let compiler_comp t c = OpamFile.Comp.read (OpamPath.compiler_comp t.root c) let is_name_installed_aux installed name = OpamPackage.Set.exists (fun nv -> OpamPackage.name nv = name) installed let is_name_installed t name = is_name_installed_aux t.installed name let find_installed_package_by_name_aux installed name = OpamPackage.Set.find (fun nv -> OpamPackage.name nv = name) installed let find_installed_package_by_name t name = find_installed_package_by_name_aux t.installed name let find_packages_by_name t name = OpamPackage.packages_of_name t.packages name let packages_of_atoms t atoms = let check_atoms nv = let name = OpamPackage.name nv in let atoms = List.filter (fun (n,_) -> n = name) atoms in atoms <> [] && List.for_all (fun a -> OpamFormula.check a nv) atoms in (* All packages satisfying [atoms] *) OpamPackage.Set.filter check_atoms t.packages ++ OpamPackage.Set.filter check_atoms t.installed let installed_map t = OpamPackage.Name.Map.map OpamPackage.Version.Set.choose_one (OpamPackage.to_map t.installed) let dot_config t name = let global = name = OpamPackage.Name.global_config in let f = if global then OpamPath.Switch.global_config t.root t.switch else OpamPath.Switch.config t.root t.switch name in if OpamFilename.exists f then OpamFile.Dot_config.safe_read f else if not global then OpamFile.Dot_config.empty else (OpamGlobals.error "No global config file found for switch %s. \ Switch broken ?" (OpamSwitch.to_string t.switch); OpamFile.Dot_config.empty) let is_package_installed t nv = OpamPackage.Set.mem nv t.installed let jobs t = match !OpamGlobals.jobs with | None -> OpamFile.Config.jobs t.config | Some j -> j let dl_jobs t = match !OpamGlobals.dl_jobs with | None -> OpamFile.Config.dl_jobs t.config | Some j -> j let sorted_repositories t = OpamRepository.sort t.repositories let mem_repository t repo_name = OpamRepositoryName.Map.mem repo_name t.repositories let find_repository_aux repo_name repositories = try OpamRepositoryName.Map.find repo_name repositories with Not_found -> OpamGlobals.error_and_exit "%s is not a valid repository name." (OpamRepositoryName.to_string repo_name) let find_repository t repo_name = find_repository_aux repo_name t.repositories let find_repository_exn t repo_name = OpamRepositoryName.Map.find repo_name t.repositories let find_repository_opt t repo_name = try Some (find_repository_exn t repo_name) with Not_found -> None let compiler_index t = OpamRepository.compiler_index t.repositories let package_index t = OpamRepository.package_index t.repositories let package_state_one t all nv = let opam = OpamPath.opam t.root nv in let descr = OpamPath.descr t.root nv in let url = OpamPath.url t.root nv in let files = OpamPath.files t.root nv in let archive = OpamPath.archive t.root nv in if not (OpamFilename.exists opam) then [] else match all with | `all -> OpamFilename.checksum opam @ OpamFilename.checksum descr @ OpamFilename.checksum url @ OpamFilename.checksum_dir files @ OpamFilename.checksum archive | `partial true -> OpamRepository.url_checksum url @ OpamFilename.checksum_dir files @ OpamFilename.checksum archive | `partial false -> OpamRepository.url_checksum url @ OpamFilename.checksum_dir files let all_installed t = OpamSwitch.Map.fold (fun switch _ accu -> let installed_f = OpamPath.Switch.installed t.root switch in let installed = OpamFile.Installed.safe_read installed_f in installed ++ accu ) t.aliases OpamPackage.Set.empty let package_state t = let installed = OpamPackage.Set.fold (fun nv map -> let state = package_state_one t `all nv in OpamPackage.Map.add nv state map ) (all_installed t) OpamPackage.Map.empty in OpamPackage.Map.fold (fun nv (repo, prefix) map -> if OpamPackage.Map.mem nv map then map else if OpamFilename.exists (OpamPath.opam t.root nv) then let state = package_state_one t `all nv in OpamPackage.Map.add nv state map else let repo = find_repository_exn t repo in let state = OpamRepository.package_state repo prefix nv `all in OpamPackage.Map.add nv state map ) t.package_index installed let package_partial_state t nv ~archive = match package_state_one t (`partial archive) nv with | [] -> false, [] | state -> let archive = OpamPath.archive t.root nv in OpamFilename.exists archive, state let package_repository_state t = OpamPackage.Map.fold (fun nv (repo, prefix) map -> let repo = find_repository_exn t repo in match OpamRepository.package_state repo prefix nv `all with | [] -> map | state -> OpamPackage.Map.add nv state map ) t.package_index OpamPackage.Map.empty let package_repository_partial_state t nv ~archive = let repo, prefix = OpamPackage.Map.find nv t.package_index in let repo = find_repository_exn t repo in let exists_archive = OpamFilename.exists (OpamPath.Repository.archive repo nv) in exists_archive, OpamRepository.package_state repo prefix nv (`partial archive) let repository_and_prefix_of_package t nv = try let repo, prefix = OpamPackage.Map.find nv t.package_index in let repo = find_repository_exn t repo in Some (repo, prefix) with Not_found -> None let repository_of_package t nv = try let repo, _ = OpamPackage.Map.find nv t.package_index in let repo = OpamRepositoryName.Map.find repo t.repositories in Some repo with Not_found -> None let compiler_state_one t c = let comp = OpamPath.compiler_comp t.root c in let descr = OpamPath.compiler_descr t.root c in if OpamFilename.exists comp then Some (OpamFilename.checksum comp @ OpamFilename.checksum descr) else None let compiler_state t = OpamCompiler.Set.fold (fun c map -> match compiler_state_one t c with | None -> map | Some s -> OpamCompiler.Map.add c s map ) t.compilers OpamCompiler.Map.empty let compiler_repository_state t = OpamCompiler.Map.fold (fun comp (repo, prefix) map -> let repo = find_repository_exn t repo in match OpamRepository.compiler_state repo prefix comp with | [] -> map | l -> OpamCompiler.Map.add comp l map ) t.compiler_index OpamCompiler.Map.empty let repository_and_prefix_of_compiler t comp = try let repo, prefix = OpamCompiler.Map.find comp t.compiler_index in let repo = find_repository_exn t repo in Some (repo, prefix) with Not_found -> None let is_pinned t n = OpamPackage.Name.Map.mem n t.pinned let locally_pinned_package t n = let option = OpamPackage.Name.Map.find n t.pinned in let path = string_of_pin_option option in let kind = kind_of_pin_option option in match repository_kind_of_pin_kind kind with | None -> OpamSystem.internal_error "locally pinned" | Some kind -> (address_of_string path, kind) let url_of_locally_pinned_package t n = let path, kind = locally_pinned_package t n in OpamFile.URL.create kind path (* Returns the directory holding the original metadata of the package. This is a low-level function, you generally want to handle different locations, like overlays for pinned packages *) let package_repo_dir root repositories package_index nv = if OpamFilename.exists (OpamPath.opam root nv) then OpamPath.packages root nv else let repo_name, prefix = OpamPackage.Map.find nv package_index in let repo = OpamRepositoryName.Map.find repo_name repositories in OpamPath.Repository.packages repo prefix nv (* Copies package definition from the repository to the overlay *) let add_pinned_overlay ?(template=false) ?version t name = let open OpamFile in let module Ov = OpamPath.Switch.Overlay in log "Add pinning overlay for %a (template:%b, version:%a)" (slog OpamPackage.Name.to_string) name template OpamMisc.Option.Op.( slog @@ fun v -> (v >>| OpamPackage.Version.to_string) +! "none" ) version; let pkg_overlay f = f t.root t.switch name in let get_orig_meta rv = let orig = package_repo_dir t.root t.repositories t.package_index rv in let files = OpamFilename.rec_files orig in let opam_f = orig // "opam" in let url_f = orig // "url" in let files = List.filter (fun f -> f <> opam_f && f <> url_f) files in let opam = OPAM.read opam_f in let url = try Some (URL.read url_f) with e -> OpamMisc.fatal e; None in opam, url, orig, files in try match OpamPackage.Name.Map.find name t.pinned with | Version v -> let opam, url, root, files = get_orig_meta (OpamPackage.create name v) in List.iter (fun f -> OpamFilename.copy_in ~root f (pkg_overlay Ov.package)) files; OPAM.write (pkg_overlay Ov.opam) (OPAM.with_version opam v); OpamMisc.Option.iter (URL.write (pkg_overlay Ov.url)) url | _ -> let nv = OpamMisc.Option.map (OpamPackage.create name) version in let rv = (* repo version *) match nv with (* Lookup in package_index to ignore pinned versions *) | Some nv when OpamPackage.Map.mem nv t.package_index -> nv | _ -> let versions = OpamPackage.Map.fold (fun nv _ acc -> if OpamPackage.name nv = name then OpamPackage.Set.add nv acc else acc) t.package_index OpamPackage.Set.empty in OpamPackage.max_version versions name (* raises Not_found *) in let v = OpamMisc.Option.default (OpamPackage.version rv) version in let opam, _url, root, files = get_orig_meta rv in let url = url_of_locally_pinned_package t name in List.iter (fun f -> OpamFilename.copy_in ~root f (pkg_overlay Ov.package)) files; OPAM.write (pkg_overlay Ov.opam) (OPAM.with_version opam v); URL.write (pkg_overlay Ov.url) url with Not_found -> (* No original meta *) let url = url_of_locally_pinned_package t name in let version = OpamMisc.Option.default (OpamPackage.Version.of_string (if template then "0.1" else "~unknown")) version in let nv = OpamPackage.create name version in let opam = if template then OPAM.template nv else OPAM.create nv in OPAM.write (pkg_overlay (if template then Ov.tmp_opam else Ov.opam)) opam; URL.write (pkg_overlay Ov.url) url let overlay_of_name t name = let f = OpamPath.Switch.Overlay.opam t.root t.switch name in if not (OpamFilename.exists f) then (log "overlay missing for %s !" (OpamPackage.Name.to_string name); add_pinned_overlay t name); f let version_of_pin t name = function | Version v -> v | _ -> let overlay = overlay_of_name t name in let opam = OpamFile.OPAM.read overlay in if OpamFile.OPAM.version_opt opam = None then let nv = try OpamPackage.max_version t.packages name with Not_found -> OpamPackage.create name (OpamPackage.Version.of_string "0") in OpamGlobals.warning "Setting missing version in %s to %s" (OpamFilename.to_string overlay) (OpamPackage.Version.to_string @@ OpamPackage.version nv); OpamFile.OPAM.(write overlay (with_version opam (OpamPackage.version nv))); OpamPackage.version nv else OpamFile.OPAM.version opam let pinned t name = let v = version_of_pin t name (OpamPackage.Name.Map.find name t.pinned) in OpamPackage.create name v let pinned_opt t name = try Some (pinned t name) with Not_found -> None let is_locally_pinned t name = try match OpamPackage.Name.Map.find name t.pinned with | Version _ -> false | _ -> true with Not_found -> false let opam_opt t nv = let name = OpamPackage.name nv in let base () = try Some (OpamPackage.Map.find nv t.opams) with Not_found -> if OpamPackage.Set.mem nv t.installed then (OpamGlobals.warning "no package description left for %s" (OpamPackage.to_string nv); Some (OpamFile.OPAM.create nv)) else None in let overlay = OpamPath.Switch.Overlay.opam t.root t.switch name in if OpamFilename.exists overlay then let o = OpamFile.OPAM.read overlay in if OpamFile.OPAM.version o = OpamPackage.version nv then Some o else if OpamPackage.Map.mem nv t.opams then (log "Looking for %s which is pinned to %s (not using overlay)" (OpamPackage.to_string nv) (OpamPackage.Version.to_string (OpamFile.OPAM.version o)); base ()) else (log "Opam file for %s not found: using the overlay even if it's for %s" (OpamPackage.to_string nv) (OpamPackage.Version.to_string (OpamFile.OPAM.version o)); Some (OpamFile.OPAM.with_version o (OpamPackage.version nv))) else base () let opam t nv = match opam_opt t nv with | None -> OpamPackage.unknown (OpamPackage.name nv) (Some (OpamPackage.version nv)) | Some nv -> nv let locate_meta overlay global repo exists t nv = let name = OpamPackage.name nv in if Some nv = pinned_opt t name && OpamFilename.exists_dir (OpamPath.Switch.Overlay.package t.root t.switch name) then let meta = overlay t.root t.switch name in if exists meta then Some meta else None else let meta = global t.root nv in if exists meta then Some meta else try let r, prefix = OpamPackage.Map.find nv t.package_index in let r = find_repository_exn t r in let meta = repo r prefix nv in if exists meta then Some meta else None with Not_found -> None let descr_file = locate_meta OpamPath.Switch.Overlay.descr OpamPath.descr OpamPath.Repository.descr OpamFilename.exists let url_file = locate_meta OpamPath.Switch.Overlay.url OpamPath.url OpamPath.Repository.url OpamFilename.exists let files = locate_meta OpamPath.Switch.Overlay.files OpamPath.files OpamPath.Repository.files OpamFilename.exists_dir let install_metadata t nv = if is_pinned t (OpamPackage.name nv) || OpamFilename.exists (OpamPath.opam t.root nv) then () else let opam = opam t nv in OpamFile.OPAM.write (OpamPath.opam t.root nv) opam; let onsome f = function None -> () | Some x -> f x in onsome (fun f -> OpamFile.Descr.write (OpamPath.descr t.root nv) (OpamFile.Descr.read f)) (descr_file t nv); onsome (fun f -> OpamFile.URL.write (OpamPath.url t.root nv) (OpamFile.URL.read f)) (url_file t nv); onsome (fun d -> OpamFilename.copy_dir ~src:d ~dst:(OpamPath.files t.root nv)) (files t nv) let remove_metadata t packages = let all_installed = all_installed t in let packages = packages -- all_installed in OpamPackage.Set.iter (fun nv -> let dir = OpamPath.packages t.root nv in OpamFilename.rmdir dir; let parent = OpamFilename.dirname_dir dir in if OpamFilename.dir_is_empty parent then OpamFilename.rmdir parent; let archive = OpamPath.archive t.root nv in OpamFilename.remove archive; ) packages let find_opam_file_in_source name dir = List.fold_left (function | None -> fun f -> if OpamFilename.exists f then Some f else None | some -> fun _ -> some) None [ dir / (OpamPackage.Name.to_string name ^ ".opam") // "opam"; dir // (OpamPackage.Name.to_string name ^ ".opam"); dir / "opam" // "opam"; dir // "opam" ] (* Returns [opam, descr_file, files_dir]. We don't consider [url] since this is for pinned packages. if [root], don't look for a subdir [opam] to find [files] and [descr]. *) let local_opam ?(root=false) ?fixed_version ?copy_invalid_to name dir = let has_dir d = if OpamFilename.exists_dir d then Some d else None in let has_file f = if OpamFilename.exists f then Some f else None in let metadir = if root then dir else match has_dir (dir / (OpamPackage.Name.to_string name ^ ".opam")) with | Some d -> d | None -> dir / "opam" in let opam_file = if root then has_file (dir // "opam") else find_opam_file_in_source name dir in let opam = match opam_file with | None -> None | Some local_opam -> try let opam = OpamFile.OPAM.read local_opam in let opam = OpamFile.OPAM.with_name opam name in let opam = match fixed_version with | None -> opam | Some v -> OpamFile.OPAM.with_version opam v in Some opam with e -> OpamMisc.fatal e; match copy_invalid_to with | Some dst -> OpamGlobals.warning "Errors in opam file from %s source, ignored (fix with 'opam pin \ edit')" (OpamPackage.Name.to_string name); OpamFilename.copy ~src:local_opam ~dst; None | None -> None in opam, has_file (metadir // "descr"), has_dir (metadir / "files") let remove_overlay t name = OpamFilename.rmdir (OpamPath.Switch.Overlay.package t.root t.switch name) let has_url_overlay t name = OpamFilename.exists (OpamPath.Switch.Overlay.url t.root t.switch name) let dev_package t nv = if has_url_overlay t (OpamPackage.name nv) && pinned_opt t (OpamPackage.name nv) = Some nv then OpamPath.Switch.dev_package t.root t.switch (OpamPackage.name nv) else OpamPath.dev_package t.root nv let pinned_packages t = OpamPackage.Name.Map.fold (fun name _ acc -> try OpamPackage.Set.add (pinned t name) acc with e -> OpamMisc.fatal e; if !OpamGlobals.strict then OpamGlobals.error_and_exit "Invalid pinned package %s" (OpamPackage.Name.to_string name) else OpamGlobals.error "Ignoring invalid pinned package %s" (OpamPackage.Name.to_string name); acc) t.pinned OpamPackage.Set.empty let descr_opt t nv = OpamMisc.Option.map OpamFile.Descr.read (descr_file t nv) let descr t nv = match descr_file t nv with | None -> OpamFile.Descr.empty | Some f -> OpamFile.Descr.read f let url t nv = OpamMisc.Option.map OpamFile.URL.read (url_file t nv) (* For documentation *) let global_variable_names = [ "ocaml-version", "The version of the currently used OCaml compiler"; "opam-version", "The currently running OPAM version"; "compiler", "The name of the current OCaml compiler (may be more \ specific than the version, eg: \"4.01.0+fp\", or \ \"system\")"; "preinstalled", "Whether the compiler was preinstalled on the system, \ or installed by OPAM"; "switch", "The local name (alias) of the current switch"; "jobs", "The number of parallel jobs set up in OPAM \ configuration"; "ocaml-native", "Whether the OCaml native compilers are available"; "ocaml-native-tools", "Whether the native \".opt\" version of the OCaml \ toolchain is available"; "ocaml-native-dynlink", "Whether native dynlink is available on this \ installation"; "arch", "The current arch, as returned by \"uname -m\""; ] let package_variable_names = [ "name", "Name of the package"; "version", "Version of the package"; "depends", "Resolved direct dependencies of the package"; "installed", "Whether the package is installed"; "enable", "Takes the value \"enable\" or \"disable\" depending on whether \ the package is installed"; "pinned", "Whether the package is pinned"; "bin", "Binary directory for this package"; "sbin", "System binary directory for this package"; "lib", "Library directory for this package"; "man", "Man directory for this package"; "doc", "Doc directory for this package"; "share", "Share directory for this package"; "etc", "Etc directory for this package"; "build", "Directory where the package was built"; "hash", "Hash of the package archive"; ] let string str = Some (S str) let bool b = Some (B b) let int i = string (string_of_int i) let is_global_conf v = OpamVariable.Full.package v = OpamPackage.Name.global_config (* Read the env variables *) let get_env_var v = let var_str = OpamVariable.to_string (OpamVariable.Full.variable v) in let var_hook = if is_global_conf v then OpamMisc.string_map (function '-' -> '_' | c -> c) var_str else Printf.sprintf "%s_%s" (OpamPackage.Name.to_string (OpamVariable.Full.package v)) var_str in try match OpamMisc.getenv ("OPAMVAR_" ^ var_hook) with | "true" | "1" -> bool true | "false" | "0" -> bool false | s -> string s with Not_found -> None (* filter handling *) let rec resolve_variable t ?opam:opam_arg local_variables v = let dirname dir = string (OpamFilename.Dir.to_string dir) in let read_var v = let var = OpamVariable.Full.variable v in let c = dot_config t (OpamVariable.Full.package v) in try OpamFile.Dot_config.variable c var with Not_found -> None in let get_local_var v = if not (is_global_conf v) then None else let var = OpamVariable.Full.variable v in try match OpamVariable.Map.find var local_variables with | None -> raise Exit (* Variable explicitly undefined *) | some -> some with Not_found -> None in let get_features_var opam v = let to_str opam = OpamPackage.to_string @@ OpamPackage.create (OpamFile.OPAM.name opam) (OpamFile.OPAM.version opam) in let features = OpamFile.OPAM.features opam in try let v, _descr, filt = List.find (fun (id,_,_) -> id = v) features in let local_variables = (* Avoid recursion *) OpamVariable.Map.add v None local_variables in try Some (OpamFilter.eval (resolve_variable t ~opam local_variables) filt) with Failure _ -> OpamGlobals.warning "Feature %s of %s didn't resolve%s" (OpamVariable.to_string v) (to_str opam) (match opam_arg with None -> "" | Some o -> Printf.sprintf " (referred to from %s)" (to_str o)); None with Not_found -> None in let get_global_var v = if not (is_global_conf v) then None else match OpamVariable.to_string (OpamVariable.Full.variable v) with | "ocaml-version" -> string (OpamCompiler.Version.to_string (Lazy.force t.compiler_version)) | "opam-version" -> string (OpamVersion.to_string OpamVersion.current) | "compiler" -> string (OpamCompiler.to_string t.compiler) | "preinstalled" -> bool (OpamFile.Comp.preinstalled (compiler_comp t t.compiler)) | "switch" -> string (OpamSwitch.to_string t.switch) | "jobs" -> int (jobs t) | "ocaml-native" -> if t.compiler = OpamCompiler.system then bool (Lazy.force OpamSystem.ocaml_native_available) else bool (OpamFilename.exists (OpamPath.Switch.bin t.root t.switch//"ocamlopt")) | "ocaml-native-tools" -> if t.compiler = OpamCompiler.system then bool (Lazy.force OpamSystem.ocaml_opt_available) else bool (OpamFilename.exists (OpamPath.Switch.bin t.root t.switch//"ocamlc.opt")) | "ocaml-native-dynlink" -> if t.compiler = OpamCompiler.system then bool (Lazy.force OpamSystem.ocaml_natdynlink_available) else bool (OpamFilename.exists (OpamPath.Switch.lib_dir t.root t.switch /"ocaml"//"dynlink.cmxa")) | "arch" -> string (OpamGlobals.arch ()) | _ -> None in let get_package_var opam v = if is_global_conf v then None else let var_str = OpamVariable.to_string (OpamVariable.Full.variable v) in let name = OpamVariable.Full.package v in let opam = (* ensure opam, if not None, corresponds to name *) match opam with | Some o when OpamFile.OPAM.name o = name -> opam | _ -> try opam_opt t (find_installed_package_by_name t name) with Not_found -> None in let feat = match opam with | Some o -> get_features_var o (OpamVariable.Full.variable v) | None -> None in if feat <> None then feat else let get_nv opam = OpamPackage.create name (OpamFile.OPAM.version opam) in match var_str, opam with | "installed", Some _ -> bool true | "installed", None -> bool false | "pinned", _ -> bool (OpamPackage.Name.Map.mem name t.pinned) | "name", _ -> if OpamPackage.has_name t.packages name then string (OpamPackage.Name.to_string name) else None | _, None -> None | "bin", _ -> dirname (OpamPath.Switch.bin t.root t.switch) | "sbin", _ -> dirname (OpamPath.Switch.sbin t.root t.switch) | "lib", _ -> dirname (OpamPath.Switch.lib t.root t.switch name) | "man", _ -> dirname (OpamPath.Switch.man_dir t.root t.switch) | "doc", _ -> dirname (OpamPath.Switch.doc t.root t.switch name) | "share", _ -> dirname (OpamPath.Switch.share t.root t.switch name) | "etc", _ -> dirname (OpamPath.Switch.etc t.root t.switch name) | "build", Some opam -> dirname (OpamPath.Switch.build t.root t.switch (get_nv opam)) | "version", Some opam -> let ver = OpamFile.OPAM.version opam in string (OpamPackage.Version.to_string ver) | "depends", Some opam -> let deps = OpamFormula.atoms (filter_deps (OpamFile.OPAM.depends opam)) @ OpamFormula.atoms (filter_deps (OpamFile.OPAM.depopts opam)) in let installed_deps = OpamMisc.filter_map (fun (n,cstr) -> try let nv = OpamPackage.Set.find (fun nv -> OpamPackage.name nv = n) t.installed in let version = OpamPackage.version nv in match cstr with | None -> Some nv | Some (op,v) when OpamFormula.eval_relop op version v -> Some nv | Some _ -> None with Not_found -> None) deps in string (OpamMisc.sconcat_map " " OpamPackage.to_string installed_deps) | "hash", Some opam -> (try let nv = get_nv opam in let f = OpamPath.archive t.root nv in if OpamFilename.exists f then string (OpamFilename.digest f) else string "" with Not_found -> string "") | _, _ -> None in let make_package_local v = (* [var] within the opam file of [pkg] is tried as [pkg:var] *) match is_global_conf v, opam_arg with | true, Some opam -> OpamVariable.Full.create (OpamFile.OPAM.name opam) (OpamVariable.Full.variable v) | _ -> v in let skip _ = None in let v' = make_package_local v in let contents = try List.fold_left (function None -> (fun (f,v) -> f v) | r -> (fun _ -> r)) None [ get_local_var, v; get_env_var, v; (if v' <> v then get_env_var else skip), v'; read_var, v; (if v' <> v then read_var else skip), v'; get_global_var, v; get_package_var opam_arg, v'; ] with Exit -> None in contents let filter_env ?opam ?(local_variables=OpamVariable.Map.empty) t = resolve_variable t ?opam local_variables let redirect t repo = if repo.repo_kind <> `http then None else let redirect = repo |> OpamPath.Repository.repo |> OpamFile.Repo.safe_read |> OpamFile.Repo.redirect in let redirect = List.fold_left (fun acc (redirect, filter) -> if OpamFilter.opt_eval_to_bool (filter_env t) filter then (redirect, filter) :: acc else acc ) [] redirect in match redirect with | [] -> None | (r,f) :: _ -> let config_f = OpamPath.Repository.config repo in let config = OpamFile.Repo_config.read config_f in let repo_address = address_of_string r in if repo_address <> config.repo_address then ( let config = { config with repo_address } in OpamFile.Repo_config.write config_f config; Some (config, f) ) else None let copy_files t nv dst = match files t nv with | None -> () | Some src -> OpamFilename.copy_files ~src ~dst let consistent_ocaml_version t opam = let atom (r,v) = match OpamCompiler.Version.to_string v with | "system" -> begin match r with | `Eq -> t.compiler = OpamCompiler.system | `Neq -> t.compiler <> OpamCompiler.system | _ -> OpamSystem.internal_error "%s is not a valid constraint for the system compiler \ (only '=' and '!=' are valid)." (OpamFormula.string_of_relop r) end | _ -> OpamCompiler.Version.eval_relop r (Lazy.force t.compiler_version) v in match OpamFile.OPAM.ocaml_version opam with | None -> true | Some c -> OpamFormula.eval atom c let consistent_os opam = match OpamFile.OPAM.os opam with | Empty -> true | f -> let atom (b, os) = let ($) = if b then (=) else (<>) in os $ OpamGlobals.os_string () in OpamFormula.eval atom f let consistent_available_field t opam = OpamFilter.eval_to_bool ~default:false (filter_env ~opam t) (OpamFile.OPAM.available opam) (* List the packages which do fulfil the compiler and OS constraints *) let available_packages t = let filter nv = match opam_opt t nv with | None -> false | Some opam -> let has_repository () = OpamPackage.Map.mem nv t.package_index || OpamPackage.Name.Map.mem (OpamPackage.name nv) t.pinned in consistent_ocaml_version t opam && consistent_os opam && consistent_available_field t opam && has_repository () in let pinned = pinned_packages t in let pinned_names = OpamPackage.Name.Map.fold (fun n _ s -> OpamPackage.Name.Set.add n s) t.pinned OpamPackage.Name.Set.empty in let packages = pinned ++ OpamPackage.Set.filter (fun nv -> not (OpamPackage.Name.Set.mem (OpamPackage.name nv) pinned_names)) t.packages in OpamPackage.Set.filter filter packages (* Display a meaningful error for a package that doesn't exist *) let unknown_package t (name, _ as atom) = if OpamPackage.Set.exists (fun nv -> OpamPackage.name nv = name) t.packages then Printf.sprintf "No package matches %s." (OpamFormula.short_string_of_atom atom) else Printf.sprintf "No package named %s found." (OpamPackage.Name.to_string name) (* Display a meaningful error for an unavailable package *) let unavailable_reason t (name, _ as atom) = let reasons () = let candidates = OpamPackage.Set.filter (OpamFormula.check atom) t.packages in let nv = OpamPackage.max_version candidates name in let r = let opam = opam t nv in (if consistent_ocaml_version t opam then [] else [ Printf.sprintf "it requires OCaml %s" (OpamFormula.string_of_formula (fun (op,v) -> OpamFormula.string_of_relop op ^ " " ^ OpamCompiler.Version.to_string v) (match OpamFile.OPAM.ocaml_version opam with | Some v -> v | None -> assert false)) ]) @ (if consistent_os opam then [] else [ Printf.sprintf "your OS doesn't match %s" (OpamFormula.string_of_formula (fun (b,s) -> (if b then "= " else "!= ") ^ s) (OpamFile.OPAM.os opam)) ]) @ (if consistent_available_field t opam then [] else [ Printf.sprintf "your system doesn't comply with %s" (OpamFilter.to_string (OpamFile.OPAM.available opam)) ]) in match r with | [] -> raise Not_found | [r] -> " because " ^ r ^ "." | rs -> " because:\n" ^ OpamMisc.itemize ~bullet:" - " (fun x -> x) rs in try Printf.sprintf "%s is not available%s" (OpamFormula.short_string_of_atom atom) (reasons ()) with Not_found -> try let pin = OpamPackage.Name.Map.find name t.pinned in Printf.sprintf "%s is not available because the package is pinned to %s." (OpamFormula.short_string_of_atom atom) (match pin with | Version v -> Printf.sprintf "version %s" (OpamPackage.Version.to_string v) | _ -> Printf.sprintf "%s, version %s" (string_of_pin_option pin) (OpamPackage.Version.to_string (version_of_pin t name pin))) with Not_found -> unknown_package t atom let static_base_packages = List.map OpamPackage.Name.of_string [ "base-unix"; "base-bigarray"; "base-threads" ] let create_system_compiler_description root = match OpamCompiler.get_system () with | None -> () | Some current -> log "create-system-compiler-description %a" (slog OpamCompiler.to_string) current; match Lazy.force OpamSystem.system_ocamlc_where with | None -> log "System compiler found but didn't answer to -where ??" | Some libdir -> let name = OpamCompiler.system in (* XXX legacy name: should be [current], but the change would have lots of implications *) let version = OpamCompiler.version current in let comp = OpamPath.compiler_comp root name in OpamFilename.remove comp; let f = OpamFile.Comp.create_preinstalled name version (if !OpamGlobals.no_base_packages then [] else static_base_packages) [ "CAML_LD_LIBRARY_PATH", "=", "%{lib}%/stublibs" ^ String.make 1 OpamSystem.path_sep ^ Filename.concat libdir "stublibs" ] in OpamFile.Comp.write comp f let system_needs_upgrade_displayed = ref false let system_needs_upgrade t = t.compiler = OpamCompiler.system && match OpamCompiler.get_system () with | None -> if not !system_needs_upgrade_displayed then ( system_needs_upgrade_displayed := true; OpamGlobals.error "You current switch uses the system compiler, but no OCaml compiler \ has been found in the current path.\n\ You should either:\n\ \ (i) reinstall OCaml version %s on your system; or\n\ \ (ii) use 'opam switch ' to use a local OCaml compiler." (OpamCompiler.Version.to_string (Lazy.force t.compiler_version)) ); false | Some c -> OpamFilename.exists (OpamPath.compiler_comp t.root t.compiler) (* XXX name of the compiler is replaced with 'system' for legacy reasons, so we'll skim over differences in suffix-versions! *) && Lazy.force t.compiler_version <> OpamCompiler.version c let read_repositories root config = let names = OpamFile.Config.repositories config in List.fold_left (fun map repo_name -> let repo = OpamFile.Repo_config.read (OpamPath.Repository.raw_config root repo_name) in OpamRepositoryName.Map.add repo_name repo map ) OpamRepositoryName.Map.empty names (* load partial state to be able to read env variables *) let load_env_state call_site = log "LOAD-ENV-STATE(%s)" call_site; let root = OpamPath.root () in let config_p = OpamPath.config root in let config = OpamFile.Config.read config_p in let switch = match !OpamGlobals.switch with | `Command_line s | `Env s -> OpamSwitch.of_string s | `Not_set -> OpamFile.Config.switch config in let aliases = OpamFile.Aliases.safe_read (OpamPath.aliases root) in let compiler = try OpamSwitch.Map.find switch aliases with Not_found -> OpamGlobals.error_and_exit "The current switch (%s) is an unknown compiler switch." (OpamSwitch.to_string switch) in let partial = true in (* evertything else is empty *) let compilers = OpamCompiler.Set.empty in let repositories = OpamRepositoryName.Map.empty in let compiler_version = lazy (OpamCompiler.Version.of_string "none") in let opams = OpamPackage.Map.empty in let packages = OpamPackage.Set.empty in let available_packages = lazy OpamPackage.Set.empty in let installed = OpamPackage.Set.empty in let installed_roots = OpamPackage.Set.empty in let reinstall = OpamPackage.Set.empty in let pinned = OpamPackage.Name.Map.empty in let package_index = OpamPackage.Map.empty in let compiler_index = OpamCompiler.Map.empty in { partial; root; switch; compiler; compiler_version; repositories; opams; packages; available_packages; installed; installed_roots; reinstall; config; aliases; pinned; compilers; package_index; compiler_index; } let base_package_names t = let comp = compiler_comp t t.compiler in let atoms = OpamFormula.atoms (OpamFile.Comp.packages comp) in OpamPackage.Name.Set.of_list (List.map fst atoms) let base_packages t = let comp = compiler_comp t t.compiler in let atoms = OpamFormula.atoms (OpamFile.Comp.packages comp) in let candidates = packages_of_atoms t atoms in List.fold_left (fun acc (name,_ as atom) -> if is_pinned t name then (* Allow overriding of base package through pinning *) OpamPackage.Set.add (pinned t name) acc else let nvs = OpamPackage.packages_of_name candidates name in if OpamPackage.Set.is_empty nvs then (OpamGlobals.error "Base package %s of compiler %s not found! Ignored." (OpamFormula.short_string_of_atom atom) (OpamCompiler.to_string t.compiler); acc) else let installed = nvs %% t.installed in if OpamPackage.Set.is_empty installed then OpamPackage.Set.add (OpamPackage.Set.choose nvs) acc else installed ++ acc ) OpamPackage.Set.empty atoms let is_compiler_installed t comp = OpamSwitch.Map.exists (fun _ c -> c = comp) t.aliases let is_switch_installed t switch = OpamSwitch.Map.mem switch t.aliases let universe t action = let opams = (* Read overlays of pinned packages *) OpamPackage.Name.Map.fold (fun name pin map -> let v = version_of_pin t name pin in let overlay = OpamPath.Switch.Overlay.opam t.root t.switch name in if OpamFilename.exists overlay then OpamPackage.Map.add (OpamPackage.create name v) (OpamFile.OPAM.read overlay) map else map) t.pinned t.opams in let base = base_packages t in { u_packages = t.installed ++ t.packages; u_action = action; u_installed = t.installed; u_available = Lazy.force t.available_packages; u_depends = OpamPackage.Map.map OpamFile.OPAM.depends opams; u_depopts = OpamPackage.Map.map OpamFile.OPAM.depopts opams; u_conflicts = OpamPackage.Map.map OpamFile.OPAM.conflicts opams; u_installed_roots = t.installed_roots; u_pinned = pinned_packages t; u_base = base; } let string_of_cnf string_of_atom cnf = let string_of_clause c = Printf.sprintf "%s" (OpamMisc.sconcat_map " | " string_of_atom (List.rev c)) in Printf.sprintf "%s" (OpamMisc.sconcat_map " , " string_of_clause (List.rev cnf)) let string_of_conjunction string_of_atom c = Printf.sprintf "%s" (OpamMisc.sconcat_map " , " string_of_atom (List.rev c)) let dump_state t oc = let opams = (* Read overlays of pinned packages *) OpamPackage.Name.Map.fold (fun name pin map -> let v = version_of_pin t name pin in let overlay = OpamPath.Switch.Overlay.opam t.root t.switch name in if OpamFilename.exists overlay then OpamPackage.Map.add (OpamPackage.create name v) (OpamFile.OPAM.read overlay) map else map) t.pinned t.opams in let depends = OpamPackage.Map.map OpamFile.OPAM.depends opams in let depopts = OpamPackage.Map.map OpamFile.OPAM.depopts opams in let conflicts = OpamPackage.Map.map OpamFile.OPAM.conflicts opams in let maintainers = OpamPackage.Map.map OpamFile.OPAM.maintainer opams in let base = base_packages t in let filter _ = true in let aux package = Printf.fprintf oc "package: %s\n" (OpamPackage.name_to_string package); Printf.fprintf oc "version: %s\n" (OpamPackage.version_to_string package); (try let m = OpamPackage.Map.find package maintainers in Printf.fprintf oc "maintainer: %s\n" (string_of_conjunction (fun a -> a) m); with Not_found -> () ); if OpamPackage.Set.mem package base then Printf.fprintf oc "base: true\n"; (try let d = OpamPackage.Map.find package depends in let formula = (OpamFormula.formula_of_extended ~filter d) in match OpamFormula.to_cnf formula with |[] -> () |[[]] -> () |dd -> Printf.fprintf oc "depends: %s\n" (string_of_cnf OpamFormula.string_of_atom dd) with Not_found -> () ); (try let d = OpamPackage.Map.find package depopts in let formula = (OpamFormula.formula_of_extended ~filter d) in match OpamFormula.to_cnf formula with |[] -> () |[[]] -> () |dd -> Printf.fprintf oc "recommends: %s\n" (string_of_cnf OpamFormula.string_of_atom dd) with Not_found -> () ); (try let c = OpamPackage.Map.find package conflicts in let n = OpamPackage.name package in match (n,None)::(OpamFormula.to_conjunction c) with |[] -> () |cc -> Printf.fprintf oc "conflicts: %s\n" (string_of_conjunction OpamFormula.string_of_atom cc); with Not_found -> () ); Printf.fprintf oc "\n"; in OpamPackage.Set.iter aux (Lazy.force t.available_packages) let installed_versions t name = OpamSwitch.Map.fold (fun switch _ map -> let installed = OpamFile.Installed.safe_read (OpamPath.Switch.installed t.root switch) in if is_name_installed_aux installed name then let nv = find_installed_package_by_name_aux installed name in if OpamPackage.Map.mem nv map then let aliases = OpamPackage.Map.find nv map in let map = OpamPackage.Map.remove nv map in OpamPackage.Map.add nv (switch :: aliases) map else OpamPackage.Map.add nv [switch] map else map ) t.aliases OpamPackage.Map.empty let installed_timestamp t name = let instfile = OpamPath.Switch.install t.root t.switch name in (Unix.stat (OpamFilename.to_string instfile)).Unix.st_mtime (* Checks: * correct opam version * only installed packages have something in $repo/tmp * only installed packages have something in $opam/pinned.cache *) let clean_dir dir nv = if OpamFilename.exists_dir dir then ( log "%a exists although %a is not installed. Removing it." (slog OpamFilename.Dir.to_string) dir (slog OpamPackage.to_string) nv; OpamFilename.rmdir dir ) let clean_file file nv = if OpamFilename.exists file then ( log "%a exists although %a is not installed. Removing it." (slog OpamFilename.to_string) file (slog OpamPackage.to_string) nv; OpamFilename.remove file ) let global_dev_packages t = let dir = OpamPath.dev_packages_dir t.root in let dirs = OpamFilename.dirs dir in List.fold_left (fun map dir -> match OpamPackage.of_dirname dir with | None -> OpamGlobals.note "Removing %s" (OpamFilename.Dir.to_string dir); OpamFilename.rmdir dir; map | Some nv -> OpamPackage.Map.add nv dir map ) OpamPackage.Map.empty dirs let switch_dev_packages t = List.fold_left (fun map dir -> try let name = OpamPackage.Name.of_string @@ OpamFilename.Base.to_string @@ OpamFilename.basename_dir dir in OpamPackage.Map.add (pinned t name) dir map with Failure _ | Not_found -> OpamGlobals.note "Removing %s" (OpamFilename.Dir.to_string dir); OpamFilename.rmdir dir; map ) OpamPackage.Map.empty (OpamFilename.dirs (OpamPath.Switch.dev_packages_dir t.root t.switch)) let keys map = OpamPackage.Map.fold (fun nv _ set -> OpamPackage.Set.add nv set ) map OpamPackage.Set.empty let is_dev_package t nv = match url t nv with | None -> false | Some url -> match OpamFile.URL.kind url with | `http -> false | _ -> true let dev_packages t = let global = global_dev_packages t in let switch = switch_dev_packages t in let all = keys global ++ keys switch in OpamPackage.Set.filter (is_dev_package t) all (* Check that the dev packages are installed -- if not, just remove the temporary files. *) let global_consistency_checks t = let pkgdir = OpamPath.dev_packages_dir t.root in let pkgdirs = OpamFilename.dirs pkgdir in let stale_pkgdirs = List.filter (fun dir -> match OpamPackage.of_dirname dir with | None -> true | Some nv -> not (OpamPackage.Set.mem nv t.installed) && try OpamPackage.Name.Map.find (OpamPackage.name nv) t.pinned <> Version (OpamPackage.version nv) with Not_found -> true) pkgdirs in List.iter (fun d -> log "Stale dev directory %s, removing" (OpamFilename.Dir.to_string d); OpamFilename.rmdir d) stale_pkgdirs; List.iter (fun f -> log "Stale file %s found, Removing\n" (OpamFilename.to_string f); OpamFilename.remove f) (OpamFilename.files pkgdir); let aliases = OpamFile.Aliases.safe_read (OpamPath.aliases t.root) in if OpamSwitch.Map.exists (fun _ c -> c = OpamCompiler.system) aliases then let comp_f = OpamPath.compiler_comp t.root OpamCompiler.system in if not (OpamFilename.exists comp_f) then ( OpamGlobals.msg "Regenerating the system compiler description.\n"; create_system_compiler_description t.root; ) let switch_consistency_checks t = let cleanup_dir title dir filter = let dirs = OpamFilename.dirs dir in let stale_dirs = List.filter (fun d -> try let name = OpamPackage.Name.of_string (OpamFilename.Base.to_string (OpamFilename.basename_dir d)) in filter name with Failure _ -> true) dirs in List.iter (fun d -> log "Stale %s directory %s, removing" title (OpamFilename.Dir.to_string d); OpamFilename.rmdir d) stale_dirs; List.iter (fun f -> OpamGlobals.error "Removing %s.\n" (OpamFilename.to_string f); OpamFilename.remove f) (OpamFilename.files dir) in cleanup_dir "dev" (OpamPath.Switch.dev_packages_dir t.root t.switch) (fun name -> not (is_name_installed t name) && not (is_pinned t name)); cleanup_dir "overlay" (OpamPath.Switch.Overlay.dir t.root t.switch) (fun name -> not (is_pinned t name) && try let opam = OpamFile.OPAM.read (OpamPath.Switch.Overlay.opam t.root t.switch name) in let nv = OpamPackage.create (OpamFile.OPAM.name opam) (OpamFile.OPAM.version opam) in not (OpamPackage.Set.mem nv t.installed) || OpamPackage.Map.mem nv t.opams (* this package has upstream metadata *) with e -> OpamMisc.fatal e; true) type cache = { cached_opams: OpamFile.OPAM.t OpamPackage.Map.t; } let check_marshaled_file file = let ic = open_in_bin (OpamFilename.to_string file) in let this_magic = OpamVersion.magic () in let magic_len = String.length this_magic in let file_magic = let b = Bytes.create magic_len in really_input ic b 0 magic_len; Bytes.to_string b in if file_magic <> this_magic then ( close_in ic; OpamSystem.internal_error "Wrong magic string in the cache (actual:%s expected:%s)." file_magic this_magic; ); let header = Bytes.create Marshal.header_size in really_input ic header 0 Marshal.header_size; let expected_size = magic_len + Marshal.total_size header 0 in let current_size = in_channel_length ic in if not (expected_size = current_size) then ( close_in ic; OpamGlobals.error "The local-state cache is corrupted, removing it."; OpamSystem.internal_error "Corrupted cache"; ); seek_in ic magic_len; ic let marshal_from_file file = try let chrono = OpamGlobals.timer () in let ic = check_marshaled_file file in let (cache: cache) = Marshal.from_channel ic in close_in ic; log "Loaded %a in %.3fs" (slog OpamFilename.to_string) file (chrono ()); Some cache.cached_opams with e -> OpamMisc.fatal e; log "Invalid cache, removing: %a" (slog Printexc.to_string) e; OpamFilename.remove file; None let save_state ~update t = let chrono = OpamGlobals.timer () in let file = OpamPath.state_cache t.root in OpamFilename.remove file; if update then ( log "Updating the cache of metadata (%s) ...\n" (OpamFilename.prettify file); ) else log "Creating a cache of metadata in %s ...\n" (OpamFilename.prettify file); let oc = open_out_bin (OpamFilename.to_string file) in output_string oc (OpamVersion.magic ()); Marshal.to_channel oc { cached_opams = t.opams } [Marshal.No_sharing]; close_out oc; log "%a written in %.3fs" (slog OpamFilename.prettify) file (chrono ()) let remove_state_cache () = let root = OpamPath.root () in let file = OpamPath.state_cache root in OpamFilename.remove file let reinstall_system_compiler t = log "reinstall-system-compiler"; let continue = OpamGlobals.confirm "Your system compiler has been changed. Do you want to upgrade \ your OPAM installation ?" in if continue then ( (* Update system.comp *) create_system_compiler_description t.root; (* Reinstall all system compiler switches *) OpamSwitch.Map.iter (fun s a -> if a = OpamCompiler.system then ( OpamGlobals.header_msg "Upgrading %s" (OpamSwitch.to_string s); !switch_reinstall_hook s ) ) t.aliases ) else OpamGlobals.exit 1 let upgrade_to_1_1_hook = ref (fun () -> assert false) let upgrade_to_1_2_hook = ref (fun () -> assert false) (* Loads the global config file and update some global references in OpamGlobals *) let load_config root = let config_p = OpamPath.config root in let config = let config = OpamFile.Config.read config_p in let config_version = OpamFile.Config.opam_version config in if config_version <> OpamVersion.current_nopatch then ( if OpamVersion.(compare current config_version) < 0 && not !OpamGlobals.skip_version_checks then OpamGlobals.error_and_exit "%s reports a newer OPAM version, aborting." (OpamFilename.Dir.to_string (OpamPath.root ())); (* opam has been updated, so refresh the configuration file and clean-up the cache. *) if OpamVersion.compare config_version (OpamVersion.of_string "1.2") < 0 then !upgrade_to_1_2_hook (); let config = OpamFile.Config.with_current_opam_version config in OpamFile.Config.write config_p config; remove_state_cache (); config ) else config in let command_of_string s = List.map (fun s -> CString s, None) (OpamMisc.split s ' ') in (* Set some globals *) let external_solver_command = let cmd = match !OpamGlobals.env_external_solver with | Some ("aspcud" | "packup" as s) -> [CIdent s, None] | Some s -> command_of_string s | None -> match OpamFile.Config.solver config with | Some f -> OpamGlobals.env_external_solver := Some (OpamMisc.sconcat_map " " (function (CIdent i,_) -> "%{"^i^"}%" | (CString s,_) -> s) f); f | None -> [CIdent OpamGlobals.default_external_solver, None] in let cmd = match cmd with | [CIdent "aspcud", None] -> List.map (fun s -> s, None) [CString "aspcud"; CIdent "input"; CIdent "output"; CIdent "criteria"] | [CIdent "packup", None] -> List.map (fun s -> s, None) [CString "packup"; CIdent "input"; CIdent "output"; CString "-u"; CIdent "criteria"] | [CString cmd, None] -> (* Default args if the command is a single string *) List.map (fun s -> s, None) [CString cmd; CIdent "input"; CIdent "output"; CIdent "criteria"] | cmd -> cmd in fun ~input ~output ~criteria -> OpamFilter.single_command (fun v -> if not (is_global_conf v) then None else match OpamVariable.to_string (OpamVariable.Full.variable v) with | "input" -> Some (S input) | "output" -> Some (S output) | "criteria" -> Some (S criteria) | _ -> None) cmd in OpamGlobals.external_solver_ref := Some external_solver_command; let solver_prefs = let config_crit = !OpamGlobals.solver_preferences @ OpamFile.Config.criteria config in let f kind = kind, try List.assoc kind config_crit with Not_found -> match OpamCudf.check_cudf_version () with | `Latest -> OpamGlobals.default_preferences kind | `Compat -> OpamGlobals.compat_preferences kind in [f `Default; f `Upgrade; f `Fixup] in OpamGlobals.solver_preferences := solver_prefs; let dl_tool = match !OpamGlobals.download_tool_env with | Some ("curl" | "wget" as s) -> Some [CIdent s, None] | Some s -> Some (command_of_string s) | None -> OpamFile.Config.dl_tool config in let dl_command cmd = fun ~url ~out ~retry ?(checksum="") ~compress -> OpamFilter.single_command (fun v -> if not (is_global_conf v) then None else match OpamVariable.to_string (OpamVariable.Full.variable v) with | "url" -> Some (S url) | "out" -> Some (S out) | "retry" -> Some (S (string_of_int retry)) | "compress" -> Some (B compress) | "checksum" -> Some (S checksum) | _ -> None) cmd in let download_tool = match dl_tool with | Some [CIdent "curl", None] -> Some `Curl | Some [CIdent "wget", None] -> Some `Wget | Some cmd -> Some (`Custom (dl_command cmd)) | None -> None in OpamGlobals.download_tool := download_tool; config let load_state ?(save_cache=true) call_site = log "LOAD-STATE(%s)" call_site; let chrono = OpamGlobals.timer () in !upgrade_to_1_1_hook (); let root = OpamPath.root () in let config = load_config root in let opams = let file = OpamPath.state_cache root in if OpamFilename.exists file then marshal_from_file file else None in let cached = opams <> None in let partial = false in let switch = match !OpamGlobals.switch with | `Command_line s | `Env s -> OpamSwitch.of_string s | `Not_set -> OpamFile.Config.switch config in let aliases = OpamFile.Aliases.safe_read (OpamPath.aliases root) in let compilers = let files = OpamFilename.rec_files (OpamPath.compilers_dir root) in let files = List.fold_left (fun acc file -> if OpamFilename.exists file then file :: acc else acc ) [] files in let comp = OpamMisc.filter_map OpamCompiler.of_filename files in OpamCompiler.Set.of_list comp in let switch, compiler = try switch, OpamSwitch.Map.find switch aliases with Not_found -> log "%a does not contain the compiler name associated to the switch %a" (slog @@ OpamFilename.to_string @* OpamPath.aliases) root (slog OpamSwitch.to_string) switch; if !OpamGlobals.safe_mode then OpamGlobals.error_and_exit "Safe mode: invalid switch selected"; match !OpamGlobals.switch with | `Command_line s | `Env s -> OpamSwitch.not_installed (OpamSwitch.of_string s) | `Not_set -> if not (OpamSwitch.Map.is_empty aliases) then ( let new_switch, new_compiler = OpamSwitch.Map.choose aliases in OpamGlobals.error "The current switch (%s) is an unknown compiler \ switch. Switching back to %s ..." (OpamSwitch.to_string switch) (OpamSwitch.to_string new_switch); let config = OpamFile.Config.with_switch config new_switch in OpamFile.Config.write (OpamPath.config root) config; new_switch, new_compiler; ) else OpamGlobals.error_and_exit "The current switch (%s) is an unknown compiler switch." (OpamSwitch.to_string switch) in let compiler_version = lazy ( let comp_f = OpamPath.compiler_comp root compiler in (* XXX: useful for upgrade to 1.1 *) if compiler = OpamCompiler.system && not (OpamFilename.exists comp_f) then create_system_compiler_description root; if not (OpamFilename.exists comp_f) then OpamCompiler.unknown compiler else OpamFile.Comp.version (OpamFile.Comp.read comp_f) ) in let repositories = read_repositories root config in let package_index = OpamFile.Package_index.safe_read (OpamPath.package_index root) in let compiler_index = OpamFile.Compiler_index.safe_read (OpamPath.compiler_index root) in let installed = OpamFile.Installed.safe_read (OpamPath.Switch.installed root switch) in let pinned = OpamFile.Pinned.safe_read (OpamPath.Switch.pinned root switch) in let installed_roots = OpamFile.Installed_roots.safe_read (OpamPath.Switch.installed_roots root switch) in let opams = match opams with | None -> let packages = OpamPackage.Set.of_list (OpamPackage.Map.keys package_index) ++ installed in OpamPackage.Set.fold (fun nv map -> try let file = package_repo_dir root repositories package_index nv // "opam" in try let opam = OpamFile.OPAM.read file in OpamPackage.Map.add nv opam map with OpamFormat.Bad_format _ | Lexer_error _ -> map (* Error printed, continue *) with | Not_found -> if not (OpamPackage.Name.Map.mem (OpamPackage.name nv) pinned) then OpamGlobals.warning "Cannot find an OPAM file for %s, skipping." (OpamPackage.to_string nv); map | Parsing.Parse_error | OpamSystem.Internal_error _ -> OpamGlobals.warning "Errors while parsing %s OPAM file, skipping." (OpamPackage.to_string nv); map ) packages OpamPackage.Map.empty | Some o -> o in let packages = OpamPackage.Set.of_list (OpamPackage.Map.keys opams) in let reinstall = OpamFile.Reinstall.safe_read (OpamPath.Switch.reinstall root switch) in let available_packages_stub = lazy OpamPackage.Set.empty in let t = { partial; root; switch; compiler; compiler_version; repositories; opams; packages; installed; installed_roots; reinstall; config; aliases; pinned; compilers; package_index; compiler_index; available_packages = available_packages_stub } in let packages = pinned_packages t ++ packages in let t = { t with packages } in let available_packages = lazy (available_packages t) in let t = { t with available_packages } in print_state t; if save_cache && not cached then save_state ~update:false t; let load_time = chrono () in log "State %s loaded in %.3fs" call_site load_time; (* Check whether the system compiler has been updated *) if system_needs_upgrade t then ( reinstall_system_compiler t; if OpamGlobals.confirm "\nSystem update successful. Go on with %S ?" (String.concat " " (Array.to_list Sys.argv)) then t else OpamGlobals.exit 0 ) else t (* install ~/.opam/switches//config/global-conf.config *) let install_global_config root switch = log "install_global_config switch=%a" (slog OpamSwitch.to_string) switch; (* .config *) let vars = let map f l = List.rev_map (fun (s,p) -> OpamVariable.of_string s, S (f p)) l in let id x = x in map OpamFilename.Dir.to_string [ ("root", root); ("prefix", OpamPath.Switch.root root switch); ("lib", OpamPath.Switch.lib_dir root switch); ("bin", OpamPath.Switch.bin root switch); ("sbin", OpamPath.Switch.sbin root switch); ("doc", OpamPath.Switch.doc_dir root switch); ("stublibs", OpamPath.Switch.stublibs root switch); ("toplevel", OpamPath.Switch.toplevel root switch); ("man", OpamPath.Switch.man_dir root switch); ("share", OpamPath.Switch.share_dir root switch); ("etc", OpamPath.Switch.etc_dir root switch); ] @ map id [ ("user" , try (Unix.getpwuid (Unix.getuid ())).Unix.pw_name with Not_found -> "user"); ("group", try (Unix.getgrgid (Unix.getgid ())).Unix.gr_name with Not_found -> "group"); ("make" , !OpamGlobals.makecmd ()); ("os" , OpamGlobals.os_string ()); ] in let config = OpamFile.Dot_config.create vars in OpamFile.Dot_config.write (OpamPath.Switch.global_config root switch) config let fix_descriptions_hook = ref (fun ?save_cache:_ ?verbose:_ _ -> assert false) (* Upgrade to the new file overlay *) let upgrade_to_1_1 () = let root = OpamPath.root () in let opam = root / "opam" in let opam_tmp = root / "opam_tmp" in let descr = root / "descr" in let compilers = root / "compilers" in let repo_index = root / "repo" // "index" in if OpamFilename.exists_dir opam || OpamFilename.exists repo_index then ( if !OpamGlobals.safe_mode then OpamGlobals.error_and_exit "Safe mode: not upgrading from opamroot <1.1"; OpamSystem.in_dir OpamGlobals.home @@ fun () -> OpamGlobals.header_msg "Upgrading to OPAM 1.1 %s" (OpamGlobals.colorise `red "[DO NOT INTERRUPT THE PROCESS]"); OpamGlobals.formatted_msg "\n\ \ In case something goes wrong, you can run that upgrade process again \ by doing:\n\ \n\ \ mkdir %s/opam && opam list\n\ \n\ ** Processing **\n" (OpamFilename.prettify_dir (OpamPath.root ())); if OpamFilename.exists_dir opam then OpamFilename.move_dir ~src:opam ~dst:opam_tmp; OpamFilename.rmdir descr; if OpamFilename.exists_dir (OpamPath.packages_dir root) then OpamFilename.rmdir (OpamPath.packages_dir root); (* Remove the cache. *) if OpamFilename.exists (OpamPath.state_cache root) then OpamFilename.remove (OpamPath.state_cache root); (* Remove the index files *) OpamFilename.remove (OpamPath.root () / "repo" // "index"); OpamFilename.remove (OpamPath.root () / "repo" // "index.packages"); OpamFilename.remove (OpamPath.root () / "repo" // "index.compilers"); (* fix the base config files *) let aliases = OpamFile.Aliases.safe_read (OpamPath.aliases root) in OpamSwitch.Map.iter (fun switch _ -> install_global_config root switch ) aliases; OpamFilename.with_tmp_dir (fun tmp_dir -> let keep_compilers = OpamCompiler.Set.of_list (OpamSwitch.Map.values aliases) in (* Fix system.comp *) let backups = OpamCompiler.Set.fold (fun compname backups -> let comp = root / "compilers" // (OpamCompiler.to_string compname ^ ".comp") in if OpamFilename.exists comp then ( let tmp_file = OpamFilename.create tmp_dir (OpamFilename.basename comp) in log "backing up %a to %a" (slog OpamFilename.to_string) comp (slog OpamFilename.to_string) tmp_file; OpamFilename.move ~src:comp ~dst:tmp_file; (compname,tmp_file) :: backups ) else backups ) keep_compilers [] in OpamFilename.rmdir compilers; List.iter (fun (compname,tmp_file) -> log "restoring %a" (slog OpamFilename.to_string) tmp_file; let comp = OpamPath.compiler_comp root compname in OpamFilename.mkdir (OpamFilename.dirname comp); OpamFilename.move ~src:tmp_file ~dst:comp ) backups; if not (OpamFilename.exists (OpamPath.compiler_comp root OpamCompiler.system)) then create_system_compiler_description root ); (* Remove pinned cache *) OpamSwitch.Map.iter (fun switch _ -> let pinned_cache = OpamPath.Switch.root root switch / "pinned.cache" in if OpamFilename.exists_dir pinned_cache then ( OpamGlobals.msg "Removing the cache of pinned packages for the switch %s ...\n" (OpamSwitch.to_string switch); OpamFilename.rmdir pinned_cache; ) ) aliases; (* Fix all the descriptions *) let t = load_state ~save_cache:false "update-to-1.1." in !fix_descriptions_hook ~verbose:false t; (* Fix the pinned packages *) OpamSwitch.Map.iter (fun switch _ -> let pinned = OpamFile.Pinned.safe_read (OpamPath.Switch.pinned root switch) in OpamPackage.Name.Map.iter (fun name _ -> let t = { t with switch } in if is_pinned t name then ( OpamFilename.rmdir (OpamPath.Switch.Overlay.package root switch name); add_pinned_overlay t name; ) ) pinned ) aliases; (* Workaround to add back packages without repositories *) List.iter (fun file -> let nv = file |> OpamFilename.chop_extension |> OpamFilename.basename |> OpamFilename.Base.to_string |> OpamPackage.of_string in let dst = OpamPath.opam root nv in if not (OpamFilename.exists dst) then OpamFilename.copy ~src:file ~dst ) (OpamFilename.files opam_tmp); OpamFilename.rmdir opam_tmp; OpamGlobals.header_msg "Upgrade complete. Now continuing with \"%s\"" (String.concat " " (Array.to_list Sys.argv)); OpamGlobals.msg "\n"; ) let upgrade_to_1_2 () = if !OpamGlobals.safe_mode then OpamGlobals.error_and_exit "Safe mode: not upgrading from opamroot <1.2"; log "Upgrade pinned packages format to 1.2"; let root = OpamPath.root () in let aliases = OpamFile.Aliases.safe_read (OpamPath.aliases root) in let remove_pinned_suffix d = let s = OpamFilename.Dir.to_string d in if Filename.check_suffix s ".pinned" then OpamFilename.move_dir ~src:d ~dst:(OpamFilename.Dir.of_string (Filename.chop_suffix s ".pinned")) in let packages = lazy ( OpamPackage.Set.of_list (OpamPackage.Map.keys (OpamFile.Package_index.safe_read (OpamPath.package_index root))) ) in OpamSwitch.Map.iter (fun switch _ -> let pinned_version name = try let f = OpamPath.Switch.Overlay.opam root switch name in match OpamFile.OPAM.version_opt (OpamFile.OPAM.read f) with | None -> raise Not_found | Some v -> v with e -> OpamMisc.fatal e; try OpamPackage.version (OpamPackage.max_version (Lazy.force packages) name) with Not_found -> OpamPackage.Version.of_string "0" in let fix_version nv = let obsolete_pinned_v = OpamPackage.Version.of_string "pinned" in if OpamPackage.version nv = obsolete_pinned_v then let name = OpamPackage.name nv in OpamPackage.create name (pinned_version name) else nv in List.iter remove_pinned_suffix (OpamFilename.dirs (OpamPath.Switch.dev_packages_dir root switch)); List.iter remove_pinned_suffix (OpamFilename.dirs (OpamPath.Switch.Overlay.dir root switch)); let installed_f = OpamPath.Switch.installed root switch in let installed = OpamFile.Installed.safe_read installed_f in OpamFile.Installed.write installed_f (OpamPackage.Set.map fix_version installed); let installed_roots_f = OpamPath.Switch.installed_roots root switch in let installed_roots = OpamFile.Installed_roots.safe_read installed_roots_f in OpamFile.Installed_roots.write installed_roots_f (OpamPackage.Set.map fix_version installed_roots); (* Move .config files *) List.iter (fun f -> let name = OpamPackage.Name.of_string @@ OpamFilename.Base.to_string @@ OpamFilename.basename @@ OpamFilename.chop_extension f in if name <> OpamPackage.Name.global_config then let dst = OpamPath.Switch.config root switch name in OpamFilename.mkdir (OpamFilename.dirname dst); OpamFilename.move ~src:f ~dst ) (OpamFilename.files (OpamPath.Switch.config_dir root switch)) ) aliases let () = upgrade_to_1_1_hook := upgrade_to_1_1; upgrade_to_1_2_hook := upgrade_to_1_2 let rebuild_state_cache () = remove_state_cache (); let t = load_state ~save_cache:false "rebuild-cache" in save_state ~update:true t let switch_eval_sh = "switch_eval.sh" let complete_sh = "complete.sh" let complete_zsh = "complete.zsh" let variables_sh = "variables.sh" let variables_csh = "variables.csh" let variables_fish = "variables.fish" let init_sh = "init.sh" let init_zsh = "init.zsh" let init_csh = "init.csh" let init_fish = "init.fish" let init_file = function | `sh -> init_sh | `csh -> init_csh | `zsh -> init_zsh | `bash -> init_sh | `fish -> init_fish let source t ~shell ?(interactive_only=false) f = let file f = OpamFilename.to_string (OpamPath.init t.root // f) in let s = match shell with | `csh -> Printf.sprintf "source %s >& /dev/null || true\n" (file f) | `fish -> Printf.sprintf ". %s > /dev/null 2> /dev/null or true\n" (file f) | _ -> Printf.sprintf ". %s > /dev/null 2> /dev/null || true\n" (file f) in if interactive_only then match shell with | `csh -> Printf.sprintf "if (tty -s >&/dev/null) then\n %sendif\n" s | `fish -> Printf.sprintf "if tty -s >/dev/null 2>&1\n %send\n" s | _ -> Printf.sprintf "if tty -s >/dev/null 2>&1; then\n %sfi\n" s else s let expand_env t ?opam (env: env_updates) : env = let fenv v = try resolve_variable t ?opam OpamVariable.Map.empty v with Not_found -> log "Undefined variable: %s" (OpamVariable.Full.to_string v); None in List.rev_map (fun (ident, symbol, string) -> let string = OpamFilter.expand_string fenv string in let prefix = OpamFilename.Dir.to_string t.root in let read_env () = try OpamMisc.reset_env_value ~prefix OpamSystem.path_sep (OpamMisc.getenv ident) with Not_found -> [] in let update_env a = let before, after = OpamMisc.cut_env_value ~prefix OpamSystem.path_sep (OpamMisc.getenv ident) in List.rev_append before (a::after) in let cons ~head a b = let c = List.filter ((<>)"") b in match b with | [] -> if head then [ ""; a ] else [ a; "" ] | "" :: _ -> "" :: a :: c | _ -> match List.rev b with | "" :: _ -> (a :: c) @ [""] | _ -> a :: c in let c = String.make 1 OpamSystem.path_sep in match symbol with | "=" -> (ident, string) | "+=" -> (ident, String.concat c (string :: read_env ())) | "=+" -> (ident, String.concat c (read_env () @ [string])) | ":=" -> (ident, String.concat c (cons ~head:true string (read_env()))) | "=:" -> (ident, String.concat c (cons ~head:false string (read_env()))) | "=+=" -> (ident, String.concat c (update_env string)) | _ -> failwith (Printf.sprintf "expand_env: %s is an unknown symbol" symbol) ) env let add_to_env t ?opam (env: env) (updates: env_updates) = let env = List.filter (fun (k,_) -> List.for_all (fun (u,_,_) -> u <> k) updates) env in env @ expand_env t ?opam updates let env_updates ~opamswitch ?(force_path=false) t = let comp = compiler_comp t t.compiler in let add_to_path = OpamPath.Switch.bin t.root t.switch in let new_path = "PATH", (if force_path then "+=" else "=+="), OpamFilename.Dir.to_string add_to_path in let perl5 = OpamPackage.Name.of_string "perl5" in let add_to_perl5lib = OpamPath.Switch.lib t.root t.switch perl5 in let new_perl5lib = "PERL5LIB", "+=", OpamFilename.Dir.to_string add_to_perl5lib in let toplevel_dir = "OCAML_TOPLEVEL_PATH", "=", OpamFilename.Dir.to_string (OpamPath.Switch.toplevel t.root t.switch) in let man_path = match OpamGlobals.os () with | OpamGlobals.OpenBSD | OpamGlobals.NetBSD | OpamGlobals.FreeBSD -> [] (* MANPATH is a global override on those, so disabled for now *) | _ -> ["MANPATH", "=:", OpamFilename.Dir.to_string (OpamPath.Switch.man_dir t.root t.switch)] in let utf8 = match OpamGlobals.os () with | OpamGlobals.Darwin -> ["OPAMUTF8MSGS", "=", "1"] | _ -> [] in let comp_env = OpamFile.Comp.env comp in let switch = if opamswitch then [ "OPAMSWITCH", "=", OpamSwitch.to_string t.switch ] else [] in let root = if !OpamGlobals.root_dir <> OpamGlobals.default_opam_dir || try !OpamGlobals.root_dir <> OpamMisc.getenv "OPAMROOT" with Not_found -> false then [ "OPAMROOT", "=", !OpamGlobals.root_dir ] else [] in new_path :: toplevel_dir :: new_perl5lib :: (man_path @ switch @ root @ utf8 @ comp_env) (* This function is used by 'opam config env' and 'opam switch' to display the environment variables. We have to make sure that OPAMSWITCH is always the one being reported in '~/.opam/config' otherwise we can have very weird results (as the inability to switch between compilers). Note: when we do the later command with --switch=SWITCH, this mean we really want to get the environment for this switch. *) let get_opam_env ~force_path t = let opamswitch = !OpamGlobals.switch <> `Not_set in add_to_env t [] (env_updates ~opamswitch ~force_path t) let get_full_env ~force_path ?opam t = let env0 = OpamMisc.env () in add_to_env t ?opam env0 (env_updates ~opamswitch:true ~force_path t) let mem_pattern_in_string ~pattern ~string = let pattern = Re.compile (Re.str pattern) in Re.execp pattern string let ocamlinit () = try let file = Filename.concat (OpamMisc.getenv "HOME") ".ocamlinit" in Some (OpamFilename.of_string file) with Not_found -> None let ocamlinit_needs_update () = match ocamlinit () with | None -> true | Some file -> if OpamFilename.exists file then ( let body = OpamFilename.read file in let pattern = "OCAML_TOPLEVEL_PATH" in not (mem_pattern_in_string ~pattern ~string:body) ) else true let update_ocamlinit () = if ocamlinit_needs_update () then ( match ocamlinit () with | None -> () | Some file -> let body = if not (OpamFilename.exists file) then "" else OpamFilename.read file in if body = "" then OpamGlobals.msg " Generating ~/.ocamlinit.\n" else OpamGlobals.msg " Updating ~/.ocamlinit.\n"; try let header = "(* Added by OPAM. *)\n\ let () =\n\ \ try Topdirs.dir_directory (Sys.getenv \"OCAML_TOPLEVEL_PATH\")\n\ \ with Not_found -> ()\n\ ;;\n\n" in let oc = open_out_bin (OpamFilename.to_string file) in output_string oc (header ^ body); close_out oc; with e -> OpamMisc.fatal e; OpamSystem.internal_error "Cannot write ~/.ocamlinit." ) else OpamGlobals.msg " ~/.ocamlinit is already up-to-date.\n" let string_of_env_update t shell updates = let fenv = resolve_variable t OpamVariable.Map.empty in let sh (k,v) = Printf.sprintf "%s=%S; export %s;\n" k v k in let csh (k,v) = Printf.sprintf "if ( ! ${?%s} ) setenv %s \"\"\nsetenv %s %S\n" k k k v in let fish (k,v) = match k with | "PATH" | "MANPATH" -> let v = OpamMisc.split_delim v ':' in Printf.sprintf "set -gx %s %s;\n" k (OpamMisc.sconcat_map " " (Printf.sprintf "%S") v) | _ -> Printf.sprintf "set -gx %s %S;\n" k v in let export = match shell with | `zsh | `sh -> sh | `fish -> fish | `csh -> csh in let aux (ident, symbol, string) = let string = OpamFilter.expand_string fenv string in let key, value = match symbol with | "=" -> (ident, string) | "+=" | ":=" -> (ident, Printf.sprintf "%s:$%s" string ident) | "=:" | "=+" -> (ident, (match shell with `csh -> Printf.sprintf "${%s}:%s" ident string | _ -> Printf.sprintf "$%s:%s" ident string)) | "=+=" -> (ident, Printf.sprintf "%s:$%s" string ident) | _ -> failwith (Printf.sprintf "%s is not a valid env symbol" symbol) in export (key, value) in OpamMisc.sconcat_map "" aux updates let init_script t ~switch_eval ~complete ~shell (variables_sh, switch_eval_sh, complete_sh)= let variables = Some (source t ~shell variables_sh) in let switch_eval = if switch_eval then OpamMisc.Option.map (source t ~shell ~interactive_only:true) switch_eval_sh else None in let complete = if complete then OpamMisc.Option.map (source t ~shell ~interactive_only:true) complete_sh else None in let buf = Buffer.create 128 in let append name = function | None -> () | Some c -> Printf.bprintf buf "# %s\n%s\n" name c in append "Load the environment variables" variables; append "Load the auto-complete scripts" complete; append "Load the opam-switch-eval script" switch_eval; Buffer.contents buf let update_init_scripts t ~global = let init_scripts = match global with | None -> [] | Some g -> let scripts = [ `sh, init_sh , (variables_sh , Some switch_eval_sh, Some complete_sh); `zsh, init_zsh, (variables_sh , Some switch_eval_sh, Some complete_zsh); `csh, init_csh, (variables_csh , None, None); `fish, init_fish, (variables_fish, None, None); ] in let aux (shell, init, scripts) = init, init_script t ~shell ~switch_eval:g.switch_eval ~complete:g.complete scripts in List.map aux scripts in let scripts = [ (complete_sh , OpamScript.complete); (complete_zsh , OpamScript.complete_zsh); (switch_eval_sh, OpamScript.switch_eval); (variables_sh , string_of_env_update t `sh (env_updates ~opamswitch:false t)); (variables_csh , string_of_env_update t `csh (env_updates ~opamswitch:false t)); (variables_fish, string_of_env_update t `fish (env_updates ~opamswitch:false t)); ] @ init_scripts in let overwrite = [ init_sh; init_csh; init_fish; init_zsh; variables_sh; variables_csh; variables_fish; ] in let updated = ref false in let write (name, body) = let file = OpamPath.init t.root // name in let needs_update = if OpamFilename.exists file && List.mem name overwrite then let current = OpamFilename.read file in body <> current else not (OpamFilename.exists file) in if needs_update then ( updated := true; try OpamFilename.write file body with e -> OpamMisc.fatal e ) in List.iter write scripts; if global <> None then List.iter (fun init_file -> let pretty_init_file = OpamFilename.prettify (OpamPath.init t.root // init_file) in if !updated then OpamGlobals.msg " Updating %s\n" pretty_init_file else OpamGlobals.msg " %s is already up-to-date.\n" pretty_init_file) [ init_sh; init_zsh; init_csh; init_fish ] let status_of_init_file t init_sh = let init_sh = OpamPath.init t.root // init_sh in if OpamFilename.exists init_sh then ( let string = OpamFilename.read init_sh in let aux pattern = mem_pattern_in_string ~pattern ~string in if OpamFilename.exists init_sh then let complete_sh = aux complete_sh in let complete_zsh = aux complete_zsh in let switch_eval_sh = aux switch_eval_sh in Some (complete_sh, complete_zsh, switch_eval_sh) else None ) else None let dot_profile_needs_update t dot_profile = if OpamFilename.exists dot_profile then ( let body = OpamFilename.read dot_profile in let pattern1 = "opam config" in let pattern2 = OpamFilename.to_string (OpamPath.init t.root // "init") in let pattern3 = OpamMisc.remove_prefix ~prefix:!OpamGlobals.root_dir pattern2 in if mem_pattern_in_string ~pattern:pattern1 ~string:body then `no else if mem_pattern_in_string ~pattern:pattern2 ~string:body then `no else if mem_pattern_in_string ~pattern:pattern3 ~string:body then `otherroot else `yes ) else `yes let update_dot_profile t dot_profile shell = let pretty_dot_profile = OpamFilename.prettify dot_profile in match dot_profile_needs_update t dot_profile with | `no -> OpamGlobals.msg " %s is already up-to-date.\n" pretty_dot_profile | `otherroot -> OpamGlobals.msg " %s is already configured for another OPAM root.\n" pretty_dot_profile | `yes -> let init_file = init_file shell in let body = if OpamFilename.exists dot_profile then OpamFilename.read dot_profile else "" in OpamGlobals.msg " Updating %s.\n" pretty_dot_profile; let body = Printf.sprintf "%s\n\n\ # OPAM configuration\n\ %s" (OpamMisc.strip body) (source t ~shell init_file) in OpamFilename.write dot_profile body let update_setup t user global = begin match user with | Some { ocamlinit = false; dot_profile = None } | None -> () | Some l -> OpamGlobals.msg "User configuration:\n"; if l.ocamlinit then update_ocamlinit (); match l.dot_profile with | None -> () | Some f -> update_dot_profile t f l.shell; end; begin match global with | None -> () | Some _ -> OpamGlobals.msg "Global configuration:\n"; update_init_scripts t ~global end let display_setup t shell dot_profile = let print (k,v) = OpamGlobals.msg " %-25s - %s\n" k v in let not_set = "not set" in let ok = "string is already present so file unchanged" in let error = "error" in let user_setup = let ocamlinit_status = if ocamlinit_needs_update () then not_set else ok in let dot_profile_status = match dot_profile_needs_update t dot_profile with | `no -> ok | `yes -> not_set | `otherroot -> error in [ ("~/.ocamlinit" , ocamlinit_status); (OpamFilename.prettify dot_profile, dot_profile_status); ] in let init_file = init_file shell in let pretty_init_file = OpamFilename.prettify (OpamPath.init t.root // init_file) in let global_setup = match status_of_init_file t init_file with | None -> [pretty_init_file, not_set ] | Some(complete_sh, complete_zsh, switch_eval_sh) -> let completion = if not complete_sh && not complete_zsh then not_set else ok in let switch_eval = if switch_eval_sh then ok else not_set in [ ("init-script" , Printf.sprintf "%s" pretty_init_file); ("auto-completion" , completion); ("opam-switch-eval", switch_eval); ] in OpamGlobals.msg "User configuration:\n"; List.iter print user_setup; OpamGlobals.msg "Global configuration:\n"; List.iter print global_setup let eval_string t = let root = let opamroot_cur = OpamFilename.Dir.to_string t.root in let opamroot_env = try OpamMisc.getenv "OPAMROOT" with Not_found -> OpamGlobals.default_opam_dir in if opamroot_cur <> opamroot_env then Printf.sprintf " --root=%s" opamroot_cur else "" in let switch = try let sw_cur = OpamSwitch.to_string t.switch in let sw_env = OpamMisc.getenv "OPAMSWITCH" in if sw_cur <> sw_env then Printf.sprintf " --switch=%s" sw_cur else "" with Not_found -> "" in match OpamMisc.guess_shell_compat () with | `fish -> Printf.sprintf "eval (opam config env%s%s)\n" root switch | _ -> Printf.sprintf "eval `opam config env%s%s`\n" root switch let up_to_date_env t = let changes = List.filter (fun (s, v) -> Some v <> try Some (OpamMisc.getenv s) with Not_found -> None) (get_opam_env ~force_path:false t) in changes = [] let print_env_warning_at_init t user = if up_to_date_env t then () else let profile_string = match user.dot_profile with | None -> "" | Some f -> Printf.sprintf "%s To correctly configure OPAM for subsequent use, add the following\n\ \ line to your profile file (for instance %s):\n\ \n\ \ %s\n" (OpamGlobals.colorise `yellow "2.") (OpamFilename.prettify f) (source t ~shell:user.shell (init_file user.shell)) in let ocamlinit_string = if not user.ocamlinit then "" else OpamGlobals.colorise `yellow "3." ^ " To avoid issues related to non-system installations of `ocamlfind`\n\ \ add the following lines to ~/.ocamlinit (create it if necessary):\n\ \n\ \ let () =\n\ \ try Topdirs.dir_directory (Sys.getenv \"OCAML_TOPLEVEL_PATH\")\n\ \ with Not_found -> ()\n\ \ ;;\n\n" in let line = OpamGlobals.colorise `cyan "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=" in OpamGlobals.msg "\n%s\n\n\ %s To configure OPAM in the current shell session, you need to run:\n\ \n\ \ %s\n\ %s%s%s\n\n" line (OpamGlobals.colorise `yellow "1.") (eval_string t) profile_string ocamlinit_string line let print_env_warning_at_switch t = if up_to_date_env t then () else OpamGlobals.msg "# To setup the new switch in the current shell, you need to run:\n%s" (eval_string t) let update_setup_interactive t shell dot_profile = let update dot_profile = let modify_user_conf = dot_profile <> None in let user = Some { shell; ocamlinit = modify_user_conf; dot_profile } in OpamGlobals.msg "\n"; update_setup t user (Some {complete=true; switch_eval=true}); modify_user_conf in OpamGlobals.msg "\n"; match OpamGlobals.read "In normal operation, OPAM only alters files within ~/.opam.\n\ \n\ During this initialisation, you can allow OPAM to add information to two\n\ other files for best results. You can also make these additions manually\n\ if you wish.\n\ \n\ If you agree, OPAM will modify:\n\n\ \ - %s (or a file you specify) to set the right environment\n\ \ variables and to load the auto-completion scripts for your shell (%s)\n\ \ on startup. Specifically, it checks for and appends the following line:\n\ \n\ \ %s\n\ \n\ \ - %s to ensure that non-system installations of `ocamlfind`\n\ \ (i.e. those installed by OPAM) will work correctly when running the\n\ \ OCaml toplevel. It does this by adding $OCAML_TOPLEVEL_PATH to the list\n\ \ of include directories.\n\ \n\ If you choose to not configure your system now, you can either configure\n\ OPAM manually (instructions will be displayed) or launch the automatic setup\n\ later by running:\n\ \n\ \ opam config setup -a\n\ \n\ \n\ Do you want OPAM to modify %s and ~/.ocamlinit?\n\ (default is 'no', use 'f' to name a file other than %s)\n\ \ [N/y/f]" (OpamGlobals.colorise `cyan @@ OpamFilename.prettify dot_profile) (OpamGlobals.colorise `bold @@ string_of_shell shell) (source t ~shell (init_file shell)) (OpamGlobals.colorise `cyan @@ "~/.ocamlinit") (OpamFilename.prettify dot_profile) (OpamFilename.prettify dot_profile) with | Some ("y" | "Y" | "yes" | "YES" ) -> update (Some dot_profile) | Some ("f" | "F" | "file" | "FILE") -> begin match OpamGlobals.read " Enter the name of the file to update:" with | None -> OpamGlobals.msg "-- No filename: skipping the auto-configuration step --\n"; false | Some f -> update (Some (OpamFilename.of_string f)) end | _ -> update None (* Add the given packages to the set of package to reinstall. If [all] is set, this is done for ALL the switches (useful when a package change upstream for instance). If not, only the reinstall state of the current switch is changed. *) let add_to_reinstall t ~all packages = log "add-to-reinstall all:%b packages:%a" all (slog OpamPackage.Set.to_string) packages; let aux switch = let installed = OpamFile.Installed.safe_read (OpamPath.Switch.installed t.root switch) in let reinstall = OpamFile.Reinstall.safe_read (OpamPath.Switch.reinstall t.root switch) ++ packages in let reinstall = OpamPackage.Set.filter (fun nv -> OpamPackage.Set.mem nv installed ) reinstall in let file = OpamPath.Switch.reinstall t.root switch in if not (OpamPackage.Set.is_empty reinstall) then OpamFile.Reinstall.write file reinstall else OpamFilename.remove file in if all then OpamSwitch.Map.iter (fun switch _ -> aux switch) t.aliases else aux t.switch let add_switch root switch compiler = log "add_switch switch=%a compiler=%a" (slog OpamSwitch.to_string) switch (slog OpamCompiler.to_string) compiler; let aliases_f = OpamPath.aliases root in let aliases = OpamFile.Aliases.safe_read aliases_f in if not (OpamSwitch.Map.mem switch aliases) then begin OpamFile.Aliases.write aliases_f (OpamSwitch.Map.add switch compiler aliases); end (* - compiles and install $opam/compiler/[ocaml_version].comp in $opam/[switch] - update $opam/switch - update $opam/config *) let install_compiler t ~quiet:_ switch compiler = log "install_compiler switch=%a compiler=%a" (slog OpamSwitch.to_string) switch (slog OpamCompiler.to_string) compiler; let comp_f = OpamPath.compiler_comp t.root compiler in if not (OpamFilename.exists comp_f) then ( OpamGlobals.msg "Cannot find %s: %s is not a valid compiler name.\n" (OpamFilename.to_string comp_f) (OpamCompiler.to_string compiler); OpamGlobals.exit 1; ); let switch_dir = OpamPath.Switch.root t.root switch in (* Do some clean-up if necessary *) if not (is_switch_installed t switch) && OpamFilename.exists_dir switch_dir then OpamFilename.rmdir switch_dir; try (* Create base directories *) OpamFilename.mkdir switch_dir; OpamFilename.mkdir (OpamPath.Switch.lib_dir t.root switch); OpamFilename.mkdir (OpamPath.Switch.stublibs t.root switch); OpamFilename.mkdir (OpamPath.Switch.toplevel t.root switch); OpamFilename.mkdir (OpamPath.Switch.build_dir t.root switch); OpamFilename.mkdir (OpamPath.Switch.bin t.root switch); OpamFilename.mkdir (OpamPath.Switch.sbin t.root switch); OpamFilename.mkdir (OpamPath.Switch.doc_dir t.root switch); OpamFilename.mkdir (OpamPath.Switch.man_dir t.root switch); OpamFilename.mkdir (OpamPath.Switch.install_dir t.root switch); OpamFilename.mkdir (OpamPath.Switch.config_dir t.root switch); List.iter (fun num -> OpamFilename.mkdir (OpamPath.Switch.man_dir ~num t.root switch) ) ["1";"1M";"2";"3";"4";"5";"6";"7";"9"]; install_global_config t.root switch; let comp = OpamFile.Comp.read comp_f in if not (OpamFile.Comp.preinstalled comp) && OpamFile.Comp.src comp <> None then begin (* Install the compiler *) let comp_src = match OpamFile.Comp.src comp with | Some f -> f | None -> OpamGlobals.error_and_exit "No source for compiler %s" (OpamCompiler.to_string compiler) in let build_dir = OpamPath.Switch.build_ocaml t.root switch in let kind = OpamFile.Comp.kind comp in let comp_name = OpamCompiler.to_string (OpamFile.Comp.name comp) in OpamGlobals.header_msg "Installing compiler %s" comp_name; if kind = `local && Sys.file_exists (fst comp_src) && Sys.is_directory (fst comp_src) then OpamFilename.link_dir ~src:(OpamFilename.Dir.of_string (fst comp_src)) ~dst:build_dir else ( OpamProcess.Job.run @@ OpamFilename.with_tmp_dir_job (fun download_dir -> let fake_pkg = match repository_and_prefix_of_compiler t compiler with | None -> OpamPackage.of_string "compiler.get" | Some (repo,_) -> OpamPackage.of_string (OpamRepositoryName.to_string repo.repo_name ^ ".comp") in let text = OpamProcess.make_command_text ~color:`magenta comp_name (string_of_repository_kind kind) in OpamProcess.Job.with_text text @@ OpamRepository.pull_url kind fake_pkg download_dir None [comp_src] @@+ function | Not_available u -> OpamGlobals.error_and_exit "%s is not available." u | Up_to_date r | Result r -> Done (OpamFilename.extract_generic_file r build_dir) )); let patches = OpamFile.Comp.patches comp in let patch_command file = let text = OpamProcess.make_command_text ~color:`magenta comp_name ~args:[OpamFilename.Base.to_string (OpamFilename.basename file)] "download" in OpamProcess.Job.with_text text @@ OpamFilename.download ~overwrite:true file build_dir in let patches = OpamParallel.map ~jobs:(dl_jobs t) ~command:patch_command patches in List.iter (fun f -> OpamFilename.patch f build_dir) patches; OpamGlobals.msg "Now compiling OCaml. This may take a while, \ please bear with us...\n"; let commands = if OpamFile.Comp.configure comp @ OpamFile.Comp.make comp <> [] then [ ( "./configure" :: OpamFile.Comp.configure comp ) @ [ "-prefix"; OpamFilename.Dir.to_string switch_dir ] (*-bindir %s/bin -libdir %s/lib -mandir %s/man*) (* NOTE In case it exists 2 '-prefix', in general the script ./configure will only consider the last one, others will be discarded. *) ; ( !OpamGlobals.makecmd () :: OpamFile.Comp.make comp ) ; [ !OpamGlobals.makecmd () ; "install" ] ] else let t = { t with switch } in let env = resolve_variable t OpamVariable.Map.empty in OpamFilter.commands env (OpamFile.Comp.build comp) in let commands = OpamMisc.filter_map (function | [] -> None | cmd::args -> let text = OpamProcess.make_command_text ~color:`magenta comp_name ~args cmd in Some (OpamSystem.make_command ~text ~dir:(OpamFilename.Dir.to_string build_dir) ~verbose:!OpamGlobals.verbose cmd args)) commands in match OpamProcess.Job.run (OpamProcess.Job.of_list commands) with | None -> OpamGlobals.msg "Done.\n"; if not !OpamGlobals.keep_build_dir then OpamFilename.rmdir build_dir | Some (cmd,err) -> OpamGlobals.error_and_exit "Compiler build failed at %S:\n%s" (OpamProcess.string_of_command cmd) (OpamProcess.string_of_result err) end; (* Update ~/.opam/aliases *) add_switch t.root switch compiler with e -> if not !OpamGlobals.debug then OpamFilename.rmdir switch_dir; raise e (* write the new version in the configuration file *) let update_switch_config t switch = let config = OpamFile.Config.with_switch t.config switch in OpamFile.Config.write (OpamPath.config t.root) config; let t = load_state "switch-config" in update_init_scripts {t with switch} ~global:None; t (* Dev packages *) let fetch_dev_package url srcdir nv = let remote_url = OpamFile.URL.url url in let mirrors = remote_url :: OpamFile.URL.mirrors url in let kind = OpamFile.URL.kind url in let checksum = OpamFile.URL.checksum url in log "updating %a:%a" (slog string_of_address) remote_url (slog string_of_repository_kind) kind; let text = OpamProcess.make_command_text (OpamPackage.Name.to_string (OpamPackage.name nv)) (string_of_repository_kind kind) in OpamProcess.Job.with_text text @@ OpamRepository.pull_url kind nv srcdir checksum mirrors @@| function | Not_available _ -> (* OpamGlobals.error "Upstream %s of %s is unavailable" u *) (* (OpamPackage.to_string nv); *) false | Up_to_date _ -> false | Result _ -> true let update_pinned_package t ?fixed_version name = let overlay = OpamPath.Switch.Overlay.package t.root t.switch name in let url_f = OpamPath.Switch.Overlay.url t.root t.switch name in if not (OpamFilename.exists url_f) then Done false else let url = OpamFile.URL.read url_f in let srcdir = OpamPath.Switch.dev_package t.root t.switch name in let pinning_kind = kind_of_pin_option (OpamPackage.Name.Map.find name t.pinned) in (* Four versions of the metadata: from the old and new versions of the package, from the current overlay, and also the original one from the repo *) let hash_meta (opam, descr, files_dir) = (match opam with None -> [] | Some o -> ["opam", `Opam o]) @ (match descr with None -> [] | Some d -> ["descr", `Digest (OpamFilename.digest d)]) @ (match files_dir with None -> [] | Some files_dir -> List.map (fun f -> OpamFilename.remove_prefix (OpamFilename.dirname_dir files_dir) f, `Digest (OpamFilename.digest f)) (OpamFilename.rec_files files_dir)) in let old_meta = (* Version previously present in the source *) if pinning_kind = `version then [] else hash_meta @@ local_opam ?fixed_version name srcdir in let was_single_opam_file = OpamFilename.exists (srcdir // "opam") in let just_opam = List.filter (function (_, `Opam _) -> true | _ -> false) in let user_meta, empty_user_meta, user_version = (* Installed version (overlay) *) let opam,_,_ as files = local_opam ~root:true ?fixed_version name overlay in hash_meta files, (match opam with Some o -> OpamFile.OPAM.(empty = with_name_opt (with_version_opt o None) None) | None -> true), OpamMisc.Option.map OpamFile.OPAM.version opam in let repo_meta = (* Version from the repo *) let nv = let packages = OpamPackage.Map.filter (fun nv _ -> OpamPackage.name nv = name) t.package_index in match user_version with | None -> (try Some (fst (OpamPackage.Map.max_binding packages)) with | Not_found -> None) | Some v -> let nv = OpamPackage.create name v in (* get the latest version below v *) match OpamPackage.Map.split nv packages with | _, Some _, _ -> Some nv | below, None, _ when not (OpamPackage.Map.is_empty below) -> Some (fst (OpamPackage.Map.max_binding below)) | _, None, above when not (OpamPackage.Map.is_empty above) -> Some (fst (OpamPackage.Map.min_binding above)) | _ -> None in let meta = match nv with | None -> Some (OpamFile.OPAM.with_name OpamFile.OPAM.empty name), None, None | Some nv -> let dir = package_repo_dir t.root t.repositories t.package_index nv in let opam, descr, files = local_opam ~root:true ?fixed_version name dir in OpamMisc.Option.map (fun o -> OpamFile.OPAM.with_version_opt o user_version) opam, descr, files in hash_meta @@ meta in let fake_nv = OpamPackage.create name (OpamPackage.Version.of_string "") in (* Do the update *) fetch_dev_package url srcdir fake_nv @@+ fun result -> let new_meta = (* New version from the source *) hash_meta @@ local_opam ?fixed_version ~copy_invalid_to:(OpamPath.Switch.Overlay.tmp_opam t.root t.switch name) name srcdir in let user_meta, old_meta, repo_meta = match find_opam_file_in_source name srcdir with | Some f when OpamFilename.dirname f = srcdir -> (* Single opam file directly at the project root: don't override other files, restrict to 'opam' *) just_opam user_meta, just_opam old_meta, just_opam repo_meta | _ -> user_meta, old_meta, repo_meta in let rec diff a b = match a,b with | (f1,h1)::r1, (f2,h2)::r2 -> if f1 < f2 then `Removed f1 :: diff r1 b else if f1 > f2 then `Added f2 :: diff a r2 else if h1 = h2 then diff r1 r2 else `Changed f1 :: diff r1 r2 | l, [] -> List.map (fun (f,_) -> `Removed f) l | [], l -> List.map (fun (f,_) -> `Added f) l in let diff_to_string = function | `Removed f -> Printf.sprintf "%S was removed" f | `Added f -> Printf.sprintf "%S was added" f | `Changed f -> Printf.sprintf "The contents of %S changed" f in let install_meta dir rm_hash hash = let root = let d = dir / (OpamPackage.Name.to_string name ^ ".opam") in if OpamFilename.exists_dir d then d else let d = dir / "opam" in if OpamFilename.exists_dir d then d else dir in List.iter (fun (f, _) -> OpamFilename.remove (overlay // f)) rm_hash; List.iter (fun (f,kind) -> match kind with | `Opam o -> let vo = OpamMisc.Option.Op.(OpamFile.OPAM.version_opt o ++ user_version) in OpamFile.OPAM.write (overlay // f) (OpamFile.OPAM.with_version_opt o vo) | `Digest _ -> OpamFilename.copy_in ~root (root // f) overlay) hash in (* Metadata from the package changed *) if result && new_meta <> [] && new_meta <> old_meta && new_meta <> user_meta then if old_meta = user_meta || repo_meta = user_meta || empty_user_meta || was_single_opam_file && old_meta = just_opam user_meta then (* No manual changes *) (OpamGlobals.formatted_msg "[%s] Installing new package description from %s\n" (OpamGlobals.colorise `green (OpamPackage.Name.to_string name)) (string_of_address (OpamFile.URL.url url)); OpamFilename.remove (OpamPath.Switch.Overlay.tmp_opam t.root t.switch name); install_meta srcdir user_meta new_meta) else if OpamGlobals.formatted_msg "[%s] Conflicting update of the metadata from %s:\n%s" (OpamGlobals.colorise `green (OpamPackage.Name.to_string name)) (string_of_address (OpamFile.URL.url url)) (OpamMisc.itemize diff_to_string (diff user_meta new_meta)); OpamGlobals.confirm "\nOverride files in %s (there will be a backup) ?" (OpamFilename.Dir.to_string overlay) then ( let bak = OpamPath.backup_dir t.root / (OpamPackage.Name.to_string name ^ ".bak") in OpamFilename.mkdir (OpamPath.backup_dir t.root); OpamFilename.rmdir bak; OpamFilename.copy_dir ~src:overlay ~dst:bak; OpamGlobals.formatted_msg "User metadata backed up in %s\n" (OpamFilename.Dir.to_string bak); install_meta srcdir user_meta new_meta; ); Done result let update_dev_package t nv = log "update-dev-package %a" (slog OpamPackage.to_string) nv; let name = OpamPackage.name nv in if is_pinned t name then update_pinned_package t name else match url t nv with | None -> Done false | Some url -> let srcdir = dev_package t nv in if OpamFile.URL.kind url = `http then Done false else fetch_dev_package url srcdir nv let update_dev_packages t packages = log "update-dev-packages"; let command nv = OpamProcess.Job.ignore_errors ~default:OpamPackage.Set.empty @@ update_dev_package t nv @@| function | true -> OpamPackage.Set.singleton nv | false -> OpamPackage.Set.empty in let updates = OpamParallel.reduce ~jobs:(dl_jobs t) ~command ~merge:OpamPackage.Set.union ~nil:OpamPackage.Set.empty (OpamPackage.Set.elements packages) in let global = OpamPackage.Set.of_list (OpamPackage.Map.keys (global_dev_packages t)) in add_to_reinstall t ~all:true (updates %% global); add_to_reinstall t ~all:false (updates -- global); updates let update_pinned_packages t names = log "update-pinned-packages"; let command name = OpamProcess.Job.ignore_errors ~default:OpamPackage.Name.Set.empty @@ update_pinned_package t name @@| function | true -> OpamPackage.Name.Set.singleton name | false -> OpamPackage.Name.Set.empty in let updates = OpamParallel.reduce ~jobs:(dl_jobs t) ~command ~merge:OpamPackage.Name.Set.union ~nil:OpamPackage.Name.Set.empty (OpamPackage.Name.Set.elements names) in let updates = OpamPackage.Name.Set.fold (fun name acc -> OpamPackage.Set.add (pinned t name) acc) updates OpamPackage.Set.empty in add_to_reinstall t ~all:false updates; updates (* Try to download $name.$version+opam.tar.gz *) let download_archive t nv = log "get_archive %a" (slog OpamPackage.to_string) nv; let dst = OpamPath.archive t.root nv in try let repo, _ = OpamPackage.Map.find nv t.package_index in let repo = find_repository t repo in let text = OpamProcess.make_command_text (OpamPackage.name_to_string nv) ~args:[OpamRepositoryName.to_string repo.repo_name] "from" in OpamProcess.Job.with_text text @@ OpamRepository.pull_archive repo nv @@+ function | Not_available _ -> if !OpamGlobals.verbose_level >= 2 then OpamGlobals.msg "%s Repo archive not found\n" text; Done None | Up_to_date f -> OpamGlobals.msg "[%s] Archive in cache\n" (OpamGlobals.colorise `green (OpamPackage.name_to_string nv)); OpamFilename.copy ~src:f ~dst; Done (Some dst) | Result f -> OpamFilename.copy ~src:f ~dst; Done (Some dst) with Not_found -> Done None (* Download a package from its upstream source, using 'cache_dir' as cache directory. *) let download_upstream t nv dirname = match url t nv with | None -> Done None | Some u -> let remote_url = OpamFile.URL.url u in let mirrors = remote_url :: OpamFile.URL.mirrors u in let kind = OpamFile.URL.kind u in let checksum = OpamFile.URL.checksum u in let text = OpamProcess.make_command_text (OpamPackage.name_to_string nv) (string_of_repository_kind kind) in OpamProcess.Job.with_text text @@ OpamRepository.pull_url kind nv dirname checksum mirrors @@| fun x -> Some x let check f = let root = OpamPath.root () in if not (OpamFilename.exists_dir root) || not (OpamFilename.exists (OpamPath.config root)) then OpamGlobals.error_and_exit "No OPAM root found at %s.\n\ Please run 'opam init' to initialize the state of OPAM, or \ specify '--root'.\n\ See 'opam init --help' for details." (OpamFilename.Dir.to_string root); match f with | Global_lock f -> (* Take the global lock *) OpamFilename.with_flock (OpamPath.lock root) (fun () -> (* clean the log directory *) OpamFilename.cleandir (OpamPath.log root); (* XXX pass t to f so that it doesn't have to reload it ? *) let t = load_state "global-lock" in global_consistency_checks t; f () ) () | Read_lock f -> (* Global read lock *) OpamFilename.with_flock ~read:true (OpamPath.lock root) f () | Switch_lock f -> (* Take a switch lock (and a global read lock). *) OpamFilename.with_flock ~read:true (OpamPath.lock root) (fun () -> let switch = match !OpamGlobals.switch with | `Command_line s | `Env s -> OpamSwitch.of_string s | `Not_set -> OpamFile.Config.switch (OpamFile.Config.read (OpamPath.config root)) in let t = load_state "switch-lock" in switch_consistency_checks t; OpamFilename.with_flock (OpamPath.Switch.lock root switch) f () ) () | Global_with_switch_cont_lock f -> (* Take the global lock *) let global_lock = OpamPath.lock root in let switch, cont = OpamFilename.with_flock global_lock (fun () -> (* clean the log directory *) OpamFilename.cleandir (OpamPath.log root); let t = load_state "global-lock" in global_consistency_checks t; f () ) () in (* Could be safer to first get the next lock, but there seems to be no guarantee with flock that we can properly turn a write lock to a read lock without unlocking first. *) OpamFilename.with_flock ~read:true global_lock (fun () -> OpamFilename.with_flock (OpamPath.Switch.lock root switch) cont () ) () opam-full-1.2.2/src/client/opamAction.ml0000644000175000017500000005373712517374212016642 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2014 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) let log fmt = OpamGlobals.log "ACTION" fmt let slog = OpamGlobals.slog open OpamTypes open OpamFilename.OP open OpamState.Types open OpamProcess.Job.Op module PackageActionGraph = OpamSolver.ActionGraph (* Install the package files *) let install_package t nv = if !OpamGlobals.dryrun then OpamGlobals.msg "Installing %s.\n" (OpamPackage.to_string nv) else let build_dir = OpamPath.Switch.build t.root t.switch nv in if OpamFilename.exists_dir build_dir then OpamFilename.in_dir build_dir (fun () -> log "Installing %s.\n" (OpamPackage.to_string nv); let name = OpamPackage.name nv in let config_f = OpamPath.Switch.build_config t.root t.switch nv in let config = OpamFile.Dot_config.safe_read config_f in let install_f = OpamPath.Switch.build_install t.root t.switch nv in let install = OpamFile.Dot_install.safe_read install_f in (* .install *) let install_f = OpamPath.Switch.install t.root t.switch name in OpamFile.Dot_install.write install_f install; (* .config *) let dot_config = OpamPath.Switch.config t.root t.switch name in OpamFilename.mkdir (OpamFilename.dirname dot_config); OpamFile.Dot_config.write dot_config config; let warnings = ref [] in let check ~src ~dst base = let src_file = OpamFilename.create src base.c in if base.optional && not (OpamFilename.exists src_file) then log "Not installing %a is not present and optional." (slog OpamFilename.to_string) src_file; if not base.optional && not (OpamFilename.exists src_file) then ( warnings := (dst, base.c) :: !warnings ); OpamFilename.exists src_file in (* Install a list of files *) let install_files exec dst_fn files_fn = let dst_dir = dst_fn t.root t.switch name in let files = files_fn install in if not (OpamFilename.exists_dir dst_dir) then ( log "creating %a" (slog OpamFilename.Dir.to_string) dst_dir; OpamFilename.mkdir dst_dir; ); List.iter (fun (base, dst) -> let src_file = OpamFilename.create build_dir base.c in let dst_file = match dst with | None -> OpamFilename.create dst_dir (OpamFilename.basename src_file) | Some d -> OpamFilename.create dst_dir d in if check ~src:build_dir ~dst:dst_dir base then OpamFilename.install ~exec ~src:src_file ~dst:dst_file (); ) files in (* bin *) install_files true (fun r s _ -> OpamPath.Switch.bin r s) OpamFile.Dot_install.bin; (* sbin *) install_files true (fun r s _ -> OpamPath.Switch.sbin r s) OpamFile.Dot_install.sbin; (* lib *) install_files false OpamPath.Switch.lib OpamFile.Dot_install.lib; install_files true OpamPath.Switch.lib OpamFile.Dot_install.libexec; (* toplevel *) install_files false (fun r s _ -> OpamPath.Switch.toplevel r s) OpamFile.Dot_install.toplevel; install_files true (fun r s _ -> OpamPath.Switch.stublibs r s) OpamFile.Dot_install.stublibs; (* Man pages *) install_files false (fun r s _ -> OpamPath.Switch.man_dir r s) OpamFile.Dot_install.man; (* Shared files *) install_files false OpamPath.Switch.share OpamFile.Dot_install.share; install_files false (fun r s _ -> OpamPath.Switch.share_dir r s) OpamFile.Dot_install.share_root; (* Etc files *) install_files false OpamPath.Switch.etc OpamFile.Dot_install.etc; (* Documentation files *) install_files false OpamPath.Switch.doc OpamFile.Dot_install.doc; (* misc *) List.iter (fun (src, dst) -> let src_file = OpamFilename.create (OpamFilename.cwd ()) src.c in if OpamFilename.exists dst && OpamGlobals.confirm "Overwriting %s ?" (OpamFilename.to_string dst) then OpamFilename.install ~src:src_file ~dst () else begin OpamGlobals.msg "Installing %s to %s.\n" (OpamFilename.Base.to_string src.c) (OpamFilename.to_string dst); if OpamGlobals.confirm "Continue ?" then OpamFilename.install ~src:src_file ~dst () end ) (OpamFile.Dot_install.misc install); if !warnings <> [] then ( let print (dir, base) = Printf.sprintf " - %s to %s\n" (OpamFilename.to_string (OpamFilename.create build_dir base)) (OpamFilename.Dir.to_string dir) in OpamGlobals.error "Installation of %s failed" (OpamPackage.to_string nv); let msg = Printf.sprintf "Some files in %s couldn't be installed:\n%s" (OpamFilename.prettify install_f) (String.concat "" (List.map print !warnings)) in failwith msg ) ); if not (!OpamGlobals.keep_build_dir || !OpamGlobals.debug) then OpamFilename.rmdir build_dir (* Prepare the package build: * apply the patches * substitute the files *) let prepare_package_build t nv = let opam = OpamState.opam t nv in (* Substitute the patched files.*) let patches = OpamFile.OPAM.patches opam in let iter_patches f = List.fold_left (fun acc (base, filter) -> if OpamFilter.opt_eval_to_bool (OpamState.filter_env ~opam t) filter then try f base; acc with e -> OpamMisc.fatal e; OpamFilename.Base.to_string base :: acc else acc ) [] patches in if !OpamGlobals.dryrun || !OpamGlobals.fake then ignore (iter_patches (fun base -> log "%s: applying %s.\n" (OpamPackage.name_to_string nv) (OpamFilename.Base.to_string base))) else let p_build = OpamPath.Switch.build t.root t.switch nv in OpamFilename.mkdir p_build; OpamFilename.in_dir p_build (fun () -> let all = OpamFile.OPAM.substs opam in let patches = OpamMisc.filter_map (fun (f,_) -> if List.mem f all then Some f else None ) patches in List.iter (OpamFilter.expand_interpolations_in_file (OpamState.filter_env ~opam t)) patches ); (* Apply the patches *) let patching_errors = iter_patches (fun base -> let root = OpamPath.Switch.build t.root t.switch nv in let patch = root // OpamFilename.Base.to_string base in log "%s: applying %s.\n" (OpamPackage.name_to_string nv) (OpamFilename.Base.to_string base); OpamFilename.patch patch p_build) in (* Substitute the configuration files. We should be in the right directory to get the correct absolute path for the substitution files (see [substitute_file] and [OpamFilename.of_basename]. *) OpamFilename.in_dir p_build (fun () -> List.iter (OpamFilter.expand_interpolations_in_file (OpamState.filter_env ~opam t)) (OpamFile.OPAM.substs opam) ); if patching_errors <> [] then ( let msg = Printf.sprintf "These patches didn't apply at %s:\n%s" (OpamFilename.Dir.to_string (OpamPath.Switch.build t.root t.switch nv)) (OpamMisc.itemize (fun x -> x) patching_errors) in failwith msg ) let download_package t nv = log "download_package: %a" (slog OpamPackage.to_string) nv; let name = OpamPackage.name nv in if !OpamGlobals.dryrun || !OpamGlobals.fake then Done (`Successful None) else let dir = try match OpamPackage.Name.Map.find name t.pinned with | Version _ -> Some (OpamPath.dev_package t.root nv) | _ -> Some (OpamPath.Switch.dev_package t.root t.switch name) with Not_found -> None in let of_dl = function | Some (Up_to_date f | Result f) -> `Successful (Some f) | Some (Not_available _) -> `Error () | None -> `Successful None in let job = match dir with | Some dir -> OpamState.download_upstream t nv dir @@| of_dl | None -> OpamState.download_archive t nv @@+ function | Some f -> assert (f = OpamPath.archive t.root nv); Done (`Successful (Some (F f))) | None -> let dir = OpamPath.dev_package t.root nv in OpamState.download_upstream t nv dir @@| of_dl in OpamProcess.Job.ignore_errors ~default:(`Error ()) job let extract_package t source nv = log "extract_package: %a from %a" (slog OpamPackage.to_string) nv (slog (OpamMisc.Option.to_string OpamTypesBase.string_of_generic_file)) source; if !OpamGlobals.dryrun then () else let build_dir = OpamPath.Switch.build t.root t.switch nv in OpamFilename.rmdir build_dir; let () = match source with | None -> () | Some (D dir) -> OpamFilename.copy_dir ~src:dir ~dst:build_dir | Some (F archive) -> OpamFilename.extract archive build_dir in let is_repackaged_archive = Some (F (OpamPath.archive t.root nv)) = source in if not is_repackaged_archive then OpamState.copy_files t nv build_dir; prepare_package_build t nv let string_of_commands commands = let commands_s = List.map (fun cmd -> String.concat " " cmd) commands in " " ^ if commands_s <> [] then String.concat "\n " commands_s else "Nothing to do." let compilation_env t opam = let env0 = OpamState.get_full_env ~opam ~force_path:true t in let env1 = [ ("MAKEFLAGS", ""); ("MAKELEVEL", ""); ("OPAM_PACKAGE_NAME", OpamPackage.Name.to_string (OpamFile.OPAM.name opam)); ("OPAM_PACKAGE_VERSION", OpamPackage.Version.to_string (OpamFile.OPAM.version opam)) ] @ env0 in OpamState.add_to_env t ~opam env1 (OpamFile.OPAM.build_env opam) let get_metadata t = let compiler = if t.compiler = OpamCompiler.system then let system_version = match OpamCompiler.get_system () with | None -> "" | Some c -> OpamCompiler.Version.to_string (OpamCompiler.version c) in Printf.sprintf "system (%s)" system_version else OpamCompiler.to_string t.compiler in [ ("compiler", compiler); ] let update_metadata t ~installed ~installed_roots ~reinstall = let installed_roots = OpamPackage.Set.inter installed_roots installed in let reinstall = OpamPackage.Set.inter installed_roots reinstall in (* XXX why _roots ? *) if not !OpamGlobals.dryrun then ( OpamFile.Installed.write (OpamPath.Switch.installed t.root t.switch) installed; OpamFile.Installed_roots.write (OpamPath.Switch.installed_roots t.root t.switch) installed_roots; OpamFile.Reinstall.write (OpamPath.Switch.reinstall t.root t.switch) reinstall ); {t with installed; installed_roots; reinstall} let removal_needs_download t nv = match OpamState.opam_opt t nv with | None -> OpamGlobals.warning "No opam file found to remove package %s. Stale files may remain." (OpamPackage.to_string nv); false | Some opam -> if OpamFile.OPAM.has_flag Pkgflag_LightUninstall opam then true else let commands = OpamFilter.commands (OpamState.filter_env ~opam t) (OpamFile.OPAM.remove opam) in (* We use a small hack: if the remove command is simply 'ocamlfind remove xxx' then, no need to extract the archive again. *) let use_ocamlfind = function | [] -> true | "ocamlfind" :: _ -> true | _ -> false in not (List.for_all use_ocamlfind commands) (* Remove a given package *) let remove_package_aux t ~metadata ?(keep_build=false) ?(silent=false) nv = log "Removing %a (%b)" (slog OpamPackage.to_string) nv metadata; let name = OpamPackage.name nv in (* Run the remove script *) let opam = OpamState.opam_opt t nv in let dot_install = OpamPath.Switch.install t.root t.switch name in let remove_job = match opam with | None -> OpamGlobals.msg "No OPAM file has been found!\n"; Done () | Some opam -> let env = compilation_env t opam in let p_build = OpamPath.Switch.build t.root t.switch nv in (* We try to run the remove scripts in the folder where it was extracted If it does not exist, we try to download and extract the archive again, if that fails, we don't really care. *) let remove = OpamFilter.commands (OpamState.filter_env ~opam t) (OpamFile.OPAM.remove opam) in let name = OpamPackage.Name.to_string name in let exec_dir, nameopt = if OpamFilename.exists_dir p_build then p_build, Some name else t.root , None in (* if remove <> [] || not (OpamFilename.exists dot_install) then *) (* OpamGlobals.msg "%s\n" (string_of_commands remove); *) let metadata = get_metadata t in let commands = OpamMisc.filter_map (function | [] -> None | cmd::args -> let text = OpamProcess.make_command_text name ~args cmd in Some (OpamSystem.make_command ?name:nameopt ~metadata ~text cmd args ~env:(OpamFilename.env_of_list env) ~dir:(OpamFilename.Dir.to_string exec_dir) ~verbose:!OpamGlobals.verbose ~check_existence:false)) remove in OpamProcess.Job.of_list ~keep_going:true commands @@+ function | Some (_,err) -> if not silent then OpamGlobals.warning "failure in package uninstall script, some files may remain:\n%s" (OpamProcess.string_of_result err); Done () | None -> Done () in let install = OpamFile.Dot_install.safe_read dot_install in let remove_files dst_fn files = let files = files install in let dst_dir = dst_fn t.root t.switch in List.iter (fun (base, dst) -> let dst_file = match dst with | None -> dst_dir // Filename.basename (OpamFilename.Base.to_string base.c) | Some b -> OpamFilename.create dst_dir b in OpamFilename.remove dst_file ) files in let remove_files_and_dir ?(quiet=false) dst_fn files = let dir = dst_fn t.root t.switch name in remove_files (fun _ _ -> dir) files; if OpamFilename.rec_files dir = [] then OpamFilename.rmdir dir else if not quiet && OpamFilename.exists_dir dir then OpamGlobals.warning "Directory %s is not empty, not removing" (OpamFilename.Dir.to_string dir) in let uninstall_files () = (* Remove build/ *) if not (keep_build || !OpamGlobals.keep_build_dir) then OpamFilename.rmdir (OpamPath.Switch.build t.root t.switch nv); (* Remove .config and .install *) log "Removing config and install files"; OpamFilename.remove (OpamPath.Switch.install t.root t.switch name); OpamFilename.remove (OpamPath.Switch.config t.root t.switch name); log "Removing files from .install"; remove_files OpamPath.Switch.sbin OpamFile.Dot_install.sbin; remove_files OpamPath.Switch.bin OpamFile.Dot_install.bin; remove_files_and_dir ~quiet:true OpamPath.Switch.lib OpamFile.Dot_install.libexec; remove_files_and_dir OpamPath.Switch.lib OpamFile.Dot_install.lib; remove_files OpamPath.Switch.stublibs OpamFile.Dot_install.stublibs; remove_files_and_dir OpamPath.Switch.share OpamFile.Dot_install.share; remove_files OpamPath.Switch.share_dir OpamFile.Dot_install.share_root; remove_files_and_dir OpamPath.Switch.etc OpamFile.Dot_install.etc; remove_files OpamPath.Switch.man_dir OpamFile.Dot_install.man; remove_files_and_dir OpamPath.Switch.doc OpamFile.Dot_install.doc; (* Remove the misc files *) log "Removing the misc files"; List.iter (fun (_,dst) -> if OpamFilename.exists dst then begin OpamGlobals.msg "Removing %s." (OpamFilename.to_string dst); if OpamGlobals.confirm "Continue ?" then OpamFilename.remove dst end ) (OpamFile.Dot_install.misc install); (* Cleanup if there was any stale overlay (unpinned but left installed package) *) if not (OpamState.is_pinned t name) then OpamState.remove_overlay t name; in let cleanup_meta () = (* Update the metadata *) let installed = OpamPackage.Set.remove nv t.installed in let installed_roots = OpamPackage.Set.remove nv t.installed_roots in let reinstall = OpamPackage.Set.remove nv t.reinstall in ignore (update_metadata t ~installed ~installed_roots ~reinstall) in remove_job @@+ fun () -> if not !OpamGlobals.dryrun then uninstall_files (); if metadata then cleanup_meta (); if not silent then OpamGlobals.msg "%s removed %s.%s\n" (if not !OpamGlobals.utf8 then "->" else OpamActionGraph.(action_color `rm (action_strings `rm))) (OpamGlobals.colorise `bold (OpamPackage.name_to_string nv)) (OpamPackage.version_to_string nv); Done () (* Removes build dir and source cache of package if unneeded *) let cleanup_package_artefacts t nv = log "Cleaning up artefacts of %a" (slog OpamPackage.to_string) nv; let build_dir = OpamPath.Switch.build t.root t.switch nv in if not !OpamGlobals.keep_build_dir && OpamFilename.exists_dir build_dir then OpamFilename.rmdir build_dir; let name = OpamPackage.name nv in let dev_dir = OpamPath.Switch.dev_package t.root t.switch name in if not (OpamState.is_package_installed t nv) then ( if OpamFilename.exists_dir dev_dir then ( log "Cleaning-up the switch repository"; OpamFilename.rmdir dev_dir ); log "Removing the local metadata"; OpamState.remove_metadata t (OpamPackage.Set.singleton nv); ); (* Remove the dev archive if no switch uses the package anymore *) let dev = OpamPath.dev_package t.root nv in if OpamFilename.exists_dir dev && not (OpamPackage.Set.mem nv (OpamState.all_installed t)) then ( log "Removing %a" (slog OpamFilename.Dir.to_string) dev; OpamFilename.rmdir dev; ) let sources_needed t g = PackageActionGraph.fold_vertex (fun act acc -> match act with | To_delete nv -> if removal_needs_download t nv then OpamPackage.Set.add nv acc else acc | To_change (None,nv) | To_recompile nv -> OpamPackage.Set.add nv acc | To_change (Some nv1, nv2) -> let acc = OpamPackage.Set.add nv2 acc in if removal_needs_download t nv1 then OpamPackage.Set.add nv1 acc else acc) g OpamPackage.Set.empty let remove_package t ~metadata ?keep_build ?silent nv = if !OpamGlobals.fake || !OpamGlobals.show then Done (OpamGlobals.msg "Would remove: %s.\n" (OpamPackage.to_string nv)) else remove_package_aux t ~metadata ?keep_build ?silent nv (* Build and install a package. Assumes the package has already been downloaded to its build dir. *) let build_and_install_package_aux t ~metadata:save_meta source nv = (* OpamGlobals.header_msg "Installing %s" (OpamPackage.to_string nv); *) extract_package t source nv; let opam = OpamState.opam t nv in let commands = OpamFile.OPAM.build opam @ (if !OpamGlobals.build_test then OpamFile.OPAM.build_test opam else []) @ (if !OpamGlobals.build_doc then OpamFile.OPAM.build_doc opam else []) @ OpamFile.OPAM.install opam in let commands = OpamFilter.commands (OpamState.filter_env ~opam t) commands in let env = OpamFilename.env_of_list (compilation_env t opam) in let name = OpamPackage.name_to_string nv in let metadata = get_metadata t in let dir = OpamPath.Switch.build t.root t.switch nv in let rec run_commands = function | (cmd::args)::commands -> let text = OpamProcess.make_command_text name ~args cmd in let dir = OpamFilename.Dir.to_string dir in OpamSystem.make_command ~env ~name ~metadata ~dir ~text ~verbose:!OpamGlobals.verbose ~check_existence:false cmd args @@> fun result -> if OpamFile.OPAM.has_flag Pkgflag_Verbose opam then List.iter (OpamGlobals.msg "%s\n") result.OpamProcess.r_stdout; if OpamProcess.is_success result then run_commands commands else ( OpamGlobals.error "The compilation of %s failed at %S." name (String.concat " " (cmd::args)); remove_package ~metadata:false t ~keep_build:true ~silent:true nv @@| fun () -> Some (OpamSystem.Process_error result) ) | []::commands -> run_commands commands | [] -> try install_package t nv; if save_meta then ( let installed = OpamPackage.Set.add nv t.installed in let installed_roots = OpamPackage.Set.add nv t.installed_roots in let reinstall = OpamPackage.Set.remove nv t.reinstall in let t = update_metadata t ~installed ~installed_roots ~reinstall in OpamState.install_metadata t nv; ); OpamGlobals.msg "%s installed %s.%s\n" (if not !OpamGlobals.utf8 then "->" else OpamActionGraph.(action_color `inst (action_strings `inst))) (OpamGlobals.colorise `bold name) (OpamPackage.version_to_string nv); Done None with e -> remove_package ~metadata:false t ~keep_build:true ~silent:true nv @@| fun () -> OpamMisc.fatal e; Some e in run_commands commands let build_and_install_package t ~metadata source nv = if not !OpamGlobals.fake then build_and_install_package_aux t ~metadata source nv else (OpamGlobals.msg "(simulation) Building and installing %s.\n" (OpamPackage.to_string nv); Done None) opam-full-1.2.2/src/client/opamConfigCommand.ml0000644000175000017500000001677412517374212020131 0ustar useruser(**************************************************************************) (* *) (* Copyright 2012-2013 OCamlPro *) (* Copyright 2012 INRIA *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) let log fmt = OpamGlobals.log "CONFIG" fmt let slog = OpamGlobals.slog open OpamTypes open OpamState.Types let need_globals ns = ns = [] || List.mem OpamPackage.Name.global_config ns (* Implicit variables *) let implicits t ns = List.fold_left (fun acc name -> let vars = if name = OpamPackage.Name.global_config then OpamState.global_variable_names else OpamState.package_variable_names @ try let nv = try OpamState.find_installed_package_by_name t name with | Not_found -> OpamPackage.Set.choose (OpamState.find_packages_by_name t name) in List.map (fun (v,desc,_) -> OpamVariable.to_string v,desc) (OpamFile.OPAM.features (OpamState.opam t nv)) with Not_found -> [] in List.rev_append (List.rev_map (fun (variable,desc) -> OpamVariable.Full.create name (OpamVariable.of_string variable), desc ) vars) acc) [] ns let help t = OpamGlobals.msg "# Global OPAM configuration variables\n\n"; let global = OpamState.dot_config t OpamPackage.Name.global_config in List.iter (fun var -> OpamGlobals.msg "%-20s %s\n" (OpamVariable.to_string var) (match OpamFile.Dot_config.variable global var with | Some c -> OpamVariable.string_of_variable_contents c | None -> "") ) (OpamFile.Dot_config.variables global); OpamGlobals.msg "\n# Global variables from the environment\n\n"; List.iter (fun (varname, doc) -> let var = OpamVariable.of_string varname in OpamGlobals.msg "%-20s %-20s # %s\n" varname (OpamFilter.ident_string (OpamState.filter_env t) ~default:"" ([],var,None)) doc) OpamState.global_variable_names; OpamGlobals.msg "\n# Package variables ('opam config list PKG' to show)\n\n"; List.iter (fun (var, doc) -> OpamGlobals.msg "PKG:%-37s # %s\n" var doc) OpamState.package_variable_names (* List all the available variables *) let list ns = log "config-list"; let t = OpamState.load_state "config-list" in if ns = [] then help t else let globals = if need_globals ns then [OpamPackage.Name.global_config, OpamState.dot_config t OpamPackage.Name.global_config] else [] in let configs = globals @ OpamPackage.Set.fold (fun nv l -> let name = OpamPackage.name nv in let file = OpamState.dot_config t (OpamPackage.name nv) in (name, file) :: l ) t.installed [] in let variables = implicits t ns @ List.fold_left (fun accu (name, config) -> (* add all the global variables *) List.fold_left (fun accu variable -> (OpamVariable.Full.create name variable, "") :: accu ) accu (OpamFile.Dot_config.variables config) ) [] configs in let contents = List.map (fun (v,descr) -> v, descr, (OpamFilter.ident_string (OpamState.filter_env t) ~default:"#undefined" (OpamFilter.ident_of_var v))) variables in List.iter (fun (variable, descr, value) -> OpamGlobals.msg "%-20s %-40s %s\n" (OpamVariable.Full.to_string variable) value (if descr <> "" then "# "^descr else "") ) contents let print_env env = List.iter (fun (k,v) -> OpamGlobals.msg "%s=%S; export %s;\n" k v k; ) env let print_csh_env env = List.iter (fun (k,v) -> OpamGlobals.msg "setenv %s %S;\n" k v; ) env let print_sexp_env env = OpamGlobals.msg "(\n"; List.iter (fun (k,v) -> OpamGlobals.msg " (%S %S)\n" k v; ) env; OpamGlobals.msg ")\n" let print_fish_env env = List.iter (fun (k,v) -> match k with | "PATH" | "MANPATH" -> let v = OpamMisc.split_delim v ':' in OpamGlobals.msg "set -gx %s %s;\n" k (OpamMisc.sconcat_map " " (Printf.sprintf "%S") v) | _ -> OpamGlobals.msg "set -gx %s %S;\n" k v ) env let env ~csh ~sexp ~fish ~inplace_path = log "config-env"; let t = OpamState.load_env_state "config-env" in let env = OpamState.get_opam_env ~force_path:(not inplace_path) t in if sexp then print_sexp_env env else if csh then print_csh_env env else if fish then print_fish_env env else print_env env let subst fs = log "config-substitute"; let t = OpamState.load_state "config-substitute" in List.iter (OpamFilter.expand_interpolations_in_file (OpamState.filter_env t)) fs let quick_lookup v = let name = OpamVariable.Full.package v in let var = OpamVariable.Full.variable v in if name = OpamPackage.Name.global_config then ( let root = OpamPath.root () in let switch = match !OpamGlobals.switch with | `Command_line s | `Env s -> OpamSwitch.of_string s | `Not_set -> let config = OpamPath.config root in OpamFile.Config.switch (OpamFile.Config.read config) in let config = OpamPath.Switch.global_config root switch in let config = OpamFile.Dot_config.read config in match OpamState.get_env_var v with | Some _ as c -> c | None -> if OpamVariable.to_string var = "switch" then Some (S (OpamSwitch.to_string switch)) else OpamFile.Dot_config.variable config var ) else None let variable v = log "config-variable"; let contents = match quick_lookup v with | Some c -> c | None -> let t = OpamState.load_state "config-variable" in OpamFilter.ident_value (OpamState.filter_env t) ~default:(S "#undefined") (OpamFilter.ident_of_var v) in OpamGlobals.msg "%s\n" (OpamVariable.string_of_variable_contents contents) let setup user global = log "config-setup"; let t = OpamState.load_state "config-setup" in OpamState.update_setup t user global let setup_list shell dot_profile = log "config-setup-list"; let t = OpamState.load_state "config-setup-list" in OpamState.display_setup t shell dot_profile let exec ~inplace_path command = log "config-exec command=%a" (slog (String.concat " ")) command; let t = OpamState.load_state "config-exec" in let cmd, args = match command with | [] -> OpamSystem.internal_error "Empty command" | h::_ as l -> h, Array.of_list l in let env = let env = OpamState.get_full_env ~force_path:(not inplace_path) t in let env = List.rev_map (fun (k,v) -> k^"="^v) env in Array.of_list env in raise (OpamGlobals.Exec (cmd, args, env)) opam-full-1.2.2/src/Makefile0000644000175000017500000001417112517374212014365 0ustar useruser-include ../Makefile.config ifndef version $(error Please run ./configure) endif all: $(MAKE) opam-lib $(MAKE) opam $(MAKE) opam-check $(MAKE) opam-admin $(MAKE) opam-installer $(MAKE) opamlfind $(MAKE) opam-admin.top # -- OCAMLFLAGS = -g -w +a-4-9-32-41-44-45-48 OCAMLLDFLAGS = -g -w +a-4-9-32-41-44-45-48 ifeq ($(OCAML_4),true) OCAMLFLAGS += -bin-annot OCAMLLDFLAGS += -bin-annot endif ifeq ($(OCAML_4_01),true) OCAMLFLAGS += -short-paths endif ifeq ($(OCAML_4_02),true) OCAMLFLAGS += -safe-string OCAMLLDFLAGS += -safe-string endif export OCAMLFLAGS OCAMLLDFLAGS USE_BYTE ?= LIBEXT = $(if $(USE_BYTE),.cma,.cmxa) BINTARGET = $(if $(USE_BYTE),byte-code,native-code) # -- ifndef HAS_LIBEXT HAS_LIBEXT := $(wildcard ../src_ext/lib) endif ifneq ($(HAS_LIBEXT),) EXT_INCDIRS = ../src_ext/lib LIBS = unix extlib re cmdliner graph cudf dose_common dose_debian dose_algo uutf jsonm else ifeq ($(HAS_PACKAGES),) $(error Dependencies missing. Either run 'make lib-ext' or install them and re-run './configure') endif export PACKS # Reset command name for ocamlfind OCAMLC = ocamlc OCAMLOPT = ocamlopt OCAMLDEP = ocamldep OCAMLLEX = ocamllex OCAMLYACC = ocamlyacc OCAMLMKLIB = ocamlmklib OCAMLDOC = ocamldoc export OCAMLC OCAMLOPT OCAMLDEP OCAMLLEX OCAMLYACC OCAMLMKLIB OCAMLDOC endif # -- SUBS = core solver repositories client OPAMLIB = $(patsubst %,./opam-%,$(SUBS)) INCDIRS = $(EXT_INCDIRS) $(SUBS) export INCDIRS opam-lib.byte: $(MAKE) $(OPAMLIB:=.cma) opam-lib.native: $(MAKE) $(OPAMLIB:=.cmxa) opam-lib: opam-lib.byte $(if $(USE_BYTE),,opam-lib.native) opam-admin.top @ addmli = $(foreach ml,$(2),$(wildcard $(addsuffix .mli,$(basename $(1)/$(ml)))) $(1)/$(ml)) subtarget = SUBTARGET=$(if $(patsubst %.cma,,$@),native-code-library,byte-code-library) opam-%.cma opam-%.cmxa: $(MAKE) -f $(OCAMLMAKEFILE) subprojs SUBPROJS=$* $(subtarget) ALWAYS: @ # -- opam-core -- # opam-core.cma opam-core.cmxa: core/opamScript.ml core/opamCompat.ml core/opamCompat.mli ALWAYS core/opamScript.ml: ../shell core/opamVersion.ml ocaml ../shell/crunch.ml "complete" < ../shell/opam_completion.sh > $@ ocaml ../shell/crunch.ml "complete_zsh" < ../shell/opam_completion_zsh.sh >> $@ ocaml ../shell/crunch.ml "switch_eval" < ../shell/opam_switch_eval.sh >> $@ ifeq ($(OCAML_4_02),true) COMPATV = 4.02 else COMPATV = 4.01 endif core/opamCompat.%: core/opamCompat.%.$(COMPATV) cp -f $< $@ SRC_core = \ opamCompat.ml \ opamJson.ml \ opamLineLexer.mll \ opamMisc.ml \ opamScript.ml \ opamVersion.ml \ opamGlobals.ml \ opamProcess.ml \ opamRepositoryName.ml \ opamSwitch.ml \ opamSystem.ml \ opamParallel.ml \ opamFilename.ml \ opamPackage.ml \ opamVariable.ml \ opamFormula.ml \ opamCompiler.ml \ opamTypes.mli \ opamTypesBase.ml \ opamPath.ml \ opamParser.mly \ opamLexer.mll \ opamFormat.ml \ opamFilter.ml \ opamFile.ml \ opamActionGraph.ml \ opamRepository.ml define PROJ_core SOURCES = $(call addmli,core,$(SRC_core)) RESULT = opam-core endef export PROJ_core # -- opam-solver -- # opam-solver.cma: opam-core.cma opam-solver.cmxa: opam-core.cmxa SRC_solver = \ opamCudf.ml \ opamHeuristic.ml \ opamSolver.ml define PROJ_solver SOURCES = $(call addmli,solver,$(SRC_solver)) RESULT = opam-solver endef export PROJ_solver # -- opam-repositories -- # opam-repositories.cma: opam-core.cma ALWAYS opam-repositories.cmxa: opam-core.cmxa ALWAYS SRC_repositories = \ opamHTTP.ml \ opamLocal.ml \ opamVCS.ml \ opamGit.ml \ opamDarcs.ml \ opamHg.ml define PROJ_repositories SOURCES = $(call addmli,repositories,$(SRC_repositories)) RESULT = opam-repositories endef export PROJ_repositories # -- opam-client -- # opam-client.cma: opam-core.cma opam-solver.cma opam-repositories.cma ALWAYS opam-client.cmxa: opam-core.cmxa opam-solver.cmxa opam-repositories.cmxa ALWAYS SRC_client = \ opamState.ml \ opamAction.ml \ opamSolution.ml \ opamSwitchCommand.ml \ opamConfigCommand.ml \ opamRepositoryCommand.ml \ opamPinCommand.ml \ opamClient.ml define PROJ_client SOURCES = $(call addmli,client,$(SRC_client)) RESULT = opam-client endef export PROJ_client # -- opam binary -- # client/opamGitVersion.ml: ALWAYS cd .. && ocaml shell/get-git-id.ml src/$@ touch $@ opam: $(addsuffix $(LIBEXT),$(OPAMLIB)) client/opamGitVersion.ml ALWAYS $(MAKE) -f $(OCAMLMAKEFILE) subprojs SUBPROJS=opam SUBTARGET=$(BINTARGET) define PROJ_opam SOURCES = $(call addmli,client,opamGitVersion.ml opamArg.ml opamMain.ml) RESULT = opam LIBS = $(LIBS) $(OPAMLIB) endef export PROJ_opam # -- opam utils -- # TOOLS = opam-check opam-admin opam-installer opamlfind $(TOOLS): opam ALWAYS $(MAKE) -f $(OCAMLMAKEFILE) subprojs SUBPROJS=$@ SUBTARGET=$(BINTARGET) define PROJ_opam-check SOURCES = tools/opam_check.ml RESULT = opam-check LIBS = $(LIBS) $(OPAMLIB) endef export PROJ_opam-check SRC_opam-admin = \ opam_mk_repo.ml \ opam_repo_check.ml \ opam_stats.ml \ opam_depexts_change.ml \ opam_findlib.ml \ opam_rename.ml \ opam_admin.ml define PROJ_opam-admin SOURCES = $(call addmli,tools,$(SRC_opam-admin)) RESULT = opam-admin LIBS = $(LIBS) $(OPAMLIB) endef export PROJ_opam-admin define PROJ_opam-installer SOURCES = tools/opam_installer.ml RESULT = opam-installer LIBS = $(LIBS) $(OPAMLIB) endef export PROJ_opam-installer define PROJ_opamlfind SOURCES = tools/opamlfind.ml RESULT = opamlfind LIBS = $(LIBS) $(OPAMLIB) endef export PROJ_opamlfind opam-admin.top: opam-lib.byte ALWAYS $(MAKE) -f $(OCAMLMAKEFILE) subprojs SUBPROJS=opam-admin-top SUBTARGET=top define PROJ_opam-admin-top SOURCES = tools/opam_admin_top.ml RESULT = opam-admin LIBS = $(LIBS) $(OPAMLIB) endef export PROJ_opam-admin-top # -- ifndef SUBPROJS export SUBPROJS = $(SUBS) opam opam-check opam-admin opam-installer opamlfind opam-admin-top endif OCAMLMAKEFILE = ../OCamlMakefile export OCAMLMAKEFILE clean-aux: rm -f $(OPAMLIB:=.cma) $(OPAMLIB:=.cmxa) $(OPAMLIB:=.a) $(TOOLS) opam-admin.top opam_admin_top.* rm -f client/opamGitVersion.ml core/opamScript.ml core/opamCompat.ml core/opamCompat.mli clean: clean-aux %: $(MAKE) -f $(OCAMLMAKEFILE) subprojs SUBTARGET=$@ opam-full-1.2.2/opam-devel.opam0000644000175000017500000000243112517374212015041 0ustar useruseropam-version: "1.2" name: "opam-test-beta" version: "1.2.1~beta2" maintainer: "opam-devel@lists.ocaml.org" authors: [ "Thomas Gazagnaire " "Louis Gesbert " ] homepage: "https://opam.ocaml.org" bug-reports: "https://github.com/ocaml/opam/issues" dev-repo: "https://github.com/ocaml/opam" build: [ ["./configure"] [make "opam"] ] install: [ ["sh" "-c" "echo \"%{version}%\" > \"%{root}%/opam.version\""] ["install" "--backup" "-m" "755" "src/opam" "%{root}%/opam"] ] remove: ["rm" "-f" "%{root}%/opam" "%{root}%/opam.version"] depends: [ "ocamlgraph" "cmdliner" "dose" {>= "3.3"} "cudf" "re" {>= "1.2.0"} "ocamlfind" "jsonm" ] # Restrict self-upgrade to "official" versions, just in case available: [ opam-version >= "1.2" & (compiler = "3.12.1" | compiler = "4.00.0" | compiler = "4.00.1" | compiler = "4.01.0" | compiler = "4.02.0" | compiler = "4.02.1" | (compiler = "system" & ocaml-version >= "3.12.1" & ocaml-version <= "4.02.0")) ] post-messages: [ " IMPORTANT: The new version of OPAM has been installed to %{root}%, and it will \ be used by default for ALL switches. In case of trouble, use `--no-self-upgrade' \ to bypass, or remove `opam' and `opam-version' from %{root}% to revert. " {success} ] opam-full-1.2.2/AUTHORS0000644000175000017500000000054712517374212013210 0ustar useruserThomas Gazagnaire Anil Madhavapeddy Fabrice Le Fessant Frederic Tuong Louis Gesbert Guillem Rieu Vincent Bernardoff Roberto Di Cosmo opam-full-1.2.2/Makefile.config.in0000644000175000017500000000151012517374212015440 0ustar useruserOCAMLVERSION = @OCAMLVERSION@ OCAML_4 = @ocaml_4@ OCAML_4_01 = @ocaml_4_01@ OCAML_4_02 = @ocaml_4_02@ datarootdir = @datarootdir@ prefix = @prefix@ mandir = @mandir@ version = @PACKAGE_VERSION@ FETCH = @fetch@ HAS_PACKAGES = @hasalldeps@ USE_BYTE := $(if $(subst no,,@OCAMLOPT@),,true) PACKS = @OCAML_PKG_unix@ @OCAML_PKG_extlib@ @OCAML_PKG_re@ @OCAML_PKG_re_emacs@ @OCAML_PKG_re_str@ @OCAML_PKG_re_perl@ @OCAML_PKG_re_pcre@ @OCAML_PKG_re_glob@ @OCAML_PKG_cmdliner@ @OCAML_PKG_ocamlgraph@ @OCAML_PKG_cudf@ @OCAML_PKG_dose3@ @OCAML_PKG_jsonm@ OCAMLFIND = @OCAMLFIND@ OCAML = @OCAML@ OCAMLC = @OCAMLC@ OCAMLOPT = @OCAMLOPT@ OCAMLDEP = @OCAMLDEP@ OCAMLLEX = @OCAMLLEX@ OCAMLYACC = @OCAMLYACC@ OCAMLMKLIB = @OCAMLMKLIB@ OCAMLDOC = @OCAMLDOC@ export OCAMLVERSION OCAMLFIND OCAML OCAMLC OCAMLOPT OCAMLDEP OCAMLLEX OCAMLYACC OCAMLMKLIB OCAMLDOC opam-full-1.2.2/CHANGES0000644000175000017500000005476412517374212013145 0ustar useruser1.2.2 * Fixed wrong locks being taken during `switch reinstall` (#2051) * Fixed `config report` that wasn't displaying the external solver (#2059) * Follow glibc standard on detecting an UTF8 locale (#2065) * Fixed issues with fish shell init scripts (#2063) * Restored printing of commands with `--verbose` and `--dry-run` * More concise printing of conflicts, with accurate version numbers * Small improvements to the causes of actions * Fixed issue causing the state cache not to be used on some OSes (OSX) (#2077) * Added numbers to lint checks, and some new checks * Restored the handling of a simple path to an `aspcud`-compatible executable in variable OPAMEXTERNALSOLVER (#2085) * Added package universe output to new PEF format for diagnostics * Prioritise newer versions even when the latest can't be installed (#2109) * Automatically install plugins on `opam plugin-name` (#2092) * Fixed a fd leak on solver calls (#2134) * Accept opam files with errors when no debug or strict options are set, for easier format updates * Add `opam list --resolve` to get dependencies as a consistent set of packages * Provide the expected checksum to download commands * Changed return code of `opam list` when no patterns are supplied and the list is empty 1.2.1 * Non-system compiler definitions without source are now allowed * Better handling of compiler "base" packages allows to move build instructions from compiler definitions to packages * Rewritten action resolution mechanism to be based on atomic actions. Actions are not aborted anymore on first failure when there is no inter-dependency * Rewritten parallel command execution engine * Better display of actions, lots of improved messages * `opam upgrade pkg` now fails if no new version of `pkg` can be installed * fixed shell configuration for various shells * Updated Dose dependency to 3.3 * Fixed behaviour of `opam switch` and related commands when a switch is locally set in a shell (through `OPAMSWITCH`) * Better behaviour on failed `opam switch` * New pinning mode: when pinning using version-control on a local path and without a branch specified, use current file tree, but limited to version-tracked files * Faster and cleaner handling of downloads * Now compiles with --safe-string on OCaml 4.02, better compatibility handling * `opam unpin` now accepts multiple arguments * `opam pin add . ` is now allowed to specify the advertised version * Fixed bug leading to a bad `CAML_LD_LIBRARY_PATH` when switching from system * Better `opam lint`, reporting warnings and errors, including format errors * `opam config setup` now takes `--shell=` instead of `--sh`, `--csh`, `--fish`, `--zsh` * Provisional feature: dependency flag `dev` is accepted (but does nothing) * Provisional feature: field `features` in opam files implemented (beta), not for use in production * Better definition of the `filter` language within opam files: propagates undefined values, bool-to-string converter syntax * Provisional feature: `verbose` may be specified in package flags * OPAM git-like plugins (commands of the form opam-xxx) are now searched in the correct OPAM path * ~/.opam/config doesn't refer to OPAM's patch-version anymore, to allow downgrading * Recognise .opam files and directories when pinning a package to source * Cleaned up debug and verbose messages, allow more control (`-v` can now be repeated) * Pinning URL can now be explicit in the form `VC+URL`, e.g. `git+ssh://`, `hg+https://`... * New flexible way to specify download and solver commands in `~/.opam/config` or in variables `OPAMFETCH` and `OPAMEXTERNALSOLVER` * Lots of bug-fixes 1.2.0 * Handle locally installed self-upgrade opam binary (#1257) * Added `opam list --depends-on` to show reverse dependencies (#693) * More consistent checks on user-specified packages (#1241) * Handle version constraints from the command line (`package>=version`) (#380) * Output clear and concise messages on non solvable requests (#595, #1238) * Much better internal parser. File locations in error messages (#1260, #1222) * Removed dependency on camlp4 (#917) * Fixed orphan packages handling (installed packages with no upstream) (#1198) * Solver: optimize default preferences, depending on the solver version. New --criteria option (#1208) * Better PATH modifications handling, add 'opam config env --inplace-path' (#1189, #1749) * Specify variable overrides with environment OPAMVAR_name (#1153) * Much better overall failsafe behaviour. Error reports on interruption (#1202, #1125, #1188...) * Better action processing, with downloads first (#984) * Much improved and faster interface with the Cudf solver (#1185, #1179) * Ask the user to confirm actions whenever non-trivial (#1165) * Added option --show-actions, made --dry-run simulate actions (#1142) * Now prints meaningful causes explaining the actions (#1174) * Fixed the stats displayed after update (#1161) * Added variables to query ocaml native tools and arch (#979) * Enable packagers to specify mirrors in url files (#807) * Cleaned up the command-line interface (#1250, #1170, #1472). Incompatible changes: - 'opam config exec': takes command args directly rather than as a string (use -- for command arguments) - 'opam switch import|export': now have a mandatory FILE argument. '-f' no longer accepted. - 'opam pin' now takes a subcommand 'add', 'remove', 'list' or 'edit'. - 'opam config -env': no longer accepted for 'opam config env' - '--no-aspcud' is now '--use-internal-solver'. - Removed unused `opam config -I`, `opam config {asm,byte}{comp,link}` - '-r' isn't accepted anymore for '--root' * Much extended pinning features, with the ability to use opam files from the source, pin packages that don't exist in a repository, fill a local opam file from a template, etc. * Improved the internal solver to handle much larger problems (#1358) * Use Unix.lockf for more reliable internal repository locks (#1299) * Large performance improvements (#1363) * Upgraded external dependencies to dose 3.2.2, ocamlgraph 1.8.5, cmdliner 0.9.4, cudf 0.7 * Switch export file now include pinning data. Pinned package restored through 'opam switch import' (#1393) * Meaningful messages explaining why packages aren't available (#1419, #1398) * More informative 'opam config list', more complete 'opam config var' * Added 'opam config cudf-universe' for use in external tools * opam files: added a 'dev-repo' field, and the experimental 'flags' field (#1217, #1472) * Generate an opam-admin.top to easily apply scripts on a package repository (#1454). Provide scripts to ease adding new metadata ('dev-repo', etc.) * Added 'opam upgrade --fixup' to save the day if your installed package set gets inconsistent. * Fixed some return codes * Added option to query (recursive) (reverse) dependencies and external dependencies to 'opam list * Fixed opam init for some shells * OPAM search now includes the 'syntax' and 'libs' fields in the search, as well as 'findlib' files * 'opam source' command to get the package archive or upstream source easily * Added an 'install' field in opam files, to separate from build * Added the 'build', 'test' and 'doc' dependency flags to limit the scope of some dependencies * Added Check for common dependencies at init time * Pinning to a local git directory pins as path, but advertises pinning as git will now automatically select the pin kind to 'git' (#1555) * Fixed init scripts for fish and csh (#952) * More reliable and faster usage of git branches in the git backend * Friendlier env variable handling (true/1/yes or false/0/no/"" for true and false) (#1608) * Specify what is not rather than 'already up-to-date' when some packages couldn't be upgradedd (#1645) * Override Make variables in sub-processes (#1617) * 'opam update' no longer needed after 'opam repo add' * Attempt to read files in 'permissive mode' when they claim a newer OPAM version (#1662) * Fixed ignore of SIGPIPE in sub-processes (#1681) * New shell completion scripts * Added 'opam lint' to perform checks on opam files * Use the published version of jsonm rather than include it (#1574) * Changed findlib package name from 'opam' to 'opam-lib' * Hundreds of smaller fixes and UI improvements 1.1.2 * Rewritten, more compatible build system based on Makefiles (#1362, #1424) 1.1.1 * Fix `opam-admin make -r` (#990) * Explicitly prettyprint list of lists, to fix `opam-admin depexts` (#997) * Tell the user which fields is invalid in a configuration file (#1016) * Add `OpamSolver.empty_universe` for flexible universe instantiation (#1033) * Add `OpamFormula.eval_relop` and `OpamFormula.check_relop` (#1042) * Change `OpamCompiler.compare` to match `Pervasives.compare` (#1042) * Add `OpamCompiler.eval_relop` (#1042) * Add `OpamPackage.Name.compare` (#1046) * Add types `version_constraint` and `version_formula` to `OpamFormula` (#1046) * Clearer command aliases. Made `info` an alias for `show` and added the alias `uninstall` (#944) * Fixed `opam init --root=` (#1047) * Display OS constraints in `opam info` (#1052) * Add a new 'opam-installer' script to make `.install` files usable outside of opam (#1026) * Add a `--resolve` option to `opam-admin make` that builds just the archives you need for a specific installation (#1031) * Fixed handling of spaces in filenames in internal files (#1014) * Replace calls to `which` by a more portable call (#1061) * Fixed generation of the init scripts in some cases (#1011) * Better reports on package patch errors (#987, #988) * More accurate warnings for unknown package dependencies (#1079) * Added `opam config report` to help with bug reports (#1034) * Do not reinstall dev packages with `opam upgrade ` (#1001) * Be more careful with `opam init` to a non-empty root directory (#974) * Cleanup build-dir after successful compiler installation to save on space (#1006) * Improved OSX compatibility in the external solver tools (#1074) * Fixed messages printed on update that were plain wrong (#1030) * Improved detection of meaningful changes from upstream packages to trigger recompilation 1.1.0 [Oct 2013] * Fix update of dev packages (#962) * Add support for zip source archives (#958) * Add `OPAMCURL` environment variable to control invocation of curl (#960) * Ensure repository redirects only happen for http remotes (#955) * Turn malformed package files into warnings instead of hard errors (#957) * Improve robustness of pinned package update (#949) * Finish conversion of default repository to (#948) * Fix regression in handling archives with no extension (treat them as tar again) (#972) * Fixed stale archives causing packages to be marked as NEW when they weren't (#945) 1.1.0RC1 [Oct 2013] * Add `make cold` target to build OPAM without a system OCaml installed (#910) * More informative error messages from `curl` (#905) * Document use of `OPAMCOLOR` for optional ANSI coloring * Add `opam-admin depexts` utility to rewrite OPAM files with external dependencies * Added `repo` files for repository meta-information * Added support for repo redirections * Added scripts for automated testing in Travis * Fixed bug in opam-admin that could keep not up-to-date archives * Added an `opam-admin depexts` script to ease handling of external dependencies * Added the `--deps-only` option to `opam install` * Fixed upgrade with corner-cases of orphan packages * Added a `note` display form * Better handling of external solver failures, and added a `--no-aspcud` option * Fixed unpinning of some installed packages * Fixed upgrade of metadata from 1.0 when there are orphan custom compilers 1.1.0-beta [Sept 2013] * Automatic backup before any operation which might alter the list of installed packages * Support for arbitrary sub-directories for metadata repositories * Lots of colors * New option `opam update -u` equivalent to `opam update && opam upgrade --yes` * New `opam-admin` tool, bundling the features of `opam-mk-repo` and `opam-repo-check` + new 'opam-admin stats' tool * New `available`: field in opam files, superseding `ocaml-version` and `os` fields * Package names specified on the command-line are now understood case-insensitively (#705) * Fixed parsing of malformed opam files (#696) * Fixed recompilation of a package when uninstalling its optional dependencies (#692) * Added conditional post-messages support, to help users when a package fails to install for a known reason (#662) * Rewrite the code which updates pin et dev packages to be quicker and more reliable * Add {opam,url,desc,files/} overlay for all packages * `opam config env` now detects the current shell and outputs a sensible default if no override is provided. * Improve `opam pin` stability and start display information about dev revisions * Add a new `man` field in `.install` files * Support hierarchical installation in `.install` files * Add a new `stublibs` field in `.install` files * OPAM works even when the current directory has been deleted * speed-up invocation of `opam config var VARIABLE` when variable is simple (eg. `prefix`, `lib`, ...) * `opam list` now display only the installed packages. Use `opam list -a` to get the previous behavior. * Inverse the depext tag selection (useful for `ocamlot`) * Add a `--sexp` option to `opam config env` to load the configuration under emacs * Purge `~/.opam/log` on each invocation of OPAM * System compiler with versions such as `version+patches` are now handled as if this was simply `version` * New `OpamVCS` functor to generate OPAM backends * More efficient `opam update` * Switch license to LGPL with linking exception * `opam search` now also searches through the tags * minor API chanages for `API.list` and `API.SWITCH.list` * Improve the syntax of filters * Add a `messages` field * Add a `--jobs` command line option and add `%{jobs}%` to be used in OPAM files * Various improvments in the solver heuristics * By default, turn-on checking of certificates for downloaded dependency archives: use `./configure --disable-certificate-check` to go back to the previous behavior * Check the md5sum of downloaded archives when compiling OPAM * Improved `opam info` command (more information, non-zero error code when no patterns match) * Display OS and OPAM version on internal errors to ease error reporting * Fix `opam reinstall` when reinstalling a package wich is a dependency of installed packages (regression introduced in 0.9.5) * Export and read `OPAMSWITCH` to be able to call OPAM in different switches * `opam-client` can now be used in a toplevel * `-n` now means `--no-setup` and not `--no-checksums` anymore * Fix support for FreeBSD * Fix installation of local compilers with local paths endings with `.../ocaml/` * Fix the contents of `~/.opam/opam-init/variable.sh` after a switch 1.0.0 [Mar 2013] * Improve the lexer performance (thx to @oandrieu) * Fix various typos (thx to @chaudhuri) * Fix build issue (thx to @avsm) 0.9.6 [Mar 2013] * Fix installation of pinned packages on BSD (thx to @smondet) * Fix configuration for zsh users (thx to @AltGr) * Fix loading of `~/.profile` when using dash (eg. in Debian/Ubuntu) * Fix installation of packages with symbolic links (regression introduced in 0.9.5) 0.9.5 [Mar 2013] * If necessary, apply patches and substitute files before removing a package * Fix `opam remove --keep-build-dir` keeps the folder if a source archive is extracted * Add build and install rules using ocamlbuild to help distro packagers * Support arbitrary level of nested subdirectories in packages repositories * Add `opam config exec "CMD ARG1 ... ARGn" --switch=SWITCH` to execute a command in a subshell * Improve the behaviour of `opam update` wrt. pinned packages * Change the default external solver criteria (only useful if you have aspcud installed on your machine) * Add support for global and user configuration for OPAM (`opam config setup`) * Stop yelling when OPAM is not up-to-date * Update or generate `~/.ocamlinit` when running `opam init` * Fix tests on *BSD (thx Arnaud Degroote) * Fix compilation for the source archive 0.9.4 [Feb 2013] * Disable auto-removal of unused dependencies. This can now be enabled on-demand using `-a` * Fix compilation and basic usage on Cygwin * Fix BSD support (use `type` instead of `which` to detect existing commands) * Add a way to tag external dependencies in OPAM files * Better error messages when trying to upgrade pinned packages * Display `depends` and `depopts` fields in `opam info` * `opam info pkg.version` shows the metadata for this given package version * Add missing `doc` fields in `.install` files * `opam list` now only shows installable packages 0.9.3 [Feb 2013] * Add system compiler constraints in OPAM files * Better error messages in case of conflicts * Cleaner API to install/uninstall packages * On upgrade, OPAM now perform all the remove action first * Use a cache for main storing OPAM metadata: this greatly speed-up OPAM invocations * after an upgrade, propose to reinstall a pinned package only if there were some changes * improvements to the solver heuristics * better error messages on cyclic dependencies 0.9.2 [Jan 2013] * Install all the API files * Fix `opam repo remove repo-name` * speed-up `opam config env` * support for `opam-foo` scripts (which can be called using `opam foo`) * 'opam update pinned-package' works * Fix 'opam-mk-repo -a' * Fix 'opam-mk-repo -i' * clean-up pinned cache dir when a pinned package fails to install 0.9.1 [Jan 2013] * Use ocaml-re 1.2.0 0.9.0 [Jan 2013] * add a new `--fake` option to simulate build and installation of packages. Use this option this care, it can easily corrupt the state of OPAM. * Better messages in case of error * OPAM proposes better solutions to the user * support for installed roots and auto-clean of unused packages * rename `--cores` to `--jobs` * better error messages for wrong argument of 'opam init' * show the root causes of actions done by OPAM * opam import and export now uses -f to specify the filename, and uses stdin and stdout if no filename is specified * Fix environment initialisation for some corner-cases * Add a way to specify how to run tests and build documentation for the packages * Display homepage, authors, doc link, license with 'opam info' * Improve `opam remove` efficiency when using `ocamlfind` command(s) only * Git pinning now works with commits/tags/branches * `opam init` works without preinstalled compiler * Support for DARCS backends * Each global command-line flag `xxx` as can be set using the `OPAMxxx` environment variable instead * Better display of compiler switch (+ read compiler descriptions) * Clearer error message when trying to pin a non-existing package * Fix issue with pinning to version number * Add a `shared` location to be used in OPAM files * Improve (but break) the command-line interface by using cmdliner 0.8.2 [Dec 2012] * Fix an issue with `opam reinstall` where packages were reinstalled in reverse order 0.8.1 [Nov 2012] * Simplify string substitution in OPAM files * Recompile the installed packages when the system compiler is upgraded * Fix various regressions in pinned and dev packages introduced in 0.8.0 0.8.0 [Nov 2012] * Improvements in the solver interface and API * The solver now use an external SAT-solver (aspcud) if found in the path * More expressive constraints in optional dependencies * Clean-up the build directory when build succeeds 0.7.7 [Oct 2012] * Add an `--alias` global command-line argument to overwrite the default alias value * Allow more concurrency between no conflicting opam commands * Upgrade to the latest version of DOSE and CUDF (solver libraries) * Add repository priorities * Create the default directories (`bin/`, `lib/` ...) when installing a new compiler 0.7.6 [Oct 2012] * major internal API refactoring * repositories are now versionned, and we try to auto-update when possible * more expressive compiler constraints in opam files 0.7.5 [Oct 2012] * dependencies can now be expressed by any formula (instead of just CNF) * It's easier to compose the value of environment variable (ie. to write `%{lwt+ssl:enable}%`) * Fix regression on init for rsync repositories 0.7.4 [Oct 2012] * improve `opam pin`: the code is more robust and it is now possible to pin a package to a git repository * add support for patches per package * add `opam switch -import file` and `opam switch -export file` 0.7.3 [Sep 2012] * Better user-message when no solution is found * Improve the minimality of installed packages 0.7.2 [Sep 2012] * Fix regression in init introcuced in 0.7.0 * Fix regression in update introduced in 0.7.0 0.7.1 [Sep 2012] * Remove forgotten debug statement 0.7.0 [Sep 2012] * report upgrade statistic on update * do no ask y/n when installing compiler's base packages * improve opam-mk-repo * fix `opam search` to be caseless * ability to filter some commands (depending on some predicates) in opam file * improvments when packages disapear upstream * check for ocaml 3.12.1 on configure * tell the user to unset some potentially dangerous variables when running opam * fix few git backend issues 0.6.0 [Sep 2012] * semantics changes in `opam switch` * solver improvements in case of install and remove * better error reporting * fix caching of package archives * fix `~/.opam/repo/index` priorities 0.5.0 [Sep 2012] * add opam search * add opam reinstall * ability to upgrade only a subset of packages * lot of bug fixes in the rsync and curl backend * better `--help` messages * better information displayed to the user 0.4.0 [Aug 2012] * better layout of repository files * (partial) possibility to specify archive checksums * if the archive is not on ocamlpro.com, download it upstream * suffix +opam to the versions of archives available on ocamlpro.com * prompt the user to evaluate `opam config -env` more often * changes in meta-data aren't picked up by the CURL backen * more modulare repository system: the 'kind' of repository is no more linked to the kind of package archives 0.3.2 [Aug 2012] * fix regression for `opam switch` introduced in 0.3 * fix deletion of optional dependencies * support for pinned packages * fix compilation for ocaml 4.00 * fix compilation for *BSD 0.3.1 [Jul 2012] * fix regression for `opam install` introduced in 0.3 0.3.0 [Jul 2012] * improve parallel compilation of packages * better recovery on compilation/installation errors * first draft of version pinnig * fix`'opam config -env` for old shells * install the latest version of packages when possible * more robust `opam update` (ie. old files are gc-ed) * add a (more or less) generic way to install and use topfind 0.2.0 [Jul 2012] * more robust switch command * more robust parallel build (not yet activated by default) * support for compiler-constraints in packages * new solver heuristics * improved performance on init with the rsync backend 0.1.0 [Jun 2012] * Initial version opam-full-1.2.2/opam.install0000644000175000017500000000122412517374212014455 0ustar useruserbin: [ "src/opam" "src/opam-admin" "src/opam-installer" ] man: [ "?doc/man/opam.1" "?doc/man/opam-admin.1" "?doc/man/opam-admin-check.1" "?doc/man/opam-admin-depexts.1" "?doc/man/opam-admin-libs.1" "?doc/man/opam-admin-make.1" "?doc/man/opam-admin-stats.1" "?doc/man/opam-config.1" "?doc/man/opam-init.1" "?doc/man/opam-install.1" "?doc/man/opam-installer.1" "?doc/man/opam-list.1" "?doc/man/opam-pin.1" "?doc/man/opam-reinstall.1" "?doc/man/opam-remove.1" "?doc/man/opam-repository.1" "?doc/man/opam-search.1" "?doc/man/opam-show.1" "?doc/man/opam-switch.1" "?doc/man/opam-update.1" "?doc/man/opam-upgrade.1" ] opam-full-1.2.2/.travis-ci.sh0000755000175000017500000000506112517374212014452 0ustar useruser# Git should be configured properely to run the tests git config --global user.email "travis@example.com" git config --global user.name "Travis CI" install_on_linux () { # Install OCaml PPAs case "$OCAML_VERSION" in 3.12.1) ppa=avsm/ocaml312+opam12 ;; 4.00.1) ppa=avsm/ocaml40+opam12 ;; 4.01.0) ppa=avsm/ocaml41+opam12 ;; 4.02.1) ppa=avsm/ocaml42+opam12 ;; *) echo Unknown $OCAML_VERSION; exit 1 ;; esac echo "yes" | sudo add-apt-repository ppa:$ppa sudo apt-get update -qq sudo apt-get install -qq ocaml ocaml-native-compilers camlp4-extra time $EXTERNAL_SOLVER ${OPAM_TEST:+opam} } install_on_osx () { curl -OL "http://xquartz.macosforge.org/downloads/SL/XQuartz-2.7.6.dmg" sudo hdiutil attach XQuartz-2.7.6.dmg sudo installer -verbose -pkg /Volumes/XQuartz-2.7.6/XQuartz.pkg -target / case "$OCAML_VERSION" in 4.02.1) brew update; brew install ocaml;; 4.03.0) brew update; brew install ocaml --HEAD ;; *) echo Skipping $OCAML_VERSION on OSX; exit 0 ;; esac if [ -n "$EXTERNAL_SOLVER$OPAM_TEST" ]; then brew install $EXTERNAL_SOLVER ${OPAM_TEST:+opam} fi } case $TRAVIS_OS_NAME in osx) install_on_osx ;; linux) install_on_linux ;; esac OCAMLV=$(ocaml -vnum) echo === OCaml version $OCAMLV === if [ "$OCAMLV" != "$OCAML_VERSION" ]; then echo "OCaml version doesn't match: travis script needs fixing" exit 12 fi export OPAMYES=1 export OCAMLRUNPARAM=b if [ "$OPAM_TEST" = "1" ]; then # Compile OPAM using the system libraries (install them using OPAM) # ignore the warnings echo "Bootstrapping for opam with:" opam config report # We still have OPAM 1.1 on Homebrew OPAMV=$(opam --version) if [ "${OPAMV%.*}" = "1.1" ]; then opam init https://opam.ocaml.org/1.1 else opam init fi eval `opam config env` opam install ocamlfind lwt cohttp ssl cmdliner ocamlgraph dose cudf re jsonm ./configure make # overwrite the previous install of OPAM with the new binary # and libraries sudo make install make libinstall prefix=$(opam config var prefix) # Compile and run opam-rt wget https://github.com/ocaml/opam-rt/archive/master.tar.gz tar xvfz master.tar.gz cd opam-rt-master make OPAMEXTERNALSOLVER=$EXTERNAL_SOLVER make KINDS="local git" run else # Compile OPAM from sources and run the basic tests ./configure make lib-ext make make opam-check make tests > tests.log 2>&1 || (tail -1000 tests.log && exit 1) # Let's see basic tasks works sudo make install opam init opam install lwt opam list fi opam-full-1.2.2/README.md0000644000175000017500000001042112517374212013407 0ustar useruser# OPAM - A package manager for OCaml OPAM is a source-based package manager for OCaml. It supports multiple simultaneous compiler installations, flexible package constraints, and a Git-friendly development workflow. OPAM was created and is maintained by [OCamlPro](http://www.ocamlpro.com). To get started, checkout the [Install](http://opam.ocaml.org/doc/Install.html) and [Usage](http://opam.ocaml.org/doc/Usage.html) guides. ## Compiling this repo * Make sure you have OCaml and GNU make installed. If you don't have a recent enough version of OCaml (>= 3.12.1) at hand, see the next paragraph. * Run `./configure` * Run `make lib-ext` as advertised by `./configure` if you don't have the dependencies installed and only need the opam binary (not the libs). This will locally take care of all OCaml dependencies for you. * Otherwise, make sure to have ocamlfind, ocamlgraph, cmdliner, jsonm, cudf, dose 3.2.2+opam and re >= 1.2.0 installed. Or run `opam install opam-lib --deps-only` if you already have a working instance. Re-run `./configure` once done. * Run `make` * Run `make install` * Run `make libinstall` if needed (this is incompatible with `make lib-ext`, as the opam library would conflict with installed versions of the dependencies) ## Compiling without OCaml `make cold` is provided as a facility to compile OCaml, then bootstrap OPAM. You don't need need to run `./configure` in that case, but you may specify `CONFIGURE_ARGS` if needed, e.g.: ``` make cold CONFIGURE_ARGS="--prefix ~/local" ``` NOTE: You'll still need GNU make. ## Bug tracker Have a bug or a feature request ? Please open an issue on [our bug-tracker](https://github.com/ocaml/opam/issues). Please search for existing issues before posting, and include the output of `opam config report` and any details that may help track down the issue. ## Documentation #### User Manual The main documentation entry point to OPAM is the user manual, available using `opam --help`. To get help for a specific command, use `opam --help`. #### Guides and Tutorials A collection of guides and tutorials is available [online](http://opam.ocaml.org/doc/Usage.html). They are generated from the files in [doc/pages](https://github.com/ocaml/opam/tree/master/doc/pages). #### API, Code Documentation and Developer Manual A more thorough technical document describing OPAM and specifying the package description format is available in the [developer manual](http://opam.ocaml.org/doc/manual/dev-manual.html). `make doc` will otherwise make the API documentation available under `doc/`. ## Community Keep track of development and community news. * Have a question that's not a feature request or bug report? [Ask on the mailing list](http://lists.ocaml.org/listinfo/infrastructure). * Chat with fellow OPAMers on IRC. On the `irc.freenode.net` server, in the `#ocaml` or the `#opam` channel. ## Contributing We welcome contributions ! Please use Github's pull-request mechanism against the master branch of the [OPAM repository](https://github.com/ocaml/opam). If that's not an option for you, you can use `git format-patch` and email TODO. ## Versioning The release cycle respects [Semantic Versioning](http://semver.org/). ## Related repositories - [ocaml/opam-repository](https://github.com/ocaml/opam-repository) is the official repository for OPAM packages and compilers. A number of non-official repositories are also available on the interwebs, for instance on [Github](https://github.com/search?q=opam-repo&type=Repositories). - [opam2web](https://github.com/ocaml/opam2web) generates a collection of browsable HTML files for a given repository. It is used to generate http://opam.ocaml.org. - [opam-rt](https://github.com/ocaml/opam-rt) is the regression framework for OPAM. - [opam-publish](https://github.com/AltGr/opam-publish) is a tool to facilitate the creation, update and publication of OPAM packages. ## Copyright and license Copyright 2012-2014 OCamlPro Copyright 2012 INRIA All rights reserved. OPAM is distributed under the terms of the GNU Lesser General Public License version 3.0. OPAM 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. opam-full-1.2.2/.travis.yml0000644000175000017500000000114312517374212014242 0ustar useruserlanguage: c script: bash -ex .travis-ci.sh os: - linux - osx env: - OCAML_VERSION=4.02.1 OPAM_TEST=1 EXTERNAL_SOLVER= - OCAML_VERSION=4.02.1 OPAM_TEST=1 EXTERNAL_SOLVER=aspcud - OCAML_VERSION=4.02.1 OPAM_TEST= - OCAML_VERSION=4.01.0 OPAM_TEST= - OCAML_VERSION=4.00.1 OPAM_TEST= - OCAML_VERSION=3.12.1 OPAM_TEST= matrix: exclude: - os: osx env: OCAML_VERSION=4.01.0 OPAM_TEST= - os: osx env: OCAML_VERSION=4.00.1 OPAM_TEST= - os: osx env: OCAML_VERSION=3.12.1 OPAM_TEST= notifications: email: - opam-commits@lists.ocaml.org irc: - "chat.freenode.net#opam" opam-full-1.2.2/doc/0000755000175000017500000000000012532744757012713 5ustar useruseropam-full-1.2.2/doc/design/0000755000175000017500000000000012532744757014164 5ustar useruseropam-full-1.2.2/doc/design/depexts-plugins0000644000175000017500000001261612517374212017234 0ustar useruserProposal for a plugin architecture for supporting checking and resolving of external dependencies (depexts) in OPAM > 1.2 ======================================================================== Rationale --------- The opam package metadata now contains a specific field for declaring dependencies on external packages handled through external package managers (typically, distribution and OS dependent, but may in general be any other package manager). There are two main functionalities that are needed: - checking whether external dependencies are satisified at a given moment; this is an operation that can be implemented in linear time (we are just checking whether a boolean formula is true or false); since external packages are managed outside opam, this check needs to be performed at the beginning of each opam run, to discover packages that are no longer functional, and report the issue to the user. With proper, OS specific integration, this operation can be made blazingly fast; a simple hack, calling an external command each time, may be functionally equivalent, but quite slow. - finding a way of satisfying external dependencies required by a set of opam packages; this is potentially much more expensive, it involves not only a dependency solving phase, but also the fetch and installation phase, and requires proper interfacing with the existing OS specific package manager. This should be done only when modifying or fixing an opam configuration and after asking user confirmation. Making things work smoothly and efficiently requires OS specific knowledge that is best found among experienced users of each OS, which may be different people, with different knowledge of Opam internals: a well designed plugin infrastructure can separate concerns and facilitate contributions. Proposal -------- It is proposed to create a plugin architecture for OS specific external dependencies, extending the following module signature for the modules implementing a plugin module type OSDependencyLayer = sig type depexts (* external dependencies, a CNF involvin OS-specific stuff *) type actions (* an abstract token corresponding to actions, and a textual representation of them to present to the user *) type explanations (* in case the depexts cannot be satisfied, explain why *) type result = Can of actions | Cannot of explanations type outcome (* result of the execution of the OS-specific actions *) val satisfied : depexts -> bool (* are the depexts already satisfied ? *) val cansatisfydepexts : depexts -> result val perform : actions -> outcome end Notice that there are two distinct sets of functions for the very different cases outlined above: - satisfied performs just a check to see whether depexts are already satisfied - cansatisfydepexts tries to solve the external dependencies, and returns a proposed action, or an explanation for the failure, while perform executes the actions (typically after user confirmation) The proposed module interface is purposedly incomplete, as it makes no assumption on the way in which plugins are identified, and registered, which is an orthogonal issue. Note on OCaml detection ----------------------- The OCaml compiler itself is an external dependency when using "system" switches. It's currently handled by a specific, dynamically generated compiler definition, with some ad-hoc code to treat it specifically, or check that it didn't change at startup time. With the current trend to move compiler handling to packages, the above won't work anymore, because "system" would now need to be a specific, dynamic package. While re-implementing the system switch hacks in this context would certainly be possible, having the depexts mechanism flexible enough to handle all this consistently would certainly be more consistent and easier to maintain. Here is a possibility: having an 'ocaml-system' package (that would "provide" ocaml) with depext on the system ocaml. * the package needs to be able to export some environment variables that are currently exported by the switch (`CAML_LD_LIBRARY_PATH`). * a change of this package should be detected at OPAM startup -- like for any depexts * "system" compilers currently don't have to be managed by the OS, they are just looked for in the PATH. Keeping this would probably require a specific (lower level) "depext" plugin, that wouldn't have the functionalities to install the depext. * this raises a new, but valid, concern: the above handles a binary state for depexts, while for this, we'd need to detect changes also. Creating one 'ocaml-system' package version for each possible compiler version may be an answer: on system compiler change, the installed 'ocaml-system' becomes invalid, and you'll need to replace it by the fitting version (recompiling all dependent packages as you go). * However, it sounds quite difficult to hold a middle ground between - "resolve with all OPAM packages installable, then check and handle their depexts", and - "check depexts, and then resolve with OPAM packages that can be installed with what's currently on the system;" (don't install them, except on conflict (how exactly?)) and the above won't play well with first option here, second option raising many more questions. Maybe this doesn't fit well with depexts, but it's worth considering opam-full-1.2.2/doc/design/depopts-and-features0000644000175000017500000001765512517374212020143 0ustar useruserOpam metadata evolution proposal for 1.2.x ========================================== This document contains the current summary proposal for evolving Opam's metadata, together with the rationale underpinning the proposed choices. In a nutshell ------------- The new metadata will restrict the allowed values of the depopts: field and add a new field features: as follows - the depopts: field will be restricted to a simple list of packages, with no version constraints, no boolean connectors - a new field features: will be introduced to express the different possible configurations of the source packages according to the availability of arbitrarily complex combinations of other packages (also known as "variability points" in the software product lines research community) It is important to roll-out these changes to get them accepted by package maintainers as soon as possible. Current status -------------- Complex formulas for "depopts" are not allowed anymore for 1.2 packages (for packages declared with an older `opam-version`, they are still accepted with the older, awkward semantics). The `features` field is not present yet as of 1.2.1. Rationale --------- The old implementation of depopts: tried to address three different needs 1) list the packages which are not mandatory for installation, but that trigger a recompilation in case their status is modified (added, removed, downgraded, upgraded). This is needed to determine if a recompilation (and reconfiguration) is necessary 2) capture multiple package/versions patterns that lead, in the configuration phase, to enable or disable various different features 3) express incompatibilities with certain versions of these packages This has led to several difficulties in practice; optional configuration features could not be easily and faithfully translated into package dependencies, which led to an incomplete ad-hoc implementation; potential ambiguities emerged in the metadata, like in the line depopts: async >= 109.15.00 | lwt >= 2.4.3 | (lwt >= 2.4.3 & ssl) where lwt >= 2.4.3 | (lwt >= 2.4.3 & ssl) looks like a typo, as A \/ (A /\ B) is logically equivalent to A, while the intention of the maintainer was to identify two possible configurations, one with lwt only, and one with both lwt and ssl. As a consequence, it has been decided to fully separate the three issues, capturing them in different fields, with a clear semantics. Core Proposal ------------- Notice that items below are numbered according to the needs they addressed, but presented in order of increased implementation complexity 1) the depopts: field now contains only a list of package names (no version constraints, no boolean combinations, just a list); Semantics: In case the status of any package appearing in this field is modified (added, removed, downgraded, upgraded), a recompilation of the package is scheduled. The depopts: field is not used at all by the package dependencies resolution phase, and must not be transalted into CUDF. After the solver returns a solution, packages in this list that are present in the system are added with all their dependencies to the dependency cone, which is then visited to determine a compatible compilation order. 3) incompatibilities implicitly expressed in the depopts: lines by using version constraints must now be made explicit in the form of conflicts added to the list contained in the conflicts: field There is no change in the semantics of conflicts: and rewriting the few old versioned depopts can be performed manually or automatically. For example, depopts: async >= 109.15.00 | lwt >= 2.4.3 | (lwt >= 2.4.3 & ssl) conflicts: tyxml will become depopts: async, lwt, ssl conflicts: tyxml, async < 109.15.00, lwt < 2.4.3 2) a new field features: is added, that contains a list of "feature specifications", each feature specification being composed by: - a state-variable (or configuration variable) - a string describing the feature - an arbitrary boolean formula built out of atoms that are package names, possibly with version constraints features: [ ssl-support "Support for SSL" { lwt >= 2.4.3 & ssl } ; multi-backend "Enable both Async and Lwt" {lwt >= 2.4.3 & async > 109.15.00 } ; minimal "Only minimalistich HTTP support" {lwt & -async & -ssl} ] Semantics: a feature, and the corresponding state variable, is enabled iff the associated boolean formula is satisfied by the current package state; this is easy to compute, as it is a simple boolean evaluation of the formula in the assignment given by the package state. Features are invisible to the solver, and intended to be used in the configuration and build phase. Benefits: it is now easy to read the intended meaning of the maintainer in the metadata, and it is possible to output meaningful information to the user during the package installation/recompilation phase Impact: ------- These above changes require several modifications to the current code base: 1) requires implementing a simple new parser and checking the logic for computing recompilation; 2) requires implementing another parser, a simple propositional logic evaluator, some user output, and an interconnection with the state-variables 3) is a noop in the code, but requires some manual rewriting of the metadata in the archive (this might be automated, but might not be worth the effort) Hence we propose to limit the changes in the next release to what is described up to here. =======END OF PROPOSED CHANGES FOR 1.2.x ==================================================== In the longer term, one may consider the following Proposal extensions: -------------------- Having isolated features clearly, we can imagine to use them for extra functionality, for example: user hints besides telling the user that a feature is enabled or not, one could add logic to compute a suggestion for enabling a feature, if requested. This will necessarily be based on some heuristics, as there might be exponentially many ways to satisfy an arbitrary boolean condition. reduced recompilation needs now that state-variables are clearly identified in the features, it is easy to check that when there is no change in the values of these state-variables, and in the versions of the packages involved in the *enabled* feature set, then no recompilation is needed: the configuration logic will only use the state-variables, which did not change, and only change to packages actually used for an enabled state-variables may be involved in a recompilation An extra suggested extension is the possibility of mixing in the formulae in the features: field state-variables and packages, like in the following example features: [ ssl-support "Support for SSL" { os != "windows" & ssl >= 1.1 & (lwt < 4 | async) } ] This requires a significant amount of extra effort to: - distinguish syntactically a package named os from a state variable named os - implement comparison with possibly non-boolean values of a state variable (the os != "windows" above) - detect and reject cyclic dependencies among state variables, like in ssl-support "Support for SSL" { ssl-support & ssl >= 1.1 & (lwt < 4 | async) } or in ssl-support "Support for SSL" { - foo & ssl >= 1.1 & (lwt < 4 | async) } foo "Just for the example" { - ssl-support } Complexity versus usefulness need to be carefully assessed beforehand. opam-full-1.2.2/doc/design/provides.md0000644000175000017500000001145012517374212016326 0ustar useruser# Provides field proposal This is a proposal to add a `provides:` field to the OPAM package description format. The feature is already supported by the Cudf format, which should ease the most difficult parts of the implementation. The purpose of this field is to make depending on a choice of packages providing the same feature easier. The `opam` file format is changed as such: ``` := ... ?provides: [ + ] ``` If package `a` is providing `b {constraint}`, this is to be understood as > installation of `a` implies that any version of `b` satisfying `constraint` > should be considered installed for all purposes regarding dependency > resolution. In particular: - any package depending on `b` with a constraint that has a non-empty intersection with `constraint` can be installed ; - any package with such an optional dependency would need to be compiled after `a`, and rebuilt on changes to `a` ; - conversely, any package conflicting with `b` with a constraint compatible with `constraint` can't be installed together with `a`. It may be simpler to start by implementing `provides` only for definite versions. ## Added functionality The feature provided can already be encoded without an extra field: given a list of packages that `provide` a given name, a package by this name can be added with a dependency towards either of those. However, on a repository maintainance point of view, having to list all the alternatives adds much more burden. Besides, it's not possible, using pinning or an additional repository, to provide a replacement for a base-repo package without redefining it explicitly: that's sometimes very useful to extend the OCaml versions where some package is available, for example. ## Virtual and replacement packages `provides` entries share the namespace of usual packages, and may therefore create _virtual_ packages, i.e. packages that only exist as provided by other packages. In the other case around, packages may both have a concrete definition and appear as `provides`, in which case we would speak of _replacement_ packages. In both cases, great care should be taken in the user interface. For example: - what to do when the user requires the installation of a virtual package ? (In `apt-get`, this is an error.) - should we print an advertisement when installing a package that has possible replacements ? - when querying info on a package, possible alternatives should be shown. - should virtual packages be listed in the normal package listing ? - other commands referring to a given package (e.g. `pin`) may become ambiguous, so they should probably just ignore `provides`, and display a warning for virtual packages. The case of replacement packages is a bit more tricky, because it may easily get confusing if the dependencies aren't explicitly traced. The format of the package index will have to be extended to allow for virtual packages, which may not have a definite version. ## Use-cases * camlp4 should be made a virtual package, provided by different implementations for different compiler versions. The current handling using package versions causes expectations on the upgrade of those, spurious warnings of not up-to-date packages, and obfuscates real upgrades. * Allow aliases or renaming of packages (see #1879). * Allow to fork existing package and provide a replacement in the repository (for example cryptokit-sha512, see #314). * Built-in stuff in the compiler would be made simpler with `provides` lines instead of the concrete (but empty) `base-` packages. With compilers in packages, that would fit well in the compiler package's description. * Adds flexibility in changing the granularity of packages: packagers could more easily go back and forth between splitting in small units or packaging a bundle. ## Constraint intersection While OPAM usually solves version constraints based on the set of actual versions, this needs to be symbolic, i.e. non-empty intersection of the sets of _possible_ versions. For example, the intersection of `a {>= 3}` and `a {<= 3}` is non-empty even if there was no known `a.3` version before. This will need some care in the opam to Cudf version conversion, which is currently based on existing versions. ## Interactions with the `features` field While `provides` occupies the namespace of packages, and is used in dependency resolution, `features` occupies that of variables, and is intended for use only at build time (we should forbid its use in the `available` field, which is resolved before dependencies). However, both indicate things that are made available by the package, so there is a high risk of user confusion. I think both are important features that we want, and there is no way to merge them, but this is to be taken into account in the interface design and documentation ; `features` might be renamed (`traits` ?). opam-full-1.2.2/doc/release/0000755000175000017500000000000012532744757014333 5ustar useruseropam-full-1.2.2/doc/release/readme.md0000644000175000017500000000215312517374212016077 0ustar useruser## Steps to follow for each release * Update version (and copyright year) in `configure.ac`, `shell/opam_installer.sh` * Run `make configure` to regenerate `./configure` * Run `make tests`, `opam-rt` (with and without aspcud) -- now checked by travis * Run `make doc` to re-generate the API documetation -- * update the CHANGELOG * tag the release (git tag -a 1.2.1; git push origin 1.2.1) * create a release on github based on your tag (https://github.com/ocaml/opam/releases/new) -- * Generate an inclusive source tarball (and the binary for your current arch while you're at it): ``` ./shell/release.sh full-archive binary publish -n git-name:git-token ``` * Check that it's been properly uploaded on https://github.com/ocaml/opam/releases * Ask people on other archs (and with write access to opam) to run ``` wget https://raw.github.com/ocaml/opam/master/shell/release.sh && \ bash -ue ./release.sh -t $VERSION ``` -- * Add some news about the release on the platform blog * Update the installation instructions in doc/pages * Update the opam-lib, opamfu, opam2web opam packages * Announce ! (platform-list, caml-list) opam-full-1.2.2/doc/Makefile0000644000175000017500000000235712517374212014346 0ustar useruserifndef OPAM OPAM = ../src/opam endif BINDIR = $(dir $(OPAM)) SRCDIR = $(wildcard ../src/*) TOPICS = $(shell $(OPAM) help topics) ifndef OPAM_ADMIN OPAM_ADMIN = $(BINDIR)/opam-admin endif TOPICS_ADMIN = check depexts findlib make rename stats HELPFMT = --help=groff ifndef OPAM_INSTALLER OPAM_INSTALLER = $(BINDIR)/opam-installer endif SRCEXTDIR = ../src_ext/lib INCLUDE = $(patsubst %,-I %,$(SRCDIR) $(SRCEXTDIR)) .PHONY: man html dev-manual pages all: man dev html pages man: rm -rf man mkdir -p man $(OPAM) $(HELPFMT) > man/opam.1 for i in $(TOPICS); do\ $(OPAM) $$i $(HELPFMT) > man/opam-$$i.1;\ done $(OPAM_ADMIN) $(HELPFMT) > man/opam-admin.1 for i in $(TOPICS_ADMIN); do\ $(OPAM_ADMIN) $$i $(HELPFMT) > man/opam-admin-$$i.1;\ done $(OPAM_INSTALLER) $(HELPFMT) > man/opam-installer.1 man-html: man rm -rf $@ mkdir -p $@ for f in $(wildcard man/*); do\ man2html -r $$f > man-html/$$(basename $$f .1).html;\ done dev: $(MAKE) -C dev-manual html: rm -rf html mkdir -p html/ ocamldoc $(INCLUDE) ../src/*/*.mli ../src/*/*.ml -html -d html/ || true pages/%.html: pages/%.md omd $^ -o $@ PAGES=$(wildcard pages/*.md) pages: $(PAGES:.md=.html) clean: rm -rf man html man-html pages/*.html $(MAKE) -C dev-manual clean opam-full-1.2.2/doc/modules0000644000175000017500000001513212517374212014274 0ustar userusersrc ├── client Everything related to the OPAM state, installation and front-end │   │   [ opam-client lib ] │   │   # State and actions │   ├── opamSolution.ml Interface with the solver, processing of full solutions through actions │   ├── opamAction.ml Handles concrete actions on packages, like installations and removals │   ├── opamState.ml Functions handling a global state corresponding to the on-disk ~/.opam, plus (too) many auxiliary and manipulation functions │   │   # User command handling │   ├── opamClient.ml High-level execution of user-facing functions like "upgrade", and wrappers around the *Command modules │   ├── opamConfigCommand.ml Functions for the "opam config" subcommand │   ├── opamPinCommand.ml Functions for the "opam pin" subcommand │   ├── opamRepositoryCommand.ml Functions for the "opam repository" subcommand │   ├── opamSwitchCommand.ml Functions for the "opam switch" subcommand │   │   [ opam exe ] │   ├── opamGitVersion.mli (generated) Current git version of OPAM │   ├── opamArg.ml Command-line argument parser (opam exec only) │   └── opamMain.ml Main │ ├── core Library of functions needed by OPAM, system and file support, OPAM file-format, global variables │   │   [ opam-core lib ] │   ├── opamVersion.ml (generated) Current OPAM version │   ├── opamScript.mli (generated) Shell config scripts as OCaml strings │   ├── opamMisc.ml Generic stdlib functions (string_split, Option submodule...) │   ├── opamTypes.mli Definitions of many types used throughout │   ├── opamTypesBase.ml Helper functions on the base types. Often opened │   ├── opamCompat.ml.4.01/4.02 Compatibility layer (Bytes, etc.) for different OCaml versions │   ├── opamGlobals.ml Global configuration references of general use ("debug","root"...) │   │   # basic types, used as keys │   ├── opamCompiler.ml The compiler type (string, version pairs) │   ├── opamPackage.ml The package type, and package name type (name+version, values often called "nv" in the code) │   ├── opamRepositoryName.ml The repository type │   ├── opamSwitch.ml The switch type │   ├── opamVariable.ml OPAM variables with scope (global or module) │   │   # system handling │   ├── opamProcess.ml Process and job handling, with logs, termination status, etc. │   ├── opamSystem.ml Bindings of lots of filesystem and system operations │   ├── opamFilename.ml Higher level file and directory name manipulation AND file operations, wrappers on OpamSystem using the filename type │   ├── opamParallel.ml Parallel execution of jobs following a directed graph │   ├── opamActionGraph.ml Handles graphs of actions (package changes), based on ocamlgraph │   │   # more advanced types │   ├── opamFilter.ml Formulas on variables, as used in opam files build scripts │   ├── opamFormula.ml Formulas on packages, opt. with sub-formulas on versions, and conversion functions │   ├── opamRepository.ml Repositories, and operations (update, download...) on top of the opam-repository lib │   │   # file format │   ├── opamJson.ml Wrapper on Jsonm; only needed for some (as of now) unused debug options │   ├── opamLineLexer.mll A simple lexer to list of lines, which are lists of words │   ├── opamLexer.mll OPAM config file lexer │   ├── opamParser.mly OPAM config file generic type parser │   ├── opamFormat.ml OPAM config files syntax and conversion tools, printing │   ├── opamFile.ml Handles all OPAM file formats as record types and submodules, conversion to and from syntax │   └── opamPath.ml Defines all paths under ~/.opam using a hierarchy of modules │ ├── repositories Handling of remote sources │   │   [ opam-repositories lib ] │   ├── opamHTTP.ml Main HTTP backend │   ├── opamLocal.ml Rsync backend, for local or ssh sources │   ├── opamVCS.ml Layer for handling version control sources │   ├── opamDarcs.ml Darcs support (through OpamVCS) │   ├── opamGit.ml Git support (through OpamVCS) │   └── opamHg.ml Mercurial support (through OpamVCS) │ ├── solver Solver and Cudf interaction │   │   [ opam-solver lib ] │   ├── opamCudf.ml Solver interaction, conversion of answer to solution │   ├── opamHeuristic.ml The "internal solver", brute-force search using Dose's checker │   └── opamSolver.ml Entry point, conversion of universe to cudf, dependencies computation │ └── tools │   [ opam-admin tool ] ├── opam_mk_repo.ml Repo index and archives generation ├── opam_depexts_change.ml Operation on external dependencies in a repo ├── opam_findlib.ml Automatically add some findlib information to a repo ├── opam_rename.ml Package renaming ├── opam_stats.ml Repo stats & graphs generation ├── opam_repo_check.ml Check the repo for errors ├── opam_admin.ml Source of the opam-admin tool, main │   [ other stand-alone tools ] ├── opam_admin_top.ml Tiny library for admin-scripts, included in opam-admin.top ├── opam_check.ml Tiny tool used in internal checks ├── opam_installer.ml Handles OPAM's ".install" files └── opamlfind.ml Experimental ocamlfind wrapper tool opam-full-1.2.2/doc/dev-manual/0000755000175000017500000000000012532744757014744 5ustar useruseropam-full-1.2.2/doc/dev-manual/dev-manual.tex0000644000175000017500000015713212517374212017514 0ustar useruser\documentclass[a4paper,10pt]{article} \usepackage{url} \usepackage{eurosym} %\usepackage[french]{babel} \usepackage[T1]{fontenc} \usepackage{pdfswitch} \usepackage{verbatim} \usepackage{fullpage} \usepackage{fancyvrb} \newenvironment{remark}[1][Remark]{\begin{trivlist} \item[\hskip \labelsep {\bfseries #1}]}{\end{trivlist}} \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{fontsize=\small,frame=single} \title{ OPAM: A Package Management System for OCaml\\ Developer Manual (version 1.2.1)\\ ~\ \\ ~\ \\} \author{Thomas GAZAGNAIRE\\ \url{thomas@gazagnaire.org}\\ Louis GESBERT\\ \url{louis.gesbert@ocamlpro.com}\\ } \begin{document} \newcommand{\OPAM}{{\sc Opam}} \maketitle \vfill \tableofcontents \section*{Overview} \OPAM\ is a source-based package manager for OCaml. It supports multiple simultaneous compiler installations, flexible package constraints, and a Git-friendly development work-flow.\\ A package management system has typically two kinds of users: {\em end-users} who install and use packages for their own projects; and {\em packagers}, who create and upload packages. End-users want to install on their machine a consistent collection of {\em packages} -- a package being a collection of OCaml libraries and/or programs. Packagers want to take a collection of their own libraries and programs and make them available to other developpers.\\ This document describes the design of \OPAM\ to answer both of these needs. \subsection*{Conventions} In this document, \verb+$home+, \verb+$opam+, and \verb+$path+ are assumed to be defined as follows: \begin{itemize} \item {\tt \$home} refers to the end-user home path, typically {\tt /home/thomas/} on linux and {\tt /Users/thomas/} on OSX. % {\tt % C:\textbackslash Documents and Settings\textbackslash % thomas\textbackslash} on Windows. \item {\tt \$opam} refers to the filesystem subtree containing the client state. Default directory is {\tt \$home/.opam}. \item {\tt \$path} refers to a list of paths in the packager filesystem, where lives the collection of programs ({\tt ocamlc}, {\tt ocamldep}, {\tt ocamlopt}, {\tt ocamlbuild}, ...). \end{itemize} User variables are written in capital letters, prefixed by \verb+$+. For instance package names will be written \verb+$NAME+, package versions \verb+$VERSION+, and the version of the ocaml compiler currently installed \verb+$SWITCH+.\\ This document is organized as follows: Section~\ref{section:packages} describes the core of \OPAM, e.g. the management of packages. Section~\ref{section:repositories} describes how repositories are handled, Section~\ref{section:switches} focus on compiler switches and finally Section~\ref{section:config} explain how packages can define configuration variables (which can be later used by the build system). \section{Managing Packages} \label{section:packages} \subsection{State} The client state is stored on the filesystem, under {\tt \$opam}. All the configurations files, libraries and binaries related to a specific instance of the OCaml compiler in \verb+$opam/$SWITCH+, where \verb+$SWITCH+ is the name of that specific compiler instance. See Section~\ref{section:switches} for more details about compiler switches. \begin{itemize} \item {\tt \$opam/config} is the main configuration file. It defines the version of \OPAM, the repository addresses and the current compiler version. The file format is described in \S\ref{file:config}. \item \verb+$opam/packages/$NAME/$NAME.$VERSION/opam+ is the specification for the package \verb+$NAME+ with version \verb+$VERSION+ (which might not be installed). The format of {\tt opam} files is described in \S\ref{file:opam}. \item \verb+$opam/packages/$NAME/$NAME.$VERSION/descr+ contains the description for the version \verb+$VERSION+ of package \verb+$NAME+ (which might not be installed). The first line of this file is the package synopsis. \item \verb+$opam/packages/$NAME/$NAME.$VERSION/url+ contains the upstream location for version \verb+$VERSION+ of package \verb+$NAME+ (which might not be installed). The format of {\tt url} files is described in \S\ref{file:url}. \item \verb+$opam/packages/$NAME/$NAME.$VERSION/files/+ contains the optional overlay files on top of the upstream sources, for version \verb+$VERSION+ of package \verb+$NAME+ (which might not be installed). This files are copied in the build directory before building and installing a package. \item \verb+$opam/archives/$NAME.$VERSION+opam.tar.gz+ contains the source archives for the version \verb+$VERSION+ of package \verb+$NAME+. This archive might be a bit different from the upstream library as it might have been repackaged by \OPAM\ to include the evenutal overlay files. \item \verb+$opam/packages.dev.+ contains cached information for development packages. \OPAM\ uses it on update to check which package needs to be upgraded. \end{itemize} \subsection{Files} \subsubsection{General Syntax of Structured Files} \label{file:general} Most of the files in the client and server states share the same syntax defined in this section. \begin{description} \item[Comments] Two kinds of comments are available: the usual \verb+(* ... *)+ OCaml comment blocks and also \verb+#+ which discard everything until the end of the current line. \item[Base types] The base types for values are: \begin{itemize} \item {\tt BOOL} is either {\tt true} or {\tt false} \item {\tt STRING} is a doubly-quoted OCaml string, for instance: {\tt "foo"}, {\tt "foo-bar"}, $\ldots$ \item {\tt SYMBOL} contains only non-letter and non-digit characters, for instance: {\tt =}, {\tt <=}, $\ldots$ Some symbols have a special meaning and thus are not valid {\tt SYMBOL}s: ``\verb+(+ \verb+)+ \verb+[+ \verb+]+ \verb+{+ \verb+}+ \verb+:+''. \item {\tt IDENT} starts with a letter and is followed by any number of letters, digit and symbols, for instance: {\tt foo}, {\tt foo-bar}, $\ldots$. \end{itemize} \item[Compound types] Types can be composed together to build more complex values: \begin{itemize} \item {\tt X Y } is a space-separated pair of value. \item {\tt X | Y } is a value of type either {\tt X} or {\tt Y}. \item {\tt ?X} is zero or one occurrence of a value of type {\tt X}. \item {\tt X+} is a space-separated list of values of at least one value of type {\tt X}. \item {\tt X*} is a space-separated list of values of values of type {\tt X} (it might contain no value). \end{itemize} \end{description} All structured files share the same syntax: \begin{Verbatim} := * := IDENT : | ?IDENT: | IDENT STRING { + } := BOOL | INT | STRING | SYMBOL | IDENT | [ + ] | value { + } \end{Verbatim} \subsubsection{Global Configuration File: {\tt config}} \label{file:config} \verb+$opam/config+ follows the syntax defined in \S\ref{file:general} with the following restrictions: \begin{Verbatim} := opam-version: "1.2" repositories: [ STRING+ ] switch: STRING ?jobs: INT ?solver: ?solver-criteria: STRING ?solver-upgrade-criteria: STRING ?solver-fixup-criteria: STRING ?download-command: ?download-jobs: INT := [ ( ?{ })+ ] \end{Verbatim} \begin{itemize} \item {\tt opam-version} indicates the current \OPAM\ repository format -- normally corresponding to the \OPAM\ minor version (\verb+MAJOR.MINOR+) \item {\tt repositories} contains the names of the currently configured repositories. \item {\tt switch} is the name of the currently active \OPAM\ switch. \item {\tt jobs} is the maximum number of build processes that can be run simultaneously. \item {\tt solver} is the external solver to call. The value may be either the single identifiers \verb+aspcud+ or \verb+packup+, which have built-in support, or a command. The string variables \verb+input+, \verb+output+ and \verb+criteria+ (only) are defined when evaluating this field. \item {\tt solver-criteria}, {\tt solver-upgrade-criteria} and {\tt solver-fixup-criteria} are the optimisation criteria provided to the solver resp. in the default case (install requested packages at their latest version, minimising the impact on other packages), for global upgrades (minimise outdated packages) and for fixup (resolve dependencies while minimising changes). \item {\tt download-command} will be called to fetch remote files over http(s) or ftp. The value may be either the single identifiers \verb+curl+ or \verb+wget+, which have built-in support, or a custom command. Only the special variables \verb+url+, \verb+out+, \verb+retries+ (strings) and \verb+compress+ (bool) can be used in this field. \item {\tt download-jobs} is the maximum number of simultaneous downloads (all remote hosts included) \end{itemize} \subsubsection{Package Specification files: {\tt opam}} \label{file:opam} \verb+$opam/packages/$NAME/$NAME.$VERSION/opam+ follows the syntax defined in \S\ref{file:general} with the following restrictions: \begin{Verbatim} := opam-version: "1.2" ?name: STRING ?version: STRING maintainer: STRING ?authors: [ STRING+ ] ?license: STRING ?homepage: STRING ?doc: STRING ?bug-reports: STRING ?dev-repo: STRING ?tags: [ STRING+ ] ?patches: [ (STRING ?{ } )+ ] ?subst: [ STRING+ ] ?build: commands ?install: commands ?build-doc: commands ?build-test: commands ?remove: commands ?depends: [ ] ?depopts: [ (STRING ?{ })+ ] ?conflicts: [ + ] ?depexts: [ [[STRING+] [STRING+]]+ ] ?messages: [ (STRING ?{ } )+ ] ?post-messages: [ (STRING ?{ } )+ ] ?available: [ ] ?os: [ + ] ?ocaml-version: [ + ] ?libraries: [ STRING+ ] ?syntax: [ STRING+ ] ?flags: [ IDENT+ ] ?features: [ (IDENT STRING )+ ] := STRING | IDENT := [ ( ?{ })+ ] ?{ } := | [ + ] := | ! | | formula() := '&' | '|' | ( ) | ! | := STRING | STRING { } := IDENT | IDENT '&' := STRING | STRING { } | STRING { ?( '&') } := STRING := '=' | '<' | '>' | '>=' | '<=' | '!=' := | := | := STRING | '!' STRING \end{Verbatim} \begin{itemize} \item {\tt opam-version} specifies the file format version, it should be the current \OPAM\ version in the format {\tt MAJOR.MINOR} (\emph{i.e.} with patch version omitted) \item {\tt name}, {\tt version} contain resp. \verb+$NAME+ and \verb+$VERSION+, specifying the package. Both fields are optional when they can be inferred from the directory name (\emph{e.g.} when the file sits in the repository). \item {\tt maintainer} is a mandatory contact address for the package maintainer (the format {\tt "name "} is allowed). \item {\tt authors} is a list of strings listing the original authors of the software. \item {\tt license} is the abbreviated name of the license under which the source software is available. \item {\tt homepage}, {\tt doc}, {\tt bug-reports} are URLs pointing to the related pages for the package. \item {\tt dev-repo} is the URL of the package's source repository, which may be useful for developpers: not to be mistaken with the URL file, which points to the specific packaged version. It is typically a version-control address, and follows the format allowed for {\tt TARGET} by {\tt opam pin add}. You can use an address of the form {\tt vcs+scheme://xxx} to specify the version control system to use, {\em e.g.} {\tt git+ssh://address} or {\tt hg+https://address}. (Note: this has been added in OPAM 1.2.1) \item {\tt tags} contains an optional list of semantic tags used to classify the packages. The {\tt "org:foo"} tag is reserved for packages officially distributed by organization ``foo''. \item {\tt patches} is a list of files relative to the project source root (often added through the {\tt files/} metadata subdirectory). The listed patch files will be applied sequentially to the source like with the {\tt patch} command, after having gone through {\em variable interpolation expansion} like files listed in {\tt subst}. Patches may be applied conditionally by adding {\em filters}. \item {\tt subst} contains a list of files relative to the project source root. Variable interpolations will be expanded on these files before the build takes place (see \S\ref{file:subst} for the file format and \S\ref{section:config} for the semantic of file substitution). \item {\tt build} is the list of commands that will be run in order to compile the package. Any command is allowed, but these should write exclusively to the package's source directory (given as {\tt CWD} to the command), be non-interactive and perform no network i/o. All libraries, syntax extensions, binaries, platform-specific configuration and install files (\verb+$NAME.config+ and \verb+$NAME.install+, see \S\ref{file:config} and \S\ref{file:install}) should be produced within the source directory subtree during this step. Each command is provided as a list of terms (a command and zero or more arguments) ; individual terms as well as full commands can be made conditional by adding {\em filters}: they will be ignored if the {\em filter} evaluates to {\tt false} or is undefined. Additionally, strings in each term undergo variable expansion: {\tt "\%\{foo\}\%"} is replaced by the contents of variable {\tt foo}. Variable {\tt foo}, if undefined globally, implicitly refers to the package being defined, in the version being defined (while {\tt \$NAME:foo} refers to the {\em installed} version of the package). See \S\ref{subsection:variables} and the output of the command {\tt opam config list} for a list of predefined variables. Filters typically refer to the {\tt os} variable, like in the following example: \begin{Verbatim} build: [ ["mv" "Makefile.unix" "Makefile"] {os != "win32"} ["mv" "Makefile.win32" "Makefile"] {os = "win32"} [make] ] \end{Verbatim} \item {\tt install} follows the exact same format as {\tt build}, but should only be used to move products of {\tt build} from the build directory to their final destination under the current {\tt prefix}, and adjust some configuration files there when needed. Commands in {\tt install} are executed sequentially after the build is finished. These commands should only write to subdirectories of {\tt prefix}, without altering the source directory itself. This field contains typically just {\tt [make "install"]}. It is recommended to prefer the usage of a \verb+$NAME.install+ file and omit the {\tt install} field. \item {\tt build-doc} and {\tt build-test} follow the same specification as the {\tt build} field. They are processed after the build phase when documentation or tests have been requested. \item {\tt remove} follows the same format as {\tt build}, and is used to uninstall the package. It should be the reverse operation of {\tt install}, and absent when {\tt install} is. \item {\tt depends} describes the requirements on other packages for this package to be built and installed. It contains a list of formulas over package names, optionally parametrized by version constraints, e.g.: \begin{itemize} \item A simple package name: {\tt "foo"}; \item A package name with version constraints: \verb+"foo" {>= "1.2" & <= "3.4"}+ \end{itemize} Elements of the list are implicitely ANDed: \verb+["foo" "bar"]+ is equivalent to \verb+["foo" & "bar"]+, and \verb+"foo" {<= "1.2"} ("bar" | "gna" {= "3.14"})+ is to be understood as ``{\em {\tt "foo"} is required, at a version lesser or equal to $1.2$, as well as one of "{\tt bar}" or "{\tt gna}" version $3.14$}'' Additionally, the version constraints may be prefixed by {\em dependency flags}. These are one of \verb+build+, \verb+test+ and \verb+doc+ and limit the meaning of the dependency: \begin{itemize} \item \verb+build+ dependencies are no longer needed at run-time: they won't trigger recompilations of your package. \item \verb+test+ dependencies are only needed when building tests (by instructions in the \verb+build-test+ field) \item likewise, \verb+doc+ dependecies are only required when building the package documentation \end{itemize} For example: \begin{verbatim} depends: [ "foo" {build} "bar" {build & doc} "baz" {build & >= "3.14"} ] \end{verbatim} \item {\tt depopts}, for ``optional dependencies'', is similar to {\tt depends} in format, with some restrictions. It contains packages that are {\em used}, if present, by the package being defined, either during build or runtime, but that are not {\em required} for its installation. The implementation uses this information to define build order and trigger recompilations, but won't automatically install {\em depopts} when installing your package. The optional dependencies may have {\em dependency flags}, but they may not specify version constraints nor formulas. {\tt depopts} can be combined with {\tt conflicts} to add version constraints on the optional dependencies. Note that this changed in \OPAM\ 1.2: previously these constraints could be put in {\tt depopts}. You should now write \verb+depopts: "foo"+, \verb+conflicts: "foo" {< "2"}+ rather than \verb+depopts: "foo" {>= "2"}+ which had a non-obvious meaning. \item {\tt conflicts} is a list of package names with optional version constraints indicating that the current package can't coexist with some packages or some specific versions. \item {\tt depexts}, for ``external dependencies'', is a list that can be used for describing the dependencies of the package towards software or packages external to the OPAM ecosystem, for various system. It contains pairs of lists of the form \verb+[ predicates ext-packages ]+. {\tt predicates} is used to select the element of the list based on the current system: it is a list of tags (strings) that can correspond to the OS, architecture or distribution. The {\tt predicates} is used as a conjunction: the pair will only be selected when {\em all} tags are active. The resulting {\tt ext-packages} should be identifiers of packages recognised by the system's package manager. There is currently no definite specification for the precise tags you should use, but the closest thing is the {\em opam-depext} project (\url{https://github.com/OCamlPro/opam-depext}). The {\tt depexts} information can be retrieved through the {\tt opam list --external} command. \item {\tt messages} (since version $1.0.1$) is used to display an additional (one-line) message when prompting a solution implying the given package. The typical use-case is to tell the user that some functionality will not be available as some optional dependencies are not installed. \item {\tt post-messages} (since version $1.1.0$) allows to print specific messages to the user after the end of installation. The special boolean variable \verb+failure+ is defined in the scope of the filter, and can be used to print messages in case there was an error (typically, a hint on how it can be resolved, or a link to an open issue). \verb+success+ is also defined as syntactic sugar for \verb+!failure+. \item {\tt available} field (since version $1.1.0$) can be used to add constraints on the OS and OCaml versions currently in use, using the built-in \verb+os+ and \verb+ocaml-version+ variables. In case the filter is not valid, the package is disabled. The {\tt os} and {\tt ocaml-version} fields are deprecated, please use {\tt available} instead in newly created packages. \item {\tt libraries} and {\tt syntax} contain the libraries and syntax extensions defined by the package. See Section~\ref{section:config} for more details. \item {\tt flags} allow a limited set of idents that give special handling instructions for the package: \begin{description} \item{\tt light-uninstall} the package's uninstall instructions don't require the package source. This is currently inferred when the only uninstall instructions have the form `ocamlfind remove...`, but making it explicit is preferred (since \OPAM\ 1.2.0). \item{\tt verbose} when this is present, the stdout of the package's build and install instructions will be printed to the user (since \OPAM\ 1.2.1). \item{\tt plugin} the package installs a program named \verb+opam-$NAME+. OPAM will hand over to it when run with subcommand \verb+$NAME+, automatically installing it if necessary (since \OPAM\ 1.2.2). \end{description} Since some of those wheren't known in \OPAM\ 1.2.0, which will complain about them, they shouldn't be used in the 1.2 branch. Using a {\tt flags:foo} {\em tag} instead is thus allowed as a compatible way to activate flag {\tt foo} on 1.2.x versions. \item {\tt features} is currently experimental and shouldn't be used on the main package repository. It allows to define custom variables that better document what {\em features} are available in a given package build. Each feature is defined as an identifier, a documentation string, and a filter expression. The filter expression can evaluate to either a boolean or a string, and the defined identifier can be used as a variable in any filter (but recursive features are not allowed and will return {\tt undefined}). This is typically useful to pass appropriate flags to {\tt ./configure} scripts, depending on what is installed. \end{itemize} \subsubsection{URL files: {\tt url}} \label{file:url} The syntax of {\tt url} files follows the one described in \S\ref{file:general} with the following restrictions: \begin{Verbatim} := ?src: STRING ?archive: STRING ?http: STRING ?local: STRING ?git: STRING ?darcs: STRING ?hg: STRING ?mirrors: [ STRING+ ] ?checksum: STRING \end{Verbatim} {\tt src}, {\tt archive}, {\tt http}, {\tt local}, {\tt git}, {\tt hg}, {\tt darcs} are the location where the package upstream sources can be downloaded. It can be one of: \begin{itemize} \item A directory on the local file system (which will be copied to the build directory). Use {\tt local}. \item An archive file on the local file system (which will be unpacked into the build directory). Use {\tt local}. \item An archive file at a URL that is understood by either curl or wget (which will be fetched using either curl (if that available) or wget (if curl is not available) and unpacked into the build directory). Use {\tt http}. \item a version-controlled repository under git, darcs or hg, or a specific commit, tag or branch in that repository if the string ends by \verb+#+ or \verb+#+ or \verb+#+. Use {\tt git}, {\tt hg} or {\tt darcs}. \item \OPAM\ will try to guess the source kind if you use {\tt src} or {\tt archive}. It shouldn't be used for version control systems, for which the above are preferred. \end{itemize} {\tt mirrors}, if specified, is assumed to be a list of addresses of the same kind as the primary address. Mirrors will be tried in order in case the download from the primary upstream fails. \subsection{Commands} \subsubsection{Creating a Fresh Client State} \label{opam-init} When an end-user starts \OPAM\ for the first time, he needs to initialize \verb+$opam/+ in a consistent state. In order to do so, he should run: \begin{verbatim} $ opam init [--kind $KIND] $REPO $ADDRESS [--comp $VERSION] \end{verbatim} Where: \begin{itemize} \item \verb+$KIND+ is the kind of \OPAM\ repository (default is {\tt http}); \item \verb+$REPO+ is the name of the repository (default is {\tt default}); and \item \verb+$ADDRESS+ is the repository address (default is \verb+http://opam.ocamlpro.com/pub+). \item \verb+$COMP+ is the compiler version to use (default is the version of the compiler installed on the system). \end{itemize} This command will: \begin{enumerate} \item Create the file \verb+$opam/config+ (as specified in \S\ref{file:config}) \item Create an empty \verb+$opam/$SWITCH/installed+ file, \verb+$SWITCH+ %being the result of ``{\tt ocamlc -version}''. is the version from the OCaml used to compile \verb+$opam+. In particular, we will not fail now if there is no \verb+ocamlc+ in \verb+$path+. \item Initialize \verb+$opam/repo/$REPO+ by running the appropriate operations (depending on the repository kind). \item Copy all \OPAM\ and description files (ie. copy every file in \verb+$opam/repo/$REPO/packages/+ to \verb+$opam/packages/+). \item Create \verb+$opam/repo/package-index+ and for each version \verb+$VERSION+ of package \verb+$NAME+ appearing in the repository, append the line \verb+'$REPO $NAME $VERSION'+ to the file. \item Create the empty directories \verb+$opam/archives+, \verb+$opam/$SWITCH/lib/+, \verb+$opam/$SWITCH/bin/+ and \verb+$opam/$SWITCH/doc/+. \end{enumerate} \subsubsection{Listing Packages} \label{opam-list} When an end-user wants to have information on all available packages, he should run: \begin{verbatim} $ opam list \end{verbatim} This command will parse \verb+$opam/$SWITCH/installed+ to know the installed packages, and \verb+$opam/packages/$NAME/$NAME.$VERSION/opam+ to get all the available packages. It will then build a summary of each packages. The description of each package will be read in \verb+$opam/packages/$NAME/$NAME.$VERSION/descr+ if it exists. For instance, if {\tt batteries} version {\tt 1.1.3} is installed, {\tt ounit} version {\tt 2.3+dev} is installed and {\tt camomille} is not installed, then running the previous command should display: \begin{verbatim} batteries 1.1.3 Batteries is a standard library replacement ounit 2.3+dev Test framework camomile -- Unicode support \end{verbatim} \subsubsection{Getting Package Info} In case the end-user wants a more details view of a specific package, he should run: \begin{verbatim} $ opam info $NAME \end{verbatim} This command will parse \verb+$opam/$SWITCH/installed+ to get the installed version of \verb+$NAME+, will process \verb+$opam/repo/index+ to get the repository where the package comes from and will look for \verb+$opam/packages/$NAME/$NAME.$VERSION/opam+ to get available versions of \verb+$NAME+. It can then display: \begin{verbatim} package: $NAME version: $VERSION versions: $VERSION1, $VERSION2, ... libraries: $LIB1, $LIB2, ... syntax: $SYNTAX1, $SYNTAX2, ... repository: $REPO description: $SYNOPSIS $LINE1 $LINE2 $LINE3 ... \end{verbatim} \subsubsection{Installing a Package} \label{opam-install} When an end-user wants to install a new package, he should run: \begin{verbatim} $ opam install $NAME \end{verbatim} This command will: \begin{enumerate} \item Compute the transitive closure of dependencies and conflicts of packages using the dependency solver (see \S\ref{deps}). If the dependency solver returns more than one answer, the tool will ask the user to pick one, otherwise it will proceed directly. The dependency solver should also mark the packages to recompile. \item The dependency solver sorts the collections of packages in topological order. Then, for each of them do: \begin{enumerate} \item Check whether the package is already installed by looking for the line \verb+$NAME $VERSION+ in \verb+$opam/$SWITCH/installed+. If not, then: \item Look into the archive cache to see whether it has already been downloaded. The cache location is: \verb+$opam/archives/$NAME.VERSION.tar.gz+ \item If not, process \verb+$opam/repo/index/+ (see \ref{section:repositories}) to get the repository \verb+$REPO+ where the archive is available and then ask the repository to download the archive if necessary. Once this is done, the archive might become available in \verb+$opam/repo/$REPO/archives/+. It it is, copy it in the global state (in \verb+$opam/archives+). If it is not, download it upstream by looking at \verb|$opam/packages/$NAME/$NAME.$VERSION/url| and add the optional overlay files located in \verb|$opam/packages/$NAME/$NAME.$VERSION/files|. Note: this files can be overwritten by anything present in \verb|$opam/$SWITCH/overlay/$NAME/|. \item Decompress the archive into \verb+$opam/$SWITCH/build/$NAME.$VERSION/+. \item Substitute the required files. \item Run the list of commands to build the package with \verb+$opam/$SWITCH/bin+ in the path. \item Process \verb+$opam/$SWITCH/build/$NAME.$VERSION/$NAME.install+ to install the created files. The file format is described in \S\ref{file:install}. \item Install the installation file \verb+$opam/$SWITCH/build/$NAME.$VERSION/$NAME.install+ in \verb+$opam/$SWITCH/install/+ and the configuration file \verb+$opam/$SWITCH/build/$NAME.$VERSION/$NAME.config+ in \verb+$opam/$SWITCH/config/+. \end{enumerate} \end{enumerate} \subsubsection{Updating Index Files} \label{opam-update} When an end-user wants to know what are the latest packages available, he will write: \begin{verbatim} $ opam update \end{verbatim} This command will follow the following steps: \begin{itemize} \item Update each repositories in \verb+$opam/config+. \item For each repositories in \verb+$opam/config+, call the corresponding update scripts. Then, look at the difference between the digest of files in the global state and in each repositories, and fix the discrepancies (while notifying the user) if necessary. Here, the order in which the repositories are specified is important: the first repository containing a given version for a package will be the one providing it (this can be changed manually by editing \verb+$opam/repo/index+ later). \item For each installed pinned and development packages, look at what changed upstream and if something has changed, update \verb+$opam/$SWITCH/reinstall+ accordingly (for each compiler version \verb+$SWITCH+). \item Packages in \verb+$opam/$SWITCH/reinstall+ will be reinstalled (or upgraded if a new version is available) on the next {\tt opam upgrade} (see \S\ref{opam-upgrade}), with \verb+$SWITCH+ being the current compiler version when the upgrade command is run. \end{itemize} \subsubsection{Upgrading Installed Packages} \label{opam-upgrade} When an end-user wants to upgrade the packages installed on his host, he will write: \begin{verbatim} $ opam upgrade \end{verbatim} This command will: \begin{itemize} \item Call the dependency solver (see \S\ref{deps}) to find a consistent state where {\bf most} of the installed packages are upgraded to their latest version. Moreover, packages listed in \verb+$opam/$SWITCH/reinstall+ will be reinstalled (or upgraded if a new version is available). It will install each non-installed packages in topological order, similar to what it is done during the install step, See \S\ref{opam-install}. \item Once this is done the command will delete \verb+$opam/$SWITCH/reinstall+. \end{itemize} \subsubsection{Removing Packages} \label{opam-remove} When the user wants to remove a package, he should write: \begin{verbatim} $ opam remove $NAME \end{verbatim} This command will check whether the package \verb+$NAME+ is installed, and if yes, it will display to the user the list packages that will be uninstalled (ie. the transitive closure of all forward-dependencies). If the user accepts the list, all the packages should be uninstalled, and the client state should be let in a consistent state. \subsubsection{Dependency Solver} \label{deps} Dependency solving is a hard problem and we do not plan to start from scratch implementing a new SAT solver. Thus our plan to integrate (as a library) the Debian depency solver for CUDF files, which is written in OCaml. \begin{itemize} \item the dependency solver should run on the client; and \item the dependency solver should take as input a list of packages (with some optional version information) the user wants to install, upgrade and remove and it should return a consistent list of packages (with version numbers) to install, upgrade, recompile and remove. \end{itemize} \section{Managing Compiler Switches} \label{section:switches} \OPAM\ is able to manage concurrent compiler installations. \subsection{State} Compiler descriptions are stored in two files: \begin{itemize} \item \verb|$opam/compilers/$VERSION/$VERSION[+$TAG]/comp| contains the meta-data for a given compiler.\verb+$VERSION+ is the compiler version and \verb+$TAG+ an optional tag (such as \verb|4.01+fp|). The format of {\tt .comp} file is described in \ref{file:comp}. \item (optional) \verb|$opam/compilers/$VERSION/$VERSION[+$TAG]/descr| contains the description of that compiler. \verb+$VERSION+ is the compiler version and \verb+$TAG+ an optional tag (such as \verb|4.01+fp|). The first line of that line is used as synopsis and is displayed with {\tt opam repository list}. \end{itemize} Switch-related meta-data are stored under \verb+$opam/$SWITCH/+: \begin{itemize} \item \verb+$opam/$SWITCH/installed+ is the list of installed packages for the compiler instance \verb+$SWITCH+. The file format is described in \S\ref{file:installed}. \item \verb+$opam/$SWITCH/installed.root+ is the list of installed packages roots for the compiler instance \verb+$SWITCH+. The file format is described in \S\ref{file:installed}. A package root has been explicitly installed by the user. \item \verb+$opam/$SWITCH/config/$NAME.config+ is a platform-specific configuration file of for the installed package \verb+$NAME+ with the compiler instance \verb+$SWITCH+. The file format is described in \S\ref{file:config}. \item \verb+$opam/$SWITCH/install/$NAME.install+ is a platform-specific package installation file for the installed package \verb+$NAME+ with the compiler instance \verb+$SWITCH+. The file format is described in \S\ref{file:install}. \item \verb+$opam/$SWITCH/lib/$NAME/+ contains the libraries associated to the installed package \verb+$NAME+ with the compiler instance \verb+$SWITCH+. \item \verb+$opam/$SWITCH/doc/$NAME/+ contains the documentation associated to the installed package {\tt NAME} with the compiler instance \verb+$SWITCH+. \item \verb+$opam/$SWITCH/bin/+ contains the program files for all installed packages with the compiler instance \verb+$SWITCH+. \item \verb+$opam/$SWITCH/build/$NAME.$VERSION/+ is a tempory folder used to build package \verb+$NAME+ with version \verb+$VERSION+, with compiler instance \verb+$SWITCH+. \item \verb+$opam/$SWITCH/reinstall+ contains the list of packages which has been changed upstream since the last upgrade. This can happen for instance when a packager uploads a new archive or fix the {\tt opam} file for a specific package version. Every package appearing in this file will be reinstalled (or upgraded if a new version is available) during the next upgrade when the current instance of the compiler is \verb+$SWITCH+. The file format is similar to the one described in \S\ref{file:installed}. \item \verb+$opam/$SWITCH/pinned+ contains the list of pinned packages. The file format is described in \S\ref{file:pinned}. \item \verb+$opam/$SWITCH/overlay/$NAME/+ contains overlay files for package \verb+$NAME+, for the switch \verb+$SWITCH+. These possible overlay files are {\tt opam}, {\tt url}, {\tt descr} or the directory {\tt files/}. If one of this file (or directory) is present, the file (or directory) will be used instead of the global one. \item \verb+$opam/$SWITCH/packages.dev+ contains cached information for dev and pinned packages. \OPAM\ uses it on update to check which package needs to be upgraded. \end{itemize} \subsection{Files} \subsubsection{Package List: {\tt installed} and {\tt reinstall}} \label{file:installed} The following configuration files: \verb+$opam/$SWITCH/installed+, \verb+$opam/$SWITCH/reinstall+, and \verb+$opam/repo/$REPO/updated+ follow a very simple syntax. The file is a list of lines which contains a space-separated name and a version. Each line \verb+$NAME $VERSION+ means that the version \verb+$VERSION+ of package \verb+$NAME+ has been compiled with the compiler instance \verb+$SWITCH+ and has been installed on the system in \verb+$opam/$SWITCH/lib/$NAME+ and \verb+$opam/$SWITCH/bin/+. \\ For instance, if {\tt batteries} version {\tt 1.0+beta} and {\tt ocamlfind} version {\tt 1.2} are installed, then \verb+$opam/$SWITCH/installed+ will contain: \begin{Verbatim} batteries 1.0+beta ocamlfind 1.2 \end{Verbatim} \subsubsection{Compiler Description Files: {\tt comp}} \label{file:comp} The syntax of {\tt comp} files follows the one described in \S\ref{file:general} with the following restrictions: \begin{Verbatim} := opam-version: "1.2" name: STRING ?src: STRING ?archive: STRING ?http: STRING ?local: STRING ?git: STRING ?darcs: STRING ?hg: STRING ?make: STRING+ ] ?build: [[STRING+]] ?patches: [ STRING+ ] ?configure: [ STRING+ ] ?packages: + ?preinstalled: BOOL ?env: [ + ] := IDENT STRING := '=' | '+=' | '=+' | ':=' | '=:' \end{Verbatim} \begin{itemize} \item {\tt name} is the compiler name, it should be identical to the filename. \item {\tt src}, {\tt archive}, {\tt http}, {\tt local}, {\tt git}, {\tt hg}, {\tt darcs} are the location where the compiler sources can be downloaded. It can be: \begin{itemize} \item A directory on the local file system (which will be linked or, if file system doesn't support links, copied to the build directory). Use {\tt local}. \item An archive file on the local file system (which will be unpacked into the build directory). Use {\tt local}. \item An archive file at a URL that is understood by either curl or wget (which will be fetched using either curl (if that available) or wget (if curl is not available) and unpacked into the build directory). Use {\tt http}. \item a version-controlled repository under git, darcs or hg, or a specific commit, tag or branch in that repository if the string ends by \verb+#+ or \verb+#+ or \verb+#+. Use {\tt git}, {\tt hg} or {\tt darcs}. \item \OPAM\ will try to guess the source kind if you use {\tt src} or {\tt archive}. \end{itemize} \item {\tt patches} are optional patch addresses, available via {\tt http} or locally on the filesystem. \item {\tt configure} are the optional flags to pass to the configure script. The order is relevant: {\tt --prefix=\$opam/SWITCH/} will be automatically added at the end to these options. Remark that if these flags contain {\tt --bindir}, {\tt --libdir}, and {\tt --mandir}, then every {\tt --prefix} will be ignored by {\tt configure}. \item {\tt make} are the flags to pass to {\tt make}. It must at least contain some target like {\tt world} or {\tt world.opt}. If {\tt make} is not present, \OPAM\ will execute all the commands listed in {\tt build}. \item {\tt packages} is the list of packages to install just after the compiler installation finished. \item {\tt preinstall} is {\tt true} when the version of the compiler available in the path is the same as {\tt name}. \item {\tt env} is the list of environment variables to set in the given compiler switch: \begin{itemize} \item {\tt VAR = "value"} set the variable to the given value; \item {\tt VAR += "value"} prepend the given value to the variable; \item {\tt VAR =+ "value"} append the given value to the variable; \item {\tt VAR := "value"} prepend the given value to the variable, separated by a colon. If the variable was empty, add the colon anyway. \item {\tt VAR =: "value"} append the given value to the variable, separated by a colon. If the variable was empty, add the colon anyway. \end{itemize} \end{itemize} For instance the file, {\tt 3.12.1+memprof.comp} describes OCaml, version $3.12.1$ with the memory profiling patch enabled: \begin{verbatim} opam-version: "1.2" name: "3.12.1" src: "http://caml.inria.fr/pub/distrib/ocaml-3.12/ocaml-3.12.1.tar.gz" make: [ "world" "world.opt" ] patches: [ "http://bozman.cagdas.free.fr/documents/ocamlmemprof-3.12.0.patch" ] env: [ CAML_LD_LIBRARY_PATH = "%{lib}%/stublibs" ] \end{verbatim} And the file {\tt trunk-g-notk-byte.comp} describes OCaml from SVN trunk, with no {\em tk} support and only in bytecode, and all the libraries built with {\tt -g}: \begin{verbatim} opam-version: "1.2" name: "trunk-g-notk-byte" src: "http://caml.inria.fr/pub/distrib/ocaml-3.12/ocaml-3.12.1.tar.gz" configure: [ "-no-tk" ] make: [ "world" ] bytecomp: [ "-g" ] bytelink: [ "-g" ] env: [ CAML_LD_LIBRARY_PATH = "%{lib}%/stublibs" ] \end{verbatim} \subsubsection{Package installation files: {\tt *.install}} \label{file:install} \verb+$opam/$SWITCH/install/NAME.install+ follows the syntax defined in \S\ref{file:general} with the following restrictions: \begin{Verbatim} := ?lib: [ + ] ?libexec: [ + ] ?bin: [ + ] ?sbin: [ + ] ?toplevel: [ + ] ?share: [ + ] ?share_root: [ + ] ?etc: [ + ] ?doc: [ + ] ?misc: [ + ] ?stublibs: [ + ] ?man: [ + ] := STRING | STRING { STRING } \end{Verbatim} \begin{itemize} \item Files listed under {\tt lib} are copied into \verb+$opam/$SWITCH/lib/$NAME/+. \item Files listed under {\tt libexec} are copied into \verb+$opam/$SWITCH/lib/$NAME/+, but with execution permission. \item Files listed under {\tt bin} are copied into \verb+$opam/$SWITCH/bin/+. \item Files listed under {\tt sbin} are copied into \verb+$opam/$SWITCH/sbin/+. \item Files listed under {\tt doc} are copied into \verb+$opam/$SWITCH/doc/$NAME/+. \item Files listed under {\tt share} are copied into \verb+$opam/$SWITCH/share/$NAME/+. \item Files listed under {\tt share\_root} are copied into \verb+$opam/$SWITCH/share/+. \item Files listed under {\tt etc} are copied into \verb+$opam/$SWITCH/etc/$NAME/+. \item Files listed under {\tt toplevel} are copied into \verb+$opam/$SWITCH/lib/toplevel/+. \item Files lister under {\tt stublibs} are copied into \verb+$opam/$SWITCH/lib/stublibs/+ \item Files listed under {\tt man} are copied into \verb+$opam/$SWITCH/man/manN+, where \verb+N+ is taken from the extension of the source file if $1\dots8$ (not considering a \verb+.gz+ extension). If the destination is explicit, it will be taken relative to \verb+$opam/$SWITCH/man+, e.g. \verb+man: [ "foo.1" ]+ is equivalent to \verb+man: [ "foo.1" {"man1/foo.1"} ]+ \item Files listed under {\tt misc} are processed as follows: for each pair \verb+$SRC { $DST }+, the tool asks the user if he wants to install \verb+$SRC+ to the absolute path \verb+$DST+. \end{itemize} General remarks: \begin{itemize} \item You control where the files are copied under the given prefix by using the optional argument. For instance: \verb+doc: [ "_build/foo.html" {"foo/index.html"} ]+ will copy the given HTML page under \verb+$opam/$SWITCH/doc/$NAME/foo/index.html+. \item \OPAM\ will try to install all the files in sequence, and it will fail in case a source filename is not available. To tell \OPAM\ a source filename might not be generated (because of byte/native constraints or because of optional dependencies) the source filename should be prefixed with \verb+?+. \item It is much cleaner if the underlying build-system can generate the right \verb+$NAME.install+ files, containing the existing files only. \item File permissions are set to $0644$, except for {\tt libexec}, {\tt bin}, {\tt sbin}, {\tt stublibs} for which it's $0755$. {\tt umask} may apply. \item These files can be used for installation outside of the scope of \OPAM using the {\tt opam-installer} program shipped with \OPAM . \end{itemize} \subsubsection{Pinned Packages: {\tt pinned}} \label{file:pinned} \verb+$opam/$SWITCH/pinned+ contains a list of lines of the form: \begin{Verbatim} \end{Verbatim} \begin{itemize} \item \verb++ is the name of the pinned package \item \verb++ is the kind of pinning. This could be \verb+version+, \verb+local+, \verb+git+ or \verb+darcs+. \item \verb++ is either the version number (if kind is \verb+version+) or the path to synchronize with. \end{itemize} \subsection{Commands} \subsubsection{Switching Compiler Version} If the user wants to switch to another compiler version, he should run: \begin{verbatim} $ opam switch [-alias-of $COMPILER] $SWITCH \end{verbatim} This command will: \begin{itemize} \item If \verb+$COMPILER+ is not set, set it to \verb+$SWITCH+ \item Look for an existing \verb+$opam/$COMPILER+ directory. \begin{itemize} \item If it exists, then change the {\tt ocaml-version} content to \verb+$COMPILER+ in \verb+$opam/config+. \item If it does not exist, look for an existing \verb|$opam/compilers/$VERSION/$VERSON[+$TAG]/comp|, where \verb|$COMPILER = $VERSION[+TAG]| If the file does not exists, the command will fail with a well-defined error. \item If the file exist, then build the new compiler with the right options (and pass \verb+--prefix $opam/$SWITCH+ to \verb+./configure+) and initialize everything in \verb+$opam/+ in a consistent state as if ``\verb+opam init+'' has just been called. \item Update the file \verb+$opam/aliases+ with the line \verb+$SWITCH $COMPILER+ \end{itemize} \end{itemize} \section{Managing Repositories} \label{section:repositories} \subsection{State} \label{state-repo} Configuration files for the remote repository \verb+REPO+ are stored in \verb+$opam/repo/$REPO+. Repositories can be of different kinds (stored on the local filesystem, available via HTTP, stored under git, $\ldots$); they all share the same filesystem hierachy, which is updated by different operations, depending on the repository kind. \begin{itemize} \item \verb+$opam/repo/$REPO/version+ contains the minimum version of \OPAM\ which can read that repository meta-data. \item \verb+$opam/repo/$REPO/config+ contains the configuration of the repository \verb+$REPO+. % The format of repository config % files is described in \S\ref{file:repo-config}. \item \verb+$opam/repo/$REPO/packages/$PREFIX/$NAME.$VERSION/opam+ is the {\tt opam} file for the package \verb+$NAME+ with version \verb+$VERSION+ (which might not be installed) with any possible \verb+$PREFIX+. The format of {\tt opam} files is described in \S\ref{file:opam}. \item (optional) \verb+$opam/repo/$REPO/packages/$PREFIX/$NAME.$VERSION/descr+ contains the textual description for the version \verb+$VERSION+ of package \verb+$NAME+ (which might not be installed) with any possible \verb+$PREFIX+ -- it should be in the same loacation as the corresponding {\tt opam} file. The first line of this file is the package synopsis. \item (optional) \verb+$opam/repo/$REPO/packages/$PREFIX/$NAME.$VERSION/url+ contains the upstream location for the version \verb+$VERSION+ of package \verb+$NAME+ (which might not be installed) with any possible \verb+$PREFIX+ -- it should be in the same loacation as the corresponding {\tt opam} file. The format of {\tt url} files is described in \S\ref{file:url}. \item (optional) \verb+$opam/repo/$REPO/packages/$PREFIX/$NAME.$VERSION/files/+ contains the overlay files for the version \verb+$VERSION+ of package \verb+$NAME+ (which might not be installed) with any possible \verb+$PREFIX+ -- it should be in the same loacation as the corresponding {\tt opam} file. The overlay files are added to the build directory when a package is built and installed. \item (optional) \verb+$opam/repo/$REPO/archives/$NAME.$VERSION.tar.gz+ contains the source archives for the version \verb+$VERSION+ of package \verb+$NAME+. This folder is populated when a package needs to be downloaded and that the given repository expose such a file. If the file is not present, \OPAM\ will download the package from the upstream sources. \end{itemize} \subsection{Files} \subsubsection{Index of packages} \label{file:index} \verb+$opam/repo/index+ follows a very simple syntax: each line of the file contains a space separated list of words \verb|$NAME.$VERSION $REPO+| specifying that all the version \verb+$VERSION+ of package \verb+$NAME+ is available in the remote repositories \verb|$REPO+|. The file contains information on all available packages (e.g. not only on the installed one). \\ For instance, if {\tt batteries} version {\tt 1.0+beta} is available in the {\tt testing} repository and {\tt ocamlfind} version {\tt 1.2} is available in the {\tt default} and testing repositories (where {\tt default} is one being used), then \verb+$opam/repo/index+ will contain: \begin{Verbatim} batteries.1.0+beta testing ocamlfind.1.2 default testing \end{Verbatim} \subsection{Commands} \subsubsection{Managing Remote Repository} An user can manage remote repositories, by writing: \begin{verbatim} $ opam repository list # 'opam repository' works as well $ opam repository add [--kind $KIND] $REPO $ADRESS $ opam repository remove $REPO \end{verbatim} \begin{itemize} \item \verb+list+ lists the current repositories by looking at \verb+$opam/config+ \item \verb+add [--kind $KIND] $REPO $ADDRESS+ initializes \verb+$REPO+ as described in \S\ref{opam-init}. \item For distributed version controlled repository, the user can use \verb+url#hash+ or \verb+url#name+ where {\tt hash} is a given revision name and {\tt name} it the name of a tag or a branch. \item \verb+remove $REPO+ deletes \verb+$opam/repo/$REPO+ and removes \verb+$REPO+ from the {\tt repositories} list in \verb+$opam/config+. Then, for each package in \verb+$opam/repo/index+ it updates the link between packages and repositories (ie. it either deletes packages or symlink them to the new repository containing the package). \end{itemize} \section{Managing Configurations} \label{section:config} \subsection{State} \subsection{Variables} \label{subsection:variables} Variables can appear in some fields of {\tt opam} files (see \S\ref{file:opam}), and in substition files (see below). There are three kinds. Note that this list is often out of date, you should check \verb+opam config list+ for a complete overview. \begin{enumerate} \item Global variables, corresponding to the current configuration \begin{itemize} \item \verb+opam-version+ the running version of OPAM \item \verb+ocaml-version+ the currently used version of OCaml \item \verb+switch+ the user-defined name (alias) of the current switch \item \verb+compiler+ the full OPAM name of the current OCaml compiler \item \verb+preinstalled+ whether the compiler was preinstalled on the system or managed by OPAM \item \verb+ocaml-native+ whether native compilation is available ({\tt ocamlopt}) \item \verb+ocaml-native-tools+ whether the {\tt .opt} variant of the compilers are available ({\bf not} the {\tt ocamlopt} native compiler itself) \item \verb+ocaml-native-dynlink+ whether native dynlink is available \item \verb+jobs+ the configured number of parallel jobs to run \item \verb+arch+ the host architecture, as returned by \verb+uname -m+ \end{itemize} \item Package-local variables. Variable \verb+$VAR+ of package \verb+$NAME+ is normally accessed using \verb+%{$NAME:$VAR}%+, which can be abbreviated as \verb+%{$VAR}%+ within \verb+$NAME+'s own opam file (but global variables take precedence, in particular directory names. Check \verb+opam config list+). Some are only available from the opam file or when the corresponding package is installed. \begin{itemize} \item \verb+installed+ whether the package is installed \item \verb+enable+ same as \verb+installed+, but takes the value \verb+"enable"+ or \verb+"disable"+. To be used in configure scripts \item \verb+pinned+ whether the package is pinned \item \verb+bin+, \verb+sbin+, \verb+lib+, \verb+man+, \verb+doc+, \verb+share+, \verb+etc+, the installation directories used by the package \item \verb+name+ the name of the package \item \verb+version+ the version of the package (the one corresponding to the current opam file if relevant, the installed one otherwise) \item \verb+build+ the temporary build directory of this package \item \verb+depends+ the list of current direct dependencies of this package. Optional dependencies are included if they are currently available \item \verb+hash+ the md5 of the opam archive of the package, if available. For cache mechanisms \end{itemize} Boolean variables can also be written as \verb!foo+bar:var! as a shortcut to \verb!foo:var & bar:var!. \item User-defined variables, as defined in {\tt *.config} files (see \S\ref{file:dotconfig}). This can also be used to override values of the above variables. \end{enumerate} As an experimental feature in \OPAM\ 1.2.1 ({\em i.e.} not to be used on the main package repository), converters of boolean variables to strings can be specified with the following syntax: \verb+"%{var?string-if-true:string-if-false-or-undefined}%"+. Either string may be empty. \subsection{Files} \subsubsection{Substitution files: {\tt *.in}} \label{file:subst} Any file can be processed using generated using a special mode of {\tt opam} which can perform tests and substitutes variables (see \S\ref{section:config} for the exact command to run). Substitution files contains some templates which will be replaced with some contents. The syntax of templates is the following: \begin{itemize} \item templates such as \verb+%{$NAME:$VAR}%+ are replaced by the value of the variable \verb+$VAR+ defined at the root of the file \verb+$opam/$SWITCH/config/NAME.config+. \item templates such as \verb+%{$NAME.$LIB:$VAR}%+ are replaced by the value of the variable \verb+$VAR+ defined in the \verb+$LIB+ section in the file \verb+$opam/$SWITCH/config/$NAME.config+ \end{itemize} \paragraph{Local and global variables} The definitions ``{\tt IDENT: BOOL}'', ``{\tt IDENT: STRING}'' and ``{\tt IDENT: [ STRING+ ]}'', are used to defined variables associated to this package, and are used to substitute variables in template files (see \S\ref{subst}): \begin{itemize} \item \verb+%{$NAME:$VAR}%+ will refer to the variable \verb+$VAR+ defined at the root of the configuration file \verb+$opam/$SWITCH/config/NAME.config+. \item Run {\tt opam config var} for the full list of available variables. \end{itemize} \subsection{Commands} \subsubsection{Getting Package Configuration} \label{opam-config} \OPAM\ contains the minimal information to be able to use installed libraries. In order to do so, the end-user (or the packager) should run: \begin{verbatim} $ opam config list $ opam config var $NAME:$VAR $ opam config var $NAME.$LIB:$VAR $ opam config subst $FILENAME+ \end{verbatim} \begin{itemize} \item \verb+var $var+ will return the value associated to the variable \verb+$var+ \item \label{subst}\verb+subst $FILENAME+ replace any occurrence of \verb+%{$NAME:$VAR}%+ and \verb+%{$NAME.$LIB:$VAR}%+ as specified in \S\ref{file:subst} in \verb+$FILENAME.in+ to create \verb+$FILENAME+. \end{itemize} \end{document} opam-full-1.2.2/doc/dev-manual/htmlmacros.hva0000644000175000017500000000003712517374212017601 0ustar useruser\loadcssfile{./dev-manual.css} opam-full-1.2.2/doc/dev-manual/dev-manual.css0000644000175000017500000000261412517374212017476 0ustar useruser/* ==== general presentation ==== */ body { padding: 0.4em 16% 3em 8%; } h1, h1 a, h2, h2 a, h3, h3 a { padding: 0 0 0 0.4em; } .titlemain, .titlerest { padding: 0.2em 3.8em; } pre { padding: 0.2em 0.4em; margin: 0.4em 0.6em; } p { padding: 0 0 0 0.8em; } dt { padding: 0 0 0 0.6em; } h1 { font-size: 1.6em; } h2 { font-size: 1.4em; } h3 { font-size: 1.2em; } h1 a { font-size: 1.0em; } h2 a { font-size: 1.0em; } h3 a { font-size: 1.0em; } a { text-decoration: none; } a:hover { text-decoration: underline; } /* ==== morning colors ==== */ body { color: #333; background-color: #F0F0F0; } pre { color: #224; background: #DDE; border: 1px solid #8AC; } h1, h1 a, h2, h2 a, h3, h3 a { color: #228; background: #CDF; } a { color: #08C; } a:hover { color: #06E; background: #DEF; } /* ==== evening colors ==== *\ body { color: #CCC; background-color: #226; } pre { color: #BDF; background: #447; border: 1px solid #46A; } h1, h1 a, h2, h2 a, h3, h3 a { color: #CCC; background: #359; } a { color: #6CF; } a:hover { color: #9EF; background: #448; } */ /* ==== sunny colors ==== *\ body { color: #333; background-color: #ffcd95; } pre { color: #422; background: #fdb50b; border: 1px solid #832809; } h1, h1 a, h2, h2 a, h3, h3 a { color: #672910; background: #ff9a0a; } a { color: #b94a48; } a:hover { color: #91310b; background: #fccb0d; } */ opam-full-1.2.2/doc/dev-manual/pdfswitch.sty0000644000175000017500000001103412517374212017463 0ustar useruser%% %% This is file `pdfswitch.sty', %% generated with the docstrip utility. %% %% The original source files were: %% %% pdfswitch.dtx (with options: `package') %% %% IMPORTANT NOTICE: %% %% For the copyright see the source file. %% %% Any modified versions of this file must be renamed %% with new filenames distinct from pdfswitch.sty. %% %% For distribution of the original source see the terms %% for copying and modification in the file pdfswitch.dtx. %% %% This generated file may be distributed as long as the %% original source files, as listed above, are part of the %% same distribution. (The sources need not necessarily be %% in the same archive or directory.) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \def\fileversion{0.0.2} \def\filedate{2003/07/12} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage% {pdfswitch}% [\filedate\space Automatic switch between pdf and ps. v\fileversion] \RequirePackage{ae,aeguill} \RequirePackage{color} \RequirePackage{ifthen} \RequirePackage{ifpdf} \newboolean{nocolor@pdfswitch} \setboolean{nocolor@pdfswitch}{false} \DeclareOption{nocolor}{\setboolean{nocolor@pdfswitch}{true}} \newboolean{backref@pdfswitch} \setboolean{backref@pdfswitch}{false} \DeclareOption{backref}{\setboolean{backref@pdfswitch}{true}} \newboolean{pagebackref@pdfswitch} \setboolean{pagebackref@pdfswitch}{false} \DeclareOption{pagebackref}{\setboolean{pagebackref@pdfswitch}{true}} \newboolean{noborder@pdfswitch} \setboolean{noborder@pdfswitch}{false} \DeclareOption{noborder}{\setboolean{noborder@pdfswitch}{true}} \newboolean{plainpages@pdfswitch} \setboolean{plainpages@pdfswitch}{false} \DeclareOption{plainpages}{\setboolean{plainpages@pdfswitch}{true}} \ProcessOptions \definecolor{pdfurlcolor}{rgb}{0,0,0.6} \definecolor{pdfcitecolor}{rgb}{0,0.6,0} \definecolor{pdflinkcolor}{rgb}{0.6,0,0} %%%%%%%%%%%%%%%%%%%%%%%%% graphicx and thumbpdf %%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ifpdf \usepackage[pdftex]{graphicx} %%% graphics for pdfLaTeX \DeclareGraphicsExtensions{.pdf} %%% standard extension for included graphics \usepackage[pdftex]{thumbpdf} %%% thumbnails for pdflatex \else \usepackage[dvips]{graphicx} %%% graphics for dvips \DeclareGraphicsExtensions{.ps,.eps} %%% standard extension for included graphics \fi %%%%%%%%%%%%%%%%%%%%%%%%% Basic options for hyperref %%%%%%%%%%%%%%%%%%%%%%%%% \ifpdf \edef\keys@pdfswitch{% pdftex, %%% hyper-references for pdflatex bookmarks=true,% %%% generate bookmarks ... bookmarksnumbered=true,% %%% ... with numbers hypertexnames=false,% %%% needed for correct links to figures !!! breaklinks=true% %%% break links if exceeding a single line } \else \edef\keys@pdfswitch{% ps2pdf, %%% hyper-references for ps2pdf bookmarks=true,% %%% generate bookmarks ... bookmarksnumbered=true,% %%% ... with numbers hypertexnames=false,% %%% needed for correct links to figures !!! breaklinks=true,% %%% breaks lines, but links are very small pdfborder={0 0 11.0} %%% border-width of frames will %%% be multiplied with 0.009 by ps2pdf } \fi \ifthenelse{\boolean{nocolor@pdfswitch}}{% \edef\keys@pdfswitch{\keys@pdfswitch,colorlinks=false}% }{ \edef\keys@pdfswitch{\keys@pdfswitch,colorlinks=true,% citecolor=pdfcitecolor, urlcolor=pdfurlcolor, linkcolor=pdflinkcolor, linkbordercolor={1 1 1}}% } \ifthenelse{\boolean{plainpages@pdfswitch}}{% }{ \edef\keys@pdfswitch{\keys@pdfswitch,plainpages=false}% } \ifthenelse{\boolean{noborder@pdfswitch}}{% \edef\keys@pdfswitch{\keys@pdfswitch,pdfborder={0 0 0}}% }{} \ifthenelse{\boolean{backref@pdfswitch}}{% \edef\keys@pdfswitch{\keys@pdfswitch,backref}% }{} \ifthenelse{\boolean{pagebackref@pdfswitch}}{% \edef\keys@pdfswitch{\keys@pdfswitch,pagebackref}% }{} \usepackage[\keys@pdfswitch]{hyperref} %%%%%%%%%%%%%%%%%%%%%%%%% HyperSetup %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ifpdf \AtBeginDocument{ \hypersetup{ pdfauthor = {\@author}, pdftitle = {\@title}, pdfsubject = {\@ifundefined{@subject}{}{\@subject}}, pdfkeywords = {\@ifundefined{@keywords}{}{\@keywords}} } } %%% pdfcreator, pdfproducer, and Creation Date are automatically set by pdflatex !!! \pdfadjustspacing=1 %%% force LaTeX-like character spacing \else \AtBeginDocument{ } \fi \endinput %% %% End of file `pdfswitch.sty'. opam-full-1.2.2/doc/dev-manual/Makefile0000644000175000017500000000035212517374212016370 0ustar useruser.PHONY: all all: dev-manual.pdf html: dev-manual.html %.pdf: %.tex pdflatex $* pdflatex $* %.html: %.tex hevea -fix htmlmacros.hva $< %.txt: %.html links -dump $< > $@ clean: rm -f *~ *.log *toc *.out *.bbl *.blg *aux *.html opam-full-1.2.2/doc/pages/0000755000175000017500000000000012532744757014012 5ustar useruseropam-full-1.2.2/doc/pages/FAQ.md0000644000175000017500000003244212517374212014734 0ustar useruser# OPAM FAQ > This FAQ is for general questions about OPAM and its usage. You may also be > interested in the more advanced [Tricks](Tricks.html) for specific use-cases > or advanced users. #### 🐫 OPAM fails, trying to reinstall already installed packages at first upgrade ? **Ubuntu "utopic" currently ships with a broken OPAM package**, that shouldn't happen and didn't in any stable OPAM release. See [the bug-report on Ubuntu's launchpad](https://bugs.launchpad.net/ubuntu/+source/opam/+bug/1401346) for the details. The best fix is to install [OPAM 1.2](Install.html) using the community packages. --- #### 🐫 What is OPAM for ? Easily installing, upgrading and managing your OCaml compiler(s), tools and libraries. It's made of a tool, the [OPAM package manager](https://github.com/ocaml/opam), and a community-maintained [package repository](https://github.com/ocaml/opam-repository). --- #### 🐫 How to get, install and upgrade OPAM ? See the [install guide](Install.html). --- #### 🐫 Where is the manual ? OPAM has git-like, hierarchical manpages. Try `opam --help` for a starting point. Or get started from the [Usage](Usage.html) guide. If you want to know more about OPAM packages, see the [Packaging Howto](Packaging.html). Last but not least, the reference on the file formats and more is in the [Developper Guide](http://opam.ocaml.org/doc/manual/dev-manual.html). --- #### 🐫 Gasp! `opam init` gives me screens fulls of errors about upgrading ! This is a glitch, at init only, on the older OPAM 1.1. We recommend upgrading to 1.2 -- but 1.1 is still supported through a compatibility layer on the repository, just use the following initialisation command to workaround the errors: ``` opam init https://opam.ocaml.org/1.1 ``` If your repository is already initialised, `opam update` should automatically redirect to 1.1 and you should be fine. --- #### 🐫 What changes does OPAM do to my filesystem ? OPAM is designed to be run strictly as user (non-root), and apart for the explicit options provided during `opam init`, only writes within `~/.opam` (and `/tmp`). This directory -- the default "OPAM root" -- contains configuration, various internal data, a cache of downloaded archives, and your OCaml installations. --- #### 🐫 Why does ``opam init`` need to add stuff to my init scripts / why is ``eval $(opam config env)`` needed ? You need two things when you install OPAM packages: to have their libraries accessible, and to access binary programs. To provide those, OPAM needs to setup a few ocaml-related environment variables, and to prepend to your PATH variable. Of course, you may choose not to let OPAM change anything at `opam init`, and run `eval $(opam config env)` yourself whenever you will be needing it. --- #### 🐫 What is a "switch" ? An OCaml installation and a set of installed packages within an OPAM installation. This can be used to keep different OCaml versions side-by-side, or different sets of packages. See the [related section](Usage.html#opamswitch) in the usage manual and `opam switch --help`. The "prefix" for a given installation is simply `~/.opam/`. A switch is either based on a system-wide OCaml installation, or on a local installation. In the former case, OPAM will need to recompile all packages when your system compiler changes. In the latter case, OCaml will be downloaded and compiled on creation of the switch. --- #### 🐫 Can I work on different switches at the same time in different shells ? Yes. Use one of: ``` eval $(opam config env --switch ) # for the current shell opam config exec --switch -- # for one command ``` This only affects the environment. --- #### 🐫 Can I get a new switch with the same packages installed ? Yes. Use: ``` opam switch export file.export # from the previous switch opam switch opam switch import file.export ``` OPAM might fail if you had packages installed that are not compatible with the OCaml version in your new switch. In that case, you'll need to remove them from the `file.export` file by hand (the format is straight-forward, one line per package). --- #### 🐫 I installed a package by hand / used ``ocamlfind remove`` / fiddled with the installed packages and OPAM is out of sync. Help ! Don't panic. OPAM assumes it's controlling what's below `~/.opam/`, but there are several ways you can recover: * `opam remove --force` will run the uninstall instructions even if the package is not registered as installed. Then retry `opam install`. * `opam reinstall` will try to remove an installed package, but go on to re-installing even if that fails. * If all else fails, you can re-install your current set of packages from scratch using `opam switch reinstall`. * You can force OPAM to register an installation or removal _without actually performing anything_ using `opam install|remove --fake`. This is not recommended though, as your manual install may not be exactly equivalent to the one expected by other OPAM packages, and OPAM may later on trigger reinstallations or upgrades of the package. Don't complain if you mess up your installation using this! If you want to control how a package is installed or modify it, the right way is `opam pin`. * You shouldn't have to, but if you want to restart from scratch, just delete `~/.opam` and get back to `opam init` --- #### 🐫 What are the minimum requirements ? 1GB of memory should be all you need. It was reported that you may run into problems with 512MB of RAM and no swap. Of course, software packages themselves may be more greedy. --- #### 🐫 Some package fail during compilation, complaining about missing dependencies ("m4", "libgtk", etc.) They probably depend on system, non-OCaml libraries: they need to be installed using your system package manager (apt-get, yum, pacman, homebrew, etc.) since they are outside the scope of OPAM. These external dependencies ("depexts") are in the process of being documented in the package repository, and the `opam-depext` tool should take care of that for you: ``` opam install depext opam depext ``` If that doesn't work... * Check for hints printed by the failing package * Dependencies for your specific system may not be known, but check the output of `opam list --rec --required-by ,... --external`: it will list dependencies on all known systems and may get you in the right direction. * Lookup the development packages corresponding to the error in your system's package repositories. In any of those case, that's useful information that was missing from the OPAM repository: we would really appreciate that you take a minute to save others the trouble of looking by filling an issue in [the opam-repository tracker](https://github.com/ocaml/opam-repository/issues), with your system details, the output of `opam depext --flags`, and the solution, if you found it. Thanks! --- #### 🐫 I have weird checksum errors: where do they come from ? First of all, you should make sure your repositories are up-to-date: ``` opam update ``` If this isn't enough, or if you get the checksum errors while running `opam init`, this could be caused by a badly configured proxy cache that is serving stale files. To clear your proxy cache, you can use `wget --no-cache ` and retry. As a last resort, you can bypass the checksum checks using `--no-checksums`. --- #### 🐫 OPAM is prompting me to install or upgrade packages that I am not interested in, or doesn't install the latest version by default. Why ? What can I do ? * You can be more explicit in your request (`opam upgrade PACKAGES`, `opam install 'PACKAGE>=VERSION' PACKAGE...`, etc.) * Action resolution in a package set is known to be a NP-complete problem; OPAM uses state-of-the-art algorithms through an external, dedicated solver: make sure you have the latest version of [aspcud](http://potassco.sourceforge.net/) installed. * Another benefit of the external solvers is that they allow to be [quite expressive](Specifying_Solver_Preferences.html) on your expectations. --- #### 🐫 When trying to install a new package, OPAM wants to remove or downgrade packages that I have installed. How to know why ? There is likely a conflict between them or their dependencies and what you are requesting, here is how to find out. We'll suppose you were trying to install `foo` and `bar` got removed: * `opam install foo bar`, if not possible, will tell you why. * The above may find a solution by using older version of the packages, in that case try and force the latest versions thusly: `opam install foo.2.0 bar.1.1` (you can also use constraints like `'foo>=2.0'`). * Like in previous question, make sure you have [aspcud](http://potassco.sourceforge.net/) installed, the proposed solutions may not be as accurate without it. --- #### 🐫 Where do I report Bugs, Issues and Feature Requests? - Bug reports and feature requests for the OPAM tool should be reported on [OPAM's issue-tracker](https://github.com/ocaml/opam/issues). - Packaging issues or requests for a new package can be reported on the [official repository's issue-tracker](https://github.com/ocaml/opam-repository/issues). - General queries for both the tool and the packages can be addressed on the [OCaml-platform mailing-list](http://lists.ocaml.org/listinfo/platform) and insights and evolution of OPAM internals can discussed on the [OPAM-devel mailing-list](http://lists.ocaml.org/listinfo/opam-devel). - You may also try IRC channel `#opam` on Freenode. --- #### 🐫 How to link to libraries installed with OPAM ? The standard way of doing this is to use [ocamlfind](http://opam.ocaml.org/packages/ocamlfind/ocamlfind.1.5.1/), which is orthogonal to OPAM: `ocamlfind query `. Your libraries are installed to the directory returned by ``opam config var lib``, which is by default `~/.opam//lib`. Note that using `ocamlc`'s option `-I +dir` will make `dir` relative to `lib/ocaml`, and will only work for the libraries that ship with the compiler. Also, remember to add the dependency when you package your project ! --- #### 🐫 How does OPAM tell which version of a package is newer ? We use the basics of the [version ordering](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version) from Debian: - version strings are sliced into alternate, possibly empty non-digit / digit sequences, always starting with a non-digit sequence. - those are sorted lexicographically, using resp. ASCII (with symbol > letter) and number order. For example `a` gives `["a"]`, and `1` gives `["";1]`, so `a` is latest (`"" < "a"`). - the `~` character is special as it sorts even before the end of sequence. It's most convenient for pre-releases, allowing `1.0~beta` to be before `1.0`. Here is an example of an ordered sequence: `~~`, `~`, `~beta2`, `~beta10`, `0.1`, `1.0~beta`, `1.0`, `1.0-test`, `1.0.1`, `1.0.10`, `dev`, `trunk` --- #### 🐫 What does the `--jobs` option do ? It doesn't seem to enable parallel builds. It does, but at the _package_ granularity: it will only be noticeable if you build independent packages in the same command. Each package has its own build commands, and it's up to them to enable parallelism. If you are a packager, you may use the `jobs` opam variable, e.g. `make "-j%{jobs}%"`. --- #### 🐫 What is "mixed mode VC pin" ? When you pin a package to a local directory that is under version control, we used to have OPAM use the version control mechanism to synchronise the package. This turned to be often confusing, because it wouldn't "see" your latest changes until you committed them. Pinning the directory as a raw path isn't perfect either, because it makes OPAM register all files, including temporary files or build artifacts. The idea of "mixed mode", which is the default for version-control pins in OPAM 1.2.1, is to take the best of both worlds: OPAM will synchronise only files under version control, but at their current state on the filesystem. You may just need to remember to register them if you added new files (e.g. `git add`). If for some reason you want the old behaviour, use one of: * `--kind path` for raw filesystem pinning * an address of the form `vc-controlled-dir#branch`, typically `#master` * on Git you can use `#HEAD` to always get to the currently checked out branch (which used to be the default, and still is for remote gits) --- #### 🐫 OPAM wants to do reinstallations after update. Can I skip them ? OPAM registers the need to recompile packages when they had meaningful changes in the repository, to guarantee consistency and allow to propagate fixes to already installed packages ; the official repository maintainers generally don't abuse this. There is no built-in command to reset them, in purpose, but removing the file `~/.opam//reinstall` is enough to make OPAM forget about them. It's quite safe, but don't report issues if you did and your system is not up to date, obviously. --- #### 🐫 Some package installation fails with "ocamlfind: already installed" Probably the package was either installed from outside of OPAM, or uncleanly removed. You should try: ``` opam remove --force opam install ``` This will process the uninstall instructions, even if OPAM has no knowledge of the package being installed. You may also try to uninstall directly with ocamlfind, or just remove the problematic files. opam-full-1.2.2/doc/pages/Usage.md0000644000175000017500000001337012517374212015370 0ustar useruser# Using OPAM This document starts with a quick introduction, then covers most commonly-used OPAM features. If you are a developer and want to get a project packaged or change an existing package, see the step-by-step [packaging guide](Packaging.html) The full documentation is available inline, using ``` opam --help opam --help ``` This document is intended as a quicker overview, use the above to dig into the details. ## Basics ``` # ** Get started ** opam init # Initialize ~/.opam using an already installed OCaml opam init --comp 4.02.1 # Initialize with a freshly compiled OCaml 4.02.1 # ** Lookup ** opam list -a # List all available packages opam search QUERY # List packages with QUERY in their name or description opam show PACKAGE # Display information about PACKAGE # ** Install ** opam install PACKAGE # Download, build and install the latest version of PACKAGE # and all its dependencies # ** Upgrade ** opam update # Update the packages database opam upgrade # Bring everything to the latest version possible # ** More ** opam CMD --help # Command-specific manpage ``` You may prefer to [browse packages online](https://opam.ocaml.org/packages). If you find a package there but not on your computer, either it has been recently added and you should simply run `opam update`, or it's not available on your system or OCaml version -- `opam install PACKAGE` will give you the reason. ## Details on commands ### opam init OPAM needs to initialize its internal state in a `~/.opam` directory to work. This command can also take care of installing a version of OCaml there if needed, using the `--comp VERSION` option. To operate as expected, some variables need to be set in your environment. You will be prompted to update your configuration, and given instructions on how to proceed manually if you decline. ### opam update This command synchronizes OPAM's database with the package repositories. The lists of available packages and their details are stored into `~/.opam/repo/`. Remember to run this regularly if you want to keep up-to-date, or if you are having trouble with a package. ### Looking up packages There are three useful commands for that: * `opam list` List installed packages, or packages matching a pattern * `opam search` Search in package descriptions * `opam show` Print details on a given package. ### opam install This command installs packages along with all their dependencies. You can specify one or several packages, along with version constraints. E.g: ``` opam install lwt opam install ocp-indent ocp-index.1.0.2 opam install "ocamlfind>=1.4.0" ``` ### opam upgrade Will attempt to upgrade the installed packages to their newest versions. You should run it after `opam update`, and may use `opam pin` to prevent specific packages from being upgraded. ### opam switch This command enables the user to have several installations on disk, each with their own prefix, set of installed packages, and OCaml version. Use cases include having to work or test with different OCaml versions, keeping separate development environments for specific projects, etc. Use `opam switch ` to _switch_ to a different OCaml version, or `opam switch --alias-of ` to name the new _switch_ as you like. Don't forget to run the advertised `eval $(opam config env)` to update your PATH accordingly. Creating a new switch requires re-compiling OCaml, unless you make it an alias of the "system" switch, relying on the global OCaml installation. There are a bunch of specific or experimental OCaml compiler definitions on the official repository, list them all with `opam switch list --all`. ### opam pin This command allows to pin a package to a specific version, but in fact, as you know if you've read the [Packaging guide](Packaging.html), it can do much more. The syntax is ``` opam pin add ``` Where `` may be a version, but also a local path, an http address or even a git, mercurial or darcs URL. The package will be kept up-to-date with its origin on `opam update` and when explicitly mentioned in a command, so that you can simply run `opam upgrade ` to re-compile it from its upstream. If the upstream includes OPAM metadata, that will be used as well. ``` opam pin add camlpdf 1.7 # version pin opam pin add camlpdf ~/src/camlpdf # path opam pin add opam-lib https://github.com/ocaml/opam.git#1.2 # specific branch or commit opam pin add opam-lib --dev-repo # upstream repository ``` This can be used in conjunction with `opam source` to start and hack an existing package before you know it: ``` opam source --dev-repo --pin cd ; hack hack hack; opam upgrade ``` ### opam repo OPAM is configured by default to use the community's software repository at [opam.ocaml.org](https://opam.ocaml.org), but this can easily be changed at `opam init` time or later. `opam repo add
` will make OPAM use the definitions of any package versions defined at `
`, falling back to the previously defined repositories for those which aren't defined. The `
` may point to an http, local or version-controlled repository. Defining your own repository, either locally or online, is quite easy: you can start off by cloning [the official repository](https://github.com/ocaml/opam-repository) if you intend it as a replacement, or just create a new directory with `packages` and `compilers` sub-directories. See the [packaging guide](Packaging.html) if you need help on the package format. If your repository is going to be served over HTTP, you should generate an index using the `opam-admin` tool. opam-full-1.2.2/doc/pages/About.md0000644000175000017500000000446512517374212015403 0ustar useruser# OPAM ### Why OPAM ? [OCamlPro](http://www.ocamlpro.com/) has decided to start writing a brand new package manager for [OCaml](http://www.ocaml.org) in the beginning of 2012, after looking at the state of affairs in the OCaml community and not being completely satisfied with the existing solutions, especially regarding the management of dependency constraints between packages. Existing technologies such as [GODI](http://godi.camlcity.org/), [oasis](http://oasis.forge.ocamlcore.org/), [odb](http://oasis.ocamlcore.org/dev/odb/) and [ocamlbrew](https://github.com/hcarty/ocamlbrew) did contain lots of good ideas that have been shamelessly stolen but the final user-experience was not so great -- and due to disagreements with some of the architectural choices done in these tools, so it wasn't so easy to contribute to fix the existing flaws. Thus OCamlPro started to discuss the specification of a new package manager with folks from [Jane Street](http://www.janestreet.com/) who decided to fund the project and from the [Mancoosi project](http://www.mancoosi.org/) to integrate state-of-the-art dependency management technologies. After few months of hard-work, and continuous support and resources from [OCamlLabs](http://www.cl.cam.ac.uk/projects/ocamllabs/) and [INRIA](http://www.inria.fr/) (through funding by the [Feder DORM](http://zenika.github.io/DORM/) project), this effort finally gave birth to the [first official release](http://www.ocamlpro.com/blog/2013/03/14/opam-1.0.0.html) of OPAM in March 2013. ### Getting Support OPAM has been created and is maintained by [OCamlPro](http://www.ocamlpro.com/). Bug reports and feature requests for the OPAM tool should be reported on [OPAM's issue-tracker](https://github.com/ocaml/opam/issues). Packaging issues or requests for a new package can be reported on the [official repository's issue-tracker](https://github.com/ocaml/opam-repository/issues). General queries for both the tool and the packages could be addressed on the [OCaml-platform mailing-list](http://lists.ocaml.org/listinfo/platform) and insights and evolution of OPAM internals can discussed on the [OPAM-devel mailing-list](http://lists.ocaml.org/listinfo/opam-devel). Standard commercial terms and support on OPAM, as well as training and consulting services, are provided by [OCamlPro](http://www.ocamlpro.com/). opam-full-1.2.2/doc/pages/index.menu0000644000175000017500000000044512517374212015776 0ustar useruser# Contains the documentation menu with the following syntax: # without extension -> A menu title # .md -> A markdown page # empty -> A menu divider OPAM 1.2 DOCUMENTATION Install.md Usage.md FAQ.md Tricks.md Packaging.md Specifying_Solver_Preferences.md Manual.md opam-full-1.2.2/doc/pages/Install.md0000644000175000017500000001556212517374212015737 0ustar useruser> NOTE: 1.2.1 is just being released. It may take a few days before binary > distributions catch up # How to install OPAM This page describes how to install and configure OPAM. For further help on how to use OPAM, either read `opam --help` or move on to the [Basic Usage](Usage.html) guide. ## Upgrading from a previous version Generally, you should just reproduce the same installation steps as for the original installation: upgrade from your system's package manager, or re-run the binary installer. OPAM will automatically update its internal repository at `~/.opam` on first run if needed (backup that if you may want to rollback the upgrade without starting over). ## Using your distribution's package system This is the recommended way, when available. Here is a list of supported distributions: #### Archlinux The [opam](http://aur.archlinux.org/packages.php?ID=62127) and [opam-git](http://aur.archlinux.org/packages.php?ID=62387) packages are available in the [AUR](https://wiki.archlinux.org/index.php/AUR). Replace `opam` with `opam-git` in the following instruction to get the development version: ``` yaourt -S opam ``` #### Debian Binary packages of OPAM are available for the [testing](http://packages.debian.org/jessie/opam) and [unstable](http://packages.debian.org/sid/opam) distributions, from the official repositories. You should be set with: ``` apt-get install opam ``` There are also unofficial packages from the [OpenSUSE Build Service](http://software.opensuse.org/download.html?project=home%3Aocaml&package=opam), for wheezy users or if the latest version isn't yet in the official repository: ``` wget http://download.opensuse.org/repositories/home:ocaml/Debian_7.0/Release.key apt-key add - < Release.key echo 'deb http://download.opensuse.org/repositories/home:/ocaml/Debian_7.0/ /' >> /etc/apt/sources.list.d/opam.list apt-get update ``` #### [Exherbo](http://exherbo.org) The [`dev-ocaml/opam`](http://git.exherbo.org/summer/packages/dev-ocaml/opam/index.html) package can be installed with the command: ``` cave resolve -x dev-ocaml/opam ``` You might need to add the `::ocaml-unofficial` repository first: ``` cave resolve -x repository/ocaml-unofficial ``` #### [Fedora](http://fedoraproject.org), [CentOS](http://centos.org) and RHEL RPMs for Fedora, CentOS and Red Hat Enterprise Linux are available with instructions on the [OpenSUSE Build Server](http://software.opensuse.org/download.html?project=home%3Aocaml&package=opam). #### Mageia The opam package for Mageia can be installed with the command: ``` urpmi opam ``` #### OpenBSD OPAM builds via sources fine on OpenBSD 5.6 or earlier, and is available in the ports and packages tree on OpenBSD 5.7 or higher. ``` cd /usr/ports/sysutils/opam make install ``` Note that the `aspcud` external solver is not yet available on OpenBSD, so you may see some odd upgrade attempts due to the use of the internal solver. #### OSX OPAM packages for [homebrew](http://mxcl.github.com/homebrew/) and [MacPorts](http://www.macports.org/) are available: ``` brew install opam # Homebrew, OSX Mavericks or later brew install opam --without-aspcud # Homebrew, OSX Mountain Lion or lower port install opam # MacPort ``` See also [howto setup Emacs.app](https://github.com/ocaml/opam/wiki/Setup-Emacs.app-on-macosx-for-opam-usage) for OPAM usage. #### Ubuntu > **Warning**: although there is an OPAM package available officially in > "**Utopic**" (14.10), it's currently broken. Don't use it, see the > [bug report](https://bugs.launchpad.net/ubuntu/+source/opam/+bug/1401346). > The Ubuntu "Vivid" (15.04) package is fine. We provide binary package for "Precise" and "Trusty" ``` add-apt-repository ppa:avsm/ppa apt-get update apt-get install ocaml ocaml-native-compilers camlp4-extra opam ``` There are also PPAs available that are [pinned to specific revisions](http://launchpad.net/~avsm) of OCaml and OPAM -- we use them for our [automated testing](http://anil.recoil.org/2013/09/30/travis-and-ocaml.html). If the command `add-apt-repository` is not available, you can install the package `software-properties-common` with `apt-get install software-properties-common`. Alternatively, you may manually edit the file `/etc/apt/sources.list` to add the PPA for your Ubuntu release. ## Binary installer Pre-compiled versions for most common architectures and OSes are available on [the Github "releases" page](https://github.com/ocaml/opam/releases/latest). We also provide a very simple installer script that will automatically download the right version for you, put it in your binary directory and initialize it. Download [opam_installer.sh](https://raw.github.com/ocaml/opam/master/shell/opam_installer.sh) and run it as follows: ``` sh /opam_installer.sh /usr/local/bin ``` You can also specify which version of OCaml you want to install: ``` sh ./opam_installer.sh /usr/local/bin 3.12.1 # Install the latest OPAM and OCaml 3.12.1 sh ./opam_installer.sh /usr/local/bin system # Install the latest OPAM using the system compiler (if any) ``` Note that this only gives you the basic `opam` command, not other binaries like `opam-admin`. You can install those through OPAM afterwards. ## From Sources #### Getting the Sources Sources of the latest stable version of OPAM are available on Github: * [OPAM releases on Github](https://github.com/ocaml/opam/releases) You can also download the full archives, including OPAM dependencies (these don't require any extra downloads, just the OCaml compiler -- 3.12.1 or later): * [1.2.1](https://github.com/ocaml/opam/releases/download/1.2.1/opam-full-1.2.1.tar.gz) MD5: 04e8823a099ab631943952e4c2ab18fc SHA1: 189e309ee0659723abaaad5f887f5caf89b34422 * [1.2.0](https://github.com/ocaml/opam/releases/download/1.2.0/opam-full-1.2.0.tar.gz) MD5 (opam-full-1.2.0.tar.gz) = 17cc252c6c80fc503c4878eac8d123e7 * [1.1.2](https://github.com/ocaml/opam/releases/download/1.1.2/opam-full-1.1.2.tar.gz) MD5 (opam-full-1.1.2.tar.gz) = ba2a4136b65003c04d905de786f3c3ab * [1.1.1](https://github.com/ocaml/opam/releases/download/1.1.1/opam-full-1.1.1.tar.gz) MD5 (opam-full-1.1.1.tar.gz) = a7bebe947b3e6c1c10ccafabb839d374 * [1.1.0](http://www.ocamlpro.com/pub/opam-full-1.1.0.tar.gz) MD5 (opam-full-1.1.0.tar.gz) = d6e2f56b10c0be73b5677963e6659d24 Follow the instructions in the included [`README.md`](https://github.com/ocaml/opam#readme) to get OPAM built and installed from there. #### Using ocamlbrew [ocamlbrew](https://github.com/hcarty/ocamlbrew) is a script that can bootstrap an OCaml environment including OPAM, from source. This option does not require an existing OCaml installation, or a pre-compiled OPAM binary for your platform. To bootstrap a new OCaml environment including OPAM, make sure that you have the necessary pre-requisites installed to run ocamlbrew, and then run: ``` curl -kL https://raw.github.com/hcarty/ocamlbrew/master/ocamlbrew-install | env OCAMLBREW_FLAGS="-r" bash ``` opam-full-1.2.2/doc/pages/Manual.md0000644000175000017500000007232012517374212015541 0ustar useruser# The OPAM manual This manual gathers reference information on OPAM and its file formats. It is primarily of use for packagers, package maintainers and repository maintainers. * For simple usage of OPAM, see the [Usage](Usage.html) page, and the comprehensive built-in documentation `opam [command] --help`. * For a gentler introduction to packaging, see the [Packaging guide](Packaging.html) * For a more complete specification, and if you are interested in more details on the layout of `~/.opam`, you may want to check the [OPAM Developer's Manual](http://opam.ocaml.org/doc/manual/dev-manual.html) This version of the manual documents the version `1.2` of the file formats, with some `1.2.1` experimental extensions mentionned. ## General file format ### General syntax The OPAM file formats share a common base syntax. The files are utf8 encoded and made of a list of fields in the form `: `. Available field names are specific to each specific file format, and each of them only allows values of a certain format. Base values can be literal booleans, integers or strings, identifiers, and operators. Strings allow the escapes `\\`, `\n`, `\r`, `\b`, `\t`, as well as three-digit decimal and two-digit hexadecimal character codes (`\NNN` and `\xNN`), and escaped newlines. Lists must be enclosed in square brackets unless they contain a single element. Values can be followed by an argument in braces. Parentheses may be used to group sub-expressions.
type format example
bool true|false true
int -?[0-9]+ 42
string "..." "a string"
ident [a-zA-Z_][a-zA-Z0-9:_+-]* foo
operator [!=<>|&+:]+ >=
list <value> or [ <value> <value> ... ] [ foo "bar" ]
option <value> or <value> { <value> <value> ... } foo { > "0" }
parens (<value>) (foo & bar)
Comments may be either enclosed in `(*` and `*)`, or `#` and newline. They are ignored by OPAM. ### Package Formulas Both package names and versions are encoded as strings. Formulas allow to specify conditions on installed packages. They are logic formulas using the operators `&` and `|` for AND and OR, over package names: ``` ("neat_package" | "also_neat_package") & "required_package" ``` Package names can be suffixed with _version constraints_, which restricts the requirement further. Version constraints have the form ` ` and can be combined with binary AND `&` and OR `|`, and prefix NOT `!`. The allowed relational operators are `=`, `!=`, `<`, `<=`, `>` and `>=`, and their meaning is defined by Version Ordering. > **Version Ordering** follows the basics of the > [Debian definition](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version): > > - version strings are sliced into alternate, possibly empty non-digit / digit > sequences, always starting with a non-digit sequence. > - those are sorted lexicographically, using resp. ASCII (with symbol > letter) > and number order. For example `a` gives `["a"]`, and `1` gives `["";1]`, so > `a` is latest (`"" < "a"`). > - the `~` character is special as it sorts even before the end of sequence. > It's most convenient for pre-releases, allowing `1.0~beta` to be before > `1.0`. > > Here is an example of an ordered sequence: `~~`, `~`, `~beta2`, `~beta10`, > `0.1`, `1.0~beta`, `1.0`, `1.0-test`, `1.0.1`, `1.0.10`, `dev`, `trunk` Here is a full example: ``` "foo" { >= "3.12" } & ("bar" | "baz" { !(> "2" & < "3.5") & != "5.1" }) ``` ### Variables #### Usage Variables may appear at a few different places in OPAM files and configuration. They can be used in two forms: - raw idents: `foo < bar` - within strings, using _interpolation_, when enclosed in `%{` and `}%`: `"%{foo}%/bar"` For both forms, and within values that allow them, the variables are replaced by their contents, if any, just before the value is used. Variable contents can be either _strings_, _booleans_ or _undefined_, and automatic conversion may take place using the strings `"true"` and `"false"` (leading to an _undefined_ bool when converting from any other string). Undefined values are propagated through boolean expressions, and lead otherwise to context-dependent default values (the empty string and `false`, unless specified otherwise). > **1.2.1 experimental feature**: boolean-to-string conversion specifiers > > In 1.2.1, the additional syntax > `"%{var?string-if-true:string-if-false-or-undefined}%"` can be used to insert > different strings depending on the boolean value of a variable. This is not > allowed yet in the main repository. Additionally, boolean package variables may be combined using the following form: `name1+name2+name3:var` is the conjunction of `var` for each of `name1`, `name2` and `name3`, _i.e_ it is equivalent to `name1:var & name2:var & name3:var` #### Scopes The defined variables depend on the specific fields being defined. There are three scopes: 1. Global variables correspond to the general current configuration (system setup, OPAM configuration, current switch, etc.). For example `opam-version`, `arch`, or `make`. 2. Package variables have the form `package-name:var-name` and contain values specific to a given package, e.g. `foo:installed` is a boolean variable that can be used to check if package `foo` is installed, `foo:lib` is its library installation directory. The prefix `package-name:` can be omitted within the package's own OPAM file (when not shadowed by another variable), in which case the variables will relate to the version of the package being defined. Otherwise, the installed version is always used, and most variables will be undefined when the package isn't installed. 3. Some fields define their own local variables, like `success` in the field `post-messages` For a comprehensive list of predefined variables, and their current local values, run: ``` opam config list ``` ### Filters "Filters" are formulas based on variables. Their main use is as optional conditions to commands or command arguments, using the postfix-braces syntax: ``` [ "./configure" "--use-foo" {foo:installed} ] ``` In build instructions, this adds the `"--use-foo"` argument only when variable `foo:installed` is `true`. This is evaluated just when the command is going to be run. Filters and package formulas have a different scope and should not be mistaken: - Package formulas are over constant _packages_ and _versions_ and can not refer to variables - Filters are over _variables_, and can't refer to packages directly - Package formulas denote abstract requirements, they're independent from any given setup. They are solved, not evaluated - Filters evaluate at a precise moment in time, in a given setup, to return a value. The following are allowed in filters: - String and boolean literals - Idents - Parens - Logical operators (binary AND `&`, binary OR `|`, prefix, unary NOT `!`) - Binary relational operators (`=`, `!=`, `<`, `<=`, `>`, `>=`) The comparisons are done using Version Order. Relational operators have a higher precedence than logical operators. Undefined values are propagated through relational operators, and logical operators unless absorbed (`undef & false` is `false`, `undef | true` is `true`). ### Interpolation Some files can be rewritten using variable interpolation expansion: when looking for `file` when this is available, if `file.in` is found, any `%{var}%` interpolations found in it are replaced by the contents of `var` and the results are written back to `file`. This can also be done explicitly using the command `opam config subst "file"`. ### Environment updates Some fields define updates to environment variables in the form: ``` ``` The allowed update operators `update-op` denote how the string is applied to the environment variable: - `=` override (or set if undefined) - `+=` prepend (or set if undefined) - `=+` append (or set if undefined) - `:=` prepend (or set to if undefined) `:` - `=:` append (or set to if undefined) `:` ### URLs URLs are provided as strings. When pointing to origins for package sources, they may be: - raw local filesystem paths - ssh addresses `user@host:path` - URLs of the form `http://`, `https://`, `ftp://`, `ssh://`, `file://`, `rsync://` - Version control URLs for git, mercurial and darcs: `git://`, `hg://`, `darcs://` - Version control bound to a specific URL: `+://`, e.g. `git://`, `hg+https://`, `git+file://`, etc. (**NOTE:** this has been added in OPAM 1.2.1) In addition, version control URLs may be suffixed with the `#` character and a reference name (branch, commit, HEAD...): `git://foo.com/git/bar#master`, `hg+file://foo.com/hg/bar#dev1` The URLs given for user information (e.g. package homepages and bugtrackers) are not concerned and should just load nice in common browsers. ## Repository format A repository is a target that can be pointed to by the `opam repository add` command and provides metadata (and possibly archives) to OPAM. ### Layout An OPAM repository is a directory structure containing the following elements: - a `packages/` sub-directory, holding all package definitions - a `compilers/` sub-directory, holding the compilers definitions (used by `opam init` and `opam switch`) - a `repo` file with some metadata on the repository itself - an `archives/` subdirectory that may hold source archives for the packages - possibly `index.tar.gz` and `urls.txt` files, when serving over HTTP. All of them are optional, although the `repo` file is recommended if the repo isn't for purely local use. The packages definitions are held in `package-name.package-version` directories below `packages/`, at any depth. The convention on the official repository is to have a directory per package name, gathering all versions, as such: `packages/package-name/package-name.package-version/`. If the directory listing gets too large in the future, it may be split into sub-directories by prefix (e.g. `packages/p/pa/package-name/package-name.version`). The compiler definitions are held in directories below `compilers/`, at any depth. The convention is to place them in separate sub-directories depending on the OCaml version they are based on: They should have a name of the form `base-ocaml-version+patch` (e.g. `4.02.1+BER` for the `BER` compiler), and be placed in a directory `compilers/base-ocaml-version/base-ocaml-version+patch/`. For the official OCaml releases, the `+patch` suffix is omitted. ### Repo specification The `repo` file, placed at the root of a repository, has the following optional fields: * `opam-version: `: File format and repository format version, should be `1.2` as of writing. * `browse: `: An URL where the users may browse available packages online * `upstream: `: The source that this repo is generated and maintained from. Typically, a version-control system address. * `redirect: [ { } ... ]`: List of URLs to (permanently) redirect to if their filters evaluate to `true`. Can be used to serve different repositories for different OSes or different versions of OPAM. ### Indexes and serving over HTTP(S) Browsing a large tree hierarchy over HTTP is unpractical. If the repository is to be served over HTTP, the `opam-admin` tool bundled with OPAM needs to be used to generate digests of all files in the repository, as well as a compressed archive: ``` opam-admin make --index ``` should be run at each repository update, and will generate the `urls.txt` and `index.tar.gz` files at the root of the repository. Additionally, if the `--index` option is omitted, **all** package archives listed in **all** packages that aren't present already will be fetched and repackaged inside the `archives/` directory, allowing direct download from the server. These are used by `opam update` even when fetching from non HTTP repositories. ### Metadata precedence When several repositories are configured in a given OPAM installation, all versions of all packages present in them are available. In case of conflict (same version of same package available in two of them), metadata from the repository configured with the highest priority is used. When pinning a package, metadata is diverted from its normal, repository source. Metadata is searched: - in a `package-name.opam/` subdirectory of the package source - in an `opam/` subdirectory of the package source - in a `package-name.opam` file at the root of the package source - in an `opam` file at the root of the package source - from the repository if no metadata subdirectory was found above, excluding the opam file is one was found above - from a template, opening an editor, if nothing was found in either the package source or the repositories. Furthermore, the metadata of pinned package is then stored within the switch (at `$(opam show --where )`), and the `opam` file can be edited through `opam pin edit` > NOTE: handling directory or files of the form `package-name.opam` is a new > feature in 1.2.1. It should only be used for source repositories that may hold > more than one OPAM package. ## Compiler specification Compilers are specified by - a file `compiler-name.descr`, similar to the package `descr` files: raw utf8 file starting with a one-line description. - a file `compiler-name.comp` specifying the source and details of the compiler. The `compiler-name.comp` file has the following fields: - `opam-version: `: File format version, should be `1.2` as of writing. - `name: `: the compiler name, should be of the form `base-version+patch`, and the same used in the filename. - `version: `: the base OCaml compiler version this is based on, e.g. `4.02.1` - `src: ` or `archive: `: as for package `url` files, the URL where the compiler source can be retrieved. Older, more specific URL fields are deprecated. - `patches: [ ... ]`: URLs of patches that will be retrieved and applied to the source from `src:` or `archive:`. - `build: [ [ { } ... ] { } ... ]`: commands that will be run from the compiler source root to build and install the compiler. - `configure: [ ... ]` and `make: [ ... ]`: alternatively, this will build using `./configure` and `make`, with the given flags (`--prefix` is automatically appended to the configure command) - `packages: [ ... ]`: these packages will be installed right after the `build:` or `make:` steps have been run. They must be self-contained (no external dependencies), and the user won't be able to change or remove them in this switch (except via explicit pinning). - `env: [ ]`: specifies environment variables updates that will be performed whenever in this switch. - `preinstalled: `: should not be set by hand, specifies that the this `.comp` file refers to an OCaml installation that lies outside of OPAM (files using this are normally auto-generated). Note that, since OPAM `1.2.1` all build instructions can be omitted, and that it is therefore possible to delegate all the build process to the packages in `packages:`. ## Package specification Metadata for a single package is made of all the following files, and should be gathered in a single directory (named `package-name.package-version` when in a repository). ### descr Descr is a simple utf8 text file -- it doesn't follow the OPAM syntactic conventions. The first line of the file is a short description of the package, suitable for displaying in package listings, and a longer description may follow on next lines. ### url The `url` file describes the source of the package and how it may be obtained. It has the following fields: - One of `src: ` or `archive: `, specifying the URL where the package can be downloaded from. When using HTTP or FTP, this should be an archive. The older alternative field names `http:`, `local:`, `git:`, `hg:` and `darcs:` are deprecated, prefer explicit URLs. On the official repository, this should always point to a stable archive over HTTP or FTP. - `checksum: `: the MD5 of the referred-to archive, to warrant integrity. Mandatory on the official repository. - `mirrors: [ ... ]`: an optional list of mirrors. They must use the same protocol as the main URL. ### files/ This subdirectory may contain any files or directories (of reasonable size) that will be copied over the root of the package source. `opam` file fields like `patches:` refer to files at that same root, so patches are typically included here. Note that repository archives generated by `opam-admin make` in `archives/` _already_ include these overlay files. #### package-name.install This file is convenient to automate package installation without resorting to external commands like `make install`. It can be included in `files/` but also at the root of the package source, or generated by the build-system. To avoid duplicating efforts for managing installations, a stand-alone `opam-installer` tool is provided that can perform installations and uninstallations from these files, without requiring OPAM. It specifies what files and compilation artefacts must be installed where. All the fields have the form ``` field: [ { } ] ``` The following take a list of filenames (relative to the root of the package source) to be installed to the field's respective directory. An optional relative path and destination filename can be given using the postfix braces syntax. A leading `?` in the origin filename is stripped and informs OPAM to continue silently when the file is not found. - `lib:` installs to `/lib/package-name` - `libexec:` installs to `/lib/package-name`, but the `exec` bit is set. - `bin:` installs to `/bin`, with the `exec` bit set - `sbin:` installs to `/sbin`, with the `exec` bit set - `toplevel:` installs to `/lib/toplevel` - `share:` installs to `/share/package-name` - `share_root:` installs relative to `/share` - `etc:` installs to `/etc/package-name` - `doc:` installs to `/doc/package-name` - `stublibs:` installs to `/lib/stublibs`, with the `exec` bit set The following are treated slightly differently: - `man:` installs relative to `/man`, with the exception that when the destination is unspecified, the proper destination directory is extracted from the extension of the source file (so that `man: [ "foo.1" ]` is equivalent to `man: [ "foo.1" {"man1/foo.1"} ]` - `misc:` requires files to specify an absolute destination, and the user will be prompted before the installation is done. ### opam The main file specifying a package's metadata. The `opam lint` command is recommended to check the validity and quality of your `opam` files. `opam` files allow the following fields: - `opam-version: ` (mandatory): the file format version, should be `1.2` as of writing. - `name: `, `version: `: the name and version of the package. Both fields are optional when they can be inferred from the directory name (e.g. when the file sits in the repository). - `maintainer: ` (mandatory): A contact address for the package maintainer (the format `"name "` is allowed). - `authors: [ ... ]`: a list of strings listing the original authors of the software. - `license: [ ... ]`: the abbreviated name(s) of the license(s) under which the source software is available. - `homepage: `, `doc: `, `bug-reports: `: URLs pointing to the related pages for the package, for user information - `dev-repo: `: the URL of the package's source repository, which may be useful for developpers: not to be mistaken with the URL file, which points to the specific packaged version. - `tags: [ ... ]`: an optional list of semantic tags used to classify the packages. The `"org:foo"` tag is reserved for packages officially distributed by organization ``foo''. Tags in the form `"flags:"` can be used to pass meaningful `flags` to OPAM: see the `flags:` field below. This is mostly intended for compatibility with earlier releases in the 1.2 branch, which will complain about unknown values in the `flags:` field. - `patches: [ { } ... ]`: a list of files relative to the project source root (often added through the `files/` metadata subdirectory). The listed patch files will be applied sequentially to the source as with the `patch` command. Variable interpolation is available, so you can specify `patches: [ "file" ]` to have the patch processed from `file.in`. Patches may be applied conditionally by adding _filters_. - `subst: [ ... ]`: a list of files relative to the project source root. These files will be generated from their `.in` counterparts, with variable interpolations expanded. - `build: [ [ { } ... ] { } ... ]`: the list of commands that will be run in order to compile the package. Each command is provided as a list of terms (a command and zero or more arguments) ; individual terms as well as full commands can be made conditional by adding filters: they will be ignored if the filter evaluates to `false` or is undefined. Variable interpolations are also evaluated. These commands will be executed in sequence, from the root of the package source. Any command is allowed, but these should write exclusively to the package's source directory, be non-interactive and perform no network i/o. All libraries, syntax extensions, binaries, platform-specific configuration and `package-name.install` files should be produced within the source directory subtree during this step. (**NOTE**: installation instructions used to be included in this step, so you may find examples of older packages that do not respect the above. This behaviour is deprecated) - `install: [ [ { } ... ] { } ... ]`: the list of commands that will be run in order to install the package. This field follows the exact same format as `build:`, but should only be used to move products of `build:` from the build directory to their final destination under the current `prefix`, and adjust some configuration files there when needed. Commands in `install:` are executed sequentially after the build is finished. These commands should only write to subdirectories of `prefix`, without altering the source directory itself. This field contains typically just `[make "install"]`. It is recommended, though, to prefer the usage of a static or generated `package-name.install` file and omit the `install:` field. - `build-doc: [ [ { } ... ] { } ... ]` and `build-test: [ [ { } ... ] { } ... ]`: the list of commands to build documentation and tests. They are processed after the build phase when documentation or tests have been requested. These follow the same specification as the `build:` field. - `remove: [ [ { } ... ] { } ... ]`: the commands used to uninstall the package. It should be the reverse operation of `install:`, and absent when `install:` is. It follows the same format as `build:`. - `depends: [ ... ]`: the package dependencies. This describes the requirements on other packages for this package to be built and installed. It contains a list of package formulas, understood as a conjunction. As an addition to the package formula format, the version constraints may be prefixed by _dependency flags_. These are one of `build`, `test` and `doc` and limit the meaning of the dependency: * `build` dependencies are no longer needed at run-time: they won't trigger recompilations of your package. * `test` dependencies are only needed when building tests (_i.e._ by instructions in the `build-test` field) * likewise, `doc` dependecies are only required when building the package documentation Dependency flags must be first, and linked by `&`: depends: [ "foo" {build} "bar" {build & doc} "baz" {build & >= "3.14"} ] - `depopts: [ { } ... ]`: the package optional dependencies. This flag is similar to `depends:` in format, but with some restrictions. It contains packages that will be _used_, if present, by the package being defined, either during build or runtime, but that are not _required_ for its installation. The implementation uses this information to define build order and trigger recompilations, but won't automatically install _depopts_ when installing the package. The optional dependencies may have _dependency flags_, but they may not specify version constraints nor formulas. `depopts:` can be combined with `conflicts:` to add version constraints on the optional dependencies. - `conflicts: [ { } ... ]`: a list of package names with optional version constraints indicating that the current package can't coexist with those. - `depexts: [ [ [ ... ] [ ... ] ] ... ]`: the package external dependencies. This field is a list that can be used for describing the dependencies of the package toward software or packages external to the OPAM ecosystem, for various systems. It contains pairs of lists of the form `[ predicates ext-packages ]`. `predicates` is used to select the element of the list based on the current system: it is a list of tags (strings) that can correspond to the OS, architecture or distribution. The `predicates` is used as a conjunction: the pair will only be selected when _all_ tags are active. The resulting `ext-packages` should be identifiers of packages recognised by the system's package manager. There is currently no definite specification for the precise tags you should use, but the closest thing is the [opam-depext project](https://github.com/OCamlPro/opam-depext). The `depexts` information can be retrieved through the `opam list --external` command. - `messages: [ { } ... ]`: used to display an additional (one-line) message when prompting a solution implying the given package. The typical use-case is to tell the user that some functionality will not be available as some optional dependencies are not installed. - `post-messages: [ { } ... ]`: allows to print specific messages to the user after the end of installation. The special boolean variable `failure` is defined in the scope of the filter, and can be used to print messages in case there was an error (typically, a hint on how it can be resolved, or a link to an open issue). `success` is also defined as syntactic sugar for `!failure`. - `available: [ ]`: can be used to add constraints on the OS and OCaml versions currently in use, using the built-in `os` and `ocaml-version` variables. In case the filter is not valid, the package is disabled. The `os` and `ocaml-version` fields are deprecated, please use `available` instead in newly created packages. This field is evaluated before request solving or any actions take place ; it can only refer to global variables, since it shouldn't depend on the current switch state. An unavailable package won't generally be seen on the system, except with `opam list -A`. - `flags: [ ... ]`: specify package flags that may alter package behaviour. Currently available flags are: - `light-uninstall`: the package's uninstall instructions don't require the package source. This is currently inferred when the only uninstall instructions have the form `ocamlfind remove...`, but making it explicit is preferred (since OPAM 1.2.0). - `verbose`: when this is present, the stdout of the package's build and install instructions will be printed to the user (since OPAM 1.2.1). - `plugin`: the package installs a program named `opam-` and may be auto-installed and run with `opam ` (since OPAM 1.2.2 ; the use is discouraged in the 1.2 branch for compatibility, use `tag: "flags:plugin"` instead) - `features: [ { } ... ]` (EXPERIMENTAL): this field is currently experimental and shouldn't be used on the main package repository. It allows to define custom variables that better document what _features_ are available in a given package build. Each feature is defined as an identifier, a documentation string, and a filter expression. The filter expression can evaluate to either a boolean or a string, and the defined identifier can be used as a variable in any filter (but recursive features are not allowed and will be _undefined_). This is typically useful to pass appropriate flags to `./configure` scripts, depending on what is installed. opam-full-1.2.2/doc/pages/Packaging.md0000644000175000017500000003174412517374212016215 0ustar useruser## Tl;dr Create a local package from the current directory ``` $ opam pin add . ``` Get a local copy of an existing package and install from there ``` $ opam source --pin ``` Get it back to normal ``` $ opam pin remove ``` Publish to the OPAM repository: * Use the [opam-publish](https://github.com/OCamlPro/opam-publish#opam-publish) tool (`opam install opam-publish`) * Or by hand: - Fork [https://github.com/ocaml/opam-repository]() - Add your `opam`, `descr` and `url` files to `packages//.` - File a [pull-request](https://github.com/ocaml/opam-repository/compare/) # Creating OPAM packages An OPAM package is basically a bunch of data about a software project: * A name, version and description * Some dependencies and constraints on other packages, compiler versions, etc. * Build, install and remove instructions * Some additional information (bugtracker, homepage, license, doc...) This document will go through a simple way to get it in the right format, whether you are packaging your own project or someone else's. It's not a complete guide to the opam file format. ## Creating a local package We'll be assuming that you have a working OPAM installation. If not, please first read the [install guide](Install.html). ### Get the source Let's start from the root directory of your project source, typically obtained from a version-controlled repository or from a tarball. ``` $ wget https://.../project.tar.gz && tar xvzf project.tar.gz # Or $ git clone git://.../project.git ... $ cd project ``` ### Opam pin OPAM 1.2 provides a feature that allows you to register packages locally, without the need for them to exist in a repository. We call this __pinning__, because it is an extension of the very common feature that allows to __pin__ a package to a specific version number in other package managers. So let's create a package __pinned__ to the current directory. We just need to choose a name and issue the command: ``` $ opam pin add . -n ``` (`-n` tells OPAM to not try and install just yet, we'll get to it later) ### The "opam" file At this stage, OPAM will be looking for metadata for the package ``, on its repository and in the source directory. Not finding any, it will open an editor with a pre-filled template for your package's `opam` file. It's best to keep the project's `README` file open at this stage, as it should contain the information we're interested in, only in a less normalised format. ``` opam-version: "1.2" name: "project" version: "0.1" maintainer: "Name " author: "Name " homepage: "" bug-reports: "" license: "" dev-repo: "" build: [ ["./configure" "--prefix=%{prefix}%"] [make] ] install: [make "install"] remove: ["ocamlfind" "remove" "project"] depends: "ocamlfind" ``` The `opam-version`, `maintainer` and `version` fields are mandatory ; you should remove the others rather than leave them empty. * You'll probably be the `maintainer` for now, so give a way to contact you in case your package needs maintenance. * Most interesting is the `build` field, that tells OPAM how to compile the project. Each element of the list is a single command in square brackets, containing arguments either as a string (`"./configure"`) or a variable name (`make`, defined by default to point at the chosen "make" command -- think `$(MAKE)` in Makefiles). `%{prefix}%` is another syntax to replace variables within strings. `opam config list` will give you the list of available variables. * `install` is similar to `build`, but tells OPAM how to install. This is indeed `install: [ [make "install"] ]`, but the extra square brackets are optional when there is a single element, just add them if you need more than one command. * `remove` is similar to `build` and `install`, but tells OPAM how to uninstall. * `depends` should be a list of existing OPAM package names that your package relies on to build and run. You'll be guaranteed those are there when you execute the `build` instructions, and won't be changed or removed while your package is installed. A few other fields are available, but that should be enough to get started. Like `install` and `remove`, most fields may contain lists in square brackets rather than a single element: `maintainer`, `author`, `homepage`, `bug-reports`, `license` and `depends`. For the list of available fields and specification of the format, see the [OPAM manual](Manual.html#opam). One you save and quit, OPAM will syntax-check and let you edit again in case of errors. ## Installing The best test is to let OPAM attempt to install your just created package. As for any package, you do it by hand with: ``` $ opam install --verbose ``` At this point, OPAM will get a snapshot of the project, resolve its dependencies and propose a course of actions for the install. Let it go and see if your project installs successfully ; it's a good idea to use `--verbose` as it will make OPAM print the output of the externals commands, in particular the ones in the `build` instructions. You can now check that everything is installed as expected. Do also check that `opam remove ` works properly. If you need to change anything, simply do ``` $ opam pin edit ``` to get back to editing the `opam` file. Manually editing the `opam` file in your source tree also works. So far, so good ! You may have missed dependencies in case they were already installed on your system, but that will be checked automatically by the continuous integration system when you attempt to publish your package to the OPAM repository, so don't worry. ## Getting a full OPAM package There are still two things missing for a complete package. * An appealing description. * An URL where OPAM may download the project source for the release. If your project is hosted on Github, pushing `TAG` will automatically provide https://github.com/me/project/archive/TAG.tar.gz. [opam-publish](https://github.com/OCamlPro/opam-publish) is a tool that automates most of the steps to get a full package ready, reviewed and published. ### With opam-publish ``` $ opam install opam-publish $ opam-publish prepare ``` This will provide you with a `.` directory, where you'll have to write a description within the `descr` file if your package is new. Check the files in that directory, it's the full contents of what will be included in the opam repository. ### By hand * Write a cool description of your package within a simple utf-8 text file `descr`. Like for git commits, the first line is a short summary, and a longer text may follow. * Create a `url` file, with a format similar to that of `opam`: ``` archive: "https://address/of/project.1.0.tar.gz" checksum: "3ffed1987a040024076c08f4a7af9b21" ``` The checksum is a simple md5 of the archive, which you can obtain with: ``` $ curl -L "https://address/of/project.1.0.tar.gz" | md5sum ``` ## Publishing Publishing is currently handled through Github, using the pull-request mechanism. If you're not familiar with it, it is a fancy way to: * Make a patch to the OPAM repository * Propose this patch for review and integration. This will also trigger tests that your package installs successfully from scratch. Opam-publish will take care of this for you and, just requiring that you have an account on Github, direct you to the web interface where you can follow the process of integration and discuss issues with the maintainers. ### With opam-publish It's just, from the same directory as above: ``` opam-publish submit . ``` This will perform some checks on your package, and, if all goes well, you'll be redirected to the github page that will track your pull-request (automated tests, discussion with the repository maintainers, etc.). If any modifications were requested, re-running the command will automatically update the existing pull-request. ### By hand Here is how to do it from scratch: 1. Go to https://github.com/ocaml/opam-repository and hit the `Fork` button on the top right corner (you may be asked to login or register) 2. Get the `clone URL` on the right, and, from the shell, run `git clone ` to get your local copy 3. Now we'll add the new package description (`opam`, `descr` and `url` files) into `opam-repository/packages//./` and make that a git commit: ``` $ cd opam-repository/packages $ mkdir -p /. $ cp /opam /. $ cp /url /descr /. $ git add $ git commit -m "Added new fancy ." ``` 4. Sending that back to github is just a matter of running `git push` 5. Back to the web interface, refresh, hit the `Pull request` button, check your changes and confirm; 6. Wait for feedback ! ### Once you are done Don't forget to `opam pin remove ` once your project is on the repository, if you don't want to continue using your local version. Remember that as long as the package is pinned, OPAM will use the metadata found in its source if any, but otherwise only what is in the OPAM repository matters. Use `git pin list` to list all currently pinned packages. ## Some tricks * You may skip the first step and pin to a remote version-controlled repository directly, using for example ``` $ opam pin add git://github.com/me/project.git ``` * OPAM will propose to save your opam file back to your source, but if you want to take a peek at the internal version it's at `~/.opam//overlay//`. You may also check it with `opam show --raw`. * Since 1.2.1, OPAM will also use files `.opam`, or metadata found in a subdirectory `opam` or `.opam` in your source tree. This can be useful if different OPAM packages are built from the same source. * You can set OPAM to use your local clone of the repository with ``` $ opam repository add my-dev-repo path/to/opam-repository ``` Don't forget to `opam pin remove `, and test your changes to the repo directly. You'll also need to `opam update my-dev-repo` each time to keep OPAM in sync (`opam update` synches all repos, this will be faster). * Pins can also be used to try out experimental changes to a project with minimal effort: you can pin to a git repository and even to a specific branch, tag or hash by adding `#BRANCH` to the target. So say you want to try out Joe's GitHub pull-request present on his branch `new-feature` on his fork of `project`, just do ``` $ opam pin project git://github.com/Joe/project.git#new-feature ``` and OPAM will use that to get the source (and possibly updated metadata) of the package; this works with any branch of any git repo, it's not github specific. * We've been focusing on git above, but OPAM can handle darcs and mercurial repositories too, using `darcs://` and `hg://`. ## More on opam files The opam files can express much more than what was shown above. Without getting into too much details, here are some of the most useful features: * **Version constraints**: an optional version constraint can be added after any package name in `depends`: simply write `"package" {>= "3.2"}`. Warning, versions are strings too, don't forget the quotes. * **Formulas**: depends are by default a conjunction (all of them are required), but you can use the logical "and" `&` and "or" `|` operators, and even group with parentheses. The same is true for version constraints: `("pkg1" & "pkg2") | "pkg3" {>= "3.2" & != "3.7"}`. * **Build depends**: you may add the key `build` in front of the version constraints, e.g. `"package" {build & >= "3.2"}`, to indicate that there is no run-time dependency to this package: it is required but won't trigger rebuilds of your package when changed. * **OS and OCaml constraints**: The `available` field is a formula that determines your package availability based on the operating system (OS), OCaml version or other constraints. For example: ``` available: [ os != "darwin" | ocaml-version >= "4.00" ] ``` * **Conflicts**: some packages just can't coexist. The `conflicts` field is a list of packages, with optional version constraints. * **Optional dependencies**: they change the way your package builds, but are not mandatory. The `depopts` field is a simple list of package names. If you require specific versions, add a `conflicts` field with the ones that won't work. * **Variables**: you can get a list of predefined variables that you can use in your opam rules with `opam config list`. * **Filters**: full commands, or single commands arguments, may need to be omitted depending on the environment. This uses the same optional argument syntax as above, postfix curly braces, with boolean conditions: ``` ["./configure" "--with-foo" {ocaml-version > "3.12"} "--prefix=%{prefix}%"] [make "byte"] { !ocaml-native } [make "native"] { ocaml-native } ``` For more, see the [OPAM Manual](Manual.html) opam-full-1.2.2/doc/pages/Specifying_Solver_Preferences.md0000644000175000017500000002067412517374212022304 0ustar useruser# Specifying user Preferences for the External Solvers A fundamental distinguishing feature of the `opam` package manager is the fact that it is designed to reuse state-of-the-art dependency solving technology that gives the users the possibility to express their preferences regarding the operations to be performed during an installation, instead of being bound to an hard-coded strategy. This section provides basic documentation on this feature, and its usage. ## What are user preferences for installations, and why are them important? When you request the installation of some packages, say p1...pn, `opam` has a lot to do: it needs to look at all the packages already installed on your machine, find all packages available from the repositories, consider your request, and then come up with a set of actions to be performed to satisfy your request. Unfortunately, there are a lot of assumptions hidden in your mind when you tell `opam` that you want p1...pn installed: should it choose the latest version of the p1...pn? That seems a sensible thing to do, but sometimes installing a recent version of a package p may lead to downgrading or removing another package q, which is something you might not want. What should `opam` do in this case? Remove q to get the latest p, or keep q and get the most recent p that is compatible with it? Well, the answer is: it depends! It depends on what _you_ really want, and different users may have different points of view. User preferences, supported by `CUDF`-compatible solvers, are the means you can use to make the assumptions in your mind explicit and known to the solver used by `opam`, so that the actions performed on your machine correspond to your personalised needs. ## How do I express my preferences? Preferences are expressed using a simple language built by prefixing a little set of combinators with the `-` (minus) or `+` (plus) operators. The most useful combinators are the following ones: * `new` : the number of new packages * `changed` : the number of packages modified * `removed` : the number of packages removed * `notuptodate` : the number of packages that are not at their latest version For example, the preference `-removed` tells the solver that among all possible ways of satisfying your request, it should choose one that minimises the number of packages removed. These combinators can be combined in a comma separated sequence, that is treated in lexicographic order by the solver. ### Default preferences for an upgrade For example, the preference `-removed,-notuptodate,-changed` tells the solver that after ensuring that removals are minimised, it should look for a solution that minimises also the number of packages wich are not at their latest version, and then reduce the changes to a minimum. This is the default preference setting used by `opam` when you perform an update or an upgrade, and in practice it tries to bring _all_ your packages to the latest version available, as far as this does not implies removing too many packages. It can be set using the environment variable `OPAMUPGRADECRITERIA` ### Default preferences for an install When you request to install a (set of) package(s), in general you do not expect to see all your existing packages updated, and this is why in this case `opam` uses a different default value `-removed,-changed,-notuptodate` that tries to minimise changes to the system. It can be set using the environment variable `OPAMCRITERIA` ### Specifying preferences for opam Recent versions of `opam` allow to specify your criteria on the command line, using the `--criteria` option, that will apply only to the current command. For example if you are a very conservative user, you might try issueing the following command: ``` opam install --criteria="-removed,-changed" ... ``` This can also be used for some tricks: if for example you want to repair your set of installed packages, you can use the `opam upgrade` command without specifying a preference for newer versions in the criteria: ``` opam upgrade --criteria="-changed" ``` You can also use the `OPAMCRITERIA` and `OPAMUPGRADECRITERIA` environment variables to specify your preferences (for example, adding your preferred settings to a shell profile). If both variables are set, upgrades are controlled by `OPAMUPGRADECRITERIA`, while `OPAMCRITERIA` applies to all other commands. If only `OPAMCRITERIA` is set, it applies to all commands. If only `OPAMUPGRADECRITERIA` is set, it applies to upgrade commands only, while all other commands are controlled by the `opam` internal default preferences. ## Yes, there are different versions of the user preference language The `opam` package manager is an instance of the approach described in the article "[A modular package manager architecture](http://dl.acm.org/citation.cfm?id=2401012)", which was one of the outcomes of the [Mancoosi](http://www.mancoosi.org) research project. This architecture relies on external dependency solvers for package managers, that communicate with the package manager front-end via the [CUDF format](http://www.mancoosi.org/cudf/). We have now several CUDF-compatible solvers, developed by a variety of research teams during the [MISC competitions](http://www.mancoosi.org/misc/) run yearly from 2010 to 2012: * [aspcud](http://www.cs.uni-potsdam.de/wv/aspcud/) * [Mccs](http://www.i3s.unice.fr/~cpjm/misc/mccs.html) * [Packup](http://sat.inesc-id.pt/~mikolas/sw/packup/) * [P2Cudf](https://wiki.eclipse.org/Equinox/p2/CUDFResolver) Each of these competitions led to improving the preferences language, by allowing the user progressively more flexibility. As of today, the preferences language described in the previous section, which corresponds to the one used in the 2010 competition, should be supported by all external solvers, but if you happen to use as external solver one of the entrants of the 2012 competition, like recent versions of `aspcud`, then you have access to a more sophisticated set of preferences, described in [the 2012 MISC competition rules](http://www.mancoosi.org/misc-2012/criteria/). For example, you could use `-count(removed), -count(down),-sum(solution,installedsize),-notuptodate(solution),-count(changed)` to instruct a solver to minimise downgrades, and mininise the installed size, among other criteria. The `aspcud` solver supports this extended language starting from its version 1.8.0, which unfortunately is not the version shipped by default with Ubuntu precise or Debian Wheezy. ### News in aspcud 1.9.x Starting from version 1.9.0, `aspcud` adds support for three extra selectors, that are particularly useful to perform local upgrades. Here they are: * `installrequest` is the set of packages in the solution that satisfy the requirements mentioned in the install: part of a CUDF request * `upgraderequest` is the set of packages in the solution that satisfy the requirements mentioned in the upgrade: part of a CUDF request * `request` is the union of the above two Using this extended set of package selector, it is now finally possible to specify user preferences that describe optimisations to be applied only to the packages explicitly mentioned in the request. For example, `-notuptodate(request),-count(changed)` would find a solution that tries to bring all packages mentioned in the request to their latest version, while leaving all the rest as untouched as possible. And if we have added to each package a `priority` value, we could also play with preferences like `+sum(upgraderequest,priority),-count(changed)` to get the packages mentioned in the upgrade request to the version with the highest possible priority, while leaving all the rest as untouched as possible. ## Preferences only work with the external solvers For portability reasons, `opam` also embarks an ad-hoc solver module that is built by wrapping a set of heuristics around the code of the SAT-solver which is used in the [Dose Library](http://dose.gforge.inria.fr/public_html/) for detecting broken packages. This solver module has no support for user preferences, and is not able to manage correctly large package repositories: it is highly recommended that you install an external CUDF solver (`aspcud` is the one best supported today). ## Using external solvers in the Cloud Thanks to support from [Irill](http://www.irill.org/), it is now possible to use an external solver for `opam` on any platform, over the network. See the [CUDF solver farm](http://cudf-solvers.irill.org/) for instructions. The latest version of the solver is on the farm, so you can use the full preferences language with it. opam-full-1.2.2/doc/pages/Tricks.md0000644000175000017500000000463012517374212015562 0ustar useruser> The following are beyond the scope of the [FAQ](FAQ.html), but have been found > useful for specific use-cases or for advanced users. #### Simulate actions from the current switch state (for debugging) - `opam upgrade --show-actions` (stop at the action summary dialog) - `opam upgrade --dry-run` (display only) - if you really want to try out the results: * `opam switch export testing-state.export` * `opam switch tmp-testing --alias-of system` * `opam switch import testing-state.export --fake` * try actions with `--fake` (registers them in OPAM, but doesn't actually run the build/install commands) * revert to normal: `opam switch ; opam switch remove tmp-testing` - Experiment with the solver: * `opam --cudf=cudf-file` * or `opam config cudf-universe >cudf-file-1.cudf` * run e.g. aspcud with `aspcud cudf-file-1.cudf /dev/stdout CRITERIA` * `admin-scripts/cudf-debug.ml cudf-file-1.cudf` may help with conflicts --- #### Install in all switches Not supported natively at the moment, but it's being considered. Quick hack: ``` for switch in $(opam switch list -s -i); do opam install --switch $switch PACKAGE done ``` You may want to add `--yes` if you're confident. --- #### Update OPAM environment within emacs You may use the following snippet to define an `opam-env` function: ```lisp (defun opam-env () (interactive nil) (dolist (var (car (read-from-string (shell-command-to-string "opam config env --sexp")))) (setenv (car var) (cadr var)))) ``` You may want to run this at emacs startup if it doesn't inherit the proper shell environment. --- #### Easily provide a set of packages for a group of users to install The easiest way is to create a package with your prerequisites as `depends` and have them pin that. A quick way to host the file is to use a [Gist](https://gist.github.com). Create one with minimal contents and listing your packages as dependencies -- the file name **has** to be `opam`: ``` opam-version: "1.2" name: "ocaml101" version: "0.1" maintainer: "Louis Gesbert " depends: [ "menhir" { = "20140422" } "merlin" { >= "2" } "ocp-indent" "ocp-index" ] ``` Save that and get the `HTTPS clone URL`. All that is needed then is to run: ```shell $ opam pin add ocaml101 ``` Furthermore, `opam update` will then pick up any modification you made to the gist. opam-full-1.2.2/m4/0000755000175000017500000000000012532744757012466 5ustar useruseropam-full-1.2.2/m4/ax_compare_version.m40000644000175000017500000001465212517374212016607 0ustar useruser# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_compare_version.html # =========================================================================== # # SYNOPSIS # # AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # # DESCRIPTION # # This macro compares two version strings. Due to the various number of # minor-version numbers that can exist, and the fact that string # comparisons are not compatible with numeric comparisons, this is not # necessarily trivial to do in a autoconf script. This macro makes doing # these comparisons easy. # # The six basic comparisons are available, as well as checking equality # limited to a certain number of minor-version levels. # # The operator OP determines what type of comparison to do, and can be one # of: # # eq - equal (test A == B) # ne - not equal (test A != B) # le - less than or equal (test A <= B) # ge - greater than or equal (test A >= B) # lt - less than (test A < B) # gt - greater than (test A > B) # # Additionally, the eq and ne operator can have a number after it to limit # the test to that number of minor versions. # # eq0 - equal up to the length of the shorter version # ne0 - not equal up to the length of the shorter version # eqN - equal up to N sub-version levels # neN - not equal up to N sub-version levels # # When the condition is true, shell commands ACTION-IF-TRUE are run, # otherwise shell commands ACTION-IF-FALSE are run. The environment # variable 'ax_compare_version' is always set to either 'true' or 'false' # as well. # # Examples: # # AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) # AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) # # would both be true. # # AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) # AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) # # would both be false. # # AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) # # would be true because it is only comparing two minor versions. # # AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) # # would be true because it is only comparing the lesser number of minor # versions of the two values. # # Note: The characters that separate the version numbers do not matter. An # empty string is the same as version 0. OP is evaluated by autoconf, not # configure, so must be a string, not a variable. # # The author would like to acknowledge Guido Draheim whose advice about # the m4_case and m4_ifvaln functions make this macro only include the # portions necessary to perform the specific comparison specified by the # OP argument in the final configure script. # # LICENSE # # Copyright (c) 2008 Tim Toolan # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 11 dnl ######################################################################### AC_DEFUN([AX_COMPARE_VERSION], [ AC_REQUIRE([AC_PROG_AWK]) # Used to indicate true or false condition ax_compare_version=false # Convert the two version strings to be compared into a format that # allows a simple string comparison. The end result is that a version # string of the form 1.12.5-r617 will be converted to the form # 0001001200050617. In other words, each number is zero padded to four # digits, and non digits are removed. AS_VAR_PUSHDEF([A],[ax_compare_version_A]) A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` AS_VAR_PUSHDEF([B],[ax_compare_version_B]) B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ -e 's/[[^0-9]]//g'` dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary dnl # then the first line is used to determine if the condition is true. dnl # The sed right after the echo is to remove any indented white space. m4_case(m4_tolower($2), [lt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [gt],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` ], [le],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` ], [ge],[ ax_compare_version=`echo "x$A x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` ],[ dnl Split the operator from the subversion count if present. m4_bmatch(m4_substr($2,2), [0],[ # A count of zero means use the length of the shorter version. # Determine the number of characters in A and B. ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` # Set A to no more than B's length and B to no more than A's length. A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` ], [[0-9]+],[ # A count greater than zero means use only that many subversions A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` ], [.+],[ AC_WARNING( [illegal OP numeric parameter: $2]) ],[]) # Pad zeros at end of numbers to make same length. ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" B="$B`echo $A | sed 's/./0/g'`" A="$ax_compare_version_tmp_A" # Check for equality or inequality as necessary. m4_case(m4_tolower(m4_substr($2,0,2)), [eq],[ test "x$A" = "x$B" && ax_compare_version=true ], [ne],[ test "x$A" != "x$B" && ax_compare_version=true ],[ AC_WARNING([illegal OP parameter: $2]) ]) ]) AS_VAR_POPDEF([A])dnl AS_VAR_POPDEF([B])dnl dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. if test "$ax_compare_version" = "true" ; then m4_ifvaln([$4],[$4],[:])dnl m4_ifvaln([$5],[else $5])dnl fi ]) dnl AX_COMPARE_VERSION opam-full-1.2.2/m4/ocaml.m40000644000175000017500000001352512517374212014015 0ustar useruserdnl autoconf macros for OCaml dnl dnl Copyright © 2009 Richard W.M. Jones dnl Copyright © 2009 Stefano Zacchiroli dnl Copyright © 2000-2005 Olivier Andrieu dnl Copyright © 2000-2005 Jean-Christophe Filliâtre dnl Copyright © 2000-2005 Georges Mariano dnl dnl For documentation, please read the ocaml.m4 man page. AC_DEFUN([AC_PROG_OCAML], [dnl # checking for ocamlc AC_CHECK_TOOL([OCAMLC],[ocamlc],[no]) if test "$OCAMLC" != "no"; then OCAMLVERSION=`$OCAMLC -v | sed -n -e 's|.*version* *\(.*\)$|\1|p'` AC_MSG_RESULT([OCaml version is $OCAMLVERSION]) # If OCAMLLIB is set, use it if test "$OCAMLLIB" = ""; then OCAMLLIB=`$OCAMLC -where 2>/dev/null || $OCAMLC -v|tail -1|cut -d ' ' -f 4` else AC_MSG_RESULT([OCAMLLIB previously set; preserving it.]) fi AC_MSG_RESULT([OCaml library path is $OCAMLLIB]) AC_SUBST([OCAMLVERSION]) AC_SUBST([OCAMLLIB]) # checking for ocamlopt AC_CHECK_TOOL([OCAMLOPT],[ocamlopt],[no]) OCAMLBEST=byte if test "$OCAMLOPT" = "no"; then AC_MSG_WARN([Cannot find ocamlopt; bytecode compilation only.]) else TMPVERSION=`$OCAMLOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt discarded.]) OCAMLOPT=no else OCAMLBEST=opt fi fi AC_SUBST([OCAMLBEST]) # checking for ocamlc.opt AC_CHECK_TOOL([OCAMLCDOTOPT],[ocamlc.opt],[no]) if test "$OCAMLCDOTOPT" != "no"; then TMPVERSION=`$OCAMLCDOTOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlc.opt discarded.]) else OCAMLC=$OCAMLCDOTOPT fi fi # checking for ocamlopt.opt if test "$OCAMLOPT" != "no" ; then AC_CHECK_TOOL([OCAMLOPTDOTOPT],[ocamlopt.opt],[no]) if test "$OCAMLOPTDOTOPT" != "no"; then TMPVERSION=`$OCAMLOPTDOTOPT -v | sed -n -e 's|.*version* *\(.*\)$|\1|p' ` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION; ocamlopt.opt discarded.]) else OCAMLOPT=$OCAMLOPTDOTOPT fi fi fi AC_SUBST([OCAMLOPT]) fi AC_SUBST([OCAMLC]) # checking for ocaml toplevel AC_CHECK_TOOL([OCAML],[ocaml],[no]) # checking for ocamldep AC_CHECK_TOOL([OCAMLDEP],[ocamldep],[no]) # checking for ocamlmktop AC_CHECK_TOOL([OCAMLMKTOP],[ocamlmktop],[no]) # checking for ocamlmklib AC_CHECK_TOOL([OCAMLMKLIB],[ocamlmklib],[no]) # checking for ocamldoc AC_CHECK_TOOL([OCAMLDOC],[ocamldoc],[no]) # checking for ocamlbuild AC_CHECK_TOOL([OCAMLBUILD],[ocamlbuild],[no]) ]) AC_DEFUN([AC_PROG_OCAMLLEX], [dnl # checking for ocamllex AC_CHECK_TOOL([OCAMLLEX],[ocamllex],[no]) if test "$OCAMLLEX" != "no"; then AC_CHECK_TOOL([OCAMLLEXDOTOPT],[ocamllex.opt],[no]) if test "$OCAMLLEXDOTOPT" != "no"; then OCAMLLEX=$OCAMLLEXDOTOPT fi fi AC_SUBST([OCAMLLEX]) ]) AC_DEFUN([AC_PROG_OCAMLYACC], [dnl AC_CHECK_TOOL([OCAMLYACC],[ocamlyacc],[no]) AC_SUBST([OCAMLYACC]) ]) AC_DEFUN([AC_PROG_CAMLP4], [dnl AC_REQUIRE([AC_PROG_OCAML])dnl # checking for camlp4 AC_CHECK_TOOL([CAMLP4],[camlp4],[no]) if test "$CAMLP4" != "no"; then TMPVERSION=`$CAMLP4 -v 2>&1| sed -n -e 's|.*version *\(.*\)$|\1|p'` if test "$TMPVERSION" != "$OCAMLVERSION" ; then AC_MSG_RESULT([versions differs from ocamlc $TMPVERSION != $OCAMLVERSION.]) CAMLP4=no fi fi AC_SUBST([CAMLP4]) # checking for companion tools AC_CHECK_TOOL([CAMLP4O],[camlp4o],[no]) AC_CHECK_TOOL([CAMLP4OF],[camlp4of],[no]) AC_CHECK_TOOL([CAMLP4OOF],[camlp4oof],[no]) AC_CHECK_TOOL([CAMLP4ORF],[camlp4orf],[no]) AC_CHECK_TOOL([CAMLP4PROF],[camlp4prof],[no]) AC_CHECK_TOOL([CAMLP4R],[camlp4r],[no]) AC_CHECK_TOOL([CAMLP4RF],[camlp4rf],[no]) AC_SUBST([CAMLP4O]) AC_SUBST([CAMLP4OF]) AC_SUBST([CAMLP4OOF]) AC_SUBST([CAMLP4ORF]) AC_SUBST([CAMLP4PROF]) AC_SUBST([CAMLP4R]) AC_SUBST([CAMLP4RF]) ]) AC_DEFUN([AC_PROG_FINDLIB], [dnl AC_REQUIRE([AC_PROG_OCAML])dnl # checking for ocamlfind AC_CHECK_TOOL([OCAMLFIND],[ocamlfind],[no]) AC_SUBST([OCAMLFIND]) ]) dnl Thanks to Jim Meyering for working this next bit out for us. dnl XXX We should define AS_TR_SH if it's not defined already dnl (eg. for old autoconf). AC_DEFUN([AC_CHECK_OCAML_PKG], [dnl AC_REQUIRE([AC_PROG_FINDLIB])dnl AC_MSG_CHECKING([for OCaml findlib package $1]) unset found unset pkg found=no for pkg in $1 $2 ; do if $OCAMLFIND query $pkg >/dev/null 2>/dev/null; then AC_MSG_RESULT([found]) AS_TR_SH([OCAML_PKG_$1])=$pkg found=yes break fi done if test "$found" = "no" ; then AC_MSG_RESULT([not found]) AS_TR_SH([OCAML_PKG_$1])=no fi AC_SUBST(AS_TR_SH([OCAML_PKG_$1])) ]) AC_DEFUN([AC_CHECK_OCAML_MODULE], [dnl AC_MSG_CHECKING([for OCaml module $2]) cat > conftest.ml <&5 2>&5 ; then found=yes break fi done if test "$found" ; then AC_MSG_RESULT([$$1]) else AC_MSG_RESULT([not found]) $1=no fi AC_SUBST([$1]) ]) dnl XXX Cross-compiling AC_DEFUN([AC_CHECK_OCAML_WORD_SIZE], [dnl AC_REQUIRE([AC_PROG_OCAML])dnl AC_MSG_CHECKING([for OCaml compiler word size]) cat > conftest.ml < conftest.ml < & <' * remove new global variables from filters in commands, messages, 'patches', 'available' *) open OpamTypes open OpamMisc.Option.Op ;; OpamGlobals.all_parens := true;; let rewrite_constraint ~conj = (* Rewrites '!=' *) OpamFormula.map OpamFormula.(function | (`Neq,v) -> if conj then And (Atom (`Lt,v), Atom (`Gt,v)) else Or (Atom (`Lt,v), Atom (`Gt,v)) | atom -> Atom atom) ;; let vars_new_1_2 = [ "compiler"; "ocaml-native"; "ocaml-native-tools"; "ocaml-native-dynlink"; "arch" ] let filter_string = let rex = Re.(compile ( seq [ str "%{"; rep (seq [opt (char '%'); opt (char '}'); diff notnl (set "}%")]); str "}%"; ])) in Re_pcre.substitute ~rex ~subst:(fun s -> match String.sub s 2 (String.length s - 4) with | "compiler" -> "ocaml-version" | "ocaml-native" | "ocaml-native-tools" | "ocaml-native-dynlink" -> "true" | s when List.mem s vars_new_1_2 -> "" | s when String.contains s '?' -> (* new if/else printers: use default *) (try let i = String.rindex s ':' + 1 in String.sub s i (String.length s - i) with Not_found -> s) | _ -> s ) let rec filter_vars = function | FIdent ([],i,None) when List.mem (OpamVariable.to_string i) vars_new_1_2 -> None | FString s -> Some (FString (filter_string s)) | FBool _ | FIdent _ as f -> Some f | FOp (f1,op,f2) -> (match filter_vars f1, filter_vars f2 with | Some f1, Some f2 -> Some (FOp (f1, op, f2)) | _ -> None) | FAnd (f1,f2) -> (match filter_vars f1, filter_vars f2 with | Some f1, Some f2 -> Some (FAnd (f1, f2)) | opt, None | None, opt -> opt) | FOr (f1,f2) -> (match filter_vars f1, filter_vars f2 with | Some f1, Some f2 -> Some (FOr (f1, f2)) | opt, None | None, opt -> opt) | FNot f -> (match filter_vars f with | Some f -> Some (FNot f) | None -> None) | FUndef -> None let filter_vars_optlist ol = List.map (fun (x, filter) -> x, filter >>= filter_vars) ol let filter_args sl = OpamMisc.filter_map (fun (s, filter) -> match s with | CString s -> Some (CString (filter_string s),filter) | CIdent i when List.mem i vars_new_1_2 -> None | id -> Some (id,filter)) sl let filter_vars_commands ol = List.map (fun (args, filter) -> filter_args (filter_vars_optlist args), filter >>= filter_vars) ol let to_1_1 _ opam = let module OF = OpamFile.OPAM in if OpamVersion.compare (OF.opam_version opam) (OpamVersion.of_string "1.2") < 0 then opam else let opam = OF.with_build opam (filter_vars_commands (OF.build opam @ OF.install opam)) in let opam = OF.with_install opam [] in let opam = OF.with_flags opam [] in let opam = OF.with_dev_repo opam None in let opam = OF.with_features opam [] in let opam = OF.with_opam_version opam (OpamVersion.of_string "1.1") in let remove_ext = OpamFormula.map (fun (n, (_,cstr)) -> OpamFormula.Atom (n, ([], rewrite_constraint ~conj:false cstr))) in let opam = OF.with_depends opam (remove_ext (OF.depends opam)) in let opam = OF.with_depopts opam (remove_ext (OF.depopts opam)) in let opam = OF.with_conflicts opam (OpamFormula.map (fun (n, cstr) -> OpamFormula.Atom (n, rewrite_constraint ~conj:true cstr)) (OF.conflicts opam)) in let opam = OF.with_available opam (filter_vars (OF.available opam) +! FBool true) in let opam = OF.with_patches opam (filter_vars_optlist (OF.patches opam)) in let opam = OF.with_libraries opam [] in let opam = OF.with_syntax opam [] in let opam = OF.with_messages opam (filter_vars_optlist (OF.messages opam)) in let opam = OF.with_post_messages opam (filter_vars_optlist (OF.post_messages opam)) in opam ;; Opam_admin_top.iter_packages ~opam:to_1_1 () opam-full-1.2.2/admin-scripts/add-github-dev.ml0000755000175000017500000000156412517374212020036 0ustar useruser#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; #use "topfind";; #require "re";; let github_re = Re.compile (Re_perl.re "https?://([^/]*github.com/.*)/archive/.*");; iter_packages_gen @@ fun nv ~prefix:_ ~opam ~descr:_ ~url ~dot_install:_ -> let opam = if OpamFile.OPAM.dev_repo opam <> None then opam else match url with | None -> opam | Some u -> match OpamFile.URL.(kind u, url u) with | `http, (addr,None) when Re.execp github_re addr -> let substrings = Re.exec github_re addr in let git = Printf.sprintf "git://%s" (Re.get substrings 1) in let opam = OpamFile.OPAM.with_dev_repo opam (Some (OpamTypes.Git (git,None))) in OpamFile.OPAM.with_opam_version opam (OpamVersion.of_string "1.2") | _ -> opam in opam, `Keep, `Keep, `Keep opam-full-1.2.2/admin-scripts/cudf-debug.ml0000755000175000017500000000233612517374212017255 0ustar useruser#!/usr/bin/env opam-admin.top #directory "+../cudf";; #directory "+../dose3";; #directory "+../opam-lib";; open Opam_admin_top;; let cudf_pp cpkg = (try Cudf.lookup_package_property cpkg OpamCudf.s_source with Not_found -> Common.CudfAdd.decode cpkg.Cudf.package), (try Cudf.lookup_package_property cpkg OpamCudf.s_source_number with Not_found -> Printf.sprintf "#cudf%d" cpkg.Cudf.version), [] let _ = match Cudf_parser.load_from_file Sys.argv.(1) with | Some preamble, univ, Some req -> begin match Algo.Depsolver.check_request ~explain:true (preamble, univ, req) with | Algo.Depsolver.Unsat (Some f) -> OpamGlobals.msg "== DOSE MESSAGE ==\n"; flush stdout; Algo.Diagnostic.fprintf_human ~pp:cudf_pp Format.err_formatter f; flush stderr; begin match OpamCudf.make_conflicts univ f with | OpamTypes.Conflicts cs -> OpamGlobals.msg "== OPAM MESSAGE ==\n%s\n" (OpamCudf.string_of_conflict (fun a -> Printf.sprintf "%s unavailable" (OpamFormula.string_of_atom a)) cs) | _ -> prerr_endline "unhandled case" end | _ -> () end | _ -> OpamGlobals.error_and_exit "unsupported cudf file" opam-full-1.2.2/admin-scripts/add-build-deps.ml0000755000175000017500000000147112517374212020025 0ustar useruser#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; (* Add the "build" dependency flag to all ocamlfind depends *) let to_build = List.map OpamPackage.Name.of_string ["ocamlfind"] let addbuild (pkg, (flags, cstr) as atom) = if List.mem pkg to_build && not (List.mem OpamTypes.Depflag_Build flags) then OpamFormula.Atom (pkg, (OpamTypes.Depflag_Build::flags, cstr)) else OpamFormula.Atom atom ;; iter_packages ~opam:(fun _ opam0 -> let open OpamFile.OPAM in let opam = opam0 in let opam = with_depends opam @@ OpamFormula.map addbuild @@ depends opam in let opam = with_depopts opam @@ OpamFormula.map addbuild @@ depopts opam in let opam = if opam <> opam0 then with_opam_version opam @@ OpamVersion.of_string "1.2" else opam in opam) () opam-full-1.2.2/admin-scripts/extract_mini_repository.sh0000755000175000017500000000561712517374212022244 0ustar useruser#! /bin/sh set -e if [ $# = 0 ]; then cat < /dev/null || true done ## Convert the required compilers as packages "${SOURCE_DIR}"/compilers-to-packages.ml ## Fetch the packages and compilers archives for version in ${COMPILERS}; do opam admin make --resolve --compiler ${version} ocaml.${version} ${PACKAGES} done ## Remove the unrequired package "versions unrequired_version() { case "$1" in base-*) return 1;; *) for version in archives/* do if [ "${version}" = "archives/$1+opam.tar.gz" ]; then return 1; fi done esac return 0 } for dir in packages/*/* do if unrequired_version "${dir##packages/*/}"; then rm -r "${dir}" fi done # Remove empty directories in "packages/" for dir in packages/* do rmdir "${dir}" 2> /dev/null || true done ## Remove unrequired files rm -f .gitignore .travis-ci-install.sh .travis-ci.sh .travis.yml README.md ## Build the archive cd "${WORK_DIR}" tar czf "${TARGET_DIR}/opam-mini-repository.tar.gz" ${REPO_DIR_NAME} opam-full-1.2.2/admin-scripts/depopts_to_conflicts.ml0000755000175000017500000000535512517374212021500 0ustar useruser#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; iter_packages ~opam:(fun _ opam -> let depopts = let formula = OpamFile.OPAM.depopts opam in let names = OpamMisc.remove_duplicates @@ List.map fst @@ OpamFormula.atoms @@ OpamFormula.formula_of_extended ~filter:(fun _ -> true) @@ formula in OpamFormula.ors @@ List.rev_map (fun n -> let flags = OpamMisc.remove_duplicates @@ OpamFormula.fold_left (fun acc (name,(flags,_)) -> if name = n then flags @ acc else acc) [] formula in OpamFormula.Atom (n, (flags,OpamFormula.Empty))) names in let conflicts = (* add complement of the depopts as conflicts *) let module NM = OpamPackage.Name.Map in let depopts = (* get back a map (name => version_constraint) *) (* XXX this takes _all_ the atoms not considering con/disjunctions *) OpamFormula.fold_left (fun acc (name,(_,f)) -> try NM.add name ((OpamFormula.ors [f; NM.find name acc])) acc with Not_found -> NM.add name f acc) NM.empty (OpamFile.OPAM.depopts opam) in let neg_depopts = NM.fold (fun name f acc -> if f = OpamFormula.Empty then acc else let f = OpamFormula.(neg (fun (op,v) -> neg_relop op, v) f) in match OpamFormula.to_cnf (OpamFormula.Atom (name,f)) with | [] -> acc | [conj] -> conj @ acc | [x;y] when x = y -> x @ acc | cnf -> (* Formula is not a conjunction, we are left with no choice but to enumerate *) let f = OpamFormula.to_atom_formula @@ OpamFormula.ands @@ List.map OpamFormula.of_disjunction cnf in let conflict_packages = OpamPackage.Set.filter (fun pkg -> OpamFormula.eval (fun atom -> OpamFormula.check atom pkg) f) (OpamPackage.packages_of_name packages name) in OpamPackage.Set.fold (fun nv acc -> (OpamPackage.name nv, Some (`Eq, OpamPackage.version nv)) :: acc) conflict_packages acc) depopts [] in let conflicts = OpamFile.OPAM.conflicts opam in let add_conflicts = let c = OpamFormula.to_conjunction conflicts in List.filter (fun f -> not (List.mem f c)) neg_depopts in OpamFormula.ands (conflicts :: [OpamFormula.of_conjunction add_conflicts]) in let opam = OpamFile.OPAM.with_depopts opam depopts in let opam = OpamFile.OPAM.with_conflicts opam conflicts in opam) () ;; opam-full-1.2.2/admin-scripts/compilers-to-packages.ml0000755000175000017500000001331012517374212021433 0ustar useruser#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; (**************************************************************************) (* *) (* Copyright 2013 OCamlPro *) (* *) (* All rights reserved.This file is distributed under the terms of the *) (* GNU Lesser General Public License version 3.0 with linking *) (* exception. *) (* *) (* OPAM 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. *) (* *) (**************************************************************************) open OpamTypes open OpamProcess.Job.Op open Opam_admin_top ;; iter_compilers_gen @@ fun c ~prefix ~comp ~descr -> let version = OpamPackage.Version.of_string (OpamCompiler.to_string (OpamFile.Comp.name comp)) in let nv = OpamPackage.create (OpamPackage.Name.of_string "ocaml") version in (* OpamGlobals.msg "Processing compiler %s => package %s\n" *) (* (OpamCompiler.to_string (OpamFile.Comp.name comp)) *) (* (OpamPackage.to_string nv); *) let nofilter x = x, (None: filter option) in let build = OpamFile.Comp.( match build comp with | [] -> List.map (fun l -> nofilter (List.map nofilter l)) [ (List.map (fun s -> CString s) ("./configure" :: configure comp )) @ [ CString "-prefix"; CIdent "prefix"]; CIdent "make" :: List.map (fun s -> CString s) (make comp); [ CIdent "make"; CString "install"]; ] | cl -> cl) in let prefix = Some (OpamPackage.Name.to_string (OpamPackage.name nv)) in let patches = OpamParallel.map ~jobs:3 ~command:(fun f -> OpamFilename.download ~overwrite:true f (OpamPath.Repository.files repo prefix nv) @@| OpamFilename.basename) (OpamFile.Comp.patches comp) in let (@) f x y = f y x in let opam = let module O = OpamFile.OPAM in O.create nv |> O.with_build @ build |> O.with_maintainer @ [ "contact@ocamlpro.com" ] |> O.with_patches @ List.map nofilter patches in (match OpamFile.Comp.src comp with | None -> () | Some address -> let adr,kind = OpamTypesBase.parse_url address in let url = OpamFile.URL.create kind adr in OpamFile.URL.write (OpamPath.Repository.url repo prefix nv) url); OpamFile.OPAM.write (OpamPath.Repository.opam repo prefix nv) opam; OpamMisc.Option.iter (OpamFile.Descr.write (OpamPath.Repository.descr repo prefix nv)) descr; let comp = let module C = OpamFile.Comp in comp |> C.with_src @ None |> C.with_patches @ [] |> C.with_configure @ [] |> C.with_make @ [] |> C.with_build @ [] |> C.with_packages @ OpamFormula.( And (Atom (OpamPackage.name nv, Atom (`Eq, OpamPackage.version nv)), C.packages comp) ) in comp, `Keep ;; iter_packages ~opam:(fun nv opam -> let ocaml_version = OpamFile.OPAM.ocaml_version opam in let ocaml_version_formula, available = match ocaml_version with | None -> let available = OpamFile.OPAM.available opam in let rec aux = function | FOp (FIdent ([],var,None), op, FString v) when OpamVariable.to_string var = "ocaml-version" -> Atom (op, OpamPackage.Version.of_string v) | FNot f -> OpamFormula.neg (fun (op,v) -> OpamFormula.neg_relop op, v) (aux f) | FAnd (f1,f2) -> OpamFormula.ands [aux f1; aux f2] | FOr (f1,f2) -> OpamFormula.ors [aux f1; aux f2] | _ -> Empty in let ocaml_dep_formula = aux available in let rec aux = function | FOp (FIdent ([],var,None), op, FString v) when OpamVariable.to_string var = "ocaml-version" -> None | FNot f -> OpamMisc.Option.map (fun f -> FNot f) (aux f) | FAnd (f1,f2) -> (match aux f1, aux f2 with | Some f1, Some f2 -> Some (FAnd (f1,f2)) | None, f | f, None -> f) | FOr (f1,f2) -> (match aux f1, aux f2 with | Some f1, Some f2 -> Some (FOr (f1,f2)) | None, None -> None | None, f | f, None -> OpamGlobals.error_and_exit "Unconvertible 'available' field in %s" (OpamPackage.to_string nv)) | f -> Some f in let rem_available = OpamMisc.Option.default (FBool true) (aux available) in ocaml_dep_formula, rem_available | Some f -> OpamFormula.map (fun (op,v) -> Atom (op, OpamPackage.Version.of_string (OpamCompiler.Version.to_string v)) ) f, OpamFile.OPAM.available opam in let depends = OpamFormula.( And (Atom (OpamPackage.Name.of_string "ocaml", ([],ocaml_version_formula)), OpamFile.OPAM.depends opam) ) in let opam = OpamFile.OPAM.with_ocaml_version opam None in if OpamPackage.name_to_string nv <> "ocaml" then let opam = OpamFile.OPAM.with_depends opam depends in let opam = OpamFile.OPAM.with_available opam available in opam else opam) () (* Warning : no conversion done on the _variable_ ocaml-version *) ;; opam-full-1.2.2/admin-scripts/lint.ml0000755000175000017500000000341412517374212016214 0ustar useruser#!/usr/bin/env opam-admin.top #directory "+../opam-lib";; open Opam_admin_top;; let includes = ref [] let excludes = ref [] let short = ref false let list = ref false let usage = "Arguments:\n\ \ -s\tshort format, don't print explanations\n\ \ -l\tlist format, only print package names\n\ \ [N]\tshow only the listed warnings\n\ \ -[N]\tskip any packages that trigger any of these warnings\n\ " let () = let args = match Array.to_list Sys.argv with | _::args -> args | [] -> [] in List.iter (function | "-s" -> short := true | "-l" -> list := true | a -> try if String.length a > 0 && a.[0] = '-' then excludes := 0 - int_of_string a :: !excludes else includes := int_of_string a :: !includes with Failure _ -> OpamGlobals.msg "%s" usage; OpamGlobals.exit 2) args let () = let quiet = !short || !list in iter_packages ~quiet ~opam:(fun nv opam -> let w = OpamFile.OPAM.validate opam in if List.exists (fun (n,_,_) -> List.mem n !excludes) w then opam else let w = if !includes = [] then w else List.filter (fun (n,_,_) -> List.mem n !includes) w in if w <> [] then if !list then print_endline (OpamPackage.to_string nv) else if !short then OpamGlobals.msg "%s %s\n" (OpamPackage.to_string nv) (OpamMisc.sconcat_map " " (fun (n,k,_) -> OpamGlobals.colorise (match k with `Warning -> `yellow | `Error -> `red) (string_of_int n)) w) else OpamGlobals.msg "\r\027[KIn %s:\n%s\n" (OpamPackage.to_string nv) (OpamFile.OPAM.warns_to_string w); opam ) () opam-full-1.2.2/admin-scripts/Makefile0000644000175000017500000000024612517374212016351 0ustar useruser%: %.ml sed 's/^#.*//' $< >$*-tmp.ml ocamlfind ocamlc -package opam-lib,opam-lib.repositories -linkpkg ../src/tools/opam_admin_top.ml $*-tmp.ml -o $@ rm $*-tmp.ml opam-full-1.2.2/LICENSE0000644000175000017500000012530512517374212013145 0ustar useruserAs a special exception to the GNU Lesser General Public License, you may link, statically or dynamically, a "work that uses the Library" with a publicly distributed version of the Library to produce an executable file containing portions of the Library, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Library General Public License. By "a publicly distributed version of the Library", we mean either the unmodified Library as distributed by the copyright holder, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Library General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Lesser General Public License. GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. ------------------------------------------------------------------------ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, either version 3 of the License, or (at your option) any later version. 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . opam-full-1.2.2/appveyor.yml0000644000175000017500000000172512517374212014527 0ustar useruserplatform: - x86 environment: global: CYG_ROOT: C:/cygwin CYG_MIRROR: http://cygwin.uib.no CYG_CACHE: C:/cygwin/var/cache/setup matrix: - CYG_ARCH: x86 init: - 'echo System architecture: %PLATFORM%' install: - 'appveyor DownloadFile http://cygwin.com/setup-%CYG_ARCH%.exe -FileName setup.exe' - 'setup.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P make -P git -P gcc-core -P ocaml -P ocaml-camlp4 -P ocaml-compiler-libs -P curl -P libncurses-devel -P m4 -P unzip >NUL' - 'setup.exe -qnNdO -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" -P libmpfr-devel -P patch -P flexdll >NUL' - '%CYG_ROOT%/bin/bash -lc "cygcheck -dc cygwin"' build_script: - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && env DJDIR="workaround" ./configure && make lib-ext && make && make install"' - '%CYG_ROOT%/bin/bash -lc "opam init -y -a"' - '%CYG_ROOT%/bin/bash -lc "opam install -y -v lwt"' opam-full-1.2.2/tests/0000755000175000017500000000000012532744757013310 5ustar useruseropam-full-1.2.2/tests/README.unittest0000644000175000017500000000122012517374212016025 0ustar useruser # to create a new unit test * clean the test repository : ./init-repo.sh -c * init the test repository : ./init-repo.sh -i * load a inital scenario (this command can be invoked multiple times): ./init-repo.sh -s 1 ./init-repo.sh -s 2 * install/remove/upgrade : OPAM_ROOT=/tmp/OPAM.ROOT PATH=/tmp/OPAM.BIN:$PATH opam --yes --root /tmp/OPAM.ROOT install P4 * crearte a new expected result file in as OPAM_ROOT=/tmp/OPAM.ROOT PATH=/tmp/OPAM.BIN:$PATH \ opam --yes --root /tmp/OPAM.ROOT list > results/new-expected-result * Make sure that the result correct ! * Add a new test case in the file tests.py opam-full-1.2.2/tests/results/0000755000175000017500000000000012532744757015011 5ustar useruseropam-full-1.2.2/tests/results/install-upgrade-P20000644000175000017500000000044312517374212020273 0ustar useruserAvailable packages for system: P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies opam-full-1.2.2/tests/results/reinstall-P20000644000175000017500000000031112517374212017167 0ustar useruserAvailable packages for system: P1 1 A very useful package P2 1 An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies opam-full-1.2.2/tests/results/install-remove-P10000644000175000017500000000031112517374212020132 0ustar useruserAvailable packages for system: P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies opam-full-1.2.2/tests/results/install-P10000644000175000017500000000031112517374212016637 0ustar useruserAvailable packages for system: P1 1 A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies opam-full-1.2.2/tests/results/install-opt0000644000175000017500000000031112517374212017161 0ustar useruserAvailable packages for system: P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies opam-full-1.2.2/tests/results/README.tests0000644000175000017500000000115212517374212017015 0ustar useruser # All tests are performed in a clean repository Initial state of the repository Available packages for system: P1 -- A very useful package P2 -- An other very useful package P3 -- Testing version names P4 -- Testing transitive closure P5 -- Testing optional dependencies * install-P1 install P1 * install-P1-P2-P3-P4 install P1, P2, P3, P4 * install-remove-P1 install P1 and then remove P1 * install-upgrade-P2 install P4 and then upgrade P2 * reinstall-P2 install P2 and the re-install P2 * install_opt install P5 , install P2, remove P5, remove P2, remove P1 opam-full-1.2.2/tests/results/install-P1-P2-P3-P40000644000175000017500000000044312517374212017665 0ustar useruserAvailable packages for system: P1 1 A very useful package P2 1 An other very useful package P3 1~weird-version.test Testing version names P4 1 Testing transitive closure P5 -- Testing optional dependencies opam-full-1.2.2/tests/test-TEST.sh0000755000175000017500000000020312517374212015362 0ustar useruser#!/bin/sh if [ -f $1 ]; then . $1 fi if [ x${TEST} != x$2 ]; then echo "Error: TEST=${TEST} instead of $2" exit 2 fi opam-full-1.2.2/tests/init-repo.sh0000755000175000017500000000461712517374212015551 0ustar useruser#! /bin/sh TEST_DIR=/tmp OPAM_ROOT=$TEST_DIR/OPAM.ROOT OPAM_REPO=$TEST_DIR/OPAM.REPO BIN=$TEST_DIR/OPAM.BIN REPO=test BINARIES=opam # opam in the path should not be a requirement ENV="OCAMLRUNPARAM=b OPAMDEBUG=2 OPAM_ROOT=$OPAM_ROOT PATH=$BIN:$PATH" ENV="OCAMLRUNPARAM=b OPAM_ROOT=$OPAM_ROOT PATH=$BIN:$PATH" OPAM="$ENV opam --yes --root $OPAM_ROOT" function binaries() { mkdir -p $BIN for bin in $BINARIES; do \ cp ../_obuild/$bin/$bin.asm $BIN/$bin ; \ done } function opam_clean() { rm -rf $ARCHIVES rm -rf $OPAM_ROOT $BIN rm -rf $OPAM_REPO } function opam_init() { mkdir -p $OPAM_REPO binaries eval $OPAM init -no-base-packages $REPO $OPAM_REPO -kind rsync } function opam_upload_stage1() { cd packages eval $OPAM upload -opam P1-1.opam -descr P1-1/README -archive P1-1.tar.gz -repo $REPO eval $OPAM upload -opam P2.opam -descr P2/README -archive P2.tar.gz -repo $REPO eval $OPAM upload -opam P3.opam -descr P3/README -archive P3.tar.gz -repo $REPO eval $OPAM upload -opam P4-1.opam -descr P4/README -archive P4.tar.gz -repo $REPO eval $OPAM upload -opam P5.opam -descr P5/README -archive P5.tar.gz -repo $REPO cd - cp compilers/* $OPAM_REPO/compilers/ # update the list of available packages with the one being updated eval $OPAM update } function opam_upload_stage2() { cd packages eval $OPAM upload -opam P1-2.opam -descr P1-2/README -archive P1-2.tar.gz -repo $REPO eval $OPAM upload -opam P4-2.opam -descr P4/README -archive P4.tar.gz -repo $REPO eval $OPAM upload -opam P4-3.opam -descr P4/README -archive P4.tar.gz -repo $REPO cd - # update the list of available packages with the one being updated eval $OPAM update } function usage() { DESCRIPTION="Opam unittest init functions" cat << EOF usage: $0 options $DESCRIPTION OPTIONS: -h Show this message -v Verbose -d Debug -i Init -c Clean EOF } VERBOSE= DEBUG= INIT= CLEAN= STAGE= while getopts "vhdcis:" flag do case "$flag" in d) set -x ; DEBUG=true;; v) VERBOSE=true ;; i) INIT=true ;; s) STAGE=$OPTARG ;; c) CLEAN=true ;; h) usage ; exit 0 ;; esac # echo "$flag" $OPTIND $OPTARG done if [ -n "$INIT" ]; then opam_clean opam_init fi if [ -n "$STAGE" ]; then if [ $STAGE = "1" ]; then opam_upload_stage1 fi if [ $STAGE = "2" ]; then opam_upload_stage2 fi fi if [ -n "$CLEAN" ]; then opam_clean fi exit 0 opam-full-1.2.2/tests/tests.py0000755000175000017500000001035612517374212015020 0ustar useruser#!/usr/bin/python import unittest from subprocess import Popen, STDOUT, PIPE from subprocess import call import uuid import os,sys,time import argparse import difflib tmpdir = "/tmp/OPAM.UNITTEST" results = "results" opamcmd = "/tmp/OPAM.BIN/opam --yes --root /tmp/OPAM.ROOT" verbose=0 FNULL=open(os.devnull, "w") def diff(fromfile,tofile,verbose=0): fromdate = time.ctime(os.stat(fromfile).st_mtime) todate = time.ctime(os.stat(tofile).st_mtime) fromlines = open(fromfile, 'U').readlines() tolines = open(tofile, 'U').readlines() diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile)#, fromdate, todate) l = list(diff) if l : print "File Differences : " print ''.join(l) return False else : return True def opam(cmd, diffile=None,verbose=0): # first we exectute the action, then # we compare the output of list with # the diffile env = os.environ.copy() env['PATH'] = ':'.join(['/tmp/OPAM.BIN',env['PATH']]) env['OPAM_ROOT'] = '/tmp/OPAM.ROOT' cmd = opamcmd.split() + cmd if verbose > 1 : print "Env\nPATH=%s\nOPAM_ROOT=%s" % (env['PATH'],env['OPAM_ROOT']) print "CMD=%s" % (' '.join(cmd)) if verbose <= 1 : call(cmd, stdout=FNULL, env=env) else : call(cmd, env=env) if diffile : f = "%s/%s.opamtest" % (tmpdir,uuid.uuid1()) output = open(f,'w') call(opamcmd.split() + ["list"], stdout=output, env=env) output.close() d = diff(f,diffile,verbose) os.remove(f) return d return None def load_scenario(scenario,verbose=0): if verbose > 0 : print "Loading scenario %d" % scenario if verbose <= 1 : call(["./init-repo.sh", "-s", str(scenario)],stdout=FNULL) else : call(["./init-repo.sh", "-s", str(scenario)]) class OpamTests(unittest.TestCase): def setUp(self): if verbose > 0 : print "\nsetting up repository" call(["./init-repo.sh", "-i"], stdout=FNULL) if not os.path.exists(tmpdir): os.makedirs(tmpdir) def tearDown(self): if verbose > 0 : print "tearing down repository" call(["./init-repo.sh", "-c"], stdout=FNULL) def test_install(self): load_scenario(1,verbose) diffile="%s/install-P1" % results d = opam(["install", "P1"],diffile,verbose) self.assertTrue(d) def test_install_many(self): load_scenario(1,verbose) diffile="%s/install-P1-P2-P3-P4" % results opam(["install", "P1"]) opam(["install", "P2"]) opam(["install", "P3"]) d = opam(["install", "P4"], diffile,verbose) self.assertTrue(d) def test_remove(self): load_scenario(1,verbose) diffile="%s/install-remove-P1" % results opam(["install", "P1"]) d = opam(["remove", "P1"],diffile,verbose) self.assertTrue(d) def test_upgrade(self): load_scenario(1,verbose) diffile="%s/install-upgrade-P2" % results opam(["install", "P4"]) d = opam(["upgrade", "P2"],diffile,verbose) self.assertTrue(d) # @unittest.skip("skipping") def test_reinstall(self): load_scenario(1,verbose) diffile="%s/reinstall-P2" % results opam(["install", "P2"]) d = opam(["reinstall", "P2"],diffile,verbose) self.assertTrue(d) def test_install_opt(self): load_scenario(1,verbose) load_scenario(2,verbose) diffile="%s/install-opt" % results opam(["install", "P5"]) opam(["install", "P2"]) opam(["remove", "P5"]) opam(["remove", "P2"]) d = opam(["remove", "P1"],diffile,verbose) self.assertTrue(d) def main(): global verbose parser = argparse.ArgumentParser(description='description of you program') parser.add_argument('-v', '--verbose', action='store_true') parser.add_argument('-d', '--debug', action='store_true') args = parser.parse_args() verbosity=0 if args.verbose == True : verbose = 1 verbosity=2 if args.debug == True : verbose = 2 suite = unittest.TestLoader().loadTestsFromTestCase(OpamTests) unittest.TextTestRunner(verbosity=verbosity).run(suite) if __name__ == '__main__': main() opam-full-1.2.2/tests/compilers/0000755000175000017500000000000012532744757015305 5ustar useruseropam-full-1.2.2/tests/compilers/20.comp0000644000175000017500000000011312517374212016365 0ustar useruseropam-version: "1" version: "20" preinstalled: true env: [ [ TEST="1" ] ] opam-full-1.2.2/tests/compilers/10+a+b.comp0000644000175000017500000000015512517374212017023 0ustar useruseropam-version: "1" version: "10" preinstalled: true env: [ [ TEST="1" ] ] packages: [ "P1" "P2" "P3" "P4" ] opam-full-1.2.2/tests/packages/0000755000175000017500000000000012532744757015066 5ustar useruseropam-full-1.2.2/tests/packages/P1-2/0000755000175000017500000000000012532744757015505 5ustar useruseropam-full-1.2.2/tests/packages/P1-2/P1.install0000644000175000017500000000012012517374212017332 0ustar useruserlib: [ "_build/p1.cma" "_build/p1.cmxa" "_build/p1.a" "_build/p1.cmi" ] opam-full-1.2.2/tests/packages/P1-2/p1.ml0000644000175000017500000000007112517374212016341 0ustar useruserlet x () = failwith "the new version is not very good" opam-full-1.2.2/tests/packages/P1-2/P1.config.in0000644000175000017500000000024112517374212017542 0ustar useruserasmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: trueopam-full-1.2.2/tests/packages/P1-2/build.sh0000755000175000017500000000005212517374212017124 0ustar useruser#! /bin/sh -eu ocamlbuild p1.cma p1.cmxa opam-full-1.2.2/tests/packages/P1-2/README0000644000175000017500000000002612517374212016347 0ustar useruserA very useful package opam-full-1.2.2/tests/packages/P4-3.opam0000644000175000017500000000020212517374212016345 0ustar useruseropam-version: "1" name: "P4" version: "3" maintainer: "contact@ocamlpro.com" depends: [ "P2" "P3" ] build: [ "./build.sh" ] opam-full-1.2.2/tests/packages/P5.opam0000644000175000017500000000054212517374212016215 0ustar useruser(* API version *) opam-version: "1" name: "P5" version: "1" maintainer: "contact@ocamlpro.com" depends: [ "P1" ] depopts: [ "P2" ] build: [ [ "./build.sh" ] [ "mkdir" "-p" "%{lib}%/p5" ] [ "touch" "%{lib}%/p5/p2_present" ] {P2:installed} [ "touch" "%{lib}%/p5/p2_absent" ] {!P2:installed} ] remove: [ "rm" "-rf" "%{lib}%/p5" ] opam-full-1.2.2/tests/packages/P5/0000755000175000017500000000000012532744757015352 5ustar useruseropam-full-1.2.2/tests/packages/P5/p5.ml0000644000175000017500000000002512517374212016211 0ustar useruserlet g () = P1.x () opam-full-1.2.2/tests/packages/P5/build.sh0000755000175000017500000000027012517374212016773 0ustar useruser#! /bin/sh -eu FLAGS="-I `${OPAM} config var P1:lib`" echo "Bytecode Compilation" ocamlopt ${FLAGS} -a p5.ml -o p5.cmxa echo "Native Compilation" ocamlc ${FLAGS} -a p5.ml -o p5.cma opam-full-1.2.2/tests/packages/P5/README0000644000175000017500000000003612517374212016215 0ustar useruserTesting optional dependencies opam-full-1.2.2/tests/packages/P4-1.opam0000644000175000017500000000020212517374212016343 0ustar useruseropam-version: "1" name: "P4" version: "1" maintainer: "contact@ocamlpro.com" depends: [ "P2" "P3" ] build: [ "./build.sh" ] opam-full-1.2.2/tests/packages/P1-1.opam0000644000175000017500000000203312517374212016344 0ustar useruser(* API version *) opam-version: "1" name: "P1" # Test # Toto (* Version are arbitrary strings *) version: "1" maintainer: "contact@ocamlpro.com" (* The command to run *) build: [ [ "./build.sh" ] # HAHAH [ "this" "should" "never" "run" ] { ocaml-version > "100" } [ make "this" ocaml-version "also" ] { os = "NO" } [ "echo" "HAHA!" ] { ocaml-version = "10" } [ "echo" make share ocaml-version ] [ "this as well" { os = "myOS" } ] ] os: [ !"NO" | ( !"NO" & !"YES") ] ocaml-version: [ ="system" | ="20" | ="10" ] (* List of files to substitute env variables *) substs: [ "P1.config" ] (* Libraries *) libraries: [ "p1" ] (* External dependencies *) depexts: [ [ ["debian" "amd64"] ["foo" "bar"] ] [ ["osx" ] ["foobar"] ] ] messages: [ "I'll always bother you displaying this message" ] post-messages: [ "Thanks SO MUCH for installing this humble package" "Everything went well" {success} "Nooo, something went wrong, this makes me feel sooo sad..." {failure} ] bug-reports: "TEST.com"opam-full-1.2.2/tests/packages/P3.opam0000644000175000017500000000027612517374212016217 0ustar useruseropam-version: "1" name: "P3" version: "1~weird-version.test" maintainer: "contact@ocamlpro.com" depends: [ "P1" ] substs: [ "P3.config" ] libraries: [ "p3" "p3_bar" ] build: [ "./build.sh" ]opam-full-1.2.2/tests/packages/P2.opam0000644000175000017500000000026712517374212016216 0ustar useruseropam-version: "1" name: "P2" version: "1" maintainer: "contact@ocamlpro.com" substs: [ "config" "P2.config" ] depends: [ "P1" ] libraries: [ "p2" ] build: [ "./build.sh" ] opam-full-1.2.2/tests/packages/P4-2.opam0000644000175000017500000000023212517374212016347 0ustar useruseropam-version: "1" name: "P4" version: "2" maintainer: "contact@ocamlpro.com" depends: [ "P1" { = "1" } "P2" "P3" ] build: [ "./build.sh" ] opam-full-1.2.2/tests/packages/P4/0000755000175000017500000000000012532744757015351 5ustar useruseropam-full-1.2.2/tests/packages/P4/p4.ml0000644000175000017500000000024412517374212016212 0ustar useruserlet f = try P3_bar.f (); P1.x () with _ -> P3.z () let () = let t = try Sys.getenv "TEST" with _ -> "" in Printf.printf "TEST=%s\n%!" t opam-full-1.2.2/tests/packages/P4/build.sh0000755000175000017500000000036212517374212016774 0ustar useruser#! /bin/sh -e echo "Building P4 with ${OPAM}" LIBDIR="`${OPAM} config var lib`" COMP="-I ${LIBDIR}/P1 -I ${LIBDIR}/P2 -I ${LIBDIR}/P3" LINK="p1.cmxa p2.cmxa p3.cmxa p3_bar.cmxa" ocamlopt ${COMP} ${LINK} p4.ml -o p4.foo echo "TEST=${TEST}" opam-full-1.2.2/tests/packages/P4/_tags0000644000175000017500000000007012517374212016352 0ustar useruser<*.{byte,native}>: use_p2, use_p3 <*.ml>: use_p2, use_p3opam-full-1.2.2/tests/packages/P4/README0000644000175000017500000000003312517374212016211 0ustar useruserTesting transitive closure opam-full-1.2.2/tests/packages/P4/P4.install0000644000175000017500000000004512517374212017207 0ustar useruserbin: [ "p4.foo" { "p4" } "p4.foo" ]opam-full-1.2.2/tests/packages/P3/0000755000175000017500000000000012532744757015350 5ustar useruseropam-full-1.2.2/tests/packages/P3/p3_bar.ml0000644000175000017500000000007012517374212017031 0ustar useruserlet f () = Printf.printf "foo\n%!" let _ = P3.z () opam-full-1.2.2/tests/packages/P3/P3.install0000644000175000017500000000030212517374212017201 0ustar useruserlib: [ (* p3 *) "_build/p3.cma" "_build/p3.cmxa" "_build/p3.a" "_build/p3.cmi" (* p3_bar *) "_build/p3_bar.cma" "_build/p3_bar.cmxa" "_build/p3_bar.a" "_build/p3_bar.cmi" ] opam-full-1.2.2/tests/packages/P3/myocamlbuild.ml0000644000175000017500000000062512517374212020352 0ustar useruserlet deps = [ "P1" ] open Ocamlbuild_plugin let libdir = Ocamlbuild_pack.My_unix.run_and_open (Printf.sprintf "%s config var lib" (Unix.getenv "OPAM")) input_line let includes = Printf.sprintf "-I %s/P1 -I %s/P2" libdir libdir let add_dep p = flag ["ocaml"; "compile"] & S[Sh includes] let _ = dispatch & function | After_rules -> List.iter add_dep deps | _ -> () opam-full-1.2.2/tests/packages/P3/build.sh0000755000175000017500000000027012517374212016771 0ustar useruser#! /bin/sh -eu echo "Building P3 version ${OPAM_PACKAGE_VERSION}" if [ "x${OPAM_PACKAGE_NAME}" = "xP3" ]; then ocamlbuild p3.cma p3.cmxa p3_bar.cma p3_bar.cmxa else exit 1 fi opam-full-1.2.2/tests/packages/P3/p3.ml0000644000175000017500000000004712517374212016211 0ustar useruserlet z () = try P1.x () with _ -> 0 opam-full-1.2.2/tests/packages/P3/README0000644000175000017500000000002612517374212016212 0ustar useruserTesting version names opam-full-1.2.2/tests/packages/P3/P3.config.in0000644000175000017500000000023512517374212017412 0ustar useruserasmcomp : "-I %{lib}%/P3" bytecomp: "-I %{lib}%/P3" asmlink : "-I %{lib}%/P3 p3.cmxa p3_bar.cmxa" bytelink: "-I %{lib}%/P3 p3.cma p3_bar.cma" requires: "p1" opam-full-1.2.2/tests/packages/P1-2.opam0000644000175000017500000000026012517374212016345 0ustar useruseropam-version: "1" name: "P1" version: "2" ocaml-version: [ < "20" ] maintainer: "contact@ocamlpro.com" substs: [ "P1.config" ] libraries: [ "p1" ] build: [ "./build.sh" ] opam-full-1.2.2/tests/packages/P1-1/0000755000175000017500000000000012532744757015504 5ustar useruseropam-full-1.2.2/tests/packages/P1-1/P1.install0000644000175000017500000000031412517374212017336 0ustar useruserlib: [ "_build/p1.cmi" "_build/p1.cma" "_build/p1.cmxa" "_build/p1.a" "?_build/this_file_will_not_exits_but_that's_ok" ] share: [ "build.sh" ] doc: [ "_build/p1.cmi" { "foo/bar/index.html" } ]opam-full-1.2.2/tests/packages/P1-1/p1.ml0000644000175000017500000000005512517374212016342 0ustar useruserlet x () = try Random.int 10 with _ -> 0 opam-full-1.2.2/tests/packages/P1-1/P1.config.in0000644000175000017500000000024112517374212017541 0ustar useruserasmcomp: "-I %{lib}%/P1" bytecomp: "-I %{lib}%/P1" asmlink: "-I %{lib}%/P1 p1.cmxa" bytelink: "-I %{lib}%/P1 p1.cma" LOCAL: "local" l: "L" FOO: "foo" bar: trueopam-full-1.2.2/tests/packages/P1-1/build.sh0000755000175000017500000000005212517374212017123 0ustar useruser#! /bin/sh -eu ocamlbuild p1.cma p1.cmxa opam-full-1.2.2/tests/packages/P1-1/README0000644000175000017500000000002612517374212016346 0ustar useruserA very useful package opam-full-1.2.2/tests/packages/P2/0000755000175000017500000000000012532744757015347 5ustar useruseropam-full-1.2.2/tests/packages/P2/p2.ml0000644000175000017500000000002512517374212016203 0ustar useruserlet g () = P1.x () opam-full-1.2.2/tests/packages/P2/build.sh0000755000175000017500000000034612517374212016774 0ustar useruser#! /bin/sh -eu OFLAGS="`${OPAM} config var P1:asmcomp`" CFLAGS="`${OPAM} config var P1:bytecomp`" echo "Bytecode Compilation" ocamlopt ${OFLAGS} -a p2.ml -o p2.cmxa echo "Native Compilation" ocamlc ${CFLAGS} -a p2.ml -o p2.cma opam-full-1.2.2/tests/packages/P2/config.in0000644000175000017500000000012012517374212017121 0ustar useruserFoo is %{P1:FOO}% Foo also contains a variable with %{P1:l}%. Funny, isn't it? opam-full-1.2.2/tests/packages/P2/P2.config.in0000644000175000017500000000020612517374212017406 0ustar useruserasmcomp: "-I %{lib}%/P2" bytecomp: "-I %{lib}%/P2" asmlink: "-I %{lib}%/P2 p2.cmxa" bytelink: "-I %{lib}%/P2 p2.cma" requires: "p1" opam-full-1.2.2/tests/packages/P2/README0000644000175000017500000000023112517374212016207 0ustar useruserAn other very useful package The description can go on multiple lines. The first line is the package synopsis, and the rest is the package description. opam-full-1.2.2/tests/packages/P2/P2.install0000644000175000017500000000006412517374212017204 0ustar useruserlib: [ "p2.cma" "p2.cmxa" "p2.a" "p2.cmi" ] opam-full-1.2.2/tests/Makefile0000644000175000017500000002170112517374212014735 0ustar useruserTMP_DIR = $(realpath .)/tmp OPAM_ROOT = $(TMP_DIR)/OPAM.ROOT OPAM_REPO = $(TMP_DIR)/OPAM.REPO # repositoy name REPO = test REPOKIND ?= local # To test GIT repo OPAM_GIT = $(TMP_DIR)/OPAM.GIT PACKAGES = P1-1 P1-2 P2 P3 P4 P5 ifndef OPAM OPAM = $(realpath ../src/opam) endif ENV = PATH=$(PATH) $(DEBUG) OPAMKEEPBUILDDIR=1 OPAMROOT=$(OPAM_ROOT) OPAMNOBASEPACKAGES=1 OPAMYES=1 OPAM=$(OPAM) OPAMBIN = $(ENV) $(OPAM) ifndef CHECK CHECK = $(ENV) $(dir $(OPAM))/opam-check endif ifeq ($(OPAMTESTQUIET), 1) DEBUG = else DEBUG = OPAMDEBUG=2 OCAMLRUNPARAM=b endif ARCHIVES = $(PACKAGES:%=packages/%.tar.gz) .PHONY: all local git all: local git @ quiet: $(MAKE) OPAMTESTQUIET=1 all printf = /usr/bin/printf define RUN @$(printf) "\e[1m- %-20s\e[m ..................................... " $(1); \ if $(MAKE) $(1) >test.log 2>&1; then \ $(printf) "\e[32m[ OK ]\e[m\n"; \ else \ $(printf) "\e[31m[FAIL]\e[m\n\n"; \ cat test.log; \ $(printf) "\n\e[31m>> %s FAILED <<\e[m\n" $(1); \ exit 1; \ fi; \ cat test.log >> fulltest.log endef run: $(call RUN,init) $(call RUN,upload) $(call RUN,install-remove) $(call RUN,list) $(call RUN,install-opt) $(call RUN,list) $(call RUN,install) $(call RUN,list) $(call RUN,reinstall) $(call RUN,list) $(call RUN,upload-new) $(call RUN,list) $(call RUN,upgrade) $(call RUN,list) $(call RUN,downgrade) $(call RUN,list) $(call RUN,switch-alias) $(call RUN,list) $(call RUN,switch-env-packages) $(call RUN,repo) $(call RUN,list) @echo "SUCCESS!" local: $(MAKE) clean $(MAKE) REPOKIND=local run git: $(MAKE) clean $(MAKE) REPOKIND=git run init: rm -rf $(OPAM_REPO) mkdir -p $(OPAM_REPO) ifeq ($(REPOKIND), git) cd $(OPAM_REPO) && git init && \ touch README && git add README && \ git commit -a -m "Initial commit" endif $(OPAMBIN) init --no-setup --no-base-packages $(REPO) $(OPAM_REPO) -k $(REPOKIND) upload: $(ARCHIVES) mkdir -p $(OPAM_REPO)/packages/P1.1 cp packages/P1-1.opam $(OPAM_REPO)/packages/P1.1/opam cp packages/P1-1/README $(OPAM_REPO)/packages/P1.1/descr mkdir -p $(OPAM_REPO)/packages/P2.1 cp packages/P2/README $(OPAM_REPO)/packages/P2.1/descr cp packages/P2.opam $(OPAM_REPO)/packages/P2.1/opam mkdir -p $(OPAM_REPO)/packages/P3.1~weird-version.test cp packages/P3.opam $(OPAM_REPO)/packages/P3.1~weird-version.test/opam cp packages/P3/README $(OPAM_REPO)/packages/P3.1~weird-version.test/descr mkdir -p $(OPAM_REPO)/packages/P4.1 cp packages/P4-1.opam $(OPAM_REPO)/packages/P4.1/opam cp packages/P4/README $(OPAM_REPO)/packages/P4.1/descr mkdir -p $(OPAM_REPO)/packages/P5.1 cp packages/P5.opam $(OPAM_REPO)/packages/P5.1/opam cp packages/P5/README $(OPAM_REPO)/packages/P5.1/descr mkdir -p $(OPAM_REPO)/compilers cp compilers/* $(OPAM_REPO)/compilers/ ifeq ($(REPOKIND), git) echo 'git: "$(OPAM_GIT)/P1-1"' > $(OPAM_REPO)/packages/P1.1/url cd $(OPAM_REPO)/packages/P1.1/ && git add * && git commit -a -m "Adding P1" echo 'git: "$(OPAM_GIT)/P2"' > $(OPAM_REPO)/packages/P2.1/url cd $(OPAM_REPO)/packages/P2.1/ && git add * && git commit -a -m "Adding P2" echo 'git: "$(OPAM_GIT)/P3"' > $(OPAM_REPO)/packages/P3.1~weird-version.test/url cd $(OPAM_REPO)/packages/P3.1~weird-version.test/ && git add * && git commit -a -m "Adding P3" echo 'git: "$(OPAM_GIT)/P4"' > $(OPAM_REPO)/packages/P4.1/url cd $(OPAM_REPO)/packages/P4.1/ && git add * && git commit -a -m "Adding P4" echo 'git: "$(OPAM_GIT)/P5"' > $(OPAM_REPO)/packages/P5.1/url cd $(OPAM_REPO)/packages/P5.1/ && git add * && git commit -a -m "Adding P5" cd $(OPAM_REPO)/compilers && git add * && git commit -a -m "Adding compilers" rm -rf $(OPAM_GIT) && mkdir -p $(OPAM_GIT) mkdir $(OPAM_GIT)/P1-1 && cp packages/P1-1/* $(OPAM_GIT)/P1-1/ mkdir $(OPAM_GIT)/P2 && cp packages/P2/* $(OPAM_GIT)/P2/ mkdir $(OPAM_GIT)/P3 && cp packages/P3/* $(OPAM_GIT)/P3/ mkdir $(OPAM_GIT)/P4 && cp packages/P4/* $(OPAM_GIT)/P4/ mkdir $(OPAM_GIT)/P5 && cp packages/P5/* $(OPAM_GIT)/P5/ cd $(OPAM_GIT)/P1-1 && git init && git add * && git commit -a -m "initial commit" cd $(OPAM_GIT)/P2 && git init && git add * && git commit -a -m "initial commit" cd $(OPAM_GIT)/P3 && git init && git add * && git commit -a -m "initial commit" cd $(OPAM_GIT)/P4 && git init && git add * && git commit -a -m "initial commit" cd $(OPAM_GIT)/P5 && git init && git add * && git commit -a -m "initial commit" else mkdir -p $(OPAM_REPO)/archives cp packages/P1-1.tar.gz $(OPAM_REPO)/archives/P1.1+opam.tar.gz cp packages/P2.tar.gz $(OPAM_REPO)/archives/P2.1+opam.tar.gz cp packages/P3.tar.gz $(OPAM_REPO)/archives/P3.1~weird-version.test+opam.tar.gz cp packages/P4.tar.gz $(OPAM_REPO)/archives/P4.1+opam.tar.gz cp packages/P5.tar.gz $(OPAM_REPO)/archives/P5.1+opam.tar.gz endif $(OPAMBIN) update list: $(OPAMBIN) list -a install-remove: $(CHECK) -l install-remove-1 $(OPAMBIN) install P1 $(CHECK) -l install-remove-2 P1.1 $(OPAMBIN) remove P1 $(CHECK) -l install-remove-3 install-opt: $(CHECK) -l install-opt-1 $(OPAMBIN) install P5 test -f $(OPAM_ROOT)/system/lib/p5/p2_absent $(CHECK) -l install-opt-2 P1.1 P5.1 $(OPAMBIN) remove P5 $(CHECK) -l install-opt-3 P1.1 $(OPAMBIN) install P5 $(CHECK) -l install-opt-4 P1.1 P5.1 $(OPAMBIN) remove P5 -a $(CHECK) -l install-opt-5 $(OPAMBIN) install P5 $(CHECK) -l install-opt-6 P1.1 P5.1 $(OPAMBIN) install P2 test -f $(OPAM_ROOT)/system/lib/p5/p2_present $(CHECK) -l install-opt-7 P1.1 P2.1 P5.1 $(OPAMBIN) remove P5 -a $(CHECK) -l install-opt-8 P1.1 P2.1 $(OPAMBIN) remove P2 -a $(CHECK) -l install-opt-9 $(OPAMBIN) install P1 P2 P5 test -f $(OPAM_ROOT)/system/lib/p5/p2_present $(CHECK) -l install-opt-10 P1.1 P2.1 P5.1 $(OPAMBIN) remove P2 -a test -f $(OPAM_ROOT)/system/lib/p5/p2_absent $(CHECK) -l install-opt-11 P1.1 P5.1 $(OPAMBIN) remove P1 $(CHECK) -l install-opt-12 install: $(CHECK) -l install-1 $(OPAMBIN) install P1 $(CHECK) -l install-2 P1.1 $(OPAMBIN) install P2 $(CHECK) -l install-3 P1.1 P2.1 $(OPAMBIN) install P3 $(CHECK) -l install-4 P1.1 P2.1 P3.1~weird-version.test $(OPAMBIN) install P4 $(CHECK) -l install-5 P1.1 P2.1 P3.1~weird-version.test P4.1 reinstall: $(CHECK) -l reinstall-1 P1.1 P2.1 P3.1~weird-version.test P4.1 $(OPAMBIN) reinstall P1 $(CHECK) -l reinstall-2 P1.1 P2.1 P3.1~weird-version.test P4.1 upload-new: mkdir $(OPAM_REPO)/packages/P4.2 cp packages/P4-2.opam $(OPAM_REPO)/packages/P4.2/opam cp packages/P4/README $(OPAM_REPO)/packages/P4.2/descr mkdir $(OPAM_REPO)/packages/P4.3 cp packages/P4-3.opam $(OPAM_REPO)/packages/P4.3/opam cp packages/P4/README $(OPAM_REPO)/packages/P4.3/descr ifeq ($(REPOKIND), git) echo "(* new line *)" >> $(OPAM_GIT)/P1-1/p1.ml cd $(OPAM_GIT)/P1-1 && git commit -a -m "a small change" echo 'git: "$(OPAM_GIT)/P4"' > $(OPAM_REPO)/packages/P4.2/url echo 'git: "$(OPAM_GIT)/P4"' > $(OPAM_REPO)/packages/P4.3/url cd $(OPAM_REPO) && git add * && git commit -a -m "Adding P4.2 and P4.3" else mkdir $(OPAM_REPO)/packages/P1.2 cp packages/P1-2.opam $(OPAM_REPO)/packages/P1.2/opam cp packages/P1-2/README $(OPAM_REPO)/packages/P1.2/descr cp packages/P1-2.tar.gz $(OPAM_REPO)/archives/P1.2+opam.tar.gz cp packages/P4.tar.gz $(OPAM_REPO)/archives/P4.2+opam.tar.gz cp packages/P4.tar.gz $(OPAM_REPO)/archives/P4.3+opam.tar.gz endif $(OPAMBIN) update upgrade: $(CHECK) -l upgrade-1 P1.1 P2.1 P3.1~weird-version.test P4.1 $(OPAMBIN) upgrade ifeq ($(REPOKIND), git) $(CHECK) -l upgrade-2 P1.1 P2.1 P3.1~weird-version.test P4.3 else $(CHECK) -l upgrade-2 P1.2 P2.1 P3.1~weird-version.test P4.3 endif downgrade: ifeq ($(REPOKIND), git) $(CHECK) -l downgrade-1 P1.1 P2.1 P3.1~weird-version.test P4.3 else $(CHECK) -l downgrade-1 P1.2 P2.1 P3.1~weird-version.test P4.3 endif $(OPAMBIN) install P4.2 $(CHECK) -l downgrade-2 P1.1 P2.1 P3.1~weird-version.test P4.2 switch-alias: $(CHECK) -l switch-alias-1 P1.1 P2.1 P3.1~weird-version.test P4.2 $(OPAMBIN) remove P3.1~weird-version.test P4.2 $(CHECK) -l switch-alias-2 P1.1 P2.1 $(OPAMBIN) switch export $(TMP_DIR)/export $(OPAMBIN) switch install test --alias-of system --no-base-packages $(CHECK) -l switch-alias-3 $(OPAMBIN) switch import $(TMP_DIR)/export $(CHECK) -l switch-alias-4 P1.1 P2.1 $(OPAMBIN) switch install test2 --alias-of 20 $(CHECK) -l switch-alias-5 $(OPAMBIN) install P1 $(CHECK) -l switch-alias-6 P1.1 $(OPAMBIN) switch system $(CHECK) -l switch-alias-7 P1.1 P2.1 $(OPAMBIN) switch remove test test2 switch-env-packages: $(CHECK) -l switch-env-packages-1 P1.1 P2.1 $(OPAMBIN) switch 10+a+b ifeq ($(REPOKIND), git) $(CHECK) -l switch-env-packages-2 P1.1 P2.1 P3.1~weird-version.test P4.3 else $(CHECK) -l switch-env-packages-2 P1.2 P2.1 P3.1~weird-version.test P4.3 endif ./test-TEST.sh $(wildcard $(OPAM_ROOT)/10+a+b/build/P4.3/P4*.env) "1" repo: $(OPAMBIN) repo add $(REPO)2 $(OPAM_REPO) -k $(REPOKIND) $(OPAMBIN) repo remove $(REPO)2 $(OPAMBIN) repo remove $(REPO) packages/%.tar.gz: packages/% cd packages && tar czf $*.tar.gz $* clean: rm -f test.log fulltest.log rm -f $(ARCHIVES) rm -rf $(TMP_DIR) opam-full-1.2.2/Makefile0000644000175000017500000000606012517374212013574 0ustar useruser-include Makefile.config all: opam-lib opam opam-admin opam-installer @ ALWAYS: @ opam-lib opam opam-admin opam-installer all: ALWAYS #backwards-compat compile with-ocamlbuild: all @ install-with-ocamlbuild: install @ libinstall-with-ocamlbuild: libinstall @ byte: $(MAKE) all USE_BYTE=true src/%: $(MAKE) -C src $* %: $(MAKE) -C src $@ lib-ext: $(MAKE) -C src_ext lib-ext download-ext: $(MAKE) -C src_ext archives clean-ext: $(MAKE) -C src_ext distclean clean: $(MAKE) -C src $@ $(MAKE) -C doc $@ OPAMINSTALLER_FLAGS = --prefix $(DESTDIR)$(prefix) OPAMINSTALLER_FLAGS += --mandir $(DESTDIR)$(mandir) # With ocamlfind, prefer to install to the standard directory rather # than $(prefix) if there are no overrides ifndef DESTDIR ifneq ($(OCAMLFIND),no) LIBINSTALL_DIR ?= $(shell $(OCAMLFIND) printconf destdir) endif endif ifneq ($(LIBINSTALL_DIR),) OPAMINSTALLER_FLAGS += --libdir $(LIBINSTALL_DIR) endif libinstall: $(if $(wildcard src_ext/lib/*),$(error Installing the opam libraries is incompatible with embedding the dependencies. Run 'make clean-ext' and try again)) src/opam-installer $(OPAMINSTALLER_FLAGS) opam-lib.install install: src/opam-installer $(OPAMINSTALLER_FLAGS) opam.install libuninstall: src/opam-installer -u $(OPAMINSTALLER_FLAGS) opam-lib.install uninstall: src/opam-installer -u $(OPAMINSTALLER_FLAGS) opam.install .PHONY: tests tests-local tests-git tests: opam opam-admin opam-check $(MAKE) -C tests all # tests-local, tests-git tests-%: opam opam-admin opam-check $(MAKE) -C tests $* .PHONY: doc doc: all $(MAKE) -C doc .PHONY: man man-html man man-html: opam opam-admin opam-installer $(MAKE) -C doc $@ configure: configure.ac m4/*.m4 aclocal -I m4 autoconf release-tag: git tag -d latest || true git tag -a latest -m "Latest release" git tag -a $(version) -m "Release $(version)" $(OPAM_FULL).tar.gz: $(MAKE) -C src_ext distclean $(MAKE) -C src_ext downloads rm -f $(OPAM_FULL) $(OPAM_FULL).tar.gz ln -s . fastlink: @$(foreach b,opam opam-admin opam-installer opam-check,\ ln -sf ../_obuild/$b/$b.asm src/$b;) @$(foreach l,core solver repositories client,\ $(foreach e,a cma cmxa,ln -sf ../_obuild/opam-$l/opam-$l.$e src/opam-$l.$e;)\ ln -sf $(addprefix ../../,\ $(foreach e,o cmo cmx cmi cmt cmti,$(wildcard _obuild/opam-$l/*.$e)))\ src/$l/;) rmartefacts: ALWAYS @rm -f $(addprefix src/, opam opam-admin opam-installer opam-check) @$(foreach l,core solver repositories client,\ $(foreach e,a cma cmxa,rm -f src/opam-$l.$e;)\ $(foreach e,o cmo cmx cmi cmt cmti,rm -f $(wildcard src/$l/*.$e);)) prefast: rmartefacts src/client/opamGitVersion.ml src/core/opamScript.ml src/core/opamCompat.ml src/core/opamCompat.mli @ocp-build -init fast: prefast @ocp-build @$(MAKE) fastlink fastclean: rmartefacts @ocp-build -clean 2>/dev/null || ocp-build clean 2>/dev/null cold: ./shell/bootstrap-ocaml.sh env PATH=$$PATH:`pwd`/bootstrap/ocaml/bin ./configure $(CONFIGURE_ARGS) env PATH=$$PATH:`pwd`/bootstrap/ocaml/bin $(MAKE) lib-ext env PATH=$$PATH:`pwd`/bootstrap/ocaml/bin $(MAKE) opam-full-1.2.2/CONTRIBUTING.md0000644000175000017500000000100612517374212014360 0ustar useruserBug reports and feature requests for **the OPAM tool** should be reported on: * http://github.com/ocaml/opam/issues (please include the output of `opam config report` whenever possible) **Packaging issues** or requests for a new package should be reported on: * http://github.com/ocaml/opam-repository/issues **General queries** can be addressed at: * http://lists.ocaml.org/listinfo/platform (for the both the tool & packages) * http://lists.ocaml.org/listinfo/opam-devel (for the tool and its evolution) opam-full-1.2.2/shell/0000755000175000017500000000000012532744757013255 5ustar useruseropam-full-1.2.2/shell/opam_installer.sh0000755000175000017500000000463512517374212016621 0ustar useruser#!/bin/sh set -ue # (c) Copyright Fabrice Le Fessant INRIA/OCamlPro 2013 # (c) Copyright Louis Gesbert OCamlPro 2014-2015 VERSION='1.2.1' default_ocaml=4.02.1 usage() { cat <&2 for s in "$@"; do echo $s; done exit 1 } TMP=${TMPDIR:-/tmp} dlerror () { error "Couldn't download $url" \ "There may not yet be a binary release for your architecture or OS, sorry." } getopam() { opamfile=$2 url=$1/$opamfile if which wget >/dev/null; then wget -q -O "$TMP/$opamfile" "$url" || dlerror else curl -s -L -o "$TMP/$opamfile" "$url" || dlerror fi } if [ $# -lt 1 ] || [ $# -gt 2 ] || [ "${1#-}" != "$1" ]; then echo "OPAM binary installer v. $VERSION" usage fi BINDIR=$1 COMP=${2:-$default_ocaml} file="opam-$VERSION-$(uname -m || echo unknown)-$(uname -s || echo unknown)" echo Downloading OPAM... getopam "https://github.com/ocaml/opam/releases/download/$VERSION" $file if [ ! -w "$BINDIR" ] || ! mkdir -p "$BINDIR" 2>/dev/null; then echo "You don't have write access to $BINDIR: sudo may ask for your password" if [ ! -d "$BINDIR" ]; then sudo mkdir -p "$BINDIR"; fi sudo install -g root -o root -m 755 $TMP/$file $BINDIR/opam else install -m 755 $TMP/$file $BINDIR/opam fi rm -f $TMP/$file OPAM=$(which opam || echo "$BINDIR/opam") if [ "$OPAM" != "$BINDIR/opam" ]; then echo "WARNING: you have a different version of OPAM installed at $OPAM" echo "It is highly recommended that you remove it." read -p "[press enter to continue]" x OPAM="$BINDIR/opam" fi if [ "$(id -u)" = "0" ]; then echo "Running as super-user: not running OPAM initialization." echo "You'll want to run \"$OPAM init --comp $COMP\" as user" else echo "Initializing with compiler $COMP" "$OPAM" init --comp "$COMP" fi echo "Installation done. If you need to uninstall, simply remove $BINDIR/opam" echo "and ~/.opam" opam-full-1.2.2/shell/dot_ocamlinit0000644000175000017500000000014112517374212016005 0ustar useruserlet () = try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH") with Not_found -> () ;;opam-full-1.2.2/shell/opam_switch_eval.sh0000644000175000017500000000013712517374212017122 0ustar useruserfunction opam-switch-eval () { opam switch "$@" --no-warning eval $(opam config env) } opam-full-1.2.2/shell/crunch.ml0000644000175000017500000000061212517374212015054 0ustar useruserlet add_stdin buf = try while true do let line = input_line stdin in Buffer.add_string buf line; Buffer.add_char buf '\n' done with End_of_file -> () let () = let name = Sys.argv.(1) in let buf = Buffer.create 1024 in add_stdin buf; let contents = Buffer.contents buf in Printf.printf "let %s =\n\"%s\"\n\n" name (String.escaped contents) opam-full-1.2.2/shell/md5check.ml0000644000175000017500000000073212517374212015260 0ustar useruserlet file, md5 = if Array.length Sys.argv <> 3 then ( Printf.eprintf "usage: ocaml %s \n" Sys.argv.(0); exit 1 ) else Sys.argv.(1), Sys.argv.(2) let md5_of_file = Digest.to_hex (Digest.file file) let () = if md5 <> md5_of_file then ( Printf.eprintf "MD5 for %s differ:\n\ \ expected: %s\n\ \ actual: %s\n" file md5 md5_of_file; Sys.remove file ) else Printf.printf "%s has the expected MD5.\n" file opam-full-1.2.2/shell/opam_completion.sh0000644000175000017500000001110112517374212016754 0ustar useruser_opam_add() { _opam_reply="$_opam_reply $1" } _opam_add_f() { local cmd cmd=$1; shift _opam_add "$($cmd "$@" 2>/dev/null)" } _opam_flags() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-%-%g' \ -e 's%^\\fB\(-[^,= ]*\)\\fR.*%\1%p' } _opam_commands() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-%-%g' \ -e '/^\.SH COMMANDS$/,/^\.SH/ s%^\\fB\([^,= ]*\)\\fR.*%\1%p' echo '--help' } _opam_vars() { opam config list --safe 2>/dev/null | \ sed -n \ -e '/^PKG:/d' \ -e 's%^\([^# ][^ ]*\).*%\1%p' } _opam() { local cmd subcmd cur prev compgen_opt COMPREPLY=() cmd=${COMP_WORDS[1]} subcmd=${COMP_WORDS[2]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} compgen_opt="" _opam_reply="" if [ $COMP_CWORD -eq 1 ]; then _opam_add_f opam help topics COMPREPLY=( $(compgen -W "$_opam_reply" -- $cur) ) unset _opam_reply return 0 fi case "$cmd" in install|show|info) _opam_add_f opam list --safe -a -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; reinstall|remove|uninstall) _opam_add_f opam list --safe -i -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; upgrade) _opam_add_f opam list --safe -i -s _opam_add_f _opam_flags "$cmd" ;; switch) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd" _opam_add_f opam switch list --safe -s -i;; 3) case "$subcmd" in install|set) _opam_add_f opam switch list --safe -s -a;; remove|reinstall) _opam_add_f opam switch list --safe -s -i;; import|export) compgen_opt="-o filenames -f";; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" esac;; config) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f _opam_commands "$cmd" else if [ $COMP_CWORD -eq 3 ] && [ "$subcmd" = "var" ]; then _opam_add_f _opam_vars else _opam_add_f _opam_flags "$cmd" fi fi;; repository|remote) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in add) if [ $COMP_CWORD -gt 3 ]; then compgen_opt="-o filenames -f" fi;; remove|priority|set-url) _opam_add_f opam repository list --safe -s;; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" case "$subcmd" in set-url|add) compgen_opt="-o filenames -f";; esac;; esac;; update) _opam_add_f opam repository list --safe -s _opam_add_f opam pin list --safe -s ;; source) _opam_add_f opam list --safe -A -s _opam_add_f _opam_flags "$cmd" ;; pin) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in add) _opam_add_f opam list --safe -A -s;; remove|edit) _opam_add_f opam pin list --safe -s;; *) _opam_add_f _opam_flags "$cmd" esac;; *) case "$subcmd" in add) compgen_opt="-o filenames -f";; *) _opam_add_f _opam_flags "$cmd" esac esac;; unpin) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f opam pin list --safe -s else _opam_add_f _opam_flags "$cmd" fi;; *) _opam_add_f _opam_commands "$cmd" _opam_add_f _opam_flags "$cmd" esac COMPREPLY=( $(compgen -W "$_opam_reply" $compgen_opt -- "$cur") ) unset _opam_reply return 0 } complete -F _opam opam opam-full-1.2.2/shell/opam_completion_zsh.sh0000644000175000017500000001114412517374212017647 0ustar useruser_opam_add() { _opam_reply="$_opam_reply $1" } _opam_add_f() { local cmd cmd=$1; shift _opam_add "$($cmd "$@" 2>/dev/null)" } _opam_flags() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-%-%g' \ -e 's%^\\fB\(-[^,= ]*\)\\fR.*%\1%p' } _opam_commands() { opam "$@" --help=groff 2>/dev/null | \ sed -n \ -e 's%\\-%-%g' \ -e '/^\.SH COMMANDS$/,/^\.SH/ s%^\\fB\([^,= ]*\)\\fR.*%\1%p' echo '--help' } _opam_vars() { opam config list --safe 2>/dev/null | \ sed -n \ -e '/^PKG:/d' \ -e 's%^\([^# ][^ ]*\).*%\1%p' } _opam() { local cmd subcmd cur prev compgen_opt COMPREPLY=() cmd=${COMP_WORDS[1]} subcmd=${COMP_WORDS[2]} cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} compgen_opt="" _opam_reply="" if [ $COMP_CWORD -eq 1 ]; then _opam_add_f opam help topics COMPREPLY=( $(compgen -W "$_opam_reply" -- $cur) ) unset _opam_reply return 0 fi case "$cmd" in install|show|info) _opam_add_f opam list --safe -a -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; reinstall|remove|uninstall) _opam_add_f opam list --safe -i -s if [ $COMP_CWORD -gt 2 ]; then _opam_add_f _opam_flags "$cmd" fi;; upgrade) _opam_add_f opam list --safe -i -s _opam_add_f _opam_flags "$cmd" ;; switch) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd" _opam_add_f opam switch list --safe -s -i;; 3) case "$subcmd" in install|set) _opam_add_f opam switch list --safe -s -a;; remove|reinstall) _opam_add_f opam switch list --safe -s -i;; import|export) compgen_opt="-o filenames -f";; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" esac;; config) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f _opam_commands "$cmd" else if [ $COMP_CWORD -eq 3 ] && [ "$subcmd" = "var" ]; then _opam_add_f _opam_vars else _opam_add_f _opam_flags "$cmd" fi fi;; repository|remote) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in add) if [ $COMP_CWORD -gt 3 ]; then compgen_opt="-o filenames -f" fi;; remove|priority|set-url) _opam_add_f opam repository list --safe -s;; *) _opam_add_f _opam_flags "$cmd" esac;; *) _opam_add_f _opam_flags "$cmd" case "$subcmd" in set-url|add) compgen_opt="-o filenames -f";; esac;; esac;; update) _opam_add_f opam repository list --safe -s _opam_add_f opam pin list --safe -s ;; source) _opam_add_f opam list --safe -A -s _opam_add_f _opam_flags "$cmd" ;; pin) case $COMP_CWORD in 2) _opam_add_f _opam_commands "$cmd";; 3) case "$subcmd" in add) _opam_add_f opam list --safe -A -s;; remove|edit) _opam_add_f opam pin list --safe -s;; *) _opam_add_f _opam_flags "$cmd" esac;; *) case "$subcmd" in add) compgen_opt="-o filenames -f";; *) _opam_add_f _opam_flags "$cmd" esac esac;; unpin) if [ $COMP_CWORD -eq 2 ]; then _opam_add_f opam pin list --safe -s else _opam_add_f _opam_flags "$cmd" fi;; *) _opam_add_f _opam_commands "$cmd" _opam_add_f _opam_flags "$cmd" esac COMPREPLY=( $(compgen -W "$_opam_reply" $compgen_opt -- "$cur") ) unset _opam_reply return 0 } autoload bashcompinit bashcompinit complete -F _opam opam opam-full-1.2.2/shell/bootstrap-ocaml.sh0000755000175000017500000000041212517374212016703 0ustar useruser#!/bin/sh -ex V=ocaml-4.02.1 URL=http://caml.inria.fr/pub/distrib/ocaml-4.02/${V}.tar.gz mkdir -p bootstrap cd bootstrap if [ ! -e ${V}.tar.gz ]; then curl -OL ${URL} fi tar -zxvf ${V}.tar.gz cd ${V} ./configure -prefix `pwd`/../ocaml make world opt make install opam-full-1.2.2/shell/get-git-id.ml0000644000175000017500000000216612517374212015532 0ustar useruserlet file = if Array.length Sys.argv <> 2 then ( Printf.eprintf "usage: ocaml %s \n" Sys.argv.(0); exit 1 ) else Sys.argv.(1) let read file = if Sys.file_exists file then let ic = open_in_bin file in Some (input_line ic) else None let write file contents = let write () = let oc = open_out file in output_string oc contents; output_char oc '\n'; close_out oc in match read file with | None -> write () | Some actual -> if actual <> contents then write () let (/) = Filename.concat let git file = ".git" / file let () = let version_none () = write file "let version = None" in match read (git "HEAD") with | None -> version_none () | Some s -> let reference = try (* look for "ref: refs/heads/..." *) let c = String.rindex s ' ' in let namedref = String.sub s (c+1) (String.length s -c-1) in read (git namedref) with Not_found -> (* detached state, .git/HEAD contains sha1 *) Some s in match reference with | None -> version_none () | Some sha1 -> write file (Printf.sprintf "let version = Some %S" sha1) opam-full-1.2.2/shell/release.sh0000755000175000017500000001075612517374212015231 0ustar useruser#!/bin/bash -ue help () { echo -e "$@" echo cat <&/dev/null; then if [ -z "${gitname:-}" ]; then echo "Please enter your github name: " read gitname fi for f in "${UPLOAD_FILES[@]}"; do echo "Uploading $(basename "$f"), please be patient..." git-upload-release "$gitname" ocaml/opam "$TAG" "$f" done elif type jq >&/dev/null; then url=$(curl "https://api.github.com/repos/ocaml/opam/releases" \ | jq '.[] | select(.tag_name == "'"$TAG"'") | .upload_url' \ | sed 's%"\([^"{?]*\).*"%\1%') for f in "${UPLOAD_FILES[@]}"; do base=$(basename "$f") echo "Uploading $base, please be patient..." curl -u "$gitname" \ -H "name: $base" \ -H "Content-Type: application/gzip" \ --data-binary "@$f" \ "$url?name=$base" | jq ".message" done else echo "Neither 'jq' nor 'git-upload-release' found, can't automatically" echo "upload to github. You can manually upload the following files to" echo "https://github.com/ocaml/opam/releases/tag/$TAG" echo echo "${UPLOAD_FILES[*]}" fi fi opam-full-1.2.2/.ocp-indent0000644000175000017500000000003012517374212014164 0ustar userusernormal strict_else=auto