-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
145 lines (113 loc) · 3.97 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
package main
import (
"flag"
"net"
"net/http"
"net/url"
"os"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/xanzy/go-gitlab"
"github.com/florianloch/gomodgraph/internal/graph"
"github.com/florianloch/gomodgraph/internal/mods"
)
// TODO: Consider "Replace" directive in go.mod
const (
glTokenEnvVar = "GITLAB_API_TOKEN"
glBaseURLEnvVar = "GITLAB_API_BASE_URL"
glBaseURLPreviousEnvVar = "GITLAB_BASE_URL"
tmpDir = "/tmp/gomodgraph/"
goModDir = tmpDir + "go_mod_files" // has to be below tmpDir
)
type config struct {
glToken string
glBaseURL string
homeModule string
goRegistryPrefix string
cleanup bool
listenAddr string
}
func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
cfg := configure()
if cfg.cleanup {
if err := os.RemoveAll(tmpDir); err != nil && !os.IsNotExist(err) {
log.Error().Msgf("Failed to remove the tmp dir (%q): %v", tmpDir, err)
}
log.Info().Msg("Emptied cache successfully")
}
glClient, err := gitlab.NewClient(cfg.glToken, gitlab.WithBaseURL(cfg.glBaseURL))
if err != nil {
log.Fatal().Msgf("Initializing GitLab client: %v", err)
}
var cacheFilled bool
if info, err := os.Stat(goModDir); err == nil && info.IsDir() {
cacheFilled = true // we simply assume the cache is filled in case the cache directory for the mod files exists
}
if err := os.MkdirAll(goModDir, 0o700); err != nil {
log.Fatal().Msgf("Directory for downloaded mod files (%q) cannot be accesses and could not be created: %v",
goModDir,
err)
}
if !cacheFilled {
log.Info().Msgf("Cache at %q is empty, will scan for projects and download mod files", goModDir)
if err := mods.Download(mods.NewGitLabModFetcher(glClient), goModDir); err != nil {
log.Fatal().Msgf("Could not download mod files: %v", err)
}
}
modFiles, err := mods.ReadModFiles(goModDir)
if err != nil {
log.Fatal().Msgf("Could not read mod files: %v", err)
}
depGraph := graph.BuildDependencyGraph(modFiles)
mux := http.NewServeMux()
mux.Handle("/", NewGraphRenderService(depGraph, cfg.goRegistryPrefix))
// We do this extra work because if port is set to 0 we want to choose a free port automatically
listener, err := net.Listen("tcp", cfg.listenAddr)
if err != nil {
log.Fatal().Msgf("Could not open listener: %v", err)
}
log.Info().Msgf("Serving at http://%s/?mod=%s", listener.Addr().(*net.TCPAddr), url.QueryEscape(cfg.homeModule))
if err := http.Serve(listener, mux); err != nil {
log.Fatal().Msgf("Serving failed: %v", err)
}
}
func configure() *config {
var (
baseURL string
homeModule string
cleanup bool
listenAddr string
)
flag.StringVar(&baseURL, "gitlab-base-url", "", "GitLab's API Base URL")
flag.StringVar(&homeModule, "mod", "", "Show graph of this module instead of giant overview graph")
flag.BoolVar(&cleanup, "cleanup", false, "Clean up the cache directory, enforcing all information to be refetched")
flag.StringVar(&listenAddr, "listen-addr", "localhost:0", "Listen on the given interface and port, set port to 0 to have a free one chosen automatically")
flag.Parse()
if baseURL == "" {
baseURL = os.Getenv(glBaseURLEnvVar)
// For backwards compatibility also check the old ENV
if baseURL == "" {
baseURL = os.Getenv(glBaseURLPreviousEnvVar)
}
if baseURL == "" {
log.Fatal().Msgf("GitLab's API Base URL is required but neither the flag nor the env variable (%q) is set", glBaseURLEnvVar)
}
}
baseURLAsURL, err := url.Parse(baseURL)
if err != nil {
log.Fatal().Msgf("GitLab API Base URL seems not to be an invalid URL: %v", err)
}
token := os.Getenv(glTokenEnvVar)
if token == "" {
log.Fatal().Msgf("GitLab's API token required but the env variable (%q) is set", glTokenEnvVar)
}
return &config{
glToken: token,
glBaseURL: baseURL,
homeModule: homeModule,
goRegistryPrefix: baseURLAsURL.Hostname(),
cleanup: cleanup,
listenAddr: listenAddr,
}
}