[Monodevelop-patches-list] r1045 - branches/MonoDevelop-playground/src/Main/StartUp

commit-watcher at mono-cvs.ximian.com commit-watcher at mono-cvs.ximian.com
Fri Feb 27 06:18:26 EST 2004


Author: jzwart
Date: 2004-02-27 06:18:26 -0500 (Fri, 27 Feb 2004)
New Revision: 1045

Added:
   branches/MonoDevelop-playground/src/Main/StartUp/BasePlugin.cs
   branches/MonoDevelop-playground/src/Main/StartUp/ICommand.cs
   branches/MonoDevelop-playground/src/Main/StartUp/MonoDevelop.cs
   branches/MonoDevelop-playground/src/Main/StartUp/monodevelop.exe.config.in
Removed:
   branches/MonoDevelop-playground/src/Main/StartUp/Dialogs/
Modified:
   branches/MonoDevelop-playground/src/Main/StartUp/Makefile.am
Log:
First part of the addin refactoring. Lots more to follow.



Added: branches/MonoDevelop-playground/src/Main/StartUp/BasePlugin.cs
===================================================================
--- branches/MonoDevelop-playground/src/Main/StartUp/BasePlugin.cs	2004-02-26 20:24:49 UTC (rev 1044)
+++ branches/MonoDevelop-playground/src/Main/StartUp/BasePlugin.cs	2004-02-27 11:18:26 UTC (rev 1045)
@@ -0,0 +1,39 @@
+//
+// BasePlugin.cs: Abstract plugin class from which all plugins must inherit.
+//
+// Author:
+//   Jeroen Zwartepoorte <jeroen at xs4all.nl>
+//
+// (C) Copyright Jeroen Zwartepoorte 2004
+//
+
+namespace MonoDevelop {
+	abstract public class BasePlugin {
+		abstract public string Author {
+			get;
+		}
+	
+		abstract public string Copyright {
+			get;
+		}
+	
+		abstract public string Description {
+			get;
+		}
+		
+		abstract public string Name {
+			get;
+		}
+		
+		abstract public string Url {
+			get;
+		}
+	
+		abstract public string Version {
+			get;
+		}
+		
+		abstract public bool InitializePlugin (byte major, byte minor);
+		abstract public void FinalizePlugin ();
+	}
+}

Added: branches/MonoDevelop-playground/src/Main/StartUp/ICommand.cs
===================================================================
--- branches/MonoDevelop-playground/src/Main/StartUp/ICommand.cs	2004-02-26 20:24:49 UTC (rev 1044)
+++ branches/MonoDevelop-playground/src/Main/StartUp/ICommand.cs	2004-02-27 11:18:26 UTC (rev 1045)
@@ -0,0 +1,24 @@
+//
+// ICommand.cs: Interface for handling command-line parameters.
+//
+// Author:
+//   Jeroen Zwartepoorte <jeroen at xs4all.nl>
+//
+// (C) Copyright Jeroen Zwartepoorte 2004
+//
+
+using System;
+
+namespace MonoDevelop {
+	public interface ICommand {
+		string CommandDescription {
+			get;
+		}
+	
+		bool TakesCommandArguments {
+			get;
+		}
+	
+		void InvokeCommand (string[] args);
+	}
+}

Modified: branches/MonoDevelop-playground/src/Main/StartUp/Makefile.am
===================================================================
--- branches/MonoDevelop-playground/src/Main/StartUp/Makefile.am	2004-02-26 20:24:49 UTC (rev 1044)
+++ branches/MonoDevelop-playground/src/Main/StartUp/Makefile.am	2004-02-27 11:18:26 UTC (rev 1045)
@@ -1,52 +1,22 @@
-BASEDIR=../../..
+monodevelopdir = $(bindir)
+monodevelop_DATA = monodevelop.exe monodevelop.exe.config
+CLEANFILES = monodevelop.exe monodevelop.exe.config
+CSC=mcs
 
-FILES= \
-./SharpDevelopMain.cs \
-./Dialogs/AddInTreeSettingsHandler.cs \
-./Dialogs/ExceptionBox.cs \
-./AssemblyInfo.cs
+monodevelop_sources = \
+	MonoDevelop.cs \
+	BasePlugin.cs \
+	ICommand.cs \
+	AssemblyInfo.cs
+	
+monodevelop_assemblies = -r:log4net.dll
 
-RESOURCES= \
-/resource:$(BASEDIR)/data/resources/StringResources.fr.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.cn-gb.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.jp.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.nl.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.pl.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.ro.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.pt.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.ru.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.goisern.resources \
-/resource:$(BASEDIR)/data/resources/BitmapResources.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.se.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.es.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.cz.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.kr.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.it.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.bg.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.de.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.cn-big.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.dk.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.resources,StringResources.resources \
-/resource:$(BASEDIR)/data/resources/StringResources.br.resources \
-/resource:$(BASEDIR)/data/resources/SplashScreen.png,SplashScreen.png
+monodevelop.exe: $(monodevelop_sources)
+	$(CSC) -debug -out:monodevelop.exe $(monodevelop_sources) $(monodevelop_assemblies)
 
-DLL=../../../build/bin/MonoDevelop.exe
+monodevelop.exe.config: monodevelop.exe.config.in
+	sed -e 's^\@monodevelop_plugin_dir\@^$(monodevelop_plugin_dir)^g' -e 's^\@monodevelop_ui_dir\@^$(monodevelop_ui_dir)^g' < $(srcdir)/monodevelop.exe.config.in > monodevelop.exe.config
 
-all: $(DLL)
-
-$(DLL): $(FILES)
-	@ mcs /debug /out:$(DLL) /r:System.Drawing.dll \
-		/r:../../../build/bin/MonoDevelop.Core.dll \
-		/r:../../../build/bin/MonoDevelop.Base.dll \
-		/r:glib-sharp.dll \
-		/define:GTK /r:gtk-sharp.dll /r:gdk-sharp.dll \
-		/r:gnome-sharp.dll \
-		$(RESOURCES) $(FILES)
-
-assemblydir = $(libdir)/monodevelop/bin
-assembly_DATA = $(DLL)           
-
-CLEANFILES=$(DLL)
-
-EXTRA_DIST = $(FILES)
-
+EXTRA_DIST = \
+	$(monodevelop_sources) \
+	monodevelop.exe.config.in

Added: branches/MonoDevelop-playground/src/Main/StartUp/MonoDevelop.cs
===================================================================
--- branches/MonoDevelop-playground/src/Main/StartUp/MonoDevelop.cs	2004-02-26 20:24:49 UTC (rev 1044)
+++ branches/MonoDevelop-playground/src/Main/StartUp/MonoDevelop.cs	2004-02-27 11:18:26 UTC (rev 1045)
@@ -0,0 +1,387 @@
+//
+// MonoDevelop.cs: Entrypoint for application. Loads plugins from .plugin files.
+//
+// Author:
+//   Jeroen Zwartepoorte <jeroen at xs4all.nl>
+//
+// (C) Copyright Jeroen Zwartepoorte 2004
+//
+// TODO
+//   - Add a standard --verbose option that sets log4net's level to ALL.
+//
+
+using System;
+using System.Collections;
+using System.Configuration;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+
+using log4net;
+using log4net.Config;
+
+namespace MonoDevelop {
+	public class PluginInfo {
+		private string assembly;
+		private string name;
+		private ArrayList dependencies;
+		private int resolvePass;
+		private int discovered;
+		private int finished;
+		private BasePlugin instance;
+		private bool active;
+	
+		public PluginInfo (string assembly, string name) {
+			this.assembly = assembly;
+			this.name = name;
+			dependencies = new ArrayList ();
+			resolvePass = -1;
+			discovered = -1;
+			finished = -1;
+			instance = null;
+			active = false;
+		}
+	
+		public string Assembly {
+			get {
+				return assembly;
+			}
+		}
+	
+		public string Name {
+			get {
+				return name;
+			}
+		}
+		
+		public ArrayList Dependencies {
+			get {
+				return dependencies;
+			}
+		}
+		
+		public int ResolvePass {
+			get {
+				return resolvePass;
+			}
+			set {
+				resolvePass = value;
+			}
+		}
+		
+		public int Discovered {
+			get {
+				return discovered;
+			}
+			set {
+				discovered = value;
+			}
+		}
+		
+		public int Finished {
+			get {
+				return finished;
+			}
+			set {
+				finished = value;
+			}
+		}
+		
+		public BasePlugin Instance {
+			get {
+				return instance;
+			}
+			set {
+				instance = value;
+			}
+		}
+		
+		public bool Active {
+			get {
+				return active;
+			}
+			set {
+				active = value;
+			}
+		}
+	}
+	
+	class NameComparer : IComparer
+	{
+		public int Compare (Object obj1, Object obj2)
+		{
+			string className = (string)obj1;
+			PluginInfo plugin = (PluginInfo)obj2;
+			return String.Compare (className, plugin.Name);
+		}
+	}
+	
+	public class MonoDevelop
+	{
+		private static readonly ILog log = LogManager.GetLogger (typeof (MonoDevelop));
+		private static NameComparer nameComparer = new NameComparer ();
+		private static int time = 0;
+		private static ArrayList plugins;
+		private static Hashtable commands = new Hashtable ();
+		private static ICommand defaultCommand = null;
+	
+		// Configure log4net using the .config file.
+		[assembly: log4net.Config.DOMConfigurator(Watch=true)]
+	
+		public static PluginInfo[] AvailablePlugins {
+			get {
+				PluginInfo[] result = new PluginInfo[plugins.Count];
+				plugins.CopyTo (result);
+				return result;
+			}
+		}
+	
+		//
+		// Registers a command handler for a particular command line option.
+		// An option value of null is used for the "default" handler. Set both
+		// parameters to null if you want to disable the default handler.
+		//
+		public static void RegisterCommand (string option, ICommand cmd)
+		{
+			if (option == null) {
+				defaultCommand = cmd;
+			} else {
+				if (commands.Contains (option))
+					log.Warn ("Command " + option + " is already registered");
+				else
+					commands.Add (option, cmd);
+			}
+		}
+	
+		static void Main (string[] args)
+		{
+			log.Debug ("Starting MonoDevelop");
+			
+			// Make a list of plugin directories.
+			ArrayList pluginDirs = new ArrayList ();
+			string path = ConfigurationSettings.AppSettings["pluginsPath"];
+			if (path == null) {
+				log.Error ("Unknown configuration property \"pluginsPath\"");
+				log.Error ("Your monodevelop.exe.config is likely broken");
+				log.Error ("Please reinstall MonoDevelop");
+				return;
+			}
+			pluginDirs.Add (path);
+			
+			// Add directories from the $MONODEVELOP_PLUGIN_PATH environment var.
+			path = Environment.GetEnvironmentVariable ("MONODEVELOP_PLUGIN_PATH");
+			if (path != null) {
+				string[] dirs = path.Split (Path.DirectorySeparatorChar);
+				foreach (string dir in dirs)
+					pluginDirs.Add (dir);
+			}
+	
+			// Scan for .plugin files in the plugin directories.
+			log.Debug ("Looking for .plugin files");
+			ArrayList pluginFiles = new ArrayList ();
+			foreach (string pluginDir in pluginDirs) {
+				if (!Directory.Exists (pluginDir))
+					continue;
+				log.Debug ("Scanning " + pluginDir);
+				DirectoryInfo di = new DirectoryInfo (pluginDir);
+				FileInfo[] files = di.GetFiles ("*.plugin");
+				pluginFiles.AddRange (files);
+			}
+			log.Debug ("" + pluginFiles.Count + " plugin file(s) found");
+			
+			// Parse the .plugin files and build a list of plugins
+			// and dependencies.
+			plugins = new ArrayList ();
+			foreach (FileInfo file in pluginFiles) {
+				log.Debug ("Parsing " + file.FullName);
+				ParsePluginFile (file.FullName);
+			}
+			
+			// Determine the order in which to load plugins.
+			SortedList loadOrder = ResolveDependencies ();
+			
+			// Load the plugins in proper order from the loadOrder SortedList.
+			foreach (PluginInfo plugin in loadOrder.Values) {
+				try {
+					log.Debug ("Loading " + plugin.Name);
+					Assembly a = Assembly.LoadFrom (plugin.Assembly);
+					plugin.Instance = (BasePlugin) a.CreateInstance (plugin.Name);
+					if (plugin.Instance.InitializePlugin ((byte)1, (byte)0))
+						plugin.Active = true;
+				} catch (System.Exception e) {
+					log.Error ("Error loading " + plugin.Name, e);
+					continue;
+				}
+			}
+	
+			// Check for --help argument.
+			if (Array.BinarySearch (args, "--help") >= 0) {
+				PrintHelp ();
+				return;
+			}
+			
+			// If the first argument isn't a registered ICommand,
+			// then interpret all the arguments as input for the
+			// default command handler.
+			if (args.Length == 0 || !commands.Contains (args[0])) {
+				// Invoke the default ICommand.
+				if (defaultCommand == null) {
+					log.Error ("No default command handler registered; Exiting");
+					return;
+				} else {
+					defaultCommand.InvokeCommand (args);
+				}
+			} else {
+				// Parse the commandline arguments.
+				for (int i = 0; i < args.Length; i++) {
+					ICommand cmd = (ICommand)commands[args[i]];
+					if (cmd.TakesCommandArguments) {
+						ArrayList p = new ArrayList ();
+						while ((args.Length > i + 1) && !commands.Contains (args[i+1]))
+							p.Add (args[++i]);
+						string[] result = new string[p.Count];
+						p.CopyTo (result);
+						cmd.InvokeCommand (result);
+					} else {
+						cmd.InvokeCommand (null);
+					}
+				}
+			}
+			
+			// At this point, the command handler has finished its task.
+			// Example: it has finished a --build command or the default
+			// command handler has returned from the GTK+ main loop.
+
+			// Finalize all plugins in the reverse order they were loaded.
+			for (int i = loadOrder.Count - 1; i >= 0; i--) {
+				PluginInfo plugin = (PluginInfo)loadOrder.GetByIndex (i);
+				plugin.Instance.FinalizePlugin ();
+			}
+			commands.Clear ();
+			loadOrder.Clear ();
+			plugins.Clear ();
+			
+			// And exit.
+			log.Debug ("Exiting MonoDevelop");
+		}
+		
+		//
+		// Output information about monodevelop's usage and possible commandline
+		// parameters to the console.
+		//
+		private static void PrintHelp ()
+		{
+			Console.WriteLine ("Usage is: monodevelop [options] files");
+			foreach (ICommand cmd in commands.Values)
+				Console.WriteLine ("   {0}", cmd.CommandDescription);
+			Console.WriteLine ("");
+		}
+		
+		//
+		// Parses a .plugin file and creates a new PluginInfo class with the
+		// attributes from the .plugin file.
+		//
+		private static void ParsePluginFile (string file)
+		{
+			XmlTextReader reader = new XmlTextReader (file);
+			PluginInfo plugin = null;
+			string assembly = null;
+			
+			while (reader.Read ()) {
+				if (reader.NodeType == XmlNodeType.Element) {
+					switch (reader.Name) {
+						case "assembly":
+							assembly = reader.ReadElementString ();
+							break;
+						case "class":
+							plugin = new PluginInfo (assembly, reader["name"]);
+							plugins.Add (plugin);
+							break;
+						case "depends":
+							plugin.Dependencies.Add (reader.ReadElementString());
+							break;
+					}
+				}
+			}
+		}
+		
+		//
+		// Returns the PluginInfo belonging to the specified className. Returns
+		// null if a matching PluginInfo wasn't found.
+		//
+		private static PluginInfo FindPlugin (ArrayList list, string className)
+		{
+			int idx = plugins.BinarySearch (className, nameComparer);
+			
+			if (idx >= 0)
+				return (PluginInfo)list[idx];
+			else
+				return null;
+		}
+		
+		//
+		// Resolve the plugin dependencies. Check for cycles and whether
+		// dependency classes exist. The end result will be that the loadOrder
+		// SortedList will contain the plugins in the order that they need to be
+		// loaded.
+		//
+		private static SortedList ResolveDependencies ()
+		{
+			time = 0;
+			int pass = 0;
+			SortedList result = new SortedList ();
+		
+			foreach (PluginInfo plugin in plugins) {
+				if (plugin.ResolvePass == -1) {
+					if (!TraversePlugin (plugin, result, pass++))
+						log.Error ("Unable to load: " + plugin.Name);
+				}
+			}
+	
+			return result;		
+		}
+		
+		//
+		// Traverse the graph using a Depth First Search and sort the plugins
+		// based on the "finished time". During each "pass", the ResolvePass 
+		// attribute is set on each PluginInfo to detect when a cycle has 
+		// occurred. When this happens, false will be returned through the 
+		// recursion and the cycle will be excluded from the loadOrder list. The
+		// same occurs when a plugin depends on a class which is not listed in 
+		// any .plugin file.
+		//
+		private static bool TraversePlugin (PluginInfo plugin,
+						    SortedList order,
+						    int        pass)
+		{
+			plugin.ResolvePass = pass;
+			plugin.Discovered = ++time;
+			
+			foreach (string className in plugin.Dependencies) {
+				PluginInfo child = FindPlugin (plugins, className);
+				
+				// Check that the dependency class exists.
+				if (child == null) {
+					log.Error ("Class not found: " + className);
+					return false;
+				}
+				
+				// Check for cycles in the dependency graph.
+				if (child.ResolvePass != pass) {
+					if (!TraversePlugin (child, order, pass)) {
+						log.Error ("Unable to load: " + child.Name);
+						return false;
+					}
+				} else {
+					log.Error ("Circular dependency: " + child.Name);
+					return false;
+				}
+			}
+			
+			plugin.Finished = ++time;
+			order.Add (plugin.Finished, plugin);
+			
+			return true;
+		}
+	}
+}

Added: branches/MonoDevelop-playground/src/Main/StartUp/monodevelop.exe.config.in
===================================================================
--- branches/MonoDevelop-playground/src/Main/StartUp/monodevelop.exe.config.in	2004-02-26 20:24:49 UTC (rev 1044)
+++ branches/MonoDevelop-playground/src/Main/StartUp/monodevelop.exe.config.in	2004-02-27 11:18:26 UTC (rev 1045)
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+	<appSettings>
+		<add key="pluginsPath" value="@scaffold_plugin_dir@"/>
+		<add key="uiPath" value="@scaffold_ui_dir@"/>
+	</appSettings>
+	<configSections>
+		<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
+	</configSections>
+	<log4net>
+		<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
+			<layout type="log4net.Layout.PatternLayout">
+				<param name="ConversionPattern" value="%-5p - %m%n"/>
+			</layout>
+		</appender>
+		<root>
+			<level value="ALL"/>
+			<appender-ref ref="ConsoleAppender"/>
+		</root>
+	</log4net>
+</configuration>




More information about the Monodevelop-patches-list mailing list