繁体   English   中英

在初始化程序中获取rake任务名称

[英]Get rake task name in initializer

我想知道,如果app实例是由rake启动的,那么我尝试在initializers捕获rake任务名称。 例如,如果我运行rake db:migrate我想要获取db:migrate或类似的东西。 我试过这个;

[7] pry(main)> $0
=> "spring app    | bilet18 | started 3 secs ago | development mode"
[8] pry(main)> ARGV
=> []
[9] pry(main)> Rake.application.top_level_tasks
=> []

但一切都是空的。

我能做什么? 请帮忙。

UPDATE

如果添加Rakefile行就好

ENV["RAKE_CURRENT_TASKS"] = Rake.application.top_level_tasks.join(' ')

然后在将来你将能够抓住它。但这个解决方案对我不好,我需要更早地抓住rake任务名称

除非你停止使用Spring否则这里提出的其他答案都不会有效,因为Spring会改变rake任务被大量调用的方式。

使用Spring时,正在运行的命令将使用UNIX套接字移交给Spring服务器进程,不幸的是,Spring服务器在初始化rails环境后读取此套接字以获取命令及其参数。 因此,在rails初始化期间,使用Spring时似乎无法获取命令及其参数(例如rake任务名称),因为Spring本身还不知道! 即使是Spring提供的after_fork钩子也无济于事,因为它也是 rails初始化之后运行的。

可以在Spring源代码中看到证据。 它是一个serve方法 ,Spring从套接字中获取命令的ARGV ,自行分叉并运行命令。 该方法的相关部分如下:

def serve(client)
  # ... getting standard input / output streams from the client socket

  # this is where rails initialization occurs
  preload unless preloaded?

  # this is where Spring gets the command name and it's ARGV and environment
  args, env = JSON.load(client.read(client.gets.to_i)).values_at("args", "env")
  command   = Spring.command(args.shift)

  # ...

  # fork and run the command
  pid = fork {
    # ...       
    # run the command
    ARGV.replace(args)
    $0 = command.exec_name
    # ...

    # run the after_fork hook
    invoke_after_fork_callbacks

    command.call
  }

  # ...
end

rails初始化程序在preload方法中运行 ,该方法从套接字读取命令名之前运行。 在初始化之后,在fork块中也设置$0ARGV变量。

因此,除非你明显地修补了Spring(用你自己的方法替换了serve方法,但是你需要自己处理套接字), 你需要停止在Spring环境中调用你的rake任务 如果rake命令是RAILS_ROOT/bin/目录中的binstub,则需要使用spring binstup --remove rake删除binstub。

只有这样,我相信,您可以在其他答案中使用其中一种解决方案。

您是否在任务中包含了=> :environment 例如

task :sometask => :environment do
    ...
end

否则,在运行rake任务时,初始化程序不会运行

有两种方法可以达到你想要的效果,

1,不使用spring ,只需运行:

spring binstub --remove --all

然后运行你的rake任务。

2,使用弹簧:

创建一个spring.rb文件config/spring.rb after_fork并使用after_fork

Spring.after_fork do
  # run your code here
  # you have access to ARGV
  binding.pry
end

我相信可以满足您的需求。 任务名称还应包括命名空间。

配置/初始化/ rake.rb

module Rake
  class Application
    attr_accessor :current_task
  end
  class Task
    alias :old_execute :execute 
    def execute(args=nil)
      Rake.application.current_task = @name  
      old_execute(args)
    end
  end #class Task
end #module Rake  

车型/ something.rb:

class Something < ActiveRecord::Base
   puts Rake.application.current_task
end

LIB /任务/ some_task.rake:

require 'rake'
namespace :ns do
  task :some_task => :environment do
    Something.all.to_a
  end
end

安慰:

rake ns:some_task
ns:some_task

也有效:

bundle exec rake ns:some_task
ns:some_task

您可以使用Rake::Task#enhance来重新定义任务,以便在调用原始任务之前创建变量,但这看起来有点混乱,您将不得不担心如何处理以下任务:environment:default

我认为最简单的方法可能是扩展Rake::Task#invoke方法以添加一个全局变量,然后可以在初始化程序中或从您想要的任何地方访问该变量。

这是一个非常快速的脏例子,你可以在Rakefile做:

module RakeTaskName
  def invoke(*args)
    $rake_task_name = name
    super *args
  end
end

Rake::Task.send :prepend, RakeTaskName

然后,在初始化程序中,您可以执行以下操作:

if defined? $rake_task_name
  puts "Running from rake task: #{$rake_task_name}"
end

编辑

这是一个带有此代码和1迁移的新rails项目 输出如下所示:

Running from rake task: db:migrate
== 20160411150810 CreateFoo: migrating ========================================
-- create_table(:foos)
   -> 0.0010s
== 20160411150810 CreateFoo: migrated (0.0011s) ===============================

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM