109 lines
2.8 KiB
Ruby
109 lines
2.8 KiB
Ruby
require "yaml"
|
|
require "digest"
|
|
|
|
module Picop
|
|
class SourceFile
|
|
attr_reader :content, :metadata, :code, :original_path
|
|
|
|
METADATA_PATTERN = /^\n*#\s*@PICOPACKAGE_START\n(.*?)^\s*#\s*@PICOPACKAGE_END\s*$/m
|
|
|
|
def self.from_file(file_path) = new(content: File.read(file_path), original_path: file_path)
|
|
|
|
def self.from_content(content, filename: nil)
|
|
instance = new(content: content)
|
|
if filename && !instance.metadata['filename']
|
|
metadata = instance.metadata.merge('filename' => filename)
|
|
instance.update_metadata(metadata) #TODO: FIX THIS
|
|
end
|
|
instance
|
|
end
|
|
|
|
def initialize(content:, original_path: nil)
|
|
@original_path = original_path
|
|
|
|
@content = content
|
|
@metadata = extract_metadata
|
|
@code = extract_code
|
|
end
|
|
|
|
def filename = @metadata['filename']
|
|
|
|
def version = @metadata['version'] || '0.0.0'
|
|
|
|
def checksum = "sha256:#{Digest::SHA256.hexdigest(code)}"
|
|
|
|
def inspect_metadata = puts JSON.pretty_generate(@metadata)
|
|
|
|
def save(destination = nil)
|
|
path = determine_save_path(destination)
|
|
File.write(path, content)
|
|
path
|
|
end
|
|
|
|
def extract_code = content.sub(METADATA_PATTERN, '')
|
|
|
|
def extract_metadata
|
|
return {} unless content =~ METADATA_PATTERN
|
|
|
|
yaml_content = $1.lines.map do |line|
|
|
line.sub(/^\s*#\s?/, '').rstrip
|
|
end.join("\n")
|
|
|
|
YAML.safe_load(yaml_content)
|
|
end
|
|
|
|
def update_metadata(metadata_hash)
|
|
@metadata = metadata_hash
|
|
@content = generate_content
|
|
end
|
|
|
|
def sign
|
|
hash = checksum
|
|
return puts "File already signed" if metadata['content_checksum'] == hash
|
|
|
|
new_metadata = metadata.merge('content_checksum' => hash)
|
|
update_metadata(new_metadata)
|
|
save
|
|
end
|
|
|
|
def verify
|
|
return false unless metadata.key? 'content_checksum'
|
|
checksum == metadata['content_checksum']
|
|
end
|
|
|
|
def modified? = !verify
|
|
|
|
private
|
|
|
|
def generate_content
|
|
metadata_block = generate_metadata
|
|
if content =~ METADATA_PATTERN
|
|
content.sub(METADATA_PATTERN, "\n#{metadata_block}")
|
|
else
|
|
[content.rstrip, "\n#{metadata_block}"].join("\n")
|
|
end
|
|
end
|
|
|
|
# This will need a comment style one day, to work with other languages
|
|
def generate_metadata
|
|
yaml_content = @metadata.to_yaml.strip
|
|
[
|
|
"# @PICOPACKAGE_START",
|
|
yaml_content.lines.map { |line| "# #{line}" }.join,
|
|
"# @PICOPACKAGE_END",
|
|
""
|
|
].join("\n")
|
|
end
|
|
|
|
def determine_save_path(destination)
|
|
if destination.nil?
|
|
@original_path || filename || raise("No filename available")
|
|
elsif File.directory?(destination)
|
|
File.join(destination, filename || File.basename(@original_path))
|
|
else
|
|
destination
|
|
end
|
|
end
|
|
|
|
end
|
|
end |