4 // Copyright (C) 2004-2005 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
;
44 private static int count
= 0;
45 private static Query query
= null;
46 private static DateTime queryStartTime
;
47 private static DateTime lastQueryTime
= DateTime
.Now
;
49 private static MainLoop main_loop
= null;
51 private static bool keep_running
= false;
52 private static bool verbose
= false;
53 private static bool display_hits
= true;
54 private static bool flood
= false;
55 private static bool listener
= false;
56 private static DateTime start_date
= DateTime
.MinValue
;
57 private static DateTime end_date
= DateTime
.MinValue
;
59 private static void OnHitsAdded (HitsAddedResponse response
)
61 lastQueryTime
= DateTime
.Now
;
63 if (count
== 0 && verbose
) {
64 Console
.WriteLine ("First hit returned in {0:0.000}s",
65 (lastQueryTime
- queryStartTime
).TotalSeconds
);
69 count
+= response
.Hits
.Count
;
73 foreach (Hit hit
in response
.Hits
) {
75 Console
.WriteLine (" Uri: {0}", hit
.Uri
);
77 Console
.WriteLine (hit
.Uri
);
80 SnippetRequest sreq
= new SnippetRequest (query
, hit
);
81 SnippetResponse sresp
= (SnippetResponse
) sreq
.Send ();
82 Console
.WriteLine ("PaUri: {0}", hit
.ParentUri
!= null ? hit
.ParentUri
.ToString () : "(null)");
83 Console
.WriteLine (" Snip: {0}", sresp
.Snippet
!= null ? sresp
.Snippet
: "(null)");
84 Console
.WriteLine (" Type: {0}", hit
.Type
);
85 Console
.WriteLine ("MimeT: {0}", hit
.MimeType
== null ? "(null)" : hit
.MimeType
);
86 Console
.WriteLine (" Src: {0}", hit
.Source
);
87 Console
.WriteLine ("Score: {0}", hit
.Score
);
88 if (hit
.ValidTimestamp
)
89 Console
.WriteLine (" Time: {0}", hit
.Timestamp
.ToLocalTime ());
91 foreach (Property prop
in hit
.Properties
)
92 Console
.WriteLine (" {0} = '{1}'", prop
.Key
, prop
.Value
);
101 private static void OnHitsSubtracted (HitsSubtractedResponse response
)
103 lastQueryTime
= DateTime
.Now
;
108 foreach (Uri uri
in response
.Uris
) {
109 Console
.WriteLine ("Subtracted Uri '{0}'", uri
);
110 Console
.WriteLine ();
116 private static void OnFinished (FinishedResponse response
)
119 Console
.WriteLine ("Elapsed time: {0:0.000}s",
120 (DateTime
.Now
- queryStartTime
).TotalSeconds
);
121 Console
.WriteLine ("Total hits: {0}", count
);
128 //Gtk.Application.Quit ();
131 public static void PrintUsageAndExit ()
134 "beagle-query: Command-line interface to the Beagle search system.\n" +
135 "Web page: http://www.gnome.org/projects/beagle\n" +
136 "Copyright (C) 2004 Novell, Inc.\n\n";
138 "Usage: beagle-query [OPTIONS] <query string>\n\n" +
140 " --verbose\t\t\tPrint detailed information about each hit.\n" +
141 " --mime <mime type>\t\tConstrain search results to the specified mime\n" +
142 " \t\ttype. Can be used multiply.\n" +
143 " --type <hit type>\t\tConstrain search results to the specified hit\n" +
144 " \t\ttype. Can be used multiply.\n" +
145 " --source <source>\t\tConstrain query to the specified source.\n" +
146 " \t\tSources list available from beagle-status.\n" +
147 " --start <date>\t\tConstrain query to items after specified date.\n" +
148 " \t\tDate must be in the form \"yyyyMMdd\" or \"yyyyMMddHHmmss\"\n" +
149 " --end <date>\t\t\tConstrain query to items before specified date.\n" +
150 " \t\t\tDate must be in the form \"yyyyMMdd\" or \"yyyyMMddHHmmss\"\n" +
151 " --keywords\t\t\tLists the keywords allowed in 'query string'.\n" +
152 " \t\t\tKeyword queries can be specified as keywordname:value e.g. ext:jpg\n" +
153 " --live-query\t\t\tRun continuously, printing notifications if a\n" +
154 " \t\t\tquery changes.\n" +
155 " --stats-only\t\t\tOnly display statistics about the query, not\n" +
156 " \t\t\tthe actual results.\n" +
157 " --max-hits\t\t\tLimit number of search results per backend\n" +
158 " \t\t\t(default = 100, max = 100)\n" +
159 " --flood\t\t\tExecute the query over and over again. Don't do that.\n" +
160 " --listener\t\t\tExecute an index listener query. Don't do that either.\n" +
161 " --help\t\t\tPrint this usage message.\n";
163 Console
.WriteLine (usage
);
165 System
.Environment
.Exit (0);
168 private static void ReadBackendMappings ()
170 ArrayList assemblies
= ReflectionFu
.ScanEnvironmentForAssemblies ("BEAGLE_BACKEND_PATH", PathFinder
.BackendDir
);
172 // Add BeagleDaemonLib if it hasn't already been added.
173 bool found_daemon_lib
= false;
174 foreach (Assembly assembly
in assemblies
) {
175 if (assembly
.GetName ().Name
== "BeagleDaemonLib") {
176 found_daemon_lib
= true;
181 if (!found_daemon_lib
) {
183 assemblies
.Add (Assembly
.LoadFrom (Path
.Combine (PathFinder
.PkgLibDir
, "BeagleDaemonLib.dll")));
184 } catch (FileNotFoundException
) {
185 Console
.WriteLine ("WARNING: Could not find backend list.");
186 Environment
.Exit (1);
190 foreach (Assembly assembly
in assemblies
) {
191 foreach (Type type
in ReflectionFu
.ScanAssemblyForInterface (assembly
, typeof (Beagle
.Daemon
.IQueryable
))) {
192 object[] attributes
= type
.GetCustomAttributes (false);
193 foreach (object attribute
in attributes
) {
194 PropertyKeywordMapping mapping
= attribute
as PropertyKeywordMapping
;
197 //Logger.Log.Debug (mapping.Keyword + " => "
198 // + mapping.PropertyName +
199 // + " is-keyword=" + mapping.IsKeyword + " ("
200 // + mapping.Description + ") "
201 // + "(" + type.FullName + ")");
202 PropertyKeywordFu
.RegisterMapping (mapping
);
208 private static void OnClosed ()
214 //Gtk.Application.Quit ();
217 private static int query_counter
= 0;
218 private static void SendQuery ()
222 if (query_counter
> 1)
223 Console
.WriteLine ();
224 Console
.WriteLine ("Sending query #{0}", query_counter
);
227 queryStartTime
= DateTime
.Now
;
230 } catch (Exception ex
) {
231 Console
.WriteLine ("Could not connect to the Beagle daemon. The daemon probably isn't running.");
232 Console
.WriteLine (ex
);
233 System
.Environment
.Exit (-1);
237 public static void Main (string[] args
)
239 main_loop
= new MainLoop ();
241 if (args
.Length
== 0 || Array
.IndexOf (args
, "--help") > -1 || Array
.IndexOf (args
, "--usage") > -1)
242 PrintUsageAndExit ();
244 StringBuilder query_str
= new StringBuilder ();
251 query
= new Query ();
255 while (i
< args
.Length
) {
259 if (++i
>= args
.Length
) PrintUsageAndExit ();
260 query
.AddMimeType (args
[i
]);
263 if (++i
>= args
.Length
) PrintUsageAndExit ();
264 query
.AddHitType (args
[i
]);
267 if (++i
>= args
.Length
) PrintUsageAndExit ();
268 query
.AddSource (args
[i
]);
278 display_hits
= false;
281 if (++i
>= args
.Length
) PrintUsageAndExit ();
282 query
.MaxHits
= Int32
.Parse (args
[i
]);
292 if (++i
>= args
.Length
) PrintUsageAndExit ();
294 start_date
= DateTime
.ParseExact (args
[i
], formats
,
295 CultureInfo
.InvariantCulture
,
296 DateTimeStyles
.None
);
297 } catch (FormatException
) {
298 Console
.WriteLine ("Invalid start date");
299 System
.Environment
.Exit (-1);
301 start_date
= start_date
.ToUniversalTime ();
305 if (++i
>= args
.Length
) PrintUsageAndExit ();
307 end_date
= DateTime
.ParseExact (args
[i
], formats
,
308 CultureInfo
.InvariantCulture
,
309 DateTimeStyles
.None
);
310 } catch (FormatException
) {
311 Console
.WriteLine ("Invalid end date");
312 System
.Environment
.Exit (-1);
314 end_date
= end_date
.ToUniversalTime ();
318 ReadBackendMappings ();
319 QueryDriver
.ReadKeywordMappings ();
321 Console
.WriteLine ("Supported query keywords are:");
323 IDictionaryEnumerator property_keyword_enum
= PropertyKeywordFu
.MappingEnumerator
;
324 while (property_keyword_enum
.MoveNext ()) {
325 PropertyDetail prop
= property_keyword_enum
.Value
as PropertyDetail
;
326 if (prop
.Description
!= null)
327 Console
.WriteLine (" {0,-20} for {1}", property_keyword_enum
.Key
, prop
.Description
);
329 Console
.WriteLine (" {0,-20}", property_keyword_enum
.Key
);
332 System
.Environment
.Exit (0);
337 // We have to do some nastiness here to deal with shell quoting.
338 // See beagled/QueryStringParser.cs for an idea of how this works.
339 string Pattern
= "(?<pm>[+-]?) (?<key>\\w+:)? (?<expr>.*)";
340 Regex r
= new Regex (Pattern
, RegexOptions
.IgnorePatternWhitespace
);
341 Match m
= r
.Match (args
[i
]);
343 string quoted_query
= m
.Groups
["pm"].ToString () +
344 m
.Groups
["key"].ToString () +
345 "\"" + m
.Groups
["expr"].ToString () + "\"";
347 if (query_str
.Length
> 0)
348 query_str
.Append (' ');
349 query_str
.Append (quoted_query
);
360 query
.IsIndexListener
= true;
364 if (query_str
.Length
> 0)
365 query
.AddText (query_str
.ToString ());
367 if (start_date
!= DateTime
.MinValue
|| end_date
!= DateTime
.MinValue
) {
368 QueryPart_DateRange part
= new QueryPart_DateRange ();
370 if (start_date
!= DateTime
.MinValue
)
371 part
.StartDate
= start_date
;
373 if (end_date
!= DateTime
.MinValue
)
374 part
.EndDate
= end_date
;
376 query
.AddPart (part
);
380 query
.HitsAddedEvent
+= OnHitsAdded
;
381 query
.HitsSubtractedEvent
+= OnHitsSubtracted
;
385 query
.FinishedEvent
+= OnFinished
;
387 query
.ClosedEvent
+= OnClosed
;