mirror of
https://github.com/chromebrew/chromebrew.git
synced 2026-01-08 23:18:10 -05:00
1244 lines
40 KiB
Ruby
Executable File
1244 lines
40 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
require_relative '../lib/color'
|
|
|
|
# Disallow sudo
|
|
abort 'Chromebrew should not be run as root.'.lightred if Process.uid == 0
|
|
|
|
require 'find'
|
|
require 'net/http'
|
|
require 'uri'
|
|
require 'digest/sha2'
|
|
require 'json'
|
|
require 'fileutils'
|
|
require 'securerandom'
|
|
require_relative '../lib/const'
|
|
require_relative '../lib/util'
|
|
|
|
# Add lib to LOAD_PATH
|
|
$LOAD_PATH.unshift "#{CREW_LIB_PATH}lib"
|
|
|
|
DOC = <<DOCOPT
|
|
Chromebrew - Package manager for Chrome OS http://skycocker.github.io/chromebrew/
|
|
|
|
Usage:
|
|
crew build [options] [-k|--keep] <name> ...
|
|
crew const [options] [<name> ...]
|
|
crew download [options] <name> ...
|
|
crew files [options] <name> ...
|
|
crew help [<command>]
|
|
crew install [options] [-k|--keep] [-s|--build-from-source] [-S|--recursive-build] <name> ...
|
|
crew list [options] (available|installed|compatible|incompatible)
|
|
crew postinstall [options] <name> ...
|
|
crew reinstall [options] [-k|--keep] [-s|--build-from-source] [-S|--recursive-build] <name> ...
|
|
crew remove [options] <name> ...
|
|
crew search [options] [<name> ...]
|
|
crew update [options]
|
|
crew upgrade [options] [-k|--keep] [-s|--build-from-source] [<name> ...]
|
|
crew whatprovides [options] <name> ...
|
|
|
|
-c --color Use colors even if standard out is not a tty.
|
|
-d --no-color Disable colors even if standard out is a tty.
|
|
-k --keep Keep the `CREW_BREW_DIR` (#{CREW_BREW_DIR}) directory.
|
|
-L --license Display the crew license.
|
|
-s --build-from-source Build from source even if pre-compiled binary exists.
|
|
-S --recursive-build Build from source, including all dependencies, even if pre-compiled binaries exist.
|
|
-v --verbose Show extra information.
|
|
-V --version Display the crew version.
|
|
-h --help Show this screen.
|
|
|
|
version #{CREW_VERSION}
|
|
DOCOPT
|
|
|
|
CREW_LICENSE = <<~LICENSESTRING
|
|
Copyright (C) 2021 Chromebrew Authors
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.html.
|
|
LICENSESTRING
|
|
|
|
# Set XZ_OPT environment variable for build command.
|
|
# If CREW_XZ_OPT is defined, use it by default. Use `-7e`, otherwise.
|
|
ENV["XZ_OPT"] = ENV['CREW_XZ_OPT'] || "-7e -T #{CREW_NPROC}"
|
|
|
|
# If CURL environment variable exists use it in lieu of curl.
|
|
CURL = ENV['CURL'] || 'curl'
|
|
|
|
# All available crew commands.
|
|
@cmds = ["build", "const", "download", "files", "help", "install", "list", "postinstall", "reinstall", "remove", "search", "update", "upgrade", "whatprovides"]
|
|
|
|
# Parse arguments using docopt
|
|
require_relative '../lib/docopt'
|
|
begin
|
|
args = Docopt::docopt(DOC)
|
|
args['<name>'] = args['<name>'].map { |arg| arg.gsub('-','_') } if args['<name>']
|
|
rescue Docopt::Exit => e
|
|
if ARGV[0] then
|
|
case ARGV[0]
|
|
when '-V', '--version'
|
|
puts CREW_VERSION
|
|
exit 0
|
|
when '-L', '--license'
|
|
puts CREW_LICENSE
|
|
exit 0
|
|
end
|
|
if ARGV[0] != '-h' and ARGV[0] != '--help' then
|
|
puts "Could not understand \"crew #{ARGV.join(' ')}\".".lightred
|
|
# Looking for similar commands
|
|
if not @cmds.include?(ARGV[0]) then
|
|
similar = @cmds.select {|word| edit_distance(ARGV[0], word) < 4}
|
|
if not similar.empty? then
|
|
puts 'Did you mean?'
|
|
similar.each {|sug| puts " #{sug}"}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
puts e.message
|
|
exit 1
|
|
end
|
|
|
|
String.use_color = args["--color"] || !args["--no-color"]
|
|
@opt_keep = args["--keep"]
|
|
@opt_verbose = args["--verbose"]
|
|
|
|
if @opt_verbose then
|
|
@fileutils_verbose = true
|
|
@verbose = 'v'
|
|
@short_verbose = '-v'
|
|
else
|
|
@fileutils_verbose = false
|
|
@verbose = ''
|
|
@short_verbose = ''
|
|
end
|
|
|
|
@opt_src = args["--build-from-source"]
|
|
@opt_recursive = args["--recursive-build"]
|
|
|
|
@device = JSON.parse(File.read(CREW_CONFIG_PATH + 'device.json'), symbolize_names: true)
|
|
#symbolize also values
|
|
@device.each do |key, elem|
|
|
@device[key] = @device[key].to_sym rescue @device[key]
|
|
end
|
|
|
|
def print_package(pkgPath, extra = false)
|
|
pkgName = File.basename pkgPath, '.rb'
|
|
set_package pkgName, pkgPath
|
|
print_current_package extra
|
|
end
|
|
|
|
def print_current_package (extra = false)
|
|
pkgName = @pkg.name
|
|
status = ''
|
|
status = 'installed' if @device[:installed_packages].any? do |elem| elem[:name] == pkgName end
|
|
status = 'incompatible' unless @device[:compatible_packages].any? do |elem| elem[:name] == pkgName end
|
|
case status
|
|
when 'installed'
|
|
print @pkg.name.lightgreen
|
|
when 'incompatible'
|
|
print @pkg.name.lightred
|
|
else
|
|
print @pkg.name
|
|
end
|
|
print ": #{@pkg.description}" if @pkg.description
|
|
if extra
|
|
puts ""
|
|
puts @pkg.homepage if @pkg.homepage
|
|
puts "Version: #{@pkg.version}"
|
|
print "License: #{@pkg.license}" if @pkg.license
|
|
end
|
|
puts ""
|
|
end
|
|
|
|
def set_package (pkgName, pkgPath)
|
|
require pkgPath
|
|
@pkg = Object.const_get(pkgName.capitalize)
|
|
@pkg.build_from_source = true if @opt_recursive
|
|
@pkg.name = pkgName
|
|
end
|
|
|
|
def list_packages
|
|
Dir[CREW_PACKAGES_PATH + '*.rb'].each do |filename|
|
|
print_package filename
|
|
end
|
|
end
|
|
|
|
def list_available
|
|
Dir[CREW_PACKAGES_PATH + '*.rb'].each do |filename|
|
|
notInstalled = true
|
|
pkgName = File.basename filename, '.rb'
|
|
notInstalled = false if File.exists? CREW_META_PATH + pkgName + '.filelist'
|
|
if notInstalled
|
|
set_package pkgName, filename
|
|
if @pkg.compatibility.include? 'all' or @pkg.compatibility.include? ARCH
|
|
puts pkgName
|
|
else
|
|
puts pkgName.lightred
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def list_installed
|
|
Dir[CREW_META_PATH + '*.directorylist'].sort.map do |f|
|
|
File.basename(f, '.directorylist').lightgreen
|
|
end
|
|
end
|
|
|
|
def list_compatible(compat = true)
|
|
Dir[CREW_PACKAGES_PATH + '*.rb'].each do |filename|
|
|
pkgName = File.basename filename, '.rb'
|
|
set_package pkgName, filename
|
|
if compat
|
|
if @pkg.compatibility.include? 'all' or @pkg.compatibility.include? ARCH
|
|
if File.exist? CREW_META_PATH + pkgName + '.filelist'
|
|
puts pkgName.lightgreen
|
|
else
|
|
puts pkgName
|
|
end
|
|
end
|
|
else
|
|
unless @pkg.compatibility.include? 'all' or @pkg.compatibility.include? ARCH
|
|
puts pkgName.lightred
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def generate_compatible
|
|
@device[:compatible_packages] = []
|
|
Dir[CREW_PACKAGES_PATH + '*.rb'].each do |filename|
|
|
pkgName = File.basename filename, '.rb'
|
|
set_package pkgName, filename
|
|
if @pkg.compatibility.include? 'all' or @pkg.compatibility.include? ARCH
|
|
#add to compatible packages
|
|
@device[:compatible_packages].push(name: @pkg.name)
|
|
end
|
|
end
|
|
File.open(CREW_CONFIG_PATH + 'device.json', 'w') do |file|
|
|
output = JSON.parse @device.to_json
|
|
file.write JSON.pretty_generate(output)
|
|
end
|
|
end
|
|
|
|
def search (pkgName, silent = false)
|
|
pkgPath = CREW_PACKAGES_PATH + pkgName + '.rb'
|
|
return set_package(pkgName, pkgPath) if File.exist?(pkgPath)
|
|
abort "Package #{pkgName} not found. :(".lightred unless silent
|
|
end
|
|
|
|
def regexp_search(pkgPat)
|
|
re = Regexp.new(pkgPat, true)
|
|
results = Dir[CREW_PACKAGES_PATH + '*.rb'].sort \
|
|
.select { |f| File.basename(f, '.rb') =~ re } \
|
|
.each { |f| print_package(f, @opt_verbose) }
|
|
if results.empty?
|
|
Dir[CREW_PACKAGES_PATH + '*.rb'].each do |packagePath|
|
|
packageName = File.basename packagePath, '.rb'
|
|
set_package packageName, packagePath
|
|
if ( @pkg.description =~ /#{pkgPat}/i )
|
|
print_current_package @opt_verbose
|
|
results.push(packageName)
|
|
end
|
|
end
|
|
end
|
|
abort "Package #{pkgPat} not found. :(".lightred unless results.length > 0
|
|
end
|
|
|
|
def help (pkgName)
|
|
case pkgName
|
|
when "build"
|
|
puts "Build package(s)."
|
|
puts "Usage: crew build [-k|--keep] [-v|--verbose] <package1> [<package2> ...]"
|
|
puts "Build package(s) from source and place the archive and checksum in the current working directory."
|
|
puts "If `-k` or `--keep` is present, the `CREW_BREW_DIR` (#{CREW_BREW_DIR}) directory will remain."
|
|
puts "If `-v` or `--verbose` is present, extra information will be displayed."
|
|
when "const"
|
|
puts "Display constant(s)."
|
|
puts "Usage: crew const [<const1> <const2> ...]"
|
|
puts "If no constants are provided, all constants will be displayed."
|
|
when "download"
|
|
puts "Download package(s)."
|
|
puts "Usage: crew download [-v|--verbose] <package1> [<package2> ...]"
|
|
puts "Download package(s) to `CREW_BREW_DIR` (#{CREW_BREW_DIR}), but don't install."
|
|
puts "If `-v` or `--verbose` is present, extra information will be displayed."
|
|
when "files"
|
|
puts "Display installed files of package(s)."
|
|
puts "Usage: crew files <package1> [<package2> ...]"
|
|
puts "The package(s) must be currently installed."
|
|
when "install"
|
|
puts "Install package(s)."
|
|
puts "Usage: crew install [-k|--keep] [-s|--build-from-source] [-S|--recursive-build] [-v|--verbose] <package1> [<package2> ...]"
|
|
puts "The package(s) must have a valid name. Use `crew search <pattern>` to search for packages to install."
|
|
puts "If `-k` or `--keep` is present, the `CREW_BREW_DIR` (#{CREW_BREW_DIR}) directory will remain."
|
|
puts "If `-s` or `--build-from-source` is present, the package(s) will be compiled instead of installed via binary."
|
|
puts "If `-S` or `--recursive-build` is present, the package(s), including all dependencies, will be compiled instead of installed via binary."
|
|
puts "If `-v` or `--verbose` is present, extra information will be displayed."
|
|
when "list"
|
|
puts "List packages"
|
|
puts "Usage: crew list available|installed|compatible|incompatible"
|
|
when "postinstall"
|
|
puts "Display postinstall messages of package(s)."
|
|
puts "Usage: crew postinstall <package1> [<package2> ...]"
|
|
puts "The package(s) must be currently installed."
|
|
when "reinstall"
|
|
puts "Remove and install package(s)."
|
|
puts "Usage: crew reinstall [-k|--keep] [-s|--build-from-source] [-S|--recursive-build] [-v|--verbose] <package1> [<package2> ...]"
|
|
puts "If `-k` or `--keep` is present, the `CREW_BREW_DIR` (#{CREW_BREW_DIR}) directory will remain."
|
|
puts "If `-s` or `--build-from-source` is present, the package(s) will be compiled instead of installed via binary."
|
|
puts "If `-S` or `--recursive-build` is present, the package(s), including all dependencies, will be compiled instead of installed via binary."
|
|
puts "If `-v` or `--verbose` is present, extra information will be displayed."
|
|
when "remove"
|
|
puts "Remove package(s)."
|
|
puts "Usage: crew remove [-v|--verbose] <package1> [<package2> ...]"
|
|
puts "The package(s) must be currently installed."
|
|
puts "If `-v` or `--verbose` is present, extra information will be displayed."
|
|
when "search"
|
|
puts "Look for package(s)."
|
|
puts "Usage: crew search [-v|--verbose] [<pattern> ...]"
|
|
puts "If <pattern> is omitted, all packages will be returned."
|
|
puts "If the package color is " + "green".lightgreen + ", it means the package is installed."
|
|
puts "If the package color is " + "red".lightred + ", it means the architecture is not supported."
|
|
puts "The <pattern> string can also contain regular expressions."
|
|
puts "If `-v` or `--verbose` is present, homepage, version and license will be displayed."
|
|
puts "Examples:"
|
|
puts " crew search ^lib".lightblue + " will display all packages that start with `lib`."
|
|
puts " crew search audio".lightblue + " will display all packages with `audio` in the name."
|
|
puts " crew search | grep -i audio".lightblue + " will display all packages with `audio` in the name or description."
|
|
puts " crew search git -v".lightblue + " will display packages with `git` in the name along with homepage, version and license."
|
|
when "update"
|
|
puts "Update crew."
|
|
puts "Usage: crew update"
|
|
puts "This only updates crew itself. Use `crew upgrade` to update packages."
|
|
when "upgrade"
|
|
puts "Update package(s)."
|
|
puts "Usage: crew upgrade [-v|--verbose] [-s|--build-from-source] <package1> [<package2> ...]"
|
|
puts "If package(s) are omitted, all packages will be updated. Otherwise, specific package(s) will be updated."
|
|
puts "Use `crew update` to update crew itself."
|
|
puts "If `-s` or `--build-from-source` is present, the package(s) will be compiled instead of upgraded via binary."
|
|
puts "If `-v` or `--verbose` is present, extra information will be displayed."
|
|
when "whatprovides"
|
|
puts "Determine which package(s) contains file(s)."
|
|
puts "Usage: crew whatprovides <pattern> ..."
|
|
puts "The <pattern> is a search string which can contain regular expressions."
|
|
else
|
|
puts "Available commands: #{@cmds.join(', ')}"
|
|
end
|
|
end
|
|
|
|
def const (var)
|
|
if var
|
|
value = eval(var)
|
|
puts "#{var}=#{value}"
|
|
else
|
|
vars = [
|
|
'ARCH',
|
|
'ARCH_LIB',
|
|
'CHROMEOS_RELEASE',
|
|
'CURL',
|
|
'CREW_BREW_DIR',
|
|
'CREW_BUILD',
|
|
'CREW_CMAKE_LIBSUFFIX_OPTIONS',
|
|
'CREW_CMAKE_OPTIONS',
|
|
'CREW_CONFIG_PATH',
|
|
'CREW_DEST_DIR',
|
|
'CREW_DEST_HOME',
|
|
'CREW_DEST_LIB_PREFIX',
|
|
'CREW_DEST_MAN_PREFIX',
|
|
'CREW_DEST_PREFIX',
|
|
'CREW_LIB_PATH',
|
|
'CREW_LIB_PREFIX',
|
|
'CREW_LIB_SUFFIX',
|
|
'CREW_MAN_PREFIX',
|
|
'CREW_COMMON_FLAGS',
|
|
'CREW_COMMON_FNO_LTO_FLAGS',
|
|
'CREW_ENV_OPTIONS',
|
|
'CREW_MESON_FNO_LTO_OPTIONS',
|
|
'CREW_MESON_OPTIONS',
|
|
'CREW_META_PATH',
|
|
'CREW_NOT_COMPRESS',
|
|
'CREW_NOT_STRIP',
|
|
'CREW_NPROC',
|
|
'CREW_OPTIONS',
|
|
'CREW_PACKAGES_PATH',
|
|
'CREW_PREFIX',
|
|
'CREW_TGT',
|
|
'CREW_VERSION',
|
|
'HOME',
|
|
'LIBC_VERSION',
|
|
'USER'
|
|
]
|
|
vars.each { |var|
|
|
value = eval(var)
|
|
puts "#{var}=#{value}"
|
|
}
|
|
end
|
|
end
|
|
|
|
def human_size (bytes)
|
|
kilobyte = 1024.0
|
|
megabyte = kilobyte * kilobyte
|
|
gigabyte = megabyte * kilobyte
|
|
if bytes < kilobyte
|
|
units = 'B'
|
|
size = bytes
|
|
end
|
|
if bytes >= kilobyte and bytes < megabyte
|
|
units = 'KB'
|
|
size = bytes / kilobyte
|
|
end
|
|
if bytes >= megabyte and bytes < gigabyte
|
|
units = 'MB'
|
|
size = bytes / megabyte
|
|
end
|
|
if bytes >= gigabyte
|
|
units = 'GB'
|
|
size = bytes / gigabyte
|
|
end
|
|
return sprintf('%.2f', size.to_s) + units
|
|
end
|
|
|
|
def files (pkgName)
|
|
filelist = "#{CREW_META_PATH}#{pkgName}.filelist"
|
|
if File.exists? filelist
|
|
system "sort #{filelist}"
|
|
lines = File.readlines(filelist).size
|
|
size = 0
|
|
File.readlines(filelist).each do |filename|
|
|
size += File.size(filename.chomp) if File.exists? filename.chomp
|
|
end
|
|
humansize = human_size(size)
|
|
puts "Total found: #{lines}".lightgreen
|
|
puts "Disk usage: #{humansize}".lightgreen
|
|
else
|
|
puts "Package #{pkgName} is not installed. :(".lightred
|
|
end
|
|
end
|
|
|
|
def whatprovides (regexPat)
|
|
fileArray = []
|
|
needle = regexPat.gsub(/-/,',').gsub(/,/,'\-')
|
|
Dir[CREW_META_PATH + '*.filelist'].each do |packageList|
|
|
packageName = File.basename packageList, '.filelist'
|
|
File.readlines(packageList).each do |line|
|
|
found = line[/#{needle}/] if line.ascii_only?
|
|
if found
|
|
fileLine = packageName + ': ' + line
|
|
if not fileArray.include? fileLine
|
|
fileArray.push(fileLine)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if not fileArray.empty?
|
|
fileArray.sort.each do |item|
|
|
puts item
|
|
end
|
|
puts "\nTotal found: #{fileArray.length}".lightgreen
|
|
end
|
|
end
|
|
|
|
def update
|
|
abort "'crew update' is used to update crew itself. Use 'crew upgrade <package1> [<package2> ...]' to update specific packages.".orange if @pkgName
|
|
@crew_testing_repo = ENV['CREW_TESTING_REPO']
|
|
@crew_testing_branch = ENV['CREW_TESTING_BRANCH']
|
|
@crew_testing = ENV['CREW_TESTING']
|
|
@crew_testing = 0 if @crew_testing_repo.nil? || @crew_testing_repo.empty?
|
|
@crew_testing = 0 if @crew_testing_branch.nil? || @crew_testing_branch.empty?
|
|
#update package lists
|
|
Dir.chdir CREW_LIB_PATH do
|
|
if @crew_testing == '1'
|
|
puts "Updating crew from testing repository..."
|
|
system "git remote add testing #{@crew_testing_repo} 2>/dev/null || \
|
|
git remote set-url testing #{@crew_testing_repo}"
|
|
system "git fetch testing #{@crew_testing_branch}"
|
|
system "git reset --hard testing/#{@crew_testing_branch}"
|
|
else
|
|
system 'git fetch origin master'
|
|
system 'git reset --hard origin/master'
|
|
end
|
|
end
|
|
|
|
puts 'Package lists, crew, and library updated.'
|
|
|
|
#update compatible packages
|
|
puts 'Generating compatible packages...'
|
|
generate_compatible
|
|
|
|
#check for outdated installed packages
|
|
puts 'Checking for package updates...'
|
|
|
|
canBeUpdated = 0
|
|
@device[:installed_packages].each do |package|
|
|
search package[:name], true
|
|
if package[:version] != @pkg.version
|
|
canBeUpdated += 1
|
|
puts @pkg.name + ' could be updated from ' + package[:version] + ' to ' + @pkg.version
|
|
end
|
|
end
|
|
|
|
if canBeUpdated > 0
|
|
puts
|
|
puts "Run `crew upgrade` to update all packages or `crew upgrade <package1> [<package2> ...]` to update specific packages."
|
|
else
|
|
puts "Your software is up to date.".lightgreen
|
|
end
|
|
end
|
|
|
|
def upgrade
|
|
if @pkgName
|
|
currentVersion = nil
|
|
@device[:installed_packages].each do |package|
|
|
if package[:name] == @pkg.name
|
|
currentVersion = package[:version]
|
|
end
|
|
end
|
|
|
|
if currentVersion != @pkg.version
|
|
puts "Updating #{@pkg.name}..."
|
|
@pkg.in_upgrade = true
|
|
resolve_dependencies_and_install
|
|
@pkg.in_upgrade = false
|
|
else
|
|
puts "#{@pkg.name} is already up to date.".lightgreen
|
|
end
|
|
else
|
|
# Make a installed packages list belong to the dependency order
|
|
dependencies = []
|
|
@device[:installed_packages].each do |package|
|
|
# skip package if it is dependent other packages previously checked
|
|
next if dependencies.include? package[:name]
|
|
# add package itself
|
|
dependencies = [ package[:name] ].concat(dependencies)
|
|
# expand depencencies and add it to the dependencies list
|
|
search package[:name], true
|
|
exp_dep = expand_dependencies
|
|
dependencies = exp_dep.concat(dependencies)
|
|
end
|
|
dependencies.uniq!
|
|
|
|
# Check version number of installed package and make a target list
|
|
toBeUpdated = []
|
|
dependencies.each do |dep|
|
|
package = @device[:installed_packages].find {|pkg| pkg[:name] == dep}
|
|
next unless package
|
|
search package[:name], true
|
|
if package[:version] != @pkg.version
|
|
toBeUpdated.push(package[:name])
|
|
end
|
|
end
|
|
|
|
if toBeUpdated.length > 0
|
|
puts 'Updating packages...'
|
|
toBeUpdated.each do |package|
|
|
search package
|
|
print_current_package
|
|
puts "Updating " + @pkg.name + "..." if @opt_verbose
|
|
@pkg.in_upgrade = true
|
|
resolve_dependencies_and_install
|
|
@pkg.in_upgrade = false
|
|
end
|
|
puts "Packages have been updated.".lightgreen
|
|
else
|
|
puts "Your software is already up to date.".lightgreen
|
|
end
|
|
end
|
|
end
|
|
|
|
def download
|
|
url = @pkg.get_url(@device[:architecture])
|
|
source = @pkg.is_source?(@device[:architecture])
|
|
|
|
uri = URI.parse url
|
|
filename = File.basename(uri.path)
|
|
sha256sum = @pkg.get_sha256(@device[:architecture])
|
|
@extract_dir = @pkg.get_extract_dir
|
|
|
|
if !url
|
|
abort "No precompiled binary or source is available for #{@device[:architecture]}.".lightred
|
|
elsif !source
|
|
puts "Precompiled binary available, downloading..."
|
|
elsif @pkg.build_from_source
|
|
puts "Downloading source..."
|
|
else
|
|
puts "No precompiled binary available for your platform, downloading source..."
|
|
end
|
|
|
|
Dir.chdir CREW_BREW_DIR do
|
|
|
|
case File.basename(filename)
|
|
# Sources that download with curl
|
|
when /\.zip$/i, /\.(tar(\.(gz|bz2|xz|lz))?|tgz|tbz|txz)$/i, /\.deb$/i
|
|
# Recall file from cache if requeseted
|
|
if CREW_CACHE_ENABLED
|
|
cachefile = CREW_CACHE_DIR + filename
|
|
if File.file?(cachefile)
|
|
if Digest::SHA256.hexdigest( File.read(cachefile) ) == sha256sum then
|
|
FileUtils.cp cachefile, CREW_BREW_DIR, verbose: @fileutils_verbose
|
|
puts "Archive found in cache".lightgreen
|
|
return {source: source, filename: filename}
|
|
else
|
|
puts 'Cached archive checksum mismatch. :/ Will download.'.lightred
|
|
end
|
|
puts 'Cannot find cached archive. :/ Will download.'.lightred
|
|
end
|
|
end
|
|
# Download file if not cached
|
|
system "#{CURL} --retry 3 -#{@verbose}#LC - --insecure \'#{url}\' --output #{filename}"
|
|
abort 'Checksum mismatch. :/ Try again.'.lightred unless
|
|
Digest::SHA256.hexdigest( File.read(filename) ) == sha256sum
|
|
puts 'Archive downloaded.'.lightgreen
|
|
# Stow file in cache if requested
|
|
if CREW_CACHE_ENABLED
|
|
FileUtils.cp filename, CREW_CACHE_DIR, verbose: @fileutils_verbose
|
|
puts 'Archive cached.'.lightgreen
|
|
end
|
|
|
|
# Sources that download with git
|
|
when /\.git$/i
|
|
# Recall repository from cache if requested
|
|
if CREW_CACHE_ENABLED
|
|
cachefile = CREW_CACHE_DIR + '/' + filename + '.tar.xz'
|
|
if File.file?(cachefile)
|
|
if system "sha256sum -c #{cachefile}.sha256"
|
|
FileUtils.mkdir @extract_dir
|
|
system "tar x#{@verbose}f #{cachefile} -C #{@extract_dir}"
|
|
return {source: source, filename: filename}
|
|
else
|
|
puts 'Cached repository checksum mismatch. :/ Will download.'.lightred
|
|
end
|
|
else
|
|
puts 'Cannot find cached repository. :/ Will download.'.lightred
|
|
end
|
|
end
|
|
# Download via git
|
|
Dir.mkdir @extract_dir
|
|
Dir.chdir @extract_dir do
|
|
system 'git init'
|
|
system 'git config advice.detachedHead false'
|
|
system 'git config init.defaultBranch master'
|
|
system "git remote add origin #{@pkg.source_url}", exception: true
|
|
unless @pkg.git_branch.nil? || @pkg.git_branch.empty?
|
|
# Leave a message because this step can be slow.
|
|
puts "Downloading src from a git branch. This may take a while..."
|
|
system "git remote set-branches origin #{@pkg.git_branch}", exception: true
|
|
system "git fetch --progress origin #{@pkg.git_branch}", exception: true
|
|
system "git checkout #{@pkg.git_hashtag}", exception: true
|
|
else
|
|
system "git fetch --depth 1 origin #{@pkg.git_hashtag}", exception: true
|
|
system 'git checkout FETCH_HEAD'
|
|
end
|
|
system 'git submodule update --init --recursive'
|
|
puts 'Repository downloaded.'.lightgreen
|
|
end
|
|
# Stow file in cache if requested
|
|
if CREW_CACHE_ENABLED
|
|
puts 'Caching downloaded archive...'
|
|
Dir.chdir "#{@extract_dir}" do
|
|
system "tar c#{@verbose}Jf #{CREW_CACHE_DIR}/#{filename}.tar.xz \
|
|
$(find -mindepth 1 -maxdepth 1 -printf '%P\n')"
|
|
end
|
|
system "sha256sum #{CREW_CACHE_DIR}/#{filename}.tar.xz > #{CREW_CACHE_DIR}/#{filename}.tar.xz.sha256"
|
|
puts 'Archive cached.'.lightgreen
|
|
end
|
|
end
|
|
end
|
|
return {source: source, filename: filename}
|
|
end
|
|
|
|
def unpack (meta)
|
|
target_dir = nil
|
|
Dir.chdir CREW_BREW_DIR do
|
|
FileUtils.mkdir_p @extract_dir, verbose: @fileutils_verbose
|
|
case File.basename meta[:filename]
|
|
when /\.zip$/i
|
|
puts "Unpacking archive using 'unzip', this may take a while..."
|
|
_verbopt = @opt_verbose ? '-v' : '-qq'
|
|
system 'unzip', _verbopt, '-d', @extract_dir, meta[:filename], exception: true
|
|
when /\.(tar(\.(gz|bz2|xz|lz))?|tgz|tbz|txz)$/i
|
|
puts "Unpacking archive using 'tar', this may take a while..."
|
|
FileUtils.mkdir @extract_dir unless Dir.exist?(@extract_dir)
|
|
system "tar x#{@verbose}f #{meta[:filename]} -C #{@extract_dir}", exception: true
|
|
when /\.deb$/i
|
|
puts "Unpacking archive using 'ar', this may take a while..."
|
|
FileUtils.mkdir @extract_dir unless Dir.exist?(@extract_dir)
|
|
system "ar -p #{meta[:filename]} data.tar.xz | xz -dc#{@verbose} | tar x#{@verbose} -C #{@extract_dir}", exception: true
|
|
end
|
|
if meta[:source] == true
|
|
# Check the number of directories in the archive
|
|
entries = Dir["#{@extract_dir}/*"]
|
|
entries = Dir[@extract_dir] if entries.empty?
|
|
if entries.length == 0
|
|
abort "Empty archive: #{meta[:filename]}".lightred
|
|
elsif entries.length == 1 && File.directory?(entries.first)
|
|
# Use `extract_dir/dir_in_archive` if there is only one directory.
|
|
target_dir = entries.first
|
|
else
|
|
# Use `extract_dir` otherwise
|
|
target_dir = @extract_dir
|
|
end
|
|
else
|
|
# Use `extract_dir` for binary distribution
|
|
target_dir = @extract_dir
|
|
end
|
|
end
|
|
return CREW_BREW_DIR + target_dir
|
|
end
|
|
|
|
def build_and_preconfigure (target_dir)
|
|
Dir.chdir target_dir do
|
|
puts 'Building from source, this may take a while...'
|
|
|
|
# Rename *.la files temporily to *.la_tmp to avoid
|
|
# libtool: link: '*.la' is not a valid libtool archive.
|
|
# See https://gnunet.org/faq-la-files and
|
|
# https://stackoverflow.com/questions/42963653/libquadmath-la-is-not-a-valid-libtool-archive-when-configuring-openmpi-with-g
|
|
puts 'Rename all *.la files to *.la_tmp'.lightblue
|
|
|
|
system "find #{CREW_LIB_PREFIX} -type f -name *.la -print0 | xargs --null -I{} mv #{@short_verbose} {} {}_tmp"
|
|
|
|
@pkg.in_build = true
|
|
@pkg.patch
|
|
@pkg.prebuild
|
|
@pkg.build
|
|
@pkg.in_build = false
|
|
# wipe crew destdir
|
|
FileUtils.rm_rf Dir.glob("#{CREW_DEST_DIR}/*"), verbose: @fileutils_verbose
|
|
puts 'Preconfiguring package...'
|
|
@pkg.install
|
|
|
|
# Rename all *.la_tmp back to *.la to avoid
|
|
# cannot access '*.la': No such file or directory
|
|
puts 'Rename all *.la_tmp files back to *.la'.lightblue
|
|
system "find #{CREW_LIB_PREFIX} -type f -name '*.la_tmp' -exec sh -c 'mv #{@short_verbose} \"$1\" \"${1%.la_tmp}.la\"' _ {} \\;"
|
|
end
|
|
end
|
|
|
|
def pre_install (dest_dir)
|
|
Dir.chdir dest_dir do
|
|
puts 'Performing pre-install...'
|
|
@pkg.preinstall
|
|
end
|
|
end
|
|
|
|
def post_install (dest_dir)
|
|
Dir.chdir dest_dir do
|
|
puts 'Performing post-install...'
|
|
@pkg.postinstall
|
|
end
|
|
end
|
|
|
|
def compress_doc (dir)
|
|
# check whether crew should compress
|
|
return if CREW_NOT_COMPRESS || ENV['CREW_NOT_COMPRESS'] || !File.exist?("#{CREW_PREFIX}/bin/compressdoc")
|
|
|
|
if Dir.exist? dir
|
|
system "find #{dir} -type f ! -perm -200 | xargs -r chmod u+w"
|
|
system "compressdoc --gzip -9 #{@short_verbose} #{dir}"
|
|
end
|
|
end
|
|
|
|
def prepare_package (destdir)
|
|
Dir.chdir destdir do
|
|
# Avoid /usr/local/share/info/dir{.gz} file conflict:
|
|
# The install-info program maintains a directory of installed
|
|
# info documents in /usr/share/info/dir for the use of info
|
|
# readers. This file must not be included in packages other
|
|
# than install-info.
|
|
# https://www.debian.org/doc/debian-policy/ch-docs.html#info-documents
|
|
FileUtils.rm "#{CREW_DEST_PREFIX}/share/info/dir" if File.exist?("#{CREW_DEST_PREFIX}/share/info/dir")
|
|
|
|
# compress manual files
|
|
compress_doc "#{CREW_DEST_PREFIX}/man"
|
|
compress_doc "#{CREW_DEST_PREFIX}/info"
|
|
compress_doc "#{CREW_DEST_PREFIX}/share/man"
|
|
compress_doc "#{CREW_DEST_PREFIX}/share/info"
|
|
|
|
# create file list
|
|
system 'find . -type f > ../filelist'
|
|
system 'find . -type l >> ../filelist'
|
|
system 'cut -c2- ../filelist > filelist'
|
|
|
|
# check for conflicts with other installed files
|
|
puts "Checking for conflicts with files from installed packages..."
|
|
conflicts = []
|
|
@conflictscmd = "grep --exclude #{CREW_META_PATH}#{@pkg.name}.filelist \
|
|
-Fxf filelist #{CREW_META_PATH}*.filelist | tr ':' ' ' | \
|
|
sed 's,.filelist,,g' | sed 's,#{CREW_META_PATH},,g'"
|
|
conflicts << %x[#{@conflictscmd}].chomp.split(" ")
|
|
conflicts.reject!(&:empty?)
|
|
unless conflicts.empty?
|
|
puts "Unable to complete this build since there is a conflict with the same file in another package.".lightred
|
|
pp = ''
|
|
conflicts.each do |p, f|
|
|
puts "\n#{p} package conflicts below:".lightred if p != pp
|
|
puts f.lightred
|
|
pp = p
|
|
end
|
|
abort unless ENV['CREW_CONFLICTS_ONLY_ADVISORY'] == '1'
|
|
end
|
|
|
|
# create directory list
|
|
system 'find . -type d > ../dlist'
|
|
system 'cut -c2- ../dlist > dlistcut'
|
|
system 'tail -n +2 dlistcut > dlist'
|
|
|
|
# remove temporary files
|
|
FileUtils.rm_rf ['dlistcut', '../dlist', '../filelist'], verbose: @fileutils_verbose
|
|
end
|
|
end
|
|
|
|
def strip_find_files (find_cmd, strip_option = "")
|
|
# check whether crew should strip
|
|
return if CREW_NOT_STRIP || ENV['CREW_NOT_STRIP'] || !File.exist?("#{CREW_PREFIX}/bin/llvm-strip")
|
|
|
|
# run find_cmd and strip only ar or ELF files
|
|
system "#{find_cmd} | xargs -r chmod u+w"
|
|
system "#{find_cmd} | xargs -r sh -c 'for i in \"$0\" \"$@\"; do case \"$(head -c 4 $i)\" in ?ELF|\!?ar) echo \"$i\";; esac ; done' | xargs -r llvm-strip #{strip_option}"
|
|
end
|
|
|
|
def install_package (pkgdir)
|
|
Dir.chdir pkgdir do
|
|
# install filelist, dlist and binary files
|
|
puts 'Performing install...'
|
|
|
|
FileUtils.mv 'dlist', CREW_META_PATH + @pkg.name + '.directorylist', verbose: @fileutils_verbose
|
|
FileUtils.mv 'filelist', CREW_META_PATH + @pkg.name + '.filelist', verbose: @fileutils_verbose
|
|
|
|
# Strip libraries with -S
|
|
strip_find_files "find . -type f -name 'lib*.a' -print", "-S"
|
|
strip_find_files "find . -type f -name 'lib*.so*' -print", "-S"
|
|
|
|
# Strip binaries but not compressed archives
|
|
strip_find_files "find . -type f ! -iname '*\.bz2' ! -iname '*\.gz' ! -iname '*\.lha' ! -iname '*\.lz' ! -iname '*\.rar' ! -iname '*\.tar' ! -iname '*\.tbz' ! -iname '*\.tgz' ! -iname '\*.txz' ! -iname '*\.xz' ! -iname '*\.zip' -perm /111 -print | sed -e '/lib.*\.a$/d' -e '/lib.*\.so/d'"
|
|
|
|
if Dir.exists? "#{pkgdir}/home" then
|
|
system "tar -c#{@verbose}f - ./usr/* ./home/* | (cd /; tar xp --keep-directory-symlink -f -)"
|
|
else
|
|
system "tar -c#{@verbose}f - ./usr/* | (cd /; tar xp --keep-directory-symlink -f -)"
|
|
end
|
|
end
|
|
end
|
|
|
|
def resolve_dependencies_and_install
|
|
begin
|
|
origin = @pkg.name
|
|
|
|
resolve_dependencies
|
|
|
|
search origin, true
|
|
install
|
|
rescue InstallError => e
|
|
abort "#{@pkg.name} failed to install: #{e.to_s}".lightred
|
|
ensure
|
|
# cleanup
|
|
unless @opt_keep
|
|
FileUtils.rm_rf Dir.glob("#{CREW_BREW_DIR}/*")
|
|
FileUtils.mkdir_p "#{CREW_BREW_DIR}/dest" # this is a little ugly, feel free to find a better way
|
|
end
|
|
end
|
|
puts "#{@pkg.name.capitalize} installed!".lightgreen
|
|
end
|
|
|
|
def expand_dependencies
|
|
@dependencies = []
|
|
if @pkg.build_from_source
|
|
# make sure all buildessential packages are installed
|
|
pkgname = @pkg.name
|
|
search 'buildessential', true
|
|
check_deps = @pkg.dependencies.map {|k, v| k}
|
|
check_deps.each do |dep|
|
|
@dependencies << dep unless @device[:installed_packages].include?(dep)
|
|
end
|
|
search pkgname, true
|
|
end
|
|
def push_dependencies
|
|
if @pkg.is_binary?(@device[:architecture]) ||
|
|
(!@pkg.in_upgrade && !@pkg.build_from_source && @device[:installed_packages].any? { |pkg| pkg[:name] == @pkg.name })
|
|
# retrieve name of dependencies that doesn't contain :build tag
|
|
check_deps = @pkg.dependencies.select {|k, v| !v.include?(:build)}.map {|k, v| k}
|
|
else
|
|
# retrieve name of all dependencies
|
|
check_deps = @pkg.dependencies.map {|k, v| k}
|
|
end
|
|
# check all dependencies recursively
|
|
check_deps.each do |dep|
|
|
# build unique dependencies list
|
|
unless @dependencies.include?(dep) || dep == @pkgName
|
|
@dependencies << dep
|
|
search dep, true
|
|
push_dependencies
|
|
end
|
|
end
|
|
end
|
|
push_dependencies
|
|
end
|
|
|
|
def resolve_dependencies
|
|
abort "Package #{@pkg.name} is not compatible with your device architecture (#{ARCH}) :/".lightred unless @pkg.compatibility.include?('all') or @pkg.compatibility.include?(ARCH)
|
|
expand_dependencies
|
|
|
|
# leave only not installed packages in dependencies
|
|
@dependencies.select! {|name| @device[:installed_packages].none? {|pkg| pkg[:name] == name}}
|
|
|
|
return if @dependencies.empty?
|
|
|
|
|
|
puts 'The following packages also need to be installed: '
|
|
|
|
i = 0
|
|
last_deps = []
|
|
last_packages = ["curl", "ghc", "mandb", "gtk3", "gtk4", "sommelier"]
|
|
@dependencies.each do |dep|
|
|
if last_packages.include?(dep)
|
|
@dependencies.delete_at(i)
|
|
last_deps.push(dep)
|
|
end
|
|
i += 1
|
|
end
|
|
@dependencies.concat last_deps.sort
|
|
|
|
@dependencies.each do |dep|
|
|
print dep + ' '
|
|
end
|
|
|
|
puts
|
|
print 'Do you agree? [Y/n] '
|
|
response = STDIN.getc
|
|
case response
|
|
when 'n'
|
|
abort 'No changes made.'
|
|
when "\n", "y", "Y"
|
|
puts 'Proceeding...'
|
|
proceed = true
|
|
else
|
|
puts "I don't understand `#{response}`. :(".lightred
|
|
abort 'No changes made.'
|
|
end
|
|
|
|
if proceed
|
|
@dependencies.each do |dep|
|
|
search dep
|
|
print_current_package
|
|
install
|
|
end
|
|
end
|
|
end
|
|
|
|
def install
|
|
if !@pkg.in_upgrade && @device[:installed_packages].any? { |pkg| pkg[:name] == @pkg.name }
|
|
puts "Package #{@pkg.name} already installed, skipping...".lightgreen
|
|
return
|
|
end
|
|
|
|
unless @pkg.is_fake?
|
|
meta = download
|
|
target_dir = unpack meta
|
|
if meta[:source] == true
|
|
|
|
# build from source and place binaries at CREW_DEST_DIR
|
|
# CREW_DEST_DIR contains usr/local/... hierarchy
|
|
build_and_preconfigure target_dir
|
|
|
|
# prepare filelist and dlist at CREW_DEST_DIR
|
|
prepare_package CREW_DEST_DIR
|
|
|
|
# use CREW_DEST_DIR
|
|
dest_dir = CREW_DEST_DIR
|
|
else
|
|
# use extracted binary directory
|
|
dest_dir = target_dir
|
|
end
|
|
end
|
|
|
|
# remove it just before the file copy
|
|
if @pkg.in_upgrade
|
|
puts 'Removing since upgrade or reinstall...'
|
|
remove @pkg.name
|
|
end
|
|
|
|
unless @pkg.is_fake?
|
|
# perform pre-install process
|
|
pre_install dest_dir
|
|
|
|
# perform install process
|
|
install_package dest_dir
|
|
|
|
# perform post-install process
|
|
post_install dest_dir
|
|
end
|
|
|
|
#add to installed packages
|
|
@device[:installed_packages].push(name: @pkg.name, version: @pkg.version)
|
|
File.open(CREW_CONFIG_PATH + 'device.json', 'w') do |file|
|
|
output = JSON.parse @device.to_json
|
|
file.write JSON.pretty_generate(output)
|
|
end
|
|
# Update shared library cache after install is complete.
|
|
system "echo #{CREW_LIB_PREFIX} > #{CREW_PREFIX}/etc/ld.so.conf"
|
|
system "#{CREW_PREFIX}/sbin/ldconfig -f #{CREW_PREFIX}/etc/ld.so.conf -C #{CREW_PREFIX}/etc/ld.so.cache"
|
|
end
|
|
|
|
def resolve_dependencies_and_build
|
|
begin
|
|
origin = @pkg.name
|
|
|
|
# mark current package as which is required to compile from source
|
|
@pkg.build_from_source = true
|
|
resolve_dependencies
|
|
|
|
search origin, true
|
|
build_package Dir.pwd
|
|
rescue InstallError => e
|
|
abort "#{@pkg.name} failed to build: #{e.to_s}".lightred
|
|
ensure
|
|
#cleanup
|
|
unless @opt_keep
|
|
FileUtils.rm_rf Dir.glob("#{CREW_BREW_DIR}/*"), verbose: @fileutils_verbose
|
|
FileUtils.mkdir_p CREW_BREW_DIR + '/dest', verbose: @fileutils_verbose #this is a little ugly, feel free to find a better way
|
|
end
|
|
end
|
|
puts "#{@pkg.name} is built!".lightgreen
|
|
end
|
|
|
|
def build_package (pwd)
|
|
abort 'It is not possible to build a fake package'.lightred if @pkg.is_fake?
|
|
abort 'It is not possible to build without source'.lightred if !@pkg.is_source?(@device[:architecture])
|
|
|
|
# download source codes and unpack it
|
|
meta = download
|
|
target_dir = unpack meta
|
|
|
|
# build from source and place binaries at CREW_DEST_DIR
|
|
build_and_preconfigure target_dir
|
|
|
|
# call check method here. this check method is called by this function only,
|
|
# therefore it is possible place time consuming tests in the check method.
|
|
if Dir.exist? target_dir
|
|
Dir.chdir target_dir do
|
|
puts 'Checking...'
|
|
@pkg.check
|
|
end
|
|
end
|
|
|
|
# prepare filelist and dlist at CREW_DEST_DIR
|
|
prepare_package CREW_DEST_DIR
|
|
|
|
# build package from filelist, dlist and binary files in CREW_DEST_DIR
|
|
puts 'Archiving...'
|
|
archive_package pwd
|
|
end
|
|
|
|
def archive_package (pwd)
|
|
pkg_name = "#{@pkg.name}-#{@pkg.version}-chromeos-#{@device[:architecture]}.tar.xz"
|
|
Dir.chdir CREW_DEST_DIR do
|
|
system "tar c#{@verbose}Jf #{pwd}/#{pkg_name} *"
|
|
end
|
|
system "sha256sum #{pwd}/#{pkg_name} > #{pwd}/#{pkg_name}.sha256"
|
|
end
|
|
|
|
def remove (pkgName)
|
|
|
|
#make sure the package is actually installed
|
|
unless @device[:installed_packages].any? { |pkg| pkg[:name] == pkgName }
|
|
puts "Package #{pkgName} isn't installed.".lightred
|
|
return
|
|
end
|
|
|
|
#if the filelist exists, remove the files and directories installed by the package
|
|
if File.file?("#{CREW_META_PATH}#{pkgName}.filelist")
|
|
Dir.chdir CREW_CONFIG_PATH do
|
|
|
|
#remove all files installed by the package
|
|
File.open("meta/#{pkgName}.filelist").each_line do |line|
|
|
begin
|
|
puts 'Removing file ' + line.chomp + ''.lightred if @opt_verbose
|
|
File.unlink line.chomp
|
|
rescue => exception #swallow exception
|
|
end
|
|
end
|
|
|
|
#remove all directories installed by the package
|
|
File.readlines("meta/#{pkgName}.directorylist").reverse.each do |line|
|
|
begin
|
|
puts 'Removing directory ' + line.chomp + ''.lightred if @opt_verbose
|
|
Dir.rmdir line.chomp
|
|
rescue => exception #swallow exception
|
|
end
|
|
end
|
|
|
|
#remove the file and directory list
|
|
File.unlink "meta/#{pkgName}.filelist"
|
|
File.unlink "meta/#{pkgName}.directorylist"
|
|
|
|
end
|
|
end
|
|
|
|
#remove from installed packages
|
|
puts 'Removing package ' + pkgName + "".lightred if @opt_verbose
|
|
@device[:installed_packages].each do |elem|
|
|
@device[:installed_packages].delete elem if elem[:name] == pkgName
|
|
end
|
|
|
|
#update the device manifest
|
|
File.open(CREW_CONFIG_PATH + 'device.json', 'w') do |file|
|
|
out = JSON.parse @device.to_json
|
|
file.write JSON.pretty_generate(out)
|
|
end
|
|
|
|
search pkgName, true
|
|
@pkg.remove
|
|
|
|
puts "#{pkgName.capitalize} removed!".lightgreen
|
|
end
|
|
|
|
def build_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName
|
|
print_current_package @opt_verbose
|
|
@pkg.preflight
|
|
resolve_dependencies_and_build
|
|
end
|
|
end
|
|
|
|
def download_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName
|
|
print_current_package @opt_verbose
|
|
download
|
|
end
|
|
end
|
|
|
|
def const_command (args)
|
|
unless args["<name>"].empty?
|
|
args["<name>"].each do |name|
|
|
const name
|
|
end
|
|
else
|
|
const nil
|
|
end
|
|
end
|
|
|
|
def files_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName
|
|
print_current_package
|
|
files name
|
|
end
|
|
end
|
|
|
|
def help_command (args)
|
|
if args["<command>"]
|
|
help args["<command>"]
|
|
else
|
|
puts "Usage: crew help <command>"
|
|
help nil
|
|
end
|
|
end
|
|
|
|
def install_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName
|
|
print_current_package true
|
|
@pkg.build_from_source = true if @opt_src or @opt_recursive
|
|
@pkg.preflight
|
|
resolve_dependencies_and_install
|
|
end
|
|
end
|
|
|
|
def list_command (args)
|
|
if args['available']
|
|
list_available
|
|
elsif args['installed']
|
|
puts list_installed
|
|
elsif args['compatible']
|
|
list_compatible true
|
|
elsif args['incompatible']
|
|
list_compatible false
|
|
end
|
|
end
|
|
|
|
def postinstall_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName, true
|
|
if @device[:installed_packages].any? do |elem| elem[:name] == @pkgName end
|
|
@pkg.postinstall
|
|
else
|
|
puts "Package #{@pkgName} is not installed. :(".lightred
|
|
end
|
|
end
|
|
end
|
|
|
|
def reinstall_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName
|
|
print_current_package
|
|
@pkg.build_from_source = true if @opt_src or @opt_recursive
|
|
if @pkgName
|
|
@pkg.in_upgrade = true
|
|
@pkg.preflight
|
|
resolve_dependencies_and_install
|
|
@pkg.in_upgrade = false
|
|
end
|
|
end
|
|
end
|
|
|
|
def remove_command (args)
|
|
args["<name>"].each do |name|
|
|
remove name
|
|
end
|
|
end
|
|
|
|
def search_command (args)
|
|
args["<name>"].each do |name|
|
|
regexp_search name
|
|
end.empty? and begin
|
|
list_packages
|
|
end
|
|
end
|
|
|
|
def update_command (args)
|
|
update
|
|
end
|
|
|
|
def upgrade_command (args)
|
|
args["<name>"].each do |name|
|
|
@pkgName = name
|
|
search @pkgName
|
|
print_current_package
|
|
@pkg.build_from_source = true if @opt_src
|
|
upgrade
|
|
end.empty? and begin
|
|
upgrade
|
|
end
|
|
end
|
|
|
|
def whatprovides_command (args)
|
|
args["<name>"].each do |name|
|
|
whatprovides name
|
|
end
|
|
end
|
|
|
|
def is_command (name)
|
|
return false if name =~ /^[-<]/
|
|
return true
|
|
end
|
|
|
|
command_name = args.find { |k, v| v && is_command(k) } [0]
|
|
function = command_name + '_command'
|
|
send(function, args)
|