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