วิธีการรันภารกิจเรคจากภายในงานเรค?


411

ฉันมี Rakefile ที่รวบรวมโครงการในสองวิธีตามตัวแปรทั่วโลก$build_typeซึ่งอาจเป็น:debugหรือ:release(ผลลัพธ์ไปในไดเรกทอรีที่แยกต่างหาก):

task :build => [:some_other_tasks] do
end

ฉันต้องการสร้างงานที่รวบรวมโครงการด้วยการกำหนดค่าทั้งสองแบบดังนี้:

task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    # call task :build with all the tasks it depends on (?)
  end
end

มีวิธีเรียกงานราวกับว่ามันเป็นวิธีการหรือไม่? หรือฉันจะบรรลุสิ่งที่คล้ายกันได้อย่างไร


7
คำตอบข้อใด?
nurettin

ฉันจะไปกับชุมชนโหวตและเลือกคำตอบ upvoted 221 ครั้ง (ในขณะที่เขียน) โปสเตอร์ต้นฉบับได้ออกจาก SO
MPritchard

คำตอบที่ถูกต้องคือstackoverflow.com/a/1290119/1536309
Blair Anderson

FYI การใช้สิ่งต่าง ๆ เช่นRake::Task["build"].invokeนั้นอาจจะมีประสิทธิภาพมากกว่าการใช้system rake buildเพราะมันไม่จำเป็นต้องสร้างเธรดใหม่และโหลดสภาพแวดล้อมของ Rails ซึ่งsystem rake buildต้องทำ
Joshua Pinter

คำตอบ:


639

หากคุณต้องการให้ภารกิจประพฤติตนเป็นวิธีการจะใช้วิธีการจริงได้อย่างไร

task :build => [:some_other_tasks] do
  build
end

task :build_all do
  [:debug, :release].each { |t| build t }
end

def build(type = :debug)
  # ...
end

หากคุณต้องการที่จะยึดติดกับrakeสำนวนนี่เป็นไปได้ของคุณรวบรวมจากคำตอบที่ผ่านมา:

  • สิ่งนี้จะเรียกใช้งานเสมอ แต่จะไม่เรียกใช้การพึ่งพา:

    Rake::Task["build"].execute
  • สิ่งนี้เรียกใช้การพึ่งพา แต่จะดำเนินการกับงานหากยังไม่ได้เรียกใช้:

    Rake::Task["build"].invoke
  • ครั้งแรกนี้จะรีเซ็ตสถานะของงานแล้ว _ _ ถูกเรียกคืนแล้วจึงอนุญาตให้งานถูกดำเนินการอีกครั้งการอ้างอิงและทั้งหมด:

    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  • โปรดทราบว่าการอ้างอิงที่ถูกเรียกใช้แล้วจะไม่ถูกเรียกใช้งานใหม่โดยอัตโนมัติเว้นแต่จะเปิดใช้งานอีกครั้ง ใน Rake> = 10.3.2 คุณสามารถใช้สิ่งต่อไปนี้เพื่อเปิดใช้งานสิ่งเหล่านั้นอีกครั้ง:

    Rake::Task["build"].all_prerequisite_tasks.each(&:reenable)

96
โปรดทราบว่าหากงานของคุณอยู่ในเนมสเปซคุณต้องรวมเนมสเปซเมื่อคุณเรียกใช้งาน เช่น. Rake::Task['db:reset'].invoke
David Tuite

126
หากงานในคำถามนั้นมีข้อโต้แย้งคุณสามารถส่งผ่านมันเป็นอาร์กิวเมนต์ไปที่ #invoke เช่น. Rake::Task['with:args'].invoke("pizza")
ร็อตเตอร์

26
หากคุณต้องการตั้งค่าตัวแปรสภาพแวดล้อมให้ทำก่อนที่จะเรียกใช้ ตัวอย่างเช่น: ENV['VERSION'] = '20110408170816'; Rake::Task['db:migrate'].invokeดูที่นี่สำหรับคำอธิบายเพิ่มเติม
Michael Stalker

13
ฉันเพิ่งค้นพบ#reenable()ไม่ได้เปิดใช้งาน pre-req อีกครั้งและต้องการมัน การเพิ่ม Rake นี้ (> = 10.3.2) #all_prerequisite_tasks()จะทำซ้ำงานทั้งหมดรวมถึง pre-req's ของ pre-req ดังนั้นRake::Task[task].all_prerequisite_tasks.each &:reenable
Richard Michael

4
@kch คุณสามารถรวมสตริงเหล่านี้เข้าด้วยกัน (เช่นใน commandline rake db:reset db:migrateเป็นต้น) คุณสามารถทำสิ่งที่ชอบ: Rake::Task["db:reset", "db:migrate"].invoke
Jeff

125

ตัวอย่างเช่น:

Rake::Task["db:migrate"].invoke

6
สิ่งนี้จะเรียกใช้งานเฉพาะเมื่อยังไม่ได้เรียกใช้ แต่ฉันต้องเรียกใช้งานกับงานอื่น ๆ ทั้งหมดมันขึ้นอยู่กับสองครั้ง

58
task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].reenable
    Rake::Task["build"].invoke
  end
end

ที่ควรจะเรียงลำดับคุณเพียงต้องการสิ่งเดียวกันเอง


มันใช้งานได้ แต่ก็เป็นไปได้ แน่นอนว่าไม่มีอะไรดีไปกว่านี้แล้ว?
kch

13
task :invoke_another_task do
  # some code
  Rake::Task["another:task"].invoke
end

หนึ่งในเหตุผลที่ฉันต้องการวิธีแก้ปัญหาเช่นนี้เนื่องจากการโหลดเรคใช้เวลานาน ด้วยการใช้โซลูชันดังกล่าวข้างต้นจะประหยัดเวลาในการโหลดหรือไม่
Dipan Mehta

11
task :build_all do
  [ :debug, :release ].each do |t|
    $build_type = t
    Rake::Task["build"].execute
  end
end

มันใช้งานไม่ได้เพราะมันแค่ประมวลผลเนื้อความของ: build task และไม่เรียกใช้งานที่ขึ้นอยู่กับมัน

4

หากคุณต้องการให้แต่ละงานรันโดยไม่คำนึงถึงความล้มเหลวใด ๆ คุณสามารถทำสิ่งต่อไปนี้:

task :build_all do
  [:debug, :release].each do |t| 
    ts = 0
    begin  
      Rake::Task["build"].invoke(t)
    rescue
      ts = 1
      next
    ensure
      Rake::Task["build"].reenable # If you need to reenable
    end
    return ts # Return exit code 1 if any failed, 0 if all success
  end
end

-1

ฉันจะไม่แนะนำให้สร้าง debug ทั่วไปและปล่อยงานถ้าโครงการเป็นสิ่งที่รวบรวมและผลลัพธ์ในไฟล์ คุณควรไปกับงานไฟล์ซึ่งค่อนข้างเป็นไปได้ในตัวอย่างของคุณในขณะที่คุณระบุว่าผลลัพธ์ของคุณไปในไดเรกทอรีที่แตกต่างกัน สมมติว่าโครงการของคุณเพียงรวบรวมไฟล์ test.c เพื่อออก / ดีบั๊ก / test.out และออก / เผยแพร่ / test.out ด้วย gcc คุณสามารถตั้งค่าโครงการของคุณเช่นนี้:

WAYS = ['debug', 'release']
FLAGS = {}
FLAGS['debug'] = '-g'
FLAGS['release'] = '-O'
def out_dir(way)
  File.join('out', way)
end
def out_file(way)
  File.join(out_dir(way), 'test.out')
end
WAYS.each do |way|
  desc "create output directory for #{way}"
  directory out_dir(way)

  desc "build in the #{way}-way"
  file out_file(way) => [out_dir(way), 'test.c'] do |t|
    sh "gcc #{FLAGS[way]} -c test.c -o #{t.name}"
  end
end
desc 'build all ways'
task :all => WAYS.map{|way|out_file(way)}

task :default => [:all]

การตั้งค่านี้สามารถใช้เช่น:

rake all # (builds debug and release)
rake debug # (builds only debug)
rake release # (builds only release)

สิ่งนี้ทำได้เพียงเล็กน้อยตามที่ขอ แต่แสดงคะแนนของฉัน:

  1. ไดเร็กทอรีเอาต์พุตถูกสร้างขึ้นตามความจำเป็น
  2. ไฟล์จะถูกคอมไพล์ใหม่หากจำเป็น (ตัวอย่างนี้ถูกต้องสำหรับไฟล์ test.c ที่ง่ายที่สุดเท่านั้น)
  3. คุณมีงานทั้งหมดอยู่ในมือหากคุณต้องการเปิดใช้งานบิลด์หรือรีลีสการดีบัก
  4. ตัวอย่างนี้รวมวิธีการกำหนดความแตกต่างเล็ก ๆ ระหว่าง debug และ release-builds
  5. ไม่จำเป็นต้องเปิดใช้งานการสร้างใหม่ที่ถูกกำหนดด้วยตัวแปรระดับโลกเพราะตอนนี้การสร้างที่แตกต่างกันมีงานที่แตกต่างกัน codereuse ของ build-task ทำโดยการนำโค้ดมาใช้ซ้ำเพื่อกำหนด build-task ดูว่าการวนซ้ำไม่ได้ทำงานเดียวกันสองครั้ง แต่แทนที่จะสร้างงานที่สามารถทริกเกอร์ได้ในภายหลัง (โดยงานทั้งหมดหรือเลือกหนึ่งในงานบน commandline rake)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.