blob: f9173ac8287016966bda36328270ed72872d3686 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
require "English"
require "open-uri"
require "time"
class PackageTask
include Rake::DSL
def initialize(package, version, release_time, options={})
@package = package
@version = version
@release_time = release_time
@archive_base_name = "#{@package}-#{@version}"
@archive_name = "#{@archive_base_name}.tar.gz"
@full_archive_name = File.expand_path(@archive_name)
@rpm_package = @package
case @version
when /-((dev|rc)\d+)\z/
base_version = $PREMATCH
sub_version = $1
type = $2
if type == "rc" and options[:rc_build_type] == :release
@deb_upstream_version = base_version
@rpm_version = base_version
@rpm_release = "1"
else
@deb_upstream_version = "#{base_version}~#{sub_version}"
@rpm_version = base_version
@rpm_release = "0.#{sub_version}"
end
else
@deb_upstream_version = @version
@rpm_version = @version
@rpm_release = "1"
end
@deb_release = "1"
end
def define
define_dist_task
define_yum_task
define_apt_task
define_version_task
end
private
def env_value(name)
value = ENV[name]
raise "Specify #{name} environment variable" if value.nil?
value
end
def parallel_build?
ENV["PARALLEL"] == "yes"
end
def debug_build?
ENV["DEBUG"] != "no"
end
def git_directory?(directory)
candidate_paths = [".git", "HEAD"]
candidate_paths.any? do |candidate_path|
File.exist?(File.join(directory, candidate_path))
end
end
def latest_commit_time(git_directory)
return nil unless git_directory?(git_directory)
cd(git_directory) do
return Time.iso8601(`git log -n 1 --format=%aI`.chomp).utc
end
end
def download(url, output_path)
if File.directory?(output_path)
base_name = url.split("/").last
output_path = File.join(output_path, base_name)
end
absolute_output_path = File.expand_path(output_path)
unless File.exist?(absolute_output_path)
mkdir_p(File.dirname(absolute_output_path))
rake_output_message "Downloading... #{url}"
open(url) do |downloaded_file|
File.open(absolute_output_path, "wb") do |output_file|
output_file.print(downloaded_file.read)
end
end
end
absolute_output_path
end
def run_docker(os, architecture=nil)
id = os
id = "#{id}-#{architecture}" if architecture
docker_tag = "#{@package}-#{id}"
build_command_line = [
"docker",
"build",
"--tag", docker_tag,
]
run_command_line = [
"docker",
"run",
"--rm",
"--tty",
"--volume", "#{Dir.pwd}:/host:rw",
]
if debug_build?
build_command_line.concat(["--build-arg", "DEBUG=yes"])
run_command_line.concat(["--env", "DEBUG=yes"])
end
if File.exist?(File.join(id, "Dockerfile"))
docker_context = id
else
from = File.readlines(File.join(id, "from")).find do |line|
/^[a-z]/i =~ line
end
build_command_line.concat(["--build-arg", "FROM=#{from.chomp}"])
docker_context = os
end
build_command_line << docker_context
run_command_line.concat([docker_tag, "/host/build.sh"])
sh(*build_command_line)
sh(*run_command_line)
end
def define_dist_task
define_archive_task
desc "Create release package"
task :dist => [@archive_name]
end
def define_yum_task
namespace :yum do
yum_dir = "yum"
repositories_dir = "#{yum_dir}/repositories"
directory repositories_dir
desc "Build RPM packages"
task :build => [@archive_name, repositories_dir] do
tmp_dir = "#{yum_dir}/tmp"
rm_rf(tmp_dir)
mkdir_p(tmp_dir)
rpm_archive_name = "#{@package}-#{@rpm_version}.tar.gz"
cp(@archive_name,
File.join(tmp_dir, rpm_archive_name))
env_sh = "#{yum_dir}/env.sh"
File.open(env_sh, "w") do |file|
file.puts(<<-ENV)
SOURCE_ARCHIVE=#{rpm_archive_name}
PACKAGE=#{@rpm_package}
VERSION=#{@rpm_version}
RELEASE=#{@rpm_release}
ENV
end
spec = "#{tmp_dir}/#{@rpm_package}.spec"
spec_in = "#{yum_dir}/#{@rpm_package}.spec.in"
spec_in_data = File.read(spec_in)
spec_data = spec_in_data.gsub(/@(.+?)@/) do |matched|
case $1
when "PACKAGE"
@rpm_package
when "VERSION"
@rpm_version
when "RELEASE"
@rpm_release
else
matched
end
end
File.open(spec, "w") do |spec_file|
spec_file.print(spec_data)
end
cd(yum_dir) do
threads = []
targets = (ENV["YUM_TARGETS"] || "").split(",")
if targets.empty?
# Disable aarch64 targets by default for now
# because they require some setups on host.
targets = [
"centos-6",
"centos-7",
# "centos-7-aarch64",
]
end
targets.each do |target|
next unless Dir.exist?(target)
distribution, version, architecture = target.split("-", 3)
os = "#{distribution}-#{version}"
if parallel_build?
threads << Thread.new(os, architecture) do |*local_values|
run_docker(*local_values)
end
else
run_docker(os, architecture)
end
end
threads.each(&:join)
end
end
end
desc "Release Yum packages"
yum_tasks = [
"yum:build",
]
task :yum => yum_tasks
end
def define_apt_task
namespace :apt do
apt_dir = "apt"
repositories_dir = "#{apt_dir}/repositories"
directory repositories_dir
desc "Build deb packages"
task :build => [@archive_name, repositories_dir] do
tmp_dir = "#{apt_dir}/tmp"
rm_rf(tmp_dir)
mkdir_p(tmp_dir)
deb_archive_name = "#{@package}-#{@deb_upstream_version}.tar.gz"
cp(@archive_name,
File.join(tmp_dir, deb_archive_name))
Dir.glob("debian*") do |debian_dir|
cp_r(debian_dir, "#{tmp_dir}/#{debian_dir}")
end
env_sh = "#{apt_dir}/env.sh"
File.open(env_sh, "w") do |file|
file.puts(<<-ENV)
PACKAGE=#{@package}
VERSION=#{@deb_upstream_version}
ENV
end
cd(apt_dir) do
threads = []
targets = (ENV["APT_TARGETS"] || "").split(",")
if targets.empty?
# Disable arm64 targets by default for now
# because they require some setups on host.
targets = [
"debian-stretch",
# "debian-stretch-arm64",
"debian-buster",
# "debian-stretch-arm64",
"ubuntu-xenial",
# "ubuntu-xenial-arm64",
"ubuntu-bionic",
# "ubuntu-bionic-arm64",
"ubuntu-disco",
# "ubuntu-disco-arm64",
]
end
targets.each do |target|
next unless Dir.exist?(target)
distribution, version, architecture = target.split("-", 3)
os = "#{distribution}-#{version}"
if parallel_build?
threads << Thread.new(os, architecture) do |*local_values|
run_docker(*local_values)
end
else
run_docker(os, architecture)
end
end
threads.each(&:join)
end
end
end
desc "Release APT repositories"
apt_tasks = [
"apt:build",
]
task :apt => apt_tasks
end
def define_version_task
namespace :version do
desc "Update versions"
task :update do
update_debian_changelog
update_spec
end
end
end
def package_changelog_message
"New upstream release."
end
def packager_name
ENV["DEBFULLNAME"] || ENV["NAME"] || guess_packager_name_from_git
end
def guess_packager_name_from_git
name = `git config --get user.name`.chomp
return name unless name.empty?
`git log -n 1 --format=%aN`.chomp
end
def packager_email
ENV["DEBEMAIL"] || ENV["EMAIL"] || guess_packager_email_from_git
end
def guess_packager_email_from_git
email = `git config --get user.email`.chomp
return email unless email.empty?
`git log -n 1 --format=%aE`.chomp
end
def update_content(path)
if File.exist?(path)
content = File.read(path)
else
content = ""
end
content = yield(content)
File.open(path, "w") do |file|
file.puts(content)
end
end
def update_debian_changelog
Dir.glob("debian*") do |debian_dir|
update_content("#{debian_dir}/changelog") do |content|
<<-CHANGELOG.rstrip
#{@package} (#{@deb_upstream_version}-#{@deb_release}) unstable; urgency=low
* New upstream release.
-- #{packager_name} <#{packager_email}> #{@release_time.rfc2822}
#{content}
CHANGELOG
end
end
end
def update_spec
release_time = @release_time.strftime("%a %b %d %Y")
update_content("yum/#{@rpm_package}.spec.in") do |content|
content = content.sub(/^(%changelog\n)/, <<-CHANGELOG)
%changelog
* #{release_time} #{packager_name} <#{packager_email}> - #{@rpm_version}-#{@rpm_release}
- #{package_changelog_message}
CHANGELOG
content = content.sub(/^(Release:\s+)\d+/, "\\11")
content.rstrip
end
end
end