package opam_bin_lib

  1. Overview
  2. Docs

Source file commandInstall.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
(**************************************************************************)
(*                                                                        *)
(*    Copyright 2020 OCamlPro & Origin Labs                               *)
(*                                                                        *)
(*  All rights reserved. This file is distributed under the terms of the  *)
(*  GNU Lesser General Public License version 2.1, with the special       *)
(*  exception on linking described in the file LICENSE.                   *)
(*                                                                        *)
(**************************************************************************)

open Ezcmd.TYPES
open EzFile.OP
open EzConfig.OP

let cmd_name = "install"

let add_repo ~repo ~url =
  if Sys.file_exists (Globals.opam_repo_dir // repo ) then
    Misc.call
      [| "opam"; "remote" ; "set-url" ; repo;
         "--all"; "--set-default"; url |]
  else
    Misc.call
      [| "opam"; "remote" ; "add" ; repo ;
         "--all"; "--set-default"; url |]

let install_exe () =
  let s = FileString.read_file Sys.executable_name in
  if Sys.file_exists Globals.opambin_bin then
    Sys.remove Globals.opambin_bin;
  EzFile.write_file Globals.opambin_bin s;
  Unix.chmod  Globals.opambin_bin 0o755;
  Printf.eprintf "Executable copied as %s\n%!" Globals.opambin_bin;
  EzFile.make_dir ~p:true Globals.opam_plugins_bin_dir ;
  Misc.call [|
    "ln"; "-sf" ;
    ".." // Globals.command // Globals.command_exe ;
    Globals.opam_plugins_bin_dir // Globals.command
  |]

let install_hooks () =

  Misc.change_opam_config (fun file_contents ->
      let file_contents =
        match CommandUninstall.remove_opam_hooks file_contents with
        | None -> file_contents
        | Some file_contents -> file_contents
      in
      Printf.eprintf "Adding %s hooks\n%!" Globals.command;
      Some (
        List.rev @@
        Misc.opam_variable "pre-build-commands"
          {| ["%s" "pre-build" name version depends] |}
          Globals.opambin_bin ::
        Misc.opam_variable "wrap-build-commands"
          {| ["%s" "wrap-build" name version depends "--"] |}
          Globals.opambin_bin ::
        Misc.opam_variable "pre-install-commands"
          {| ["%s" "pre-install" name version depends] |}
          Globals.opambin_bin ::
        Misc.opam_variable "wrap-install-commands"
          {| ["%s" "wrap-install" name version depends "--"] |}
          Globals.opambin_bin ::
        Misc.opam_variable "post-install-commands"
          {| ["%s" "post-install" name version depends installed-files] { error-code = 0} |}
          Globals.opambin_bin  ::
        Misc.opam_variable "pre-remove-commands"
          {| ["%s" "pre-remove" name version depends] |}
          Globals.opambin_bin ::
        List.rev file_contents
      )
    )

let install_repos () =

  EzFile.make_dir ~p:true Globals.opambin_store_repo_packages_dir;
  EzFile.write_file ( Globals.opambin_store_repo_dir // "repo" )
    {|
opam-version: "2.0"
archive-mirrors: "../../cache"
|};
  EzFile.write_file ( Globals.opambin_store_repo_dir // "version" )
    "0.9.0";

  add_repo ~repo:Globals.opam_opambin_repo
    ~url:( Printf.sprintf "file://%s"
             Globals.opambin_store_repo_dir )

let install_patches () =
  let patches_url = !!Config.patches_url in
  if EzString.starts_with patches_url ~prefix:"file://" then
    (* nothing to do *)
    Printf.eprintf "Using %s for patches\n%!" patches_url
  else
    let opambin_patches_dir = Globals.opambin_patches_dir in
    let tmp_dir = opambin_patches_dir ^ ".tmp" in

    if EzString.starts_with patches_url ~prefix:"git@" then begin
      Misc.call [| "rm"; "-rf"; tmp_dir |];
      Misc.call [| "git"; "clone" ; patches_url ; tmp_dir |];
      Misc.call [| "rm"; "-rf"; opambin_patches_dir |];
      Misc.call [| "mv"; tmp_dir; opambin_patches_dir |]
    end else

    if EzString.starts_with patches_url ~prefix:"https://"
    || EzString.starts_with patches_url ~prefix:"http://" then begin
      let output = Globals.opambin_dir // "relocation-patches.tar.gz" in
      Printf.eprintf "Downloading patches...\n%!";
      match Misc.wget ~url:patches_url ~output with
      | None ->
        Printf.kprintf failwith "Could not retrieve archive at %s" patches_url
      | Some output ->

        Misc.call [| "rm"; "-rf"; tmp_dir |];
        EzFile.make_dir ~p:true tmp_dir ;

        Unix.chdir tmp_dir ;
        Misc.call [| "tar" ; "zxf" ; output |] ;
        Unix.chdir Globals.curdir;

        let patches_subdir = tmp_dir // "patches" in
        if not ( Sys.file_exists patches_subdir ) then
          Printf.kprintf failwith
            "archive %s does not contain 'patches/' subdir" patches_url;

        Misc.call [| "rm"; "-rf"; opambin_patches_dir |];
        EzFile.make_dir ~p:true opambin_patches_dir;
        Sys.rename patches_subdir (opambin_patches_dir // "patches");
        Misc.call [| "rm"; "-rf"; tmp_dir |];
        Sys.remove output

    end
    else
      begin
        Printf.eprintf
          "Error: patches_url '%s' should either be local (file://) or git (git@, http[s]://)\n%!" patches_url;
        exit 2
      end


let action args =
  Printf.eprintf "%s\n\n%!" Globals.about ;

  EzFile.make_dir ~p:true Globals.opambin_dir ;
  Config.save ();

  EzFile.make_dir ~p:true Globals.opambin_cache_dir;

  match args with
  | [] ->
    install_exe ();
    install_hooks ();
    install_repos ();
    install_patches ()
  | _ ->
    List.iter (function
        | "exe" -> install_exe ()
        | "hooks" -> install_hooks ()
        | "repos" -> install_repos ()
        | "patches" -> install_patches ()
        | s ->
          Printf.eprintf "Error: unexpected argument %S" s;
          exit 2)
      args

let cmd =
  let anon_args = ref [] in
  {
    cmd_name ;
    cmd_action = (fun () -> action !anon_args) ;
    cmd_args = [

      [], Anons (fun list -> anon_args := list),
      Ezcmd.info "No args = all, otherwise 'exe', 'hooks' and/or 'repos'";

    ];
    cmd_man = [
      `S "DESCRIPTION" ;
      `Blocks [
        `P {|Here are the names of the actions performed by the command, that can be passed as arguments:|};
        `I ("[exe]",
            {|Install the current executable as an opam plugin, so that it is possible to use "opam bin" instead of "opam-bin" from anywhere;|});
        `I ("[hooks]",
            {|Modify the hooks of opam to call opam-bin everytime a package is installed;|});
        `I ("[repos]",
            {|Add the repository of generated binary packages as one of the default opam repository|});
        `I ("[patches]", {|Download/upgrade the set of relocation patches|});
      ];
      `P {|Without argument, all the actions are performed.|}
    ];
    cmd_doc = {|
installs opam-bin in opam and download the set of relocation patches.
|}
  }