compile.go 3.46 KB
Newer Older
Ma_124's avatar
Ma_124 committed
1 2 3 4
package awesomefw

import (
	"bufio"
Ma_124's avatar
Ma_124 committed
5
	"github.com/schollz/progressbar"
Ma_124's avatar
Ma_124 committed
6 7 8 9
	"io"
	"os"
)

Ma_124's avatar
Ma_124 committed
10
// The file format according to which the input will be parsed.
Ma_124's avatar
Ma_124 committed
11
type InputFileFormat struct {
Ma_124's avatar
Ma_124 committed
12
	// This function should parse a line and call either outFF.Item() or outFF.Literal()
Ma_124's avatar
Ma_124 committed
13 14 15
	ParseLine func(out io.Writer, l string, outFF *OutputFileFormat, ctx *Ctx)
}

Ma_124's avatar
Ma_124 committed
16
// This is the context that is passed between the IFF, OFF, FetchMeta and many more.
Ma_124's avatar
Ma_124 committed
17
type Ctx struct {
Ma_124's avatar
Ma_124 committed
18 19 20 21 22 23 24 25 26 27
	// This is the context for the IFF
	InFFCtx map[string]interface{}

	// This is the context for the OFF
	OutFFCtx map[string]interface{}

	fetchMetaGhRequests int // TODO

	// This is the API config passed to FetchMeta
	ApisCfg *ApisCfg
Ma_124's avatar
Ma_124 committed
28 29
}

30 31
// An Item usually consists at least of a name, url and description
type Item struct {
Ma_124's avatar
Ma_124 committed
32 33
	Name    string
	Url     string
34
	RepoUrl string
Ma_124's avatar
Ma_124 committed
35
	Desc    string
36 37
}

Ma_124's avatar
Ma_124 committed
38
// The output file format
Ma_124's avatar
Ma_124 committed
39
type OutputFileFormat struct {
Ma_124's avatar
Ma_124 committed
40
	// This should write the literal l to out
Ma_124's avatar
Ma_124 committed
41
	Literal func(out io.Writer, l string, ctx *Ctx)
Ma_124's avatar
Ma_124 committed
42 43

	// This should write the formatted item to out
44
	Item func(out io.Writer, item *Item, ctx *Ctx)
Ma_124's avatar
Ma_124 committed
45 46 47 48 49 50

	// This function is called to initialize the OFF and it's context. It can be nil.
	Start func(out io.Writer, ctx *Ctx)

	// This function is called to teardown the OFF and it's context. It can be nil.
	End func(out io.Writer, ctx *Ctx)
Ma_124's avatar
Ma_124 committed
51 52
}

Ma_124's avatar
Ma_124 committed
53
// This holds ApiCfgs for each API used by FetchMeta
54
type ApisCfg struct {
Ma_124's avatar
Ma_124 committed
55 56
	UseProgressBar bool
	GitHubCfg      *ApiCfg
57 58
}

Ma_124's avatar
Ma_124 committed
59
// This is used by FetchMeta to get the access token and the maximum number of requests for any given API.
60
type ApiCfg struct {
Ma_124's avatar
Ma_124 committed
61 62
	// This is an access token passed to the API
	// NOTE: Make sure your access tokens aren't in the source code.
63
	AccessToken string
Ma_124's avatar
Ma_124 committed
64 65 66

	// This variable specifies how many requests should be made to the API before falling back to a default response.
	// NOTE: This should only be used for development purposes.
67 68 69
	MaxRequests int
}

Ma_124's avatar
Ma_124 committed
70
// Opens the file and runs Compile
71
func CompileFile(inpPath string, out io.Writer, inFF *InputFileFormat, outFF *OutputFileFormat, apis *ApisCfg) {
Ma_124's avatar
Ma_124 committed
72 73 74 75 76 77 78 79 80 81 82
	fi, err := os.Stat(inpPath)
	if err != nil {
		panic(err)
	}

	f, err := os.Open(inpPath)
	if err != nil {
		panic(err)
	}
	defer f.Close()

83
	Compile(f, int(fi.Size()), out, inFF, outFF, apis)
Ma_124's avatar
Ma_124 committed
84 85
}

Ma_124's avatar
Ma_124 committed
86 87 88 89 90 91 92 93 94
func NewCtx(apis *ApisCfg) *Ctx {
	return &Ctx{
		InFFCtx:  make(map[string]interface{}),
		OutFFCtx: make(map[string]interface{}),
		ApisCfg:  apis,
	}
}

func NewDebugReqsApisCfg() *ApisCfg {
Ma_124's avatar
Ma_124 committed
95 96 97 98 99
	return &ApisCfg{false, &ApiCfg{"", 6000}}
}

func NewDebugCfg() *ApisCfg {
	return &ApisCfg{false, &ApiCfg{}}
Ma_124's avatar
Ma_124 committed
100 101 102 103 104 105
}

func NewDebugCtx() *Ctx {
	return NewCtx(NewDebugReqsApisCfg())
}

Ma_124's avatar
Ma_124 committed
106 107 108
// Parses the file conforming to inFF and writes the output of outFF to out.
// The size argument is used to provide a progressbar.
// The apis config is forwarded to FetchMeta.
109
func Compile(in io.Reader, size int, out io.Writer, inFF *InputFileFormat, outFF *OutputFileFormat, apis *ApisCfg) {
Ma_124's avatar
Ma_124 committed
110 111 112 113 114
	var pb *progressbar.ProgressBar
	if apis.UseProgressBar {
		pb = progressbar.New(size)
	}

Ma_124's avatar
Ma_124 committed
115 116 117 118
	r := bufio.NewReader(in)

	offset := 0

Ma_124's avatar
Ma_124 committed
119
	ctx := NewCtx(apis)
120 121 122

	if outFF.Start != nil {
		outFF.Start(out, ctx)
Ma_124's avatar
Ma_124 committed
123 124 125 126
	}

	eofReached := false
	for !eofReached {
127
		l, err := r.ReadString('\n') // TODO add support CR
Ma_124's avatar
Ma_124 committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
		if err != nil {
			if err == io.EOF {
				if len(l) == 0 {
					break
				}
				eofReached = true
				l += "\n"
			} else {
				panic(err)
			}
		}

		inFF.ParseLine(out, l, outFF, ctx)

		offset += len(l)
Ma_124's avatar
Ma_124 committed
143 144 145
		if apis.UseProgressBar {
			_ = pb.Set(offset)
		}
Ma_124's avatar
Ma_124 committed
146
	}
147 148 149 150

	if outFF.End != nil {
		outFF.End(out, ctx)
	}
Ma_124's avatar
Ma_124 committed
151
}