@@ -223,10 +223,14 @@ def method_hook(cls, method_names, labels)
223
223
'JSON::Ext::Generator::State' => TargetMethods . new ( :generate , Package . build_from_path ( 'json' , package_name : 'json' , labels : %w[ format.json.generate ] ) ) ,
224
224
} . freeze
225
225
226
- attr_reader :name , :packages , :exclude , :hooked_methods , :builtin_hooks
226
+ attr_reader :name , :appmap_dir , : packages, :exclude , :hooked_methods , :builtin_hooks
227
227
228
- def initialize ( name , packages , exclude : [ ] , functions : [ ] )
228
+ def initialize ( name ,
229
+ packages : [ ] ,
230
+ exclude : [ ] ,
231
+ functions : [ ] )
229
232
@name = name
233
+ @appmap_dir = AppMap ::DEFAULT_APPMAP_DIR
230
234
@packages = packages
231
235
@hook_paths = Set . new ( packages . map ( &:path ) )
232
236
@exclude = exclude
@@ -253,38 +257,119 @@ def initialize(name, packages, exclude: [], functions: [])
253
257
class << self
254
258
# Loads configuration data from a file, specified by the file name.
255
259
def load_from_file ( config_file_name )
256
- require 'yaml'
257
- load YAML . safe_load ( ::File . read ( config_file_name ) )
260
+ logo = lambda do
261
+ Util . color ( <<~LOGO , :magenta )
262
+ ___ __ ___
263
+ / _ | ___ ___ / |/ /__ ____
264
+ / __ |/ _ \\ / _ \\ / /|_/ / _ `/ _ \\
265
+ /_/ |_/ .__/ .__/_/ /_/\\ _,_/ .__/
266
+ /_/ /_/ /_/
267
+ LOGO
268
+ end
269
+
270
+ config_present = true if File . exists? ( config_file_name )
271
+
272
+ config_data = if config_present
273
+ require 'yaml'
274
+ YAML . safe_load ( ::File . read ( config_file_name ) )
275
+ else
276
+ warn logo . ( )
277
+ warn ''
278
+ warn Util . color ( %Q|NOTICE: The AppMap config file #{ config_file_name } was not found!| , :magenta , bold : true )
279
+ warn ''
280
+ warn Util . color ( <<~MISSING_FILE_MSG , :magenta )
281
+ AppMap uses this file to customize its behavior. For example, you can use
282
+ the 'packages' setting to indicate which local file paths and dependency
283
+ gems you want to include in the AppMap. Since you haven't provided specific
284
+ settings, the appmap gem will try and guess some reasonable defaults.
285
+ To suppress this message, create the file:
286
+
287
+ #{ Pathname . new ( config_file_name ) . expand_path } .
288
+
289
+ Here are the default settings that will be used in the meantime. You can
290
+ copy and paste this example to start your appmap.yml.
291
+ MISSING_FILE_MSG
292
+ { }
293
+ end
294
+ load ( config_data ) . tap do |config |
295
+ config_yaml = {
296
+ 'name' => config . name ,
297
+ 'packages' => config . packages . select { |p | p . path } . map do |pkg |
298
+ { 'path' => pkg . path }
299
+ end ,
300
+ 'exclude' => [ ]
301
+ } . compact
302
+ unless config_present
303
+ warn Util . color ( YAML . dump ( config_yaml ) , :magenta )
304
+ warn logo . ( )
305
+ end
306
+ end
258
307
end
259
308
260
309
# Loads configuration from a Hash.
261
310
def load ( config_data )
262
- functions = ( config_data [ 'functions' ] || [ ] ) . map do |function_data |
263
- package = function_data [ 'package' ]
264
- cls = function_data [ 'class' ]
265
- functions = function_data [ 'function' ] || function_data [ 'functions' ]
266
- raise 'AppMap class configuration should specify package, class and function(s)' unless package && cls && functions
267
- functions = Array ( functions ) . map ( &:to_sym )
268
- labels = function_data [ 'label' ] || function_data [ 'labels' ]
269
- labels = Array ( labels ) . map ( &:to_s ) if labels
270
- Function . new ( package , cls , labels , functions )
311
+ name = config_data [ 'name' ] || guess_name
312
+ config_params = {
313
+ exclude : config_data [ 'exclude' ]
314
+ } . compact
315
+
316
+ if config_data [ 'functions' ]
317
+ config_params [ :functions ] = config_data [ 'functions' ] . map do |function_data |
318
+ package = function_data [ 'package' ]
319
+ cls = function_data [ 'class' ]
320
+ functions = function_data [ 'function' ] || function_data [ 'functions' ]
321
+ raise %q(AppMap config 'function' element should specify 'package', 'class' and 'function' or 'functions') unless package && cls && functions
322
+
323
+ functions = Array ( functions ) . map ( &:to_sym )
324
+ labels = function_data [ 'label' ] || function_data [ 'labels' ]
325
+ labels = Array ( labels ) . map ( &:to_s ) if labels
326
+ Function . new ( package , cls , labels , functions )
327
+ end
271
328
end
272
- packages = ( config_data [ 'packages' ] || [ ] ) . map do |package |
273
- gem = package [ 'gem' ]
274
- path = package [ 'path' ]
275
- raise 'AppMap package configuration should specify gem or path, not both' if gem && path
276
-
277
- if gem
278
- shallow = package [ 'shallow' ]
279
- # shallow is true by default for gems
280
- shallow = true if shallow . nil?
281
- Package . build_from_gem ( gem , exclude : package [ 'exclude' ] || [ ] , shallow : shallow )
329
+
330
+ config_params [ :packages ] = \
331
+ if config_data [ 'packages' ]
332
+ config_data [ 'packages' ] . map do |package |
333
+ gem = package [ 'gem' ]
334
+ path = package [ 'path' ]
335
+ raise %q(AppMap config 'package' element should specify 'gem' or 'path', not both) if gem && path
336
+
337
+ if gem
338
+ shallow = package [ 'shallow' ]
339
+ # shallow is true by default for gems
340
+ shallow = true if shallow . nil?
341
+ Package . build_from_gem ( gem , exclude : package [ 'exclude' ] || [ ] , shallow : shallow )
342
+ else
343
+ Package . build_from_path ( path , exclude : package [ 'exclude' ] || [ ] , shallow : package [ 'shallow' ] )
344
+ end
345
+ end . compact
282
346
else
283
- Package . build_from_path ( path , exclude : package [ 'exclude' ] || [ ] , shallow : package [ 'shallow' ] )
347
+ Array ( guess_paths ) . map do |path |
348
+ Package . build_from_path ( path )
349
+ end
284
350
end
285
- end . compact
286
- exclude = config_data [ 'exclude' ] || [ ]
287
- Config . new config_data [ 'name' ] , packages , exclude : exclude , functions : functions
351
+
352
+ Config . new name , config_params
353
+ end
354
+
355
+ def guess_name
356
+ reponame = lambda do
357
+ next unless File . directory? ( '.git' )
358
+
359
+ repo_name = `git config --get remote.origin.url` . strip
360
+ repo_name . split ( '/' ) . last . split ( '.' ) . first unless repo_name == ''
361
+ end
362
+ dirname = -> { Dir . pwd . split ( '/' ) . last }
363
+
364
+ reponame . ( ) || dirname . ( )
365
+ end
366
+
367
+ def guess_paths
368
+ if defined? ( ::Rails )
369
+ %w[ app/controllers app/models ]
370
+ elsif File . directory? ( 'lib' )
371
+ %w[ lib ]
372
+ end
288
373
end
289
374
end
290
375
@@ -294,7 +379,7 @@ def to_h
294
379
packages : packages . map ( &:to_h ) ,
295
380
functions : @functions . map ( &:to_h ) ,
296
381
exclude : exclude
297
- }
382
+ } . compact
298
383
end
299
384
300
385
# Determines if methods defined in a file path should possibly be hooked.
0 commit comments