簡體   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