-
Notifications
You must be signed in to change notification settings - Fork 2
/
init.go
252 lines (208 loc) · 6.57 KB
/
init.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
package main
import (
"io/ioutil"
"os"
)
// Even if you delete a lot of this stuff, this file
// could be interesting to read through to see if you have
// all standard files for a publisher.
var (
initialFiles = map[string]string{
".gitignore": gitIgnore,
"robots.txt": robots,
"rss.xml": rss,
"sitemap.xml": sitemapXML,
"base.html": baseHTML,
"static/css/main.css": mainCSS,
"pages/index.md": pagesIndexMD,
"pages/demo/index.md": pagesDemoIndexMD,
"pages/demo/help.html": pagesDemoHelpHTML,
"app.yaml": appYaml,
"main.go": mainGo,
".gcloudignore": gcloudIgnore,
}
)
// TODO leverage this in other spots that use os.MkdirAll
// Make this file's base dir (no error if already exists,
// same behavior as mkdir -p)
func mkdirDashP(dir string) {
err := os.MkdirAll(dir, 0755)
if err != nil {
die("Failed to create dir (%s), err (%v)", dir, err) // Haven't seen this happen
}
}
// Must be run in project's base dir
func initNewProj() {
// First make sure there's no files
files, err := ioutil.ReadDir(".")
if err != nil {
die("Failed to read current directory (%v)", err)
}
for _, f := range files {
if f.Name() == ".git" && f.IsDir() {
continue // Only successful case!
}
die("Init command found a file or dir (%s). Base dir must be empty save .git", f.Name())
}
// Then create some dirs
mkdirDashP("static/css")
mkdirDashP("pages/demo")
// Then write em all!
for fileName, contents := range initialFiles {
err = ioutil.WriteFile(fileName, []byte(contents), 0644)
if err != nil {
die("Couldn't write file (%s), err: (%v)", fileName, err)
}
}
}
// ***** Standard project and publishing related files
var gitIgnore = `
# Shouldnt need too many ignores for a static site
.idea
.vscode
.DS_Store
`
// Robots txt tells crawlers like GoogleBot what not to crawl
// Generally this is for gated sections like /users/ or similar
// See https://www.nytimes.com/robots.txt for example.
// If you wanted to disable all robots you could:
// User-agent: *
// Disallow: /
//
// Of course no robots or humans are forced to obey this :)
var robots = `
Sitemap: /sitemap.xml
`
// TODO support this and other forms like google news, yahoo, etc.
// RSS and Sitemap will need to go into the generation process
var rss = ``
var sitemapXML = ``
// ***** Base HTML template that uses Bootstrap4
// This is "Starter Template" from bootstrap 4 at
//
var baseHTML = `
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<!-- Add our own CSS -->
<link rel="stylesheet" href="/static/css/main.css">
<title>Grumpo, Example</title>
</head>
<body>
<h1>Grumpo, Example</h1>
<p>You can check out Grumpo <a href="https://github.com/wrunk/grumpo">here.</a></p>
<p>Page content goes below which is usually wrapped in bootstrap containers/row/cols</p>
{{ .page }}
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>
`
// ***** Example CSS file. You could put js/ img/ in static as well
var mainCSS = `
/* Example CSS */
h1 {
text-decoration: underline;
}
`
// ***** Example pages
var pagesIndexMD = `
{
"title":"Home Page!",
"desc":"Welcome to the premeier web site of all websites"
// You can use c-style comments as long as they are on their own
// line and use the // format (not /**/)
// Headlines and live/publish dates probably don't make sense for the homepage
// Setting the homepage to false will prevent the site from actually
// generating (but you can still view it locally)
"live":false
}
# Home Page!
This part should be a paragraph about the home page!
Check the html to confirm.
`
var pagesDemoIndexMD = `
# Demo Index Markdown Page
Just showing use of a subdir...
`
var pagesDemoHelpHTML = `
<h1>Pages can also be written in html</h1>
<p>This demo help page is html!</p>
`
// ***** App Engine hosting related files
// Main app engine hosting configuration file.
// You can see more info about using App Engine with Golang here:
// https://cloud.google.com/appengine/docs/standard/go112/quickstart
// However you need careful settings to serve a static site
// TODO add comments or a post on this
var appYaml = `
runtime: go111
service: grumpo
env: standard
instance_class: F1
# Make sure our content isn't cached too long (10m is default)
default_expiration: "60s"
handlers:
- url: /
static_files: build/index.html
upload: /
secure: always
# TODO add rules for sitemaps, robots, rss
- url: /static
static_dir: build/static
secure: always
- url: /(.*)/$
static_files: build/\1/index.html
upload: .*\.html$
secure: always
- url: '.*'
script: auto
# Do we need this?
automatic_scaling:
min_idle_instances: automatic
max_idle_instances: automatic
min_pending_latency: automatic
max_pending_latency: automatic
`
// In order to make this work on App Engine, you
// need to have a dynamic server setup even if does
// nothing. TODO link to a blog post about this.
// For now any requests that end up here are assumed to be 404.
// TODO consider how to link a 404.html in here
var mainGo = `
package main
import (
"fmt"
"log"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", indexHandler)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
log.Printf("Defaulting to port %s", port)
}
log.Printf("Listening on port %s", port)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}
// Always return 404 for now since this is a static site
func indexHandler(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r)
}
`
// This tells App Engine not to deploy these files/directories.
// Similar format to .gitignore
var gcloudIgnore = `
/pages
`