Module: DocOpsLab::Dev::FileUtilities

Defined in:
lib/docopslab/dev/file_utils.rb

Class Method Summary collapse

Class Method Details

.file_matches_ignore_pattern?(file, pattern) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/docopslab/dev/file_utils.rb', line 103

def file_matches_ignore_pattern? file, pattern
  if pattern.include?('*') || pattern.include?('?')
    # Handle glob patterns
    # If pattern ends with /*, treat it as recursive (dir/**/*)
    recursive_pattern = if pattern.end_with?('/*')
                          pattern.sub(%r{/\*$}, '/**/*')
                        else
                          pattern
                        end

    File.fnmatch(recursive_pattern, file, File::FNM_PATHNAME | File::FNM_DOTMATCH) ||
      # Also try exact match without modification for explicit patterns
      File.fnmatch(pattern, file, File::FNM_PATHNAME | File::FNM_DOTMATCH)
  else
    # Non-glob patterns: match directory name anywhere in path
    File.fnmatch("**/#{pattern}/**", file, File::FNM_PATHNAME | File::FNM_DOTMATCH) ||
      File.fnmatch("**/#{pattern}", file, File::FNM_PATHNAME | File::FNM_DOTMATCH)
  end
end

.find_asciidoc_files(context) ⇒ Object



99
100
101
# File 'lib/docopslab/dev/file_utils.rb', line 99

def find_asciidoc_files context
  FileUtilities.find_files_to_lint('vale', context)
end

.find_files_to_lint(tool_slug, context) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/docopslab/dev/file_utils.rb', line 48

def find_files_to_lint tool_slug, context
  path_config = context.get_path_config(tool_slug)
  lint_paths = path_config[:lint]
  skip_paths = path_config[:skip]
  exts = path_config[:exts]
  git_tracked_only = path_config[:git_tracked_only]

  return [] unless lint_paths

  files = []
  lint_paths.each do |path|
    # If path is a directory, search recursively. Otherwise, it's a glob.
    glob_pattern = File.directory?(path) ? File.join(path, '**', '*') : path
    Dir.glob(glob_pattern).each do |file|
      next unless File.file?(file)

      # Normalize path by removing ./ prefix for consistent pattern matching
      normalized = file.sub(%r{^\./}, '')
      files << normalized
    end
  end

  files.uniq!

  # Filter by extension if exts is provided
  if exts && !exts.empty?
    files.select! do |file|
      ext = File.extname(file).delete_prefix('.')
      exts.include?(ext)
    end
  end

  # Filter out ignored paths
  files.reject! do |file|
    should_skip = skip_paths.any? do |ignored|
      FileUtilities.file_matches_ignore_pattern?(file, ignored)
    end
    should_skip
  end

  # Filter by git tracking status
  if git_tracked_only
    files.select! do |file|
      is_tracked = FileUtilities.git_tracked_or_staged?(file)
      is_tracked
    end
  end

  files.sort
end

.find_shell_scripts(context) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/docopslab/dev/file_utils.rb', line 9

def find_shell_scripts context
  # First, try to find files using the new path configuration system
  files = find_files_to_lint('shellcheck', context)
  return files if files && !files.empty?

  # Fallback to old method if no paths are configured for shellcheck
  scripts = []
  patterns = [
    '**/*.sh',
    '**/*.bash',
    '**/.*rc',
    '**/.*profile',
    'scripts/*.sh'
  ]
  patterns.each do |pattern|
    Dir.glob(pattern).each do |file|
      next unless File.file?(file)
      next if file.include?('/.vendor/')
      next if file.include?('/node_modules/')
      next unless FileUtilities.git_tracked_or_staged?(file)

      scripts << file if File.executable?(file) || FileUtilities.shell_shebang?(file)
    end
  end
  scripts.uniq.sort
end

.git_tracked_or_staged?(file) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/docopslab/dev/file_utils.rb', line 123

def git_tracked_or_staged? file
  return true unless Dir.exist?('.git')

  repo_root = `git rev-parse --show-toplevel`.strip
  rel = Pathname.new(file).expand_path.relative_path_from(Pathname.new(repo_root)).to_s

  # Check if the file is tracked
  return true if system('git', 'ls-files', '--error-unmatch', rel, out: File::NULL, err: File::NULL)

  # Check if the file is staged (but not necessarily committed yet)
  return true if system('git', 'diff', '--name-only', '--cached', '--', rel, out: File::NULL, err: File::NULL)

  false
end

.shell_shebang?(file) ⇒ Boolean

Returns:

  • (Boolean)


36
37
38
39
40
41
42
43
44
45
46
# File 'lib/docopslab/dev/file_utils.rb', line 36

def shell_shebang? file
  return false unless File.readable?(file)

  first_line = File.open(file, 'r') do |f|
    f.readline
  rescue StandardError
    ''
  end
  first_line.start_with?('#!') &&
    (first_line.include?('sh') || first_line.include?('bash'))
end