Class: Everywhere::Ignore

Inherits:
Object
  • Object
show all
Defined in:
lib/everywhere/ignore.rb

Overview

Shared source-exclusion rules, read from .everywhereignore (dockerignore style) when present, else a sensible default. ONE source of truth so the build receipt's source checksum (Receipt) and the Platform snapshot (every platform build, later) describe exactly the same set of files — a checksum that didn't match what actually ships would be worse than none.

Pattern semantics are a pragmatic subset of .dockerignore/.gitignore:

dist            → a path segment named "dist", anywhere
vendor/bundle   → that exact path (and everything under it)
*.log           → glob against the full path and the basename
!keep/this.log  → NEGATION: re-include a file an earlier pattern excluded

Rules are evaluated top to bottom and the LAST one that matches a path wins (dockerignore semantics), so ordering matters: put ! re-includes after the broad exclude they carve out of.

Constant Summary collapse

FILE =
".everywhereignore"
FLAGS =
File::FNM_PATHNAME | File::FNM_DOTMATCH
DEFAULTS =

Build products, caches, VCS, local state, and secrets. Excluding .env* and the key/cert family keeps signing material out of both the checksum and any future snapshot.

%w[
  dist tmp log node_modules .git storage .bundle vendor/bundle
  coverage public/assets public/packs .DS_Store .env* *.log
  *.key *.pem *.crt *.p12 *.mobileprovision
].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rules) ⇒ Ignore

Returns a new instance of Ignore.



53
54
55
# File 'lib/everywhere/ignore.rb', line 53

def initialize(rules)
  @rules = rules
end

Instance Attribute Details

#rulesObject (readonly)

Returns the value of attribute rules.



51
52
53
# File 'lib/everywhere/ignore.rb', line 51

def rules
  @rules
end

Class Method Details

.for(root) ⇒ Object



32
33
34
35
36
# File 'lib/everywhere/ignore.rb', line 32

def self.for(root)
  path = File.join(root, FILE)
  source = File.exist?(path) ? File.read(path) : DEFAULTS.join("\n")
  new(parse(source))
end

.parse(text) ⇒ Object

→ [{ negated:, pattern: }, ...] in file order. Blank lines and whole-line # comments are dropped; a leading ! marks a re-include.



40
41
42
43
44
45
46
47
48
49
# File 'lib/everywhere/ignore.rb', line 40

def self.parse(text)
  text.lines.filter_map do |raw|
    line = raw.chomp
    next if line.strip.empty? || line.lstrip.start_with?("#")

    negated = line.start_with?("!")
    pattern = (negated ? line[1..] : line).strip.sub(%r{\A/}, "").chomp("/")
    { negated: negated, pattern: pattern } unless pattern.empty?
  end
end

Instance Method Details

#files(root) ⇒ Object

Every non-ignored regular file under root, as sorted root-relative paths.



58
59
60
61
62
63
# File 'lib/everywhere/ignore.rb', line 58

def files(root)
  Dir.glob("**/*", File::FNM_DOTMATCH, base: root)
    .reject { |rel| ignored?(rel) }
    .select { |rel| File.file?(File.join(root, rel)) }
    .sort
end

#ignored?(rel) ⇒ Boolean

Last matching rule wins; a negated match re-includes. Default: kept.

Returns:

  • (Boolean)


66
67
68
69
70
71
72
73
# File 'lib/everywhere/ignore.rb', line 66

def ignored?(rel)
  base = rel.split("/").last
  return true if [".", ".."].include?(base)

  @rules.reduce(false) do |ignored, rule|
    match?(rule[:pattern], rel, base) ? !rule[:negated] : ignored
  end
end