Class: Condenser::BuildCache

Inherits:
Object
  • Object
show all
Defined in:
lib/condenser/build_cache.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, logger:, listen: {}) ⇒ BuildCache

Returns a new instance of BuildCache.



6
7
8
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
35
36
37
38
39
40
41
42
43
44
45
46
47
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/condenser/build_cache.rb', line 6

def initialize(path, logger:, listen: {})
  @logger = logger
  @path = path
  @map_cache = {}
  @lookup_cache = {}
  @process_dependencies = {}
  @export_dependencies = {}
  @listening = if listen
    require 'listen'
    Listen::Adapter.select != Listen::Adapter::Polling
  else
    false
  end
  
  if !@listening
    @polling = false
  else
    @semaphore = Mutex.new
    @listener = Listen.to(*path) do |modified, added, removed|
      modified = Set.new(modified)
      added = Set.new(added)
      removed = Set.new(removed)
      
      @semaphore.synchronize do
        @logger.debug { "build cache semaphore locked by #{Thread.current.object_id}" }
        @logger.debug do
          (
            removed.map { |f| "Asset removed: #{f}" } +
            added.map { |f| "Asset created: #{f}" } +
            modified.map { |f| "Asset updated: #{f}" }
          ).join("\n")
        end

        globs = []
        (added + removed + modified).each do |file|
          globs << file.match(/([^\.]+)(\.|$)/).to_a[1]
          if path_match = @path.find { |p| file.start_with?(p) }
            a = file.delete_prefix(path_match).match(/([^\.]+)(\.|$)/).to_a[1]
            b = File.join(File.dirname(a), "*")
          
            globs << a << a.delete_prefix('/')
            globs << b << b.delete_prefix('/')
          end
        end

        others = []
        @map_cache&.delete_if do |k,v|
          if globs.any?{ |a| k.starts_with?(a) }
            @export_dependencies[v.source_file]&.each do |a| 
              others << "/#{a.filename}".delete_suffix(File.extname(a.filename))
            end
            true
          else
            false
          end
        end
        @map_cache&.delete_if do |k,v|
          others.any?{ |a| k.starts_with?(a) || k.starts_with?("/" + a) }
        end
        
        others = []
        @lookup_cache.delete_if do |key, value|
          if globs.any?{ |a| key.starts_with?(a) }
            value.each do |v|
              @export_dependencies[v.source_file]&.each do |a| 
                others << "/#{a.filename}".delete_suffix(File.extname(a.filename))
              end
            end
            value.each do |asset|
              modified << asset.source_file
            end
            true
          end
        end
        @lookup_cache&.delete_if do |k,v|
          others.any?{ |a| k.starts_with?(a) || k.starts_with?("/" + a) }
        end
        

        
        removed.each do |file|
          @process_dependencies[file]&.delete_if do |asset|
            if asset.source_file == file
              true
            else
              asset.needs_reprocessing!
              false
            end
          end
        
          @export_dependencies[file]&.delete_if do |asset|
            if asset.source_file == file
              true
            else
              asset.needs_reexporting!
              false
            end
          end
        end
        
        modified.each do |file|
          @process_dependencies[file]&.each do |asset|
            asset.needs_reprocessing!
          end
        
          @export_dependencies[file]&.each do |asset|
            asset.needs_reexporting!
          end
        end

        @logger.debug { "build cache semaphore unlocked by #{Thread.current.object_id}" }
      end
    end
    @listener.start
  end
end

Instance Attribute Details

#listeningObject (readonly)

Returns the value of attribute listening.



4
5
6
# File 'lib/condenser/build_cache.rb', line 4

def listening
  @listening
end

#loggerObject (readonly)

Returns the value of attribute logger.



4
5
6
# File 'lib/condenser/build_cache.rb', line 4

def logger
  @logger
end

#semaphoreObject (readonly)

Returns the value of attribute semaphore.



4
5
6
# File 'lib/condenser/build_cache.rb', line 4

def semaphore
  @semaphore
end

Instance Method Details

#[](value) ⇒ Object



152
153
154
# File 'lib/condenser/build_cache.rb', line 152

def [](value)
  @lookup_cache[value]
end

#[]=(value, assets) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/condenser/build_cache.rb', line 127

def []=(value, assets)
  @lookup_cache[value] = assets
  
  if @fetching.nil?
    begin
      assets.each do |asset|
        @fetching = Set.new
        asset.all_process_dependencies(@fetching).each do |pd|
          @process_dependencies[pd] ||= Set.new
          @process_dependencies[pd] << asset
        end

        @fetching = Set.new
        asset.all_export_dependencies(@fetching).each do |pd|
          @export_dependencies[pd] ||= Set.new

          @export_dependencies[pd] << asset
        end
      end
    ensure
      @fetching = nil
    end
  end
end

#fetch(key) ⇒ Object



156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/condenser/build_cache.rb', line 156

def fetch(key)
  value = self[key]
  
  if value.nil?
    value = yield
    if (value.is_a?(Array) ? !value.empty? : value)
      self[key] = value
    end
  end
  
  value
end

#map(key) ⇒ Object



123
124
125
# File 'lib/condenser/build_cache.rb', line 123

def map(key)
  @map_cache[key] ||= yield
end