简体   繁体   English

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

[英]Get rake task name in initializer

I want to know, if the app instance is started by rake , so I tried out catching rake task name in initializers . 我想知道,如果app实例是由rake启动的,那么我尝试在initializers捕获rake任务名称。 For example, if I run rake db:migrate I want get db:migrate or something like this. 例如,如果我运行rake db:migrate我想要获取db:migrate或类似的东西。 I tried this; 我试过这个;

[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
=> []

but everything is empty. 但一切都是空的。

What can I do that? 我能做什么? please help. 请帮忙。

UPDATE UPDATE

if add in Rakefile line like 如果添加Rakefile行就好

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

then in future you'll be able to catch it in. but this solution is not good for me, I need to catch rake task name earlier 然后在将来你将能够抓住它。但这个解决方案对我不好,我需要更早地抓住rake任务名称

None of the other answers presented here will work unless you stop using Spring , because Spring changes the way rake tasks are called significantly. 除非你停止使用Spring否则这里提出的其他答案都不会有效,因为Spring会改变rake任务被大量调用的方式。

When using Spring, the command being run is handed over to the Spring server process using a UNIX socket and unfortunately Spring server reads this socket to get the command and its arguments after initializing the rails environment . 使用Spring时,正在运行的命令将使用UNIX套接字移交给Spring服务器进程,不幸的是,Spring服务器在初始化rails环境后读取此套接字以获取命令及其参数。 Thus, during rails initialization, there seems to be no way of getting the command and its arguments (eg the rake task name) when using Spring, as Spring itself does not know yet! 因此,在rails初始化期间,使用Spring时似乎无法获取命令及其参数(例如rake任务名称),因为Spring本身还不知道! Even the after_fork hook that Spring provides won't help, because it is being also run after rails initialization. 即使是Spring提供的after_fork钩子也无济于事,因为它也是 rails初始化之后运行的。

A proof can be seen in the Spring source code. 可以在Spring源代码中看到证据。 It is the serve method in which Spring gets the ARGV of the command being run from the socket, forks itself and runs the command. 它是一个serve方法 ,Spring从套接字中获取命令的ARGV ,自行分叉并运行命令。 The relevant parts of the method are these: 该方法的相关部分如下:

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

The rails initializers are run in the preload method which is run before the command name is read from the socket. rails初始化程序在preload方法中运行 ,该方法从套接字读取命令名之前运行。 The $0 and ARGV variables are also set after initialization, in the fork block. 在初始化之后,在fork块中也设置$0ARGV变量。

So, unless you monkey-patched Spring significantly (replaced the serve method with your own, but you'd need to handle working with the socket yourself), you need to stop calling your rake tasks inside the Spring environment . 因此,除非你明显地修补了Spring(用你自己的方法替换了serve方法,但是你需要自己处理套接字), 你需要停止在Spring环境中调用你的rake任务 If the rake command is a binstub in the RAILS_ROOT/bin/ directory, you need to remove the binstub with spring binstup --remove rake . 如果rake命令是RAILS_ROOT/bin/目录中的binstub,则需要使用spring binstup --remove rake删除binstub。

Only then, I believe, you can use one of the solutions in the other answers. 只有这样,我相信,您可以在其他答案中使用其中一种解决方案。

Did you include the => :environment in your task? 您是否在任务中包含了=> :environment Eg 例如

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

Otherwise the initializers wont run when you run a rake task 否则,在运行rake任务时,初始化程序不会运行

There is two ways to achieve what you want, 有两种方法可以达到你想要的效果,

1 .Not using spring , just run: 1,不使用spring ,只需运行:

spring binstub --remove --all

and then run your rake task. 然后运行你的rake任务。

2 .Using spring: 2,使用弹簧:

create a spring.rb file config/spring.rb and use after_fork 创建一个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

I believe this answers your needs. 我相信可以满足您的需求。 Task name should include also the namespace. 任务名称还应包括命名空间。

config/initializers/rake.rb 配置/初始化/ 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  

models/something.rb: 车型/ something.rb:

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

lib/tasks/some_task.rake: LIB /任务/ some_task.rake:

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

console: 安慰:

rake ns:some_task
ns:some_task

also works: 也有效:

bundle exec rake ns:some_task
ns:some_task

You could redefine tasks using Rake::Task#enhance to create a variable before invoking the original task, but that seems a bit messy and you'll have to worry about what to do with tasks like :environment and :default . 您可以使用Rake::Task#enhance来重新定义任务,以便在调用原始任务之前创建变量,但这看起来有点混乱,您将不得不担心如何处理以下任务:environment:default

I think the easiest way is probably to just extend the Rake::Task#invoke method to add a global variable which you could then access in initializers, or from wherever else you want. 我认为最简单的方法可能是扩展Rake::Task#invoke方法以添加一个全局变量,然后可以在初始化程序中或从您想要的任何地方访问该变量。

Here's a really quick an dirty example which you could do in the Rakefile : 这是一个非常快速的脏例子,你可以在Rakefile做:

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

Rake::Task.send :prepend, RakeTaskName

Then, in an initializer, you can do: 然后,在初始化程序中,您可以执行以下操作:

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

Edit 编辑

Here's a new rails project with this code & 1 migration. 这是一个带有此代码和1迁移的新rails项目 The output looks like this: 输出如下所示:

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