uberinstaller 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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