linux-update: removed. ruby-version should be more stable than shell-version. linux-update.rb renamed to linux-update.

master
Denis Knauf 2013-04-20 21:42:58 +02:00
parent de8785d5ba
commit 777cfce5a3
2 changed files with 466 additions and 647 deletions

View File

@ -1,181 +1,497 @@
#!/bin/sh
#!/usr/bin/env ruby
[ 0 = "`id -u`" ] || exec sudo http_proxy="$http_proxy" "$0" "$@"
require 'shellwords'
require 'getoptlong'
require 'json'
require 'pathname'
require 'shell'
require 'uri'
SOURCE_BASE_DIR=/usr/src
SOURCE_BASE_URI=http://www.kernel.org/pub/linux/kernel/v3.x/
class RequiredGems
attr_reader :requires, :failed
def self.require &block
rg = new
block.call rg, &rg.method(:push)
rg.require
end
usage() {
echo "Usage: $0 $(help | sed -ne '3,$s/^\([^'"`printf '\t'`"']*\)'"`printf '\t'`"'.*$/\1/p' | tr '\n' '|' | sed -e 's/|/ | /g;s/ | $//')"
}
def initialize
@requires, @failed = [], []
end
help() { #@ Print this help message
cat <<EOH
$0 Command
possible commands:
EOH
}
def push lib, gem = nil, name = nil
gem ||= lib
name ||= gem
@requires.push [lib, gem, name]
end
cache() {
eval "$1() { echo '$(echo "$2" | sed -e 's/'\''/'"'\\\''"'/g')'; }"
$1
}
def try_require lib
require lib
true
rescue LoadError
false
end
_latest_stable() {
curl -s http://www.kernel.org/kdist/finger_banner | sed -E -ne 's/^The latest stable .* version of the Linux kernel is: *([0-9.]*).*/\1/p' | head -1
}
def require lib = nil
return super lib if lib # if lib given, require it.
latest_stable() { #@ prints the latest stable available version on kernel.org
cache latest_stable "`_latest_stable`"
}
@failed = @requires.reject {|(lib, _, _)| try_require lib }
return if @failed.empty?
STDERR.puts <<EOF
Loading of #{@failed.map{|(_,_,n)|n}.join ', '} failed.
Please install if first:
sudo gem install #{@failed.map{|(_,g,_)|g}.join ' '}
EOF
exit 127
end
end
print_version() {
while read v d
do
echo "$v"
done
}
def requires_lib_gem &block
requires = []
push = lambda {|lib, gem = lib, name = gem| requires.push [lib, gem, name] }
block.call &push
failed = requires.reject do |(lib, _, _)|
begin
require lib
true
rescue LoadError
false
end
end
return if failed.empty?
STDERR.puts <<EOF
Loading of #{failed.map{|(_,_,n)|n}.join ', '} failed.
Please install if first:
sudo gem install #{failed.map{|(_,g,_)|g}.join ' '}
EOF
exit 127
end
print_dir() {
while read v d
do
echo "$d"
done
}
requires_lib_gem do |&push|
push[ 'thor', nil, 'Thor']
push[ 'irb-pager', nil, 'IRB::Pager']
push[ 'active_support/all', 'activesupport', 'ActiveSupport']
push[ 'excon', nil, 'Excon']
push[ 'versionomy', nil, 'Versionomy']
end
kernelversion_of() {
make -isC "$1" kernelversion
}
dir_of() {
w="${1}"
fetched | while read v d
do
[ "$w" = "$v" ] && echo "$d"
done
}
module LinuxUpdate
Release = Struct.new :version, :moniker, :source, :pgp, :released, :gitweb, :changelog, :patch_full, :patch_incremental, :iseol
class Release
include Comparable
def self.parse json
return nil if json['version'] =~ /^next-/
data = members.map {|m| json[m.to_s] }
data[0] = Versionomy.parse data[0]
data[2] = URI.parse data[2] rescue
data[3] = URI.parse data[3] rescue
data[4] = Time.at data[4]['timestamp'].to_i
new *data
end
fetched() { #@ prints all fetched versions
for d in "${SOURCE_BASE_DIR}"/linux-*
do
v="`kernelversion_of "$d"`"
if [ "$v" ]
then
echo "$v $d"
fi
done
}
def stable?() 'stable' == moniker end
def mainline?() 'mainline' == moniker end
def longterm?() 'longterm' == moniker end
def linux_next?() 'linux-next' == moniker end
alias eol? iseol
alias end_of_life? iseol
latest_version() {
sort -rV | head -1
}
def <=>( other) version <=> other.version end
latest_fetched() { #@ prints the latest fetched version
fetched | latest_version
}
def to_s
r = "linux-#{version} (#{moniker})"
r += " (EOL)" if end_of_life?
r
end
end
is_listed() {
awk \""${1}"'"==$1{print$0;exit}'
}
class Fetched
attr_reader :dir
def initialize dir
@dir = Pathname.new dir
end
latest_stable_is_fetched() {
fetched | is_listed "`latest_stable`"
}
def make *opts, &block
block ||= lambda {|rd| IO::copy_stream rd, STDOUT }
dir = @dir.to_s
rd, wr = IO.pipe
pid = fork do
STDOUT.reopen wr
rd.close
exec 'make', '-C', dir, *opts
end
wr.close
wr = nil
reader = Thread.new { block.call rd }
Process.waitpid pid
raise Base::MakeFailed, "make #{opts.join ' '}" unless 0 == $?.exitstatus
reader.value
ensure
rd.close if rd
wr.close if wr
end
update_available() { #@ prints the latest stable available version on kernel.org if it isn't fetched yet
[ -z "`latest_stable_is_fetched`" ]
}
def version
@version ||= make '-is', 'kernelversion' do |rd|
Versionomy.parse rd.readlines.join.chomp
end
end
download_uri() { #@ [V] prints the uri of V (default: latest_stable)
echo "${SOURCE_BASE_URI}/linux-${1:-`latest_stable`}.tar.xz"
}
def config
dir + '.config'
end
download() { #@ [V] downloads the kernel of V (default: latest_stable)
echo "Download $1" >&2
curl `download_uri "${1}"`
}
def configured?
return @configured if @configured
@configured = config.exist?
end
unpack() { #@ simple unpack with unxz and tar in \$SOURCE_BASE_DIR (default: $SOURCE_BASE_DIR)
unxz | tar -C "${SOURCE_BASE_DIR}" -xf -
}
def <=>( other) version <=> other.version end
fetch() { #@ [V] downloads and unpack the kernel of V (default: latest_stable)
download "${1}" | unpack
}
def to_s
r = "#{dir}"
r += " #{version}" if @version
r += " #{configured? ? :configured : 'not configured'}" if nil != @configured
r
end
update() { #@ downloads and unpack the latest_stable kernel if it isn't fetched yet
if update_available
then
echo Update available: `latest_stable`
fetch
else
echo "Upto date."
return 1
fi
}
def open_config opts = nil, &block
opts ||= 'r'
if block_given?
File.open config, opts, &block
else
File.open config, opts
end
end
configs() {
fetched | while read v d
do
[ -e "$d/.config" ] && echo "$v $d"
done
}
def import_config_from_io( io) open_config('w') {|c| io.each_line {|l| c.print l } } end
has_config() { #@ [V] This kernel has a config?
configs | is_listed "$2"
}
def import_config file_or_io_or_fetched
info "Import config #{file_or_io_or_fetched}"
case file_or_io_or_fetched
when IO then import_config_from_io file_or_io_or_fetched
when Fetched
file_or_io_or_fetched.open_config &method(:import_config_from_io)
else
File.open file_or_io_or_fetched.to_s, &method(:import_config_from_io)
end
end
latest_config() { #@ Which is the latest kernel with config?
configs | latest_version
}
def oldconfig
info 'make oldconfig'
make 'oldconfig'
end
copy_to_dir_config() {
cp "${2:-`latest_config | print_dir`}/.config" "${1:-`latest_fetched | print_dir`}"
}
def menuconfig
info 'make menuconfig'
make 'menuconfig'
end
install_config() { #@ [V] Copys the config of the newest kernel with config to V.
d="${1:-`latest_fetched | print_dir`}"
s="${2:-`latest_config | print_dir`}"
[ -e "$d/.config" ] || copy_to_dir_config "${d}" "${s}"
}
def compile
info 'make all'
make 'all'
end
oldconfig() { #@ [V] Run oldconfig (calls install_config previeusly).
d="${1:-`latest_fetched | print_dir`}"
install_config "$d" && make -C "$d" oldconfig
}
def install
info 'make modules_install install'
make 'modules_install', 'install'
end
install_all() {
echo "=====-- $1 --====="
d="${1:-`latest_fetched | print_dir`}"
echo "===== $d ====="
oldconfig "$d" && \
make -j3 -C "$d" all && \
make -j3 -C "$d" modules_install && \
make -j3 -C "$d" install
}
def info text
STDERR.puts "[#{version}] #{text}"
end
end
cmd="$1"
shift
class Base
class Error <Exception
end
class InvalidVersionType <Error
end
class MakeFailed <Error
end
class DownloadFailed <Error
def initialize uri
super "Download of #{uri} failed."
end
end
class UnpackFailed <Error
def initialize tarball
super "Unpack of #{tarball} failed."
end
end
attr_reader :releases_uri, :sources_base_dir, :cache_dir
ReleasesURI = 'https://www.kernel.org/releases.json'
SourcesBaseDir = '/usr/src/linux'
CacheDir = '/var/cache/linux-update'
case "$cmd" in
latest_stable) latest_stable ;;
fetched) fetched ;;
latest_fetched) latest_fetched ;;
update_available) update_available ;;
fetch) fetch "$@" ;;
download_uri) download_uri "$@" ;;
download) download "$@" ;;
unpack) unpack ;;
update) update ;;
help|--help|-h) help ;;
usage) usage ;;
latest_stable_is_fetched) latest_stable_is_fetched ;;
oldconfig) oldconfig "${1:+`dir_of "$1"`}" ;;
configs) configs "${1:+`dir_of "$1"`}" ;;
install) install_all "${1:+`dir_of "$1"`}" ;;
all) update "$1" && install_all "${1:+`dir_of "$1"`}" ;;
*)
usage >&2
exit 1
;;
esac
def releases_uri=( uri) @releases_uri = URI.parse uri.to_s end
def sources_base_dir=( dir) @sources_base_dir = Pathname.new dir.to_s end
def cache_dir=( dir) @cache_dir = Pathname.new dir.to_s end
def initialize
self.releases_uri = ENV['LINUX_RELEASE_URI'] || ReleasesURI
self.sources_base_dir = ENV['LINUX_SOURCES_BASE_DIR'] || SourcesBaseDir
self.cache_dir = ENV['CacheDir'] || CacheDir
end
def info text
STDERR.puts text
end
def releases
return @releases if @releases
res = Excon.get @releases_uri.to_s, expects: 200
json = JSON.parse res.body
@releases = json['releases'].map {|r| Release.parse r }.compact
end
def releases_moniker moniker = nil
moniker ? releases.select {|r| moniker == r.moniker } : releases
end
def fetched
@fetched ||= Dir[ @sources_base_dir + 'linux-*'].
map( &Pathname.method( :new)).
select( &:directory?).
map {|d| Fetched.new d }
end
def configured() fetched.select &:configured? end
def unconfigured() fetched.reject &:configured? end
def find_fetched_version version
case version
when Fetched then version
when Versionomy::Value then fetched.find {|f| version == f.version }
when Release then find_fetched_version version.version
when String then find_fetched_version Versionomy.parse( version)
when nil, false then fetched.max
else raise InvalidVersionType, "I know Fetched, Versionomy, Release and String, but what is #{version.class}?"
end
end
def exist? file
Pathname.new( file.to_s).exist?
end
def format_bytes bytes
case bytes
when 0...1.kilobyte then "%6dB" % bytes
when 0...1.megabyte then "%4dKiB" % (bytes / 1.kilobyte)
when 0...1.gigabyte then "%4dMiB" % (bytes / 1.megabyte)
when 0...1.terabyte then "%4dGiB" % (bytes / 1.gigabyte)
when 0...1.petabyte then "%4dTiB" % (bytes / 1.terabyte)
else "%4dEiB" % (bytes / 1.petabyte)
end
end
def _download uri, file
dest = Pathname.new "#{file}.download"
info "Download #{uri} => #{file}"
if true
raise DownloadFailed, uri unless Kernel.system( 'wget', '-c', '-O', dest.to_s, uri.to_s)
else
done = dest.size
p dest => done
dest.open 'a+' do |fd|
streamer = lambda do |chunk, remaining, total|
fd.write chunk
count = total - remaining
STDERR.print "\rloading %s/%s % 3d%%\e[J" % [
format_bytes(count), format_bytes(total), 100.0*count/total ]
end
res = Excon.get uri.to_s,
response_block: streamer,
expects: 200,
headers: {'Range' => "#{done}-" }
end
end
dest.rename file
end
def _unpack tarball, destdir
info "Unpack #{tarball} => #{destdir}"
unless Kernel.system 'tar', '-C', destdir.to_s, '-xf', tarball.to_s
raise UnpackFailed, tarball
end
end
# returns tarballs-filename (e.g. linux-3.1.0.tar.xz)
# unpack-path will be @sources_base_dir, but sources dir is unknown.
def download release_or_uri
uri =
case release_or_uri
when Release then release_or_uri.source
when URI, String then URI.parse release_or_uri.to_s
else raise UnexpectedThingToDownload, "This is no URI, String or Release"
end
# We do not understand anything else than operating systems with / as separator
@cache_dir.mkdir 0755 unless @cache_dir.exist?
tarball = @cache_dir + File.basename( uri.path)
_download uri, tarball unless tarball.exist?
_unpack tarball, @sources_base_dir
tarball.basename
end
def oldconfig_prepare version = nil, config = nil
version = find_fetched_version version
config =
case config
when lambda {|x| Pathname.new( config.to_s).exist? } then config
when nil, false then configured.max.config
else find_fetched_version( config).config
end
[version, config]
end
end
class Cmd < Thor
class Error < Exception
end
class NoAvailableRelease < Error
end
class InvalidVersionType < Error
end
option :latest, type: :boolean, aliases: '-l', desc: 'Only the most actual linux kernel.'
option :moniker, type: :string, aliases: '-m', desc: 'stable, mainline, longterm (default: no moniker)'
desc 'releases [MONIKER]', 'Prints known linux-kernel releases'
def releases moniker = nil
listing base.releases_moniker( moniker || options[:moniker])
end
option :latest, type: :boolean, aliases: '-l', desc: 'Only the most actual linux kernel.'
desc 'fetched', 'Prints all fetched linux-kernel'
def fetched
listing base.fetched
end
option :print, type: :boolean, aliases: '-p', desc: 'Only print the URI. No fetch.'
option :any, type: :boolean, aliases: '-a', desc: 'Select any versions.'
option :longterm, type: :boolean, aliases: '-o', desc: 'Select long term versions.'
option :stable, type: :boolean, aliases: '-s', desc: 'Select stable versions (default).'
option :mainline, type: :boolean, aliases: '-m', desc: 'Select mainline versions.'
desc 'fetch [VERSION]', 'Download linux-kernel'
def fetch version = nil
rs = nil
if version
version = Versionomy.parse version
rs = base.releases.select! {|r| version == r.version }
else
moniker = :stable
moniker = :mainline if options[:mainline]
moniker = nil if options[:any]
rs = base.releases_moniker moniker.to_s
end
release = rs.max
raise NoAvailableRelease, "There is no available release which matchs your wishes." unless release
if options[:print]
puts release.source
return
end
base.download release
end
desc 'importconfig [VERSION] [CONFIG]', 'Imports an other config from file or an other source directory. (default: most actual version with config to most actual version).'
def importconfig version = nil, config = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if config
end
option :config, type: :string, aliases: '-c', default: false,
desc: 'Which pre existing config should be used? Can be an other linux-VERSION with an old config or a config-file. --no-config will prevent copying a config.'
desc 'oldconfig [VERSION]', 'Configure linux-VERSION (default: most actual version).'
long_desc <<-ELD
First it will copy an older config to your sources-directory, if needed and not --no-config.
If you use `--config CONFIG`, the existing config will be replaced by CONFIG!
Second make oldconfig will called.
ELD
def oldconfig version = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if nil != options['config'] and config and not version.config.exist?
version.oldconfig
end
option :config, type: :string, aliases: '-c', default: false,
desc: 'Which pre existing config should be used? Can be an other linux-VERSION with an old config or a config-file. --no-config will prevent copying a config.'
desc 'oldconfig [VERSION]', 'Configure linux-VERSION (default: most actual version).'
long_desc <<-ELD
First it will copy an older config to your sources-directory, if needed and not --no-config.
If you use `--config CONFIG`, the existing config will be replaced by CONFIG!
Second make oldconfig will called.
ELD
desc 'menuconfig|configure [VERSION]', 'Configure your linux-VERSION. (default: most actual version).'
def menuconfig version = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if nil != options['config'] and config and not version.config.exist?
version.menuconfig
end
map configure: :menuconfig
desc 'compile [VERSION]', 'Will compile kernel and modules.'
def compile version = nil
version = base.find_fetched_version version
version.compile
end
desc 'install [VERSION]', 'Will install kernel and modules. It will trigger updating third-party-modules.'
def install version = nil
version = base.find_fetched_version version
version.install
end
desc 'all [VERSION]', 'Will oldconfig, compile and install kernel and modules. See these methods.'
def all version = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if nil != options['config'] and config and not version.config.exist?
version.oldconfig
version.compile
version.install
end
option :any, type: :boolean, aliases: '-a', desc: 'Select any versions.'
option :longterm, type: :boolean, aliases: '-o', desc: 'Select long term versions.'
option :stable, type: :boolean, aliases: '-s', desc: 'Select stable versions (default).'
option :mainline, type: :boolean, aliases: '-m', desc: 'Select mainline versions.'
desc 'update [VERSION]', 'Download, compile and install linux-kernel'
def update version = nil
tarball = fetch version
/^linux-(.*)\.tar\./ =~ tarball.basename.to_s
# try it with version in tarball's name:
all $1
end
no_commands do
def base
@base ||= Base.new
end
def listing list
list.each do |e|
e.configured? if e.is_a? Fetched
end
if options[:latest]
puts list.max
else
puts list.sort {|a,b|b<=>a}
end
end
end
end
end
begin # if __FILE__ == $0
$debug = true if $DEBUG
LinuxUpdate::Cmd.start ARGV
rescue LinuxUpdate::Cmd::Error, LinuxUpdate::Base::Error
STDERR.puts "Error: #{$!}"
STDERR.puts $!.backtrace.map {|c| "\t#{c}" } if $debug
raise
#exit 1
rescue Object
STDERR.puts "Unknown and unexpected Error: #{$!} (#{$!.class})"
STDERR.puts $!.backtrace.map {|c| "\t#{c}" } if $debug
raise
#exit 2
end if __FILE__ == $0

View File

@ -1,497 +0,0 @@
#!/usr/bin/env ruby
require 'shellwords'
require 'getoptlong'
require 'json'
require 'pathname'
require 'shell'
require 'uri'
class RequiredGems
attr_reader :requires, :failed
def self.require &block
rg = new
block.call rg, &rg.method(:push)
rg.require
end
def initialize
@requires, @failed = [], []
end
def push lib, gem = nil, name = nil
gem ||= lib
name ||= gem
@requires.push [lib, gem, name]
end
def try_require lib
require lib
true
rescue LoadError
false
end
def require lib = nil
return super lib if lib # if lib given, require it.
@failed = @requires.reject {|(lib, _, _)| try_require lib }
return if @failed.empty?
STDERR.puts <<EOF
Loading of #{@failed.map{|(_,_,n)|n}.join ', '} failed.
Please install if first:
sudo gem install #{@failed.map{|(_,g,_)|g}.join ' '}
EOF
exit 127
end
end
def requires_lib_gem &block
requires = []
push = lambda {|lib, gem = lib, name = gem| requires.push [lib, gem, name] }
block.call &push
failed = requires.reject do |(lib, _, _)|
begin
require lib
true
rescue LoadError
false
end
end
return if failed.empty?
STDERR.puts <<EOF
Loading of #{failed.map{|(_,_,n)|n}.join ', '} failed.
Please install if first:
sudo gem install #{failed.map{|(_,g,_)|g}.join ' '}
EOF
exit 127
end
requires_lib_gem do |&push|
push[ 'thor', nil, 'Thor']
push[ 'irb-pager', nil, 'IRB::Pager']
push[ 'active_support/all', 'activesupport', 'ActiveSupport']
push[ 'excon', nil, 'Excon']
push[ 'versionomy', nil, 'Versionomy']
end
module LinuxUpdate
Release = Struct.new :version, :moniker, :source, :pgp, :released, :gitweb, :changelog, :patch_full, :patch_incremental, :iseol
class Release
include Comparable
def self.parse json
return nil if json['version'] =~ /^next-/
data = members.map {|m| json[m.to_s] }
data[0] = Versionomy.parse data[0]
data[2] = URI.parse data[2] rescue
data[3] = URI.parse data[3] rescue
data[4] = Time.at data[4]['timestamp'].to_i
new *data
end
def stable?() 'stable' == moniker end
def mainline?() 'mainline' == moniker end
def longterm?() 'longterm' == moniker end
def linux_next?() 'linux-next' == moniker end
alias eol? iseol
alias end_of_life? iseol
def <=>( other) version <=> other.version end
def to_s
r = "linux-#{version} (#{moniker})"
r += " (EOL)" if end_of_life?
r
end
end
class Fetched
attr_reader :dir
def initialize dir
@dir = Pathname.new dir
end
def make *opts, &block
block ||= lambda {|rd| IO::copy_stream rd, STDOUT }
dir = @dir.to_s
rd, wr = IO.pipe
pid = fork do
STDOUT.reopen wr
rd.close
exec 'make', '-C', dir, *opts
end
wr.close
wr = nil
reader = Thread.new { block.call rd }
Process.waitpid pid
raise Base::MakeFailed, "make #{opts.join ' '}" unless 0 == $?.exitstatus
reader.value
ensure
rd.close if rd
wr.close if wr
end
def version
@version ||= make '-is', 'kernelversion' do |rd|
Versionomy.parse rd.readlines.join.chomp
end
end
def config
dir + '.config'
end
def configured?
return @configured if @configured
@configured = config.exist?
end
def <=>( other) version <=> other.version end
def to_s
r = "#{dir}"
r += " #{version}" if @version
r += " #{configured? ? :configured : 'not configured'}" if nil != @configured
r
end
def open_config opts = nil, &block
opts ||= 'r'
if block_given?
File.open config, opts, &block
else
File.open config, opts
end
end
def import_config_from_io( io) open_config('w') {|c| io.each_line {|l| c.print l } } end
def import_config file_or_io_or_fetched
info "Import config #{file_or_io_or_fetched}"
case file_or_io_or_fetched
when IO then import_config_from_io file_or_io_or_fetched
when Fetched
file_or_io_or_fetched.open_config &method(:import_config_from_io)
else
File.open file_or_io_or_fetched.to_s, &method(:import_config_from_io)
end
end
def oldconfig
info 'make oldconfig'
make 'oldconfig'
end
def menuconfig
info 'make menuconfig'
make 'menuconfig'
end
def compile
info 'make all'
make 'all'
end
def install
info 'make modules_install install'
make 'modules_install', 'install'
end
def info text
STDERR.puts "[#{version}] #{text}"
end
end
class Base
class Error <Exception
end
class InvalidVersionType <Error
end
class MakeFailed <Error
end
class DownloadFailed <Error
def initialize uri
super "Download of #{uri} failed."
end
end
class UnpackFailed <Error
def initialize tarball
super "Unpack of #{tarball} failed."
end
end
attr_reader :releases_uri, :sources_base_dir, :cache_dir
ReleasesURI = 'https://www.kernel.org/releases.json'
SourcesBaseDir = '/usr/src/linux'
CacheDir = '/var/cache/linux-update'
def releases_uri=( uri) @releases_uri = URI.parse uri.to_s end
def sources_base_dir=( dir) @sources_base_dir = Pathname.new dir.to_s end
def cache_dir=( dir) @cache_dir = Pathname.new dir.to_s end
def initialize
self.releases_uri = ENV['LINUX_RELEASE_URI'] || ReleasesURI
self.sources_base_dir = ENV['LINUX_SOURCES_BASE_DIR'] || SourcesBaseDir
self.cache_dir = ENV['CacheDir'] || CacheDir
end
def info text
STDERR.puts text
end
def releases
return @releases if @releases
res = Excon.get @releases_uri.to_s, expects: 200
json = JSON.parse res.body
@releases = json['releases'].map {|r| Release.parse r }.compact
end
def releases_moniker moniker = nil
moniker ? releases.select {|r| moniker == r.moniker } : releases
end
def fetched
@fetched ||= Dir[ @sources_base_dir + 'linux-*'].
map( &Pathname.method( :new)).
select( &:directory?).
map {|d| Fetched.new d }
end
def configured() fetched.select &:configured? end
def unconfigured() fetched.reject &:configured? end
def find_fetched_version version
case version
when Fetched then version
when Versionomy::Value then fetched.find {|f| version == f.version }
when Release then find_fetched_version version.version
when String then find_fetched_version Versionomy.parse( version)
when nil, false then fetched.max
else raise InvalidVersionType, "I know Fetched, Versionomy, Release and String, but what is #{version.class}?"
end
end
def exist? file
Pathname.new( file.to_s).exist?
end
def format_bytes bytes
case bytes
when 0...1.kilobyte then "%6dB" % bytes
when 0...1.megabyte then "%4dKiB" % (bytes / 1.kilobyte)
when 0...1.gigabyte then "%4dMiB" % (bytes / 1.megabyte)
when 0...1.terabyte then "%4dGiB" % (bytes / 1.gigabyte)
when 0...1.petabyte then "%4dTiB" % (bytes / 1.terabyte)
else "%4dEiB" % (bytes / 1.petabyte)
end
end
def _download uri, file
dest = Pathname.new "#{file}.download"
info "Download #{uri} => #{file}"
if true
raise DownloadFailed, uri unless Kernel.system( 'wget', '-c', '-O', dest.to_s, uri.to_s)
else
done = dest.size
p dest => done
dest.open 'a+' do |fd|
streamer = lambda do |chunk, remaining, total|
fd.write chunk
count = total - remaining
STDERR.print "\rloading %s/%s % 3d%%\e[J" % [
format_bytes(count), format_bytes(total), 100.0*count/total ]
end
res = Excon.get uri.to_s,
response_block: streamer,
expects: 200,
headers: {'Range' => "#{done}-" }
end
end
dest.rename file
end
def _unpack tarball, destdir
info "Unpack #{tarball} => #{destdir}"
unless Kernel.system 'tar', '-C', destdir.to_s, '-xf', tarball.to_s
raise UnpackFailed, tarball
end
end
# returns tarballs-filename (e.g. linux-3.1.0.tar.xz)
# unpack-path will be @sources_base_dir, but sources dir is unknown.
def download release_or_uri
uri =
case release_or_uri
when Release then release_or_uri.source
when URI, String then URI.parse release_or_uri.to_s
else raise UnexpectedThingToDownload, "This is no URI, String or Release"
end
# We do not understand anything else than operating systems with / as separator
@cache_dir.mkdir 0755 unless @cache_dir.exist?
tarball = @cache_dir + File.basename( uri.path)
_download uri, tarball unless tarball.exist?
_unpack tarball, @sources_base_dir
tarball.basename
end
def oldconfig_prepare version = nil, config = nil
version = find_fetched_version version
config =
case config
when lambda {|x| Pathname.new( config.to_s).exist? } then config
when nil, false then configured.max.config
else find_fetched_version( config).config
end
[version, config]
end
end
class Cmd < Thor
class Error < Exception
end
class NoAvailableRelease < Error
end
class InvalidVersionType < Error
end
option :latest, type: :boolean, aliases: '-l', desc: 'Only the most actual linux kernel.'
option :moniker, type: :string, aliases: '-m', desc: 'stable, mainline, longterm (default: no moniker)'
desc 'releases [MONIKER]', 'Prints known linux-kernel releases'
def releases moniker = nil
listing base.releases_moniker( moniker || options[:moniker])
end
option :latest, type: :boolean, aliases: '-l', desc: 'Only the most actual linux kernel.'
desc 'fetched', 'Prints all fetched linux-kernel'
def fetched
listing base.fetched
end
option :print, type: :boolean, aliases: '-p', desc: 'Only print the URI. No fetch.'
option :any, type: :boolean, aliases: '-a', desc: 'Select any versions.'
option :longterm, type: :boolean, aliases: '-o', desc: 'Select long term versions.'
option :stable, type: :boolean, aliases: '-s', desc: 'Select stable versions (default).'
option :mainline, type: :boolean, aliases: '-m', desc: 'Select mainline versions.'
desc 'fetch [VERSION]', 'Download linux-kernel'
def fetch version = nil
rs = nil
if version
version = Versionomy.parse version
rs = base.releases.select! {|r| version == r.version }
else
moniker = :stable
moniker = :mainline if options[:mainline]
moniker = nil if options[:any]
rs = base.releases_moniker moniker.to_s
end
release = rs.max
raise NoAvailableRelease, "There is no available release which matchs your wishes." unless release
if options[:print]
puts release.source
return
end
base.download release
end
desc 'importconfig [VERSION] [CONFIG]', 'Imports an other config from file or an other source directory. (default: most actual version with config to most actual version).'
def importconfig version = nil, config = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if config
end
option :config, type: :string, aliases: '-c', default: false,
desc: 'Which pre existing config should be used? Can be an other linux-VERSION with an old config or a config-file. --no-config will prevent copying a config.'
desc 'oldconfig [VERSION]', 'Configure linux-VERSION (default: most actual version).'
long_desc <<-ELD
First it will copy an older config to your sources-directory, if needed and not --no-config.
If you use `--config CONFIG`, the existing config will be replaced by CONFIG!
Second make oldconfig will called.
ELD
def oldconfig version = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if nil != options['config'] and config and not version.config.exist?
version.oldconfig
end
option :config, type: :string, aliases: '-c', default: false,
desc: 'Which pre existing config should be used? Can be an other linux-VERSION with an old config or a config-file. --no-config will prevent copying a config.'
desc 'oldconfig [VERSION]', 'Configure linux-VERSION (default: most actual version).'
long_desc <<-ELD
First it will copy an older config to your sources-directory, if needed and not --no-config.
If you use `--config CONFIG`, the existing config will be replaced by CONFIG!
Second make oldconfig will called.
ELD
desc 'menuconfig|configure [VERSION]', 'Configure your linux-VERSION. (default: most actual version).'
def menuconfig version = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if nil != options['config'] and config and not version.config.exist?
version.menuconfig
end
map configure: :menuconfig
desc 'compile [VERSION]', 'Will compile kernel and modules.'
def compile version = nil
version = base.find_fetched_version version
version.compile
end
desc 'install [VERSION]', 'Will install kernel and modules. It will trigger updating third-party-modules.'
def install version = nil
version = base.find_fetched_version version
version.install
end
desc 'all [VERSION]', 'Will oldconfig, compile and install kernel and modules. See these methods.'
def all version = nil
version, config = base.oldconfig_prepare( version, options[:config])
version.import_config config if nil != options['config'] and config and not version.config.exist?
version.oldconfig
version.compile
version.install
end
option :any, type: :boolean, aliases: '-a', desc: 'Select any versions.'
option :longterm, type: :boolean, aliases: '-o', desc: 'Select long term versions.'
option :stable, type: :boolean, aliases: '-s', desc: 'Select stable versions (default).'
option :mainline, type: :boolean, aliases: '-m', desc: 'Select mainline versions.'
desc 'update [VERSION]', 'Download, compile and install linux-kernel'
def update version = nil
tarball = fetch version
/^linux-(.*)\.tar\./ =~ tarball.basename.to_s
# try it with version in tarball's name:
all $1
end
no_commands do
def base
@base ||= Base.new
end
def listing list
list.each do |e|
e.configured? if e.is_a? Fetched
end
if options[:latest]
puts list.max
else
puts list.sort {|a,b|b<=>a}
end
end
end
end
end
begin # if __FILE__ == $0
$debug = true if $DEBUG
LinuxUpdate::Cmd.start ARGV
rescue LinuxUpdate::Cmd::Error, LinuxUpdate::Base::Error
STDERR.puts "Error: #{$!}"
STDERR.puts $!.backtrace.map {|c| "\t#{c}" } if $debug
raise
#exit 1
rescue Object
STDERR.puts "Unknown and unexpected Error: #{$!} (#{$!.class})"
STDERR.puts $!.backtrace.map {|c| "\t#{c}" } if $debug
raise
#exit 2
end if __FILE__ == $0