1 /** 2 * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Jan 19, 2011 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dvm.commands.DvmInstall; 8 9 import std.algorithm : each, filter, find, map; 10 import std.array : array, join; 11 import std.exception : assumeUnique; 12 import std.file : append, exists, thisExePath; 13 import std.path : buildPath; 14 import std.stdio : writeln; 15 16 import tango.io.device.File; 17 import tango.sys.HomeFolder; 18 19 import Path = dvm.io.Path; 20 import dvm.commands.Command; 21 import dvm.dvm.Exceptions; 22 import dvm.dvm.ShellScript; 23 import dvm.dvm.Options; 24 import dvm.util.Util; 25 version (Windows) import DvmRegistry = dvm.util.DvmRegistry; 26 version (Windows) import dvm.util.Windows; 27 28 class DvmInstall : Command 29 { 30 private 31 { 32 enum postInstallInstructions = import("post_install_instructions.txt"); 33 enum failedInstallInstructions = import("failed_install_instructions.txt"); 34 35 version (Posix) 36 enum dvmScript = import("dvm.sh"); 37 38 else 39 enum dvmScript = import("dvm.bat"); 40 } 41 42 override void execute () 43 { 44 install; 45 } 46 47 private: 48 49 void install () 50 { 51 if (Path.exists(options.path.dvm)) 52 return update; 53 54 verbose("Installing dvm to: ", options.path.dvm); 55 createPaths; 56 copyExecutable; 57 writeScript; 58 59 version (Posix) 60 { 61 setPermissions; 62 installBashInclude(createBashInclude); 63 } 64 65 version (Windows) 66 setupRegistry; 67 } 68 69 void update () 70 { 71 createPaths; 72 copyExecutable; 73 writeScript; 74 setPermissions; 75 76 version (Windows) 77 setupRegistry; 78 } 79 80 void createPaths () 81 { 82 verbose("Creating paths:"); 83 84 createPath(options.path.dvm); 85 createPath(options.path.archives); 86 createPath(Path.join(options.path.dvm, options.path.bin).assumeUnique); 87 createPath(options.path.compilers); 88 createPath(options.path.env); 89 createPath(options.path.scripts); 90 91 verbose(); 92 } 93 94 void copyExecutable () 95 { 96 verbose("Copying executable:"); 97 verbose("thisExePath: ", thisExePath); 98 copy(thisExePath, options.path.dvmExecutable); 99 } 100 101 void writeScript () 102 { 103 verbose("Writing script to: ", options.path.dvmScript); 104 File.set(options.path.dvmScript, dvmScript); 105 } 106 107 void setPermissions () 108 { 109 verbose("Setting permissions:"); 110 permission(options.path.dvmScript, "+x"); 111 permission(options.path.dvmExecutable, "+x"); 112 } 113 114 version (Posix) 115 void installBashInclude (ShellScript sh) 116 { 117 static string defaultProfile() 118 { 119 with(Shell) switch (Options.instance.shell) 120 { 121 case bash: return ".bash_profile"; 122 case zsh: return ".zprofile"; 123 default: throw new DvmException("Failed to identify a " ~ 124 "default shell profile file", __FILE__, __LINE__); 125 } 126 } 127 128 enum potentialShellProfileFiles = [ 129 [".bashrc", ".bash_profile"], 130 [".zshrc", ".zprofile"] 131 ]; 132 133 const home = homeFolder.assumeUnique; 134 alias toFullPath = path => home.buildPath(path); 135 136 auto existingPofilePaths = potentialShellProfileFiles 137 .map!(files => files.map!toFullPath) 138 .map!(files => files.find!exists) 139 .filter!(files => !files.empty) 140 .map!(files => files.front); 141 142 auto profilePaths = existingPofilePaths.empty ? 143 [home.buildPath(defaultProfile)] : existingPofilePaths.array; 144 145 verbose("Installing dvm in the shell loading file(s): ", profilePaths.join(", ")); 146 profilePaths.each!(path => append(path, sh.content)); 147 writeln(postInstallInstructions); 148 } 149 150 void createPath (string path) 151 { 152 verbose(options.indentation, path); 153 if(!Path.exists(path)) 154 Path.createFolder(path); 155 } 156 157 void permission (string path, string mode) 158 { 159 version (Posix) 160 { 161 verbose(options.indentation, "mode: " ~ mode); 162 verbose(options.indentation, "file: " ~ path, '\n'); 163 164 Path.permission(path, mode); 165 } 166 } 167 168 void copy (string source, string destination) 169 { 170 verbose(options.indentation, "source: ", source); 171 verbose(options.indentation, "destination: ", destination, '\n'); 172 173 Path.copy(source, destination); 174 } 175 176 ShellScript createBashInclude () 177 { 178 auto sh = new ShellScript; 179 sh.nl.nl; 180 sh.comment("This loads DVM into a shell session.").nl; 181 182 sh.ifFileIsNotEmpty(options.path.dvmScript, { 183 sh.source(options.path.dvmScript); 184 }); 185 186 return sh; 187 } 188 189 version (Windows) 190 void setupRegistry () 191 { 192 auto defaultCompilerPath = DvmRegistry.getDefaultCompilerPath(); 193 DvmRegistry.updateEnvironment(options.path.binDir, defaultCompilerPath); 194 DvmRegistry.checkSystemPath(); 195 broadcastSettingChange("Environment"); 196 println("DVM has now been installed."); 197 println("To use dvm, you may need to open a new command prompt."); 198 } 199 }