-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate.rb
executable file
·260 lines (219 loc) · 7.02 KB
/
generate.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#!/usr/bin/env ruby
# this script will generate all necessary meta-packages (rpm and deb)
# based on the main config file and what is already present under the
# target directory
require 'pp'
require 'date'
require 'fileutils'
require 'yaml'
# store path of this script
ROOT = File.expand_path(__dir__).freeze
# standard directory layout (relative to $ROOT)
# meta/ contains the meta package definitions - one per file
# stage/pkgname/{deb,rpm}/ contain all necessary information to build meta-packages
def rpm_create_source(pkg_data)
spec = File.open("#{ROOT}/stage/#{pkg_data['name']}/rpm/#{pkg_data['name']}.spec", 'w')
spec.puts <<-SPECSTART
Name: #{pkg_data['name']}
Version: #{pkg_data['changelog'][0]['version']}
Release: 1%{?dist}
License: GPLv3+
URL: https://git.ligo.org/packaging/lscsoft-metapackages
Summary: #{pkg_data['desc_short']}
BuildArch: noarch
SPECSTART
# add dependencies
dep_list = []
pkg_data['deps'].each do |k,v|
# add key as package name if value is nil (simple package, same for deb and rpm)
if v.nil?
dep_list << k
# if our key (rpm/deb) exists use its value or the package name itself if value is empty
elsif v.key?('rpm')
dep_list << ( v['rpm'].nil? ? k : v['rpm'] )
end
end
# write out Requires block
spec.puts
dep_list.sort.each do |d|
spec.puts "Requires: #{d}"
end
# if extra headers are specified, add them verbatim here
if pkg_data.key?('extra_headers') && pkg_data['extra_headers'].key?('rpm')
spec.puts
pkg_data['extra_headers']['rpm'].each do |h|
spec.puts h
end
end
spec.puts <<-SPECMID
%description
#{pkg_data['desc_long'].strip}
%prep
%build
%install
%files
%changelog
SPECMID
pkg_data['changelog'].each do |entry|
spec.puts "* #{entry['date'].strftime('%a %b %e %Y')} #{entry['author']} #{entry['version']}-1"
entry['changes'].each do |item|
indent = '- '
# this can be a multiline string from YAML, hence
# - split on newline
# - add '- ' to first and
# - ' 'to every other line
item.split("\n").each do |line|
spec.puts indent + line
indent = ' '
end
end
end
end
def reformat_wrapped(s, width = 78)
# helper function needed to reformat long description
# based on https://www.safaribooksonline.com/library/view/ruby-cookbook/0596523696/ch01s15.html
# other solution, thanks AlexP
# .gsub("\n\n", "\n.\n").scan(/\S.{0,#{width-2}}\S(?=\s|$)|\S+/).collect {|x| " " + x }.join("\n")
parts = []
s.split(/\n\n/).each do |part|
lines = []
line = ''
part.split(/\s+/).each do |word|
if line.size + word.size >= width
lines << line
line = word
elsif line.empty?
line = word
else
line << ' ' << word
end
end
lines << line if line
parts << ' ' + (lines.join "\n ")
end
parts.join "\n .\n"
end
def deb_create_source(pkg_data)
deb_control(pkg_data)
deb_readme(pkg_data)
deb_changelog(pkg_data)
deb_copyright(pkg_data)
end
def deb_readme(pkg_data)
# create README
readme = File.new("#{ROOT}/stage/#{pkg_data['name']}/deb/README", 'w')
readme.puts pkg_data['desc_long']
readme.close
end
def deb_changelog(pkg_data)
# create changelog
changelog = File.new("#{ROOT}/stage/#{pkg_data['name']}/deb/changelog.Debian", 'w')
pkg_data['changelog'].each do |entry|
changelog.puts "#{pkg_data['name']} (#{entry['version']}) unstable; urgency=medium\n\n"
entry['changes'].each do |item|
indent = ' * '
# this can be a multiline string from YAML, hence
# - split on newline
# - add ' * ' to first and
# - ' ' to every other line
item.split("\n").each do |line|
changelog.puts indent + line + "\n"
indent = ' '
end
changelog.puts
end
changelog.puts " -- #{entry['author']} #{entry['date'].strftime('%a, %d %b %Y %H:%M:%S %z')}\n\n"
end
changelog.close
end
def deb_copyright(pkg_data)
# create 'copyright'
copyright = File.new("#{ROOT}/stage/#{pkg_data['name']}/deb/copyright", 'w')
copyright.puts <<-COPYRIGHT
Upstream Author(s): The LIGO Scientific Collaboration
Copyright: LIGO Scientific Collaboration
License: GPLv2 (or later)
COPYRIGHT
copyright.close
end
def deb_control(pkg_data)
# create control file
control = File.new("#{ROOT}/stage/#{pkg_data['name']}/deb/control", 'w')
# start with simple header
control.puts <<-CONTROLSTART
Section: #{pkg_data['section']}
Priority: #{pkg_data['priority']}
Standards-Version: 3.9.8
Package: #{pkg_data['name']}
Maintainer: #{pkg_data['maintainer']}
Readme: README
Changelog: changelog.Debian
Copyright: copyright
Architecture: all
CONTROLSTART
# add dependencies
dep_list = []
pkg_data['deps'].each do |k, v|
# add key as package name if value is nil (simple package, same for deb and rpm)
if v.nil?
dep_list << k
# if our key (rpm/deb) exists use its value or the package name itself if value is empty
elsif v.key?('deb')
dep_list << (v['deb'].nil? ? k : v['deb'])
end
end
# write out dependency block
control.puts 'Depends: ' + dep_list.sort.join(', ')
# if extra headers are specified, add them verbatim here
if pkg_data.key?('extra_headers') && pkg_data['extra_headers'].key?('deb')
control.puts
pkg_data['extra_headers']['deb'].each do |h|
control.puts h
end
end
control.puts <<-CONTROLEND
Description: #{pkg_data['desc_short']}
#{reformat_wrapped(pkg_data['desc_long'])}
CONTROLEND
control.close
end
############# MAIN
# iterate over each file in meta/
Dir.glob("#{ROOT}/meta/*.yml") do |meta_file|
puts "Working on: #{meta_file}"
pkg = meta_file[/^#{ROOT}\/meta\/(.+)\.yml$/, 1]
content = YAML.load_file(meta_file)
# a few modifications need to be done (convenience)
# parse date/times from changelog and sort them with newest first
content['changelog'].each do |entry|
entry['date'] = DateTime.parse(entry['date'].to_s)
end
content['changelog'].sort! { |x, y| y['date'] <=> x['date'] }
# add package name (inferred from YAML fname)
content['name'] = pkg
# add long description unless given
content['desc_long'] = content['desc_short'] if content['desc_long'].nil?
# basic tests
%w[changelog desc_short desc_long deps name maintainer priority section].each do |t|
raise "#{meta_file} requires key '#{t}'" unless content.key?(t)
end
# ensure target dirs are is present
%w[deb rpm].each do |d|
FileUtils.mkpath("#{ROOT}/stage/#{pkg}/#{d}")
end
# once we get here, check if we need to work at all on this one
# for that, check its version file and compare to latest one from changelog
last_version = "#{ROOT}/stage/#{pkg}/version"
if File.exist?(last_version)
version = File.open(last_version, &:gets)
next if version.to_s.chomp.eql?(content['changelog'][0]['version'].to_s.chomp)
end
# create rpm source package
rpm_create_source(content)
# create deb source package
deb_create_source(content)
# all done, then update version file
version = File.open(last_version, 'w')
version.puts content['changelog'][0]['version'].to_s
version.close
end