January 25th, 2014

解决方法

有网友反映说jekyll升级到1.4.3后出现类似下面的错误:

d:/Ruby193/lib/ruby/1.9.1/fileutils.rb:247:in `mkdir': Invalid argument -  d:/Projects/NRemedy/_site/d:. Use --trace to view backtrace

根据我研究下来可能windows下特有的问题,解决方案有两种:

安装低版本的jekyll,这个办法简单粗暴

gem uninstall jekyll
gem install jekyll --version "=1.3.0"

还有一个办法是修改代码,我先讲步骤,再讲原理:

来到这个目录,根据你ruby的安装位置,前缀可能有所不同

D:\Ruby193\lib\ruby\gems\1.9.1\gems\jekyll-1.4.3\lib\jekyll

找到post.rb中的下面代码:

def destination(dest)
	# The url needs to be unescaped in order to preserve the correct filename
	path = File.join(dest, File.expand_path(CGI.unescape(self.url),"/"))
	path = File.join(path, "index.html") if path[/\.html$/].nil?
	path
end

修改为:

def destination(dest)
	# The url needs to be unescaped in order to preserve the correct filename
	path = File.join(dest, CGI.unescape(self.url))
	path = File.join(path, "index.html") if path[/\.html$/].nil?
	path
end

找到page.rb中的下面代码:

def destination(dest)
	path = File.join(dest, File.expand_path(self.url, "/"))
	path = File.join(path, "index.html") if self.url =~ /\/$/
	path
end

改成

def destination(dest)
	path = File.join(dest, self.url)
	path = File.join(path, "index.html") if self.url =~ /\/$/
	path
end

这样应该就可以了。

原理

下面来讲讲原理。

jekyll在生成目标文件前需要计算目标文件的物理路径在哪里,根据我的调试,上面代码中两个关键的变量值分别是:

  • dest : 即默认的输出路径_site的全路径
  • self.url : 是每篇文章计算得到的一个相对路径,通常有分类和文件名中的时间部分决定的,形如:/life/2013/01/02/hello-github.html

上面代码的destination方法实际上是需要将destself.url合并在一起,最后得到文件的全路径,但是在这个过程,1.4.3版本多了一个File.expand_path。从这里看到这个方法的含义是将一个相对路径扩展为绝对路径,而实际上destself.url是可以直接用File.join合并在一起的。那么出于什么原因需要调用File.expand_path呢?

首先看下1.4.3这个版本的Release Notes

大致知道是出于安全的考虑,如果用户文件的文件名包含类似..这样的符号,可能会导致安全隐患。

那么为什么在windows下会出错呢?由于笔者对Ruby不是很了解,只能猜测一下了:

/life/2013/01/02/hello-github.html这样的路径在linux下是基于根目录的,而在windows下这个路径如果用File.expand_path扩展的话就会变成相对于根驱动器,也就是说

File.join("/life/2013/01/02/hello-github.html","/") #可能会得到d:/life/2013/01/02/hello-github.html

于是再与dest拼接就变成

d:/Projects/NRemedy/_site/d:/life/2013/01/02/hello-github.html

这个路径当然不能被用来mkdir啦,就是报出这个错误

d:/Ruby193/lib/ruby/1.9.1/fileutils.rb:247:in `mkdir': Invalid argument -  d:/Projects/NRemedy/_site/d:. Use --trace to view backtrace

以上是个人的初步调研结果,没有太多的精力深入研究下去,只能严重关注jekyll的进展了。这是我在jekyll项目针对这个问题提的一个issue

更新:目前这个问题已经修复


1块2块也是钱,小额赞助