Browse Source

Initial iteration

drymer 5 months ago
parent
commit
0f2c7d89a9
Signed by: drymer <drymer@autistici.org> GPG Key ID: A307D64D5DDFDAAD

+ 50
- 0
.drone.yml View File

@@ -0,0 +1,50 @@
1
+---
2
+pipeline:
3
+  check-format:
4
+    image: golang:1.11.5-alpine3.9
5
+    commands:
6
+      - apk add -U make
7
+      - make test
8
+    when:
9
+      event: push
10
+
11
+  docker-build:
12
+    image: docker
13
+    commands:
14
+      - apk add -U make
15
+      - make docker-build
16
+    volumes:
17
+      - /var/run/docker.sock:/var/run/docker.sock
18
+    when:
19
+      event: push
20
+      branch: master
21
+
22
+  docker-push:
23
+    image: docker
24
+    commands:
25
+      - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD r.daemons.it
26
+      - apk add -U make
27
+      - make docker-push
28
+    volumes:
29
+      - /var/run/docker.sock:/var/run/docker.sock
30
+    secrets: [docker_username, docker_password]
31
+    when:
32
+      event: push
33
+      branch: master
34
+
35
+  notify-good:
36
+    image: registry.daemons.it/drone-xmpp
37
+    secrets: [xmpp_user, xmpp_password, xmpp_room]
38
+    message: Beep, boop, soy un bot. El job ha terminado correctamente, drymer.
39
+    when:
40
+      status: [success]
41
+      event: push
42
+
43
+  notify-bad:
44
+    image: registry.daemons.it/drone-xmpp
45
+    message: "Beep, boop, soy un bot. El job ha ido mal: {build_link}"
46
+    secrets: [xmpp_user, xmpp_password, xmpp_room]
47
+    when:
48
+      status: [failure]
49
+      event: push
50
+branch: master

+ 12
- 0
Dockerfile View File

@@ -0,0 +1,12 @@
1
+FROM golang:1.11.5-alpine3.9 as builder
2
+COPY gomic.go /go/gomic.go
3
+RUN apk add -U git
4
+RUN go get github.com/cavaliercoder/grab
5
+RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o gomic .
6
+
7
+FROM scratch as production
8
+COPY --from=builder /go/gomic /gomic/gomic
9
+COPY templates /gomic/templates/
10
+COPY static /gomic/static/
11
+WORKDIR /gomic
12
+ENTRYPOINT ["/gomic/gomic"]

+ 28
- 0
Makefile View File

@@ -0,0 +1,28 @@
1
+.PHONY: help
2
+
3
+help:
4
+	@echo "Please use 'make <target>' where <target> is one of"
5
+	@echo "  clean                       remove the go binary"
6
+	@echo "  build                       build the binary"
7
+	@echo "  docker-build                build the docker image"
8
+	@echo "  push                        push the docker image"
9
+	@echo "Check the Makefile to know exactly what each target is doing."
10
+
11
+test:
12
+	@echo "Checking format"
13
+	@sh scripts/check-format.sh
14
+clean:
15
+	@echo "Deleting binary"
16
+	@rm -f gomic
17
+
18
+build:
19
+	@echo "Creating static binary"
20
+	@docker run -i -v `pwd`:/gomic golang:1.11.5-alpine3.9 sh /gomic/scripts/build.sh
21
+
22
+docker-build:
23
+	docker build -t r.daemons.it/gomic:latest --target production .
24
+
25
+docker-push:
26
+	docker push r.daemons.it/gomic:latest
27
+
28
+all: clean build docker-build

+ 32
- 1
README.md View File

@@ -1,3 +1,34 @@
1 1
 # gomic
2 2
 
3
-This is just an exercise to learn some go. This program downloads a list of images and creates a webserver with a photo gallery to serve them. The images in the repo are technical comics.
3
+Este proyecto nace como un ejercicio para aprender un poco de go. Esencialmente
4
+descarga imágenes y las muestra en un servidor web. La idea es recopilar comics
5
+que tengan que ver con diferentes temas tecnológicos y tenerlos en un solo sitio.
6
+
7
+Hay que crear unos origenes, que vienen a ser ficheros con extensión `.txt` que
8
+contengan una lista de imágenes. Cada origen es un recopilatorio de comics de
9
+cierta temática tecnológica común. Por ejemplo, el origen `Julia Evans`
10
+contiene muchos de los comics que ella ha hecho y publicado en twitter (aunque
11
+todos se pueden comprar en [su página web](https://wizardzines.com/)).
12
+
13
+![Ejemplo](./img/comics.png)
14
+
15
+## Compilar
16
+Solo hace falta tener docker:
17
+
18
+``` bash
19
+make build
20
+```
21
+
22
+## Crear imágen docker
23
+
24
+``` bash
25
+make docker-build
26
+```
27
+
28
+## Usar
29
+
30
+``` bash
31
+./gomic
32
+# O con docker
33
+docker run -ti -v `pwd`/comics/:/gomic/comics -v `pwd`/origin/:/gomic/origin -v /etc/ssl:/etc/ssl ./gomic
34
+```

+ 143
- 0
gomic.go View File

@@ -0,0 +1,143 @@
1
+package main
2
+
3
+import (
4
+	"bufio"
5
+	"github.com/cavaliercoder/grab"
6
+	"html/template"
7
+	"io/ioutil"
8
+	"log"
9
+	"net/http"
10
+	"os"
11
+	"path/filepath"
12
+	"strings"
13
+)
14
+
15
+// downloadComics descarga una lista de imágenes y las escribe en un directorio.
16
+// El directorio seguirá el formato `origin/$originName/`. El parámetro `origin`
17
+// es un string que contiene el nombre o "namespace" del comic.
18
+func downloadComics(origin string) {
19
+	// Leer un fichero en formato bytes y mostrar el error de haberlo
20
+	fileHandle, err := os.Open("./origin/" + origin + ".txt")
21
+	if err != nil {
22
+		log.Fatal(err)
23
+	}
24
+	// Cerrar el fichero
25
+	defer fileHandle.Close()
26
+
27
+	// Crear un objeto escaner, que se usará para leer el fichero origen y
28
+	// hacer un bucle, siendo cada iteración una linea de este fichero.
29
+	fileScanner := bufio.NewScanner(fileHandle)
30
+	for fileScanner.Scan() {
31
+		// Inizializar y asignar el valor de linea a la variable url
32
+		url := fileScanner.Text()
33
+		// Descargar fichero y mostrar el error de haberlo
34
+		response, err := grab.Get("./comics/"+origin+"/", url)
35
+		if err != nil {
36
+			log.Print("error downloading " + url)
37
+			log.Print(err)
38
+		} else {
39
+			// Imprimir por pantalla el resultado correcto de la descarga del fichero
40
+			log.Print("successfully downloaded " + url + " to " + response.Filename)
41
+		}
42
+	}
43
+}
44
+
45
+// comicServer sirve el html a las peticiones que llegan. Según la petición que
46
+// llegue, se renderizan los comics de ese origen. El parámetro `w` es el objeto
47
+// que renderizará el html. El parámetro `r` es la petición de entrada, de la
48
+// que se saca el nombre del origen.
49
+func comicServer(w http.ResponseWriter, r *http.Request) {
50
+	// Declarar la variable con el tipo array de strings
51
+	var parameter []string
52
+
53
+	// Declarar e instanciar con el valor `./templates/$origen`.
54
+	variableTemplate := filepath.Join("./templates", filepath.Clean(r.URL.Path))
55
+	// Declarar e instanciar con el valor `./templates/layout.html`.
56
+	fixedTemplate := filepath.Join("./templates", "layout.html")
57
+
58
+	// TODO mover a switch
59
+	if filepath.Clean(r.URL.Path) != "/index.html" {
60
+		parameter = ls(r.URL.Path)
61
+	} else {
62
+		parameter = getOrigins()
63
+	}
64
+
65
+	// Declarar, instanciar y ejecutar el objeto template
66
+	tmpl, _ := template.ParseFiles(variableTemplate, fixedTemplate)
67
+	tmpl.ExecuteTemplate(w, "layout", parameter)
68
+}
69
+
70
+// ls devuelve un array de strings con los comics del origen que recibe.
71
+func ls(origin string) []string {
72
+	// Declarar variable
73
+	var images []string
74
+
75
+	// Declarar e instanciar variable con el valor `statc/$origen.html`.
76
+	var path = "comics" + strings.Replace(filepath.Clean(origin), ".html", "", -1)
77
+
78
+	// Listar ficheros de del directorio `./static/$origin.html` y capturar el
79
+	// error de haberlo
80
+	_images, err := ioutil.ReadDir(path)
81
+	if err != nil {
82
+		log.Print("the path " + path + " doesn't exist")
83
+	}
84
+
85
+	// Convertir el array de os.FileInfo a un array de strings
86
+	for _, entry := range _images {
87
+		images = append(images, "/"+path+"/"+entry.Name())
88
+	}
89
+
90
+	return images
91
+}
92
+
93
+// getOrigins devuelve un array de strings con los origenes detectados.
94
+// Los orígenes se detectan haciendo un ls del directorio de `origins`, en el
95
+// que hay directorios con la extensión `.txt`.
96
+func getOrigins() []string {
97
+	// Declarar variable
98
+	var origins []string
99
+
100
+	// Listar ficheros del directorio `./origin/` y captura el error de haberlo
101
+	files, err := ioutil.ReadDir("./origin/")
102
+	if err != nil {
103
+		log.Fatal(err)
104
+	}
105
+
106
+	// Iterar sobre los ficheros del directorio anterior, creando un array de
107
+	// strings con el nombre de la ruta completo de los ficheros
108
+	for _, f := range files {
109
+		origins = append(origins, (strings.Replace(f.Name(), ".txt", "", -1)))
110
+	}
111
+
112
+	return origins
113
+}
114
+
115
+func main() {
116
+	// Declarar variable
117
+	var origins []string
118
+	var port = ":8080"
119
+
120
+	// Instanciar variable con los origenes
121
+	origins = getOrigins()
122
+	for _, origin := range origins {
123
+		// Descargar los comics de cada origen
124
+		downloadComics(origin)
125
+	}
126
+
127
+	// Añadir el directorio `static` como directorio disponible en el servidor
128
+	// web
129
+	fs := http.FileServer(http.Dir("./static/"))
130
+	// Añadir el directorio `comics` como directorio disponible en el servidor
131
+	// web
132
+	cm := http.FileServer(http.Dir("./comics/"))
133
+	// Asociar el endpoint `/static/` con el directorio `static`
134
+	http.Handle("/static/", http.StripPrefix("/static/", fs))
135
+	// Asociar el endpoint `/comics/` con el directorio `comics`
136
+	http.Handle("/comics/", http.StripPrefix("/comics/", cm))
137
+	// Asociar todo lo demás a la función de servir comics
138
+	http.HandleFunc("/", comicServer)
139
+	// Imprimir por pantalla la dirección del servidor web
140
+	log.Print("Starting webserver at http://localhost" + port)
141
+	// Crear y servir el servidor
142
+	http.ListenAndServe(port, nil)
143
+}

BIN
img/comics.png View File


+ 71
- 0
origin/juliaevans.txt View File

@@ -0,0 +1,71 @@
1
+https://wizardzines.com/zines/bite-size-command-line/samples/grep.jpg
2
+https://wizardzines.com/zines/bite-size-command-line/samples/xargs.jpg
3
+https://wizardzines.com/zines/bite-size-linux/samples/pipes.jpg
4
+https://wizardzines.com/zines/bite-size-linux/samples/unix-domain-sockets.jpg
5
+https://wizardzines.com/zines/manager/samples/1:1s.jpeg
6
+https://wizardzines.com/zines/manager/samples/specific-feedback.jpeg
7
+https://wizardzines.com/zines/oh-shit-git/samples/ohshit-commit.png
8
+https://wizardzines.com/zines/oh-shit-git/samples/ohshit-reflog.png
9
+https://pbs.twimg.com/media/DzVeTzoVsAIjnN9.jpg
10
+https://pbs.twimg.com/media/DzP-KfpV4AA4TH2.jpg
11
+https://pbs.twimg.com/media/DzD8nn5V4AAJ00j.jpg
12
+https://pbs.twimg.com/media/Dy-3HWvUcAArBZA.jpg
13
+https://pbs.twimg.com/media/Dyadf5wUUAAt0fe.jpg
14
+https://pbs.twimg.com/media/DyaUCjnUYAA5nPx.jpg
15
+https://pbs.twimg.com/media/DyIWpmmVYAASzfl.jpg
16
+https://pbs.twimg.com/media/DyCqcpyVAAEjyKC.jpg
17
+https://pbs.twimg.com/media/DxzWci-VsAAXoFV.jpg
18
+https://pbs.twimg.com/media/DxunMITVsAARWAF.jpg
19
+https://pbs.twimg.com/media/DxkgbEgXcAAbS6W.jpg
20
+https://pbs.twimg.com/media/Dxep9dqV4AE2vdA.jpg
21
+https://pbs.twimg.com/media/DrSqr38WoAA9eJ6.jpg
22
+https://pbs.twimg.com/media/DrSjGFOU0AAK6eZ.jpg
23
+https://pbs.twimg.com/media/DrK2undX0AAzH1S.jpg
24
+https://pbs.twimg.com/media/DqDCcRwXcAEoAut.jpg
25
+https://pbs.twimg.com/media/Dp9nnBSUcAEN9t2.jpg
26
+https://pbs.twimg.com/media/Dp1_VUtVsAECAxk.jpg
27
+https://pbs.twimg.com/media/Dlj-JhzW4AUkgDa.jpg
28
+https://pbs.twimg.com/media/DlQBiN2XsAAbiKt.jpg
29
+https://pbs.twimg.com/media/DlP3gbZXoAEMGVv.jpg
30
+https://pbs.twimg.com/media/DlNGyVQXsAEM5eA.jpg
31
+https://pbs.twimg.com/media/DlNDu6aX0AAhHKM.jpg
32
+https://pbs.twimg.com/media/DjKZmQMW4AAnvf7.jpg
33
+https://pbs.twimg.com/media/DjFb_FPX4AAOwpa.jpg
34
+https://pbs.twimg.com/media/DjFRu-OX0AA_eey.jpg
35
+https://pbs.twimg.com/media/DjANQToUwAAIx60.jpg
36
+https://pbs.twimg.com/media/DjAE_gQW0AAroNe.jpg
37
+https://pbs.twimg.com/media/DiJ55nTX4AAM4bU.jpg
38
+https://pbs.twimg.com/media/DiGecyWWsAAdCxO.jpg
39
+https://pbs.twimg.com/media/DfQlzD5XcAAYnw5.jpg
40
+https://pbs.twimg.com/media/DfDxXSiW0AA2zKd.jpg
41
+https://pbs.twimg.com/media/DeQaFUMWAAAfTWf.jpg
42
+https://pbs.twimg.com/media/DeN10NLUQAApvNY.jpg
43
+https://pbs.twimg.com/media/DeLcVfSWAAAw6OZ.jpg
44
+https://pbs.twimg.com/media/DeGNDzqX0AAow7z.jpg
45
+https://pbs.twimg.com/media/DeF0p2kW0AYdvg9.jpg
46
+https://pbs.twimg.com/media/DcwearbXkAAnSzm.jpg
47
+https://pbs.twimg.com/media/DcroahkW0AATfbV.jpg
48
+https://pbs.twimg.com/media/DcpE8wLXcAAzZRO.jpg
49
+https://pbs.twimg.com/media/Dcml7ovWsAAsXgn.jpg
50
+https://pbs.twimg.com/media/DcaNg4hX0AAAXOA.jpg
51
+https://pbs.twimg.com/media/DcPeD_CW0AEkSar.jpg
52
+https://pbs.twimg.com/media/DbmtKZpWkAAlra6.jpg
53
+https://pbs.twimg.com/media/DbhhpljXkAEYL-R.jpg
54
+https://pbs.twimg.com/media/DbeboCeX4AAVR_5.jpg
55
+https://pbs.twimg.com/media/DbcAjhJW4AAI28b.jpg
56
+https://pbs.twimg.com/media/DbZVoiPWsAEJ3u7.jpg
57
+https://pbs.twimg.com/media/DbUc7vDX0AAm9n6.jpg
58
+https://pbs.twimg.com/media/DbURcekXkAALzV2.jpg
59
+https://pbs.twimg.com/media/DbMSmYqWsAEy3_L.jpg
60
+https://pbs.twimg.com/media/DbHVy9tW0AAP8UR.jpg
61
+https://pbs.twimg.com/media/DagUeioVMAAVMm0.jpg
62
+https://pbs.twimg.com/media/DabTJdnU0AAkdi3.jpg
63
+https://pbs.twimg.com/media/DaROZeQW4AEMUl5.jpg
64
+https://pbs.twimg.com/media/DaMLUoGXUAI21V6.jpg
65
+https://pbs.twimg.com/media/DaJxjj9WsAAwTZS.jpg
66
+https://pbs.twimg.com/media/DaEj6zWVwAEl9eH.jpg
67
+https://pbs.twimg.com/media/DZ-fnm3WAAEDK4n.jpg
68
+https://pbs.twimg.com/media/DZ3HpVXXkAEgxpc.jpg
69
+https://pbs.twimg.com/media/DZ0ORLSW4AQnwD8.jpg
70
+https://pbs.twimg.com/media/DZz-itaX0AESV67.jpg
71
+https://pbs.twimg.com/media/DZjtir0W4AIvmHm.jpg

+ 6
- 0
scripts/build.sh View File

@@ -0,0 +1,6 @@
1
+#!/usr/bin/env bash
2
+
3
+apk add -U git > /dev/null
4
+cd /gomic
5
+go get -d -v
6
+CGO_ENABLED=0 GOOS=linux go build -i -a -ldflags '-extldflags "-static"' -o gomic

+ 6
- 0
scripts/check-format.sh View File

@@ -0,0 +1,6 @@
1
+#!/usr/bin/env bash
2
+
3
+if [ -n "$(go fmt gomic.go)" ]
4
+then
5
+    return 1
6
+fi

+ 20
- 0
static/css/gallery.css View File

@@ -0,0 +1,20 @@
1
+div.gallery {
2
+  margin: 5px;
3
+  border: 1px solid #ccc;
4
+  float: left;
5
+  width: 180px;
6
+}
7
+
8
+div.gallery:hover {
9
+  border: 1px solid #777;
10
+}
11
+
12
+div.gallery img {
13
+  width: 100%;
14
+  height: auto;
15
+}
16
+
17
+div.desc {
18
+  padding: 15px;
19
+  text-align: center;
20
+}

+ 63
- 0
static/css/main.css View File

@@ -0,0 +1,63 @@
1
+body {
2
+	font-family: "Aller", "sans-serif";  /* just a custom font */
3
+}
4
+
5
+
6
+a:-webkit-any-link {
7
+  	text-decoration: none;	/* ignoring default link settings */
8
+}
9
+
10
+
11
+ul
12
+{
13
+	list-style-type: none;	/* hiding the bullets from ul */
14
+}
15
+
16
+.fade {
17
+   opacity: 0.8;		/* sets default view to a 80% opacity */
18
+   transition: opacity .25s ease-in-out;
19
+   -moz-transition: opacity .25s ease-in-out;
20
+   -webkit-transition: opacity .25s ease-in-out;
21
+}
22
+
23
+.fade:hover {
24
+      opacity: 1;	/* sets default view to a 100% opacity when on hover state */
25
+}
26
+
27
+.img-wrapper {
28
+	width: 300px;
29
+	height: 240px;
30
+	border: 0.1em solid #ccc;
31
+	border-radius: 0.4em;
32
+	background-color: #f3f3f3;
33
+	box-shadow: 0.1em 0.1em 0.5em -0.2em #777;
34
+	margin: 1em 1em;
35
+}
36
+
37
+img {
38
+	border-radius: 0.4em 0.4em 0em 0em;		/* radius should be the same as the img-wrapper */
39
+}
40
+
41
+.gallery-wrapper ul li{
42
+	display: inline-block;		/* sit wrappers in rows, not column block */
43
+
44
+}
45
+
46
+h1 {
47
+	padding-left: 14em;
48
+}
49
+
50
+h4 {							/* style the photos titles */
51
+	text-align: center;
52
+	font-size: 1em;
53
+	margin: 0;
54
+	padding: 0.5em 2em;
55
+	text-transform: uppercase;
56
+	font-weight: bold;
57
+	color: black;
58
+}
59
+
60
+.logo {
61
+	margin-left: 22em;
62
+	margin-bottom: 4em;
63
+}

+ 4
- 0
static/js/jquery-1.11.0.min.js
File diff suppressed because it is too large
View File


+ 2
- 0
static/js/jquery-migrate-1.2.1.min.js
File diff suppressed because it is too large
View File


+ 1
- 0
static/js/jquery.fancybox-1.3.4.pack.min.js
File diff suppressed because it is too large
View File


+ 8
- 0
templates/index.html View File

@@ -0,0 +1,8 @@
1
+{{define "title"}}Index of comics{{end}}
2
+{{define "body"}}
3
+<ul>
4
+{{range . }}
5
+<li><a href="/{{.}}.html">{{.}}</a></li>
6
+{{end}}
7
+</ul>
8
+{{end}}

+ 13
- 0
templates/juliaevans.html View File

@@ -0,0 +1,13 @@
1
+{{define "title"}}Julia Evans Comics{{end}}
2
+{{define "body"}}
3
+<div class="gallery-wrapper">
4
+<p>You may want to visit her <a href="https://wizardzines.com/">official webpage</a>!</p>
5
+<ul>
6
+{{range . }}
7
+<li>
8
+  <figure class="img-wrapper fade"><a class="fancybox" href="{{.}}"><img src="{{.}}" height="300" width="300"></a></figure>
9
+</li>
10
+{{end}}
11
+</ul>
12
+</div>
13
+{{end}}

+ 38
- 0
templates/layout.html View File

@@ -0,0 +1,38 @@
1
+{{define "layout"}}
2
+<!doctype html>
3
+<html>
4
+<head>
5
+  <meta charset="utf-8">
6
+  <link rel="stylesheet" href="/static/css/main.css">
7
+  <link rel="stylesheet" type="text/css" media="screen" href="http://cdnjs.cloudflare.com/ajax/libs/fancybox/1.3.4/jquery.fancybox-1.3.4.css"/>
8
+  <script type="text/javascript" src="/static/js/jquery-1.11.0.min.js"></script>
9
+  <script type="text/javascript" src="/static/js/jquery-migrate-1.2.1.min.js"></script>
10
+  <script type="text/javascript" src="/static/js/jquery.fancybox-1.3.4.pack.min.js"></script>
11
+  <title>{{template "title"}}</title>
12
+</head>
13
+<body>
14
+  <h1>{{template "title"}}</h1>
15
+  {{template "body" .}}
16
+</body>
17
+<script type="text/javascript">
18
+    $(function($){
19
+        var addToAll = false;
20
+        var gallery = true;
21
+        var titlePosition = 'inside';
22
+        $(addToAll ? 'img' : 'img.fancybox').each(function(){
23
+            var $this = $(this);
24
+            var title = $this.attr('title');
25
+            var src = $this.attr('data-big') || $this.attr('src');
26
+            var a = $('<a href="#" class="fancybox"></a>').attr('href', src).attr('title', title);
27
+            $this.wrap(a);
28
+        });
29
+        if (gallery)
30
+            $('a.fancybox').attr('rel', 'fancyboxgallery');
31
+        $('a.fancybox').fancybox({
32
+            titlePosition: titlePosition
33
+        });
34
+    });
35
+    $.noConflict();
36
+</script>
37
+</html>
38
+{{end}}

Loading…
Cancel
Save