backup 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 97b183cb0d0c210153909788775e95a6a686a4cc
4
- data.tar.gz: 4eb3b105dcdea08f667c8e94625ec9bdf174dc49
3
+ metadata.gz: 8030ea8ce771bafd23266be65ddac30e62d9954b
4
+ data.tar.gz: bc53925b9956147157e9200d4cfb9d8c7886d343
5
5
  SHA512:
6
- metadata.gz: d5c1cd997c5e0823022b323b639c7977b7d3f573468c860f0fab496ed619b3b44baae8c56ab8dbe13e9ab0643844dac72be9ac6e79c19ef5859faf2fd05760c5
7
- data.tar.gz: 07af01b103adf78549d1296145403dded6e8e6d4cea9dbd5b750839ca26f585c32e0c42a0359f46f9ac0bcc57a412e6b6fdb3e8ab5b8b0936f8496109af7ce09
6
+ metadata.gz: b9631215669b56c92b1694d5a1005d5292ae9d3e25dd2da717cfbe40e30af80d6163b38e6662b7c309c2b480d4d69fe953458171c7dcd5fa908a51314d1ab584
7
+ data.tar.gz: 799f65d322c49d396d9301163412db25369ced068c6260a66fb54444cbd234da73fa07d92c3f6b8e8a58f6bfc241d763c1261d475dc2d3580f6acee02e295cce
data/README.md CHANGED
@@ -68,10 +68,8 @@ $ tar -tvf my_backup.tar
68
68
  my_backup/archives/user_avatars.tar.gz
69
69
  my_backup/archives/log_files.tar.gz
70
70
  my_backup/databases/
71
- my_backup/databases/PostgreSQL/
72
- my_backup/databases/PostgreSQL/pg_db_name.sql.gz
73
- my_backup/databases/Redis/
74
- my_backup/databases/Redis/redis_db_name.rdb.gz
71
+ my_backup/databases/PostgreSQL.sql.gz
72
+ my_backup/databases/Redis.rdb.gz
75
73
  ```
76
74
 
77
75
  ### Storages
@@ -200,7 +198,7 @@ Backup::Model.new(:my_backup, 'Description for my_backup') do
200
198
  mail.user_name = "sender@email.com"
201
199
  mail.password = "my_password"
202
200
  mail.authentication = "plain"
203
- mail.enable_starttls_auto = true
201
+ mail.encryption = :starttls
204
202
  end
205
203
 
206
204
  notify_by Twitter do |tweet|
@@ -53,6 +53,7 @@ module Backup
53
53
  @model = model
54
54
  @name = name.to_s
55
55
  @options = {
56
+ :sudo => false,
56
57
  :root => false,
57
58
  :paths => [],
58
59
  :excludes => [],
@@ -69,7 +70,7 @@ module Backup
69
70
 
70
71
  pipeline = Pipeline.new
71
72
  pipeline.add(
72
- "#{ utility(:tar) } #{ tar_options } -cPf -#{ tar_root } " +
73
+ "#{ tar_command } #{ tar_options } -cPf -#{ tar_root } " +
73
74
  "#{ paths_to_exclude } #{ paths_to_package }",
74
75
  tar_success_codes
75
76
  )
@@ -95,6 +96,11 @@ module Backup
95
96
 
96
97
  private
97
98
 
99
+ def tar_command
100
+ tar = utility(:tar)
101
+ options[:sudo] ? "#{ utility(:sudo) } -n #{ tar }" : tar
102
+ end
103
+
98
104
  def tar_root
99
105
  options[:root] ? " -C '#{ File.expand_path(options[:root]) }'" : ''
100
106
  end
@@ -129,6 +135,10 @@ module Backup
129
135
  @options = options
130
136
  end
131
137
 
138
+ def use_sudo(val = true)
139
+ @options[:sudo] = val
140
+ end
141
+
132
142
  def root(path)
133
143
  @options[:root] = path
134
144
  end
data/lib/backup/cli.rb CHANGED
@@ -4,25 +4,17 @@
4
4
  # Build the Backup Command Line Interface using Thor
5
5
  module Backup
6
6
  class CLI < Thor
7
- include Thor::Actions
8
7
 
9
8
  ##
10
9
  # [Perform]
11
- # Performs the backup process. The only required option is the --trigger [-t].
12
- # If the other options (--config-file, --data-path, --cache-path, --tmp-path)
13
- # aren't specified they will fallback to the (good) defaults.
14
10
  #
11
+ # The only required option is the --trigger [-t].
12
+ # If --config-file, --data-path, --cache-path, --tmp-path aren't specified
13
+ # they will fallback to defaults defined in Backup::Config.
15
14
  # If --root-path is given, it will be used as the base path for our defaults,
16
15
  # as well as the base path for any option specified as a relative path.
17
16
  # Any option given as an absolute path will be used "as-is".
18
17
  #
19
- # If the --check option is given, the config.rb and all model files will be
20
- # loaded, but no triggers will be run. If the check fails, errors will be
21
- # reported to the console. If the check passes, a success message will be
22
- # reported to the console unless --quiet is set. Use --no-quiet to ensure
23
- # these messages are output. The command will exit with status 0 if
24
- # successful, or status 1 if there were problems.
25
- #
26
18
  # This command will exit with one of the following status codes:
27
19
  #
28
20
  # 0: All triggers were successful and no warnings were issued.
@@ -30,128 +22,201 @@ module Backup
30
22
  # 2: All triggers were processed, but some failed.
31
23
  # 3: A fatal error caused Backup to exit.
32
24
  # Some triggers may not have been processed.
25
+ #
26
+ # If the --check option is given, `backup check` will be run
27
+ # and no triggers will be performed.
33
28
  desc 'perform', "Performs the backup for the specified trigger(s)."
34
- long_desc "Performs the backup for the specified trigger(s).\n\n" +
35
- "You may perform multiple backups by providing multiple triggers, separated by commas.\n\n" +
36
- "Example:\n\s\s$ backup perform --triggers backup1,backup2,backup3,backup4\n\n" +
37
- "This will invoke 4 backups, and they will run in the order specified (not asynchronous).\n\n" +
38
- "\n\n" +
39
- "--root-path may be an absolute path or relative to the current working directory.\n\n" +
40
- "To use the current directory, you can use: `--root-path .` (i.e. a period for the argument)"
41
-
42
- method_option :trigger, :type => :string, :required => true, :aliases => ['-t', '--triggers'],
43
- :desc => "Triggers to perform. e.g. 'trigger_a,trigger_b'"
44
- method_option :config_file, :type => :string, :default => '', :aliases => '-c',
45
- :desc => "Path to your config.rb file. " +
46
- "Absolute, or relative to --root-path."
47
- method_option :root_path, :type => :string, :default => '', :aliases => '-r',
48
- :desc => "Root path to base all relative path on. " +
49
- "Absolute or relative to current directory (#{Dir.pwd})."
50
- method_option :data_path, :type => :string, :default => '', :aliases => '-d',
51
- :desc => "Path to store persisted data (storage 'keep' data). " +
52
- "Absolute, or relative to --root-path."
53
- method_option :log_path, :type => :string, :default => '', :aliases => '-l',
54
- :desc => "Path to store Backup's log file. " +
55
- "Absolute, or relative to --root-path."
56
- method_option :cache_path, :type => :string, :default => '',
57
- :desc => "Path to store Dropbox's cached authorization. " +
58
- "Absolute, or relative to --root-path."
59
- method_option :tmp_path, :type => :string, :default => '',
60
- :desc => "Path to store temporary data during the backup process. " +
61
- "Absolute, or relative to --root-path."
29
+
30
+ long_desc <<-EOS.gsub(/^ +/, '')
31
+ Performs the backup for the specified trigger(s).
32
+
33
+ You may perform multiple backups by providing multiple triggers,
34
+ separated by commas. Each will run in the order specified.
35
+
36
+ $ backup perform --triggers backup1,backup2,backup3,backup4
37
+
38
+ --root-path may be an absolute path or relative to the current directory.
39
+
40
+ To use the current directory, use: `--root-path .`
41
+
42
+ Relative paths given for --config-file, --data-path, --log-path,
43
+ --cache-path and --tmp-path will be relative to --root-path.
44
+
45
+ Console log output may be forced using --no-quiet.
46
+
47
+ Logging to file or syslog may be disabled using --no-logfile or --no-syslog
48
+ respectively. This will override logging options set in `config.rb`.
49
+ EOS
50
+
51
+ method_option :trigger,
52
+ :aliases => ['-t', '--triggers'],
53
+ :required => true,
54
+ :type => :string,
55
+ :desc => "Triggers to perform. e.g. 'trigger_a,trigger_b'"
56
+
57
+ method_option :config_file,
58
+ :aliases => '-c',
59
+ :type => :string,
60
+ :default => '',
61
+ :desc => 'Path to your config.rb file.'
62
+
63
+ method_option :root_path,
64
+ :aliases => '-r',
65
+ :type => :string,
66
+ :default => '',
67
+ :desc => 'Root path to base all relative path on.'
68
+
69
+ method_option :data_path,
70
+ :aliases => '-d',
71
+ :type => :string,
72
+ :default => '',
73
+ :desc => 'Path to store storage cycling data.'
74
+
75
+ method_option :log_path,
76
+ :aliases => '-l',
77
+ :type => :string,
78
+ :default => '',
79
+ :desc => "Path to store Backup's log file."
80
+
81
+ method_option :cache_path,
82
+ :type => :string,
83
+ :default => '',
84
+ :desc => "Path to store Dropbox's cached authorization."
85
+
86
+ method_option :tmp_path,
87
+ :type => :string,
88
+ :default => '',
89
+ :desc => 'Path to store temporary data during the backup.'
90
+
62
91
  # Note that :quiet, :syslog and :logfile are specified as :string types,
63
92
  # so the --no-<option> usage will set the value to nil instead of false.
64
- method_option :quiet, :type => :string, :default => false, :aliases => '-q', :banner => '',
65
- :desc => "Disable console log output. " +
66
- "May be force enabled using --no-quiet."
67
- method_option :syslog, :type => :string, :default => false, :banner => '',
68
- :desc => "Enable logging to syslog. " +
69
- "May be forced disabled using --no-syslog."
70
- method_option :logfile, :type => :string, :default => true, :banner => '',
71
- :desc => "Enable Backup's log file. " +
72
- "May be forced disabled using --no-logfile."
73
- method_option :check, :type => :boolean, :default => false,
74
- :desc => "Check `config.rb` and all Model configuration for errors or warnings."
93
+ method_option :quiet,
94
+ :aliases => '-q',
95
+ :type => :string,
96
+ :default => false,
97
+ :banner => '',
98
+ :desc => 'Disable console log output.'
99
+
100
+ method_option :syslog,
101
+ :type => :string,
102
+ :default => false,
103
+ :banner => '',
104
+ :desc => 'Enable logging to syslog.'
105
+
106
+ method_option :logfile,
107
+ :type => :string,
108
+ :default => true,
109
+ :banner => '',
110
+ :desc => "Enable Backup's log file."
111
+
112
+ method_option :check,
113
+ :type => :boolean,
114
+ :default => false,
115
+ :desc => 'Check configuration for errors or warnings.'
75
116
 
76
117
  def perform
77
- ##
78
- # Prepare to perform requested backup jobs.
118
+ check if options[:check] # this will exit()
119
+
79
120
  models = nil
80
121
  begin
81
- ##
82
122
  # Set logger options
83
123
  opts = options
84
124
  Logger.configure do
85
- console.quiet = opts[:quiet]
86
- logfile.enabled = opts[:logfile]
87
- logfile.log_path = opts[:log_path]
88
- syslog.enabled = opts[:syslog]
125
+ console.quiet = opts[:quiet]
126
+ logfile.enabled = opts[:logfile]
127
+ logfile.log_path = opts[:log_path]
128
+ syslog.enabled = opts[:syslog]
89
129
  end
90
130
 
91
- ##
92
131
  # Update Config variables
93
132
  # (config_file, root_path, data_path, cache_path, tmp_path)
94
133
  Config.update(options)
95
134
 
96
- ##
97
- # Ensure the :cache_path and :tmp_path are created
98
- # if they do not yet exist
99
- [Config.cache_path, Config.tmp_path].each do |path|
100
- FileUtils.mkdir_p(path)
101
- end
102
-
103
- ##
104
135
  # Load the user's +config.rb+ file (and all their Models).
105
- # May update Logger options.
136
+ # May update Logger (and Config) options.
106
137
  Config.load_config!
107
138
 
108
- ##
109
139
  # Identify all Models to be run for the given +triggers+.
110
140
  triggers = options[:trigger].split(',').map(&:strip)
111
141
  models = triggers.map {|trigger|
112
142
  Model.find_by_trigger(trigger)
113
143
  }.flatten.uniq
114
144
 
115
- if models.empty?
116
- raise Errors::CLIError,
117
- "No Models found for trigger(s) '#{triggers.join(',')}'."
118
- end
145
+ raise Errors::CLIError, "No Models found for trigger(s) " +
146
+ "'#{ triggers.join(',') }'." if models.empty?
119
147
 
120
- if options[:check] && Logger.has_warnings?
121
- raise Errors::CLIError, 'Configuration Check has warnings.'
122
- end
123
-
124
- ##
125
- # Finalize Logger configuration and begin real-time logging.
148
+ # Finalize Logger and begin real-time logging.
126
149
  Logger.start!
127
150
 
128
151
  rescue Exception => err
129
152
  Logger.error Errors::CLIError.wrap(err)
130
- Logger.error 'Configuration Check Failed.' if options[:check]
131
153
  # Logger configuration will be ignored
132
154
  # and messages will be output to the console only.
133
155
  Logger.abort!
134
- exit(options[:check] ? 1 : 3)
156
+ exit(3)
135
157
  end
136
158
 
137
- if options[:check]
138
- Logger.info 'Configuration Check Succeeded.'
159
+ # Model#perform! handles all exceptions from this point,
160
+ # as each model may fail and return here to allow others to run.
161
+ warnings = errors = false
162
+ models.each do |model|
163
+ model.perform!
164
+ warnings ||= Logger.has_warnings?
165
+ errors ||= Logger.has_errors?
166
+ Logger.clear!
167
+ end
168
+ exit(errors ? 2 : 1) if errors || warnings
169
+ end
170
+
171
+ ##
172
+ # [Check]
173
+ #
174
+ # Loads the user's `config.rb` (and all Model files) and reports any Errors
175
+ # or Warnings. This is primarily for checking for syntax errors, missing
176
+ # dependencies and deprecation warnings.
177
+ #
178
+ # This may also be invoked using the `--check` option to `backup perform`.
179
+ #
180
+ # This command only requires `Config.config_file` to be correct.
181
+ # All other Config paths are irrelevant.
182
+ #
183
+ # All output will be sent to the console only.
184
+ # Logger options will be ignored.
185
+ #
186
+ # If successful, this method with exit(0).
187
+ # If there are Errors or Warnings, it will exit(1).
188
+ desc 'check', 'Check for configuration errors or warnings'
189
+
190
+ long_desc <<-EOS.gsub(/^ +/, '')
191
+ Loads your 'config.rb' file and all models and reports any
192
+ errors or warnings with your configuration, including missing
193
+ dependencies and the use of any deprecated settings.
194
+ EOS
195
+
196
+ method_option :config_file,
197
+ :aliases => '-c',
198
+ :type => :string,
199
+ :default => '',
200
+ :desc => "Path to your config.rb file."
201
+
202
+ def check
203
+ begin
204
+ Config.update(options)
205
+ Config.load_config!
206
+ rescue Exception => err
207
+ Logger.error Errors::CLIError.wrap(err)
208
+ end
209
+
210
+ if Logger.has_warnings? || Logger.has_errors?
211
+ Logger.error 'Configuration Check Failed.'
212
+ exit_code = 1
139
213
  else
140
- ##
141
- # Perform the backup job for each Model found for the given triggers,
142
- # clearing the Logger after each job.
143
- #
144
- # Model#perform! handles all exceptions from this point,
145
- # as each model may fail and return here to allow others to run.
146
- warnings = errors = false
147
- models.each do |model|
148
- model.perform!
149
- warnings ||= Logger.has_warnings?
150
- errors ||= Logger.has_errors?
151
- Logger.clear!
152
- end
153
- exit(errors ? 2 : 1) if errors || warnings
214
+ Logger.info 'Configuration Check Succeeded.'
215
+ exit_code = 0
154
216
  end
217
+
218
+ Logger.abort!
219
+ exit(exit_code)
155
220
  end
156
221
 
157
222
  ##
@@ -161,14 +226,28 @@ module Backup
161
226
  # $ backup generate:model --trigger my_backup --databases='mongodb'
162
227
  # will generate a pre-populated model with a base MongoDB setup
163
228
  desc 'generate:model', "Generates a Backup model file."
164
- long_desc "Generates a Backup model file.\n\n" +
165
- "\s\sNote: '--config-path' is the path to the directory where 'config.rb' is located.\n\n" +
166
- "\s\sThe model file will be created as '<config_path>/models/<trigger>.rb'\n\n" +
167
- "\s\sDefault: #{Config.root_path}\n\n"
168
229
 
169
- method_option :trigger, :type => :string, :required => true, :aliases => '-t'
170
- method_option :config_path, :type => :string,
171
- :desc => 'Path to your Backup configuration directory'
230
+ long_desc <<-EOS.gsub(/^ +/, '')
231
+ Generates a Backup model file.
232
+
233
+ '--config-path' is the path to the *directory* where 'config.rb' is located.
234
+
235
+ The model file will be created as '<config_path>/models/<trigger>.rb'
236
+
237
+ The default location would be:
238
+
239
+ #{ Config.root_path }/models/
240
+ EOS
241
+
242
+ method_option :trigger,
243
+ :aliases => '-t',
244
+ :required => true,
245
+ :type => :string,
246
+ :desc => 'Trigger name for the Backup model'
247
+
248
+ method_option :config_path,
249
+ :type => :string,
250
+ :desc => 'Path to your Backup configuration directory'
172
251
 
173
252
  # options with their available values
174
253
  %w{ databases storages syncers
@@ -178,9 +257,13 @@ module Backup
178
257
  "(#{Dir[path + '/*'].sort.map {|p| File.basename(p) }.join(', ')})"
179
258
  end
180
259
 
181
- method_option :archives, :type => :boolean
182
- method_option :splitter, :type => :boolean, :default => true,
183
- :desc => "use `--no-splitter` to disable"
260
+ method_option :archives,
261
+ :type => :boolean,
262
+ :desc => 'Model will include tar archives.'
263
+ method_option :splitter,
264
+ :type => :boolean,
265
+ :default => true,
266
+ :desc => "Use `--no-splitter` to disable"
184
267
 
185
268
  define_method "generate:model" do
186
269
  opts = options.merge(
@@ -193,8 +276,12 @@ module Backup
193
276
  config = File.join(config_path, "config.rb")
194
277
  model = File.join(models_path, "#{opts[:trigger]}.rb")
195
278
 
279
+ if File.file?(config_path)
280
+ abort('--config-path should be a directory, not a file.')
281
+ end
282
+
196
283
  FileUtils.mkdir_p(models_path)
197
- if overwrite?(model)
284
+ if Helpers.overwrite?(model)
198
285
  File.open(model, 'w') do |file|
199
286
  file.write(
200
287
  Backup::Template.new({:options => opts}).result("cli/model.erb")
@@ -203,7 +290,7 @@ module Backup
203
290
  puts "Generated model file: '#{ model }'."
204
291
  end
205
292
 
206
- if not File.exist?(config)
293
+ unless File.exist?(config)
207
294
  File.open(config, "w") do |file|
208
295
  file.write(Backup::Template.new.result("cli/config"))
209
296
  end
@@ -215,8 +302,18 @@ module Backup
215
302
  # [Generate:Config]
216
303
  # Generates the main configuration file
217
304
  desc 'generate:config', 'Generates the main Backup bootstrap/configuration file'
218
- method_option :config_path, :type => :string,
219
- :desc => "Path to your Backup configuration directory. Default: #{Config.root_path}"
305
+
306
+ long_desc <<-EOS.gsub(/^ +/, '')
307
+ Path to your Backup configuration directory.
308
+
309
+ Default path would be:
310
+
311
+ #{ Config.root_path }
312
+ EOS
313
+
314
+ method_option :config_path,
315
+ :type => :string,
316
+ :desc => 'Path to your Backup configuration directory.'
220
317
 
221
318
  define_method 'generate:config' do
222
319
  config_path = options[:config_path] ?
@@ -224,7 +321,7 @@ module Backup
224
321
  config = File.join(config_path, "config.rb")
225
322
 
226
323
  FileUtils.mkdir_p(config_path)
227
- if overwrite?(config)
324
+ if Helpers.overwrite?(config)
228
325
  File.open(config, "w") do |file|
229
326
  file.write(Backup::Template.new.result("cli/config"))
230
327
  end
@@ -247,13 +344,20 @@ module Backup
247
344
  case options[:encryptor].downcase
248
345
  when 'openssl'
249
346
  base64 = options[:base64] ? '-base64' : ''
250
- password = options[:password_file].empty? ? '' : "-pass file:#{options[:password_file]}"
347
+ password = options[:password_file].empty? ? '' :
348
+ "-pass file:#{ options[:password_file] }"
251
349
  salt = options[:salt] ? '-salt' : ''
252
- %x[openssl aes-256-cbc -d #{base64} #{password} #{salt} -in '#{options[:in]}' -out '#{options[:out]}']
350
+
351
+ Helpers.exec!(
352
+ "openssl aes-256-cbc -d #{ base64 } #{ password } #{ salt } " +
353
+ "-in '#{ options[:in] }' -out '#{ options[:out] }'"
354
+ )
253
355
  when 'gpg'
254
- %x[gpg -o '#{options[:out]}' -d '#{options[:in]}']
356
+ Helpers.exec!(
357
+ "gpg -o '#{ options[:out] }' -d '#{ options[:in] }'"
358
+ )
255
359
  else
256
- puts "Unknown encryptor: #{options[:encryptor]}"
360
+ puts "Unknown encryptor: #{ options[:encryptor] }"
257
361
  puts "Use either 'openssl' or 'gpg'."
258
362
  end
259
363
  end
@@ -262,24 +366,27 @@ module Backup
262
366
  # [Dependencies]
263
367
  # Returns a list of Backup's dependencies
264
368
  desc 'dependencies', 'Display, Check or Install Dependencies for Backup.'
265
- long_desc 'Display the list of dependencies for Backup, check the installation status, or install them through Backup.'
266
- method_option :install, :type => :string
369
+
370
+ long_desc <<-EOS.gsub(/^ +/, '')
371
+ To display a list of available dependencies, run:
372
+
373
+ $ backup dependencies --list
374
+
375
+ To install one of these dependencies, run:
376
+
377
+ $ backup dependencies --install <name>
378
+
379
+ To check if a dependency is already installed, run:
380
+
381
+ $ backup dependencies --installed <name>
382
+ EOS
383
+
384
+ method_option :install, :type => :string, :banner => 'NAME'
267
385
  method_option :list, :type => :boolean
268
- method_option :installed, :type => :string
386
+ method_option :installed, :type => :string, :banner => 'NAME'
269
387
 
270
388
  def dependencies
271
- unless options.any?
272
- puts
273
- puts "To display a list of available dependencies, run:\n\n"
274
- puts " backup dependencies --list"
275
- puts
276
- puts "To install one of these dependencies (with the correct version), run:\n\n"
277
- puts " backup dependencies --install <name>"
278
- puts
279
- puts "To check if a dependency is already installed, run:\n\n"
280
- puts " backup dependencies --installed <name>"
281
- exit
282
- end
389
+ Helpers.exec!("#{ $0 } help dependencies") unless options.any?
283
390
 
284
391
  if options[:list]
285
392
  deps = Dependency.all
@@ -361,23 +468,27 @@ module Backup
361
468
  puts "Backup #{Backup::Version.current}"
362
469
  end
363
470
 
364
- private
365
-
366
- ##
367
- # Helper method for asking the user if he/she wants to overwrite the file
368
- def overwrite?(path)
369
- if File.exist?(path)
370
- return yes? "A file already exists at '#{ path }'. Do you want to overwrite? [y/n]"
371
- end
372
- true
373
- end
374
-
375
471
  # This is to avoid Thor's warnings when stubbing methods on the Thor class.
376
472
  module Helpers
377
473
  class << self
474
+
475
+ def overwrite?(path)
476
+ return true unless File.exist?(path)
477
+
478
+ $stderr.print "A file already exists at '#{ path }'.\n" +
479
+ "Do you want to overwrite? [y/n] "
480
+ /^[Yy]/ =~ $stdin.gets
481
+ end
482
+
483
+ def exec!(cmd)
484
+ puts "Lauching: #{ cmd }"
485
+ exec(cmd)
486
+ end
487
+
378
488
  def bundler_loaded?
379
489
  !ENV['BUNDLE_GEMFILE'].to_s.empty?
380
490
  end
491
+
381
492
  end
382
493
  end
383
494