1 /**
2  * Copyright: Copyright (c) 2011 Nick Sabalausky. All rights reserved.
3  * Authors: Nick Sabalausky
4  * Version: Initial created: Jun 4, 2011
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dvm.util.DvmRegistry;
8 
9 version (Windows):
10 
11 /// DVM-Specific Registry Utilities
12 
13 import tango.io.Console;
14 import tango.io.Stdout;
15 import tango.text.Unicode;
16 
17 import Path = dvm.io.Path;
18 import dvm.io.Console;
19 import dvm.util.Registry;
20 import dvm.util.Windows;
21 import dvm.util.Util;
22 
23 private string dvmEnvVar = "DVM";
24 
25 void updateEnvironment (string binDir, string dmdDir="")
26 {
27     string dvmEnvVarExpand = "%"~dvmEnvVar~"%";
28     binDir = Path.native(binDir.dup);
29     dmdDir = Path.native(dmdDir.dup);
30     string dvmEnvValue = (dmdDir == "")? binDir : dmdDir~";"~binDir;
31 
32     scope envKey = new RegistryKey(RegRoot.HKEY_CURRENT_USER, "Environment");
33     envKey.setValue(dvmEnvVar, dvmEnvValue);
34 
35     if (envKey.valueExists("PATH"))
36     {
37         auto path = envKey.getValue("PATH");
38 
39         if (path.type != RegValueType.SZ && path.type != RegValueType.EXPAND_SZ)
40             throw new RegistryException(envKey.toString ~ `\PATH`, false, "Expected type REG_SZ or REG_EXPAND_SZ, not " ~ dvm.util.Registry.toString(path.type));
41 
42         if (!path.asString.contains(dvmEnvVarExpand))
43             envKey.setValueExpand("PATH", dvmEnvVarExpand ~ ";" ~ path.asString);
44     }
45 
46     else
47         envKey.setValueExpand("PATH", dvmEnvVarExpand);
48 }
49 
50 /// Returns empty string if there's no default compiler
51 string getDefaultCompilerPath()
52 {
53     scope envKeyRead = new RegistryKey(RegRoot.HKEY_CURRENT_USER, "Environment", RegKeyOpenMode.Open, RegKeyAccess.Read);
54     if (envKeyRead.valueExists(dvmEnvVar))
55     {
56         auto pathValue = envKeyRead.getValue(dvmEnvVar);
57 
58         if (pathValue.type == RegValueType.SZ || pathValue.type == RegValueType.EXPAND_SZ)
59         {
60             auto bothPaths = pathValue.asString;
61             auto sepIndex = bothPaths.indexOf(";");
62 
63             if (sepIndex < sepIndex.max)
64                 return bothPaths[0..sepIndex];
65         }
66     }
67 
68     return "";
69 }
70 
71 bool isDMDDir(string path)
72 {
73     path = expandEnvironmentStrings(path);
74 
75     foreach (singlePath; split(path, ";"))
76     {
77         Path.native(singlePath);
78         if (singlePath.length != 0 && singlePath[$-1] != '\\')
79             singlePath ~= '\\';
80 
81         if (Path.exists(singlePath) && Path.isFolder(singlePath))
82         {
83             if ( (Path.exists(singlePath~"dmd.exe") && Path.isFile(singlePath~"dmd.exe")) ||
84                  (Path.exists(singlePath~"dmd.bat") && Path.isFile(singlePath~"dmd.bat")) )
85                 return true;
86         }
87     }
88 
89     return false;
90 }
91 
92 void checkSystemPath()
93 {
94     auto envKeyPath = `SYSTEM\CurrentControlSet\Control\Session Manager\Environment`;
95     scope envKeyRead = new RegistryKey(RegRoot.HKEY_LOCAL_MACHINE, envKeyPath, RegKeyOpenMode.Open, RegKeyAccess.Read);
96     if (envKeyRead.valueExists("PATH"))
97     {
98         auto pathValue = envKeyRead.getValue("PATH");
99 
100         if (pathValue.type != RegValueType.SZ && pathValue.type != RegValueType.EXPAND_SZ)
101             throw new RegistryException(envKeyRead.toString ~ `\PATH`, false, "Expected type REG_SZ or REG_EXPAND_SZ, not " ~ dvm.util.Registry.toString(pathValue.type));
102 
103         // Check each path
104         string[] pathsWithDMD;
105         string[] pathsWithoutDMD;
106         foreach (path; split(pathValue.asString, ";"))
107         {
108             if(isDMDDir(path))
109                 pathsWithDMD ~= path;
110             else
111                 pathsWithoutDMD ~= path;
112         }
113 
114         // DMD found in system PATH?
115         if (pathsWithDMD.length > 0)
116         {
117             println("Your system PATH appears to already contain DMD:");
118 
119             foreach (path; pathsWithDMD)
120                 println("  ", path);
121 
122             println("");
123             println("The above path(s) must be removed from your system PATH or else DVM won't");
124             println("be able to set your \"default\" compiler. (However, you can still use DVM");
125             println("to set your \"current\" compiler.)");
126             println("");
127             println("Would you like DVM to automatically remove those existing DMD entries from");
128             println("your system path? (If 'yes', this will affect ALL USERS on this computer.)");
129             println("");
130 
131             bool shouldRemoveDMD = promptYesNo();
132 
133             // Remove DMD paths from system PATH?
134             if (shouldRemoveDMD)
135             {
136                 string newValue = "";
137                 foreach (path; pathsWithoutDMD)
138                 {
139                     if (newValue != "")
140                         newValue ~= ';';
141 
142                     newValue ~= path;
143                 }
144 
145                 try
146                 {
147                     scope envKeyRW = new RegistryKey(RegRoot.HKEY_LOCAL_MACHINE, envKeyPath);
148                     envKeyRW.setValueExpand("PATH", newValue);
149                 }
150                 catch(Exception e)
151                 {
152                     println("DVM was unable to edit your system PATH.");
153                     println("(Maybe you don't have sufficient privileges?)");
154                     println("");
155                     println("You'll have to remove the DMD from your system PATH manually,");
156                     println("or contact your system administrator.");
157                     println("");
158                 }
159             }
160         }
161     }
162 }