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