package oui
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A tool that builds standalone installers for your OCaml applications
Install
dune-project
Dependency
Authors
Maintainers
Sources
oui-0.1.0.tbz
sha256=b806a63c9acd581a00729a48f1faf86b294cc82936fc705fc628a20ede33f977
sha512=e61c35a6e08671634c1edabd7b0add926ac6e0c6c43c9e0a095e89efab7696b6ae5cc1ea0844283a80640c19adb36478bdfb2414bbcab5077ceb7fd16ae45e66
doc/src/oui.lib/macos_postinstall.ml.html
Source file macos_postinstall.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 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268(**************************************************************************) (* *) (* Copyright 2025 OCamlPro *) (* *) (* 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. *) (* *) (**************************************************************************) (** Shell function to parse install.conf files. *) let load_conf_function = {| load_conf() { local conf="$1" var_prefix="$2" while IFS= read -r line || [ -n "$line" ]; do case "$line" in ""|\#*) continue ;; esac case "$line" in *=*) ;; *) printf '%s\n' "Invalid line in $conf: $line" >&2; return 1 ;; esac local key="${line%%=*}" local val="${line#*=}" case "$key" in *[!a-zA-Z0-9_]*) printf '%s\n' "Invalid key in $conf: $key" >&2; return 1 ;; *) eval "${var_prefix}${key}=\$val" ;; esac done < "$conf" return 0 } |} let generate_wrapper_section ~app_path ~binary_name ~has_binary ~env = if not has_binary then "# Plugin-only package - no wrapper script" else let wrapper_content = let env_lines = List.map (fun (var, value) -> (* VAR="VALUE" \ *) Printf.sprintf "%s=\"%s\" \\\\" var value) env in String.concat "\n" ( "#!/bin/bash" :: env_lines @ [ Printf.sprintf {|exec "%s/Contents/MacOS/%s" "$@"|} app_path binary_name ] ) in let wrapper_creation = Printf.sprintf {|cat > "/usr/local/bin/%s" << 'WRAPPER_EOF' %s WRAPPER_EOF|} binary_name wrapper_content in let wrapper_chmod = Printf.sprintf "chmod +x \"/usr/local/bin/%s\"" binary_name in Printf.sprintf "mkdir -p /usr/local/bin\n\n%s\n%s" wrapper_creation wrapper_chmod let generate_load_app_conf ~target_app = let capitalized = String.capitalize_ascii target_app in let var_prefix = Plugin_utils.app_var_prefix target_app in Printf.sprintf {|# Find and load %s's install.conf TARGET_CONF="/Applications/%s.app/Contents/Resources/install.conf" if [ -f "$TARGET_CONF" ]; then load_conf "$TARGET_CONF" "%s" else echo "Error: %s is not installed. Cannot install plugin." >&2 exit 1 fi|} target_app capitalized var_prefix target_app let generate_plugin_symlinks ~resources ~(plugin : Installer_config.plugin) = let var_prefix = Plugin_utils.app_var_prefix plugin.app_name in let plugin_basename = Filename.basename plugin.plugin_dir in let lib_basename = Filename.basename plugin.lib_dir in let dyn_deps_symlinks = plugin.dyn_deps |> List.map (fun dep -> let dep_basename = Filename.basename dep in Printf.sprintf {|ln -sf "%s/%s" "${%slib}/%s"|} resources dep var_prefix dep_basename) |> String.concat "\n" in Printf.sprintf {|echo "Installing plugin %s for %s..." ln -sf "%s/%s" "${%splugins}/%s" ln -sf "%s/%s" "${%slib}/%s" %s|} plugin.name plugin.app_name resources plugin.plugin_dir var_prefix plugin_basename resources plugin.lib_dir var_prefix lib_basename dyn_deps_symlinks let generate_plugin_install_section ~resources ~plugins = match plugins with | [] -> "" | _ -> let unique_apps = plugins |> List.map (fun (p : Installer_config.plugin) -> p.app_name) |> List.sort_uniq String.compare in let load_apps = unique_apps |> List.map (fun app -> generate_load_app_conf ~target_app:app) |> String.concat "\n\n" in let symlinks = plugins |> List.map (fun p -> generate_plugin_symlinks ~resources ~plugin:p) |> String.concat "\n\n" in Printf.sprintf "%s\n%s\n\n%s" load_conf_function load_apps symlinks let generate_manpages_section ~resources = let app_man_dir = Printf.sprintf "%s/man" resources in Printf.sprintf {|if [ -d "%s" ]; then mkdir -p /usr/local/share/man for section_dir in %s/*; do if [ -d "$section_dir" ]; then section=$(basename "$section_dir") mkdir -p /usr/local/share/man/${section} for manpage in "$section_dir"/*; do [ -f "$manpage" ] && ln -sf "$manpage" "/usr/local/share/man/${section}/$(basename "$manpage")" done fi done fi|} app_man_dir app_man_dir let generate_postinstall_script ~env ~app_name ~binary_name ~has_binary ?(plugins : Installer_config.plugin list = []) () = let app_path = Printf.sprintf "/Applications/%s.app" app_name in let resources = Printf.sprintf "%s/Contents/Resources" app_path in let def_install_path = Printf.sprintf "INSTALL_PATH=%s" resources in let wrapper_section = generate_wrapper_section ~app_path ~binary_name ~has_binary ~env in let plugin_install_section = generate_plugin_install_section ~resources ~plugins in let manpages_section = generate_manpages_section ~resources in Printf.sprintf {|#!/bin/bash set -e %s %s %s %s exit 0|} def_install_path wrapper_section plugin_install_section manpages_section let generate_uninstall_script ~app_name ~binary_name ~has_binary ~plugins = let app_path = Printf.sprintf "/Applications/%s.app" app_name in let resources = Printf.sprintf "%s/Contents/Resources" app_path in (* Plugin symlink removal *) let plugin_removal = match plugins with | [] -> "" | _ -> let load_and_remove = Printf.sprintf {|%s # Load our own install.conf to get target app paths if [ -f "%s/install.conf" ]; then load_conf "%s/install.conf" "" fi |} load_conf_function resources resources in let remove_symlinks = List.map (fun (p : Installer_config.plugin) -> let var_prefix = Plugin_utils.app_var_prefix p.app_name in let plugin_basename = Filename.basename p.plugin_dir in let lib_basename = Filename.basename p.lib_dir in let dyn_deps_removal = List.map (fun dep -> Printf.sprintf {|rm -f "${%slib}/%s" 2>/dev/null || true|} var_prefix (Filename.basename dep)) p.dyn_deps |> String.concat "\n" in Printf.sprintf {| echo "Removing plugin %s from %s..." rm -f "${%splugins}/%s" 2>/dev/null || true rm -f "${%slib}/%s" 2>/dev/null || true %s|} p.name p.app_name var_prefix plugin_basename var_prefix lib_basename dyn_deps_removal) plugins |> String.concat "\n" in load_and_remove ^ remove_symlinks in let wrapper_removal = if has_binary then Printf.sprintf {|# Remove wrapper from /usr/local/bin if [ -L "/usr/local/bin/%s" ] || [ -f "/usr/local/bin/%s" ]; then echo "Removing /usr/local/bin/%s" rm -f "/usr/local/bin/%s" fi|} binary_name binary_name binary_name binary_name else "# Plugin-only package - no wrapper to remove" in Printf.sprintf {|#!/bin/bash set -e echo "Uninstalling %s..." %s %s # Remove manpage symlinks find /usr/local/share/man -type l -lname "%s/*" -delete 2>/dev/null || true # Remove the app bundle if [ -d "%s" ]; then echo "Removing %s" rm -rf "%s" fi echo "Uninstallation complete!" |} app_name plugin_removal wrapper_removal resources app_path app_path app_path let save_postinstall_script ~content ~scripts_dir = OpamFilename.mkdir scripts_dir; let script_path = OpamFilename.Op.(scripts_dir // "postinstall") in OpamFilename.write script_path content; System.call_unit System.Chmod (755, script_path); OpamConsole.msg "Created postinstall script: %s\n" (OpamFilename.to_string script_path); script_path let save_uninstall_script ~content ~resources_dir = let script_path = OpamFilename.Op.(resources_dir // "uninstall.sh") in OpamFilename.write script_path content; System.call_unit System.Chmod (755, script_path); OpamConsole.msg "Created uninstall script: %s\n" (OpamFilename.to_string script_path); script_path
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>