如何在 Rake 的不同目录中处理输入和输出?
How To Process Inputs and Outputs in Separate Directories in Rake?
我正在尝试使用 Rake 将 Haml 文件转换为 HTML 文件,这样如果 Haml 文件没有更改,我就不会重新生成现有的 HTML.
但是,我不希望我的输入文件、输出文件和 Rakefile
全部混入一个目录中。相反,我希望我的输入文件位于 src/
中,而我的输出文件位于 build/output/
中。所以,我想开始:
Rakefile
src/
slides.haml
我想结束:
Rakefile
src/
slides.haml
build/
output/
slides.html
我已经尝试了几位 Rake 代码,但没有成功。
首先,我尝试了穴居人方法,对我正在尝试的精确文件进行硬编码:
task "build/output/slides.html" => "src/slides.haml" do
touch task.name
end
task :slides => "src/slides.haml"
task :default => "slides"
运行 rake --trace
结果:
** Invoke default (first_time)
** Invoke slides (first_time)
** Invoke src/slides.haml (first_time, not_needed)
** Execute slides
** Execute default
目录没有建立,我没有空的build/output/slides.html
文件。
理想情况下,我更喜欢 rule
-和-FileList
方法,使用 this SO answer or this "Rake cheatshet" entry 之类的东西。但是,我尝试了该主题的一些变体,得到了相同的结果,这表明我搞砸了一些更深层次的事情。我已将我的 Rakefile
调整回穴居人方法,只是想弄清楚这里发生了什么。
为什么 Rake 无法识别我的 "build/output/slides.html"
任务?在 Rake 中使用子目录(输入或输出)有什么神奇之处吗?
首先,任务声明为task :name => dependency
。您的 :slides
任务命名了一个源而不是输出依赖项。此外,您的 :default
任务依赖于文件 "slides"
而不是任务 :slides
。将这些行更改为
task :slides => "build/output/slides.html"
task :default => :slides
接下来,实际执行的代码块应该是规则,而不是任务,您可以通过#{t.<param>}
:
访问规则的内部信息
rule "build/output/slides.html" => "src/slides.html" do |t|
sh "mkdir -p $(dirname #{t.name})"
sh "touch #{t.name}"
end
有更好的方法可以使规则更通用,构建源文件列表并将它们映射到输出等。这里有一些有用的教程 https://github.com/ruby/rake#presentations-and-articles-about-rake
如果 build/output/
目录不存在,可能还有更多 Ruby 风格的方法,而不是调用 shell 来创建它。
我错过了文件任务使用 file
而不是 task
,并且还有一个 directory
任务。
穴居人方法的工作版本是:
namespace :build do
directory "build/output"
file "build/output/slides.html" => ["build/output", "src/slides.haml"] do |t|
touch t.name
end
task :all => "build/output/slides.html"
end
task :default => ['build:all']
这是我今天放在一起的一些东西,我相信它可以完成你想要完成的同样的事情。首先,我定义mv_rule
(可以在你import
/require
的单独ruby文件中),然后为输出目录定义一个directory
任务,最后做一个描述输出模式(包括目录)和输入模式(包括目录)的规则。
# Declare a rule for auto-tasks that have input and output in different directories
#
# Example:
# mv_rule 'obj/*.o' => 'src/*.c' do |t|
# sh "gcc -c #{t.source} -o #{t.name}"
#
def mv_rule(*args, &block) # :doc:
outFile, inFile = args[0].keys[0], args[0].values[0]
outExt = File.extname outFile
outDir = File.dirname outFile
inExt = File.extname inFile
inDir = File.dirname inFile
destPattern = Regexp.new("#{outDir}/.*\#{outExt}")
srcPattern = ->(o){o.pathmap("%{^#{outDir}/,#{inDir}/}X#{inExt}")}
Rake::Task.create_rule(destPattern => [srcPattern, outDir], &block)
end
directory "build/output"
mv_rule 'build/output/*.html' => 'src/*.haml' do |t|
touch t.name
end
task :all => "build/output/slides.html"
task :default => [:all]
我可以 运行 它与 rake
一起执行 :default
任务。或者,由于我在适当的目录中指定了从 haml
制作 html
的一般规则,我可以 运行 它与 rake build/output/more_slides.html
(假设有一个 src/more_slides.haml
) .
我有点惊讶没有 built-in 方法来指定不同的输出目录。这似乎是一个很常见的场景。
我的 mv_rule
是为了用漂亮的 straight-forward 语法来解决问题。它可能有我什至没有想过的局限性。我使用 http://www.virtuouscode.com/2014/04/23/rake-part-3-rules/ and http://www.virtuouscode.com/2014/04/24/rake-part-4-pathmap/ 作为灵感。
这项工作的非穴居人工具是 pathmap
。
SOURCES = FileList['src/*.haml']
directory 'build/output'
rule '.html' do |t|
sh 'touch', t.name
end
task :default => ['build/output', SOURCES.pathmap('build/output/%n.html')]
输出:
$ mkdir src && touch src/slides.haml
$ rake --trace
** Invoke default (first_time)
** Invoke build/output (first_time)
** Execute build/output
mkdir -p build/output
** Invoke build/output/slides.html (first_time)
** Execute build/output/slides.html
touch build/output/slides.html
** Execute default
对于此类任务,您可能还对 rake/clean
生成任务以将项目恢复到原始状态感兴趣:
require 'rake/clean'
CLOBBER.include 'build' # running 'rake clobber' will remove the build directory
我正在尝试使用 Rake 将 Haml 文件转换为 HTML 文件,这样如果 Haml 文件没有更改,我就不会重新生成现有的 HTML.
但是,我不希望我的输入文件、输出文件和 Rakefile
全部混入一个目录中。相反,我希望我的输入文件位于 src/
中,而我的输出文件位于 build/output/
中。所以,我想开始:
Rakefile
src/
slides.haml
我想结束:
Rakefile
src/
slides.haml
build/
output/
slides.html
我已经尝试了几位 Rake 代码,但没有成功。
首先,我尝试了穴居人方法,对我正在尝试的精确文件进行硬编码:
task "build/output/slides.html" => "src/slides.haml" do
touch task.name
end
task :slides => "src/slides.haml"
task :default => "slides"
运行 rake --trace
结果:
** Invoke default (first_time)
** Invoke slides (first_time)
** Invoke src/slides.haml (first_time, not_needed)
** Execute slides
** Execute default
目录没有建立,我没有空的build/output/slides.html
文件。
理想情况下,我更喜欢 rule
-和-FileList
方法,使用 this SO answer or this "Rake cheatshet" entry 之类的东西。但是,我尝试了该主题的一些变体,得到了相同的结果,这表明我搞砸了一些更深层次的事情。我已将我的 Rakefile
调整回穴居人方法,只是想弄清楚这里发生了什么。
为什么 Rake 无法识别我的 "build/output/slides.html"
任务?在 Rake 中使用子目录(输入或输出)有什么神奇之处吗?
首先,任务声明为task :name => dependency
。您的 :slides
任务命名了一个源而不是输出依赖项。此外,您的 :default
任务依赖于文件 "slides"
而不是任务 :slides
。将这些行更改为
task :slides => "build/output/slides.html"
task :default => :slides
接下来,实际执行的代码块应该是规则,而不是任务,您可以通过#{t.<param>}
:
rule "build/output/slides.html" => "src/slides.html" do |t|
sh "mkdir -p $(dirname #{t.name})"
sh "touch #{t.name}"
end
有更好的方法可以使规则更通用,构建源文件列表并将它们映射到输出等。这里有一些有用的教程 https://github.com/ruby/rake#presentations-and-articles-about-rake
如果 build/output/
目录不存在,可能还有更多 Ruby 风格的方法,而不是调用 shell 来创建它。
我错过了文件任务使用 file
而不是 task
,并且还有一个 directory
任务。
穴居人方法的工作版本是:
namespace :build do
directory "build/output"
file "build/output/slides.html" => ["build/output", "src/slides.haml"] do |t|
touch t.name
end
task :all => "build/output/slides.html"
end
task :default => ['build:all']
这是我今天放在一起的一些东西,我相信它可以完成你想要完成的同样的事情。首先,我定义mv_rule
(可以在你import
/require
的单独ruby文件中),然后为输出目录定义一个directory
任务,最后做一个描述输出模式(包括目录)和输入模式(包括目录)的规则。
# Declare a rule for auto-tasks that have input and output in different directories
#
# Example:
# mv_rule 'obj/*.o' => 'src/*.c' do |t|
# sh "gcc -c #{t.source} -o #{t.name}"
#
def mv_rule(*args, &block) # :doc:
outFile, inFile = args[0].keys[0], args[0].values[0]
outExt = File.extname outFile
outDir = File.dirname outFile
inExt = File.extname inFile
inDir = File.dirname inFile
destPattern = Regexp.new("#{outDir}/.*\#{outExt}")
srcPattern = ->(o){o.pathmap("%{^#{outDir}/,#{inDir}/}X#{inExt}")}
Rake::Task.create_rule(destPattern => [srcPattern, outDir], &block)
end
directory "build/output"
mv_rule 'build/output/*.html' => 'src/*.haml' do |t|
touch t.name
end
task :all => "build/output/slides.html"
task :default => [:all]
我可以 运行 它与 rake
一起执行 :default
任务。或者,由于我在适当的目录中指定了从 haml
制作 html
的一般规则,我可以 运行 它与 rake build/output/more_slides.html
(假设有一个 src/more_slides.haml
) .
我有点惊讶没有 built-in 方法来指定不同的输出目录。这似乎是一个很常见的场景。
我的 mv_rule
是为了用漂亮的 straight-forward 语法来解决问题。它可能有我什至没有想过的局限性。我使用 http://www.virtuouscode.com/2014/04/23/rake-part-3-rules/ and http://www.virtuouscode.com/2014/04/24/rake-part-4-pathmap/ 作为灵感。
这项工作的非穴居人工具是 pathmap
。
SOURCES = FileList['src/*.haml']
directory 'build/output'
rule '.html' do |t|
sh 'touch', t.name
end
task :default => ['build/output', SOURCES.pathmap('build/output/%n.html')]
输出:
$ mkdir src && touch src/slides.haml
$ rake --trace
** Invoke default (first_time)
** Invoke build/output (first_time)
** Execute build/output
mkdir -p build/output
** Invoke build/output/slides.html (first_time)
** Execute build/output/slides.html
touch build/output/slides.html
** Execute default
对于此类任务,您可能还对 rake/clean
生成任务以将项目恢复到原始状态感兴趣:
require 'rake/clean'
CLOBBER.include 'build' # running 'rake clobber' will remove the build directory