seanmcl avatar seanmcl committed 36bb6e0

notify-maintainer-of-error

Comments (0)

Files changed (12)

 new stuff
 =========
-- Got omake-mode working on OSX
+
+- omake-mode working on OSX
+
+- Omake.show-raw-buffer will show you the raw buffer for the last compilation
+  of a project that is not compiling.  This is important when your OMakefiles
+  are messed up, because in that case the omake process stops and the
+  project is killed immediately.
 
 changes
 =========
 
+- better error handling
+- better handling of preprocessor errors, which now appear as omake failures
+  rather than ocaml errors so you can see the context of the failure.
+-
+
 bug fixes
 =========
+
 - stopping server from the command line left connection objects alive
 
 --------------------------------------------------------------------------------

elisp/jane/jane-lib.el

   (let ((s (replace-regexp-in-string "^[[:space:]]*" "" s)))
     (replace-regexp-in-string "[[:space:]]*$" "" s)))
 (Jane.test (String.strip " abc def ") "abc def")
+(Jane.test (String.strip " abc \n def ") "abc\ndef")
 
 (defun String.eval (s)
   "Eval a string as code"
   (with-temp-buffer (insert s) (eval-buffer)))
 ;; Can't test.  Always returns nil.
 
+(defun String.escape-quotes (s)
+  (replace-regexp-in-string "\"" "\\\\\"" s))
+
 (defun String.escaped (s)
   "Escape newlines and quotes"
   (let ((tab '(("\n" . "\\\\n")
-;;  I can't figure out how to escape quotes (" --> \")
-;;               ("\"" . "\\\"")
-               )))
+               ("\"" . "\\\\\""))))
     (List.foldl (lambda (s p)
                   (let ((l (car p))
                         (r (cdr p)))
                 s tab)))
 (Jane.test (String.escaped "abc\ndef\"ghi\"") "abc\\ndef\"ghi\"")
 (Jane.test (String.escaped "abc") "abc")
+(Jane.test (String.escaped "\"abc\"") "\\\"abc\\\"")
 ;; (Jane.test (String.escaped "\"abc\"") "\"abc\"")
 
 (defun String.quote (s)
       (count-lines (point-min) (point-max)))))
 ;; (Buffer.num-lines path)
 
-(defun Buffer.clear (buffer)
+(defun Buffer.clear (&optional buffer)
   "Remove all contents of a given buffer"
-  (with-current-buffer buffer
-    (delete-region (point-min) (point-max))))
+  (let ((buf (if buffer buffer (current-buffer))))
+    (with-current-buffer buf
+      (delete-region (point-min) (point-max)))))
 
 (defun Buffer.eval-and-return (buf)
   "Eval a buffer and return the result of the last sexp."
   (let* ((file (dired-file-name-at-point)))
     (shell-command (format "hg resolve -m %s" file))))
 
+
 ;;----------------------------------------------------------------------------;;
 ;; Semaphores                                                                 ;;
 ;;----------------------------------------------------------------------------;;
           "Releasing a semaphore you haven't acquired.")
   (setf (Semaphore.val s) 0))
 
-;; (setq tmp (Semaphore.create))
-;; (Semaphore.acquire tmp)
-;; (Semaphore.release tmp)
+
+
+(defun* Mail.send (&key recipients subject body)
+  "Send email."
+  (when (null recipients) (error "empty recipients"))
+  (let* ((fst (car recipients))
+         (rst (cdr recipients))
+         (cmd
+          (format "echo \"%s\" | mail -s \"%s\" %s -t %s"
+                  ;;(String.escaped body) (String.escaped subject)
+                  body subject
+                  fst (apply 'concat (List.intersperse " " rst))))
+         (res (shell-command cmd)))
+    (unless (equal res 0) 
+      (error "Mail.send: failed"))))
+;; (setq recipients (list "seanmcl@gmail.com" "sweeks@gmail.com"))
+;; (setq body "abc")
+;; (setq subject "test7")
+;; (Mail.send :recipients recipients :subject subject :body body)
+;; (Mail.send :recipients '("seanmcl@gmail.com") :subject "foo" :body "bar")
 
 (provide 'jane-lib)

elisp/omake/make.sh

 
 file=/tmp/all.el
 
+case $(uname) in
+    Darwin)
+        path=/Users/seanmcl/save/projects/omake-mode/elisp/jane
+        ;;
+    Linux)
+        path=/home/seanmcl/jane-local/elisp/jane
+        ;;
+    *)
+        echo "Unknown system"
+esac
+
 files="
 omake-file.el
 omake-errors.el
   (require 'autorevert)
   (setq byte-compile-warnings (remove 'cl-functions byte-compile-warning-types))
   (require 'cl)
-  (add-to-list 'load-path "/home/seanmcl/jane-local/elisp/jane")
+  (add-to-list 'load-path "$path")
   (require 'jane-lib))
 (declare-function remove-if-not "cl-seq")
 (declare-function set-difference "cl-seq")

elisp/omake/omake-errors.el

     'Omake.Errors.abort
     "Aborted")
    (cons
+    'Omake.Errors.no-omakeroot
+    "Can't find an OMakeroot in this dir or any of its ancestors.")
+   (cons
     'Omake.Errors.file-perms
     (format "Can't read/write file.  Check the permissions in %s" Omake.File.root))))
 
   (declare (debug (body)))
   `(condition-case err
        (progn ,@body)
-     (Omake.Errors.all (message "Error: %s" (error-message-string err)))))
-;; (Omake.handle-errors (signal 'Omake.Errors.tramp '(1 2 3)))
-;; (defun foo (&optional x) (interactive) (Omake.handle-errors (let* ((x (if x x 5))) (message "%d" x))))
-;; (macroexpand '(Omake.handle-errors (signal 'Omake.Errors.tramp '(1 2 3))))
+     (Omake.Errors.all
+      (let ((msg (when err (car err)))
+            (data (when err (cdr err))))
+        (if data
+            (message "Error: %s (%s)" (error-message-string err) (cdr err))
+          (message "Error: %s" (error-message-string err)))))))
+
+(defmacro Omake.ignore-errors (&rest body)
+  (declare (indent defun))
+  (declare (debug (body)))
+  `(condition-case err
+       (progn ,@body)
+     (error nil)))
+;; (Omake.ignore-errors (error "abc"))
 
 (font-lock-add-keywords
  'emacs-lisp-mode
- '(("\\<\\(Omake.handle-errors\\)" 1 font-lock-keyword-face))
- t)
+ '(("\\<\\(Omake.handle-errors\\)" 1 font-lock-keyword-face)
+   ("\\<\\(Omake.defun\\)" 1 font-lock-keyword-face)) t)
 
 ;; (setq command-error-function nil)
 ;; (setq command-error-function
 ;;       (lambda (data context caller)
 ;;         (message "in command-error-function")))
 
-;; (signal 'Omake.Errors.tramp '(1 2 3))
-;; (error "abc")
+(defun Omake.Errors.bug-report-buffer ()
+  (get-buffer-create "[omake mode bug report]"))
+
+(defun Omake.Errors.get-bug-desc (callback)
+  (lexical-let*
+      ((callback callback)
+       (header 
+        (concat
+         "-------------------------------------------------------\n"
+         "Please describe the problem.  Type C-x # when finished.\n"
+         "-------------------------------------------------------\n\n"))
+       (start (length header))
+       (finish 
+        (lambda ()
+          (interactive)
+          (funcall callback (buffer-substring start (point-max)))
+          (kill-buffer (Omake.Errors.bug-report-buffer))))
+       (buf (Omake.Errors.bug-report-buffer)))
+    (pop-to-buffer buf)
+    (Buffer.clear)
+    (insert header)
+    (local-set-key (kbd "C-x #") finish)))
+;;(Omake.Errors.get-bug-desc (lambda (desc) (message desc)))
+
+(defun Omake.notify-maintainer-of-error ()
+  (interactive)
+  (make-directory Omake.File.bug-report-dir t)
+  (Omake.handle-errors
+    (lexical-let*
+        ((id (Omake.Id.current))
+         (existing (mapcar 'string-to-number (directory-files Omake.File.bug-report-dir)))
+         (n (1+ (apply 'max existing)))
+         (dir (expand-file-name (number-to-string n) Omake.File.bug-report-dir))
+         (_ (make-directory dir t))
+         (tramp (format "%s:%s" (system-name) dir))
+         (recipients (list Omake.maintainer-email-addr))
+         (subject "[omake-mode bug report]")
+         (callback (lambda (desc)
+                     (let* ((loc (format "Files: %s" tramp))
+                            (desc (format "User report:\n%s" (String.escape-quotes desc)))
+                            (body (format "%s\n\n%s" loc desc))
+                            (file (format "%s/%s" dir "user-report")))
+                       (with-temp-buffer 
+                         (insert desc)
+                         (write-region nil nil file))
+                       (Mail.send :recipients recipients
+                                  :subject subject
+                                  :body body))))
+         copy)
+      (fset 'copy
+            (lambda (f name) 
+              (Omake.ignore-errors
+                  (copy-file f (expand-file-name name dir)))))
+      (fset 'copy-buf
+            (lambda (b name) 
+              (Omake.ignore-errors
+               (with-current-buffer b (write-file name)))))
+      (message "Collecting bug files")
+      (copy Omake.File.server-log "server-log")
+      (copy Omake.File.server-state "server-state.el")
+      (copy Omake.File.mode-log "mode-log")
+      (copy (Omake.File.raw id) "raw")
+      (copy (Omake.File.elisp id) "elisp")
+      (copy (Omake.File.project-log id) "project-log")
+      (Omake.ignore-errors
+       (copy-buf (Omake.Buffer.get 'status) "status-buffer"))
+      (message "Emailing maintainer")
+      (Omake.Errors.get-bug-desc callback))))
 
 (provide 'omake-errors)

elisp/omake/omake-file.el

 (defconst Omake.File.server-log
   (expand-file-name "server-log" Omake.File.top))
 
+(defconst Omake.File.server-state
+  (expand-file-name "server-state.el" Omake.File.top))
+
 (defconst Omake.File.mode-log-dir
   (expand-file-name "mode-log" Omake.File.top))
 
     (concat (match-string 1 f) (if (match-beginning 2) ".ml" ".mli"))))
 ;; (Omake.File.partner "abc.ml")
 
+(defconst Omake.File.bug-report-dir
+  (format "%s/bug-report" Omake.File.top))
+
 ;; (defun Omake.File.check-perms (f &optional socket)
 ;;   ;; Don't worry about readability.  The socket can't be read, so
 ;;   ;; just consider writability (for uniformity).

elisp/omake/omake-id.el

 (defun Omake.Id.current ()
   (let ((path (Filename.default-directory)))
     (Omake.Id.of-path path)))
+;; (Omake.Id.current)
 
 (provide 'omake-id)

elisp/omake/omake-interface.el

 
 (defun Omake.next-error (&optional user-num id)
   (interactive "P")
-  (Omake.with-connection
-    (Omake.handle-errors
+  (Omake.handle-errors
+    (Omake.with-connection
       (catch 'exit
         ;; We'll definitely show the error window, so uniconify the error frame if it exists
         (Omake.Frame.uniconify 'status)
 
 (defun Omake.show-raw-buffer ()
   (interactive)
-  (display-buffer (Omake.Buffer.get 'raw (Omake.Project.current))))
+  (Omake.handle-errors
+    (let ((id (Omake.Id.current)))
+      (if (Omake.Project.find id)
+          (progn
+            (unless (Omake.Model.has id) (Omake.watch id))
+            (display-buffer (Omake.Buffer.get 'raw (Omake.Project.current))))
+        (let ((cont (y-or-n-p
+                     (format "No project is compiling for %s.\nDo you want to see the raw buffer from the previous compilation? " (Omake.Id.to-string id)))))
+          (when cont (find-file (Omake.File.raw id))))))))
 
 (defun Omake.show-elisp-buffer ()
   (interactive)
-  (display-buffer (Omake.Buffer.get 'elisp (Omake.Project.current))))
+  (Omake.handle-errors
+    (display-buffer (Omake.Buffer.get 'elisp (Omake.Project.current)))))
 
 (defun Omake.show-project-log ()
   (interactive)
-  (display-buffer (Omake.Buffer.get 'project-log (Omake.Project.current))))
+  (Omake.handle-errors
+    (display-buffer (Omake.Buffer.get 'project-log (Omake.Project.current)))))
 
 (defun Omake.show-mode-log ()
   (interactive)
-  (display-buffer (Omake.Buffer.get 'mode-log)))
+  (Omake.handle-errors
+    (display-buffer (Omake.Buffer.get 'mode-log))))
 
 (defun Omake.show-server-log ()
   (interactive)
-  (display-buffer (Omake.Buffer.get 'server-log)))
+  (Omake.handle-errors
+    (display-buffer (Omake.Buffer.get 'server-log))))
 
 ;;----------------------------------------------------------------------------;;
 ;; Debug                                                                      ;;

elisp/omake/omake-model.el

         (setf (Omake.Model.result model) result)
         (Omake.Model.show model)))))
 
-(defun Omake.Model.current () (Omake.Model.get (Omake.Id.current)))
-(defun Omake.Project.current () (Omake.Model.project (Omake.Model.current)))
+(defun Omake.Model.current ()
+  (Omake.Model.get (Omake.Id.current)))
+
+(defun Omake.Project.current ()
+  (Omake.Model.project (Omake.Model.current)))
 
 (provide 'omake-model)

elisp/omake/omake-path.el

          ;; locate-dominating-file leaves the last slash on the path
          (dir (Filename.strip-final-slash dir)))
     (if (not dir)
-        (error "Can't determine OMake project: no OMakeroot in %s or any of its ancestors"
-               path))
+        (signal 'Omake.Errors.no-omakeroot path))
     (assert (file-directory-p dir))
     dir))
-;; (Omake.Path.omakeroot-dir "/mnt/local/sda1/smclaughlin/elisp/dev/omake-mode")
-;; (Omake.Path.omakeroot-dir "~/gord-test")
-;; (Omake.Path.omakeroot-dir "/mnt/local.a.b.c/sda1/smclaughlin/elisp/dev/omake-mode")
+;; (Omake.handle-errors (Omake.Path.omakeroot-dir "~/save/projects/omake-mode-test/ocaml2/lib"))
+
+(defun Omake.Path.has-omakeroot (path)
+  (assert (stringp path))
+  (locate-dominating-file path "OMakeroot"))
+;; (Omake.Path.has-omakeroot "/tmp")
 
 (provide 'omake-path)

elisp/omake/omake-server.el

   (apply 'Log.printf (cons (Omake.Buffer.get 'mode-log) (cons fmt rest)))
   (with-temp-buffer
     (insert (apply 'format (cons fmt rest)) "\n")
-    ;; (write-region nil nil Omake.File.mode-log t
-    ;;               (concat Omake.File.mode-log ".lock"))))
     (write-region nil nil Omake.File.mode-log t 'no-message)))
 ;; (Omake.Server.logf "sean: %s %d" "abc" 8)
 
   (x-send-client-message nil 0 nil "_NET_WM_STATE" 32
                          '(2 "_NET_WM_STATE_FULLSCREEN" 0)))
 
-(setq Info-directory-list
-      (list (format "%s/doc/" jane-home)
-            "/usr/share/info/"))
+(add-to-list 'Info-directory-list (format "%s/doc/" jane-home) t)
+(add-to-list 'Info-directory-list "/usr/share/info/" t)
 
 
 (progn

ocaml/omake/omake.ml

     (* *** omake: the current directory /home/seanmcl/ocaml/ocaml1/lib/abc
        *** omake: is not part of the root project in /home/seanmcl/ocaml/ocaml1 *)
     let error11 = "\\*\\*\\* omake: the current directory" in
+    let error12 = "depends on:" in
+    let error13 = " *Error: Preprocessor error" in
     (* Don't use "waiting for project lock" because the line takes a long time
        to end while omake spits out ............. *)
     (* let error10 = "\\*\\*\\* omake: waiting for project lock:" in *)
-    Regex.of_string (sprintf "(%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s)"
+    Regex.of_string (sprintf "(%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s)"
                        error1 error2 error3 error4 error5 error6
-                       error7 error8 error9 error10 error11)
+                       error7 error8 error9 error10 error11 error12
+                       error13)
 end
 
 (* -------------------------------------------------------------------------- *)
     ; "- exit.*"
     ; "\\+ ocaml.*"
     ; "^\\[=+"
-    ; "depends on:.*"
+    (* ; "depends on:.*" *)
     ; "make\\[.*"
     ; ".*\\.cmx.*"
       (* Need *.cmi for
     ; "- build.*"
     ; "- exit.*"
     ; "^\\[=+"
-    ; "depends on:.*"
+    (* ; "depends on:.*" *)
     ; "ln -sf.*"
     ; "cp .*\\.a.*"
     ]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.