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 ();
93 libdir = GetLibDir ();
95 libdir = Path.Combine (gacdir, "mono");
96 gacdir = Path.Combine (libdir, "gac");
99 string link_gacdir = gacdir;
101 libdir = Path.Combine (root, gacdir);
102 gacdir = Path.Combine (root, libdir);
106 case Command.Install:
108 Console.WriteLine ("Option " + args [0] + " takes 1 argument");
109 Environment.Exit (1);
111 Install (name, package, gacdir, link_gacdir, libdir);
113 case Command.Uninstall:
115 Console.WriteLine ("Option " + args [0] + " takes 1 argument");
116 Environment.Exit (1);
118 Uninstall (name, package, gacdir, libdir);
120 case Command.UninstallSpecific:
122 Console.WriteLine ("Opetion " + args [0] + " takes 1 argument");
123 Environment.Exit (1);
125 UninstallSpecific (name, package, gacdir, libdir);
135 private static void Install (string name, string package,
136 string gacdir, string link_gacdir, string libdir)
138 string failure_msg = "Failure adding assembly to the cache: ";
140 if (!File.Exists (name)) {
141 Console.WriteLine (failure_msg + "The system cannot find the file specified.");
142 Environment.Exit (1);
145 AssemblyName an = null;
149 an = AssemblyName.GetAssemblyName (name);
151 Console.WriteLine (failure_msg + "The file specified is not a valid assembly.");
152 Environment.Exit (1);
155 pub_tok = an.GetPublicKeyToken ();
156 if (pub_tok == null || pub_tok.Length == 0) {
157 Console.WriteLine (failure_msg + "Attempt to install an assembly without a strong name.");
158 Environment.Exit (1);
161 string conf_name = name + ".config";
162 string version_token = an.Version + "_" +
163 an.CultureInfo.Name.ToLower (CultureInfo.InvariantCulture) + "_" +
164 GetStringToken (pub_tok);
165 string full_path = Path.Combine (Path.Combine (gacdir, an.Name), version_token);
166 string asmb_file = Path.GetFileName (name);
167 string asmb_path = Path.Combine (full_path, asmb_file);
170 if (Directory.Exists (full_path)) {
171 // Wipe out the directory. This way we ensure old assemblies
172 // config files, and AOTd files are removed.
173 Directory.Delete (full_path, true);
175 Directory.CreateDirectory (full_path);
177 Console.WriteLine (failure_msg + "gac directories could not be created, " +
178 "possibly permission issues.");
179 // Environment.Exit (1);
183 File.Copy (name, asmb_path, true);
184 if (File.Exists (conf_name))
185 File.Copy (conf_name, asmb_path + ".config", true);
187 if (package != null) {
188 string link_path = Path.Combine (Path.Combine (link_gacdir,an.Name), version_token);
189 string ref_dir = Path.Combine (libdir, package);
190 string ref_path = Path.Combine (ref_dir, asmb_file);
191 if (File.Exists (ref_path))
192 File.Delete (ref_path);
194 Directory.CreateDirectory (ref_dir);
196 Console.WriteLine ("ERROR: Could not create package dir file.");
197 Environment.Exit (1);
199 Symlink (Path.Combine (link_path, asmb_file), ref_path);
200 Console.WriteLine ("Package exported to: " + Path.Combine (libdir, package));
203 Console.WriteLine ("{0} installed into the gac ({1})", an.Name, gacdir);
206 private static void Uninstall (string name, string package, string gacdir, string libdir)
208 string [] assembly_pieces = name.Split (new char[] { ',' });
209 Hashtable asm_info = new Hashtable ();
211 foreach (string item in assembly_pieces) {
212 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
213 if(pieces.Length == 1)
214 asm_info ["assembly"] = pieces [0];
216 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
219 string asmdir = Path.Combine (gacdir, (string) asm_info ["assembly"]);
220 if (!Directory.Exists (asmdir)) {
221 Console.WriteLine ("No assemblies found that match: " + name);
222 Environment.Exit (1);
225 string searchString = GetSearchString (asm_info);
226 string [] directories = Directory.GetDirectories (asmdir, searchString);
228 foreach (string dir in directories) {
229 Directory.Delete (dir, true);
230 if (package != null) {
231 string link_dir = Path.Combine (libdir, package);
232 string link = Path.Combine (link_dir, (string) asm_info ["assembly"] + ".dll");
234 if (Directory.GetFiles (link_dir).Length == 0) {
235 Console.WriteLine ("Cleaning package directory, it is empty.");
236 Directory.Delete (link_dir);
239 Console.WriteLine ("Assembly removed from the gac.");
242 if(Directory.GetDirectories (asmdir).Length == 0) {
243 Console.WriteLine ("Cleaning assembly dir, its empty");
244 Directory.Delete (asmdir);
248 private static void UninstallSpecific (string name, string package,
249 string gacdir, string libdir)
251 string failure_msg = "Failure to remove assembly from the cache: ";
253 if (!File.Exists (name)) {
254 Console.WriteLine (failure_msg + "The system cannot find the file specified.");
255 Environment.Exit (1);
258 AssemblyName an = null;
261 an = AssemblyName.GetAssemblyName (name);
263 Console.WriteLine (failure_msg + "The file specified is not a valid assembly.");
264 Environment.Exit (1);
267 Uninstall (an.FullName.Replace (" ", String.Empty),
268 package, gacdir, libdir);
271 private static void List (string name, string gacdir)
273 Console.WriteLine ("The following assemblies are installed into the GAC:");
276 FilteredList (name, gacdir);
281 DirectoryInfo gacinfo = new DirectoryInfo (gacdir);
282 foreach (DirectoryInfo parent in gacinfo.GetDirectories ()) {
283 foreach (DirectoryInfo dir in parent.GetDirectories ()) {
284 Console.WriteLine (AsmbNameFromVersionString (parent.Name, dir.Name));
288 Console.WriteLine ("Number of items = " + count);
291 private static void FilteredList (string name, string gacdir)
293 string [] assembly_pieces = name.Split (new char[] { ',' });
294 Hashtable asm_info = new Hashtable ();
296 foreach (string item in assembly_pieces) {
297 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
298 if(pieces.Length == 1)
299 asm_info ["assembly"] = pieces [0];
301 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
304 string asmdir = Path.Combine (gacdir, (string) asm_info ["assembly"]);
305 if (!Directory.Exists (asmdir)) {
306 Console.WriteLine ("Number of items = 0");
309 string search = GetSearchString (asm_info);
310 string [] dir_list = Directory.GetDirectories (asmdir, search);
313 foreach (string dir in dir_list) {
314 Console.WriteLine (AsmbNameFromVersionString ((string) asm_info ["assembly"],
315 new DirectoryInfo (dir).Name));
318 Console.WriteLine ("Number of items = " + count);
321 private static string GetSearchString (Hashtable asm_info)
323 if (asm_info.Keys.Count == 1)
325 string version, culture, token;
327 version = asm_info ["version"] as string;
328 version = (version == null ? "*" : version);
329 culture = asm_info ["culture"] as string;
330 culture = (culture == null ? "*" : culture.ToLower (CultureInfo.InvariantCulture));
331 token = asm_info ["publickeytoken"] as string;
332 token = (token == null ? "*" : token.ToLower (CultureInfo.InvariantCulture));
334 return String.Format ("{0}_{1}_{2}", version, culture, token);
337 private static string AsmbNameFromVersionString (string name, string str)
339 string [] pieces = str.Split ('_');
340 return String.Format ("{0}, Version={1}, Culture={2}, PublicKeyToken={3}",
341 name, pieces [0], (pieces [1] == String.Empty ? "neutral" : pieces [1]),
345 private static bool IsSwitch (string arg)
347 return (arg [0] == '-' || (arg [0] == '/' && !File.Exists (arg)));
350 private static Command GetCommand (string arg)
352 Command c = Command.Unknown;
364 c = Command.Uninstall;
368 case "--uninstall-specific":
369 c = Command.UninstallSpecific;
385 private static void Symlink (string oldpath, string newpath) {
386 if (Path.DirectorySeparatorChar == '/') {
387 symlink (oldpath, newpath);
389 File.Copy (oldpath, newpath);
393 [DllImport ("libc", SetLastError=true)]
394 public static extern int symlink (string oldpath, string newpath);
396 private static string GetGacDir () {
397 PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath",
398 BindingFlags.Static|BindingFlags.NonPublic);
400 Console.WriteLine ("ERROR: Mono runtime not detected, please use " +
401 "the mono runtime for gacutil.exe");
402 Environment.Exit (1);
404 MethodInfo get_gac = gac.GetGetMethod (true);
405 return (string) get_gac.Invoke (null, null);
408 private static string GetLibDir () {
409 MethodInfo libdir = typeof (System.Environment).GetMethod ("internalGetGacPath",
410 BindingFlags.Static|BindingFlags.NonPublic);
411 if (libdir == null) {
412 Console.WriteLine ("ERROR: Mono runtime not detected, please use " +
413 "the mono runtime for gacutil.exe");
414 Environment.Exit (1);
416 return Path.Combine ((string)libdir.Invoke (null, null), "mono");
419 private static string GetStringToken (byte[] tok)
421 StringBuilder sb = new StringBuilder ();
422 for (int i = 0; i < tok.Length ; i++)
423 sb.Append (tok[i].ToString ("x2"));
424 return sb.ToString ();
427 private static void Usage ()
430 Environment.Exit (1);
433 private static void ShowHelp (bool detailed)
435 Console.WriteLine ("Usage: gacutil.exe <commands> [ <options> ]");
436 Console.WriteLine ("Commands:");
438 Console.WriteLine ("-i <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
439 Console.WriteLine ("\tInstalls an assembly into the global assembly cache.");
441 Console.WriteLine ("\t<assembly_path> is the name of the file that contains the " +
442 "\tassembly manifest\n" +
443 "\tExample: -i myDll.dll");
445 Console.WriteLine ();
447 Console.WriteLine ("-u <assembly_display_name> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
448 Console.WriteLine ("\tUninstalls an assembly from the global assembly cache.");
450 Console.WriteLine ("\t<assembly_display_name> is the name of the assembly (partial or\n" +
451 "\tfully qualified) to remove from the global assembly cache. If a \n" +
452 "\tpartial name is specified all matching assemblies will be uninstalled.\n" +
453 "\tExample: -u myDll,Version=1.2.1.0");
455 Console.WriteLine ();
457 Console.WriteLine ("-us <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
458 Console.WriteLine ("\tUninstalls an assembly using the specifed assemblies full name.");
460 Console.WriteLine ("\t<assembly path> is the path to an assembly. The full assembly name\n" +
461 "\tis retrieved from the specified assembly if there is an assembly in\n" +
462 "\tthe GAC with a matching name, it is removed.\n" +
463 "\tExample: -us myDll.dll");
465 Console.WriteLine ();
467 Console.WriteLine ("-l [assembly_name] [-root ROOTDIR] [-gacdir GACDIR]");
468 Console.WriteLine ("\tLists the contents of the global assembly cache.");
470 Console.WriteLine ("\tWhen the <assembly_name> parameter is specified only matching\n" +
471 "\tassemblies are listed.");
473 Console.WriteLine ();
475 Console.WriteLine ("-?");
476 Console.WriteLine ("\tDisplays a detailed help screen\n");
477 Console.WriteLine ();
482 Console.WriteLine ("Options:");
483 Console.WriteLine ("-package <NAME>");
484 Console.WriteLine ("Used to create a directory in prefix/lib/mono with the name NAME, and a\n" +
485 "\tsymlink is created from NAME/assembly_name to the assembly on the GAC.\n" +
486 "\tThis is used so developers can reference a set of libraries at once.");
487 Console.WriteLine ();
489 Console.WriteLine ("-gacdir <GACDIR>");
490 Console.WriteLine ("Used to specify the GACs base directory. Once an assembly has been installed\n" +
491 "\tto a non standard gacdir the MONO_GAC_PATH environment variable must be used\n" +
492 "\tto access the assembly.");
493 Console.WriteLine ();
495 Console.WriteLine ("-root <ROOTDIR>");
496 Console.WriteLine ("\tUsed by developers integrating this with automake tools or packaging tools\n" +
497 "\tthat require a prefix directory to be specified. The root represents the\n" +
498 "\t\"libdir\" component of a prefix (typically prefix/lib).");