confpkgs 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +31 -0
- data/bin/confpkgs +133 -0
- data/lib/Pkgfile +5 -0
- data/lib/Pkgfile.rb +45 -0
- data/lib/Utils.rb +30 -0
- data/lib/package_manager/Zypper.rb +42 -0
- metadata +165 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56b749400fc3c7bdc55a72d33bf990f989f7f44e
|
4
|
+
data.tar.gz: 8b1f751d2a9079ae1a0e03fb0750b517e9f5957d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 18d7e5f118ce1a1316103cf89e13ccfbdfe98e55e49716c19d810bf809633e0fc8ee3375036b06058b606dd40b1e0e6b936c01267ef5b35931e4c96273e43280
|
7
|
+
data.tar.gz: d5c526f52d37d118ce07d80d324701caff6c4c789d5543d39d7a0c926151faefb7a0817de35735f8e5017f4c0ff7e2c69fed66f8450b97955a6ce4efe0c491fa
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Martin Kurgi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
= confpkgs
|
2
|
+
|
3
|
+
A utility for configuring batches of Linux packages in an automated fashion.
|
4
|
+
Why? Because sometimes you need to reinstall your favorite Linux distro. And removing/installing the same sets of packages every time is annoying. Really annoying.
|
5
|
+
|
6
|
+
== Version 0.0.1
|
7
|
+
|
8
|
+
*Only Zypper, OpenSUSE's package manager is supported.
|
9
|
+
*Installing and removing of packages works
|
10
|
+
|
11
|
+
TODO:
|
12
|
+
*Documentation for rdoc
|
13
|
+
*Support for Apt, Yum, maybe some other package managers
|
14
|
+
*Support for adding and removing package repositories
|
15
|
+
*Support for installing package from specific package repository
|
16
|
+
|
17
|
+
== Contributing to confpkgs
|
18
|
+
|
19
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
20
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
21
|
+
* Fork the project.
|
22
|
+
* Start a feature/bugfix branch.
|
23
|
+
* Commit and push until you are happy with your contribution.
|
24
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
25
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
26
|
+
|
27
|
+
== Copyright
|
28
|
+
|
29
|
+
Copyright (c) 2014 Martin Kurgi. See LICENSE.txt for
|
30
|
+
further details.
|
31
|
+
|
data/bin/confpkgs
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
#TODO documentation and other stuff: see how rake does it
|
3
|
+
|
4
|
+
include Process #for root privileges checking
|
5
|
+
#check for root privileges of current user
|
6
|
+
if Process.uid != 0
|
7
|
+
puts "confpkgs requires root privileges.\n"
|
8
|
+
puts "use \'sudo\' if using system ruby, \'rvmsudo\' if using rvm"
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
#Check for cmdline argument
|
13
|
+
if ARGV.empty?
|
14
|
+
puts "confpkgs requires path/to/Pkgfile as an argument"
|
15
|
+
exit
|
16
|
+
end
|
17
|
+
|
18
|
+
require_relative '../lib/Pkgfile'
|
19
|
+
require_relative '../lib/Utils'
|
20
|
+
require 'colored'
|
21
|
+
require 'ruby-progressbar'
|
22
|
+
|
23
|
+
include Confpkgs::Utils
|
24
|
+
|
25
|
+
#Preliminary list of distros and their respective package managers (as a constant)
|
26
|
+
package_managers = {ubuntu:"Apt", opensuse:"Zypper", debian:"Apt", linuxmint:"Apt", fedora:"Yum"}
|
27
|
+
#dynamically require distro-specific package manager class
|
28
|
+
if is_linux
|
29
|
+
distro = distro_name.downcase.to_sym
|
30
|
+
pkg_mgr = package_managers[distro]
|
31
|
+
require_relative "../lib/package_manager/#{pkg_mgr}"
|
32
|
+
|
33
|
+
#create an os-specific object
|
34
|
+
@os = eval("Confpkgs::#{pkg_mgr}.new")
|
35
|
+
else #is not linux
|
36
|
+
raise NotImplementedError, "Confpkgs only supports GNU/Linux at the moment"
|
37
|
+
end
|
38
|
+
###################
|
39
|
+
#Package operations
|
40
|
+
###################
|
41
|
+
#ARGF must contain only the filename (and path) of one Pkgfile (the file needn't actually be named Pkgfile)
|
42
|
+
if ARGV.empty?
|
43
|
+
puts "confpkgs requires path/to/Pkgfile as an argument"
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
pkgfile = Pkgfile.new(ARGF.readlines)
|
47
|
+
|
48
|
+
ops = [:install, :remove]#, :add_repos]
|
49
|
+
msgs = {}
|
50
|
+
|
51
|
+
ops.each do |op|
|
52
|
+
begin
|
53
|
+
data = pkgfile.send("#{op}")
|
54
|
+
rescue NoMethodError
|
55
|
+
#Current op not specified in Pkgfile - skip it
|
56
|
+
#ops.delete(op)
|
57
|
+
next
|
58
|
+
end
|
59
|
+
#skip op if nothing to do
|
60
|
+
if data.empty?
|
61
|
+
#ops.delete(op)
|
62
|
+
next
|
63
|
+
end
|
64
|
+
case op
|
65
|
+
when :install
|
66
|
+
@install = data
|
67
|
+
msgs[op] = "The following packages are going to be INSTALLED:\n#{@install.join(' ').cyan}"
|
68
|
+
when :remove
|
69
|
+
@remove = data
|
70
|
+
msgs[op] = "The following packages (and their dependencies) are going to be REMOVED:\n#{@remove.join(' ').cyan}"
|
71
|
+
#TODO: This is not yet fully implemented
|
72
|
+
=begin
|
73
|
+
when :add_repos
|
74
|
+
@add_repos = data.delete_if{|repo, url| }#@os.is_added?(repo)}
|
75
|
+
next if @add_repos.empty?
|
76
|
+
msg = "The following repositories are going to be ADDED:\n"
|
77
|
+
@add_repos.each {|repo, url| msg += "#{repo.to_s.blue} => #{url.blue.underline}\n"}
|
78
|
+
@msgs[op] = msg
|
79
|
+
#end TODO
|
80
|
+
=end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
#Delete ops that are not specified in pkgfile or that have no valid pkg names associated with them
|
85
|
+
#Note: package manager errors will still happen if an attempt is made to install a package
|
86
|
+
# which cannot be found in the repositories
|
87
|
+
ops.delete_if{|op| (not pkgfile.respond_to?("#{op}")) or instance_variable_get("@#{op}").nil?}
|
88
|
+
#print summary messages for all pending package/repository operations
|
89
|
+
msgs.values.each {|val| puts val}
|
90
|
+
#confirmation prompt
|
91
|
+
puts "Continue: yes/no: "
|
92
|
+
continue = gets.chomp
|
93
|
+
#The user needs to spell it out, otherwise nothing will be done
|
94
|
+
if continue == "yes"
|
95
|
+
#Thread for performing package operations
|
96
|
+
ops_thread = Thread.new do
|
97
|
+
ops.each {|op| @os.send("#{op}", self.instance_variable_get("@#{op}"))}
|
98
|
+
end
|
99
|
+
|
100
|
+
#Thread for busy-indicator spinner
|
101
|
+
spinner_thread = Thread.new do
|
102
|
+
pb = ProgressBar.create(
|
103
|
+
:unknown_progress_animation_steps => ['[|]', '[/]', '[-]', '[\]'],
|
104
|
+
:total => nil,
|
105
|
+
:length => 13,
|
106
|
+
:format => '%t%B',
|
107
|
+
:title => 'Working...')
|
108
|
+
loop do
|
109
|
+
if not ops_thread.alive?
|
110
|
+
puts "Working...All done\n"
|
111
|
+
Thread.exit
|
112
|
+
end
|
113
|
+
pb.increment
|
114
|
+
sleep(1)
|
115
|
+
end
|
116
|
+
end #end spinner_thread
|
117
|
+
|
118
|
+
#Join the threads, yo
|
119
|
+
[ops_thread, spinner_thread].each {|thr| thr.join}
|
120
|
+
|
121
|
+
#Write package manager log to file
|
122
|
+
File.open("/var/log/confpkgs.log", 'w') do |f|
|
123
|
+
f.write(Time.now.strftime('%Y-%m-%d %H:%M:%S')+"\n")
|
124
|
+
@os.op_msgs.each do |op, msg|
|
125
|
+
f.write(pretty_print(op))
|
126
|
+
f.write(msg)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
puts "Log file at /var/log/confpkgs.log"
|
130
|
+
else
|
131
|
+
puts "No changes made"
|
132
|
+
end
|
133
|
+
|
data/lib/Pkgfile
ADDED
data/lib/Pkgfile.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#Functionality for retrieving package and repository information from the Pkgfile
|
2
|
+
class Pkgfile
|
3
|
+
|
4
|
+
def initialize(pkgfile_lines)
|
5
|
+
@current_array = nil
|
6
|
+
pkgfile_lines.each do |line|
|
7
|
+
next if line.match(/^#/) #Skip comments
|
8
|
+
|
9
|
+
if line.match(/^\[.*\]/) #an array is specified on this line
|
10
|
+
@current_array = line[1..-3] #update current array name
|
11
|
+
#create new array if one doesn't exist yet with this name
|
12
|
+
instance_variable_set("@#{@current_array}", []) if not instance_variables.include? "@#{@current_array}"
|
13
|
+
#process next line of pkgfile
|
14
|
+
next
|
15
|
+
end
|
16
|
+
#skip line in case text found before an array was specified via '[array_name]'
|
17
|
+
next if @current_array.nil?
|
18
|
+
#Append value of line to current array, removing preceding and trailing whitespace
|
19
|
+
instance_variable_set("@#{@current_array}", instance_variable_get("@#{@current_array}") << line.strip)
|
20
|
+
end
|
21
|
+
#Create attr_reader methods for all instance variables
|
22
|
+
instance_variables.each do |ivar|
|
23
|
+
if ivar[1..-1] == "repo"
|
24
|
+
#Repo reader method returns a hash as {:repo_name => "repo_url"}
|
25
|
+
self.class.send(:define_method, "add_repos") {repo_to_h}
|
26
|
+
next
|
27
|
+
end
|
28
|
+
#create normal reader methods
|
29
|
+
self.class.send(:define_method, ivar[1..-1]) {instance_variable_get("#{ivar}")}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
#converts values of @repo to a hash: {:repo_name => "repo_url"} + removes preceding and trailing whitespace
|
36
|
+
def repo_to_h
|
37
|
+
h = {}
|
38
|
+
@repo.each do |val|
|
39
|
+
a = val.partition("=>")
|
40
|
+
h[a[0].strip.to_sym] = a[2].strip
|
41
|
+
end
|
42
|
+
h
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/lib/Utils.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'ruby-progressbar'
|
3
|
+
#This module contains methods that are not Linux distribution specific
|
4
|
+
module Confpkgs
|
5
|
+
#This module contains methods that are not Linux distribution specific
|
6
|
+
module Utils
|
7
|
+
#Returns true if current environment is linux, false otherwise
|
8
|
+
def is_linux
|
9
|
+
@os = RbConfig::CONFIG['host_os']
|
10
|
+
return true if @os.downcase.match('linux')
|
11
|
+
false
|
12
|
+
end
|
13
|
+
|
14
|
+
#Returns lowercase name of linux distribution of current environment
|
15
|
+
def distro_name
|
16
|
+
distro_name = %x(cat /etc/os-release | grep '^ID=')[3..-2]
|
17
|
+
end
|
18
|
+
|
19
|
+
#returns a prettier string
|
20
|
+
def pretty_print(msg)
|
21
|
+
str = ""
|
22
|
+
line = Proc.new {str += "+"; msg.size.times {str += "-"}; str+= "+\n"}
|
23
|
+
line.call
|
24
|
+
str += "|#{msg.capitalize}|\n"
|
25
|
+
line.call
|
26
|
+
#print str
|
27
|
+
str
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Confpkgs
|
2
|
+
class Zypper
|
3
|
+
|
4
|
+
attr_reader :op_msgs
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
#Hash for storing package manager output for each pkg operation
|
8
|
+
@op_msgs = {}
|
9
|
+
end
|
10
|
+
=begin
|
11
|
+
#Returns true if pkg is installed on system, false otherwise
|
12
|
+
def is_installed?(pkg)
|
13
|
+
result = %x(rpm -qa | grep '^#{pkg}-')
|
14
|
+
return false if result.empty?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
#Returns true if repository named 'repo' is added to system, false otherwise
|
19
|
+
def is_added?(repo)
|
20
|
+
result = %x(zypper lr | grep #{repo})
|
21
|
+
return false if result.empty?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
=end
|
25
|
+
#install pkgs
|
26
|
+
def install(array_of_pkgs)
|
27
|
+
@op_msgs[:install] = %x(zypper --non-interactive in #{array_of_pkgs.join(' ')})
|
28
|
+
end
|
29
|
+
|
30
|
+
#remove pkgs
|
31
|
+
def remove(array_of_pkgs)
|
32
|
+
@op_msgs[:remove] = %x(zypper --non-interactive rm --clean-deps #{array_of_pkgs.join(' ')})
|
33
|
+
end
|
34
|
+
|
35
|
+
#add external package repositories
|
36
|
+
def add_repos(repo_hash)
|
37
|
+
repo_hash.each do |repo, url|
|
38
|
+
@op_msgs[:add_repos] = %x(zypper ar -f -n #{repo} #{url} #{repo})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: confpkgs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Kurgi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colored
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ruby-progressbar
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.4.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.4.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.14.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.14.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.7
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.8.7
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rdoc
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.1.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.1.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bundler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.5.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.5.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: jeweler
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 2.0.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.0.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.8.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.8.0
|
125
|
+
description: Configuration file based Linux package management
|
126
|
+
email: martinkurgi@gmail.com
|
127
|
+
executables:
|
128
|
+
- confpkgs
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files:
|
131
|
+
- LICENSE.txt
|
132
|
+
- README.rdoc
|
133
|
+
files:
|
134
|
+
- LICENSE.txt
|
135
|
+
- README.rdoc
|
136
|
+
- bin/confpkgs
|
137
|
+
- lib/Pkgfile
|
138
|
+
- lib/Pkgfile.rb
|
139
|
+
- lib/Utils.rb
|
140
|
+
- lib/package_manager/Zypper.rb
|
141
|
+
homepage: http://github.com/martin1/confpkgs
|
142
|
+
licenses:
|
143
|
+
- MIT
|
144
|
+
metadata: {}
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
requirements: []
|
160
|
+
rubyforge_project:
|
161
|
+
rubygems_version: 2.2.2
|
162
|
+
signing_key:
|
163
|
+
specification_version: 4
|
164
|
+
summary: Configuration file based Linux package management
|
165
|
+
test_files: []
|