carioca 2.0.12 → 2.1.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 (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +7 -1
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +10 -1
  5. data/LICENSE.txt +21 -0
  6. data/README.md +562 -9
  7. data/Rakefile +5 -0
  8. data/VERSION +1 -1
  9. data/assets/images/carioca_output_emoji_colors.PNG +0 -0
  10. data/assets/images/carioca_output_emoji_no_colors.PNG +0 -0
  11. data/assets/images/carioca_output_no_emoji_colors.PNG +0 -0
  12. data/assets/images/carioca_output_no_emoji_no_colors.PNG +0 -0
  13. data/assets/images/description_carioca.png +0 -0
  14. data/assets/images/description_configuration_carioca.png +0 -0
  15. data/assets/images/description_container_carioca.png +0 -0
  16. data/assets/images/description_registry_carioca.png +0 -0
  17. data/assets/images/description_services_carioca.png +0 -0
  18. data/assets/images/logo_carioca_full_large.png +0 -0
  19. data/assets/images/logo_carioca_full_small.png +0 -0
  20. data/assets/images/logo_carioca_light_small.png +0 -0
  21. data/carioca.gemspec +2 -0
  22. data/config/locales/en.yml +34 -0
  23. data/config/locales/fr.yml +35 -1
  24. data/lib/carioca/configuration.rb +6 -2
  25. data/lib/carioca/constants.rb +38 -1
  26. data/lib/carioca/dependencies.rb +13 -0
  27. data/lib/carioca/services/config.rb +1 -1
  28. data/lib/carioca/services/finisher.rb +121 -0
  29. data/lib/carioca/services/sanitycheck.rb +140 -0
  30. data/lib/carioca/services/securestore.rb +81 -0
  31. data/lib/carioca/services/setup.rb +83 -0
  32. data/lib/carioca/services/toolbox.rb +104 -0
  33. data/samples/config/carioca.registry +0 -15
  34. data/samples/config/locales/en.yml +2 -1
  35. data/samples/config/settings.yml +29 -6
  36. data/samples/test.rb +111 -11
  37. metadata +48 -2
@@ -20,4 +20,38 @@ fr:
20
20
  success: "Service de configuration initialisé avec succès depuis : %{from}"
21
21
  output:
22
22
  load:
23
- context: "Service output initialisé en mode : %{confset}"
23
+ context: "Service output initialisé en mode : %{confset}"
24
+ finisher:
25
+ messages:
26
+ not_root: "L'opération doit être lancée en root (utiliser sudo ou rvmsudo)"
27
+ options_incompatibility: "Options incompatibles"
28
+ service_dependence_missing: "Service Carioca, dépendence manquante"
29
+ config_required: "Configuration spécifique requise"
30
+ setup_error: "Setup terminé avec succès"
31
+ setup_success: "Setup terminé en échec"
32
+ sanitycheck_error: "Sanitycheck terminé en echec"
33
+ sanitycheck_success: "Sanitycheck terminé avec succès"
34
+ configuration_error: "Erreur de configuration"
35
+ success_exit: "Opération terminée avec succès"
36
+ error_exit: "Opération terminée en échec"
37
+ interrupt: "Opération interrompue par l'utilisateur"
38
+ not_found: "Objet non trouvé"
39
+ already_exist: "L'objet existé déjà"
40
+ status_ok: "Status OK"
41
+ status_ko: "Status KO"
42
+ bad_usage: "return_case et exit_case sont incompatibles"
43
+ setup:
44
+ error: "Opération en echec durant le setup"
45
+ execute:
46
+ start: "Début du setup :"
47
+ install: "Installation du fichier %{file}"
48
+ mkdir: "Creation du répertoire %{path}"
49
+ ln: "Creation du lien symbolique %{target} -> %{source}"
50
+ sanitycheck:
51
+ error: "Sanitycheck stoppé sur une erreur de configuration"
52
+ success: "Sanitycheck terminé sans erreurs"
53
+ failure: "Sanitycheck termoiné avec des erreurs"
54
+ run:
55
+ start: "Démarrage du sanitycheck :"
56
+ ok: "Testcase %{testcase} sur %{name} ok"
57
+ ko: "Testcase %{testcase} sur %{name} ko, problème(s) : %{pbm}"
@@ -5,7 +5,8 @@ module Carioca
5
5
  include Carioca::Constants
6
6
  include Carioca::Helpers
7
7
  attr_accessor :filename, :name, :builtins, :log_target, :default_locale, :locales_load_path, :debugger_tracer,
8
- :config_file, :config_root, :environment, :supported_environment, :output_mode, :log_level, :output_target
8
+ :config_file, :config_root, :environment, :supported_environments, :output_mode, :log_level, :output_target, :user_config_path,
9
+ :master_key_file, :secure_store_file
9
10
  attr_writer :init_from_file, :output_colors, :output_emoji
10
11
  attr_reader :log_file, :locales_availables, :debug
11
12
 
@@ -21,13 +22,16 @@ module Carioca
21
22
  @environment = DEFAULT_ENVIRONMENT.dup
22
23
  @config_root = DEFAULT_CONFIG_ROOT.dup
23
24
  @log_target = '::Logger::new(STDOUT)'
24
- @supported_environment = DEFAULT_ENVIRONMENTS_LIST.dup
25
+ @supported_environments = DEFAULT_ENVIRONMENTS_LIST.dup
25
26
  @default_locale = DEFAULT_LOCALE
26
27
  @locales_availables = []
27
28
  @output_mode = DEFAULT_OUTPUT_MODE.dup
28
29
  @output_colors = DEFAULT_COLORS_STATUS.dup
29
30
  @output_emoji = DEFAULT_EMOJI_STATUS.dup
30
31
  @output_target = DEFAULT_OUTPUT_TARGET.dup
32
+ @user_config_path = DEFAULT_USER_CONFIG_PATH.dup
33
+ @master_key_file = DEFAULT_MASTER_KEY_FILE.dup
34
+ @secure_store_file = DEFAULT_SECURE_STORE_FILE.dup
31
35
  path = search_file_in_gem('carioca', 'config/locales')
32
36
  @locales_load_path = Dir["#{File.expand_path(path)}/*.yml"]
33
37
  Dir["#{path}/*.yml"].sort.each do |file|
@@ -14,6 +14,11 @@ module Carioca
14
14
  DEFAULT_COLORS_STATUS = true
15
15
  DEFAULT_LOG_LEVEL = :info
16
16
 
17
+ DEFAULT_USER_CONFIG_PATH = "~/.carioca"
18
+
19
+ DEFAULT_MASTER_KEY_FILE = "#{DEFAULT_USER_CONFIG_PATH}/master.key"
20
+ DEFAULT_SECURE_STORE_FILE = "#{DEFAULT_USER_CONFIG_PATH}/secure.Store"
21
+
17
22
  DEFAULT_DEBUGGER_TRACER = :output
18
23
 
19
24
  # service definitions specs
@@ -24,6 +29,9 @@ module Carioca
24
29
 
25
30
  DEFAULT_ENVIRONMENTS_LIST = %i[production staging test development].freeze
26
31
 
32
+
33
+
34
+
27
35
  BUILTINS = {
28
36
  configuration: {
29
37
  type: :internal,
@@ -50,7 +58,7 @@ module Carioca
50
58
  },
51
59
  output: {
52
60
  type: :internal,
53
- description: 'The Output serice of Carioca',
61
+ description: 'The Output service of Carioca',
54
62
  service: "Carioca::Services::Output::Provider::new(
55
63
  mode: Carioca::Registry.config.output_mode,
56
64
  emoji: Carioca::Registry.config.output_emoji?,
@@ -59,6 +67,35 @@ module Carioca
59
67
  target: Carioca::Registry.config.output_target
60
68
  )"
61
69
  },
70
+ finisher: {
71
+ type: :internal,
72
+ service: 'Carioca::Services::Finisher::new',
73
+ description: 'The Finisher service of Carioca',
74
+ depends: [:i18n,:logger, :configuration]
75
+ },
76
+ toolbox: {
77
+ type: :internal,
78
+ service: 'Carioca::Services::Toolbox',
79
+ description: 'The Misceleanous Toolbox service of Carioca',
80
+ },
81
+ setup: {
82
+ type: :internal,
83
+ service: 'Carioca::Services::Setup::new',
84
+ description: 'The Setup service of Carioca',
85
+ depends: [:i18n,:logger, :configuration ]
86
+ },
87
+ sanitycheck: {
88
+ type: :internal,
89
+ service: 'Carioca::Services::Sanitycheck::new',
90
+ description: 'The Sanitycheck service of Carioca',
91
+ depends: [:i18n,:logger, :configuration ]
92
+ },
93
+ securestore: {
94
+ type: :internal,
95
+ service: 'Carioca::Services::SecureStore::new',
96
+ description: 'The SecureStore service of Carioca',
97
+ depends: [:i18n,:logger, :configuration ]
98
+ },
62
99
  debugger: {
63
100
  type: :internal,
64
101
  description: 'The Debugger Service of Carioca',
@@ -4,11 +4,24 @@ require 'yaml'
4
4
  require 'forwardable'
5
5
  require 'singleton'
6
6
 
7
+ require 'socket'
8
+ require 'yaml'
9
+ require 'thread'
10
+ require 'fileutils'
11
+ require 'etc'
12
+ require 'json'
13
+ require 'uri'
14
+ require 'openssl'
15
+ require 'base64'
16
+
17
+
18
+
7
19
  require 'rubygems'
8
20
  require 'i18n'
9
21
  require 'locale'
10
22
  require 'deep_merge'
11
23
  require 'pastel'
24
+ require 'ps-ruby'
12
25
 
13
26
  require_relative 'helpers'
14
27
  require_relative 'constants'
@@ -67,7 +67,7 @@ module Carioca
67
67
  @data = {} unless @data.instance_of?(Hash)
68
68
  @data.delete_if { |key, _value| config.config_root != key }
69
69
  @data[config.config_root] = {} unless @data.include? config.config_root
70
- config.supported_environment.each do |evt|
70
+ config.supported_environments.each do |evt|
71
71
  @data[config.config_root][evt] = {} unless @data[config.config_root].include? evt
72
72
  end
73
73
  @data[config.config_root][:default] = {} unless @data[config.config_root].include? :default
@@ -0,0 +1,121 @@
1
+ # coding: utf-8
2
+
3
+ # base Carioca namespace
4
+ module Carioca
5
+
6
+ module Services
7
+
8
+ class SpecificError < Exception
9
+ attr_reader :error_case
10
+ def initialize(*arg, error_case: :status_ko)
11
+ super(*arg)
12
+ @error_case = error_case
13
+ end
14
+ end
15
+
16
+ # Exiter namespace
17
+ class Finisher
18
+
19
+ DEFAULT_FINISHERS_SPECS = {
20
+ # global
21
+ not_root: { code: 40, key: 'finisher.messages.not_root' },
22
+ options_incompatibility: { code: 410, key: 'finisher.messages.options_incompatibility'},
23
+ service_dependence_missing: { code: 430, key: 'finisher.messages.service_dependence_missing'},
24
+ config_required: { code: 420, key: 'finisher.messages.config_required'},
25
+ setup_error: { code: 520, key: 'finisher.messages.setup_error'},
26
+ setup_success: { code: 0, key: 'finisher.messages.setup_success'},
27
+ sanitycheck_error: { code: 510, key: 'finisher.messages.sanitycheck_error'},
28
+ sanitycheck_success: { code: 0, key: 'finisher.messages.sanitycheck_success'},
29
+ configuration_error: { code: 501, key: 'finisher.messages.configuration_error'},
30
+ success_exit: { code: 0, key: 'finisher.messages.success_exit' },
31
+ quiet_exit: { code: 0 },
32
+ error_exit: { code: 50, key: 'finisher.messages.error_exit' },
33
+ # events
34
+ interrupt: { code: 330, key: 'finisher.messages.interrupt' },
35
+ # request
36
+ not_found: { code: 404, key: 'finisher.messages.not_found' },
37
+ already_exist: { code: 408, key: 'finisher.messages.already_exist' },
38
+ # daemon
39
+ status_ok: { code: 200, key: 'finisher.messages.status_ok' },
40
+ status_ko: { code: 500, key: 'finisher.messages.status_ko' }
41
+ }
42
+
43
+
44
+ def initialize
45
+ registry = Carioca::Registry.get
46
+ @output = registry.get_service name: :output
47
+ @i18n = registry.get_service name: :i18n
48
+ @configuration = registry.get_service name: :configuration
49
+ @exit_map = DEFAULT_FINISHERS_SPECS
50
+ @exit_map.merge! @configuration.settings.exit_cases if @configuration.settings.exit_cases
51
+ end
52
+
53
+ def terminate(return_case: nil, exit_case: nil, more: nil )
54
+ raise "Case must be a return or an exit" if return_case and exit_case
55
+ do_exit!( exit_case: exit_case, more: more) if exit_case
56
+ do_return(return_case: return_case, more: more) if return_case
57
+ end
58
+
59
+ # exiter
60
+ # @option [Symbol] :case an exit case
61
+ # @option [String] :more a complementary string to display
62
+ def do_exit!(exit_case: :quiet_exit, more: nil )
63
+ mess = ""
64
+ mess = @i18n.t(@exit_map[exit_case][:key]) if @exit_map[exit_case].include? :key
65
+ mess << " : " unless mess.empty? or not more
66
+ mess << "#{more}" if more
67
+ if @exit_map[exit_case][:code] == 0 then
68
+ @output.success mess unless mess.empty?
69
+ exit 0
70
+ else
71
+ @output.fatal mess unless mess.empty?
72
+ exit @exit_map[exit_case][:code]
73
+ end
74
+ end
75
+
76
+ def do_return(return_case: :status_ok, more: nil )
77
+ data = @exit_map[return_case].clone
78
+ if data.include? :key then
79
+ data[:message] = @i18n.t(data[:key])
80
+ data.delete :key
81
+ end
82
+ data[:more] = more if more
83
+ return data
84
+ end
85
+
86
+ def secure_raise(message: "unknown error", error_case: :status_ko)
87
+ raise SpecificError::new message, error_case: error_case
88
+ end
89
+
90
+
91
+ def secure_api_return(data: nil, return_case: nil, structured: false, json: true)
92
+ result = {}
93
+ begin
94
+ data = yield if block_given?
95
+ result = (structured)? do_return(return_case: return_case).merge({data: data }) : data
96
+ rescue Exception => e
97
+ key = (e.respond_to? :error_case)? e.error_case : :status_ko
98
+ more = (e.respond_to? :error_case)? e.message : "#{e.class.to_s} : #{e.message}"
99
+ result = do_return return_case: key, more: more
100
+ end
101
+ result = JSON.pretty_generate(JSON.parse(result.to_json)) if json
102
+ return result
103
+ end
104
+
105
+
106
+ def secure_execute!( exit_case: :success_exit )
107
+ result = {}
108
+ begin
109
+ more = yield
110
+
111
+ rescue Exception => e
112
+ key = (e.respond_to? :error_case)? e.error_case : :error_exit
113
+ more = (e.respond_to? :error_case)? e.message : "#{e.class.to_s} : #{e.message}"
114
+ exit_case = key
115
+ end
116
+ do_exit! exit_case: exit_case, more: more
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,140 @@
1
+ # coding: utf-8
2
+
3
+ # base Carioca namespace
4
+ module Carioca
5
+
6
+ module Services
7
+
8
+ # Exiter namespace
9
+ class Sanitycheck
10
+
11
+ def initialize
12
+ registry = Carioca::Registry.get
13
+ @output = registry.get_service name: :output
14
+ @i18n = registry.get_service name: :i18n
15
+ @toolbox = registry.get_service name: :toolbox
16
+ @configuration = registry.get_service name: :configuration
17
+ @finisher = registry.get_service name: :finisher
18
+ @schema = {}
19
+ if @configuration.settings.include? :sanitycheck then
20
+ @schema = (@configuration.settings.sanitycheck.include? :rules)? @configuration.settings.sanitycheck.rules : {}
21
+ end
22
+ end
23
+
24
+ def run
25
+ begin
26
+ result = []
27
+ @output.info @i18n.t('sanitycheck.run.start')
28
+ error_number = 0
29
+ @schema.each do |item|
30
+ testcase = item[:test] ; item.delete(:test)
31
+ res = self.send(testcase, **item)
32
+ if res.empty? then
33
+ @output.ok @i18n.t('sanitycheck.run.ok', testcase: testcase, name: item[:name].to_s)
34
+ else
35
+ pbm = res.map {|p| p.to_s}.join(',')
36
+ @output.ko @i18n.t('sanitycheck.run.ko', testcase: testcase, name: item[:name].to_s, pbm: pbm)
37
+ error_number =+ 1
38
+ end
39
+ end
40
+ if error_number>0 then
41
+ @output.error @i18n.t('sanitycheck.failure')
42
+ else
43
+ @output.success @i18n.t('sanitycheck.success')
44
+ end
45
+ rescue Exception
46
+ @finisher.secure_raise message: @i18n.t('sanitychek.error'), error_case: :status_ko
47
+ end unless @schema.empty?
48
+
49
+ end
50
+
51
+
52
+
53
+ #@!group Verifiers for application : FS and TCP/IP services
54
+
55
+ # check folder
56
+ # @return [Array] of Symbol with error type : [:inexistant,:mode,:owner,:group]
57
+ # @option [String] :name folder path (relative or absolute)
58
+ # @option [String] :mode String for OCTAL rights like "644", default 755
59
+ # @option [String] :owner file owner for folder, optionnal
60
+ # @option [String] :group file group for folder, optionnal
61
+ def verify_folder(name:, mode: "755", owner: nil, group: nil)
62
+ res = Array::new
63
+ return [:inexistant] unless File.directory?(name)
64
+ stat = File.stat(name)
65
+ if mode then
66
+ tested_mode = "%o" % stat.mode
67
+ res << :mode if tested_mode[-3..-1] != mode
68
+ end
69
+ if owner then
70
+ res << :owner if Etc.getpwuid(stat.uid).name != owner
71
+ end
72
+ if group then
73
+ res << :group if Etc.getgrgid(stat.gid).name != group
74
+ end
75
+ return res
76
+ end
77
+
78
+ # check symlink
79
+ # @return [Boolean]
80
+ # @option [String] :name path of the link
81
+ def verify_link(name: )
82
+ res = Array::new
83
+ res.push :inexistant unless File.file?(name)
84
+ return res
85
+ end
86
+
87
+ # check file
88
+ # @return [Array] of Symbol with error type : [:inexistant,:mode,:owner,:group]
89
+ # @option [String] :name path of file
90
+ # @option [String] :mode String for OCTAL rights like "644", optionnal
91
+ # @option [String] :owner file owner for file, optionnal
92
+ # @option [String] :group file group for file, optionnal
93
+ def verify_file(name: , mode: '644', owner: nil, group: nil)
94
+ res = Array::new
95
+ return [:inexistant] unless File.file?(name)
96
+ stat = File.stat(name)
97
+ if mode then
98
+ tested_mode = "%o" % stat.mode
99
+ res << :mode if tested_mode[-3..-1] != mode
100
+ end
101
+ if owner then
102
+ res << :owner if Etc.getpwuid(stat.uid).name != owner
103
+ end
104
+ if group then
105
+ res << :group if Etc.getgrgid(stat.gid).name != group
106
+ end
107
+ return res
108
+ end
109
+
110
+ # TCP/IP service checker
111
+ # @return [Bool] status
112
+ # @option [String] :name display name
113
+ # @option [String] :host hostname
114
+ # @option [String] :port TCP port
115
+ # @option [String] :url full URL, priority on :host and :port
116
+ def verify_service(name: nil, url: nil, host: nil, port: nil)
117
+ begin
118
+ if url then
119
+ uri = URI.parse(url)
120
+ host = uri.host
121
+ port = uri.port
122
+ end
123
+ Timeout::timeout(1) do
124
+ begin
125
+ s = TCPSocket.new(host, port)
126
+ s.close
127
+ return true
128
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
129
+ return false
130
+ end
131
+ end
132
+ rescue Timeout::Error
133
+ return false
134
+ end
135
+ end
136
+ #!@endgroup
137
+
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,81 @@
1
+
2
+ module Carioca
3
+ module Services
4
+
5
+ class SecureStore
6
+ attr_accessor :data
7
+
8
+ extend Carioca::Injector
9
+ inject service: :logger
10
+ inject service: :setup
11
+ inject service: :sanitycheck
12
+
13
+ def initialize(storefile: Carioca::Registry.config.secure_store_file, keyfile: Carioca::Registry.config.master_key_file)
14
+ [storefile, keyfile].map {|file| File.dirname(file) }.each do |path|
15
+ setup.make_folder path: File.expand_path(path), mode: "400" unless sanitycheck.verify_folder name: path
16
+ end
17
+ @storefile = File.expand_path(storefile)
18
+ @keyfile = File.expand_path(keyfile)
19
+ init! unless initialized?
20
+ @data = decrypt
21
+ end
22
+
23
+ def initialized?
24
+ File.exist?(@storefile) && File.exist?(@keyfile)
25
+ end
26
+
27
+ def save!
28
+ encrypt(@data)
29
+ end
30
+
31
+ def init!
32
+ path = File.dirname(@storefile)
33
+ FileUtils.mkdir_p path
34
+ generate_key
35
+ init_data = {}
36
+ encrypt(init_data)
37
+ logger.warn(to_s) { 'Secure Store initialized' }
38
+ end
39
+
40
+ private
41
+
42
+ def generate_key
43
+ cipher = OpenSSL::Cipher.new('aes-256-cbc')
44
+ cipher.encrypt
45
+ key = cipher.random_key
46
+ iv = cipher.random_iv
47
+ encoded_key = Base64.encode64("#{key}|#{iv}")
48
+ unless File.exist? @keyfile
49
+ File.write(@keyfile, encoded_key)
50
+ FileUtils.chmod 0o400, @keyfile
51
+ end
52
+ end
53
+
54
+ def decrypt
55
+ decipher = OpenSSL::Cipher.new('aes-256-cbc')
56
+ decipher.decrypt
57
+ encoded_key = File.read(@keyfile)
58
+ key, iv = Base64.decode64(encoded_key).split('|')
59
+ decipher.key = key
60
+ decipher.iv = iv
61
+ encoded = File.read(@storefile)
62
+ encrypted = Base64.decode64(encoded)
63
+ plain = decipher.update(encrypted) + decipher.final
64
+ YAML.load(plain)
65
+ end
66
+
67
+ def encrypt(data)
68
+ encoded_key = File.read(@keyfile)
69
+ key, iv = Base64.decode64(encoded_key).split('|')
70
+ cipher = OpenSSL::Cipher.new('aes-256-cbc')
71
+ cipher.encrypt
72
+ cipher.key = key
73
+ cipher.iv = iv
74
+ encrypted = cipher.update(data.to_yaml) + cipher.final
75
+ encoded = Base64.encode64(encrypted)
76
+ File.write(@storefile, encoded)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
@@ -0,0 +1,83 @@
1
+ # coding: utf-8
2
+
3
+ # base Carioca namespace
4
+ module Carioca
5
+
6
+ module Services
7
+
8
+ # Exiter namespace
9
+ class Setup
10
+
11
+ def initialize
12
+ registry = Carioca::Registry.get
13
+ @output = registry.get_service name: :output
14
+ @i18n = registry.get_service name: :i18n
15
+ @toolbox = registry.get_service name: :toolbox
16
+ @configuration = registry.get_service name: :configuration
17
+ @finisher = registry.get_service name: :finisher
18
+ @schema = {}
19
+ if @configuration.settings.include? :setup then
20
+ @schema = (@configuration.settings.setup.include? :rules)? @configuration.settings.setup.rules : {}
21
+ end
22
+ end
23
+
24
+
25
+ def execute!
26
+ begin
27
+ @output.info @i18n.t('setup.execute.start')
28
+ @schema.each do |item|
29
+ action = item[:action] ; item.delete(:action)
30
+ self.send action, **item
31
+ end
32
+ rescue Exception
33
+ @finisher.secure_raise message: @i18n.t('setup.error'), error_case: :status_ko
34
+ end unless @schema.empty?
35
+ end
36
+
37
+
38
+
39
+
40
+ # @!group facilities for file system commands
41
+
42
+ # facility for file installation
43
+ # @option [String] :source file source path
44
+ # @option [String] :target file target path
45
+ # @option [String] :mode String for OCTAL rights (default "644")
46
+ # @option [String] :owner file owner for target (optional)
47
+ # @option [String] :group file group for target (optional)
48
+ # @option [Bool] :force to copy file in force (default true)
49
+ # @option [Bool] :gem resolve file in gem root (default true)
50
+ # @option [String] :gem_name name of the gem where to search (default "carioca")
51
+ def install_file(source:, target:, mode: "644", owner: nil, group: nil, force: true, gem: true, gem_name: "carioca" )
52
+ @output.item @i18n.t('setup.install', file: target)
53
+ source = (gem)? @toolbox.search_file_in_gem(gem_name,source) : source
54
+ FileUtils::copy source, target if force
55
+ FileUtils.chmod mode.to_i(8), target
56
+ FileUtils.chown owner, group, target if owner and group
57
+ end
58
+
59
+ # facility for folder creation
60
+ # @option [String] :path folder path (relative or absolute)
61
+ # @option [String] :mode String for OCTAL rights like "644"
62
+ # @option [String] :owner file owner for folder
63
+ # @option [String] :group file group for folder
64
+ def make_folder(path:, mode: "644", owner: nil, group: nil )
65
+ @output.item @i18n.t('setup.mkdir', path: path)
66
+ FileUtils::mkdir_p path unless File::exist? path
67
+ FileUtils.chmod mode.to_i(8), path
68
+ FileUtils.chown owner, group, path if owner and group
69
+ end
70
+
71
+ # facility for Symbolic link
72
+ # @option [String] :source path of the file
73
+ # @option [String] :link path of the symlink
74
+ def make_link(source:, link:)
75
+ @output.item @i18n.t('setup.ln', target: link, source: source)
76
+ FileUtils::rm link if (File::symlink? link and not File::exist? link)
77
+ FileUtils::ln_s source, link unless File::exist? link
78
+ end
79
+ # @!endgroup
80
+
81
+ end
82
+ end
83
+ end