refactor(cli): enhance file inclusion/exclusion logic
Some checks failed
continuous-integration/drone/push Build is failing

Improves the flexibility and clarity of file processing by introducing
separate include and exclude lists.

- Replace `ignore_list` with `exclude_list` and add `include_list` in
  `.code_preloader.yml`.
- Update `cli.cr` to handle both `include_list` and `exclude_list` for
  file selection.
- Add support for tracing exceptions with a new `trace` configuration
  option.
- Modify `PackOptions` class to include `exclude_list` and
  `include_list` properties.
- Adjust option parsing in `config.cr` to reflect new configuration
  options.

Signed-off-by: Glenn <glenux@glenux.net>
This commit is contained in:
Glenn Y. Rolland 2025-06-16 16:14:09 +02:00
parent e3e091974d
commit aea7979e40
6 changed files with 81 additions and 47 deletions

View file

@ -1,6 +1,9 @@
--- ---
ignore_list: include_list:
- .*cr$
exclude_list:
- ^\.git/.* - ^\.git/.*
- ^\.vagrant/.* - ^\.vagrant/.*
- ^misc/.* - ^misc/.*

View file

@ -92,12 +92,15 @@ module CodePreloader
filelist = FileList.new() filelist = FileList.new()
filelist.add(source_list) filelist.add(source_list)
pack_options.ignore_list.each do |ignore_pattern| pack_options.exclude_list
filelist.reject { |path| !!(path =~ Regex.new(ignore_pattern)) } .map { |exclude_pattern| Regex.new(exclude_pattern) }
end .each { |exclude_regexp| filelist.reject { |path| !!(path =~ exclude_regexp) } }
pack_options.include_list
.map { |include_pattern| Regex.new(include_pattern) }
.each { |include_regexp| filelist.select { |path| !!(path =~ include_regexp) } }
STDERR.puts "Loading template file from: #{prompt_template_path ? prompt_template_path : "<internal>" }".colorize(:yellow) STDERR.puts "Loading template file from: #{prompt_template_path ? prompt_template_path : "<internal>" }".colorize(:yellow)
if prompt_template_path if prompt_template_path
prompt_template_content = File.read(prompt_template_path) prompt_template_content = File.read(prompt_template_path)
else else
prompt_template_content = FileStorage.get("default_template.j2").gets_to_end prompt_template_content = FileStorage.get("default_template.j2").gets_to_end
@ -136,19 +139,22 @@ module CodePreloader
# FIXME: prompt_footer_path.try { output_file.puts prompt_footer_content } # FIXME: prompt_footer_path.try { output_file.puts prompt_footer_content }
output_file.puts Crinja.render( output_file.puts Crinja.render(
prompt_template_content, prompt_template_content,
{ {
"prompt_header": prompt_header_content, "prompt_header": prompt_header_content,
"prompt_files": processed_files, "prompt_files": processed_files,
"prompt_footer": prompt_footer_content "prompt_footer": prompt_footer_content
} }
) )
output_file.close if regular_output_file output_file.close if regular_output_file
STDERR.puts "Processing completed.".colorize(:yellow) STDERR.puts "Processing completed.".colorize(:yellow)
rescue e : Exception rescue e : Exception
STDERR.puts "ERROR: #{e.message}" STDERR.puts "ERROR: #{e.message}"
if @config.trace?
STDERR.puts e.backtrace.map(&.gsub(/^/, " ")).join("\n")
end
exit(1) exit(1)
end end

View file

@ -27,14 +27,16 @@ module CodePreloader
class PackOptions class PackOptions
property config_path : String? = nil property config_path : String? = nil
property source_list : Array(String) = [] of String property source_list : Array(String) = [] of String
property ignore_list : Array(String) = [] of String property exclude_list : Array(String) = [] of String
property include_list : Array(String) = [] of String
property output_path : String? property output_path : String?
property prompt_template_path : String? property prompt_template_path : String?
property prompt_header_path : String? property prompt_header_path : String?
property prompt_footer_path : String? property prompt_footer_path : String?
end end
getter verbose : Bool = false getter? verbose : Bool = false
getter? trace : Bool = false
getter parser : OptionParser? getter parser : OptionParser?
getter subcommand : Subcommand = Subcommand::None getter subcommand : Subcommand = Subcommand::None
getter pack_options : PackOptions? getter pack_options : PackOptions?
@ -60,9 +62,10 @@ module CodePreloader
end end
end end
parser.on( parser.on(
"-c FILE", "-c FILE",
"--config=FILE", "--config=FILE",
"Load parameters from FILE" "Load parameters from FILE"
) do |config_file| ) do |config_file|
@init_options.try { |opt| opt.config_path = config_file } @init_options.try { |opt| opt.config_path = config_file }
@ -83,11 +86,11 @@ module CodePreloader
# complete_with "code-preloader init", parser # complete_with "code-preloader init", parser
end end
def parse_pack_options(parser) def parse_pack_options(parser)
@pack_options = PackOptions.new @pack_options = PackOptions.new
unless ENV["CODE_PRELOADER_DETECT"]? =~ /(no|false|0)/i unless ENV["CODE_PRELOADER_DETECT"]? =~ /(no|false|0)/i
config_file = detect_config_file config_file = detect_config_file
config_file.try { |path| load_pack_config(path) } config_file.try { |path| load_pack_config(path) }
end end
@ -99,48 +102,56 @@ module CodePreloader
parser.separator "\nPack options:" parser.separator "\nPack options:"
parser.on( parser.on(
"-c FILE", "-c FILE",
"--config=FILE", "--config=FILE",
"Load parameters from FILE\n(default: autodetect)" "Load parameters from FILE\n(default: autodetect)"
) do |config_file| ) do |config_file|
@pack_options.try { |opt| load_pack_config(config_file) } @pack_options.try { |opt| load_pack_config(config_file) }
end end
parser.on( parser.on(
"-F FILE", "-F FILE",
"--prompt-footer=FILE", "--prompt-footer=FILE",
"Load prompt footer from FILE (default: none)" "Load prompt footer from FILE (default: none)"
) do |prompt_footer_path| ) do |prompt_footer_path|
@pack_options.try { |opt| opt.prompt_footer_path = prompt_footer_path } @pack_options.try { |opt| opt.prompt_footer_path = prompt_footer_path }
end end
parser.on( parser.on(
"-H FILE", "-H FILE",
"--prompt-header=FILE", "--prompt-header=FILE",
"Load prompt header from FILE (default: none)" "Load prompt header from FILE (default: none)"
) do |prompt_header_path| ) do |prompt_header_path|
@pack_options.try { |opt| opt.prompt_header_path = prompt_header_path } @pack_options.try { |opt| opt.prompt_header_path = prompt_header_path }
end end
parser.on( parser.on(
"-i REGEXP", "-i REGEXP",
"--ignore=REGEXP", "--include=REGEXP",
"Ignore file or directory. Can be used\nmultiple times (default: none)" "Include file or directory. Can be used\nmultiple times (default: none)"
) do |ignore_file| ) do |include_regexp|
@pack_options.try { |opt| opt.ignore_list << ignore_file } @pack_options.try { |opt| opt.include_list << include_regexp }
end end
parser.on( parser.on(
"-o FILE", "-e REGEXP",
"--output=FILE", "--exclude=REGEXP",
"Exclude file or directory. Can be used\nmultiple times (default: none)"
) do |exclude_regexp|
@pack_options.try { |opt| opt.exclude_list << exclude_regexp }
end
parser.on(
"-o FILE",
"--output=FILE",
"Write output to FILE (default: \"-\", STDOUT)" "Write output to FILE (default: \"-\", STDOUT)"
) do |output_file| ) do |output_file|
@pack_options.try { |opt| opt.output_path = output_file } @pack_options.try { |opt| opt.output_path = output_file }
end end
parser.on( parser.on(
"-t FILE", "-t FILE",
"--template=FILE", "--template=FILE",
"Load template from FILE (default: internal)" "Load template from FILE (default: internal)"
) do |prompt_template_path| ) do |prompt_template_path|
@pack_options.try { |opt| opt.prompt_template_path = prompt_template_path } @pack_options.try { |opt| opt.prompt_template_path = prompt_template_path }
@ -186,11 +197,14 @@ module CodePreloader
@verbose = true @verbose = true
end end
parser.on("-t", "--trace", "Show detailed traces for exceptions") do
@trace = true
end
parser.on("--version", "Show version") do parser.on("--version", "Show version") do
@subcommand = Subcommand::Version @subcommand = Subcommand::Version
end end
parser.separator "\nSubcommands:" parser.separator "\nSubcommands:"
parser.on("init", "Create an example .code_preloader.yml file") do parser.on("init", "Create an example .code_preloader.yml file") do
@ -277,11 +291,14 @@ module CodePreloader
if opts.source_list.nil? || opts.source_list.try &.empty? if opts.source_list.nil? || opts.source_list.try &.empty?
root.source_list.try { |value| opts.source_list = value } root.source_list.try { |value| opts.source_list = value }
end end
if opts.ignore_list.nil? || opts.ignore_list.try &.empty? if opts.exclude_list.nil? || opts.exclude_list.try &.empty?
root.ignore_list.try { |value| opts.ignore_list = value } root.exclude_list.try { |value| opts.exclude_list = value }
end
if opts.include_list.nil? || opts.include_list.try &.empty?
root.include_list.try { |value| opts.include_list = value }
end end
if opts.output_path.nil? if opts.output_path.nil?
opts.output_path = root.output_path opts.output_path = root.output_path
end end
if opts.prompt_header_path.nil? if opts.prompt_header_path.nil?
root.prompt.try &.header_path.try { |value| opts.prompt_header_path = value } root.prompt.try &.header_path.try { |value| opts.prompt_header_path = value }

View file

@ -13,13 +13,13 @@ module CodePreloader
end end
@sources : Array(String) @sources : Array(String)
@filters_in : Array(Filter) @include_filters : Array(Filter)
@filters_out : Array(Filter) @exclude_filters : Array(Filter)
def initialize(dirs = [] of String) def initialize(dirs = [] of String)
@sources = [] of String @sources = [] of String
@filters_in = [] of Filter @include_filters = [] of Filter
@filters_out = [] of Filter @exclude_filters = [] of Filter
dirs.each { |dir| self.add(dir) } dirs.each { |dir| self.add(dir) }
end end
@ -34,11 +34,11 @@ module CodePreloader
end end
def select(&filter : Filter) def select(&filter : Filter)
@filters_in << filter @include_filters << filter
end end
def reject(&filter : Filter) def reject(&filter : Filter)
@filters_out << filter @exclude_filters << filter
end end
def each(&block) def each(&block)
@ -56,16 +56,16 @@ module CodePreloader
must_reject = false must_reject = false
clean_path = path.to_s.gsub(/^\.\//,"") clean_path = path.to_s.gsub(/^\.\//,"")
@filters_in.each do |filter_in| @include_filters.each do |filter_in|
must_select = must_select || filter_in.call(clean_path) must_select = must_select || filter_in.call(clean_path)
end end
keep = keep && must_select if @filters_in.any? keep = keep && must_select if @include_filters.any?
keep = keep || is_dir keep = keep || is_dir
@filters_out.each do |filter_out| @exclude_filters.each do |filter_out|
must_reject = must_reject || filter_out.call(clean_path) must_reject = must_reject || filter_out.call(clean_path)
end end
keep = keep && !must_reject if @filters_out.any? keep = keep && !must_reject if @exclude_filters.any?
keep keep
end end

View file

@ -16,7 +16,10 @@ module CodePreloader::Models
@[YAML::Field(key: "prompt")] @[YAML::Field(key: "prompt")]
getter prompt : PromptConfig? getter prompt : PromptConfig?
@[YAML::Field(key: "ignore_list")] @[YAML::Field(key: "exclude_list")]
getter ignore_list : Array(String)? getter exclude_list : Array(String)?
@[YAML::Field(key: "include_list")]
getter include_list : Array(String)?
end end
end end

View file

@ -6,9 +6,14 @@
# - "path/to/repo1" # - "path/to/repo1"
# - "path/to/repo2" # - "path/to/repo2"
# List of patterns to ignore during preloading # List of patterns to exclude (= ignore) during preloading
ignore_list: exclude_list:
- ^\.git/.* - ^\.git/.*
- ".*\\.(png|jpeg|jpg|webp|pdf|mp4|mp3)$"
# List of patterns to include (= limit) during preloading
include_list:
- ".*\\.(md|txt|markdown)$"
# Path to the output file (if null, output to STDOUT) # Path to the output file (if null, output to STDOUT)
output_path: null output_path: null