-
Notifications
You must be signed in to change notification settings - Fork 9
/
control.go
336 lines (294 loc) · 12 KB
/
control.go
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
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
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
331
332
333
334
335
336
// Copyright 2017 Debpkg authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package debpkg
import (
"fmt"
"io/ioutil"
"math"
"strings"
"github.com/xor-gate/debpkg/internal/targzip"
)
type control struct {
tgz *targzip.TarGzip
info controlInfo
conffiles string // List of configuration-files
hasCustomConffiles bool
}
type controlInfoVersion struct {
full string // Full version string. E.g "0.1.2"
major uint // Major version number
minor uint // Minor version number
patch uint // Patch version number
}
type controlInfo struct {
name string
version controlInfoVersion
architecture string
maintainer string
maintainerEmail string
homepage string
depends string
recommends string
suggests string
conflicts string
provides string
replaces string
section string
priority Priority
descrShort string // Short package description
descr string // Long package description
vcsType VcsType // E.g: "Svn", "Git" etcetera
vcsURL string // E.g: git@github.com:xor-gate/debpkg.git
vcsBrowser string // E.g: https://github.com/xor-gate/debpkg
builtUsing string // E.g: gcc-4.6 (= 4.6.0-11)
}
// SetName sets the name of the binary package (mandatory)
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Package
func (deb *DebPkg) SetName(name string) {
deb.control.info.name = name
}
// SetVersion sets the full version string (mandatory), or use SetVersion* functions for "major.minor.patch"
// The upstream_version may contain only alphanumerics ( A-Za-z0-9 ) and the characters . + - : ~
// (full stop, plus, hyphen, colon, tilde) and should start with a digit.
// NOTE: When the full string is set the other SetVersion* function calls are ignored
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
func (deb *DebPkg) SetVersion(version string) {
deb.control.info.version.full = version
}
// SetVersionMajor sets the version major number
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
func (deb *DebPkg) SetVersionMajor(major uint) {
deb.control.info.version.major = major
}
// SetVersionMinor sets the version minor number
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
func (deb *DebPkg) SetVersionMinor(minor uint) {
deb.control.info.version.minor = minor
}
// SetVersionPatch sets the version patch level
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version
func (deb *DebPkg) SetVersionPatch(patch uint) {
deb.control.info.version.patch = patch
}
// SetArchitecture sets the architecture of the package where it can be installed.
// E.g "i386, amd64, arm, any, all". See `dpkg-architecture -L` for all supported.
// Architecture: any
// The generated binary package is an architecture dependent one usually in a compiled language.
// Architecture: all
// The generated binary package is an architecture independent one usually consisting of text,
// images, or scripts in an interpreted language.
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Architecture
// And: http://man7.org/linux/man-pages/man1/dpkg-architecture.1.html
func (deb *DebPkg) SetArchitecture(arch string) {
deb.control.info.architecture = arch
}
// SetMaintainer (mandatory), sets the package maintainers name and surname. E.g: "Foo Bar"
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Maintainer
func (deb *DebPkg) SetMaintainer(maintainer string) {
deb.control.info.maintainer = maintainer
}
// SetMaintainerEmail sets the package maintainers email address. E.g: "foo@bar.com"
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Maintainer
func (deb *DebPkg) SetMaintainerEmail(email string) {
deb.control.info.maintainerEmail = email
}
// SetDepends sets the package dependencies. E.g: "lsb-release"
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
func (deb *DebPkg) SetDepends(depends string) {
deb.control.info.depends = depends
}
// SetRecommends sets the package recommendations. E.g: "aptitude"
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
func (deb *DebPkg) SetRecommends(recommends string) {
deb.control.info.recommends = recommends
}
// SetSuggests sets the package suggestions. E.g: "aptitude"
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html#s-binarydeps
func (deb *DebPkg) SetSuggests(suggests string) {
deb.control.info.suggests = suggests
}
// SetConflicts sets one or more conflicting packages. E.g: "nano"
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html#s-conflicts
func (deb *DebPkg) SetConflicts(conflicts string) {
deb.control.info.conflicts = conflicts
}
// SetProvides sets the type which the package provides. E.g: "editor"
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html#s-virtual
func (deb *DebPkg) SetProvides(provides string) {
deb.control.info.provides = provides
}
// SetReplaces sets the names of packages which will be replaced. E.g: "pico"
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html
func (deb *DebPkg) SetReplaces(replaces string) {
deb.control.info.replaces = replaces
}
// SetPriority (recommended). Default set to debpkg.PriorityUnset
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Priority
// And: https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities
func (deb *DebPkg) SetPriority(priority Priority) {
deb.control.info.priority = priority
}
// SetSection (recommended). E.g: editors
// See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Section
// And: https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections
func (deb *DebPkg) SetSection(section string) {
deb.control.info.section = section
}
// SetHomepage sets the homepage URL of the package. E.g: "https://github.com/foo/bar"
func (deb *DebPkg) SetHomepage(url string) {
deb.control.info.homepage = url
}
// SetShortDescription sets the single line synopsis. E.g: "My awesome foo bar baz tool"
func (deb *DebPkg) SetShortDescription(descr string) {
deb.control.info.descrShort = descr
}
// SetDescription sets the extended description over several lines. E.g:
// "This tool will calculation the most efficient way to world domination"
// NOTE: The debian control file has a special formatting of the long description
// this function replaces newlines with a newline and a space.
func (deb *DebPkg) SetDescription(descr string) {
deb.control.info.descr = " " + strings.Replace(descr, "\n", "\n ", -1)
}
// SetVcsType sets the version control system (Vcs) type for the source package.
// See: https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#s6.2.5.2
func (deb *DebPkg) SetVcsType(vcs VcsType) {
deb.control.info.vcsType = vcs
}
// SetVcsURL sets the version control system (Vcs) URL for the source package.
// See: https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#s6.2.5.2
func (deb *DebPkg) SetVcsURL(url string) {
deb.control.info.vcsURL = url
}
// SetVcsBrowser sets the version control system (Vcs) browsable source-tree URL for the source package.
// See: https://www.debian.org/doc/manuals/developers-reference/best-pkging-practices.html#s6.2.5.2
func (deb *DebPkg) SetVcsBrowser(url string) {
deb.control.info.vcsBrowser = url
}
// SetBuiltUsing incorporate parts of other packages when built but do not have to depend on those packages.
// A package using the source code from the gcc-4.6-source binary package built from the gcc-4.6 source package
// would have this field in its control file:
// Built-Using: gcc-4.6 (= 4.6.0-11)
// A package including binaries from grub2 and loadlin would have this field in its control file:
// Built-Using: grub2 (= 1.99-9), loadlin (= 1.6e-1)
// See: https://www.debian.org/doc/debian-policy/ch-relationships.html#s-built-using
func (deb *DebPkg) SetBuiltUsing(info string) {
deb.control.info.builtUsing = info
}
// AddControlExtraString is the same as AddControlExtra except it uses a string input.
// the files have possible DOS line-endings replaced by UNIX line-endings
func (deb *DebPkg) AddControlExtraString(name, s string) error {
if name == "conffiles" {
deb.control.hasCustomConffiles = true
}
s = strings.Replace(s, "\r\n", "\n", -1)
return deb.control.tgz.AddFileFromBuffer(name, []byte(s), 0755)
}
// AddControlExtra allows the advanced user to add custom script to the control.tar.gz Typical usage is
// for preinst, postinst, postrm, prerm: https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html
// And: https://www.debian.org/doc/manuals/maint-guide/dother.en.html#maintscripts
// the files have possible DOS line-endings replaced by UNIX line-endings
func (deb *DebPkg) AddControlExtra(name, filename string) error {
b, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
return deb.AddControlExtraString(name, string(b))
}
// verify the control file for validity
func (c *control) verify() error {
if c.info.name == "" {
return fmt.Errorf("empty package name")
}
if c.info.architecture == "" {
return fmt.Errorf("empty architecture")
}
return nil
}
func (c *control) markConfigFile(dest string) error {
if dest == "" {
return fmt.Errorf("config file cannot be empty")
}
c.conffiles += dest + "\n"
return nil
}
// finalizeControlFile creates the actual control-file, adds MD5-sums and stores
// config-files
func (c *control) finalizeControlFile(d *data) error {
if !c.hasCustomConffiles {
if err := c.tgz.AddFileFromBuffer("conffiles", []byte(c.conffiles), 0); err != nil {
return err
}
}
controlFile := []byte(c.String(d.tgz.Written()))
if err := c.tgz.AddFileFromBuffer("control", controlFile, 0); err != nil {
return err
}
if err := c.tgz.AddFileFromBuffer("md5sums", []byte(d.md5sums), 0); err != nil {
return err
}
return nil
}
// Generate version string (e.g "1.2.3") from major,minor patch or from full version
func (c *control) version() string {
if c.info.version.full != "" {
return c.info.version.full
}
return fmt.Sprintf("%d.%d.%d",
c.info.version.major,
c.info.version.minor,
c.info.version.patch)
}
func (c *control) size() int64 {
return c.tgz.Size()
}
// Create control file for control.tar.gz
func (c *control) String(installedSize uint64) string {
var o string
o += fmt.Sprintf("Package: %s\n", c.info.name)
o += fmt.Sprintf("Version: %s\n", c.version())
o += fmt.Sprintf("Architecture: %s\n", c.info.architecture)
o += fmt.Sprintf("Maintainer: %s <%s>\n",
c.info.maintainer,
c.info.maintainerEmail)
o += fmt.Sprintf("Installed-Size: %d\n", uint64(math.Ceil(float64(installedSize)/1024)))
if c.info.section != "" {
o += fmt.Sprintf("Section: %s\n", c.info.section)
}
if c.info.priority != PriorityUnset {
o += fmt.Sprintf("Priority: %s\n", c.info.priority)
}
if c.info.homepage != "" {
o += fmt.Sprintf("Homepage: %s\n", c.info.homepage)
}
if c.info.vcsType != VcsTypeUnset && c.info.vcsURL != "" {
o += fmt.Sprintf("Vcs-%s: %s\n", c.info.vcsType, c.info.vcsURL)
}
if c.info.vcsBrowser != "" {
o += fmt.Sprintf("Vcs-Browser: %s\n", c.info.vcsBrowser)
}
if c.info.builtUsing != "" {
o += fmt.Sprintf("Built-Using: %s\n", c.info.builtUsing)
}
if c.info.depends != "" {
o += fmt.Sprintf("Depends: %s\n", c.info.depends)
}
if c.info.recommends != "" {
o += fmt.Sprintf("Recommends: %s\n", c.info.recommends)
}
if c.info.suggests != "" {
o += fmt.Sprintf("Suggests: %s\n", c.info.suggests)
}
if c.info.conflicts != "" {
o += fmt.Sprintf("Conflicts: %s\n", c.info.conflicts)
}
if c.info.provides != "" {
o += fmt.Sprintf("Provides: %s\n", c.info.provides)
}
if c.info.replaces != "" {
o += fmt.Sprintf("Replaces: %s\n", c.info.replaces)
}
o += fmt.Sprintf("Description: %s\n", c.info.descrShort)
o += fmt.Sprintf("%s", c.info.descr)
return o
}