mirror of
https://github.com/chromebrew/chromebrew.git
synced 2026-01-10 07:57:59 -05:00
354 lines
9.4 KiB
Ruby
Executable File
354 lines
9.4 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
require 'find'
|
|
require 'net/http'
|
|
require 'uri'
|
|
require 'digest/sha1'
|
|
require 'json'
|
|
require 'fileutils'
|
|
|
|
@command = ARGV[0]
|
|
@pkgName = ARGV[1]
|
|
|
|
CREW_PREFIX = '/usr/local'
|
|
CREW_LIB_PATH = CREW_PREFIX + '/lib/crew/'
|
|
CREW_CONFIG_PATH = CREW_PREFIX + '/etc/crew/'
|
|
CREW_BREW_DIR = CREW_PREFIX + '/tmp/crew/'
|
|
CREW_DEST_DIR = CREW_BREW_DIR + '/dest'
|
|
|
|
$LOAD_PATH.unshift "#{CREW_LIB_PATH}lib"
|
|
|
|
USER = `whoami`.chomp
|
|
|
|
@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 setPkg (pkgName, silent = false)
|
|
require CREW_LIB_PATH + 'packages/' + pkgName
|
|
@pkg = Object.const_get(pkgName.capitalize)
|
|
@pkg.name = pkgName
|
|
puts "Found #{pkgName}, version #{@pkg.version}" unless silent
|
|
end
|
|
|
|
def list_packages
|
|
Find.find (CREW_LIB_PATH + 'packages') do |filename|
|
|
Find.find(CREW_CONFIG_PATH + 'meta/') do |packageList|
|
|
packageName = File.basename filename, '.rb'
|
|
print '(i) ' if packageList == CREW_CONFIG_PATH + 'meta/' + packageName + '.filelist'
|
|
end
|
|
puts File.basename filename, '.rb' if File.extname(filename) == '.rb'
|
|
end
|
|
end
|
|
|
|
def search (pkgName, silent = false)
|
|
Find.find (CREW_LIB_PATH + 'packages') do |filename|
|
|
return setPkg(pkgName, silent) if filename == CREW_LIB_PATH + 'packages/' + pkgName + '.rb'
|
|
end
|
|
abort "package #{pkgName} not found :("
|
|
end
|
|
|
|
def update
|
|
abort "'crew update' is used to update crew itself. Use 'crew upgrade <packageName> to upgrade a specific package." if @pkgName
|
|
|
|
#update package lists
|
|
Dir.chdir CREW_LIB_PATH do
|
|
system "git fetch origin master"
|
|
system "git reset --hard origin/master"
|
|
end
|
|
puts "Package lists, crew, and library updated."
|
|
|
|
#check for outdated installed packages
|
|
puts "Checking for package updates..."
|
|
puts ""
|
|
|
|
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 upgrade everything or 'crew upgrade <packageName>' to upgrade a specific package."
|
|
else
|
|
puts "Your software is up to date."
|
|
end
|
|
end
|
|
|
|
def upgrade
|
|
if @pkgName
|
|
search @pkgName
|
|
|
|
currentVersion = nil
|
|
@device[:installed_packages].each do |package|
|
|
if package[:name] == @pkg.name
|
|
currentVersion = package[:version]
|
|
end
|
|
end
|
|
|
|
if currentVersion != @pkg.version
|
|
search @pkg.name
|
|
puts "Updating #{@pkg.name}..."
|
|
remove
|
|
resolveDependenciesAndInstall
|
|
else
|
|
puts "#{@pkg.name} is already up to date."
|
|
end
|
|
else
|
|
toBeUpdated = []
|
|
@device[:installed_packages].each do |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
|
|
remove
|
|
resolveDependenciesAndInstall
|
|
end
|
|
puts "Packages have been updated."
|
|
else
|
|
puts "Your software is already up to date."
|
|
end
|
|
end
|
|
end
|
|
|
|
def download
|
|
if @pkg.binary_url && @pkg.binary_url.has_key?(@device[:architecture])
|
|
url = @pkg.binary_url[@device[:architecture]]
|
|
source = false
|
|
puts "Precompiled binary available, downloading..."
|
|
else
|
|
url = @pkg.source_url
|
|
source = true
|
|
puts "No precompiled binary available for your platform, downloading source..."
|
|
end
|
|
uri = URI.parse url
|
|
filename = File.basename(uri.path)
|
|
if source
|
|
sha1sum = @pkg.source_sha1
|
|
else
|
|
sha1sum = @pkg.binary_sha1[@device[:architecture]]
|
|
end
|
|
Dir.chdir CREW_BREW_DIR do
|
|
system('wget', '--continue', '--content-disposition', '--no-check-certificate', '-N', url, '-O', filename)
|
|
abort 'Checksum mismatch :/ try again' unless Digest::SHA1.hexdigest( File.read("./#{filename}") ) == sha1sum
|
|
end
|
|
puts "Archive downloaded"
|
|
return {source: source, filename: filename}
|
|
end
|
|
|
|
def resolveDependenciesAndInstall
|
|
origin = @pkg.name
|
|
|
|
resolveDependencies
|
|
|
|
search origin
|
|
install
|
|
|
|
#cleanup
|
|
unless ARGV[2] == 'keep'
|
|
Dir.chdir CREW_BREW_DIR do
|
|
system "rm -rf *"
|
|
system "mkdir dest" #this is a little ugly, feel free to find a better way
|
|
end
|
|
end
|
|
end
|
|
|
|
def resolveDependencies
|
|
@dependencies = []
|
|
|
|
def pushDeps
|
|
if @pkg.dependencies
|
|
@dependencies.unshift @pkg.dependencies
|
|
|
|
@pkg.dependencies.each do |dep|
|
|
search dep, true
|
|
pushDeps
|
|
end
|
|
end
|
|
end
|
|
|
|
pushDeps
|
|
|
|
return if @dependencies.empty?
|
|
|
|
puts "Following packages also need to be installed: "
|
|
@dependencies.flatten!.each do |dep|
|
|
print dep + " "
|
|
end
|
|
puts ""
|
|
puts "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}' :("
|
|
abort "No changes made."
|
|
end
|
|
|
|
if proceed
|
|
@dependencies.each do |dep|
|
|
search dep
|
|
install
|
|
end
|
|
end
|
|
end
|
|
|
|
def install
|
|
if @device[:installed_packages].any? { |pkg| pkg[:name] == @pkg.name }
|
|
puts "Package #{@pkg.name} already installed, skipping..."
|
|
return
|
|
end
|
|
|
|
unless @pkg.is_fake?
|
|
meta = download
|
|
Dir.chdir CREW_BREW_DIR do
|
|
puts "Unpacking archive, this may take a while..."
|
|
system "tar", "xf", meta[:filename]
|
|
if meta[:source] == true
|
|
abort "You don't have a working C compiler. Run 'crew install buildessential' to get one and try again." unless system("gcc", "--version")
|
|
topdir = `tar -tf #{meta[:filename]} | sed -e 's@/.*@@' | uniq`.chomp!
|
|
Dir.chdir CREW_BREW_DIR + topdir do
|
|
puts "Building from source, this may take a while..."
|
|
@pkg.build
|
|
system "rm -rf", CREW_DEST_DIR + "/*" #wipe crew destdir
|
|
puts "Preconfiguring package..."
|
|
@pkg.install
|
|
end
|
|
|
|
Dir.chdir CREW_DEST_DIR do
|
|
#create directory list
|
|
system "find . -type f > ../filelist"
|
|
system "find . -type l >> ../filelist"
|
|
system "cut -c2- ../filelist > filelist"
|
|
#create file list
|
|
system "find . -type d > ../dlist"
|
|
system "cut -c2- ../dlist > dlistcut"
|
|
system "tail -n +2 dlistcut > dlist"
|
|
#remove temporary files
|
|
system "rm dlistcut ../dlist ../filelist"
|
|
|
|
#create resulting folders list
|
|
directories = []
|
|
Dir.glob('*').select do |fn|
|
|
if File.directory?(fn)
|
|
directories.push(fn)
|
|
end
|
|
end
|
|
|
|
#wipe directories with the same name in brew dir to avoid conflicts
|
|
directories.each do |dir|
|
|
system "rm -rf ../" + dir.chomp
|
|
end
|
|
|
|
#move result files and directories to brew dir
|
|
system "mv * ../"
|
|
end
|
|
end
|
|
|
|
puts "Installing..."
|
|
|
|
FileUtils.mv 'dlist', CREW_CONFIG_PATH + "meta/#{@pkg.name}.directorylist"
|
|
FileUtils.mv 'filelist', CREW_CONFIG_PATH + "meta/#{@pkg.name}.filelist"
|
|
|
|
File.open(CREW_CONFIG_PATH + "meta/#{@pkg.name}.directorylist").each_line do |line|
|
|
system "sudo", "mkdir", "-p", line.chomp
|
|
end
|
|
|
|
File.open(CREW_CONFIG_PATH + "meta/#{@pkg.name}.filelist").each_line do |line|
|
|
system "sudo", "mv", CREW_BREW_DIR + line.chomp, line.chomp
|
|
end
|
|
end
|
|
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
|
|
puts "#{@pkg.name.capitalize} installed!"
|
|
end
|
|
|
|
def remove
|
|
unless @device[:installed_packages].any? { |pkg| pkg[:name] == @pkg.name }
|
|
puts "Package #{@pkg.name} isn't installed."
|
|
return
|
|
end
|
|
|
|
unless @pkg.is_fake?
|
|
Dir.chdir CREW_CONFIG_PATH do
|
|
File.open("meta/#{@pkg.name}.filelist").each_line do |line|
|
|
begin
|
|
File.unlink line.chomp
|
|
rescue => exception #swallow exception
|
|
end
|
|
end
|
|
|
|
File.readlines("meta/#{@pkg.name}.directorylist").reverse.each do |line|
|
|
begin
|
|
Dir.rmdir line.chomp
|
|
rescue => exception #swallow exception
|
|
end
|
|
end
|
|
|
|
File.unlink "meta/#{@pkg.name}.filelist"
|
|
File.unlink "meta/#{@pkg.name}.directorylist"
|
|
end
|
|
end
|
|
|
|
#remove from installed packages
|
|
@device[:installed_packages].each do |elem|
|
|
@device[:installed_packages].delete elem if elem[:name] == @pkg.name
|
|
end
|
|
File.open(CREW_CONFIG_PATH + 'device.json', 'w') do |file|
|
|
out = JSON.parse @device.to_json
|
|
file.write JSON.pretty_generate(out)
|
|
end
|
|
puts "#{@pkg.name.capitalize} removed!"
|
|
end
|
|
|
|
case @command
|
|
when "search"
|
|
if @pkgName
|
|
search @pkgName
|
|
else
|
|
list_packages
|
|
end
|
|
when "download"
|
|
search @pkgName
|
|
download
|
|
when "update"
|
|
update
|
|
when "upgrade"
|
|
upgrade
|
|
when "install"
|
|
search @pkgName
|
|
resolveDependenciesAndInstall
|
|
when "remove"
|
|
abort 'Removing actions must be ran with sudo.' unless USER == 'root'
|
|
search @pkgName
|
|
remove
|
|
when nil
|
|
puts "Chromebrew, version 0.2.1"
|
|
puts "Usage: crew [command] [package]"
|
|
puts "Available commands: search, download, install, remove"
|
|
else
|
|
puts "I have no idea how to do #{@command} :("
|
|
puts "Available commands: search, download, install, remove"
|
|
end
|