/
markdown.go
134 lines (115 loc) · 3.4 KB
/
markdown.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
package main
import (
"context"
_ "embed"
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"strconv"
"strings"
"cloud.google.com/go/storage"
"github.com/alexflint/doc-publisher/googledoc"
"github.com/alexflint/doc-publisher/markdown"
"google.golang.org/api/docs/v1"
"google.golang.org/api/option"
)
type exportMarkdownArgs struct {
Input string `arg:"positional"`
SeparateBy string `help:"separate into multiple markdown files. Possible values: pagebreak"`
Output string `arg:"-o,--output"`
}
func exportMarkdown(ctx context.Context, args *exportMarkdownArgs) error {
// load the document from a file
d, err := googledoc.ReadFile(args.Input)
if err != nil {
return err
}
fmt.Printf("loaded a googledoc with %d images\n", len(d.Images))
// create a cloud storage client
storageClient, err := storage.NewClient(ctx,
option.WithCredentialsJSON(storageServiceAccount))
if err != nil {
return fmt.Errorf("error creating storage client: %w", err)
}
bucket := storageClient.Bucket(imageBucket)
// upload the images to cloud storage
var urls []string
for _, image := range d.Images {
extension := filepath.Ext(image.Filename)
if extension == "" {
extension = ".jpg"
}
url, err := uploadImage(ctx, bucket, extension, image.Content)
if err != nil {
return fmt.Errorf("%s: %w", image.Filename, err)
}
urls = append(urls, url)
}
// align the image URLs to the objects in the google doc
imageURLsByObjectID, err := googledoc.MatchObjectIDsToImages(d, urls)
if err != nil {
return err
}
// convert and export
switch args.SeparateBy {
case "":
// export the entire document as a single markdown file
md, err := markdown.FromGoogleDoc(d.Doc, imageURLsByObjectID)
if err != nil {
return err
}
// write the result to output
if args.Output == "" {
fmt.Println(md)
} else {
err = ioutil.WriteFile(args.Output, []byte(md), 0666)
if err != nil {
return fmt.Errorf("error writing to %s: %w", args.Output, err)
}
fmt.Printf("wrote markdown to %s\n", args.Output)
}
case "pagebreak":
// split the doc at page breaks into multiple markdown files
if !strings.Contains(args.Output, "INDEX") {
return errors.New("when using --separateby, output must be to a filename containing the string 'INDEX'")
}
var n int
var cur []*docs.StructuralElement
for i, elem := range d.Doc.Body.Content {
// determine whether this element contains a page break
var found bool
if elem.Paragraph != nil {
for _, e := range elem.Paragraph.Elements {
if e.PageBreak != nil {
found = true
break
}
}
}
// if we have a page break then write out the next document
if found || i == len(d.Doc.Body.Content)-1 {
// convert segment of the google doc to markdown
md, err := markdown.FromGoogleDocSegment(d.Doc, cur, imageURLsByObjectID)
if err != nil {
return err
}
// write markdown to a file
filename := strings.ReplaceAll(args.Output, "INDEX", strconv.Itoa(n+1))
err = ioutil.WriteFile(filename, []byte(md), 0666)
if err != nil {
return fmt.Errorf("error writing to %s: %w", filename, err)
}
fmt.Printf("wrote markdown to %s\n", filename)
// reset the elements and increment the counter
cur = make([]*docs.StructuralElement, 0, 1000)
n += 1
} else {
cur = append(cur, elem)
}
}
default:
return fmt.Errorf("invalid value for --separateby: %q", args.SeparateBy)
}
return nil
}