Skip to content

Commit

Permalink
Improve 'opam switch'
Browse files Browse the repository at this point in the history
* better 'opam switch list'
* better documentation (this should fix ocaml#299)
* add compiler description files (this should fix ocaml#305)
  • Loading branch information
samoht committed Dec 18, 2012
1 parent 865233b commit 5a1b838
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 69 deletions.
38 changes: 12 additions & 26 deletions src/client/opamClient.ml
Expand Up @@ -197,7 +197,9 @@ let update_repositories t ~show_compilers repositories =
if comp <> OpamCompiler.default
&& OpamSwitch.Map.for_all (fun _ c -> comp <> c) t.aliases then (
let comp_f = OpamPath.compiler t.root comp in
let descr_f = OpamPath.compiler_descr t.root comp in
OpamFilename.remove comp_f;
OpamFilename.remove descr_f;
)
) (OpamState.compilers t);

Expand All @@ -209,9 +211,13 @@ let update_repositories t ~show_compilers repositories =
let comp_dir = OpamPath.compilers_dir t.root in
OpamCompiler.Set.iter (fun o ->
let comp_g = OpamPath.compiler t.root o in
let comp_f = OpamPath.Repository.compiler repo_p o in
if not (OpamFilename.exists comp_g) && OpamFilename.exists comp_f then
OpamFilename.link_in comp_f comp_dir
let comp_r = OpamPath.Repository.compiler repo_p o in
if not (OpamFilename.exists comp_g) && OpamFilename.exists comp_r then
OpamFilename.link_in comp_r comp_dir;
let descr_g = OpamPath.compiler_descr t.root o in
let descr_r = OpamPath.Repository.compiler_descr repo_p o in
if not (OpamFilename.exists descr_g) && OpamFilename.exists descr_r then
OpamFilename.link_in descr_r comp_dir;
) comps
) (sorted_repositories t)

Expand Down Expand Up @@ -325,26 +331,6 @@ let update_packages t ~show_packages repositories =
if !has_error then
OpamGlobals.exit 1

let indent_left s nb =
let nb = nb - String.length s in
if nb <= 0 then
s
else
s ^ String.make nb ' '

let indent_right s nb =
let nb = nb - String.length s 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

let s_not_installed = "--"

let names_of_regexp t ~installed_only ~name_only ~case_sensitive ~all regexps =
Expand Down Expand Up @@ -423,9 +409,9 @@ let list ~print_short ~installed_only ?(name_only = true) ?(case_sensitive = fal
| None -> s_not_installed
| Some v -> OpamPackage.Version.to_string v in
OpamGlobals.msg "%s %s %s\n"
(indent_left name max_n)
(indent_right version max_v)
(sub_at 100 synopsis)
(OpamMisc.indent_left name max_n)
(OpamMisc.indent_right version max_v)
(OpamMisc.sub_at 100 synopsis)
) names

let info regexps =
Expand Down
23 changes: 19 additions & 4 deletions src/client/opamMain.ml
Expand Up @@ -626,13 +626,26 @@ let switch_doc = "Manage multiple installation of compilers."
let switch =
let doc = switch_doc in
let commands = [
["add";"install"], `install , "Install the given compiler.";
["add";"install"], `install , "Install the given compiler. The commands fails if the package is \
already installed (e.g. it will not transparently switch to the \
installed compiler switch, as $(b,opam switch <name>) does).";
["rm";"remove"] , `remove , "Remove the given compiler.";
["export"] , `export , "Export the list installed package to a file.";
["import"] , `import , "Install the packages from a file.";
["reinstall"] , `reinstall, "Reinstall the given compiler.";
["list"] , `list , "List the available compilers.";
["current"] , `current , "Show the current compiler.";
["reinstall"] , `reinstall, "Reinstall the given compiler switch. This will also try reinstall the
installed packages.";
["list"] , `list , "List the available compilers. \
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 <name>). If you want to use a new \
compiler <comp>, use $(b,opam switch <comp>): this will download, \
compile and create a fresh and independant 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 <name> --alias-of <comp>). In case \
<name> and <comp> are the same, this is equivalent to $(b,opam switch <comp>).";
["show";"current"], `current , "Show the current compiler.";
] in
let man = [
`S "DESCRIPTION";
Expand All @@ -641,6 +654,8 @@ let switch =
compiler for the first time. The different compiler versions are
totally independant 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 commands in

let command, params = mk_subcommands_with_default commands
Expand Down
88 changes: 65 additions & 23 deletions src/client/opamSwitchCommand.ml
Expand Up @@ -18,34 +18,76 @@ let log fmt = OpamGlobals.log "SWITCH" fmt
open OpamTypes
open OpamState.Types

(* name + state + compiler + description *)
(* TODO: add repo *)
let list () =
log "list";

let t = OpamState.load_state () in
let descrs = OpamState.compilers t in
let aliases = OpamFile.Aliases.read (OpamPath.aliases t.root) in
OpamGlobals.msg "--- Installed compilers ---\n";
OpamSwitch.Map.iter (fun n c ->
let current = if n = t.switch then "*" else " " in
let compiler = OpamCompiler.to_string c in
let switch_name = OpamSwitch.to_string n in
if switch_name = compiler then
OpamGlobals.msg " %s %s\n" current switch_name
else
OpamGlobals.msg " %s %s [%s]\n" current compiler switch_name
) aliases;
OpamGlobals.msg "\n--- Available compilers ---\n";
OpamCompiler.Set.iter (fun c ->
let comp = OpamFile.Comp.read (OpamPath.compiler t.root c) in
let preinstalled = if OpamFile.Comp.preinstalled comp then "~" else " " in
let version = OpamFile.Comp.version comp in
let version, compiler =
if OpamCompiler.Version.to_string version = OpamCompiler.to_string c then
OpamCompiler.Version.to_string version, ""
let descr c = OpamFile.Comp_descr.safe_read (OpamPath.compiler_descr t.root c) in

let installed = "I" in
let current = "C" in
let not_installed = "--" in

let installed =
OpamSwitch.Map.fold (fun name comp acc ->
let s =
if name = t.switch
then current
else installed in
let n = OpamSwitch.to_string name in
let c = OpamCompiler.to_string comp in
let d = descr comp in
(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
) descrs in

let officials, patches =
OpamCompiler.Set.fold (fun comp (officials, patches) ->
let c = OpamFile.Comp.read (OpamPath.compiler 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
OpamCompiler.Version.to_string version,
Printf.sprintf "(%s)" (OpamCompiler.to_string c) in
OpamGlobals.msg " %s %-8s %s\n" preinstalled version compiler
) descrs
officials, comp :: patches
) descrs ([],[]) in

let mk l =
List.fold_left (fun acc comp ->
let c = OpamCompiler.to_string comp in
let d = descr comp in
(not_installed, not_installed, c, d) :: acc
) [] l in

let all = installed @ mk officials @ mk patches 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) all in

let print_compiler (name, state, compiler, descr) =
OpamGlobals.msg "%s %s %s %s\n"
(OpamMisc.indent_left name max_name)
(OpamMisc.indent_right state max_state)
(OpamMisc.indent_left compiler max_compiler)
descr in

List.iter print_compiler all

let remove switch =
log "remove switch=%s" (OpamSwitch.to_string switch);
Expand Down
41 changes: 28 additions & 13 deletions src/core/opamFile.ml
Expand Up @@ -370,24 +370,20 @@ module Descr = struct
let internal = "descr"
type t = Lines.t
let empty = []
type t = string
let create str =
[[str]]
let empty = ""
let synopsis = function
| [] -> ""
| h::_ -> String.concat " " h
let synopsis str =
match OpamMisc.cut_at str '\n' with
| None -> str
| Some (s,_) -> s
let full l =
let one l = String.concat " " l in
String.concat "\n" (List.map one l)
let full str = str
let of_string = Lines.of_string
let of_string _ x = x
let to_string = Lines.to_string
let to_string _ x = x
end
Expand Down Expand Up @@ -1296,6 +1292,20 @@ module Comp = struct
end
module Comp_descr = struct
let internal = "comp_descr"
type t = string
let empty = ""
let of_string _ x = x
let to_string _ x = x
end
module Subst = struct
let internal = "subst"
Expand Down Expand Up @@ -1393,6 +1403,11 @@ module Descr = struct
include Make (Descr)
end
module Comp_descr = struct
include Comp_descr
include Make (Comp_descr)
end
module Aliases = struct
include Aliases
include Make (Aliases)
Expand Down
7 changes: 4 additions & 3 deletions src/core/opamFile.mli
Expand Up @@ -166,14 +166,12 @@ module Descr: sig

include IO_FILE

(** Create a description file *)
val create: string -> t

(** Return the first line *)
val synopsis: t -> string

(** Return the full description *)
val full: t -> string

end

(** Compiler aliases: [$opam/aliases] *)
Expand Down Expand Up @@ -255,6 +253,9 @@ module Comp: sig

end

(** Compiler descriptions *)
module Comp_descr: IO_FILE with type t = string

(** {2 Configuration files} *)

(** .install files *)
Expand Down
20 changes: 20 additions & 0 deletions src/core/opamMisc.ml
Expand Up @@ -247,3 +247,23 @@ let env = lazy (

let getenv n =
List.assoc n (Lazy.force env)

let indent_left s nb =
let nb = nb - String.length s in
if nb <= 0 then
s
else
s ^ String.make nb ' '

let indent_right s nb =
let nb = nb - String.length s 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
9 changes: 9 additions & 0 deletions src/core/opamMisc.mli
Expand Up @@ -148,6 +148,15 @@ val contains: string -> char -> bool
(** Split a string *)
val split: string -> char -> string list

(** left indenting *)
val indent_left: string -> int -> string

(** right indenting *)
val indent_right: string -> int -> string

(** Cut a string *)
val sub_at: int -> string -> string

(** {2 Misc} *)

(** Remove from a ':' separated list of string the one with the given prefix *)
Expand Down
4 changes: 4 additions & 0 deletions src/core/opamPath.ml
Expand Up @@ -40,6 +40,8 @@ let compilers_dir t = t / "compilers"

let compiler t ov = compilers_dir t // (OpamCompiler.to_string ov ^ ".comp")

let compiler_descr t ov = compilers_dir t // (OpamCompiler.to_string ov ^ ".descr")

let descr_dir t = t / "descr"

let descr t nv = descr_dir t // OpamPackage.to_string nv
Expand Down Expand Up @@ -145,6 +147,8 @@ module Repository = struct

let compiler t ov = compilers_dir t // (OpamCompiler.to_string ov ^ ".comp")

let compiler_descr t ov = compilers_dir t // (OpamCompiler.to_string ov ^ ".descr")

let url t nv = package t nv // "url"

let files t nv = package t nv / "files"
Expand Down
6 changes: 6 additions & 0 deletions src/core/opamPath.mli
Expand Up @@ -43,6 +43,9 @@ val opam: t -> package -> filename
(** Compiler files: {i $opam/compilers/$OVERSION.comp} *)
val compiler: t -> compiler -> filename

(** Compiler description files: {i $opam/compilers/$OVERSION.descr} *)
val compiler_descr: t -> compiler -> filename

(** Compiler files: {i $opam/compilers/} *)
val compilers_dir: t -> dirname

Expand Down Expand Up @@ -218,6 +221,9 @@ module Repository: sig
(** Compiler files: {i $opam/repo/$repo/compilers/$OVERSION.comp} *)
val compiler: r -> compiler -> filename

(** Compiler description files: {i $opam/repo/$repo/compilers/$OVERSION.descr} *)
val compiler_descr: r -> compiler -> filename

(** Compiler files: {i $opam/repo/$repo/compilers/} *)
val compilers_dir: r -> dirname

Expand Down

0 comments on commit 5a1b838

Please sign in to comment.