Add Ruby Getrealdeps (#9270)

* Add rubyized getrealdeps

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* adjust documentation

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* Have crew add missing dependencies after build

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* adjust logic

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* Add gawk message for getrealdeps

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* bugfix

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* Use puts

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* suggested changes

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* fix missing dependency check

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* fixup template

* Initial add of getrealdeps to crew

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* update getrealdeps command

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* add to README.md

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* collapse getrealdeps into a crew --deep option

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* Add punctuation.

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* Add binary_compression line if it doesn't exist in the file.

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* fix variable

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* fixup logic

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* fix upload logic, add triple backslashes

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

* remove extra section in help

Signed-off-by: Satadru Pramanik <satadru@gmail.com>

---------

Signed-off-by: Satadru Pramanik <satadru@gmail.com>
This commit is contained in:
Satadru Pramanik, DO, MPH, MEng
2024-02-07 18:24:13 -05:00
committed by GitHub
parent 569fae3b61
commit 5170c0b29f
4 changed files with 166 additions and 49 deletions

View File

@@ -40,7 +40,7 @@ DOC = <<~DOCOPT
Usage:
crew build [options] [-k|--keep] <name> ...
crew const [options] [<name> ...]
crew deps [options] [-t|--tree] [-b|--include-build-deps] [--exclude-buildessential] <name> ...
crew deps [options] [--deep] [-t|--tree] [-b|--include-build-deps] [--exclude-buildessential] <name> ...
crew download [options] [-s|--source] <name> ...
crew files [options] <name> ...
crew help [<command>] [<subcommand>]
@@ -360,11 +360,12 @@ def help(pkgName = nil)
when 'deps'
puts <<~EOT
Display dependencies of package(s).
Usage: crew deps [-t|--tree] [-b|--include-build-deps] [--exclude-buildessential] <package1> [<package2> ...]
Usage: crew deps [--deep] [-t|--tree] [-b|--include-build-deps] [--exclude-buildessential] <package1> [<package2> ...]
If `-t` or `--tree` specified, dependencies will be printed in a tree-structure format
If `-b` or `--include-build-deps` specified, build dependencies will be included in output
It `--exclude-buildessential` specified, `buildessential` and its dependencies will not be inserted automatically
If `--deep` specified, runtime dependencies will be generated by crawling every binary in a package.
If `-t` or `--tree` specified, dependencies will be printed in a tree-structure format.
If `-b` or `--include-build-deps` specified, build dependencies will be included in output.
It `--exclude-buildessential` specified, `buildessential` and its dependencies will not be inserted automatically.
EOT
when 'download'
puts <<~EOT
@@ -1711,6 +1712,8 @@ def archive_package(crew_archive_dest)
end
end
system "sha256sum #{crew_archive_dest}/#{pkg_name} > #{crew_archive_dest}/#{pkg_name}.sha256"
# Make sure the package file has runtime dependencies added properly.
system "#{CREW_LIB_PATH}/tools/getrealdeps.rb #{@pkgName}"
# Copy package file for the successfully generated package to CREW_LOCAL_REPO_ROOT only if force is set.
if @opt_force
FileUtils.cp "#{CREW_PACKAGES_PATH}/#{@pkgName}.rb", "#{CREW_LOCAL_REPO_ROOT}/packages/"
@@ -1900,8 +1903,19 @@ def upload(pkgName = nil)
if binary_compression_set.nil?
ext = File.extname(new_tarfile)
puts "Setting binary compression in #{pkg_file}..."
puts "sed -i \"s/binary_compression.*/binary_compression 'tar#{ext}'/\" #{pkg_file}" if @opt_verbose
system "sed -i \"s/binary_compression.*/binary_compression 'tar#{ext}'/\" #{pkg_file}"
# Add binary compression setting, and add the line if it doesn't exist.
if File.read(pkg_file).include?('binary_compression')
puts "sed -i \"s/binary_compression.*/binary_compression 'tar#{ext}'/\" #{pkg_file}" if @opt_verbose
system "sed -i \"s/binary_compression.*/binary_compression 'tar#{ext}'/\" #{pkg_file}"
elsif File.read(pkg_file).include?('source_sha256')
puts "sed -i \"/source_sha256/a \\\ \\\ binary_compression 'tar#{ext}'\" #{pkg_file}" if @opt_verbose
system "sed -i \"/source_sha256/a \\\ \\\ binary_compression 'tar#{ext}'\" #{pkg_file}"
elsif File.read(pkg_file).include?('git_hashtag')
puts "sed -i \"/git_hashtag/a \\\ \\\ binary_compression 'tar#{ext}'\" #{pkg_file}" if @opt_verbose
system "sed -i \"/git_hashtag/a \\\ \\\ binary_compression 'tar#{ext}'\" #{pkg_file}"
else
puts "Unable to tell where to add \"binary_compression 'tar#{ext}'\" to #{pkg_file}. Please add it and manually.".lightblue
end
binary_compression_set = 1
end
puts "Package: #{package}, Arch: #{arch}".yellow
@@ -2026,6 +2040,8 @@ def deps_command(args)
if args['--tree']
# call `print_deps_tree` (print dependency tree) if --tree is specified
print_deps_tree(args)
elsif args['--deep']
system "#{CREW_LIB_PATH}/tools/getrealdeps.rb #{name}"
else
# print dependencies according to the install order if --tree is not specified
puts @pkg.get_deps_list(include_build_deps: args['--include-build-deps'] || 'auto', exclude_buildessential: args['--exclude-buildessential'])

View File

@@ -1,7 +1,7 @@
# lib/const.rb
# Defines common constants used in different parts of crew
CREW_VERSION = '1.42.7'
CREW_VERSION = '1.42.8'
# kernel architecture
KERN_ARCH = `uname -m`.chomp

62
packages/template.rb.template Normal file → Executable file
View File

@@ -12,66 +12,46 @@ class Template < Package
compatibility '' # Package architecture compatibility (eg. aarch64, armv7l, i686, x86_64 or all)
source_url '' # The url to the source code (eg. https://ftpmirror.gnu.org/sed/sed-4.8.tar.xz)
source_sha256 ''
binary_compression 'tar.zst'
# Optional: Prebuilt binary
# binary_url ({
# aarch64: '',
# armv7l: '',
# i686: '',
# x86_64: '',
# })
# binary_sha256 ({
# aarch64: '',
# armv7l: '',
# i686: '',
# x86_64: '',
# })
# These are needed to successfully build and check for dependencies.
binary_sha256({
aarch64: '000',
armv7l: '000',
i686: '111',
x86_64: '222'
})
# Register dependencies (use the following line as a basis)
#
# depends_on '*'
# Runtime dependencies:
# depends_on '*' # R
# Build dependencies:
# depends_on '*' => :build
#
# Function to check if install should occur.
def self.preflight
end
def self.preflight; end
# Function to perform patch operations prior to build from source.
def self.patch
end
def self.patch; end
# Function to perform pre-build operations prior to build from source.
def self.prebuild
end
def self.prebuild; end
# Function to perform build from source.
def self.build
end
def self.build; end
# Function to perform check from source build.
# This is executed only during `crew build`.
def self.check
end
def self.check; end
# Function to perform pre-install operations prior to install for both source build and binary distribution.
def self.preinstall
end
def self.preinstall; end
# Function to perform install from source build.
def self.install
end
def self.install; end
# Function to perform post-install for both source build and binary distribution
def self.postinstall
end
end
def self.postinstall; end
end

121
tools/getrealdeps.rb Executable file
View File

@@ -0,0 +1,121 @@
#!/usr/bin/env ruby
# getrealdeps for Chromebrew version 1.2
# Author: Satadru Pramanik (satmandu) satadru at gmail dot com
require 'fileutils'
# Exit quickly if an invalid package name is given.
if ARGV[0].nil? || ARGV[0].empty? || ARGV[0].include?('#')
puts 'Getrealdeps checks for the dependencies of a package.'
puts 'Dependencies are added if the package file is missing them.'
puts 'Usage: getrealdeps.rb <packagename>'
exit 1
end
pkg = ARGV[0].chomp('.rb')
CREW_PREFIX = ENV['CREW_PREFIX'] || `crew const CREW_PREFIX`.split('=')[1].chomp
CREW_LIB_PREFIX = ENV['CREW_LIB_PREFIX'] || `crew const CREW_LIB_PREFIX`.split('=')[1].chomp
# Package needs to be installed for package filelist to be populated.
unless File.exist? "#{CREW_PREFIX}/etc/crew/meta/#{pkg}.filelist"
puts "Installing #{pkg} because it is not installed."
system("yes | crew install #{pkg}")
end
unless File.exist?("#{CREW_PREFIX}/etc/crew/meta/#{pkg}.filelist")
puts "Package #{pkg} either does not exist or does not contain any libraries."
exit 1
end
# Speed up grep.
ENV['LC_ALL'] = 'C'
# Install grep if a functional local copy does not exist.
if system('grep --version > /dev/null 2>&1')
GREP = 'grep'
else
system('crew install grep')
GREP = "#{CREW_PREFIX}/bin/grep"
end
# Gawk is needed for adding dependencies.
unless system('gawk -W version > /dev/null 2>&1')
puts "\nGawk is needed for adding dependencies to package files."
system('crew install gawk')
end
# upx is needed to expand compressed binaries to check for dependencies.
unless system('upx --version > /dev/null 2>&1')
puts "\nUpx is needed to expand compressed binaries."
system('crew install upx')
end
# Search for which packages have a needed library in CREW_LIB_PREFIX.
# This is a subset of what crew whatprovides gives.
def whatprovidesfxn(pkgdepslcl, pkg)
filelcl = if pkgdepslcl.include?(CREW_LIB_PREFIX)
`#{GREP} --exclude #{pkg}.filelist --exclude={"#{CREW_PREFIX}/etc/crew/meta/*_build.filelist"} "#{pkgdepslcl}$" "#{CREW_PREFIX}"/etc/crew/meta/*.filelist`
else
`#{GREP} --exclude #{pkg}.filelist --exclude={"#{CREW_PREFIX}/etc/crew/meta/*_build.filelist"} "^#{CREW_LIB_PREFIX}.*#{pkgdepslcl}$" "#{CREW_PREFIX}"/etc/crew/meta/*.filelist`
end
filelcl.gsub(/.filelist.*/, '').gsub(%r{.*/}, '').split("\n").uniq.join("\n").gsub(':', '')
end
# What files does a package provide.
def crewfilesfxn(pkgname)
File.read("#{CREW_PREFIX}/etc/crew/meta/#{pkgname}.filelist")
end
pkgfiles = crewfilesfxn(pkg).split("\n").uniq
FileUtils.rm_rf("/tmp/deps/#{pkg}")
# Remove files we don't care about, such as man files and non-binaries.
pkgfiles = pkgfiles.reject { |i| !File.file?(i.chomp) || !File.read(i.chomp, 4) == "\x7FELF" || i.include?('.zst') }
# Use readelf to determine library dependencies, as
# this doesn't almost run a program like using ldd would.
pkgdepsfiles = pkgfiles.map do |i|
system("upx -d #{i} > /dev/null 2>&1")
FileUtils.mkdir_p("/tmp/deps/#{pkg}/")
`readelf -d "#{i}" 2>/dev/null | #{GREP} NEEDED | awk '{print $5}' | sed 's/\\[//g' | sed 's/\\]//g' | awk '!x[$0]++' | tee /tmp/deps/#{pkg}/#{File.basename(i)}`
end
pkgdepsfiles = pkgdepsfiles.map do |filedeps|
filedeps.split("\n")
end.flatten.compact.uniq
# Figure out which Chromebrew packages provide the relevant deps.
pkgdeps = pkgdepsfiles.map do |file|
whatprovidesfxn(file, pkg)
end.sort.reject { |i| i.include?(pkg) }.map { |i| i.split("\n")}.flatten.uniq
# Massage the glibc entries in the dependency list.
pkgdeps = pkgdeps.map { |i| i.gsub(/glibc_build.*/, 'glibc') }.uniq
pkgdeps = pkgdeps.map { |i| i.gsub(/glibc_lib.*/, 'glibc_lib') }.uniq.map(&:strip).reject(&:empty?)
# Look for missing runtime dependencies.
missingpkgdeps = pkgdeps.reject { |i| File.read("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").include?("depends_on '#{i}'") unless File.read("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").include?("depends_on '#{i}' => :build") }
puts "\nPackage #{pkg} has runtime library dependencies on these packages:"
pkgdeps.each do |i|
puts " depends_on '#{i}' # R"
end
if missingpkgdeps.length.positive?
puts "\nPackage file #{pkg}.rb is missing these runtime library dependencies:"
missingpkgdeps.each do |i|
puts " depends_on '#{i}' # R"
end
end
# Add missing dependencies to the package.
missingpkgdeps.each do |adddep|
puts "\n Adding deps: #{adddep}"
gawk_cmd = if File.foreach("#{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb").grep(/depends_on/).any?
# This files contains dependencies already, so add new deps after existing dependencies.
"gawk -i inplace -v dep=\" depends_on '#{adddep}' # R\" 'FNR==NR{ if (/depends_on/) p=NR; next} 1; FNR==p{ print dep }' #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb"
else
# This files doesn't contain deps, so just add new deps.
"gawk -i inplace -v dep=\" depends_on '#{adddep}' # R\" 'FNR==NR{ if (/})/) p=NR; next} 1; FNR==p{ print \"\\n\" dep }' #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb #{CREW_PREFIX}/lib/crew/packages/#{pkg}.rb"
end
system(gawk_cmd)
end