(defconst elpa-download-log-line-re (rx (group (1+ (or digit "." ":"))) " - - " "[" (group (repeat 2 digit) "/" (repeat 3 alpha) "/" (repeat 4 digit) ":" (repeat 2 digit) ":" (repeat 2 digit) ":" (repeat 2 digit) " " (or "+" "-") (repeat 4 digit)) "]" ;; ;; HTTP query: " \"" (group (1+ alpha)) ; method " " (group (1+ (not (any blank)))) ; path " " "HTTP/" (1+ (or alnum ".")) "\"" ; protocol " " (group (1+ digit)) ; status code " " (group (1+ digit)) ; size " \"-\" " ; ? "\"" (group (1+ (not (any "\"")))) "\"")) (defun elpa-log-to-package-stats (log-string) "Return alist of (PACKAGE . DOWNLOADS) seen in LOG-STRING. LOG-STRING is an HTTP download log." (let ((stats (make-hash-table :test #'equal))) (with-temp-buffer (insert log-string) (goto-char (point-min)) (cl-loop while (re-search-forward elpa-download-log-line-re nil t) for file = (match-string 4) when (string-match-p (rx bos "/packages/" (1+ anything) (or ".tar" ".el") eos) file) do (if (gethash file stats) (cl-incf (gethash file stats)) (setf (gethash file stats) 1)))) (map-into stats 'alist))) ;; (("/packages/seq-2.23.tar" . 1) ("/packages/let-alist-1.0.6.el" . 1))