Class: SC::Manifest

Inherits:
HashStruct show all
Defined in:
lib/sproutcore/models/manifest.rb

Overview

A Manifest describes all of the files that should be found inside of a single bundle/language. A Manifest can have global properties assigned to it which will be used by the manifest entries themselves. This is largly defined by the manifest build tasks.

Defined Under Namespace

Classes: EntryList

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from HashStruct

#deep_clone, #has_options?, #merge, #merge!, #method_missing, #print_first_caller

Constructor Details

#initialize(target, opts) ⇒ Manifest

Returns a new instance of Manifest.



30
31
32
33
34
35
# File 'lib/sproutcore/models/manifest.rb', line 30

def initialize(target, opts)
  super(opts)
  @target = target
  @entries = EntryList.new
  @staging_uuid = 0
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class SC::HashStruct

Instance Attribute Details

#targetObject (readonly)

Returns the value of attribute target.



18
19
20
# File 'lib/sproutcore/models/manifest.rb', line 18

def target
  @target
end

Instance Method Details

#add_composite(filename, opts = {}) ⇒ Object

Creates a composite entry with the passed filename. Expects you to a source_entries option. This automatically hides the source entries unless you pass the :hide_entries => false option.



207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/sproutcore/models/manifest.rb', line 207

def add_composite(filename, opts = {})
  should_hide_entries = opts.delete(:hide_entries)
  should_hide_entries = true if should_hide_entries.nil?

  opts[:filename] = filename
  opts[:source_entries] ||= []
  opts[:composite] = true
  @entries << (ret = ManifestEntry.new(self, opts)).prepare!

  ret[:source_entries].each { |entry| entry.hide! } if should_hide_entries
  return ret
end

#add_entry(filename, opts = {}) ⇒ Object

Creates a new manifest entry with the passed options. Will setup extra tracking needed by entry.

Params

opts:: the options you want to set on the entry

Returns

the new manifest entry


198
199
200
201
202
# File 'lib/sproutcore/models/manifest.rb', line 198

def add_entry(filename, opts = {})
  opts[:filename] = filename
  @entries << (ret = ManifestEntry.new(self, opts)).prepare!
  return ret
end

#add_transform(entry, opts = {}) ⇒ Object

Creates an entry with will apply a build task to the source entry. Use this method when you need to apply a build task to an entry to convert it into another format or to perform some kind of incremental build.

Params

entry:: the entry that should be the source of the transform

Options

You can assign any options you like and they will be copied onto the new entry. The following options, however, have special meaning:

:build_task:: name the new build task you use.  otherwise uses copy
:ext:: the new file extension. if you don't override, the build_path
  staging_path and filename will all be adjusted to have this ext.
:hide_entry:: the source entry will be hidden unless set to false

Returns

the new ManifestEntry


238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/sproutcore/models/manifest.rb', line 238

def add_transform(entry, opts ={})
  should_hide_entries = opts.delete(:hide_entries) || opts.delete(:hide_entry)
  should_hide_entries = true if should_hide_entries.nil?

  # Clone important properties to new transform...
  opts = HashStruct.new(opts)

  opts[:filename]   ||= entry[:filename]
  opts[:build_path] ||= entry[:build_path]
  opts[:url]        ||= entry[:url]

  # generate a unique staging path.  If the original entry has its
  # staging_path set == to source_root (optimization for build:copy), then
  # first rebase staging path against the staging root.
  if (staging_path = entry[:staging_path]) == entry[:source_path]
    staging_path = File.join(self[:staging_root], entry[:filename])
  end

  opts[:staging_path] ||= unique_staging_path(staging_path)

  # generate a unique cache path from the staging page.  just sub the
  # staging root for the cache root
  opts[:cache_path] ||= unique_cache_path(entry[:cache_path])

  # copy other useful entries
  opts[:source_entry]   = entry
  opts[:source_entries] = [entry]
  opts[:composite]      = true
  opts[:transform]      = true # make .transform? = true

  # Normalize to new extension if provided.  else copy ext from entry...
  if ext = opts[:ext]
    opts[:url] = opts[:url].ext(ext)
    opts[:staging_path] = opts[:staging_path].ext(ext)
    opts[:build_path] = opts[:build_path].ext(ext)
    opts[:filename] = opts[:filename].ext(ext)
  else
    opts[:ext] = entry[:ext]
  end

  # Create new entry and hide old one
  @entries << (ret = ManifestEntry.new(self, opts)).prepare!

  entry.hide! if should_hide_entries

  # done!
  return ret
end

#build!Object

Builds the manifest if it has not been built yet.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/sproutcore/models/manifest.rb', line 80

def build!
  prepare!
  if !@is_built
    @is_built = true
    if target.buildfile.task_defined? 'manifest:build'
      target.buildfile.invoke 'manifest:build',
        :manifest => self,
        :target => self.target,
        :config => self.target.config,
        :project => self.target.project
    end

    # Information indicating where the built app can be found. This is useful
    # when manually uploading builds, to ensure we have the newest build.
    if target[:target_type] == :app
      SC.logger.info "Built #{target[:target_name]} to #{target[:build_root]}/#{target[:build_number]}"
    end
  end
  return self
end

#built?Boolean

Returns:

  • (Boolean)


101
# File 'lib/sproutcore/models/manifest.rb', line 101

def built?; @is_built; end

#entries(opts = {}) ⇒ Object



20
21
22
# File 'lib/sproutcore/models/manifest.rb', line 20

def entries(opts = {})
  opts[:hidden] ? @entries : @entries.visible
end

#entry_for(filename, opts = {}) ⇒ Object

Finds the first visible entry with the specified filename. You may also pass any number of additional options which will be used to further restrict your search. If you pass :hidden => true only hidden entries will be returned. Otherwise, only visible entries will be returned.

You may also include the name of the target you would like to search. The target name should be relative to the target you are requesting from.

Examples

entry = manifest.entry_for('javascript.js')
  => returns local javascript.js entry

entry = manifest.entry_for('sproutcore:javascript.js')
  => returns entry for javascript.js in 'sproutcore' bundle

entry = manifest.entry_for('sproutcore/costello:javascript.js')

Params

filename:: the filename to search

Options

:hidden:: if true, include hidden entries

Returns

the manifest entry


315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/sproutcore/models/manifest.rb', line 315

def entry_for(filename, opts = {})
  target_name, filename = filename.split(':')
  if filename.nil?  # no targetname given...
    manifest = self
    filename = target_name
  else
    if (_manifest_target = target.target_for(target_name)).nil?
      throw "Cannot file target #{target_name} for entry #{filename}"
    end
    manifest = _manifest_target.manifest_for(self.variation)
    manifest.build!
  end

  manifest.entries(opts).find do |entry|
    (entry[:filename] == filename) && entry.has_options?(opts)
  end
end

#find_entry(fragment, opts = {}, seen = nil) ⇒ Object

Attempts to find any entry matching the specified static URL fragment. the fragment you pass may contain only a portion of the url, and it may exclude the file extension if you choose. The filter will select the entry with the broadest match possible.

This is the root search method used by static_url().



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# File 'lib/sproutcore/models/manifest.rb', line 340

def find_entry(fragment, opts = {}, seen=nil)

  entry_extname = entry_rootname = ret = target_name = nil

  # optionally you can specify an explicit target name
  split_index = fragment.to_s.index(':') # find first index
  unless split_index.nil?
    target_name = '/' + fragment[0..(split_index-1)] if split_index>0
    fragment    = fragment[(split_index+1)..-1] # remove colon
  end

  # find the current manifest
  if target_name
    cur_target = self.target.target_for(target_name) || self.target
    cur_manifest = cur_target.manifest_for(self.variation).build!
  else
    cur_manifest = self
  end

  extname = File.extname(fragment.to_s)
  extname = nil if extname.empty?

  # Add leading slash and remove extension
  rootname = fragment.to_s.sub(/\/?/, '/').sub(/#{extname}$/, '')

  # look on our own target only if target is named
  ret = cur_manifest.entries(opts).find do |entry|
    next unless entry.has_options?(opts)
    next if extname && (entry.extension != extname)

    normalized_rootname = entry.rootname.sub!(/\/?/, '/') # Add leading slash
    normalized_rootname[-rootname.length, rootname.length] == rootname
  end

  return ret if ret

  # if no match was found, search the same manifests in required targets
  seen ||= Set.new
  seen << cur_manifest.target

  cur_manifest.target.expand_required_targets(:theme => true).each do |t|
    next if seen.include?(t) # avoid recursion

    manifest = t.manifest_for(self.variation).build!
    ret = manifest.find_entry(fragment, opts, seen)
    return ret if ret
  end

  nil
end

#inspectObject



37
38
39
40
41
42
# File 'lib/sproutcore/models/manifest.rb', line 37

def inspect
  opts = variation.dup
  opts[:target] = target[:target_name]
  desc = opts.keys.sort { |a,b| a.to_s <=> b.to_s }.map { |k| [k, opts[k]].join("=") }.join(" ")
  "SC::Manifest(#{desc})"
end

#load(hash) ⇒ Object

Loads a hash into the manifest, replacing whatever contents are already here.

Params

hash:: the hash loaded from disk

Returns

Manifest (self)


178
179
180
181
182
183
184
185
186
187
# File 'lib/sproutcore/models/manifest.rb', line 178

def load(hash)
  merge!(hash)
  entry_hashes = self.delete(:entries) || []
  @entries = EntryList.new
  entry_hashes.each do |opts|
    @entries << ManifestEntry.new(self, opts)
  end

  return self
end

#prepare!Object

Invoked just before a manifest is built. If you load a manifest file this method will not be invoked.

Returns

self


48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/sproutcore/models/manifest.rb', line 48

def prepare!
  if !@is_prepared
    @is_prepared = true
    target.prepare!
    if target.buildfile.task_defined? 'manifest:prepare'
      target.buildfile.invoke 'manifest:prepare',
        :manifest => self,
        :target => self.target,
        :config => self.target.config,
        :project => self.target.project
    end
  end
  return self
end

#prepared?Boolean

Returns:

  • (Boolean)


63
# File 'lib/sproutcore/models/manifest.rb', line 63

def prepared?; @is_prepared || false; end

#reset!Object

Resets this manifest, and all same-variation manifests the target depends on. This is useful when building: it clears the entries and frees up memory so building doesn’t take multiple gigabytes.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/sproutcore/models/manifest.rb', line 108

def reset!
  return if @is_resetting
  @is_resetting = true

  targets = target.expand_required_targets({ :theme => true }) + [target]
  entries = targets.map do |t|
    t.manifest_for(variation).reset!
  end

  targets = target.modules({ :debug => false, :test => false, :theme => true }).each do |t|
    t.manifest_for(variation).reset!
  end

  reset_entries!

  @is_resetting = false

  return self
end

#reset_entries!Object

Resets the manifest entries. this is called before a build is performed. This will reset only the entries, none of the other props.

Returns

Manifest (self)


134
135
136
137
138
139
# File 'lib/sproutcore/models/manifest.rb', line 134

def reset_entries!
  @is_built = false
  self.delete(:entries)
  @entries = EntryList.new
  return self
end

#to_hash(opts = {}) ⇒ Object

Returns the manifest as a hash that can be serialized to json or yaml



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/sproutcore/models/manifest.rb', line 142

def to_hash(opts={})
  ret = super()

  if only_keys = opts[:only]
    filtered = {}
    ret.each do |key, value|
      filtered[key] = value if only_keys.include?(key)
    end
    ret = filtered
  end

  # Always include entries unless they are explicitly excluded
  ret[:entries] = entries(opts).map { |e| e.to_hash(opts) }

  if except_keys = opts[:except]
    filtered = {}
    ret.each do |key, value|
      filtered[key] = value unless except_keys.include?(key)
    end
    ret = filtered
  end

  # always add target name. needed to reload
  ret[:target_name] = target.target_name
  return ret
end

#unique_cache_path(path) ⇒ Object

Finds a unique cache path starting with the root proposed staging path.



403
404
405
406
407
408
409
# File 'lib/sproutcore/models/manifest.rb', line 403

def unique_cache_path(path)
  # paths = entries(:hidden => true).map { |e| e[:cache_path] }
  # while paths.include?(path)
  #   path = path.sub(/(__\$[0-9]+)?(\.\w+)?$/,"__#{next_staging_uuid}\\2")
  # end
  return path
end

#unique_staging_path(path) ⇒ Object

Finds a unique staging path starting with the root proposed staging path.



393
394
395
396
397
398
399
# File 'lib/sproutcore/models/manifest.rb', line 393

def unique_staging_path(path)
  # paths = entries(:hidden => true).map { |e| e[:staging_path] }
  # while paths.include?(path)
  #   path = path.sub(/(__\$[0-9]+)?(\.\w+)?$/,"__#{next_staging_uuid}\\2")
  # end
  return path
end

#variationObject

Returns the options that select the current variation. The current implementation is hardcoded to return the language, but this may be generalized in the future.

You can use this method to select the same manifest in other targets.

Examples

other_manifest = other_target.manifest_for(my_manifest.variation)


75
76
77
# File 'lib/sproutcore/models/manifest.rb', line 75

def variation
  return { :language => self[:language] }
end