5 // Tood Berman <tberman@gentoo.org>
6 // Jackson Harper <jackson@ximian.com>
8 // Copyright 2003 Todd Berman
9 // Copyright 2004 Novell, Inc (http://www.novell.com)
16 using System.Reflection;
17 using System.Collections;
18 using System.Globalization;
19 using System.Runtime.InteropServices;
23 namespace Mono.Tools {
27 private enum Command {
36 public static int Main (string [] args)
41 Command command = GetCommand (args [0]);
43 if (command == Command.Unknown && IsSwitch (args [0])) {
44 Console.WriteLine ("Unknown command: " + args [0]);
46 } else if (command == Command.Unknown) {
48 } else if (command == Command.Help) {
53 string libdir = GetLibDir ();
54 string name, package, gacdir, root;
55 name = package = root = gacdir = null;
57 for (int i=1; i<args.Length; i++) {
58 if (IsSwitch (args [i])) {
60 // for cmd line compatibility with other gacutils
61 if (args [i] == "-f" || args [i] == "/f")
64 if (i + 1 >= args.Length) {
65 Console.WriteLine ("Option " + args [i] + " takes 1 argument");
92 gacdir = GetGacDir ();
94 gacdir = Path.Combine (Path.Combine (gacdir, "mono"), "gac");
96 string link_gacdir = gacdir;
98 libdir = Path.Combine (Path.Combine (root, gacdir), "mono");
99 gacdir = Path.Combine (libdir, "gac");
103 case Command.Install:
105 Console.WriteLine ("Option " + args [0] + " takes 1 argument");
106 Environment.Exit (1);
108 Install (name, package, gacdir, link_gacdir, libdir);
110 case Command.Uninstall:
112 Console.WriteLine ("Option " + args [0] + " takes 1 argument");
113 Environment.Exit (1);
115 Uninstall (name, package, gacdir, libdir);
117 case Command.UninstallSpecific:
119 Console.WriteLine ("Opetion " + args [0] + " takes 1 argument");
120 Environment.Exit (1);
122 UninstallSpecific (name, package, gacdir, libdir);
132 private static void Install (string name, string package,
133 string gacdir, string link_gacdir, string libdir)
135 string failure_msg = "Failure adding assembly to the cache: ";
137 if (!File.Exists (name)) {
138 Console.WriteLine (failure_msg + "The system cannot find the file specified.");
139 Environment.Exit (1);
142 AssemblyName an = null;
146 an = AssemblyName.GetAssemblyName (name);
148 Console.WriteLine (failure_msg + "The file specified is not a valid assembly.");
149 Environment.Exit (1);
152 pub_tok = an.GetPublicKeyToken ();
153 if (pub_tok == null || pub_tok.Length == 0) {
154 Console.WriteLine (failure_msg + "Attempt to install an assembly without a strong name.");
155 Environment.Exit (1);
158 string conf_name = name + ".config";
159 string version_token = an.Version + "_" +
160 an.CultureInfo.Name.ToLower (CultureInfo.InvariantCulture) + "_" +
161 GetStringToken (pub_tok);
162 string full_path = Path.Combine (Path.Combine (gacdir, an.Name), version_token);
163 string asmb_file = Path.GetFileName (name);
164 string asmb_path = Path.Combine (full_path, asmb_file);
167 if (Directory.Exists (full_path)) {
168 // Wipe out the directory. This way we ensure old assemblies
169 // config files, and AOTd files are removed.
170 Directory.Delete (full_path, true);
172 Directory.CreateDirectory (full_path);
174 Console.WriteLine (failure_msg + "gac directories could not be created, " +
175 "possibly permission issues.");
176 // Environment.Exit (1);
180 File.Copy (name, asmb_path, true);
181 if (File.Exists (conf_name))
182 File.Copy (conf_name, asmb_path + ".config", true);
184 if (package != null) {
185 string link_path = Path.Combine (Path.Combine (link_gacdir,an.Name), version_token);
186 string ref_dir = Path.Combine (libdir, package);
187 string ref_path = Path.Combine (ref_dir, asmb_file);
188 if (File.Exists (ref_path))
189 File.Delete (ref_path);
191 Directory.CreateDirectory (ref_dir);
193 Console.WriteLine ("ERROR: Could not create package dir file.");
194 Environment.Exit (1);
196 Symlink (Path.Combine (link_path, asmb_file), ref_path);
197 Console.WriteLine ("Package exported to: " + Path.Combine (libdir, package));
200 Console.WriteLine ("{0} installed into the gac ({1})", an.Name, gacdir);
203 private static void Uninstall (string name, string package, string gacdir, string libdir)
205 string [] assembly_pieces = name.Split (new char[] { ',' });
206 Hashtable asm_info = new Hashtable ();
208 foreach (string item in assembly_pieces) {
209 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
210 if(pieces.Length == 1)
211 asm_info ["assembly"] = pieces [0];
213 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
216 string asmdir = Path.Combine (gacdir, (string) asm_info ["assembly"]);
217 if (!Directory.Exists (asmdir)) {
218 Console.WriteLine ("No assemblies found that match: " + name);
219 Environment.Exit (1);
222 string searchString = GetSearchString (asm_info);
223 string [] directories = Directory.GetDirectories (asmdir, searchString);
225 foreach (string dir in directories) {
226 Directory.Delete (dir, true);
227 if (package != null) {
228 string link_dir = Path.Combine (libdir, package);
229 string link = Path.Combine (link_dir, (string) asm_info ["assembly"] + ".dll");
231 if (Directory.GetFiles (link_dir).Length == 0) {
232 Console.WriteLine ("Cleaning package directory, it is empty.");
233 Directory.Delete (link_dir);
236 Console.WriteLine ("Assembly removed from the gac.");
239 if(Directory.GetDirectories (asmdir).Length == 0) {
240 Console.WriteLine ("Cleaning assembly dir, its empty");
241 Directory.Delete (asmdir);
245 private static void UninstallSpecific (string name, string package,
246 string gacdir, string libdir)
248 string failure_msg = "Failure to remove assembly from the cache: ";
250 if (!File.Exists (name)) {
251 Console.WriteLine (failure_msg + "The system cannot find the file specified.");
252 Environment.Exit (1);
255 AssemblyName an = null;
258 an = AssemblyName.GetAssemblyName (name);
260 Console.WriteLine (failure_msg + "The file specified is not a valid assembly.");
261 Environment.Exit (1);
264 Uninstall (an.FullName.Replace (" ", String.Empty),
265 package, gacdir, libdir);
268 private static void List (string name, string gacdir)
270 Console.WriteLine ("The following assemblies are installed into the GAC:");
273 FilteredList (name, gacdir);
278 DirectoryInfo gacinfo = new DirectoryInfo (gacdir);
279 foreach (DirectoryInfo parent in gacinfo.GetDirectories ()) {
280 foreach (DirectoryInfo dir in parent.GetDirectories ()) {
281 Console.WriteLine (AsmbNameFromVersionString (parent.Name, dir.Name));
285 Console.WriteLine ("Number of items = " + count);
288 private static void FilteredList (string name, string gacdir)
290 string [] assembly_pieces = name.Split (new char[] { ',' });
291 Hashtable asm_info = new Hashtable ();
293 foreach (string item in assembly_pieces) {
294 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
295 if(pieces.Length == 1)
296 asm_info ["assembly"] = pieces [0];
298 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
301 string asmdir = Path.Combine (gacdir, (string) asm_info ["assembly"]);
302 if (!Directory.Exists (asmdir)) {
303 Console.WriteLine ("Number of items = 0");
306 string search = GetSearchString (asm_info);
307 string [] dir_list = Directory.GetDirectories (asmdir, search);
310 foreach (string dir in dir_list) {
311 Console.WriteLine (AsmbNameFromVersionString ((string) asm_info ["assembly"],
312 new DirectoryInfo (dir).Name));
315 Console.WriteLine ("Number of items = " + count);
318 private static string GetSearchString (Hashtable asm_info)
320 if (asm_info.Keys.Count == 1)
322 string version, culture, token;
324 version = asm_info ["version"] as string;
325 version = (version == null ? "*" : version);
326 culture = asm_info ["culture"] as string;
327 culture = (culture == null ? "*" : culture.ToLower (CultureInfo.InvariantCulture));
328 token = asm_info ["publickeytoken"] as string;
329 token = (token == null ? "*" : token.ToLower (CultureInfo.InvariantCulture));
331 return String.Format ("{0}_{1}_{2}", version, culture, token);
334 private static string AsmbNameFromVersionString (string name, string str)
336 string [] pieces = str.Split ('_');
337 return String.Format ("{0}, Version={1}, Culture={2}, PublicKeyToken={3}",
338 name, pieces [0], (pieces [1] == String.Empty ? "neutral" : pieces [1]),
342 private static bool IsSwitch (string arg)
344 return (arg [0] == '-' || (arg [0] == '/' && !File.Exists (arg)));
347 private static Command GetCommand (string arg)
349 Command c = Command.Unknown;
361 c = Command.Uninstall;
365 case "--uninstall-specific":
366 c = Command.UninstallSpecific;
382 private static void Symlink (string oldpath, string newpath) {
383 if (Path.DirectorySeparatorChar == '/') {
384 symlink (oldpath, newpath);
386 File.Copy (oldpath, newpath);
390 [DllImport ("libc", SetLastError=true)]
391 public static extern int symlink (string oldpath, string newpath);
393 private static string GetGacDir () {
394 PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath",
395 BindingFlags.Static|BindingFlags.NonPublic);
397 Console.WriteLine ("ERROR: Mono runtime not detected, please use " +
398 "the mono runtime for gacutil.exe");
399 Environment.Exit (1);
401 MethodInfo get_gac = gac.GetGetMethod (true);
402 return (string) get_gac.Invoke (null, null);
405 private static string GetLibDir () {
406 MethodInfo libdir = typeof (System.Environment).GetMethod ("internalGetGacPath",
407 BindingFlags.Static|BindingFlags.NonPublic);
408 if (libdir == null) {
409 Console.WriteLine ("ERROR: Mono runtime not detected, please use " +
410 "the mono runtime for gacutil.exe");
411 Environment.Exit (1);
413 return Path.Combine ((string)libdir.Invoke (null, null), "mono");
416 private static string GetStringToken (byte[] tok)
418 StringBuilder sb = new StringBuilder ();
419 for (int i = 0; i < tok.Length ; i++)
420 sb.Append (tok[i].ToString ("x2"));
421 return sb.ToString ();
424 private static void Usage ()
427 Environment.Exit (1);
430 private static void ShowHelp (bool detailed)
432 Console.WriteLine ("Usage: gacutil.exe <commands> [ <options> ]");
433 Console.WriteLine ("Commands:");
435 Console.WriteLine ("-i <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
436 Console.WriteLine ("\tInstalls an assembly into the global assembly cache.");
438 Console.WriteLine ("\t<assembly_path> is the name of the file that contains the " +
439 "\tassembly manifest\n" +
440 "\tExample: -i myDll.dll");
442 Console.WriteLine ();
444 Console.WriteLine ("-u <assembly_display_name> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
445 Console.WriteLine ("\tUninstalls an assembly from the global assembly cache.");
447 Console.WriteLine ("\t<assembly_display_name> is the name of the assembly (partial or\n" +
448 "\tfully qualified) to remove from the global assembly cache. If a \n" +
449 "\tpartial name is specified all matching assemblies will be uninstalled.\n" +
450 "\tExample: -u myDll,Version=1.2.1.0");
452 Console.WriteLine ();
454 Console.WriteLine ("-us <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
455 Console.WriteLine ("\tUninstalls an assembly using the specifed assemblies full name.");
457 Console.WriteLine ("\t<assembly path> is the path to an assembly. The full assembly name\n" +
458 "\tis retrieved from the specified assembly if there is an assembly in\n" +
459 "\tthe GAC with a matching name, it is removed.\n" +
460 "\tExample: -us myDll.dll");
462 Console.WriteLine ();
464 Console.WriteLine ("-l [assembly_name] [-root ROOTDIR] [-gacdir GACDIR]");
465 Console.WriteLine ("\tLists the contents of the global assembly cache.");
467 Console.WriteLine ("\tWhen the <assembly_name> parameter is specified only matching\n" +
468 "\tassemblies are listed.");
470 Console.WriteLine ();
472 Console.WriteLine ("-?");
473 Console.WriteLine ("\tDisplays a detailed help screen\n");
474 Console.WriteLine ();
479 Console.WriteLine ("Options:");
480 Console.WriteLine ("-package <NAME>");
481 Console.WriteLine ("Used to create a directory in prefix/lib/mono with the name NAME, and a\n" +
482 "\tsymlink is created from NAME/assembly_name to the assembly on the GAC.\n" +
483 "\tThis is used so developers can reference a set of libraries at once.");
484 Console.WriteLine ();
486 Console.WriteLine ("-gacdir <GACDIR>");
487 Console.WriteLine ("Used to specify the GACs base directory. Once an assembly has been installed\n" +
488 "\tto a non standard gacdir the MONO_GAC_PATH environment variable must be used\n" +
489 "\tto access the assembly.");
490 Console.WriteLine ();
492 Console.WriteLine ("-root <ROOTDIR>");
493 Console.WriteLine ("\tUsed by developers integrating this with automake tools or packaging tools\n" +
494 "\tthat require a prefix directory to be specified. The root represents the\n" +
495 "\t\"libdir\" component of a prefix (typically prefix/lib).");