Module: RSMP::SXL::Processing::Manifest

Defined in:
lib/rsmp/sxl/processing/manifest.rb

Overview

Creates and verifies deterministic SXL manifests.

Constant Summary collapse

TOP_LEVEL_KEYS =
%w[meta sxls].freeze
META_KEYS =
%w[created_at created_by format].freeze

Class Method Summary collapse

Class Method Details

.create(documents, format:, now: Time.now) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/rsmp/sxl/processing/manifest.rb', line 13

def self.create(documents, format:, now: Time.now)
  validate_documents!(documents, format)
  {
    'meta' => {
      'created_at' => now.utc.iso8601,
      'created_by' => "rsmp v#{RSMP::VERSION}",
      'format' => format.to_s
    },
    'sxls' => NaturalSort.sort(documents.map(&:name)).to_h do |name|
      document = documents.find { |candidate| candidate.name == name }
      [name, document.version_string]
    end
  }
end

.dump(manifest) ⇒ Object



28
29
30
# File 'lib/rsmp/sxl/processing/manifest.rb', line 28

def self.dump(manifest)
  Psych.safe_dump(manifest, permitted_classes: [], aliases: false, line_width: -1)
end

.load(path) ⇒ Object



32
33
34
35
36
37
38
39
# File 'lib/rsmp/sxl/processing/manifest.rb', line 32

def self.load(path)
  raise Error, "Manifest #{path} not found" unless File.exist?(path)
  raise Error, "Manifest #{path} is not a file" unless File.file?(path)

  parse(File.read(path, encoding: 'UTF-8'), path: path)
rescue EncodingError => e
  raise Error, "Cannot read manifest #{path}: #{e.message}"
end

.parse(source, path: '(manifest)') ⇒ Object



41
42
43
44
45
# File 'lib/rsmp/sxl/processing/manifest.rb', line 41

def self.parse(source, path: '(manifest)')
  Psych.safe_load(source, permitted_classes: [Date, Time], permitted_symbols: [], aliases: false)
rescue Psych::Exception => e
  raise Error, "Cannot read manifest #{path}: #{e.message}"
end

.validate_documents!(documents, format) ⇒ Object

Raises:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rsmp/sxl/processing/manifest.rb', line 55

def self.validate_documents!(documents, format)
  format_version = VersionRequirement.exact_version(format, label: 'manifest format')
  documents.each do |document|
    next unless document.minimum_core_version && document.minimum_core_version > format_version

    raise Error,
          "SXL #{document.name} #{document.version_string} requires Core " \
          "#{document.minimum_core_version}, newer than manifest format #{format}"
  end
  cycle = DependencyGraph.cycle(documents)
  raise Error, "Cyclic dependency #{cycle.join(' -> ')}" if cycle

  ConflictChecker.check!(documents)
end

.verify!(manifest, catalogue) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/rsmp/sxl/processing/manifest.rb', line 47

def self.verify!(manifest, catalogue)
  meta, sxls = validate_shape!(manifest)
  documents = load_documents!(sxls, catalogue)
  validate_dependency_closure!(documents, sxls)
  validate_documents!(documents, meta['format'])
  documents
end