[PATCH] Monodoc/Beagle



? beagle-monodoc.patch
? beagled/MonodocQueryable/MonodocQueryable.cs
Index: beagled/Makefile.am
===================================================================
RCS file: /cvs/gnome/beagle/beagled/Makefile.am,v
retrieving revision 1.41
diff -r1.41 Makefile.am
207a208,211
> monodocqueryable = $(srcdir)/MonodocQueryable
> MONODOC_QUERYABLE_CSFILES =				\
> 	$(monodocqueryable)/MonodocQueryable.cs
> 
213a218
> 	$(MONODOC_QUERYABLE_CSFILES)		\
//
// MonodocQueryable.cs
//
// Copyright (C) 2004 Novell, Inc.
//
// Authors:
//   Fredrik Hedberg (fredrik hedberg avafan com)
//

//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

using System;
using System.IO;
using System.Xml;
using System.Text;

using Beagle.Daemon;
using Beagle.Util;

using ICSharpCode.SharpZipLib.Zip;

namespace Beagle.Daemon.MonodocQueryable {

	[QueryableFlavor (Name="Mondoc", Domain=QueryDomain.Local)]
	public class MonodocQueryable : LuceneQueryable {

		private static Logger log = Logger.Get ("MonodocQueryable");

		string monodocDir;
		int wdMonodoc = -1;

		public MonodocQueryable () : base (Path.Combine (PathFinder.RootDir, "MondocIndex"))
		{
			monodocDir = "/usr/lib/monodoc/sources"; // FIXME Find out where the source archives are
		}

		public override void Start () 
		{
			base.Start ();

			if (! (Directory.Exists (monodocDir)))
				return;
			
			InotifyEventType mask;
			mask = InotifyEventType.MovedTo
				| InotifyEventType.MovedFrom
				| InotifyEventType.CreateFile
				| InotifyEventType.DeleteFile
				| InotifyEventType.Modify;

			wdMonodoc = Inotify.Watch (monodocDir, mask);

			Inotify.InotifyEvent += new InotifyHandler (OnInotifyEvent);

			// Crawl all of our existing notes to make sure that
			// everything is up-to-date.
			log.Info ("Scanning Monodoc sources...");
			Stopwatch stopwatch = new Stopwatch ();
			int countArchives = 0;
			int countTypes = 0;
			stopwatch.Start ();
			DirectoryInfo dir = new DirectoryInfo (monodocDir);
			foreach (FileInfo file in dir.GetFiles ()) {
				if (file.Extension == ".zip")
				{
					countTypes += IndexArchive (file, 0);
					countArchives++;
				}
			}
			stopwatch.Stop ();
			log.Info ("Scanned {0} types in {1} archives in {2}",countTypes,countArchives, stopwatch);
		}

		private void OnInotifyEvent (int wd,
					     string path,
					     string subitem,
					     InotifyEventType type,
					     int cookie)
		{
			if (wd != wdMonodoc)
				return;

			// Ignore operations on the directories themselves
			if (subitem == "")
				return;

			// Ignore metadata files
			if (Path.GetExtension (subitem) != ".zip")
				return;
			
			if (wd == wdMonodoc && type == InotifyEventType.MovedTo) {
				int countTypes = IndexArchive (new FileInfo (Path.Combine (path, subitem)), 100);
				log.Info ("Indexed {0} types in {1}", countTypes,Path.Combine (path, subitem));
			}
		}

		int IndexArchive (FileInfo file, int priority)
		{
			if (Driver.IsUpToDate (file))
				return -1; // FIXME Make caller handle when files are up to date

			log.Info ("Scanning " + file);
			
			int countTypes = 0;			
			ZipFile archive = new ZipFile(file.ToString());
			
			// Iterate through zip file entries
			foreach (ZipEntry entry in archive)
			{
				// Process files without file suffix
				if (entry.Name.IndexOf (".") != -1)
					continue;

				log.Debug( "Going through entry " + entry.Name);

				XmlDocument document = new XmlDocument();
				document.Load( archive.GetInputStream( entry));
			
				XmlNode type = document.SelectSingleNode( "/Type");

				if (type == null)
					continue;

				Driver.ScheduleAddAndMark (TypeNodeToIndexable(type,file),priority, file);

				foreach(XmlNode member in type.SelectNodes("Members/Member"))
				{
					Driver.ScheduleAddAndMark(MemberNodeToIndexable(member,file,type.Attributes["FullName"].Value),priority,file);
				}
				countTypes++;
			}

			return countTypes;
		}

		Indexable TypeNodeToIndexable(XmlNode node,FileInfo file)
		{
			log.Debug("Parsing T:" + node.Attributes["FullName"].Value);

			Indexable indexable = new Indexable(
				new Uri("monodoc://" + file + ";item=T:"+node.Attributes["FullName"].Value));

			indexable.MimeType = "application/monodoc";
			indexable.Type = "Monodoc";

			indexable.AddProperty(Property.NewKeyword("fixme:fullname",node.Attributes["FullName"].Value));
			indexable.AddProperty(Property.NewKeyword("fixme:type","type"));

			// Should we add other stuff here? Implemented interfaces etc?

			StringReader reader = new StringReader (node.SelectSingleNode("Docs").InnerXml); // FIXME Use FilterHtml to mark "hot" words in content
                        indexable.SetTextReader(reader);

			return indexable;
		}
		
		Indexable MemberNodeToIndexable(XmlNode node, FileInfo file, string parentName)
		{
			char memberType = MemberTypeToChar(node.SelectSingleNode("MemberType").InnerText);
			StringBuilder memberFullName = new StringBuilder();
	
			memberFullName.Append(memberType + ":"+ parentName);

			if (memberType != 'C')
				memberFullName.Append("." + node.Attributes["MemberName"].Value);

			if (memberType == 'C' || memberType == 'M' || memberType == 'E')
			{	
				memberFullName.Append("(");
				bool inside = false;

				foreach (XmlNode parameter in node.SelectNodes("Parameters/Parameter"))
				{	
					if (!inside) inside = true; else memberFullName.Append(","); // FIXME I'm the spagetti man

					memberFullName.Append(parameter.Attributes["Type"].Value);								
				}

				memberFullName.Append(")");
			}

			log.Debug("Parsing " + memberFullName);

			Indexable indexable = new Indexable(
				new Uri("monodoc://" + file + ";item=" + memberFullName));

			indexable.MimeType = "application/monodoc";
			indexable.Type = "Monodoc";

			indexable.AddProperty(Property.NewKeyword("fixme:fullname",memberFullName));
			indexable.AddProperty(Property.NewKeyword("fixme:type",node.SelectSingleNode("MemberType").InnerText.ToLower()));

			StringReader reader = new StringReader (node.SelectSingleNode("Docs").InnerXml); // FIXME Use FilterHtml to mark "hot" words in content
                        indexable.SetTextReader(reader);

			return indexable;			
		}

		char MemberTypeToChar(string memberType)
		{
			switch (memberType) 
			{
				case "Constructor":
					return 'C';
				case "Event":
					return 'E';
				case "Property":
					return 'P';
				case "Field":
					return 'F';
				case "Method":
					return 'M';
				default:
					return 'M'; // Ever happen?
			}
		}
	}
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]