Class: FPM::Package::Python::PythonMetadata
- Inherits:
-
Object
- Object
- FPM::Package::Python::PythonMetadata
- Defined in:
- lib/fpm/package/python.rb
Defined Under Namespace
Classes: MissingField, UnexpectedContent
Constant Summary collapse
- MULTIPLE_USE =
According to packaging.python.org/en/latest/specifications/core-metadata/ > Core Metadata v2.4 - August 2024
%w(Dynamic Platform Supported-Platform License-File Classifier Requires-Dist Requires-External Project-URL Provides-Extra Provides-Dist Obsoletes-Dist)
- FIELD_MAP =
{ :@name => "Name", :@version => "Version", :@summary => "Summary", :@description => "Description", :@keywords => "Keywords", :@maintainer => "Author-email", # Note: License can also come from the deprecated "License" field # This is processed later in this method. :@license => "License-Expression", :@requires => "Requires-Dist", }
- REQUIRED_FIELDS =
[ "Metadata-Version", "Name", "Version" ]
Instance Attribute Summary collapse
-
#description ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#homepage ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#keywords ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#license ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#maintainer ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#name ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#requires ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#summary ⇒ Object
readonly
Only focusing on terms fpm may care about.
-
#version ⇒ Object
readonly
Only focusing on terms fpm may care about.
Class Method Summary collapse
-
.from(input) ⇒ Object
self.parse.
-
.parse(input) ⇒ Object
METADATA files are described in Python Packaging “Core Metadata”[1] and appear to have roughly RFC822 syntax.
Instance Method Summary collapse
-
#initialize(headers, body = nil) ⇒ PythonMetadata
constructor
headers - a Hash containing field-value pairs from headers as read from a python METADATA file.
Constructor Details
#initialize(headers, body = nil) ⇒ PythonMetadata
headers - a Hash containing field-value pairs from headers as read from a python METADATA file. body - optional, a string containing the body text of a METADATA file
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/fpm/package/python.rb', line 200 def initialize(headers, body=nil) REQUIRED_FIELDS.each do |field| if !headers.include?(field) raise MissingField, "Missing required Python metadata field, '#{field}'. This might be a bug in the package or in fpm." end end FIELD_MAP.each do |attr, field| if headers.include?(field) instance_variable_set(attr, headers.fetch(field)) end end # Do any extra processing on fields to turn them into their expected content. process_description(headers, body) process_license(headers) process_homepage(headers) process_maintainer(headers) end |
Instance Attribute Details
#description ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def description @description end |
#homepage ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def homepage @homepage end |
#keywords ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def keywords @keywords end |
#license ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def license @license end |
#maintainer ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def maintainer @maintainer end |
#name ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def name @name end |
#requires ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def requires @requires end |
#summary ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def summary @summary end |
#version ⇒ Object (readonly)
Only focusing on terms fpm may care about
179 180 181 |
# File 'lib/fpm/package/python.rb', line 179 def version @version end |
Class Method Details
.from(input) ⇒ Object
self.parse
174 175 176 |
# File 'lib/fpm/package/python.rb', line 174 def self.from(input) return PythonMetadata.new(*parse(input)) end |
.parse(input) ⇒ Object
METADATA files are described in Python Packaging “Core Metadata”[1] and appear to have roughly RFC822 syntax.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 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 168 169 170 171 172 |
# File 'lib/fpm/package/python.rb', line 113 def self.parse(input) s = StringScanner.new(input) headers = {} # Default "Multiple use" fields to empty array instead of nil. MULTIPLE_USE.each do |field| headers[field] = [] end while !s.eos? and !s.scan("\n") do # Field is non-space up, but excluding the colon field = s.scan(/[^\s:]+/) # Skip colon and following whitespace s.scan(/:\s*/) # Value is text until newline, and any following lines if they have leading spaces. value = s.scan(/[^\n]+(?:\Z|\n(?:[ \t][^\n]+\n)*)/) if value.nil? raise "Failed parsing Python package metadata value at field #{field}, char offset #{s.pos}" end value = value.chomp if MULTIPLE_USE.include?(field) raise "Header field should be an array. This is a bug in fpm." if !headers[field].is_a?(Array) headers[field] << value else headers[field] = value end end # while reading headers # If there's more content beyond the last header, then it's a content body. # In Python Metadata >= 2.1, the descriptino can be written in the body. if !s.eos? if headers["Metadata-Version"].to_f >= 2.1 # Per Python core-metadata spec: # > Changed in version 2.1: This field may be specified in the message body instead. #return PythonMetadata.new(headers, s.string[s.pos ...]) return headers, s.string[s.pos ... ] elsif headers["Metadata-Version"].to_f >= 2.0 # dnspython v1.15.0 has a description body and Metadata-Version 2.0 # this seems out of spec, but let's accept it anyway. return headers, s.string[s.pos ... ] else raise "After reading METADATA headers, extra data is in the file but was not expected. This may be a bug in fpm." end end #return PythonMetadata.new(headers) return headers, nil # nil means no body in this metadata rescue => e puts "String scan failed: #{e}" puts "Position: #{s.pointer}" puts "---" puts input puts "===" puts input[s.pointer...] puts "---" raise e end |