Class: DGD::Manifest::AppFile

Inherits:
Object
  • Object
show all
Defined in:
lib/dgd-tools/manifest.rb

Overview

This class parses the DGD manifest

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(repo, path, shared_dir:) ⇒ AppFile

Returns a new instance of AppFile.



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
# File 'lib/dgd-tools/manifest.rb', line 247

def initialize(repo, path, shared_dir:)
    @path = path
    @repo = repo
    @shared_dir = shared_dir
    raise("No such dgd.manifest file as #{path.inspect}!") unless File.exist?(path)
    contents = AppFile.parse_manifest_file(path)

    read_manifest_file(contents)

    output_paths = @specs.flat_map { |s| s.paths.values }
    unless output_paths == output_paths.uniq
        repeated_paths = output_paths.select { |p| output_paths.count(p) > 1 }
        raise "Repeated (conflicting?) paths in dgd.manifest! #{repeated_paths.inspect}"
    end

    ## Make sure the dgd.manifest file overrides either no kernel paths or both/all
    #if KERNEL_PATHS.any? { |kp| output_paths.include?(kp) }
    #    unless KERNEL_PATHS.all? { |kp| output_paths.include?(kp) }
    #        raise "dgd.manifest file #{path.inspect} includes some Kernel Library paths but not all! All needed: #{KERNEL_PATHS}!"
    #    end
    #    puts "This dgd.manifest file overrides the Kernel Library with its own."
    #else
    #    puts "This dgd.manifest needs the default Kernel Library."
    #    # This app has specified no kernellib paths -- add them
    #    spec_git_repo = @repo.git_repo(DEFAULT_KERNELLIB_URL)
    #    klib_spec = GoodsSpec.new @repo, name: "default Kernel Library",
    #        source: spec_git_repo, paths: KERNEL_PATH_MAP
    #    specs.unshift klib_spec
    #end

    nil
end

Instance Attribute Details

#dgd_configObject (readonly)

Returns the value of attribute dgd_config.



244
245
246
# File 'lib/dgd-tools/manifest.rb', line 244

def dgd_config
  @dgd_config
end

#pathObject (readonly)

Returns the value of attribute path.



241
242
243
# File 'lib/dgd-tools/manifest.rb', line 241

def path
  @path
end

#repoObject (readonly)

Returns the value of attribute repo.



242
243
244
# File 'lib/dgd-tools/manifest.rb', line 242

def repo
  @repo
end

#shared_dirObject (readonly)

Returns the value of attribute shared_dir.



245
246
247
# File 'lib/dgd-tools/manifest.rb', line 245

def shared_dir
  @shared_dir
end

#specsObject (readonly)

Returns the value of attribute specs.



243
244
245
# File 'lib/dgd-tools/manifest.rb', line 243

def specs
  @specs
end

Class Method Details

.parse_manifest_file(path) ⇒ Object

Load the JSON and then remove comments



281
282
283
284
285
# File 'lib/dgd-tools/manifest.rb', line 281

def self.parse_manifest_file(path)
    contents = JSON.parse(File.read path)
    remove_comments!(contents)
    contents
end

.remove_comments!(items) ⇒ Object



287
288
289
290
291
292
293
294
295
# File 'lib/dgd-tools/manifest.rb', line 287

def self.remove_comments!(items)
    if items.is_a?(Hash)
        items.delete_if { |k, v| k[0] == "#" }
        items.values.each { |v| remove_comments!(v) }
    elsif items.is_a?(Array)
        items.delete_if { |i| i.is_a?(String) && i[0] == "#" }
        items.each { |i| remove_comments!(i) }
    end
end

Instance Method Details

#app_rootObject



332
333
334
# File 'lib/dgd-tools/manifest.rb', line 332

def app_root
    @dgd_config.app_root
end

#ordered_specsObject



381
382
383
384
385
386
387
388
389
390
391
392
# File 'lib/dgd-tools/manifest.rb', line 381

def ordered_specs
    @specs.flat_map do |s|
        deps = [s]
        deps_to_add = s.dependencies
        while(deps_to_add.size > 0)
            next_deps = deps_to_add.flat_map { |dep| dep.dependencies }
            deps = deps_to_add + deps
            deps_to_add = next_deps
        end
        deps
    end
end

#read_manifest_file(contents) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/dgd-tools/manifest.rb', line 297

def read_manifest_file(contents)
    raise "Expected a top-level JSON object in dgd.manifest!" unless contents.is_a?(Hash)

    @specs = []

    @dgd_config = DGDRuntimeConfig.new (contents["config"] || {})

    if contents["app_root"]
        raise "App_root must now be inside config block!"
    end

    if contents["unbundled_goods"]
        raise "Unbundled_goods must be an array!" unless contents["unbundled_goods"].is_a?(Array)

        @specs += contents["unbundled_goods"].map { |item| unbundled_json_to_spec(item) }
    end

    if contents["goods"]
        raise "Goods must be an array!" unless contents["goods"].is_a?(Array)

        @specs += contents["goods"].map do |goods_url|
            begin
                text_contents = URI.open(goods_url).read
                local_path = shared_dir + "/goods/" + goods_url.tr("/\\ ", "_")
                File.open(local_path, "wb") { |f| f.write(text_contents) }
                json_contents = JSON.parse text_contents
            rescue
                STDERR.puts "Error reading or parsing by URL: #{goods_url.inspect}"
                raise
            end
            unbundled_json_to_spec(json_contents)
        end
    end
end

#unbundled_json_to_spec(fields) ⇒ Object



336
337
338
339
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
# File 'lib/dgd-tools/manifest.rb', line 336

def unbundled_json_to_spec(fields)
    source = nil
    source_details = nil
    dependencies = []

    if fields["git"]
        raise "A git source requires a git url: #{fields.inspect}!" unless fields["git"]["url"]
        source = @repo.git_repo(fields["git"]["url"])
        source_details = fields["git"]  # May contain branch info, etc.
    else
        raise "DGD Manifest currently requires a Git-based source!"
    end

    unless fields["paths"].all? { |k, v| k.is_a?(String) && v.is_a?(String) }
        raise "Paths in Goods files must map strings to strings! #{fields["paths"].inspect}"
    end

    if fields["dependencies"]
        # For now, permit a single string as a dependency.
        fields["dependencies"] = [ fields["dependencies"] ] if fields["dependencies"].is_a?(String)

        goods_url = nil
        fields["dependencies"].each do |dep|
            if dep.is_a?(String)
                goods_url = dep
            elsif dep.is_a?(Hash)
                raise "Currently only URL-based dependencies on Goods files are supported!" unless dep["url"]
                goods_url = dep["url"]
            else
                raise "Unexpected dependency type #{dep.class} when parsing DGD Manifest specs, item: #{dep.inspect}"
            end

            text_contents = URI.open(goods_url).read
            local_path = shared_dir + "/goods/" + goods_url.tr("/\\ ", "_")
            File.open(local_path, "wb") { |f| f.write(text_contents) }
            dep_fields = JSON.parse text_contents

            dependencies.push unbundled_json_to_spec(dep_fields)
        end
    end

    spec = GoodsSpec.new(@repo, name: fields["name"], source: source, source_details: source_details, paths: fields["paths"], dependencies: dependencies)
    return spec
end