4 // Copyright (C) 2004-2006 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 using System
.Collections
;
30 using System
.Globalization
;
31 using System
.Reflection
;
32 using System
.Threading
;
34 using System
.Text
.RegularExpressions
;
35 using System
.Runtime
.InteropServices
;
45 private static int count
= 0;
46 private static Query query
= null;
47 private static DateTime queryStartTime
;
48 private static DateTime lastQueryTime
= DateTime
.Now
;
50 private static MainLoop main_loop
= null;
52 private static bool keep_running
= false;
53 private static bool verbose
= false;
54 private static bool display_hits
= true;
55 private static bool flood
= false;
56 private static bool listener
= false;
57 private static DateTime start_date
= DateTime
.MinValue
;
58 private static DateTime end_date
= DateTime
.MinValue
;
60 private static void OnHitsAdded (HitsAddedResponse response
)
62 lastQueryTime
= DateTime
.Now
;
64 if (count
== 0 && verbose
) {
65 Console
.WriteLine ("First hit returned in {0:0.000}s",
66 (lastQueryTime
- queryStartTime
).TotalSeconds
);
69 if (response
.NumMatches
>= 0)
70 Console
.WriteLine ("Returned latest {0} results out of total {1} matches", response
.Hits
.Count
, response
.NumMatches
);
73 count
+= response
.Hits
.Count
;
77 foreach (Hit hit
in response
.Hits
) {
79 Console
.WriteLine (" Uri: {0}", hit
.Uri
);
81 Console
.WriteLine (hit
.Uri
);
84 SnippetRequest sreq
= new SnippetRequest (query
, hit
);
85 SnippetResponse sresp
= (SnippetResponse
) sreq
.Send ();
86 Console
.WriteLine ("PaUri: {0}", hit
.ParentUri
!= null ? hit
.ParentUri
.ToString () : "(null)");
87 Console
.WriteLine (" Snip: {0}", sresp
.Snippet
!= null ? sresp
.Snippet
: "(null)");
88 Console
.WriteLine (" Type: {0}", hit
.Type
);
89 Console
.WriteLine ("MimeT: {0}", hit
.MimeType
== null ? "(null)" : hit
.MimeType
);
90 Console
.WriteLine (" Src: {0}", hit
.Source
);
91 Console
.WriteLine ("Score: {0}", hit
.Score
);
92 if (hit
.ValidTimestamp
)
93 Console
.WriteLine (" Time: {0}", hit
.Timestamp
);
95 foreach (Property prop
in hit
.Properties
)
96 Console
.WriteLine (" {0} = '{1}'", prop
.Key
, prop
.Value
);
105 private static void OnHitsSubtracted (HitsSubtractedResponse response
)
107 lastQueryTime
= DateTime
.Now
;
112 foreach (Uri uri
in response
.Uris
) {
113 Console
.WriteLine ("Subtracted Uri '{0}'", uri
);
114 Console
.WriteLine ();
120 private static void OnFinished (FinishedResponse response
)
123 Console
.WriteLine ("Elapsed time: {0:0.000}s",
124 (DateTime
.Now
- queryStartTime
).TotalSeconds
);
125 Console
.WriteLine ("Total hits: {0}", count
);
134 public static void PrintUsageAndExit ()
137 "beagle-query: Command-line interface to the Beagle search system.\n" +
138 "Web page: http://www.gnome.org/projects/beagle\n" +
139 "Copyright (C) 2004-2006 Novell, Inc.\n\n";
141 "Usage: beagle-query [OPTIONS] <query string>\n\n" +
143 " --verbose\t\t\tPrint detailed information about each hit.\n" +
144 " --mime <mime type>\t\tConstrain search results to the specified mime\n" +
145 " \t\ttype. Can be used multiply.\n" +
146 " --type <hit type>\t\tConstrain search results to the specified hit\n" +
147 " \t\ttype. Can be used multiply.\n" +
148 " --source <source>\t\tConstrain query to the specified source.\n" +
149 " \t\tSources list available from beagle-status.\n" +
150 " --start <date>\t\tConstrain query to items after specified date.\n" +
151 " \t\tDate must be in the form \"yyyyMMdd\" or \"yyyyMMddHHmmss\"\n" +
152 " --end <date>\t\t\tConstrain query to items before specified date.\n" +
153 " \t\t\tDate must be in the form \"yyyyMMdd\" or \"yyyyMMddHHmmss\"\n" +
154 " --keywords\t\t\tLists the keywords allowed in 'query string'.\n" +
155 " \t\t\tKeyword queries can be specified as keywordname:value e.g. ext:jpg\n" +
156 " --live-query\t\t\tRun continuously, printing notifications if a\n" +
157 " \t\t\tquery changes.\n" +
158 " --stats-only\t\t\tOnly display statistics about the query, not\n" +
159 " \t\t\tthe actual results.\n" +
160 " --max-hits\t\t\tLimit number of search results per backend\n" +
161 " \t\t\t(default = 100, max = 100)\n" +
162 " --flood\t\t\tExecute the query over and over again. Don't do that.\n" +
163 " --listener\t\t\tExecute an index listener query. Don't do that either.\n" +
164 " --help\t\t\tPrint this usage message.\n" +
166 "Query string supports an advanced query syntax.\n" +
167 "For details of the query syntax, please see http://beagle-project.org/Searching_Data\n" +
168 "Note: Quotes (\" or \') need to be shell escaped if used.\n";
170 Console
.WriteLine (usage
);
172 System
.Environment
.Exit (0);
175 private static void ReadBackendMappings ()
177 ArrayList assemblies
= ReflectionFu
.ScanEnvironmentForAssemblies ("BEAGLE_BACKEND_PATH", PathFinder
.BackendDir
);
179 // Add BeagleDaemonLib if it hasn't already been added.
180 bool found_daemon_lib
= false;
181 foreach (Assembly assembly
in assemblies
) {
182 if (assembly
.GetName ().Name
== "BeagleDaemonLib") {
183 found_daemon_lib
= true;
188 if (!found_daemon_lib
) {
190 assemblies
.Add (Assembly
.LoadFrom (Path
.Combine (PathFinder
.PkgLibDir
, "BeagleDaemonLib.dll")));
191 } catch (FileNotFoundException
) {
192 Console
.WriteLine ("WARNING: Could not find backend list.");
193 Environment
.Exit (1);
197 foreach (Assembly assembly
in assemblies
) {
198 foreach (Type type
in ReflectionFu
.GetTypesFromAssemblyAttribute (assembly
, typeof (IQueryableTypesAttribute
))) {
199 object[] attributes
= type
.GetCustomAttributes (false);
200 foreach (object attribute
in attributes
) {
201 PropertyKeywordMapping mapping
= attribute
as PropertyKeywordMapping
;
204 //Logger.Log.Debug (mapping.Keyword + " => "
205 // + mapping.PropertyName +
206 // + " is-keyword=" + mapping.IsKeyword + " ("
207 // + mapping.Description + ") "
208 // + "(" + type.FullName + ")");
209 PropertyKeywordFu
.RegisterMapping (mapping
);
215 private static void OnClosed ()
223 private static int query_counter
= 0;
224 private static void SendQuery ()
228 if (query_counter
> 1)
229 Console
.WriteLine ();
230 Console
.WriteLine ("Sending query #{0}", query_counter
);
233 queryStartTime
= DateTime
.Now
;
236 } catch (Exception ex
) {
237 Console
.WriteLine ("Could not connect to the Beagle daemon. The daemon probably isn't running.");
238 Console
.WriteLine (ex
);
239 System
.Environment
.Exit (-1);
243 [DllImport("libgobject-2.0.so.0")]
244 static extern void g_type_init ();
246 public static void Main (string[] args
)
248 // Initialize GObject type system
251 main_loop
= new MainLoop ();
253 if (args
.Length
== 0 || Array
.IndexOf (args
, "--help") > -1 || Array
.IndexOf (args
, "--usage") > -1)
254 PrintUsageAndExit ();
256 StringBuilder query_str
= new StringBuilder ();
263 query
= new Query ();
267 while (i
< args
.Length
) {
271 if (++i
>= args
.Length
) PrintUsageAndExit ();
272 query
.AddMimeType (args
[i
]);
275 if (++i
>= args
.Length
) PrintUsageAndExit ();
276 query
.AddHitType (args
[i
]);
279 if (++i
>= args
.Length
) PrintUsageAndExit ();
280 query
.AddSource (args
[i
]);
290 display_hits
= false;
293 if (++i
>= args
.Length
) PrintUsageAndExit ();
294 query
.MaxHits
= Int32
.Parse (args
[i
]);
304 if (++i
>= args
.Length
) PrintUsageAndExit ();
306 start_date
= DateTime
.ParseExact (args
[i
], formats
,
307 CultureInfo
.InvariantCulture
,
308 DateTimeStyles
.None
);
309 } catch (FormatException
) {
310 Console
.WriteLine ("Invalid start date");
311 System
.Environment
.Exit (-1);
313 start_date
= start_date
.ToUniversalTime ();
317 if (++i
>= args
.Length
) PrintUsageAndExit ();
319 end_date
= DateTime
.ParseExact (args
[i
], formats
,
320 CultureInfo
.InvariantCulture
,
321 DateTimeStyles
.None
);
322 } catch (FormatException
) {
323 Console
.WriteLine ("Invalid end date");
324 System
.Environment
.Exit (-1);
326 end_date
= end_date
.ToUniversalTime ();
330 ReadBackendMappings ();
331 QueryDriver
.ReadKeywordMappings ();
333 Console
.WriteLine ("Supported query keywords are:");
335 IDictionaryEnumerator property_keyword_enum
= PropertyKeywordFu
.MappingEnumerator
;
336 while (property_keyword_enum
.MoveNext ()) {
337 PropertyDetail prop
= property_keyword_enum
.Value
as PropertyDetail
;
338 if (prop
.Description
!= null)
339 Console
.WriteLine (" {0,-20} for {1}", property_keyword_enum
.Key
, prop
.Description
);
341 Console
.WriteLine (" {0,-20}", property_keyword_enum
.Key
);
344 System
.Environment
.Exit (0);
348 if (query_str
.Length
> 0)
349 query_str
.Append (' ');
350 query_str
.Append (args
[i
]);
361 query
.IsIndexListener
= true;
365 if (query_str
.Length
> 0)
366 query
.AddText (query_str
.ToString ());
368 if (start_date
!= DateTime
.MinValue
|| end_date
!= DateTime
.MinValue
) {
369 QueryPart_DateRange part
= new QueryPart_DateRange ();
371 if (start_date
!= DateTime
.MinValue
)
372 part
.StartDate
= start_date
;
374 if (end_date
!= DateTime
.MinValue
)
375 part
.EndDate
= end_date
;
377 query
.AddPart (part
);
381 query
.HitsAddedEvent
+= OnHitsAdded
;
382 query
.HitsSubtractedEvent
+= OnHitsSubtracted
;
386 query
.FinishedEvent
+= OnFinished
;
388 query
.ClosedEvent
+= OnClosed
;