require "option_parser" require "file_utils" require "colorize" require "./context.cr" require "./recipe.cr" extend Package context = Context.new() context.repositories << "." configuration_file = "#{SYSCONF_DIR}/packaging.cfg" configuration_file_requested = false requested_recipes = [] of String download_only = false do_not_clean = false watch_only = false skip_build_dependencies = false print_deps = false used_X = false OptionParser.parse do |parser| parser.banner = "Usage: package [options] >>" parser.on("-X DIR", "--repository DIR", "Sets a ports repository for finding dependencies (default=.).") { |dir| unless used_X while context.repositories.pop? end used_X = true end context.repositories << dir } parser.on("-c FILE", "--conf FILE", "Use a configuration file other than the default one.") { |file| configuration_file = file configuration_file_requested = true } parser.on("-D", "--download-only", "Only download sources, do not build.") { download_only = true } parser.on("-k", "--keep-work-dir", "Do not clean after building.") { do_not_clean = true } parser.on("-h", "--help", "Prints this help message.") { puts parser exit 0 } parser.on("-V", "--version", "Prints package's version and exits.") { puts Package::Version exit 0 } parser.on("-w", "--watch", "Checks if the recipe is up to date and exits.") { watch_only = true } parser.on("-B", "--print-deps", "Prints build dependencies and exits.") { print_deps = true } parser.on("-v", "--verbose", "Runs more verbosely.") { context.verbosity += 1 } parser.on("-q", "--quiet", "Runs more quietely.") { context.verbosity -= 1 } parser.on("-n", "--ignore-dependencies", "Do not try to install build-dependencies.") { skip_build_dependencies = true } parser.invalid_option do |flag| STDERR.puts "ERROR: #{flag} is not a valid option." STDERR.puts parser exit(1) end parser.unknown_args do |arg| requested_recipes = arg end end if File.exists? configuration_file context.read_configuration configuration_file elsif configuration_file_requested STDERR.puts "ERROR: configuration file '#{configuration_file}' does not exist" exit 1 end found_recipes = requested_recipes.map do |name| context.find_recipe(name) || name end invalid_recipes = found_recipes.select &.is_a?(String) if invalid_recipes.size > 0 STDERR.puts "ERROR: some of the requested recipes could not be found:" invalid_recipes.each do |name| STDERR.puts " - #{name}" end STDERR.puts " (try using -X?)" end recipes = found_recipes.compact_map do |recipe_or_string| recipe_or_string unless recipe_or_string.is_a?(String) end # FIXME: Now we need to build their respective deptrees and to deduplicate # the list of recipes. if watch_only if recipes.size == 0 context.repositories.each do |repo| Dir.children(repo).each do |i| recipe_file_name = "#{repo}/#{i}/recipe.spec" if File.exists? recipe_file_name recipes << context.read_recipe recipe_file_name end end end end recipes.each &.watch exit 0 end begin latest_build_dir = "" dependencies = [] of String recipes.each do |recipe| recipe.build_dependencies.each do |dep| dependencies << dep unless dependencies.any? &.==(dep) end end if print_deps puts dependencies.join "\n" exit 0 end if dependencies.size > 0 && ! skip_build_dependencies && !download_only # FIXME: We’ll probably want to have backends other than apk at some point. opts = ["add"] + (ENV["APK_FLAGS"]? || "-i").split(/[ \t]+/) + dependencies puts "+ apk #{opts.join " "}" r = Process.run "apk", opts, output: Process::Redirect::Inherit, input: Process::Redirect::Inherit, error: Process::Redirect::Inherit if r.exit_status != 0 STDERR.puts "!! Running apk failed!" exit 8 end end recipes.each do |recipe| latest_build_dir = recipe.building_directory context.title recipe.name recipe.download next if download_only recipe.extract recipe.build recipe.package recipe.clean unless do_not_clean end rescue e : Package::Exception STDERR.puts "!! #{e.message}".colorize(:red).bright STDERR.puts "!! You may want to inspect the build directory at #{latest_build_dir}" exit 1 rescue e STDERR.puts "!! An unexpected error occured:".colorize(:red).bright STDERR.puts e exit 1 end