4
// Copyright (C) 2008 D Bera <dbera.web@gmail.com>
5
// Copyright (C) 2004-2006 Novell, Inc.
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in all
17
// copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
using System.Collections;
31
using System.Collections.Generic;
32
using System.Reflection;
34
using System.Runtime.InteropServices;
42
// Assembly information
43
[assembly: AssemblyTitle ("beagle-static-query")]
44
[assembly: AssemblyDescription ("Command-line interface to query the Beagle index")]
46
public class QueryTool {
48
private static int count = 0;
49
private static Query query = null;
50
private static DateTime queryStartTime;
51
private static DateTime lastQueryTime = DateTime.Now;
54
private static bool verbose = false;
55
private static bool display_hits = true;
56
private static bool display_cached_text = false;
58
private static void OnHitsAdded (QueryResult result, ICollection hits, int num_hits)
60
lastQueryTime = DateTime.Now;
62
if (count == 0 && verbose) {
63
Console.WriteLine ("First hit returned in {0:0.000}s",
64
(lastQueryTime - queryStartTime).TotalSeconds);
67
if (verbose && num_hits >= 0)
68
Console.WriteLine ("Returned latest {0} results out of total {1} matches", hits.Count, num_hits);
75
foreach (Hit hit in hits) {
77
Console.WriteLine (" Uri: {0}", hit.Uri);
79
Console.WriteLine (hit.Uri);
82
SnippetRequest sreq = new SnippetRequest (query, hit);
83
if (display_cached_text)
86
List<SnippetLine> snippets = GetSnippet (sreq);
87
Console.WriteLine ("PaUri: {0}", hit.ParentUri != null ? hit.ParentUri.ToString () : "(null)");
88
if (! display_cached_text) {
89
Console.Write (" Snip: ");
90
if (snippets.Count == 0)
91
Console.WriteLine ("(null)");
93
foreach (SnippetLine snippet_line in snippets) {
94
Console.Write (snippet_line);
95
Console.Write (" ... ");
102
Console.WriteLine (" Type: {0}", hit.Type);
103
Console.WriteLine ("MimeT: {0}", hit.MimeType == null ? "(null)" : hit.MimeType);
104
Console.WriteLine (" Src: {0}", hit.Source);
105
Console.WriteLine ("Score: {0}", hit.Score);
106
if (hit.ValidTimestamp)
107
Console.WriteLine (" Time: {0}", DateTimeUtil.ToString (hit.Timestamp));
109
foreach (Property prop in hit.Properties)
110
Console.WriteLine (" {0} = '{1}'",
112
(prop.Type != PropertyType.Date ? prop.Value : DateTimeUtil.ToString (StringFu.StringToDateTime (prop.Value))));
115
if (display_cached_text) {
116
Console.WriteLine ("-- Cache -------------------------------------");
117
if (snippets.Count == 0)
118
Console.WriteLine ("(empty)");
120
foreach (SnippetLine snippet_line in snippets) {
121
if (snippet_line == null || snippet_line.Fragments == null)
122
Console.WriteLine ("(empty)");
124
Console.WriteLine (((Fragment)snippet_line.Fragments [0]).Text);
127
Console.WriteLine ("----------------------------------------------");
129
Console.WriteLine ();
136
private static void OnFinished (QueryResult result)
139
Console.WriteLine ("Elapsed time: {0:0.000}s",
140
(DateTime.Now - queryStartTime).TotalSeconds);
141
Console.WriteLine ("Total hits: {0}", count);
145
private static List<SnippetLine> GetSnippet (SnippetRequest request)
147
Queryable queryable = QueryDriver.GetQueryable (request.Hit.Source);
148
ISnippetReader snippet_reader;
149
bool full_text = request.FullText;
150
int ctx_length = request.ContextLength;
151
int snp_length = request.SnippetLength;
153
if (queryable == null) {
154
Console.WriteLine ("SnippetExecutor: No queryable object matches '{0}'", request.Hit.Source);
155
snippet_reader = new SnippetReader (null, null, false, -1, -1);
158
snippet_reader = queryable.GetSnippet (request.QueryTerms, request.Hit, full_text, ctx_length, snp_length);
160
List<SnippetLine> snippetlines = new List<SnippetLine> ();
161
if (snippet_reader == null)
165
foreach (SnippetLine snippet_line in snippet_reader.GetSnippet ())
166
snippetlines.Add (snippet_line);
168
SnippetLine snippet_line = new SnippetLine ();
169
snippet_line.Line = 1;
171
Fragment fragment = new Fragment ();
172
fragment.QueryTermIndex = -1;
173
StringBuilder sb = new StringBuilder ();
176
// Read data from snippet_reader and write
177
while ((line = snippet_reader.ReadLine ()) != null) {
178
sb.Append (StringFu.CleanupInvalidXmlCharacters (line));
182
fragment.Text = sb.ToString ();
183
snippet_line.Fragments = new ArrayList ();
184
snippet_line.Fragments.Add (fragment);
185
snippetlines.Add (snippet_line);
188
snippet_reader.Close ();
193
public static void PrintUsageAndExit ()
195
VersionFu.PrintHeader ();
198
"Usage: beagle-query [OPTIONS] <query string>\n\n" +
200
" --verbose\t\tPrint detailed information about each hit.\n" +
201
" --cache\t\tShow the entire cached text instead of a snippet\n" +
202
" \t\tshowing the matches, requires --verbose.\n" +
203
" \t\tFor large documents this will produce extremely large output,\n" +
204
" \t\tso use this with uri queries or queries returning only a few results\n" +
205
" \t\tNot recommended for live-queries or stats-only queries.\n" +
206
" --keywords\t\tLists the keywords allowed in 'query string'.\n" +
207
" \t\tKeyword queries can be specified as keywordname:value e.g. ext:jpg\n" +
208
" --stats-only\t\tOnly display statistics about the query, not\n" +
209
" \t\tthe actual results.\n" +
210
" --max-hits\t\tLimit number of search results per backend\n" +
211
" \t\t(default 100)\n" +
214
" --help\t\tPrint this usage message.\n" +
215
" --version\t\tPrint version information.\n" +
217
"Query string supports an advanced query syntax.\n" +
218
"For details of the query syntax, please see http://beagle-project.org/Searching_Data\n" +
219
"Note: Quotes (\" or \') need to be shell escaped if used.\n";
221
Console.WriteLine (usage);
223
System.Environment.Exit (0);
226
[DllImport("libgobject-2.0.so.0")]
227
static extern void g_type_init ();
229
public static void Main (string[] args)
231
// Initialize GObject type system
234
Beagle.Util.Log.Level = LogLevel.Always; // shhhh... silence
236
if (args.Length == 0 || Array.IndexOf (args, "--help") > -1 || Array.IndexOf (args, "--usage") > -1)
237
PrintUsageAndExit ();
239
if (Array.IndexOf (args, "--version") > -1) {
240
VersionFu.PrintVersion ();
241
Environment.Exit (0);
244
StringBuilder query_str = new StringBuilder ();
246
query = new Query ();
251
while (i < args.Length) {
258
display_cached_text = true;
262
display_hits = false;
265
if (++i >= args.Length) PrintUsageAndExit ();
266
query.MaxHits = Int32.Parse (args[i]);
269
case "--list-backends":
270
Console.WriteLine ("Current available backends:");
271
Console.Write (QueryDriver.ListBackends ());
272
Environment.Exit (0);
276
if (++i >= args.Length) PrintUsageAndExit ();
279
if (next_arg.StartsWith ("--")) {
280
Console.WriteLine ("--backend requires a backend name. Invalid name '{0}'", next_arg);
281
Environment.Exit (1);
285
if (next_arg [0] != '+' && next_arg [0] != '-')
286
QueryDriver.OnlyAllow (next_arg);
288
if (next_arg [0] == '+')
289
QueryDriver.Allow (next_arg.Substring (1));
291
QueryDriver.Deny (next_arg.Substring (1));
296
case "--add-static-backend":
297
if (++i >= args.Length) PrintUsageAndExit ();
300
if (! next_arg.StartsWith ("--"))
301
QueryDriver.AddStaticQueryable (next_arg);
305
PropertyKeywordFu.ReadKeywordMappings ();
307
Console.WriteLine ("Supported query keywords are:");
309
foreach (string key in PropertyKeywordFu.Keys) {
310
foreach (QueryKeywordMapping mapping in PropertyKeywordFu.Properties (key)) {
311
// Dont print properties without description; they confuse people
312
if (string.IsNullOrEmpty (mapping.Description))
314
Console.WriteLine (" {0,-20} for {1}", key, mapping.Description);
318
System.Environment.Exit (0);
322
if (args [i].StartsWith ("--"))
323
PrintUsageAndExit ();
324
if (query_str.Length > 0)
325
query_str.Append (' ');
326
query_str.Append (args [i]);
335
Beagle.Util.Log.Level = LogLevel.Debug;
337
if (query_str.Length > 0)
338
query.AddText (query_str.ToString ());
340
Stopwatch watch = new Stopwatch ();
345
Console.WriteLine ("QueryDriver started in {0}", watch);
347
QueryResult result = new QueryResult ();
348
result.HitsAddedEvent += OnHitsAdded;
349
result.FinishedEvent += OnFinished;
351
queryStartTime = DateTime.Now;
352
QueryDriver.DoQueryLocal (query, result);
356
private static void StartQueryDriver ()
359
string tmp = PathFinder.StorageDir;
360
if (! Directory.Exists (tmp))
361
throw new IOException ("Beagle directory not found");
362
} catch (Exception e) {
363
Console.WriteLine ("Unable to start the daemon: {0}", e.Message);
364
Environment.Exit (-1);
367
QueryDriver.IndexingDelay = -1;
370
Console.WriteLine ("Starting Beagle Daemon (version {0})", ExternalStringsHack.Version);
371
Console.WriteLine ("Running on {0}", SystemInformation.MonoRuntimeVersion);
374
// Check if global configuration files are installed
375
if (! Conf.CheckGlobalConfig ()) {
376
Console.WriteLine ("Global configuration files not found in '{0}'", PathFinder.ConfigDataDir);
377
Environment.Exit (-1);
381
QueryDriver.Start ();