uberinstaller 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. data/.gitignore +20 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +66 -0
  5. data/Rakefile +7 -0
  6. data/TODO +14 -0
  7. data/bin/uberinstaller +6 -0
  8. data/lib/uberinstaller.rb +24 -0
  9. data/lib/uberinstaller/cli.rb +51 -0
  10. data/lib/uberinstaller/commander.rb +112 -0
  11. data/lib/uberinstaller/config.rb +55 -0
  12. data/lib/uberinstaller/exception.rb +40 -0
  13. data/lib/uberinstaller/exceptions/command_not_processable.rb +13 -0
  14. data/lib/uberinstaller/exceptions/invalid_folder.rb +13 -0
  15. data/lib/uberinstaller/exceptions/invalid_json.rb +13 -0
  16. data/lib/uberinstaller/exceptions/invalid_local_package.rb +13 -0
  17. data/lib/uberinstaller/exceptions/invalid_package.rb +13 -0
  18. data/lib/uberinstaller/exceptions/invalid_ppa.rb +13 -0
  19. data/lib/uberinstaller/exceptions/invalid_url.rb +13 -0
  20. data/lib/uberinstaller/exceptions/json_file_not_found.rb +13 -0
  21. data/lib/uberinstaller/exceptions/json_parse_error.rb +13 -0
  22. data/lib/uberinstaller/exceptions/missing_local_package.rb +13 -0
  23. data/lib/uberinstaller/exceptions/missing_url.rb +13 -0
  24. data/lib/uberinstaller/exceptions/multiple_local_files_not_supported.rb +13 -0
  25. data/lib/uberinstaller/exceptions/multiple_repositories_not_supported.rb +13 -0
  26. data/lib/uberinstaller/exceptions/no_preprocessor_exception.rb +13 -0
  27. data/lib/uberinstaller/exceptions/parser_argument_error.rb +13 -0
  28. data/lib/uberinstaller/exceptions/wrong_architecture.rb +13 -0
  29. data/lib/uberinstaller/exceptions/wrong_version.rb +13 -0
  30. data/lib/uberinstaller/installer.rb +284 -0
  31. data/lib/uberinstaller/logger.rb +113 -0
  32. data/lib/uberinstaller/package_manager.rb +27 -0
  33. data/lib/uberinstaller/package_managers/apt.rb +18 -0
  34. data/lib/uberinstaller/package_managers/base.rb +87 -0
  35. data/lib/uberinstaller/package_managers/dpkg.rb +15 -0
  36. data/lib/uberinstaller/package_managers/git.rb +15 -0
  37. data/lib/uberinstaller/parser.rb +51 -0
  38. data/lib/uberinstaller/platform.rb +103 -0
  39. data/lib/uberinstaller/runner.rb +218 -0
  40. data/lib/uberinstaller/utils.rb +13 -0
  41. data/lib/uberinstaller/version.rb +3 -0
  42. data/uberinstaller.gemspec +35 -0
  43. metadata +243 -0
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .ruby-gemset
19
+ .ruby-version
20
+ .rspec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in uberinstaller.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Edoardo Tenani
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Uberinstaller
2
+
3
+ Uberinstaller is a ruby gem that make easy to install system packages from a JSON configuration file.
4
+ Thinked for Ubuntu, can handle pre and post installation commands, repositories and PPA, package installation from system repositories, git repositories or local files.
5
+
6
+ Has support for different Package Managers as the one in use now can be modified and extended as needed.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'uberinstaller'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install uberinstaller
21
+
22
+ Also, you need to have `sudo` installed and working on your machine to execute the uberinstaller executable and for every command launched from uberinstaller.
23
+
24
+ ## Usage
25
+
26
+ duplicates are overridden!
27
+ order is respected!
28
+
29
+ Architecture verification:
30
+ - system => leave to the system to handle architecture package version resolution
31
+ - i386 => can be run only on 32 bit systems
32
+ - x86_64 => can be run only on 64 bit systems
33
+
34
+ Version verification:
35
+ - codename of OS ( precise on ubuntu )
36
+
37
+ Installation type:
38
+ - system
39
+ - git
40
+ - local
41
+ - json ( no extension )
42
+
43
+ Command before/after:
44
+ - in the right folder: cmds/after/ cmds/before/, so specify only the filename, with extension
45
+ - array of commands
46
+ - a single command in a string
47
+
48
+ before all => cmds/before/all.sh
49
+ after all => cmds/after/all.sh
50
+
51
+ Blocking package configuration as Debconf in Debian system must be properly avoided ( APT Package Manager use gnome DEBIAN_FRONTEND to avoid apt-get hangs)
52
+
53
+ ## Docs
54
+
55
+ http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
56
+ http://rubydoc.info/docs/yard/file/docs/Tags.md
57
+
58
+ http://gorails.com/setup/ubuntu
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
data/TODO ADDED
@@ -0,0 +1,14 @@
1
+ ☐ add JSON schema validation https://github.com/hoxworth/json-schema
2
+ ☐ installation advanced option ( install with dpkg for local install, --force-architecture )
3
+ ☐ README need refactoring
4
+ ☐ support {version} and {arch} in ppa/pkg strings
5
+ ☐ add repository support, not only ppa
6
+ ☐ check for superuser!
7
+ ☐ add progress bar for multiple packages installation
8
+
9
+
10
+ ___________________
11
+ Archive:
12
+ ✔ multiple "recipe" inclusion in recipe @done (13-07-17 02:44)
13
+ ✘ preseeding @cancelled (13-07-17 01:43)
14
+ ✔ use proper debian frontend to avoid hangs @done (13-07-17 01:43)
data/bin/uberinstaller ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'uberinstaller'
4
+ require 'uberinstaller/cli'
5
+
6
+ Uberinstaller::Cli.start(ARGV)
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'uberinstaller/version'
4
+ require 'uberinstaller/config'
5
+
6
+ require 'uberinstaller/commander'
7
+ require 'uberinstaller/exception'
8
+ require 'uberinstaller/installer'
9
+ require 'uberinstaller/platform'
10
+ require 'uberinstaller/package_manager'
11
+ require 'uberinstaller/parser'
12
+ require 'uberinstaller/runner'
13
+
14
+
15
+ module Uberinstaller
16
+ # Create a new instance of the Runner class in an easy way
17
+ #
18
+ # @param [String] file
19
+ # the path of the JSON configuration file
20
+ def self.new(file)
21
+ puts "#{Config.app_name} - v#{Config.app_version}"
22
+ Uberinstaller::Runner.new file
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'logger'
4
+ require 'thor'
5
+
6
+ module Uberinstaller
7
+ class Cli < Thor
8
+ default_task :help
9
+
10
+ # Main Uberinstaller installation command.
11
+ #
12
+ # @param file [String] the JSON file with package informations
13
+ #
14
+ # Exit status:
15
+ # - 0 => Execution has been done as expected
16
+ # - 127 => An error stopped execution
17
+ desc "install FILE", "Install packages from the specified JSON FILE"
18
+ method_option :verbose,
19
+ :type => :boolean,
20
+ :default => false,
21
+ :aliases => "-v",
22
+ :desc => "Enable verbose output"
23
+ method_option :debug,
24
+ :type => :boolean,
25
+ :default => false,
26
+ :aliases => "-d",
27
+ :desc => "Enable debug output, include verbose option"
28
+ method_option :dry_run,
29
+ :type => :boolean,
30
+ :default => false,
31
+ :desc => "Enable dry run, no modification to the system will be made during this execution"
32
+ def install(file)
33
+ Uberinstaller::Loggable.level = Logger::WARN
34
+ Uberinstaller::Loggable.level = Logger::INFO if options[:verbose]
35
+ Uberinstaller::Loggable.level = Logger::DEBUG if options[:debug]
36
+
37
+ Uberinstaller::Loggable.log_path = File.join(File.dirname(file), 'log', "#{Time.now}.log") unless options[:debug]
38
+
39
+ Uberinstaller::Config.uberdirectory = File.dirname file
40
+ Uberinstaller::Config.dry_run = options[:dry_run]
41
+
42
+ begin
43
+ runner = Uberinstaller.new file
44
+ runner.preprocess
45
+ runner.install
46
+ rescue Uberinstaller::Exception::WrongVersion, Uberinstaller::Exception::WrongArchitecture => e
47
+ exit(127)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,112 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'uberinstaller/config'
4
+ require 'uberinstaller/exception'
5
+ require 'uberinstaller/logger'
6
+
7
+ module Uberinstaller
8
+
9
+ # Execute user defined command before and after installation
10
+ class Commander
11
+ include Loggable
12
+
13
+ # @!attribute [String] pkg_name
14
+ # The name of the package being processed
15
+ # @!attribute [Hash] pkg
16
+ # an Hash rapresenting a package to be installed
17
+ attr_reader :pkg_name, :pkg
18
+
19
+ # Initialize the Commander class with the package information
20
+ #
21
+ # @param pkg_name [String] the name of the package
22
+ # @param pkg [Hash] the content of the package
23
+ def initialize(pkg_name, pkg)
24
+ @pkg_name = pkg_name
25
+ @pkg = pkg
26
+
27
+ @after_cmd_path = File.join Config.command_path, 'after'
28
+ @before_cmd_path = File.join Config.command_path, 'before'
29
+ end
30
+
31
+ # Execute after installation command
32
+ def after
33
+ if @pkg.has_key? :cmd and @pkg[:cmd].has_key? :after
34
+ logger.info "Executing after commands..."
35
+ run :after
36
+ end
37
+ end
38
+
39
+ # Execute after installation command
40
+ def before
41
+ if @pkg.has_key? :cmd and @pkg[:cmd].has_key? :before
42
+ logger.info "Executing before commands..."
43
+ run :before
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ # Execute a command in a subprocess
50
+ #
51
+ # All commands will be executed using `sudo`
52
+ #
53
+ # @param command [String] the command to be executed
54
+ def exec(command)
55
+ command = "sudo #{command}"
56
+ logger.debug "Executing command: #{command}"
57
+
58
+ unless Config.dry_run
59
+ Open3.popen3(command) { |stdin, stdout, stderr, wait_thr|
60
+ pid = wait_thr.pid # pid of the started process.
61
+ logger.debug "Running pid: #{pid}"
62
+
63
+ logger.debug stdout.readlines
64
+
65
+ exit_status = wait_thr.value.to_i # Process::Status object returned.
66
+ logger.debug "Exit status: #{exit_status}"
67
+ unless exit_status == 0
68
+ logger.error 'Some error happended during execution:'
69
+ logger.error stderr.readlines
70
+ end
71
+ }
72
+ end
73
+ end
74
+
75
+ # Execute the specified file
76
+ #
77
+ # Passes the file to the `exec` function
78
+ #
79
+ # @param file [String] the path to the file to be executed
80
+ def exec_file(file)
81
+ exec "#{file}"
82
+ end
83
+
84
+ # Execute the specified action
85
+ #
86
+ # Currently available actions are: :after, :before
87
+ #
88
+ # @param type [Symbol] a symbol rapresenting an action to be performed
89
+ def run(type)
90
+ file = (type == :after) ? File.join(@after_cmd_path, @pkg[:cmd][type]) : File.join(@before_cmd_path, @pkg[:cmd][type])
91
+
92
+ logger.debug @pkg[:cmd][type]
93
+ logger.debug 'is array : ' + (@pkg[:cmd][type].kind_of? Array).to_s
94
+ logger.debug 'is string : ' + (@pkg[:cmd][type].kind_of? String).to_s
95
+ logger.debug 'file exists : ' + (File.exists? file).to_s if @pkg[:cmd][type].kind_of? String
96
+
97
+ if @pkg[:cmd][type].kind_of? Array
98
+ @pkg[:cmd][type].each do |cmd|
99
+ exec cmd
100
+ end
101
+ elsif @pkg[:cmd][type].kind_of? String
102
+ if File.exists? file
103
+ exec_file file
104
+ else
105
+ exec @pkg[:cmd][type]
106
+ end
107
+ else
108
+ raise Exception::CommandNotProcessable, @pkg_name, type
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,55 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'uberinstaller/version'
4
+
5
+ module Uberinstaller
6
+
7
+ # Shared configuration for Uberinstaller
8
+ module Config
9
+ class << self
10
+ attr_accessor :dry_run, :local_package_manager, :remote_package_manager, :uberdirectory
11
+
12
+ attr_reader :app_name, :app_version
13
+
14
+ def command_path
15
+ @command_path ||= File.join @uberdirectory, 'cmds'
16
+ end
17
+ def local_pkg_path
18
+ @local_pkg_path ||= File.join @uberdirectory, 'pkgs'
19
+ end
20
+ def json_path
21
+ @json_path ||= File.join @uberdirectory, 'json'
22
+ end
23
+ end
24
+
25
+ # @!attribute [rw] uberdirectory
26
+ # absolute path to the folder in which the JSON file is located and in which every other installation script must be located
27
+ @uberdirectory = nil
28
+ # @!attribute [r] command_path
29
+ @command_path = nil
30
+ # @!attribute [r] local_pkg_path
31
+ # absolute path in which local package for the configuration file are found
32
+ @local_pkg_path = nil
33
+ # @!attribute [r] json_path
34
+ # absolute path in which locate json file to be imported in configuration
35
+ @local_pkg_path = nil
36
+
37
+ # @!attribute [rw] remote_package_manager
38
+ # the package manager used to install system type packages
39
+ @remote_package_manager = 'Apt'
40
+ # @!attribute [rw] local_package_manager
41
+ # the package manager used to install local type packages
42
+ @local_package_manager = 'Dpkg'
43
+
44
+ # @!attribute [rw] dry_run
45
+ # prevent real execution of commands enabling a dummy execution for test and debug purposes
46
+ @dry_run = false
47
+
48
+ # @!attribute [r] app_name
49
+ # Application name
50
+ @app_name = "UberInstaller"
51
+ # @!attribute [r] app_version
52
+ # Application version
53
+ @app_version = VERSION
54
+ end
55
+ end
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'uberinstaller/logger'
4
+
5
+ module Uberinstaller
6
+ module Exception
7
+ class Exception < StandardError
8
+ include Loggable
9
+
10
+ attr :parent
11
+
12
+ def initialize(parent, print = true)
13
+ @parent = parent
14
+ logger.fatal parent if print
15
+ super parent
16
+ end
17
+ end
18
+
19
+ # When :pkg for a :type => :local package is not a String
20
+ class MultipleLocalFileNotSupported < Exception; end
21
+ end
22
+ end
23
+
24
+ require 'uberinstaller/exceptions/command_not_processable'
25
+ require 'uberinstaller/exceptions/invalid_folder'
26
+ require 'uberinstaller/exceptions/invalid_json'
27
+ require 'uberinstaller/exceptions/invalid_local_package'
28
+ require 'uberinstaller/exceptions/invalid_package'
29
+ require 'uberinstaller/exceptions/invalid_ppa'
30
+ require 'uberinstaller/exceptions/invalid_url'
31
+ require 'uberinstaller/exceptions/json_file_not_found'
32
+ require 'uberinstaller/exceptions/json_parse_error'
33
+ require 'uberinstaller/exceptions/missing_local_package'
34
+ require 'uberinstaller/exceptions/multiple_local_files_not_supported'
35
+ require 'uberinstaller/exceptions/multiple_repositories_not_supported'
36
+ require 'uberinstaller/exceptions/missing_url'
37
+ require 'uberinstaller/exceptions/no_preprocessor_exception'
38
+ require 'uberinstaller/exceptions/parser_argument_error'
39
+ require 'uberinstaller/exceptions/wrong_architecture'
40
+ require 'uberinstaller/exceptions/wrong_version'
@@ -0,0 +1,13 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Uberinstaller
4
+ module Exception
5
+
6
+ # When a package as an unknown command ( is not a string nor an array )
7
+ class CommandNotProcessable < Exception
8
+ def initialize(name, type)
9
+ super "#{name}'s #{type} command is not proccessable, as it is of unknown type"
10
+ end
11
+ end
12
+ end
13
+ end