diff options
author | Ricardo Wurmus <rekado@elephly.net> | 2020-03-12 12:08:22 +0100 |
---|---|---|
committer | Ricardo Wurmus <rekado@elephly.net> | 2020-03-12 12:08:22 +0100 |
commit | 380eb969042d004ffeffe42479e249f2412ec3ca (patch) | |
tree | 7ed69c591c0dcfcffacf5c130f821ec33ee5acc9 | |
parent | 53cc7b44381f1af08eff9313fbfaee120dae90ab (diff) |
messages: Implement search with mu.
* mumi/messages.scm (search-bugs): Use mu to find messages according
to the query, then filter by message sets from the local database.
(ago, date-term->epoch-seconds): Remove procedures.
(punctuation?): New procedure.
(process-query): Remove handling of attributes; replace filters with
sets; build up mu query and use local database for bug sets.
* mumi/web/controller.scm (controller): Adjust call of search-bugs.
-rw-r--r-- | mumi/messages.scm | 165 | ||||
-rw-r--r-- | mumi/web/controller.scm | 18 |
2 files changed, 55 insertions, 128 deletions
diff --git a/mumi/messages.scm b/mumi/messages.scm index 6ccad33..63f68df 100644 --- a/mumi/messages.scm +++ b/mumi/messages.scm @@ -196,19 +196,17 @@ result for a while." (_ #f))))) msg-nums))))))) -(define* (search-bugs query #:key (attributes '()) (max 100)) - "Return a list of all bugs matching the given QUERY string." - (let* ((matches (soap-invoke* (%config 'debbugs) - search-est - query - #:max max - #:attributes - (append attributes - '((package string-prefix "guix"))))) - (ids (filter-map (lambda (item) - (assoc-ref item "id")) - matches))) - (status-with-cache ids))) +(define* (search-bugs query #:key (sets '()) (max 100)) + "Return a list of all bugs matching the given QUERY string. +Interset the result with the id sets in the list SETS." + (let* ((ids (delete-duplicates + (map (compose string->number mu:bugid) + (mu:message-list query)))) + (filtered (match sets + (() ids) + (_ (apply lset-intersection eq? ids sets))))) + (status-with-cache (if (> (length filtered) max) + (take filtered max) filtered)))) ;; TODO: This returns *any* matching debbugs bug, even if it is not ;; part of the default packages. @@ -241,125 +239,68 @@ result for a while." severity-ids))) (status-with-cache ids))) -(define (ago unit amount) - "Return the point in time that lies AMOUNT UNITs in the past." - (let ((amount* (match unit - ('hours amount) - ('days (* 24 amount)) - ('weeks (* 24 7 amount)) - ('months (* 24 30 amount)) - ('years (* 24 365 amount))))) - (subtract-duration (date->time-utc (current-date)) - (make-time time-duration 0 (* 60 60 amount*))))) - -(define (date-term->epoch-seconds term) - "Convert a date search term string into seconds since the epoch, or -return #F if the term is invalid." - (match term - ("now" 'now) - ("today" (time-second (ago 'days 1))) - ("yesterday" (time-second (ago 'days 2))) - (_ - (cond - ;; TODO: support more date template strings - ((or (false-if-exception (string->date term "~Y~m~d")) - (false-if-exception (string->date term "~Y-~m-~d"))) - => (lambda (date) - (time-second (date->time-utc date)))) - ;; e.g. "12h" meaning "12 hours ago" - ((string->number (string-drop-right term 1)) - => (lambda (amount) - (match (string-take-right term 1) - ("h" - (time-second (ago 'hours amount))) - ("d" - (time-second (ago 'days amount))) - ("w" - (time-second (ago 'weeks amount))) - ("m" - (time-second (ago 'months amount))) - ("y" - (time-second (ago 'years amount))) - (_ #f)))) - (else #f))))) +(define punctuation? + (cut char-set-contains? char-set:punctuation <>)) (define-public (process-query query) - "Process the QUERY string and return two values: the remaining -unprocessed query string and an alist of search attributes." + "Process the QUERY string and return a list of query terms and +sets that need to overlap the result set." + ;; Mu doesn't like punctuation. Replace with spaces. + (define (clean-term term) + (string-map (match-lambda + ((? punctuation? c) #\space) + (c c)) + term)) (fold (lambda (term acc) (match acc ((#:terms terms - #:attributes attrs - #:filters fs) + #:sets fs) (match (string-split term #\:) ;; This is not supported by the Debbugs SOAP service, ;; so we filter locally. (("is" (or "done" "closed")) `(#:terms ,terms - #:attributes ,attrs - #:filters - ,(cons bug-done fs))) + #:sets ,(cons (db:bugs-by-status "done") fs))) (("is" (or "open" "pending")) `(#:terms ,terms - #:attributes ,attrs - #:filters - ,(cons (negate bug-done) fs))) - ;; "date" for submission date, "mdate" for message date. - (((and (or "date" "mdate") type) when) - (let ((date-attribute (match type - ("date" 'date) - ("mdate" '@cdate))) - (pat "(yesterday|today|now|[1-9][0-9]*(h|d|w|m|y)|[0-9]+)")) - (or (match (map (compose date-term->epoch-seconds - match:substring) - (list-matches pat when)) - ((and ((? number? start) - (? number? end)) - range) - (match (sort range <) - ((start end) - `(#:terms ,terms - #:attributes ,(cons `(,date-attribute >< ,start ,end) attrs) - #:filters ,fs)))) - ((or ('now (? number? since)) - ((? number? since) 'now)) - `(#:terms ,terms - #:attributes ,(cons `(,date-attribute > ,since) attrs) - #:filters ,fs)) - (_ #f)) - ;; Invalid, don't do anything. - `(#:terms ,terms - #:attributes ,attrs - #:filters ,fs)))) + #:sets ,(cons (db:bugs-by-status "open") fs))) + (("date" when) + `(#:terms ,(cons (string-append "date:" when) terms) + #:sets ,fs)) + ;; TODO: this should only be the title of the bug, not + ;; the subject. (("title" title) - `(#:terms ,terms - #:attributes ,(cons `(subject string-contains ,title) attrs) - #:filters ,fs)) + `(#:terms + ,(cons (string-append "subject:" (clean-term title)) + terms) + #:sets ,fs)) + (("subject" subject) + `(#:terms + ,(cons (string-append "subject:" (clean-term subject)) + terms) + #:sets ,fs)) (("tag" tag) `(#:terms ,terms - #:attributes ,(cons `(tags string= ,tag) attrs) - #:filters ,fs)) + #:sets + ,(cons (db:bugs-by-tag (clean-term tag)) fs))) (("author" who) + `(#:terms + ,(cons (string-append "from:" (clean-term who)) terms) + #:sets ,fs)) + (("owner" who) `(#:terms ,terms - #:attributes ,(cons `(@author string-contains ,who) attrs) - #:filters ,fs)) - ;; This is not supported by the Debbugs SOAP service, - ;; so we filter locally. At least we know that we need - ;; bugs where the author is "who". + #:sets ,(cons (db:bugs-by-owner who) fs))) (("submitter" who) `(#:terms ,terms - #:attributes ,(cons `(@author string-contains ,who) attrs) - #:filters ,(cons (lambda (bug) - (string-contains-ci (bug-originator bug) - who)) - fs))) + #:sets ,(cons (db:bugs-by-submitter who) fs))) (("severity" level) `(#:terms ,terms - #:attributes ,(cons `(severity string= ,level) attrs) - #:filters ,fs)) + #:sets ,(cons (db:bugs-by-severity level) fs))) + ((whatever term) + `(#:terms ,(cons (clean-term term) terms) + #:sets ,fs)) (_ - `(#:terms ,(cons term terms) - #:attributes ,attrs - #:filters ,fs)))))) - '(#:terms () #:attributes () #:filters ()) + `(#:terms ,(cons (clean-term term) terms) + #:sets ,fs)))))) + '(#:terms () #:sets ()) (string-tokenize query))) diff --git a/mumi/web/controller.scm b/mumi/web/controller.scm index 7f0d9d5..e854823 100644 --- a/mumi/web/controller.scm +++ b/mumi/web/controller.scm @@ -81,23 +81,9 @@ (list-of-matching-bugs query (match (process-query query) ((#:terms terms - #:attributes attrs - #:filters '()) + #:sets s) (search-bugs (string-join terms) - #:attributes attrs)) - ;; Fetch more messages if there - ;; are local filters to increase - ;; the chance of finding some - ;; that pass the filter. - ((#:terms terms - #:attributes attrs - #:filters fs) - (let ((str (string-join terms))) - (filter (lambda (bug) - (every (lambda (f) (f bug)) fs)) - (search-bugs (string-join terms) - #:attributes attrs - #:max 800))))))) + #:sets s))))) `(p "Could not search for " (strong ,query) ".")))))) (('GET "issue" (? string->number id)) (render-with-error-handling |