问题
I am currently using the following code to hook up flymake and Pyflakes in emacs:
(defun flymake-create-temp-in-system-tempdir (filename prefix)
(make-temp-file (or prefix "flymake")))
and then I pass this function to flymake-init-create-temp-buffer-copy
. (Taken from http://hustoknow.blogspot.com/2010/09/emacs-and-pyflakes-using-tmp-directory.html).
This code worked fine until yesterday. When I visit certain Python files, I get the following error:
switched OFF Flymake mode for buffer admin.py due to fatal status
CFGERR, warning Configuration error has occured while running
(pyflakes ../../../../../../../tmp/flymake28459SVv)
Why is flymake passing what seems like the wrong filename to pyflakes? I expect it to pass something like "/tmp/efe234234" and I haven't modified any of the tmp directory settings.
I don't recall emacs being updated for Ubuntu recently and can't think of anything that might have caused this to mess up (.emacs files are versioned).
The only issue I can think of is that this is a heavily nested directory symlinked to a directory in my ~/Dropbox directory but this doesn't happen to other symlinked in a similar way.
How can I fix this problem?
UPDATE
I've done some debugging and now I see that it's not passing the correct path as the argument. It needs one more parent directory inserted into the path to make it work which makes me think it's getting messed up because of symlinks.
Here is an example shell session to show what I mean. I am doing this from the correct relative directory:
$ pyflakes ../../../../../tmp/flymake13382xHi
../../../../../tmp/flymake13382xHi: No such file or directory
That is the command flymake is trying to run. If I change it:
$ pyflakes ../../../../../../tmp/flymake13382xHi
I get no output (as expected). Note the extra ".." in the path.
How can I get flymake to pass an absolute path instead of these crazy relative paths?
UPDATE 2
I've gotten everything to work. Basically there is this function:
(defun flymake-pyflakes-init ()
; Make sure it's not a remote buffer or flymake would not work
(when (not (subsetp (list (current-buffer)) (tramp-list-remote-buffers)))
(let* ((temp-file (flymake-init-create-temp-buffer-copy
'flymake-create-temp-in-system-tempdir))
(local-file (file-relative-name
temp-file
(file-name-directory buffer-file-name))))
(list "pyflakes" (list temp-file)))))
In the last part I had to change the argument to list
from local-file
to temp-file
because local-file
was the crazy relative path I didn't want. Why did the author of that snippet use local-file
in the first place?
Thanks, Ryan
回答1:
For me, i have resolved by modify user script /usr/local/bin/pyflakes, i test if file exist, if no, i add a slash.
#!/bin/bash
FILE=$1
# Test if folder exist
if [ ! -e "$FILE" ]; then
FILE="/$1"
fi
epylint "$FILE" 2>/dev/null
pep8 --ignore=E221,E701,E202 --repeat "$FILE"
true
回答2:
I don't have a direct solution to the pyflakes question, but here's something similar for you.
I didn't like how C# was handled in flymake, so I modified the C# entry in the flymake-allowed-file-name-masks
to refer to distinct init and cleanup routines, with this code:
(let ((csharpentry (assoc "\\.cs\\'" flymake-allowed-file-name-masks)))
(if csharpentry
(setcdr csharpentry '(csharp-flymake-init csharp-flymake-cleanup))
(add-to-list
'flymake-allowed-file-name-masks
(list key 'csharp-flymake-init 'csharp-flymake-cleanup))))
The documentation is sort of spotty on this stuff, but the code is the documentation, and from what I could tell, the init routine is supposed to return the command line for a syntax check run. It is formatted as a 2-element list, the car is the command to run, and the cadr is itself a list of the arguments. In my example the return value is like this:
("csc.exe" ("/t:module" "/nologo" "nameOfFileToCheck.cs"))
The init routine that returns this command line copies the existing buffer into a temporary file, using flymake's builtin copy fn, and then uses the name of the temp file as the thing to check. So if the buffer filename is "source.cs", the actual value returned from the init fn is
("csc.exe" ("/t:module" "/nologo" "source_flymake.cs"))
The code looks like this:
(defun csharp-flymake-init ()
(csharp-flymake-init-impl
'flymake-create-temp-inplace t t 'csharp-flymake-get-cmdline))
(defun csharp-flymake-init-impl (create-temp-f use-relative-base-dir use-relative-source get-cmdline-f)
"Create syntax check command line for a directly checked source file.
Use CREATE-TEMP-F for creating temp copy."
(let* ((args nil)
(temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)))
(setq args (flymake-get-syntax-check-program-args
temp-source-file-name "."
use-relative-base-dir use-relative-source
get-cmdline-f))
args))
I implemented it in 2 distinct functions, only to follow the pattern I saw in flymake.el.
Anyway...What you can see is that the init fn creates the temp file then returns the arguments. The call to flymake-get-syntax-check-program-args
actually boils down to a call into get-cmdline-f
, which in the case of C# is csharp-flymake-get-cmdline
. Why all this layering and indirection? I don't know; that's how flymake is.
In the C#-specific cleanup fn, I just check for any "product" files from the syntax check and delete them, and then also chain to flymake-simple-cleanup
, to delete the *_flymake.cs temp file that was created.
Maybe your nested dir path has something to do with the use-relative-base-dir
and use-relative-source
arguments that flymake uses in its own default init routine, which I think is flymake-simple-make-init-impl
.
回答3:
The function make-temp-file
uses the variable temporary-file-directory
, so perhaps you could try setting temporary-file-directory
to something else to fix your problem.
回答4:
This is what I use for PHP on Windows. It uses the make-temp-file
suggestion from Trey. It also explicitly sets the init and cleanup functions for PHP, to the things I want. You could use basically the same thing, for python.
(defun cheeso-flymake-create-temp-intemp (file-name prefix)
"Return file name in temporary directory for checking FILE-NAME.
This is a replacement for `flymake-create-temp-inplace'. The
difference is that it gives a file name in
`temporary-file-directory' instead of the same directory as
FILE-NAME.
For the use of PREFIX see that function.
This won't always work; it will fail if the source module
refers to relative paths.
"
(unless (stringp file-name)
(error "Invalid file-name"))
(or prefix
(setq prefix "flymake"))
(let* ((name (concat
(file-name-nondirectory
(file-name-sans-extension file-name))
"_" prefix))
(ext (concat "." (file-name-extension file-name)))
(temp-name (make-temp-file name nil ext))
)
(flymake-log 3 "create-temp-intemp: file=%s temp=%s" file-name temp-name)
temp-name))
(defun cheeso-php-flymake-get-cmdline (source base-dir)
"Gets the cmd line for running a flymake session in a PHP buffer.
This gets called by flymake itself."
(list "c:\\Progra~2\\PHP\\v5.3\\php.exe"
(list "-f" source "-l")))
(defun cheeso-php-flymake-init ()
"initialize flymake for php"
(let ((create-temp-f 'cheeso-flymake-create-temp-intemp)
;;(create-temp-f 'flymake-create-temp-inplace)
(use-relative-base-dir t)
(use-relative-source t)
(get-cmdline-f 'cheeso-php-flymake-get-cmdline)
args
temp-source-file-name)
(setq temp-source-file-name (flymake-init-create-temp-buffer-copy create-temp-f)
args (flymake-get-syntax-check-program-args
temp-source-file-name "."
use-relative-base-dir use-relative-source
get-cmdline-f))
args))
(defun cheeso-php-flymake-cleanup ()
)
(eval-after-load "flymake"
'(progn
;; 1. add a PHP entry to the flymake-allowed-file-name-masks
(let* ((key "\\.php\\'")
(phpentry (assoc key flymake-allowed-file-name-masks)))
(if phpentry
(setcdr phpentry '(cheeso-php-flymake-init cheeso-php-flymake-cleanup))
(add-to-list
'flymake-allowed-file-name-masks
(list key 'cheeso-php-flymake-init 'cheeso-php-flymake-cleanup))))))
来源:https://stackoverflow.com/questions/5793839/can-flymakes-temporary-file-be-created-in-the-systems-temporary-directory