You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gbuild 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #!/usr/bin/ruby
  2. require 'optparse'
  3. require 'yaml'
  4. require 'fileutils'
  5. require 'pathname'
  6. @options = {}
  7. def system!(cmd)
  8. system(cmd) or raise "failed to run #{cmd}"
  9. end
  10. def sanitize(str, where)
  11. raise "unsanitary string in #{where}" if (str =~ /[^\w.-]/)
  12. str
  13. end
  14. def info(str)
  15. puts str unless @options[:quiet]
  16. end
  17. OptionParser.new do |opts|
  18. opts.banner = "Usage: build [options] <build-description>.yml"
  19. opts.on("-i", "--skip-image", "reuse current target image") do |v|
  20. @options[:skip_image] = v
  21. end
  22. opts.on("-q", "--quiet", "be quiet") do |v|
  23. @options[:skip_image] = v
  24. end
  25. end.parse!
  26. base_dir = Pathname.new(__FILE__).expand_path.dirname.parent
  27. libexec_dir = base_dir + 'libexec'
  28. ENV['PATH'] = libexec_dir.to_s + ":" + ENV['PATH']
  29. ENV['GITIAN_BASE'] = base_dir.to_s
  30. build_desc_file = ARGV.shift or raise "must supply YAML build description file"
  31. in_sums = []
  32. build_desc = YAML.load_file(build_desc_file)
  33. package_name = build_desc["name"] or raise "must supply name"
  34. package_name = sanitize(package_name, "package name")
  35. desc_sum = `sha256sum #{build_desc_file}`
  36. desc_sum = desc_sum.sub(build_desc_file, "#{package_name}-desc.yml")
  37. in_sums << desc_sum
  38. reference_datetime = build_desc["reference_datetime"] or raise "must supply reference_datetime"
  39. build_dir = 'build'
  40. result_dir = 'result'
  41. FileUtils.rm_rf(build_dir)
  42. FileUtils.mkdir(build_dir)
  43. FileUtils.mkdir_p(result_dir)
  44. info "Stopping target if it is up"
  45. system "stop-target"
  46. sleep 1
  47. unless @options[:skip_image]
  48. info "Making a new image copy"
  49. system! "cp base.qcow2 target.qcow2"
  50. end
  51. info "Starting target"
  52. system! "start-target &"
  53. $stdout.write "Checking if target is up"
  54. (1..10).each do
  55. system "on-target true 2> /dev/null" and break
  56. sleep 2
  57. $stdout.write '.'
  58. end
  59. info ''
  60. system! "on-target true"
  61. info "Preparing build environment"
  62. system! "on-target bash < target-bin/init-build.sh"
  63. build_desc["files"].each do |filename|
  64. filename = sanitize(filename, "files section")
  65. system! "cd inputs && copy-to-target #{filename} build/"
  66. in_sums << `cd inputs && sha256sum #{filename}`
  67. end
  68. info "Installing additional packages (log in var/install.log)"
  69. system! "on-target -u root apt-get -y install #{build_desc["packages"].join(" ")} > var/install.log 2>&1"
  70. info "Grabbing package manifest"
  71. system! "on-target -u root bash < target-bin/grab-packages.sh > var/base.manifest"
  72. info "Creating build script (var/build-script)"
  73. File.open("var/build-script", "w") do |script|
  74. script.puts "#!/bin/bash"
  75. script.puts "set -e"
  76. script.puts "export OUTDIR=$HOME/out"
  77. script.puts "MAKEOPTS=(-j2)"
  78. (ref_date, ref_time) = reference_datetime.split
  79. script.puts "REFERENCE_DATETIME='#{reference_datetime}'"
  80. script.puts "REFERENCE_DATE='#{ref_date}'"
  81. script.puts "REFERENCE_TIME='#{ref_time}'"
  82. script.puts
  83. build_desc["remotes"].each do |remote|
  84. script.puts "git clone -q #{remote["url"]} build/#{remote["dir"]}"
  85. script.puts "(cd build/#{remote["dir"]} && git checkout -q #{remote["commit"]})"
  86. end
  87. script.puts "cd build"
  88. script.puts build_desc["script"]
  89. end
  90. info "Running build script (log in var/build.log)"
  91. system! "on-target bash < var/build-script > var/build.log 2>&1"
  92. info "Grabbing results"
  93. system! "copy-from-target out #{build_dir}"
  94. out_dir = File.join(build_dir, "out")
  95. out_sums = {}
  96. info "Generating report"
  97. Dir.new(out_dir).each do |file|
  98. next if file.start_with?(".")
  99. file = sanitize(file, out_dir)
  100. out_sums[file] = `cd #{out_dir} && sha256sum #{file}`
  101. raise "failed to sum #{file}" unless $? == 0
  102. puts out_sums[file] unless @options[:quiet]
  103. end
  104. out_manifest = out_sums.keys.sort.map { |key| out_sums[key] }.join('')
  105. base_manifest = File.read('var/base.manifest')
  106. in_manifest = in_sums.join('')
  107. # Use Omap to keep result deterministic
  108. report = YAML::Omap[
  109. 'out_manifest', out_manifest,
  110. 'in_manifest', in_manifest,
  111. 'base_manifest', base_manifest,
  112. ]
  113. result_file = "#{package_name}-res.yml"
  114. File.open(File.join(result_dir, result_file), "w") do |io|
  115. io.write report.to_yaml
  116. end
  117. system!("cd #{result_dir} && sha256sum #{result_file}") unless @options[:quiet]
  118. info "Done."