codeclimate 0.17.0 → 0.18.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be2909fa3f01d67de344c999494d63d650599c22
4
- data.tar.gz: f093673d099ddfbcca4e5ac63456097a76f20ce3
3
+ metadata.gz: 1cc07ab27995ff71abe7fcf3d17cdb26c0e7cab0
4
+ data.tar.gz: 0bde4385fe0659131b7254d595a3b87a2a099659
5
5
  SHA512:
6
- metadata.gz: b6efca56017e42e7991255f0e3acda6058f4c876dde88be14b8e9d113f9a61701e482fedc3b5ce47747f07a69c83b2963288c2ff985d6bc78e9d866b80f39204
7
- data.tar.gz: d1c74c3732550d6a001879a22538c9f0d6fdfb8ee15e3bebf6e8cd99776f866454f16ae524ce2a5198b2e6a53de1cb707b1214b2501ebcf6186ab682a9432b80
6
+ metadata.gz: 788524a629d27d9825bfd87bb3181da46444273395fbac5c16ac10254a7ac5d13f9c0bb86494f5f4710d605115a4ae97385ce6773713802fce2bc983dcbf3caf
7
+ data.tar.gz: def528a3546470b85c9200334286a1afd1a6c6c0eb8eca43189d3fb747745dd43f22db131e8b87b587438aa2b4379637200adca22c21be62aea9049617833af1
@@ -12,13 +12,10 @@ module CC
12
12
  autoload :EnginesRunner, "cc/analyzer/engines_runner"
13
13
  autoload :Filesystem, "cc/analyzer/filesystem"
14
14
  autoload :Formatters, "cc/analyzer/formatters"
15
- autoload :IncludePathsBuilder, "cc/analyzer/include_paths_builder"
16
15
  autoload :Issue, "cc/analyzer/issue"
17
16
  autoload :IssueSorter, "cc/analyzer/issue_sorter"
18
17
  autoload :LocationDescription, "cc/analyzer/location_description"
19
18
  autoload :LoggingContainerListener, "cc/analyzer/logging_container_listener"
20
- autoload :PathPatterns, "cc/analyzer/path_patterns"
21
- autoload :PathMinimizer, "cc/analyzer/path_minimizer"
22
19
  autoload :RaisingContainerListener, "cc/analyzer/raising_container_listener"
23
20
  autoload :SourceBuffer, "cc/analyzer/source_buffer"
24
21
  autoload :StatsdContainerListener, "cc/analyzer/statsd_container_listener"
@@ -172,6 +172,7 @@ module CC
172
172
  def reap_running_container(message)
173
173
  Analyzer.logger.warn("killing container name=#{@name} message=#{message.inspect}")
174
174
  POSIX::Spawn::Child.new("docker", "kill", @name)
175
+ POSIX::Spawn::Child.new("docker", "wait", @name, timeout: 5.minutes)
175
176
  end
176
177
 
177
178
  def timeout
@@ -29,23 +29,27 @@ module CC
29
29
 
30
30
  private
31
31
 
32
- attr_reader :include_paths
33
-
34
32
  def engine_config(raw_engine_config)
33
+ engine_workspace = engine_workspace(raw_engine_config)
35
34
  config = raw_engine_config.merge(
36
- exclude_paths: exclude_paths,
37
- include_paths: include_paths,
35
+ include_paths: engine_workspace.paths,
38
36
  )
39
- # The yaml gem turns a config file string into a hash, but engines
40
- # expect the string. So we (for now) need to turn it into a string in
41
- # that one scenario.
42
- # TODO: update the engines to expect the hash and then remove this.
43
- if config.fetch("config", {}).keys.size == 1 && config["config"].key?("file")
44
- config["config"] = config["config"]["file"]
45
- end
37
+
38
+ normalize_config_file(config)
39
+
46
40
  config
47
41
  end
48
42
 
43
+ def engine_workspace(raw_engine_config)
44
+ if raw_engine_config.key?("exclude_paths") && !@requested_paths.present?
45
+ base_workspace.clone.tap do |workspace|
46
+ workspace.remove(raw_engine_config["exclude_paths"])
47
+ end
48
+ else
49
+ base_workspace
50
+ end
51
+ end
52
+
49
53
  def names_and_raw_engine_configs
50
54
  {}.tap do |ret|
51
55
  (@config.engines || {}).each do |name, raw_engine_config|
@@ -56,20 +60,22 @@ module CC
56
60
  end
57
61
  end
58
62
 
59
- def include_paths
60
- IncludePathsBuilder.new(exclude_paths, Array(@requested_paths)).build
61
- end
62
-
63
- def exclude_paths
64
- PathPatterns.new(@config.exclude_paths || []).expanded +
65
- gitignore_paths
63
+ def base_workspace
64
+ @base_workspace ||= Workspace.new.tap do |workspace|
65
+ workspace.add(@requested_paths)
66
+ unless @requested_paths.present?
67
+ workspace.remove([".git"])
68
+ workspace.remove(@config.exclude_paths)
69
+ end
70
+ end
66
71
  end
67
72
 
68
- def gitignore_paths
69
- if File.exist?(".gitignore")
70
- `git ls-files --others -i -z --exclude-from .gitignore`.split("\0")
71
- else
72
- []
73
+ # The yaml gem turns a config file string into a hash, but engines expect
74
+ # the string. So we (for now) need to turn it into a string in that one
75
+ # scenario.
76
+ def normalize_config_file(config)
77
+ if config.fetch("config", {}).keys.size == 1 && config["config"].key?("file")
78
+ config["config"] = config["config"]["file"]
73
79
  end
74
80
  end
75
81
  end
@@ -1,6 +1,8 @@
1
1
  module CC
2
2
  module Analyzer
3
3
  class Filesystem
4
+ attr_reader :root
5
+
4
6
  def initialize(root)
5
7
  @root = root
6
8
  end
@@ -22,30 +24,14 @@ module CC
22
24
  File.chown(root_uid, root_gid, path_for(path))
23
25
  end
24
26
 
25
- def any?(&block)
26
- file_paths.any?(&block)
27
- end
28
-
29
- def files_matching(globs)
30
- Dir.chdir(@root) do
31
- globs.map do |glob|
32
- Dir.glob(glob)
33
- end.flatten.sort.uniq
34
- end
27
+ def ls
28
+ Dir.entries(root).reject { |entry| [".", ".."].include?(entry) }
35
29
  end
36
30
 
37
31
  private
38
32
 
39
- def file_paths
40
- @file_paths ||= Dir.chdir(@root) do
41
- `find . -type f -print0`.strip.split("\0").map do |path|
42
- path.sub(%r{^\.\/}, "")
43
- end
44
- end
45
- end
46
-
47
33
  def path_for(path)
48
- File.join(@root, path)
34
+ File.join(root, path)
49
35
  end
50
36
 
51
37
  def root_uid
@@ -57,7 +43,7 @@ module CC
57
43
  end
58
44
 
59
45
  def root_stat
60
- @root_stat ||= File.stat(@root)
46
+ @root_stat ||= File.stat(root)
61
47
  end
62
48
  end
63
49
  end
@@ -1,6 +1,7 @@
1
1
  require "active_support"
2
2
  require "active_support/core_ext"
3
3
  require "cc/analyzer"
4
+ require "cc/workspace"
4
5
  require "cc/yaml"
5
6
 
6
7
  module CC
@@ -15,5 +16,16 @@ module CC
15
16
  autoload :Test, "cc/cli/test"
16
17
  autoload :ValidateConfig, "cc/cli/validate_config"
17
18
  autoload :Version, "cc/cli/version"
19
+
20
+ def self.debug(message, values = {})
21
+ if ENV["CODECLIMATE_DEBUG"]
22
+ if values.any?
23
+ message << " "
24
+ message << values.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")
25
+ end
26
+
27
+ $stderr.puts("[DEBUG] #{message}")
28
+ end
29
+ end
18
30
  end
19
31
  end
@@ -21,13 +21,7 @@ module CC
21
21
 
22
22
  def add_exclude_paths(paths)
23
23
  config["exclude_paths"] ||= []
24
- config["exclude_paths"] += paths.map do |path|
25
- if path.ends_with?("/")
26
- "#{path}**/*"
27
- else
28
- path
29
- end
30
- end
24
+ config["exclude_paths"] |= paths
31
25
  end
32
26
 
33
27
  private
@@ -1,3 +1,5 @@
1
+ require "shellwords"
2
+
1
3
  module CC
2
4
  module CLI
3
5
  class ConfigGenerator
@@ -37,7 +39,7 @@ module CC
37
39
  end
38
40
 
39
41
  def exclude_paths
40
- AUTO_EXCLUDE_PATHS.select { |path| filesystem.exist?(path) }
42
+ @exclude_paths ||= AUTO_EXCLUDE_PATHS.select { |path| filesystem.exist?(path) }
41
43
  end
42
44
 
43
45
  def post_generation_verb
@@ -59,10 +61,32 @@ module CC
59
61
  end
60
62
 
61
63
  def files_exist?(engine)
62
- filesystem.any? do |path|
64
+ workspace_files.any? do |path|
63
65
  engine["enable_regexps"].any? { |re| Regexp.new(re).match(path) }
64
66
  end
65
67
  end
68
+
69
+ def non_excluded_paths
70
+ @non_excluded_paths ||= begin
71
+ excludes = exclude_paths.map { |path| path.chomp("/") }
72
+ filesystem.ls.reject do |path|
73
+ path.starts_with?(".") || excludes.include?(path)
74
+ end
75
+ end
76
+ end
77
+
78
+ def workspace_files
79
+ @workspace_files ||= Dir.chdir(filesystem.root) do
80
+ if non_excluded_paths.empty?
81
+ []
82
+ else
83
+ find_cmd = "find #{non_excluded_paths.map(&:shellescape).join(' ')} -type f -print0"
84
+ `#{find_cmd}`.strip.split("\0").map do |path|
85
+ path.sub(%r{^\.\/}, "")
86
+ end
87
+ end
88
+ end
89
+ end
66
90
  end
67
91
  end
68
92
  end
@@ -10,11 +10,11 @@ module CC
10
10
  def run
11
11
  if !upgrade? && filesystem.exist?(CODECLIMATE_YAML)
12
12
  warn "Config file .codeclimate.yml already present.\nTry running 'validate-config' to check configuration."
13
- create_default_configs
13
+ create_default_engine_configs if engines_enabled?
14
14
  elsif upgrade? && engines_enabled?
15
15
  fatal "--upgrade should not be used on a .codeclimate.yml configured for the Platform.\nTry running 'validate-config' to check configuration."
16
16
  else
17
- generate_config
17
+ generate_all_config
18
18
  end
19
19
  end
20
20
 
@@ -24,7 +24,7 @@ module CC
24
24
  @args.include?("--upgrade")
25
25
  end
26
26
 
27
- def generate_config
27
+ def generate_all_config
28
28
  unless config_generator.can_generate?
29
29
  config_generator.errors.each do |error|
30
30
  $stderr.puts colorize("ERROR: #{error}", :red)
@@ -34,10 +34,11 @@ module CC
34
34
 
35
35
  create_codeclimate_yaml
36
36
  success "Config file .codeclimate.yml successfully #{config_generator.post_generation_verb}.\nEdit and then try running 'validate-config' to check configuration."
37
- create_default_configs
37
+ create_default_engine_configs
38
38
  end
39
39
 
40
40
  def create_codeclimate_yaml
41
+ say "Generating .codeclimate.yml..."
41
42
  config = CC::CLI::Config.new
42
43
 
43
44
  config_generator.eligible_engines.each do |(engine_name, engine_config)|
@@ -48,8 +49,9 @@ module CC
48
49
  filesystem.write_path(CODECLIMATE_YAML, config.to_yaml)
49
50
  end
50
51
 
51
- def create_default_configs
52
- available_configs.each do |config_path|
52
+ def create_default_engine_configs
53
+ say "Generating default configuration for engines..."
54
+ available_engine_configs.each do |config_path|
53
55
  file_name = File.basename(config_path)
54
56
  if filesystem.exist?(file_name)
55
57
  say "Skipping generating #{file_name} file (already exists)."
@@ -60,29 +62,34 @@ module CC
60
62
  end
61
63
  end
62
64
 
63
- def available_configs
64
- all_paths = config_generator.eligible_engines.flat_map do |engine_name, _|
65
+ def available_engine_configs
66
+ engine_names = existing_cc_config.engines.select do |_, config|
67
+ config.enabled?
68
+ end.keys
69
+
70
+ all_paths = engine_names.flat_map do |engine_name|
65
71
  engine_directory = File.expand_path("../../../../config/#{engine_name}", __FILE__)
66
72
  Dir.glob("#{engine_directory}/*", File::FNM_DOTMATCH)
67
73
  end
68
-
69
- all_paths.reject { |path| [".", ".."].include?(File.basename(path)) }
74
+ all_paths.reject do |path|
75
+ %w[. ..].include?(File.basename(path))
76
+ end
70
77
  end
71
78
 
72
79
  def engines_enabled?
73
- unless @engines_enabled.nil?
74
- return @engines_enabled
75
- end
76
-
77
- if filesystem.exist?(CODECLIMATE_YAML)
78
- config = CC::Analyzer::Config.new(File.read(CODECLIMATE_YAML))
79
- @engines_enabled ||= config.engine_names.any?
80
- end
80
+ cc_config = existing_cc_config
81
+ cc_config.present? && cc_config.engines.present?
81
82
  end
82
83
 
83
84
  def config_generator
84
85
  @config_generator ||= ConfigGenerator.for(filesystem, engine_registry, upgrade?)
85
86
  end
87
+
88
+ def existing_cc_config
89
+ if filesystem.exist?(CODECLIMATE_YAML)
90
+ CC::Yaml.parse(filesystem.read_path(CODECLIMATE_YAML))
91
+ end
92
+ end
86
93
  end
87
94
  end
88
95
  end
@@ -10,9 +10,7 @@ module CC
10
10
  rescue => ex
11
11
  $stderr.puts("error: (#{ex.class}) #{ex.message}")
12
12
 
13
- if ENV["CODECLIMATE_DEBUG"]
14
- $stderr.puts("backtrace: #{ex.backtrace.join("\n\t")}")
15
- end
13
+ CLI.debug("backtrace: #{ex.backtrace.join("\n\t")}")
16
14
  end
17
15
 
18
16
  def initialize(args)
@@ -0,0 +1,34 @@
1
+ module CC
2
+ class Workspace
3
+ autoload :Exclusion, "cc/workspace/exclusion"
4
+ autoload :PathTree, "cc/workspace/path_tree"
5
+
6
+ def initialize(path_tree = PathTree.new("."))
7
+ @path_tree = path_tree
8
+ end
9
+
10
+ def clone
11
+ self.class.new(path_tree.clone)
12
+ end
13
+
14
+ def paths
15
+ path_tree.all_paths
16
+ end
17
+
18
+ def add(paths)
19
+ if paths.present?
20
+ path_tree.include_paths(paths)
21
+ end
22
+ end
23
+
24
+ def remove(patterns)
25
+ Array(patterns).each do |pattern|
26
+ path_tree.exclude_paths(Exclusion.new(pattern).expand)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :path_tree
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ module CC
2
+ class Workspace
3
+ class Exclusion
4
+ def initialize(pattern)
5
+ @pattern = simplify(pattern)
6
+ end
7
+
8
+ def expand
9
+ if glob?
10
+ Dir.glob(pattern)
11
+ else
12
+ [pattern]
13
+ end
14
+ end
15
+
16
+ def glob?
17
+ pattern.include?("*")
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :pattern
23
+
24
+ def simplify(pattern)
25
+ pattern.to_s.sub(%r{(/\*\*)?(/\*)?$}, "")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,110 @@
1
+ require "pathname"
2
+ require "set"
3
+
4
+ module CC
5
+ class Workspace
6
+ class PathTree
7
+ def self.create(pathname)
8
+ if pathname.directory?
9
+ new(pathname.to_s)
10
+ else
11
+ FileNode.new(pathname.to_s)
12
+ end
13
+ end
14
+
15
+ def initialize(root_path, children = {})
16
+ @root_path = root_path.dup.freeze
17
+ @children = children
18
+ end
19
+
20
+ def clone
21
+ self.class.new(root_path, children.dup)
22
+ end
23
+
24
+ def exclude_paths(paths)
25
+ paths.each { |path| remove(*normalized_path_pieces(path)) }
26
+ end
27
+
28
+ def include_paths(paths)
29
+ paths.each { |path| add(*normalized_path_pieces(path)) }
30
+ end
31
+
32
+ def all_paths
33
+ if populated?
34
+ children.values.flat_map(&:all_paths)
35
+ else
36
+ [File.join(root_path, File::SEPARATOR)]
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def populated?
43
+ children.present?
44
+ end
45
+
46
+ def remove(head = nil, *tail)
47
+ return if head.nil? && tail.empty?
48
+ populate_direct_children
49
+
50
+ if (child = children[head])
51
+ child.remove(*tail)
52
+ children.delete(head) unless child.populated?
53
+ end
54
+ end
55
+
56
+ def add(head = nil, *tail)
57
+ return if head.nil? && tail.empty?
58
+
59
+ if (entry = find_direct_child(head))
60
+ children[entry.basename.to_s] = self.class.create(entry)
61
+ children[entry.basename.to_s].add(*tail)
62
+ else
63
+ CLI.debug("Couldn't include because part of path doesn't exist.", path: File.join(root_path, head))
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ attr_reader :children, :root_path
70
+
71
+ def populate_direct_children
72
+ return if populated?
73
+
74
+ Pathname.new(root_path).each_child do |child_path|
75
+ children[child_path.basename.to_s] = self.class.create(child_path)
76
+ end
77
+ end
78
+
79
+ def find_direct_child(name)
80
+ Pathname.new(root_path).children.detect { |c| c.basename.to_s == name }
81
+ end
82
+
83
+ def normalized_path_pieces(path)
84
+ Pathname.new(path).cleanpath.to_s.split(File::SEPARATOR).reject(&:blank?)
85
+ end
86
+
87
+ class FileNode
88
+ def initialize(root_path)
89
+ @root_path = root_path.dup.freeze
90
+ end
91
+
92
+ def all_paths
93
+ [@root_path]
94
+ end
95
+
96
+ def populated?
97
+ false
98
+ end
99
+
100
+ def remove(*)
101
+ # this space intentionally left blank
102
+ end
103
+
104
+ def add(*)
105
+ # this space intentionally left blank
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codeclimate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code Climate
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-21 00:00:00.000000000 Z
11
+ date: 2016-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 0.6.1
53
+ version: 0.7.0
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: 0.6.1
60
+ version: 0.7.0
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: faraday
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -216,15 +216,10 @@ files:
216
216
  - lib/cc/analyzer/formatters/json_formatter.rb
217
217
  - lib/cc/analyzer/formatters/plain_text_formatter.rb
218
218
  - lib/cc/analyzer/formatters/spinner.rb
219
- - lib/cc/analyzer/include_paths_builder.rb
220
219
  - lib/cc/analyzer/issue.rb
221
220
  - lib/cc/analyzer/issue_sorter.rb
222
221
  - lib/cc/analyzer/location_description.rb
223
222
  - lib/cc/analyzer/logging_container_listener.rb
224
- - lib/cc/analyzer/path_entries.rb
225
- - lib/cc/analyzer/path_filter.rb
226
- - lib/cc/analyzer/path_minimizer.rb
227
- - lib/cc/analyzer/path_patterns.rb
228
223
  - lib/cc/analyzer/raising_container_listener.rb
229
224
  - lib/cc/analyzer/source_buffer.rb
230
225
  - lib/cc/analyzer/statsd_container_listener.rb
@@ -248,7 +243,9 @@ files:
248
243
  - lib/cc/cli/upgrade_config_generator.rb
249
244
  - lib/cc/cli/validate_config.rb
250
245
  - lib/cc/cli/version.rb
251
- - lib/file_utils_ext.rb
246
+ - lib/cc/workspace.rb
247
+ - lib/cc/workspace/exclusion.rb
248
+ - lib/cc/workspace/path_tree.rb
252
249
  homepage: https://codeclimate.com
253
250
  licenses:
254
251
  - MIT
@@ -1,62 +0,0 @@
1
- require "file_utils_ext"
2
- require "cc/analyzer/path_minimizer"
3
- require "cc/analyzer/path_filter"
4
-
5
- module CC
6
- module Analyzer
7
- class IncludePathsBuilder
8
- IGNORE_PATHS = [".", "..", ".git"].freeze
9
-
10
- attr_reader :cc_include_paths
11
-
12
- def initialize(cc_exclude_paths, cc_include_paths = [])
13
- @cc_exclude_paths = cc_exclude_paths
14
- @cc_include_paths = cc_include_paths
15
- end
16
-
17
- def build
18
- PathMinimizer.new(paths_filter.paths).minimize.uniq
19
- end
20
-
21
- private
22
-
23
- def paths_filter
24
- @_paths =
25
- PathFilter.new(include_paths).
26
- reject_paths(ignored_files).
27
- reject_unreadable_paths.
28
- select_readable_files.
29
- reject_symlinks
30
- end
31
-
32
- def include_paths
33
- if @cc_include_paths.empty?
34
- all_paths
35
- else
36
- @cc_include_paths.flat_map do |path|
37
- PathEntries.new(path).entries
38
- end
39
- end
40
- end
41
-
42
- def all_paths
43
- Dir.glob("*", File::FNM_DOTMATCH).
44
- reject { |path| IncludePathsBuilder::IGNORE_PATHS.include?(path) }.
45
- flat_map { |path| PathEntries.new(path).entries }
46
- end
47
-
48
- def ignored_files
49
- return @_ignored_files if @_ignored_files
50
-
51
- Tempfile.open(".cc_gitignore") do |tmp|
52
- tmp.write(File.read(".gitignore")) if File.file?(".gitignore")
53
- tmp << @cc_exclude_paths.join("\n")
54
- tmp.close
55
- tracked_and_ignored = `git ls-files -zi -X #{tmp.path} 2>/dev/null`.split("\0")
56
- untracked_and_ignored = `git ls-files -zio -X #{tmp.path} 2>/dev/null`.split("\0")
57
- @_ignored_files = tracked_and_ignored + untracked_and_ignored
58
- end
59
- end
60
- end
61
- end
62
- end
@@ -1,27 +0,0 @@
1
- module CC
2
- module Analyzer
3
- class PathEntries
4
- def initialize(initial_path)
5
- @initial_path = initial_path.gsub(%r{/$}, "")
6
- end
7
-
8
- def entries
9
- if File.directory?(initial_path)
10
- all_entries.reject do |path|
11
- path.end_with?("/.") || path.start_with?(".git/")
12
- end
13
- else
14
- initial_path
15
- end
16
- end
17
-
18
- private
19
-
20
- attr_reader :initial_path
21
-
22
- def all_entries
23
- Dir.glob("#{initial_path}/**/*", File::FNM_DOTMATCH).push(initial_path)
24
- end
25
- end
26
- end
27
- end
@@ -1,50 +0,0 @@
1
- module CC
2
- module Analyzer
3
- class PathFilter
4
- attr_reader :paths
5
-
6
- def initialize(paths)
7
- @paths = paths
8
- end
9
-
10
- def reject_unreadable_paths
11
- @paths = paths - unreadable_path_entries
12
- self
13
- end
14
-
15
- def reject_paths(ignore_paths)
16
- @paths = paths - ignore_paths
17
- self
18
- end
19
-
20
- def select_readable_files
21
- @paths = paths.select { |path| File.exist?(path) && FileUtils.readable_by_all?(path) }
22
- self
23
- end
24
-
25
- def reject_symlinks
26
- @paths = paths.reject { |path| File.symlink?(path) }
27
- self
28
- end
29
-
30
- def reject_globs(globs)
31
- patterns = PathPatterns.new(globs)
32
- @paths = paths.reject { |path| patterns.match?(pathpatterns.match?(path)) }
33
- self
34
- end
35
-
36
- private
37
-
38
- def unreadable_path_entries
39
- @_unreadable_path_entries ||=
40
- unreadable_paths.flat_map { |path| PathEntries.new(path).entries }
41
- end
42
-
43
- def unreadable_paths
44
- paths.select do |path|
45
- File.directory?(path) && !FileUtils.readable_by_all?(path)
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,84 +0,0 @@
1
- require "cc/analyzer/path_entries"
2
- require "cc/analyzer/include_paths_builder"
3
-
4
- module CC
5
- module Analyzer
6
- class PathMinimizer
7
- def initialize(paths)
8
- @paths = paths
9
- @to_remove = []
10
- end
11
-
12
- def minimize
13
- if diff.empty?
14
- ["./"]
15
- else
16
- filtered_paths
17
- end
18
- end
19
-
20
- private
21
-
22
- attr_reader :paths
23
-
24
- def diff
25
- @_diff ||=
26
- (all_files - paths).
27
- reject { |path| File.symlink?(path) }.
28
- flat_map { |path| build_entry_combinations(path) }
29
- end
30
-
31
- def filtered_paths
32
- filtered_paths = @paths - paths_to_remove
33
- filtered_paths.map { |path| add_trailing_slash(path) }
34
- end
35
-
36
- def paths_to_remove
37
- @paths.reduce([]) do |to_remove, path|
38
- if File.directory?(path)
39
- to_remove + removable_paths_for(path)
40
- else
41
- to_remove
42
- end
43
- end
44
- end
45
-
46
- def removable_paths_for(path)
47
- file_paths = PathEntries.new(path).entries
48
-
49
- if all_paths_match?(file_paths)
50
- file_paths - [path]
51
- else
52
- [path]
53
- end
54
- end
55
-
56
- def all_paths_match?(paths)
57
- paths.all? { |path| @paths.include?(path) }
58
- end
59
-
60
- def add_trailing_slash(path)
61
- if File.directory?(path) && !path.end_with?("/")
62
- "#{path}/"
63
- else
64
- path
65
- end
66
- end
67
-
68
- def build_entry_combinations(path)
69
- split = path.split("/")
70
-
71
- 0.upto(split.length - 1).map do |n|
72
- split[0..n].join("/")
73
- end
74
- end
75
-
76
- def all_files
77
- @_all_files ||=
78
- Dir.glob("*", File::FNM_DOTMATCH).
79
- reject { |path| IncludePathsBuilder::IGNORE_PATHS.include?(path) }.
80
- flat_map { |path| PathEntries.new(path).entries }
81
- end
82
- end
83
- end
84
- end
@@ -1,46 +0,0 @@
1
- module CC
2
- module Analyzer
3
- class PathPatterns
4
- def initialize(patterns, root = Dir.pwd)
5
- @patterns = patterns
6
- @root = root
7
- end
8
-
9
- def match?(path)
10
- expanded.include?(path)
11
- end
12
-
13
- def expanded
14
- @expanded ||= expand
15
- end
16
-
17
- private
18
-
19
- def expand
20
- results = Dir.chdir(@root) do
21
- @patterns.flat_map do |pattern|
22
- value = glob_value(pattern)
23
- Dir.glob(value)
24
- end
25
- end
26
-
27
- results.sort.uniq
28
- end
29
-
30
- def glob_value(pattern)
31
- # FIXME: there exists a temporary workaround whereby **-style globs
32
- # are translated to **/*-style globs within cc-yaml's custom
33
- # Glob#value method. It was thought that that would work correctly
34
- # with Dir.glob but it turns out we have to actually invoke #value
35
- # directrly for this to work. We need to guard this on class (not
36
- # respond_to?) because our mocking framework adds a #value method to
37
- # all objects, apparently.
38
- if pattern.is_a?(CC::Yaml::Nodes::Glob)
39
- pattern.value
40
- else
41
- pattern
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,7 +0,0 @@
1
- require "fileutils"
2
-
3
- module FileUtils
4
- def self.readable_by_all?(path)
5
- (File.stat(path).mode & 004) != 0
6
- end
7
- end