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
);
70 count
+= response
.Hits
.Count
;
74 foreach (Hit hit
in response
.Hits
) {
76 Console
.WriteLine (" Uri: {0}", hit
.Uri
);
78 Console
.WriteLine (hit
.Uri
);
81 SnippetRequest sreq
= new SnippetRequest (query
, hit
);
82 SnippetResponse sresp
= (SnippetResponse
) sreq
.Send ();
83 Console
.WriteLine ("PaUri: {0}", hit
.ParentUri
!= null ? hit
.ParentUri
.ToString () : "(null)");
84 Console
.WriteLine (" Snip: {0}", sresp
.Snippet
!= null ? sresp
.Snippet
: "(null)");
85 Console
.WriteLine (" Type: {0}", hit
.Type
);
86 Console
.WriteLine ("MimeT: {0}", hit
.MimeType
== null ? "(null)" : hit
.MimeType
);
87 Console
.WriteLine (" Src: {0}", hit
.Source
);
88 Console
.WriteLine ("Score: {0}", hit
.Score
);
89 if (hit
.ValidTimestamp
)
90 Console
.WriteLine (" Time: {0}", hit
.Timestamp
.ToLocalTime ());
92 foreach (Property prop
in hit
.Properties
)
93 Console
.WriteLine (" {0} = '{1}'", prop
.Key
, prop
.Value
);
102 private static void OnHitsSubtracted (HitsSubtractedResponse response
)
104 lastQueryTime
= DateTime
.Now
;
109 foreach (Uri uri
in response
.Uris
) {
110 Console
.WriteLine ("Subtracted Uri '{0}'", uri
);
111 Console
.WriteLine ();
117 private static void OnFinished (FinishedResponse response
)
120 Console
.WriteLine ("Elapsed time: {0:0.000}s",
121 (DateTime
.Now
- queryStartTime
).TotalSeconds
);
122 Console
.WriteLine ("Total hits: {0}", count
);
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-2006 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
.GetTypesFromAssemblyAttribute (assembly
, typeof (IQueryableTypesAttribute
))) {
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 ()
216 private static int query_counter
= 0;
217 private static void SendQuery ()
221 if (query_counter
> 1)
222 Console
.WriteLine ();
223 Console
.WriteLine ("Sending query #{0}", query_counter
);
226 queryStartTime
= DateTime
.Now
;
229 } catch (Exception ex
) {
230 Console
.WriteLine ("Could not connect to the Beagle daemon. The daemon probably isn't running.");
231 Console
.WriteLine (ex
);
232 System
.Environment
.Exit (-1);
236 [DllImport("libgobject-2.0.so.0")]
237 static extern void g_type_init ();
239 public static void Main (string[] args
)
241 // Initialize GObject type system
244 main_loop
= new MainLoop ();
246 if (args
.Length
== 0 || Array
.IndexOf (args
, "--help") > -1 || Array
.IndexOf (args
, "--usage") > -1)
247 PrintUsageAndExit ();
249 StringBuilder query_str
= new StringBuilder ();
256 query
= new Query ();
260 while (i
< args
.Length
) {
264 if (++i
>= args
.Length
) PrintUsageAndExit ();
265 query
.AddMimeType (args
[i
]);
268 if (++i
>= args
.Length
) PrintUsageAndExit ();
269 query
.AddHitType (args
[i
]);
272 if (++i
>= args
.Length
) PrintUsageAndExit ();
273 query
.AddSource (args
[i
]);
283 display_hits
= false;
286 if (++i
>= args
.Length
) PrintUsageAndExit ();
287 query
.MaxHits
= Int32
.Parse (args
[i
]);
297 if (++i
>= args
.Length
) PrintUsageAndExit ();
299 start_date
= DateTime
.ParseExact (args
[i
], formats
,
300 CultureInfo
.InvariantCulture
,
301 DateTimeStyles
.None
);
302 } catch (FormatException
) {
303 Console
.WriteLine ("Invalid start date");
304 System
.Environment
.Exit (-1);
306 start_date
= start_date
.ToUniversalTime ();
310 if (++i
>= args
.Length
) PrintUsageAndExit ();
312 end_date
= DateTime
.ParseExact (args
[i
], formats
,
313 CultureInfo
.InvariantCulture
,
314 DateTimeStyles
.None
);
315 } catch (FormatException
) {
316 Console
.WriteLine ("Invalid end date");
317 System
.Environment
.Exit (-1);
319 end_date
= end_date
.ToUniversalTime ();
323 ReadBackendMappings ();
324 QueryDriver
.ReadKeywordMappings ();
326 Console
.WriteLine ("Supported query keywords are:");
328 IDictionaryEnumerator property_keyword_enum
= PropertyKeywordFu
.MappingEnumerator
;
329 while (property_keyword_enum
.MoveNext ()) {
330 PropertyDetail prop
= property_keyword_enum
.Value
as PropertyDetail
;
331 if (prop
.Description
!= null)
332 Console
.WriteLine (" {0,-20} for {1}", property_keyword_enum
.Key
, prop
.Description
);
334 Console
.WriteLine (" {0,-20}", property_keyword_enum
.Key
);
337 System
.Environment
.Exit (0);
342 // We have to do some nastiness here to deal with shell quoting.
343 // See beagled/QueryStringParser.cs for an idea of how this works.
344 string Pattern
= "(?<pm>[+-]?) (?<key>\\w+:)? (?<expr>.*)";
345 Regex r
= new Regex (Pattern
, RegexOptions
.IgnorePatternWhitespace
);
346 Match m
= r
.Match (args
[i
]);
348 string quoted_query
= m
.Groups
["pm"].ToString () +
349 m
.Groups
["key"].ToString () +
350 "\"" + m
.Groups
["expr"].ToString () + "\"";
352 if (query_str
.Length
> 0)
353 query_str
.Append (' ');
354 query_str
.Append (quoted_query
);
365 query
.IsIndexListener
= true;
369 if (query_str
.Length
> 0)
370 query
.AddText (query_str
.ToString ());
372 if (start_date
!= DateTime
.MinValue
|| end_date
!= DateTime
.MinValue
) {
373 QueryPart_DateRange part
= new QueryPart_DateRange ();
375 if (start_date
!= DateTime
.MinValue
)
376 part
.StartDate
= start_date
;
378 if (end_date
!= DateTime
.MinValue
)
379 part
.EndDate
= end_date
;
381 query
.AddPart (part
);
385 query
.HitsAddedEvent
+= OnHitsAdded
;
386 query
.HitsSubtractedEvent
+= OnHitsSubtracted
;
390 query
.FinishedEvent
+= OnFinished
;
392 query
.ClosedEvent
+= OnClosed
;