Home | History | Annotate | Download | only in emacs
      1 ; To use this,
      2 ; 1) Add to init.el:
      3 ;    (setq-default chrome-root "/path/to/chrome/src/")
      4 ;    (add-to-list 'load-path (concat chrome-root "tools/emacs"))
      5 ;    (require 'trybot)
      6 ; 2) Run on trybot output:
      7 ;    M-x trybot
      8 ;
      9 ; To hack on this,
     10 ; M-x eval-buffer
     11 ; M-x trybot-test-win  or  M-x trybot-test-mac
     12 
     13 (defvar chrome-root nil
     14   "Path to the src/ directory of your Chrome checkout.")
     15 
     16 (defun get-chrome-root ()
     17   (or chrome-root default-directory))
     18 
     19 ; Hunt down from the top, case correcting each path component as needed.
     20 ; Currently does not keep a cache.  Returns nil if no matching file can be
     21 ; figured out.
     22 (defun case-corrected-filename (filename)
     23   (save-match-data
     24     (let ((path-components (split-string filename "/"))
     25           (corrected-path (file-name-as-directory (get-chrome-root))))
     26       (mapc
     27        (function
     28         (lambda (elt)
     29           (if corrected-path
     30               (let ((next-component
     31                      (car (member-ignore-case
     32                            elt (directory-files corrected-path)))))
     33                 (setq corrected-path
     34                       (and next-component
     35                            (file-name-as-directory
     36                             (concat corrected-path next-component))))))))
     37        path-components)
     38       (if corrected-path
     39           (file-relative-name (directory-file-name corrected-path)
     40                               (get-chrome-root))
     41         nil))))
     42 
     43 (defun trybot-fixup-win ()
     44   "Fix up Windows-specific output."
     45 
     46   ; Fix Windows paths ("d:\...\src\").
     47   (save-excursion
     48     ; This regexp is subtle and rather hard to read. :~(
     49     ; Use regexp-builder when making changes to it.
     50     (while (re-search-forward
     51             (concat
     52              ; First part: path leader, either of the form
     53              ;   e:\...src\  or  ..\
     54              "\\(^.:\\\\.*\\\\src\\\\\\|\\.\\.\\\\\\)"
     55              ; Second part: path, followed by error message marker.
     56              "\\(.*?\\)[(:]") nil t)
     57       (replace-match "" nil t nil 1)
     58       ; Line now looks like:
     59       ;  foo\bar\baz.cc error message here
     60       ; We want to fixup backslashes in path into forward slashes,
     61       ; without modifying the error message - by matching up to the
     62       ; first colon above (which will be just beyond the end of the
     63       ; filename) we can use the end of the match as a limit.
     64       (subst-char-in-region (point) (match-end 0) ?\\ ?/)
     65       ; See if we can correct the file name casing.
     66       (let ((filename (buffer-substring (match-beginning 2) (match-end 2))))
     67         (if (and (not (file-exists-p filename))
     68                  (setq filename (case-corrected-filename filename)))
     69             (replace-match filename t t nil 2))))))
     70 
     71 (defun trybot-fixup-maclin ()
     72   "Fix up Mac/Linux output."
     73   (save-excursion
     74     (while (re-search-forward "^/b/build/[^ ]*/src/" nil t)
     75       (replace-match ""))))
     76 
     77 (defun trybot-fixup (type-hint)
     78   "Parse and fixup the contents of the current buffer as trybot output."
     79 
     80   ; XXX is there something I should so so this stuff doesn't end up on the
     81   ; undo stack?
     82 
     83   ;; Fixup paths.
     84   (cd (get-chrome-root))
     85 
     86   (goto-char (point-min))
     87 
     88   ;; Fix up path references.
     89   (cond ((eq type-hint 'win) (trybot-fixup-win))
     90         ((eq type-hint 'mac) (trybot-fixup-maclin))
     91         ((eq type-hint 'linux) (trybot-fixup-maclin))
     92         (t (trybot-fixup-win) (trybot-fixup-maclin)))
     93 
     94   (compilation-mode))
     95 
     96 (defun trybot-get-new-buffer ()
     97   "Get a new clean buffer for trybot output."
     98   ; Use trybot-buffer-name if available; otherwise, "*trybot*".
     99   (let ((buffer-name (if (boundp 'trybot-buffer-name)
    100                          trybot-buffer-name
    101                        "*trybot*")))
    102     (let ((old (get-buffer buffer-name)))
    103       (when old (kill-buffer old)))
    104     (get-buffer-create buffer-name)))
    105 
    106 (defun trybot-fetch (type-hint url)
    107   "Fetch a URL and postprocess it as trybot output."
    108 
    109   (let ((on-fetch-completion
    110          (lambda (process state)
    111            (switch-to-buffer (process-buffer process))
    112            (when (equal state "finished\n")
    113              (trybot-fixup (process-get process 'type-hint)))))
    114         (command (concat "curl -s " (shell-quote-argument url)
    115                          ; Pipe it through the output shortener.
    116                          (cond
    117                           ((eq type-hint 'win)
    118                            (concat " | " (get-chrome-root)
    119                                    "build/sanitize-win-build-log.sh"))
    120                           ((eq type-hint 'mac)
    121                            (concat " | " (get-chrome-root)
    122                                    "build/sanitize-mac-build-log.sh"))))))
    123 
    124     ; Start up the subprocess.
    125     (let* ((coding-system-for-read 'utf-8-dos)
    126            (buffer (trybot-get-new-buffer))
    127            (process (start-process-shell-command "curl" buffer command)))
    128       ; Attach the type hint to the process so we can get it back when
    129       ; the process completes.
    130       (process-put process 'type-hint type-hint)
    131       (set-process-query-on-exit-flag process nil)
    132       (set-process-sentinel process on-fetch-completion))))
    133 
    134 (defun trybot-test (type-hint filename)
    135   "Load the given test data filename and do the trybot parse on it."
    136 
    137   (let ((trybot-buffer-name "*trybot-test*")
    138         (url (concat "file://" (get-chrome-root) "tools/emacs/" filename)))
    139     (trybot-fetch type-hint url)))
    140 
    141 (defun trybot-test-win ()
    142   "Load the Windows test data and do the trybot parse on it."
    143   (interactive)
    144   (trybot-test 'win "trybot-windows.txt"))
    145 (defun trybot-test-mac ()
    146   "Load the Mac test data and do the trybot parse on it."
    147   (interactive)
    148   (trybot-test 'mac "trybot-mac.txt"))
    149 (defun trybot-test-linux ()
    150   "Load the Linux test data and do the trybot parse on it."
    151   (interactive)
    152   (trybot-test 'linux "trybot-linux.txt"))
    153 
    154 (defun trybot (url)
    155   "Fetch a trybot URL and fix up the output into a compilation-mode buffer."
    156   (interactive "sURL to trybot stdout (leave empty to use clipboard): ")
    157 
    158   ;; Yank URL from clipboard if necessary.
    159   (when (= (length url) 0)
    160     (with-temp-buffer
    161       (clipboard-yank)
    162       (setq url (buffer-string))))
    163 
    164   ;; Append /text to the URL to get plain text output in the common
    165   ;; case of getting a URL to the HTML build log.
    166   (when (equal "stdio" (car (last (split-string url "/"))))
    167     (setq url (concat url "/text")))
    168 
    169   (let ((type-hint (cond ((string-match "/[Ww]in" url) 'win)
    170                          ((string-match "/mac/" url) 'mac)
    171                          ; Match /linux, /linux_view, etc.
    172                          ((string-match "/linux" url) 'linux)
    173                          (t 'unknown))))
    174     (trybot-fetch type-hint url)))
    175 
    176 (provide 'trybot)
    177