This repository was archived by the owner on Jul 7, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathmain.go
188 lines (160 loc) · 5.78 KB
/
main.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
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"time"
"github.com/mattn/go-zglob"
"github.com/spf13/pflag"
)
var version = "unknown"
func main() {
// TODO: cache contents and control as gzipped JSON (strict) to .cache/repogen/v{DEB-PARSER-REVISION}/{SHA1-OF-PATH}-{FILE-SIZE}-{FILE-CTIME}
// TODO: refactor the entire thing (it's a mess)
maintainerOverride := pflag.StringP("maintainer-override", "m", "", "overrides the maintainer of all packages (format: First Last <email@address.com>)")
origin := pflag.StringP("origin", "o", "repogen", "sets the origin field used in the Release file (this field is used as a user-friendly way to identify the repository)")
description := pflag.StringP("description", "d", "Generated by repogen (version: "+version+")", "sets the description field used in the Release file")
generateContents := pflag.BoolP("generate-contents", "c", false, "generates the Contents index (makes repogen slower to load)")
generateWeb := pflag.BoolP("generate-web", "b", false, "generate a web interface for browsing the packages")
watch := pflag.BoolP("watch", "w", false, "watch the input directory for new packages")
watchInterval := pflag.DurationP("watch-interval", "i", time.Second, "the interval to check for new packages (if watch is enabled)")
symlink := pflag.BoolP("symlink", "l", false, "Symlink packages instead of copying them")
help := pflag.BoolP("help", "h", false, "show this help text")
sversion := pflag.Bool("version", false, "show the version")
pflag.Parse()
if *sversion {
fmt.Printf("repogen %s\n", version)
os.Exit(0)
}
if *help || pflag.NArg() != 3 {
fmt.Fprintf(os.Stderr, "Usage: repogen [OPTIONS] PRIVATE_KEY_FILE INPUT_DIR OUTPUT_DIR\n\nVersion:\n repogen %s\n\nOptions:\n", version)
pflag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\nArguments:\n PRIVATE_KEY_FILE is the path to a ascii-armoured gpg private key with no passphrase. It is used to sign the repository.\n INPUT_DIR is the path to the directory containing the deb packages. It should be in the following layout (and must not contain any unrelated files): INPUT_DIR/dist/component/*.deb\n OUTPUT_DIR is the path to place the generated repository in. It must not exist.\n")
os.Exit(1)
}
pkFile := pflag.Arg(0)
inRoot := pflag.Arg(1)
outRoot := pflag.Arg(2)
buf, err := ioutil.ReadFile(pkFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not read private key from '%s': %v\n", pkFile, err)
os.Exit(1)
}
if fi, err := os.Stat(inRoot); err != nil {
fmt.Fprintf(os.Stderr, "Error: error reading input directory '%s': %v\n", inRoot, err)
os.Exit(1)
} else if !fi.IsDir() {
fmt.Fprintf(os.Stderr, "Error: input directory '%s' must be a directory\n", inRoot)
os.Exit(1)
}
if _, err := os.Stat(outRoot); err == nil {
fmt.Fprintf(os.Stderr, "Error: output directory '%s' must not exist\n", outRoot)
os.Exit(1)
}
if inRoot, err = filepath.Abs(inRoot); err != nil {
fmt.Fprintf(os.Stderr, "Error: could not resolve path to input directory '%s': %v\n", inRoot, err)
os.Exit(1)
}
if outRoot, err = filepath.Abs(outRoot); err != nil {
fmt.Fprintf(os.Stderr, "Error: could not resolve path to output directory '%s': %v\n", outRoot, err)
os.Exit(1)
}
var ls string
for {
for {
if !*watch {
break
}
fs, err := zglob.Glob(filepath.Join(inRoot, "**", "*.deb"))
if err != nil {
fmt.Fprintf(os.Stderr, "Warning: could not search for files in input directory '%s': %v\n", outRoot, err)
time.Sleep(*watchInterval)
continue
}
var e bool
var s1, s2 int64
for _, fn := range fs {
if fi, err := os.Stat(fn); err != nil {
fmt.Fprintf(os.Stderr, "Warning: could not search for files in input directory '%s': %v\n", outRoot, err)
e = true
break
} else {
s1 += fi.Size()
}
}
if e {
time.Sleep(*watchInterval)
continue
}
time.Sleep(time.Second)
for _, fn := range fs {
if fi, err := os.Stat(fn); err != nil {
fmt.Fprintf(os.Stderr, "Warning: could not search for files in input directory '%s': %v\n", outRoot, err)
e = true
break
} else {
s2 += fi.Size()
}
}
if e {
time.Sleep(*watchInterval)
continue
}
if s1 != s2 {
fmt.Fprintf(os.Stderr, "Warning: file probably still being written (will check again in 2s): total size of input directory changed: %d -> %d\n", s1, s2)
time.Sleep(time.Second * 2)
continue
}
fs = append(fs, fmt.Sprint(s1))
sort.Strings(fs)
if s := fmt.Sprintf("%x", sha256sum([]byte(strings.Join(fs, ";")))); ls != s {
ls = s
break
}
time.Sleep(*watchInterval)
}
fmt.Println("Info: updating repo")
os.RemoveAll(outRoot)
r, err := NewRepo(inRoot, outRoot, *generateContents, *maintainerOverride, *origin, *description, string(buf))
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not generate repository: %v\n", err)
os.Exit(1)
}
r.Symlink = *symlink
err = r.Scan()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not generate repository: could not scan deb packages: %v\n", err)
os.Exit(1)
}
err = r.MakePool()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not generate repository: could not generate pool: %v\n", err)
os.Exit(1)
}
err = r.MakeDist()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not generate repository: could not generate dists: %v\n", err)
os.Exit(1)
}
err = r.MakeRoot()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not generate repository: %v\n", err)
os.Exit(1)
}
if *generateWeb {
err = r.GenerateWeb()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: could not generate web interface: %v\n", err)
os.Exit(1)
}
}
if !*watch {
break
}
fmt.Println("Info: waiting for changes")
}
fmt.Println("Info: successfully generated repository")
}