2010-04-03 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / gacutil / driver.cs
blob68a44c753b08c50c9cd98b753de1d4909437ae51
1 //
2 // Mono.Tools.GacUtil
3 //
4 // Author(s):
5 // Todd Berman <tberman@sevenl.net>
6 // Jackson Harper <jackson@ximian.com>
7 //
8 // Copyright 2003, 2004 Todd Berman
9 // Copyright 2004 Novell, Inc (http://www.novell.com)
13 using System;
14 using System.IO;
15 using System.Diagnostics;
16 using System.Text;
17 using System.Reflection;
18 using System.Collections;
19 using System.Globalization;
20 using System.Runtime.InteropServices;
21 using System.Security.Cryptography;
23 using Mono.Security;
24 using Mono.Security.Cryptography;
26 namespace Mono.Tools {
28 public class Driver {
30 private enum Command {
31 Unknown,
32 Install,
33 InstallFromList,
34 Uninstall,
35 UninstallFromList,
36 UninstallSpecific,
37 List,
38 Help
41 private enum VerificationResult
43 StrongNamed,
44 WeakNamed,
45 DelaySigned,
46 Skipped
49 private static bool silent;
50 static bool in_bootstrap;
52 public static int Main (string [] args)
54 if (args.Length == 0)
55 Usage ();
57 Command command = Command.Unknown;
58 string command_str = null;
60 string libdir;
61 string name, package, gacdir, root;
62 name = package = root = gacdir = null;
63 bool check_refs = false;
65 // Check for silent arg first so we can suppress
66 // warnings during command line parsing
67 if (Array.IndexOf (args, "/silent") > -1 || Array.IndexOf (args, "-silent") > -1)
68 silent = true;
70 for (int i=0; i<args.Length; i++) {
71 if (IsSwitch (args [i])) {
73 // for cmd line compatibility with other gacutils
74 // we always force it though
75 if (args [i] == "-f" || args [i] == "/f")
76 continue;
78 // Ignore this option for now, although we might implement it someday
79 if (args [i] == "/r") {
80 WriteLine ("WARNING: gacutil does not support traced references." +
81 "This option is being ignored.");
82 i += 3;
83 continue;
86 // This is already handled we just dont want to choke on it
87 if (args [i] == "-silent" || args [i] == "/silent")
88 continue;
90 if (args [i] == "-check_refs" || args [i] == "/check_refs") {
91 check_refs = true;
92 continue;
95 if (args [i] == "-bootstrap" || args [i] == "/bootstrap") {
96 in_bootstrap = true;
97 continue;
100 if (command == Command.Unknown) {
101 command = GetCommand (args [i]);
102 if (command != Command.Unknown) {
103 command_str = args [i];
104 continue;
108 if (i + 1 >= args.Length) {
109 Console.WriteLine ("Option " + args [i] + " takes 1 argument");
110 return 1;
113 switch (args [i]) {
114 case "-package":
115 case "/package":
116 package = args [++i];
117 continue;
118 case "-root":
119 case "/root":
120 root = args [++i];
121 continue;
122 case "-gacdir":
123 case "/gacdir":
124 gacdir = args [++i];
125 continue;
126 case "/nologo":
127 case "-nologo":
128 // we currently don't display a
129 // logo banner, so ignore it
130 // for command-line compatibility
131 // with MS gacutil
132 continue;
135 if (name == null)
136 name = args [i];
137 else
138 name += args [i];
141 if (command == Command.Unknown && IsSwitch (args [0])) {
142 Console.WriteLine ("Unknown command: " + args [0]);
143 return 1;
144 } else if (command == Command.Unknown) {
145 Usage ();
146 } else if (command == Command.Help) {
147 ShowHelp (true);
148 return 1;
151 if (gacdir == null) {
152 gacdir = GetGacDir ();
153 libdir = GetLibDir ();
154 } else {
155 gacdir = EnsureLib (gacdir);
156 libdir = Path.Combine (gacdir, "mono");
157 gacdir = Path.Combine (libdir, "gac");
160 string link_gacdir = gacdir;
161 string link_libdir = libdir;
162 if (root != null) {
163 libdir = Path.Combine (root, "mono");
164 gacdir = Path.Combine (libdir, "gac");
167 LoadConfig (silent);
169 switch (command) {
170 case Command.Install:
171 if (name == null) {
172 WriteLine ("Option " + command_str + " takes 1 argument");
173 return 1;
175 if (!Install (check_refs, name, package, gacdir, link_gacdir, libdir, link_libdir))
176 return 1;
177 break;
178 case Command.InstallFromList:
179 if (name == null) {
180 WriteLine ("Option " + command_str + " takes 1 argument");
181 return 1;
183 if (!InstallFromList (check_refs, name, package, gacdir, link_gacdir, libdir, link_libdir))
184 return 1;
185 break;
186 case Command.Uninstall:
187 if (name == null) {
188 WriteLine ("Option " + command_str + " takes 1 argument");
189 return 1;
191 int uninstallCount = 0;
192 int uninstallFailures = 0;
193 Uninstall (name, package, gacdir, libdir, false,
194 ref uninstallCount, ref uninstallFailures);
195 WriteLine ("Assemblies uninstalled = {0}", uninstallCount);
196 WriteLine ("Failures = {0}", uninstallFailures);
197 if (uninstallFailures > 0)
198 return 1;
199 break;
200 case Command.UninstallFromList:
201 if (name == null) {
202 WriteLine ("Option " + command_str + " takes 1 argument");
203 return 1;
205 if (!UninstallFromList (name, package, gacdir, libdir))
206 return 1;
207 break;
208 case Command.UninstallSpecific:
209 if (name == null) {
210 WriteLine ("Option " + command_str + " takes 1 argument");
211 return 1;
213 if (!UninstallSpecific (name, package, gacdir, libdir))
214 return 1;
215 break;
216 case Command.List:
217 List (name, gacdir);
218 break;
221 return 0;
224 static void Copy (string source, string target, bool v)
226 try {
227 File.Delete (target);
228 } catch {}
229 File.Copy (source, target, v);
232 private static bool Install (bool check_refs, string name, string package,
233 string gacdir, string link_gacdir, string libdir, string link_libdir)
235 string failure_msg = "Failure adding assembly {0} to the cache: ";
236 ArrayList resources;
238 if (!File.Exists (name)) {
239 WriteLine (string.Format (failure_msg, name) + "The system cannot find the file specified.");
240 return false;
243 Assembly assembly = null;
244 AssemblyName an = null;
246 try {
247 assembly = Assembly.LoadFrom (name);
248 } catch {
249 WriteLine (string.Format (failure_msg, name) + "The file specified is not a valid assembly.");
250 return false;
253 an = assembly.GetName ();
255 switch (VerifyStrongName (an, name)) {
256 case VerificationResult.StrongNamed:
257 case VerificationResult.Skipped:
258 break;
259 case VerificationResult.WeakNamed:
260 WriteLine (string.Format (failure_msg, name) + "Attempt to install an assembly without a strong name"
261 + (in_bootstrap ? "(continuing anyway)" : string.Empty));
262 if (!in_bootstrap)
263 return false;
264 break;
265 case VerificationResult.DelaySigned:
266 WriteLine (string.Format (failure_msg, name) + "Strong name cannot be verified for delay-signed assembly"
267 + (in_bootstrap ? "(continuing anyway)" : string.Empty));
268 if (!in_bootstrap)
269 return false;
270 break;
273 resources = new ArrayList ();
274 foreach (string res_name in assembly.GetManifestResourceNames ()) {
275 ManifestResourceInfo res_info = assembly.GetManifestResourceInfo (res_name);
277 if ((res_info.ResourceLocation & ResourceLocation.Embedded) == 0) {
278 if (!File.Exists (res_info.FileName)) {
279 WriteLine (string.Format (failure_msg, name) + "The system cannot find resource " + res_info.FileName);
280 return false;
283 resources.Add (res_info);
287 if (check_refs && !CheckReferencedAssemblies (an)) {
288 WriteLine (string.Format (failure_msg, name) +
289 "Attempt to install an assembly that " +
290 "references non strong named assemblies " +
291 "with -check_refs enabled.");
292 return false;
295 string [] siblings = { ".config", ".mdb" };
296 string version_token = an.Version + "_" +
297 an.CultureInfo.Name.ToLower (CultureInfo.InvariantCulture) + "_" +
298 GetStringToken (an.GetPublicKeyToken ());
299 string full_path = Path.Combine (Path.Combine (gacdir, an.Name), version_token);
300 string asmb_file = Path.GetFileName (name);
301 string asmb_path = Path.Combine (full_path, asmb_file);
303 try {
304 if (Directory.Exists (full_path)) {
305 // Wipe out the directory. This way we ensure old assemblies
306 // config files, and AOTd files are removed.
307 Directory.Delete (full_path, true);
309 Directory.CreateDirectory (full_path);
310 } catch {
311 WriteLine (string.Format (failure_msg, name) +
312 "gac directories could not be created, " +
313 "possibly permission issues.");
314 return false;
317 Copy (name, asmb_path, true);
319 foreach (string ext in siblings) {
320 string sibling = String.Concat (name, ext);
321 if (File.Exists (sibling))
322 Copy (sibling, String.Concat (asmb_path, ext), true);
325 foreach (ManifestResourceInfo resource_info in resources) {
326 try {
327 Copy (resource_info.FileName, Path.Combine (full_path, Path.GetFileName (resource_info.FileName)), true);
328 } catch {
329 WriteLine ("ERROR: Could not install resource file " + resource_info.FileName);
330 Environment.Exit (1);
334 if (package != null) {
335 string ref_dir = Path.Combine (libdir, package);
336 string ref_path = Path.Combine (ref_dir, asmb_file);
338 if (File.Exists (ref_path))
339 File.Delete (ref_path);
340 try {
341 Directory.CreateDirectory (ref_dir);
342 } catch {
343 WriteLine ("ERROR: Could not create package dir file.");
344 Environment.Exit (1);
346 if (Path.DirectorySeparatorChar == '/') {
347 string pkg_path = "../gac/" + an.Name + "/" + version_token + "/" + asmb_file;
348 symlink (pkg_path, ref_path);
350 foreach (string ext in siblings) {
351 string sibling = String.Concat (pkg_path, ext);
352 string sref = String.Concat (ref_path, ext);
353 if (File.Exists (sibling))
354 symlink (sibling, sref);
355 else {
356 try {
357 File.Delete (sref);
358 } catch {
359 // Ignore error, just delete files that should not be there.
363 WriteLine ("Package exported to: {0} -> {1}", ref_path, pkg_path);
364 } else {
365 // string link_path = Path.Combine (Path.Combine (link_gacdir, an.Name), version_token);
367 // We can't use 'link_path' here, since it need not be a valid path at the time 'gacutil'
368 // is run, esp. when invoked in a DESTDIR install.
369 Copy (name, ref_path, true);
370 WriteLine ("Package exported to: " + ref_path);
374 WriteLine ("Installed {0} into the gac ({1})", name,
375 gacdir);
377 return true;
380 private static void Uninstall (string name, string package, string gacdir, string libdir, bool listMode, ref int uninstalled, ref int failures)
382 string [] assembly_pieces = name.Split (new char[] { ',' });
383 Hashtable asm_info = new Hashtable ();
385 foreach (string item in assembly_pieces) {
386 if (item == String.Empty) continue;
387 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
388 if(pieces.Length == 1)
389 asm_info ["assembly"] = pieces [0];
390 else
391 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
394 string assembly_name = (string) asm_info ["assembly"];
395 string asmdir = Path.Combine (gacdir, assembly_name);
396 if (!Directory.Exists (asmdir)) {
397 if (listMode) {
398 failures++;
399 WriteLine ("Assembly: " + name);
401 WriteLine ("No assemblies found that match: " + name);
402 return;
405 string searchString = GetSearchString (asm_info);
406 string [] directories = Directory.GetDirectories (asmdir, searchString);
408 if (directories.Length == 0) {
409 if (listMode) {
410 failures++;
411 WriteLine ("Assembly: " + name);
412 WriteLine ("No assemblies found that match: " + name);
414 return;
417 for (int i = 0; i < directories.Length; i++) {
418 if (listMode && i > 0)
419 break;
421 string dir = directories [i];
423 AssemblyName an = AssemblyName.GetAssemblyName (
424 Path.Combine (dir, assembly_name + ".dll"));
425 WriteLine ("Assembly: " + an.FullName);
427 Directory.Delete (dir, true);
428 if (package != null) {
429 string link_dir = Path.Combine (libdir, package);
430 string link = Path.Combine (link_dir, assembly_name + ".dll");
431 try {
432 File.Delete (link);
433 } catch {
434 // The file might not exist, happens with
435 // the debugger on make uninstall
438 if (Directory.GetFiles (link_dir).Length == 0) {
439 WriteLine ("Cleaning package directory, it is empty.");
440 try {
441 Directory.Delete (link_dir);
442 } catch {
443 // Workaround: GetFiles does not list Symlinks
448 uninstalled++;
449 WriteLine ("Uninstalled: " + an.FullName);
452 if (Directory.GetDirectories (asmdir).Length == 0) {
453 WriteLine ("Cleaning assembly dir, it is empty");
454 try {
455 Directory.Delete (asmdir);
456 } catch {
457 // Workaround: GetFiles does not list Symlinks
462 private static bool UninstallSpecific (string name, string package,
463 string gacdir, string libdir)
465 string failure_msg = "Failure to remove assembly from the cache: ";
467 if (!File.Exists (name)) {
468 WriteLine (failure_msg + "The system cannot find the file specified.");
469 return false;
472 AssemblyName an = null;
474 try {
475 an = AssemblyName.GetAssemblyName (name);
476 } catch {
477 WriteLine (failure_msg + "The file specified is not a valid assembly.");
478 return false;
481 int uninstallCount = 0;
482 int uninstallFailures = 0;
483 Uninstall (an.FullName.Replace (" ", String.Empty),
484 package, gacdir, libdir, true, ref uninstallCount,
485 ref uninstallFailures);
486 WriteLine ("Assemblies uninstalled = {0}", uninstallCount);
487 WriteLine ("Failures = {0}", uninstallFailures);
488 return (uninstallFailures == 0);
491 private static void List (string name, string gacdir)
493 WriteLine ("The following assemblies are installed into the GAC:");
495 if (name != null) {
496 FilteredList (name, gacdir);
497 return;
500 int count = 0;
501 DirectoryInfo gacinfo = new DirectoryInfo (gacdir);
502 foreach (DirectoryInfo parent in gacinfo.GetDirectories ()) {
503 foreach (DirectoryInfo dir in parent.GetDirectories ()) {
504 string asmb = Path.Combine (Path.Combine (parent.FullName, dir.Name), parent.Name) + ".dll";
505 if (File.Exists (asmb)) {
506 WriteLine (AsmbNameFromVersionString (parent.Name, dir.Name));
507 count++;
511 WriteLine ("Number of items = " + count);
514 private static void FilteredList (string name, string gacdir)
516 string [] assembly_pieces = name.Split (new char[] { ',' });
517 Hashtable asm_info = new Hashtable ();
519 foreach (string item in assembly_pieces) {
520 string[] pieces = item.Trim ().Split (new char[] { '=' }, 2);
521 if(pieces.Length == 1)
522 asm_info ["assembly"] = pieces [0];
523 else
524 asm_info [pieces[0].Trim ().ToLower (CultureInfo.InvariantCulture)] = pieces [1];
527 string asmdir = Path.Combine (gacdir, (string) asm_info ["assembly"]);
528 if (!Directory.Exists (asmdir)) {
529 WriteLine ("Number of items = 0");
530 return;
532 string search = GetSearchString (asm_info);
533 string [] dir_list = Directory.GetDirectories (asmdir, search);
535 int count = 0;
536 foreach (string dir in dir_list) {
537 string asmb = Path.Combine (dir, (string) asm_info ["assembly"]) + ".dll";
538 if (File.Exists (asmb)) {
539 WriteLine (AsmbNameFromVersionString ((string) asm_info ["assembly"],
540 new DirectoryInfo (dir).Name));
541 count++;
544 WriteLine ("Number of items = " + count);
547 private static bool InstallFromList (bool check_refs, string list_file, string package,
548 string gacdir, string link_gacdir, string libdir, string link_libdir)
550 StreamReader s = null;
551 int processed, failed;
552 string listdir = Path.GetDirectoryName (
553 Path.GetFullPath (list_file));
555 processed = failed = 0;
557 try {
558 s = new StreamReader (list_file);
560 string line;
561 while ((line = s.ReadLine ()) != null) {
562 string file = line.Trim ();
563 if (file.Length == 0)
564 continue;
566 string assemblyPath = Path.Combine (listdir,
567 file);
569 if (!Install (check_refs, assemblyPath, package, gacdir,
570 link_gacdir, libdir, link_libdir))
571 failed++;
572 processed++;
575 WriteLine ("Assemblies processed = {0}", processed);
576 WriteLine ("Assemblies installed = {0}", processed - failed);
577 WriteLine ("Failures = {0}", failed);
579 return (failed == 0);
580 } catch (IOException) {
581 WriteLine ("Failed to open assemblies list file " + list_file + ".");
582 return false;
583 } finally {
584 if (s != null)
585 s.Close ();
589 private static bool UninstallFromList (string list_file, string package,
590 string gacdir, string libdir)
592 StreamReader s = null;
593 int failed, uninstalled;
595 failed = uninstalled = 0;
597 try {
598 s = new StreamReader (list_file);
600 string line;
601 while ((line = s.ReadLine ()) != null) {
602 string name = line.Trim ();
603 if (name.Length == 0)
604 continue;
605 Uninstall (line, package, gacdir, libdir,
606 true, ref uninstalled, ref failed);
609 WriteLine ("Assemblies processed = {0}", uninstalled+failed);
610 WriteLine ("Assemblies uninstalled = {0}", uninstalled);
611 WriteLine ("Failures = {0}", failed);
613 return (failed == 0);
614 } catch (IOException) {
615 WriteLine ("Failed to open assemblies list file " + list_file + ".");
616 return false;
617 } finally {
618 if (s != null)
619 s.Close ();
623 private static bool CheckReferencedAssemblies (AssemblyName an)
625 AppDomain d = null;
626 try {
627 Assembly a = Assembly.LoadFrom (an.CodeBase);
628 AssemblyName corlib = typeof (object).Assembly.GetName ();
630 foreach (AssemblyName ref_an in a.GetReferencedAssemblies ()) {
631 if (ref_an.Name == corlib.Name) // Just do a string compare so we can install on diff versions
632 continue;
633 byte [] pt = ref_an.GetPublicKeyToken ();
634 if (pt == null || pt.Length == 0) {
635 WriteLine ("Assembly " + ref_an.Name + " is not strong named.");
636 return false;
639 } catch (Exception e) {
640 WriteLine (e.ToString ()); // This should be removed pre beta3
641 return false;
642 } finally {
643 if (d != null) {
644 try {
645 AppDomain.Unload (d);
646 } catch { }
650 return true;
653 private static string GetSearchString (Hashtable asm_info)
655 if (asm_info.Keys.Count == 1)
656 return "*";
657 string version, culture, token;
659 version = asm_info ["version"] as string;
660 version = (version == null ? "*" : version + "*");
661 culture = asm_info ["culture"] as string;
662 culture = (culture == null ? "*" : (culture == "neutral") ? String.Empty : culture.ToLower (CultureInfo.InvariantCulture));
663 token = asm_info ["publickeytoken"] as string;
664 token = (token == null ? "*" : token.ToLower (CultureInfo.InvariantCulture));
666 return String.Format ("{0}_{1}_{2}", version, culture, token);
669 private static string AsmbNameFromVersionString (string name, string str)
671 string [] pieces = str.Split ('_');
672 return String.Format ("{0}, Version={1}, Culture={2}, PublicKeyToken={3}",
673 name, pieces [0], (pieces [1] == String.Empty ? "neutral" : pieces [1]),
674 pieces [2]);
677 static bool LoadConfig (bool quiet)
679 MethodInfo config = typeof (System.Environment).GetMethod ("GetMachineConfigPath",
680 BindingFlags.Static | BindingFlags.NonPublic);
682 if (config != null) {
683 string path = (string) config.Invoke (null, null);
685 bool exist = File.Exists (path);
686 if (!quiet && !exist)
687 Console.WriteLine ("Couldn't find machine.config");
689 StrongNameManager.LoadConfig (path);
690 return exist;
691 } else if (!quiet)
692 Console.WriteLine ("Couldn't resolve machine.config location (corlib issue)");
694 // default CSP
695 return false;
698 // modified copy from sn
699 private static VerificationResult VerifyStrongName (AssemblyName an, string assemblyFile)
701 byte [] publicKey = StrongNameManager.GetMappedPublicKey (an.GetPublicKeyToken ());
702 if ((publicKey == null) || (publicKey.Length < 12)) {
703 // no mapping
704 publicKey = an.GetPublicKey ();
705 if ((publicKey == null) || (publicKey.Length < 12))
706 return VerificationResult.WeakNamed;
709 // Note: MustVerify is based on the original token (by design). Public key
710 // remapping won't affect if the assembly is verified or not.
711 if (StrongNameManager.MustVerify (an)) {
712 RSA rsa = CryptoConvert.FromCapiPublicKeyBlob (publicKey, 12);
713 StrongName sn = new StrongName (rsa);
714 if (sn.Verify (assemblyFile)) {
715 return VerificationResult.StrongNamed;
716 } else {
717 return VerificationResult.DelaySigned;
719 } else {
720 return VerificationResult.Skipped;
724 private static bool IsSwitch (string arg)
726 return (arg [0] == '-' || (arg [0] == '/' && !arg.EndsWith(".dll") && arg.IndexOf('/', 1) < 0 ) );
729 private static Command GetCommand (string arg)
731 Command c = Command.Unknown;
733 switch (arg) {
734 case "-i":
735 case "/i":
736 case "--install":
737 c = Command.Install;
738 break;
739 case "-il":
740 case "/il":
741 case "--install-from-list":
742 c = Command.InstallFromList;
743 break;
744 case "-u":
745 case "/u":
746 case "/uf":
747 case "--uninstall":
748 c = Command.Uninstall;
749 break;
750 case "-ul":
751 case "/ul":
752 case "--uninstall-from-list":
753 c = Command.UninstallFromList;
754 break;
755 case "-us":
756 case "/us":
757 case "--uninstall-specific":
758 c = Command.UninstallSpecific;
759 break;
760 case "-l":
761 case "/l":
762 case "--list":
763 c = Command.List;
764 break;
765 case "-?":
766 case "/?":
767 case "--help":
768 c = Command.Help;
769 break;
771 return c;
774 [DllImport ("libc", SetLastError=true)]
775 public static extern int symlink (string oldpath, string newpath);
777 private static string GetGacDir () {
778 PropertyInfo gac = typeof (System.Environment).GetProperty ("GacPath",
779 BindingFlags.Static|BindingFlags.NonPublic);
780 if (gac == null) {
781 WriteLine ("ERROR: Mono runtime not detected, please use " +
782 "the mono runtime for gacutil.exe");
783 Environment.Exit (1);
785 MethodInfo get_gac = gac.GetGetMethod (true);
786 return (string) get_gac.Invoke (null, null);
789 private static string GetLibDir () {
790 MethodInfo libdir = typeof (System.Environment).GetMethod ("internalGetGacPath",
791 BindingFlags.Static|BindingFlags.NonPublic);
792 if (libdir == null) {
793 WriteLine ("ERROR: Mono runtime not detected, please use " +
794 "the mono runtime for gacutil.exe");
795 Environment.Exit (1);
797 return Path.Combine ((string)libdir.Invoke (null, null), "mono");
800 private static string GetStringToken (byte[] tok)
802 StringBuilder sb = new StringBuilder ();
803 for (int i = 0; i < tok.Length ; i++)
804 sb.Append (tok[i].ToString ("x2"));
805 return sb.ToString ();
808 private static string EnsureLib (string dir)
810 DirectoryInfo d = new DirectoryInfo (dir);
811 if (d.Name == "lib")
812 return dir;
813 return Path.Combine (dir, "lib");
816 private static void WriteLine ()
818 if (silent)
819 return;
820 Console.WriteLine ();
823 private static void WriteLine (string line)
825 if (silent)
826 return;
827 Console.WriteLine (line);
830 private static void WriteLine (string line, params object [] p)
832 if (silent)
833 return;
834 Console.WriteLine (line, p);
837 private static void Usage ()
839 ShowHelp (false);
840 Environment.Exit (1);
843 private static void ShowHelp (bool detailed)
845 WriteLine ("Usage: gacutil.exe <commands> [ <options> ]");
846 WriteLine ("Commands:");
848 WriteLine ("-i <assembly_path> [-check_refs] [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
849 WriteLine ("\tInstalls an assembly into the global assembly cache.");
850 if (detailed) {
851 WriteLine ("\t<assembly_path> is the name of the file that contains the " +
852 "\tassembly manifest\n" +
853 "\tExample: -i myDll.dll");
855 WriteLine ();
857 WriteLine ("-il <assembly_list_file> [-check_refs] [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
858 WriteLine ("\tInstalls one or more assemblies into the global assembly cache.");
859 if (detailed) {
860 WriteLine ("\t<assembly_list_file> is the path to a test file containing a list of\n" +
861 "\tassembly file paths on separate lines.\n" +
862 "\tExample -il assembly_list.txt\n" +
863 "\t\tassembly_list.txt contents:\n" +
864 "\t\tassembly1.dll\n" +
865 "\t\tassembly2.dll");
867 WriteLine ();
869 WriteLine ("-u <assembly_display_name> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
870 WriteLine ("\tUninstalls an assembly from the global assembly cache.");
871 if (detailed) {
872 WriteLine ("\t<assembly_display_name> is the name of the assembly (partial or\n" +
873 "\tfully qualified) to remove from the global assembly cache. If a \n" +
874 "\tpartial name is specified all matching assemblies will be uninstalled.\n" +
875 "\tExample: -u myDll,Version=1.2.1.0");
877 WriteLine ();
879 WriteLine ("-ul <assembly_list_file> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
880 WriteLine ("\tUninstalls one or more assemblies from the global assembly cache.");
881 if (detailed) {
882 WriteLine ("\t<assembly_list_file> is the path to a test file containing a list of\n" +
883 "\tassembly names on separate lines.\n" +
884 "\tExample -ul assembly_list.txt\n" +
885 "\t\tassembly_list.txt contents:\n" +
886 "\t\tassembly1,Version=1.0.0.0,Culture=en,PublicKeyToken=0123456789abcdef\n" +
887 "\t\tassembly2,Version=2.0.0.0,Culture=en,PublicKeyToken=0123456789abcdef");
889 WriteLine ();
891 WriteLine ("-us <assembly_path> [-package NAME] [-root ROOTDIR] [-gacdir GACDIR]");
892 WriteLine ("\tUninstalls an assembly using the specifed assemblies full name.");
893 if (detailed) {
894 WriteLine ("\t<assembly path> is the path to an assembly. The full assembly name\n" +
895 "\tis retrieved from the specified assembly if there is an assembly in\n" +
896 "\tthe GAC with a matching name, it is removed.\n" +
897 "\tExample: -us myDll.dll");
899 WriteLine ();
901 WriteLine ("-l [assembly_name] [-root ROOTDIR] [-gacdir GACDIR]");
902 WriteLine ("\tLists the contents of the global assembly cache.");
903 if (detailed) {
904 WriteLine ("\tWhen the <assembly_name> parameter is specified only matching\n" +
905 "\tassemblies are listed.");
907 WriteLine ();
909 WriteLine ("-?");
910 WriteLine ("\tDisplays a detailed help screen");
911 WriteLine ();
913 if (!detailed)
914 return;
916 WriteLine ("Options:");
917 WriteLine ("-package <NAME>");
918 WriteLine ("\tUsed to create a directory in prefix/lib/mono with the name NAME, and a\n" +
919 "\tsymlink is created from NAME/assembly_name to the assembly on the GAC.\n" +
920 "\tThis is used so developers can reference a set of libraries at once.");
921 WriteLine ();
923 WriteLine ("-gacdir <GACDIR>");
924 WriteLine ("\tUsed to specify the GACs base directory. Once an assembly has been installed\n" +
925 "\tto a non standard gacdir the MONO_GAC_PREFIX environment variable must be used\n" +
926 "\tto access the assembly.");
927 WriteLine ();
929 WriteLine ("-root <ROOTDIR>");
930 WriteLine ("\tUsed by developers integrating this with automake tools or packaging tools\n" +
931 "\tthat require a prefix directory to be specified. The root represents the\n" +
932 "\t\"libdir\" component of a prefix (typically prefix/lib).");
933 WriteLine ();
935 WriteLine ("-check_refs");
936 WriteLine ("\tUsed to ensure that the assembly being installed into the GAC does not\n" +
937 "\treference any non strong named assemblies. Assemblies being installed to\n" +
938 "\tthe GAC should not reference non strong named assemblies, however the is\n" +
939 "\tan optional check.");
941 WriteLine ();
942 WriteLine ("Ignored Options:");
943 WriteLine ("-f");
944 WriteLine ("\tThe Mono gacutil ignores the -f option to maintain commandline compatibility with");
945 WriteLine ("\tother gacutils. gacutil will always force the installation of a new assembly.");
947 WriteLine ();
948 WriteLine ("-r <reference_scheme> <reference_id> <description>");
949 WriteLine ("\tThe Mono gacutil has not implemented traced references and will emit a warning");
950 WriteLine ("\twhen this option is used.");