chore(tools): Remove //tools/blog_cli
No longer needed with the deprecation of tazblog.
This commit is contained in:
parent
eb6e64ad47
commit
31b3e533c6
5 changed files with 0 additions and 263 deletions
|
@ -16,9 +16,6 @@ case "${TARGET_TOOL}" in
|
||||||
kontemplate)
|
kontemplate)
|
||||||
attr="kontemplate"
|
attr="kontemplate"
|
||||||
;;
|
;;
|
||||||
blog_cli)
|
|
||||||
attr="tools.blog_cli"
|
|
||||||
;;
|
|
||||||
stern)
|
stern)
|
||||||
attr="third_party.stern"
|
attr="third_party.stern"
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
__dispatch.sh
|
|
|
@ -1,41 +0,0 @@
|
||||||
tazblog CLI
|
|
||||||
===========
|
|
||||||
|
|
||||||
My blog stores its content in DNS, spread out over three types of `TXT` entries:
|
|
||||||
|
|
||||||
* `TXT _posts.blog.tazj.in.`: A sorted list of posts, serialised as a JSON list of
|
|
||||||
strings (e.g. `["1486830338", "1476807384"]`)
|
|
||||||
|
|
||||||
* `TXT _chunks.$postID.blog.tazj.in`: JSON chunks containing the blog post text
|
|
||||||
|
|
||||||
* `TXT _meta.$postID.blog.tazj.in`: JSON blob with blog post metadata
|
|
||||||
|
|
||||||
All JSON blobs are base64-encoded.
|
|
||||||
|
|
||||||
This CLI tool helps to update those records.
|
|
||||||
|
|
||||||
Each blog post data is a series of JSON-encoded structures which follow one of
|
|
||||||
these formats:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct metadata {
|
|
||||||
chunks: int
|
|
||||||
title: string
|
|
||||||
date: date
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Where `chunks` describes the number of chunks following this format:
|
|
||||||
|
|
||||||
```
|
|
||||||
struct chunk {
|
|
||||||
c: int
|
|
||||||
t: string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Writing a blog post to DNS means taking its text and metadata, chunking it up
|
|
||||||
and writing the chunks.
|
|
||||||
|
|
||||||
Reading a blog post means retrieving all data, reading the metadata and then
|
|
||||||
assembling the chunks in order.
|
|
|
@ -1,9 +0,0 @@
|
||||||
{ pkgs, ... }:
|
|
||||||
|
|
||||||
pkgs.buildGo.program {
|
|
||||||
name = "blog_cli";
|
|
||||||
srcs = [ ./main.go ];
|
|
||||||
deps = with pkgs.third_party; [
|
|
||||||
gopkgs."google.golang.org".api.dns.v1.gopkg
|
|
||||||
];
|
|
||||||
} // { meta.enableCI = true; }
|
|
|
@ -1,209 +0,0 @@
|
||||||
// The tazblog CLI implements updating my blog records in DNS, see the
|
|
||||||
// README in this folder for details.
|
|
||||||
//
|
|
||||||
// The post input format is a file with the title on one line,
|
|
||||||
// followed by the date on a line, followed by an empty line, followed
|
|
||||||
// by the post text.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"google.golang.org/api/dns/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
project = flag.String("project", "tazjins-infrastructure", "Target GCP project")
|
|
||||||
zone = flag.String("zone", "blog-tazj-in", "Target Cloud DNS zone")
|
|
||||||
title = flag.String("title", "", "Title of the blog post")
|
|
||||||
date = flag.String("date", "", "Date the post was written on")
|
|
||||||
infile = flag.String("text", "", "Text file containing the blog post")
|
|
||||||
id = flag.String("id", "", "Post ID - will be generated if unset")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Number of runes to include in a single chunk. If any chunks exceed
|
|
||||||
// the limit of what can be encoded, the chunk size is reduced and we
|
|
||||||
// try again.
|
|
||||||
var chunkSize = 200
|
|
||||||
|
|
||||||
type day time.Time
|
|
||||||
|
|
||||||
func (d day) MarshalJSON() ([]byte, error) {
|
|
||||||
j := (time.Time(d)).Format(`"2006-01-02"`)
|
|
||||||
return []byte(j), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type metadata struct {
|
|
||||||
Chunks int `json:"c"`
|
|
||||||
Title string `json:"t"`
|
|
||||||
Date day `json:"d"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type chunk struct {
|
|
||||||
Chunk int
|
|
||||||
Text string
|
|
||||||
}
|
|
||||||
|
|
||||||
type post struct {
|
|
||||||
ID string
|
|
||||||
Meta metadata
|
|
||||||
Chunks []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *post) writeToDNS() error {
|
|
||||||
var additions []*dns.ResourceRecordSet
|
|
||||||
additions = append(additions, &dns.ResourceRecordSet{
|
|
||||||
Name: fmt.Sprintf("_meta.%s.blog.tazj.in.", p.ID),
|
|
||||||
Type: "TXT",
|
|
||||||
Ttl: 1200,
|
|
||||||
Rrdatas: []string{
|
|
||||||
encodeJSON(p.Meta),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
for i, c := range p.Chunks {
|
|
||||||
additions = append(additions, &dns.ResourceRecordSet{
|
|
||||||
Name: fmt.Sprintf("_%v.%s.blog.tazj.in.", i, p.ID),
|
|
||||||
Type: "TXT",
|
|
||||||
Ttl: 1200,
|
|
||||||
Rrdatas: []string{c},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
dnsSvc, err := dns.NewService(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
change := dns.Change{
|
|
||||||
Additions: additions,
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = dnsSvc.Changes.Create(*project, *zone, &change).Do()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode given value as JSON and base64-encode it.
|
|
||||||
func encodeJSON(v interface{}) string {
|
|
||||||
outer, err := json.Marshal(v)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Failed to encode JSON", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return base64.RawStdEncoding.EncodeToString(outer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode a chunk and check whether it is too large
|
|
||||||
func encodeChunk(c chunk) (string, bool) {
|
|
||||||
tooLarge := false
|
|
||||||
s := base64.RawStdEncoding.EncodeToString([]byte(c.Text))
|
|
||||||
|
|
||||||
if len(s) >= 255 {
|
|
||||||
tooLarge = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, tooLarge
|
|
||||||
}
|
|
||||||
|
|
||||||
func createPost(id, title, text string, date day) post {
|
|
||||||
runes := []rune(text)
|
|
||||||
n := 0
|
|
||||||
tooLarge := false
|
|
||||||
|
|
||||||
var chunks []string
|
|
||||||
|
|
||||||
for chunkSize < len(runes) {
|
|
||||||
c, l := encodeChunk(chunk{
|
|
||||||
Chunk: n,
|
|
||||||
Text: string(runes[0:chunkSize:chunkSize]),
|
|
||||||
})
|
|
||||||
|
|
||||||
tooLarge = tooLarge || l
|
|
||||||
chunks = append(chunks, c)
|
|
||||||
runes = runes[chunkSize:]
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(runes) > 0 {
|
|
||||||
c, l := encodeChunk(chunk{
|
|
||||||
Chunk: n,
|
|
||||||
Text: string(runes),
|
|
||||||
})
|
|
||||||
|
|
||||||
tooLarge = tooLarge || l
|
|
||||||
chunks = append(chunks, c)
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
|
|
||||||
if tooLarge {
|
|
||||||
log.Println("Too large at chunk size", chunkSize)
|
|
||||||
chunkSize -= 5
|
|
||||||
return createPost(id, title, text, date)
|
|
||||||
}
|
|
||||||
|
|
||||||
return post{
|
|
||||||
ID: id,
|
|
||||||
Meta: metadata{
|
|
||||||
Chunks: n,
|
|
||||||
Title: title,
|
|
||||||
Date: date,
|
|
||||||
},
|
|
||||||
Chunks: chunks,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if *title == "" {
|
|
||||||
log.Fatalln("Post title must be set (-title)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *infile == "" {
|
|
||||||
log.Fatalln("Post text file must be set (-text)")
|
|
||||||
}
|
|
||||||
|
|
||||||
if *id == "" {
|
|
||||||
log.Fatalln("Post ID must be set (-id)")
|
|
||||||
}
|
|
||||||
|
|
||||||
var postDate day
|
|
||||||
if *date != "" {
|
|
||||||
t, err := time.Parse("2006-01-02", *date)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Invalid post date", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
postDate = day(t)
|
|
||||||
} else {
|
|
||||||
postDate = day(time.Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := ioutil.ReadFile(*infile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Failed to read post:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
post := createPost(*id, *title, string(t), postDate)
|
|
||||||
|
|
||||||
log.Println("Writing post to DNS ...")
|
|
||||||
err = post.writeToDNS()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Failed to write post:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println("Successfully wrote entries")
|
|
||||||
}
|
|
Loading…
Add table
Reference in a new issue