flymake的临时文件能在系统临时目录创建吗?

5 投票
4 回答
2065 浏览
提问于 2025-04-16 16:27

我现在在使用以下代码把flymake和Pyflakes连接到emacs里:

(defun flymake-create-temp-in-system-tempdir (filename prefix)
  (make-temp-file (or prefix "flymake")))

然后我把这个函数传给了flymake-init-create-temp-buffer-copy。(这个内容来自于http://hustoknow.blogspot.com/2010/09/emacs-and-pyflakes-using-tmp-directory.html。)

这段代码之前一直运行得很好,直到昨天。当我打开某些Python文件时,我收到了以下错误:

switched OFF Flymake mode for buffer admin.py due to fatal status
CFGERR, warning Configuration error has occured while running    
(pyflakes ../../../../../../../tmp/flymake28459SVv)

为什么flymake传给pyflakes的文件名看起来不对呢?我本来期待它传的是像“/tmp/efe234234”这样的路径,而我没有修改任何临时目录的设置。

我不记得最近Ubuntu更新过emacs,也想不出有什么可能导致这个问题的原因(.emacs文件是有版本控制的)。

我能想到的唯一问题是,这个目录是一个层层嵌套的符号链接,链接到了我~/Dropbox目录下的一个目录,但其他以类似方式链接的目录没有出现这个问题。

我该怎么解决这个问题呢?

更新

我做了一些调试,现在我发现它传递的路径参数不正确。需要在路径中插入一个额外的父目录才能正常工作,这让我觉得可能是因为符号链接导致的混乱。

这里有一个示例的shell会话,来说明我的意思。我是在正确的相对目录下执行的:

$ pyflakes ../../../../../tmp/flymake13382xHi 
../../../../../tmp/flymake13382xHi: No such file or directory

这是flymake尝试运行的命令。如果我把它改成:

$ pyflakes ../../../../../../tmp/flymake13382xHi

我没有得到任何输出(这是预期的结果)。注意路径中的额外“..”。

我该如何让flymake传递一个绝对路径,而不是这些奇怪的相对路径呢?

更新 2

我已经把一切都搞定了。基本上有这个函数:

(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)))))

在最后一部分,我把list的参数从local-file改成了temp-file,因为local-file是我不想要的奇怪相对路径。为什么那个代码片段的作者一开始要用local-file呢?

谢谢,
Ryan

4 个回答

0

这个函数 make-temp-file 是用一个叫 temporary-file-directory 的变量的。所以你可以试着把 temporary-file-directory 设置成其他的地方,看看能不能解决你的问题。

0

我没有直接解决pyflakes问题的方法,但我有一些类似的内容可以分享给你。

我不太喜欢flymake处理C#的方式,所以我修改了flymake-allowed-file-name-masks中的C#条目,让它指向不同的初始化和清理程序,代码如下:

(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))))

关于这些内容的文档有点不完整,但代码就是文档。从我了解的情况来看,初始化程序应该返回一个用于语法检查的命令行。这个命令行的格式是一个包含两个元素的列表,第一个元素是要运行的命令,第二个元素是一个包含参数的列表。在我的例子中,返回值是这样的:

("csc.exe" ("/t:module" "/nologo" "nameOfFileToCheck.cs"))  

这个返回命令行的初始化程序会把现有的缓冲区复制到一个临时文件中,使用flymake自带的复制功能,然后用临时文件的名字作为要检查的内容。所以如果缓冲区的文件名是“source.cs”,那么从初始化函数返回的实际值是

("csc.exe" ("/t:module" "/nologo" "source_flymake.cs"))  

代码看起来是这样的:

(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))

我把它实现成两个不同的函数,只是为了遵循我在flymake.el中看到的模式。

总之……你可以看到,初始化函数创建了临时文件,然后返回参数。调用flymake-get-syntax-check-program-args实际上是调用get-cmdline-f,在C#的情况下是csharp-flymake-get-cmdline。为什么要这么多层次和间接调用?我也不知道;这就是flymake的工作方式。

在C#特定的清理函数中,我只是检查语法检查生成的任何“产品”文件并删除它们,然后还调用flymake-simple-cleanup,以删除创建的*_flymake.cs临时文件。

也许你的嵌套目录路径与flymake在其默认初始化程序中使用的use-relative-base-diruse-relative-source参数有关,我认为那个初始化程序是flymake-simple-make-init-impl

1

对我来说,我是通过修改用户脚本 /usr/local/bin/pyflakes 来解决这个问题的。我先检查一下文件是否存在,如果不存在,就加一个斜杠。

#!/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

撰写回答