Can flymake's temporary file be created in the system's temporary directory?

橙三吉。 提交于 2019-12-04 23:42:03

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!