~chrisppy/go-barefeed

ff17c3718fe91fd00b8bd4d8bc71984d6e1ff341 — Chris Palmer 3 months ago 612d5fb
add tests and fixes
2 files changed, 33 insertions(+), 269 deletions(-)

M Makefile
M barefeed.go
M Makefile => Makefile +3 -0
@@ 33,4 33,7 @@ test:
tidy:
	$(GO) mod tidy

gen:
	$(GO) run git.sr.ht/~sircmpwn/go-bare/cmd/gen \
		-p barefeed schema.bare schema.go


M barefeed.go => barefeed.go +30 -269
@@ 5,297 5,58 @@ package barefeed

import (
	"fmt"
	"os"
	"path/filepath"
	"io"

	"git.sr.ht/~sircmpwn/go-bare"
)

// FeedEntries map
type FeedEntries map[string]FeedEntry
// FeedMap map of Linked
type FeedMap map[string]Linked

// FeedEntry containing the linkage between a Feed and Entry
type FeedEntry struct {
// Linked containing the linkage between a Feed and Entry
type Linked struct {
	Feed    Feed
	Entries map[string]Entry
}

// Importer contains the source path to the barefeed file
//type Importer struct {
//	Path string
//}

// Exporter containers the source path to the barefeed directory
//type Exporter struct {
//	Path string
//}

// NewImporter creates the importer based on the source path to the barefeed
// file.
//func NewImporter(source ...string) *Importer {
//	return &Importer{Path: filepath.Join(source...)}
//}

// Import a barefeed file to the target location
//func (d *Importer) Import(target ...string) (err error) {
//	var f *os.File
//	f, err = os.Open(filepath.Clean(d.Path))
//	if err != nil {
//		return
//	}
//
//	defer func() {
//		err = f.Close()
//	}()
//
//	var gzf *gzip.Reader
//	gzf, err = gzip.NewReader(f)
//	if err != nil {
//		return
//	}
//
//	defer func() {
//		err = gzf.Close()
//	}()
//
//	p := filepath.Join(target...)
//	p = filepath.Join(p, "barefeed")
//
//	tf := tar.NewReader(gzf)
//	for {
//		var exit bool
//		if exit, err = writeFromArchive(tf, p); err != nil {
//			return
//		} else if exit {
//			break
//		}
//	}
//
//	return
//}

// NewExporter creates the exporter based on the directory path that contains
// the barefeed folder.
//func NewExporter(directory ...string) *Exporter {
//	d := filepath.Join(directory...)
//	d = filepath.Join(d, "barefeed")
//	return &Exporter{Path: d}
//}

// Export a barefeed file to the target location
//func (d *Exporter) Export(target ...string) (err error) {
//	if _, err = os.Stat(d.Path); err != nil {
//		return
//	}
//
//	date := time.Now().Format("2006-01-02")
//
//	path := filepath.Join(target...)
//	path = filepath.Join(path, fmt.Sprintf("%s.barefeed", date))
//
//	var f *os.File
//	f, err = os.Create(path)
//	if err != nil {
//		return
//	}
//	defer func() {
//		err = f.Close()
//	}()
//
//	gz := gzip.NewWriter(f)
//	defer func() {
//		err = gz.Close()
//	}()
//
//	tw := tar.NewWriter(gz)
//	defer func() {
//		err = tw.Close()
//	}()
//
//	err = filepath.Walk(d.Path, func(path string, fi os.FileInfo, e error) error {
//		if e != nil {
//			return e
//		} else if !fi.Mode().IsRegular() {
//			return nil
//		}
//
//		header, e := tar.FileInfoHeader(fi, fi.Name())
//		if e != nil {
//			return e
//		}
//
//		header.Name = strings.TrimPrefix(strings.Replace(path, d.Path, "", -1), string(filepath.Separator))
//
//		if e := tw.WriteHeader(header); e != nil {
//			return e
//		}
//
//		file, e := os.Open(filepath.Clean(path))
//		if e != nil {
//			return e
//		}
//
//		if _, e := io.Copy(tw, file); e != nil {
//			if e := file.Close(); e != nil {
//				return e
//			}
//			return e
//		}
//
//		return file.Close()
//	})
//
//	return
//}

// Read will parse the provided directory for a barefeed directory
func Read(directory ...string) (FeedEntries, error) {
	fem := make(FeedEntries)

	d := filepath.Join(directory...)
	d = filepath.Join(d, "barefeed")
	if err := filepath.Walk(filepath.Clean(d), fem.walk); err != nil {
		return nil, err
	}

	return fem, nil
}

// Write the Feed to a bin file
func (d Feed) Write(generator string, path ...string) error {
	bin := Bin{
		Generator: generator,
		Content:   d,
	}

	return writeBin(bin)
}

// Write the Entry to a bin file. Path should be where you want the barefeed
// directory to exist
func (d Entry) Write(generator string, path ...string) error {
	bin := Bin{
		Generator: generator,
		Content:   d,
	}

	return writeBin(bin)
}

func (d FeedEntries) walk(path string, f os.FileInfo, err error) error {
	if err != nil {
		return err
	} else if f.IsDir() {
		return nil
	} else if filepath.Ext(path) != ".bin" {
		return nil
	}

	fe, err := readFile(path)
	if err != nil {
		return err
// Read will open the provided reader and load it into the FeedEntry
func (d FeedMap) Read(reader io.Reader) (err error) {
	var b Bin
	if err = bare.UnmarshalReader(reader, &b); err != nil {
		return
	}

	switch content := fe.Content.(type) {
	switch content := b.Content.(type) {
	case *Feed:
		l := Linked{
			Feed:    *content,
			Entries: make(map[string]Entry),
		}
		if v, ok := d[content.FeedID]; ok {
			d[content.FeedID] = FeedEntry{
				Feed:    *content,
				Entries: v.Entries,
			}
		} else {
			d[content.FeedID] = FeedEntry{
				Feed:    *content,
				Entries: make(map[string]Entry),
			}
			l.Entries = v.Entries
		}

		d[content.FeedID] = l
	case *Entry:
		if _, ok := d[content.FeedID]; ok {
			d[content.FeedID].Entries[content.EntryID] = *content
		} else {
			d[content.FeedID] = FeedEntry{
				Entries: make(map[string]Entry),
			}
			d[content.FeedID].Entries[content.EntryID] = *content
			return
		}
	default:
		return fmt.Errorf("unknown %+v for %s", content, path)
	}

	return nil
}

func writeBin(bin Bin, path ...string) (err error) {
	p := filepath.Join(path...)

	if filepath.Ext(p) != ".bin" {
		err = fmt.Errorf("must be a .bin file")
		return
	}

	var f *os.File
	f, err = os.Create(filepath.Clean(p))
	if err != nil {
		return
		d[content.FeedID] = Linked{
			Entries: map[string]Entry{
				content.EntryID: *content,
			},
		}
	default:
		err = fmt.Errorf("unknown type provided %+v", content)
	}

	defer func() {
		err = f.Close()
	}()

	w := bare.NewWriter(f)
	err = bare.MarshalWriter(w, &bin)

	return
}

func readFile(path ...string) (b Bin, err error) {
	var f *os.File
	f, err = os.Open(filepath.Clean(filepath.Join(path...)))
	if err != nil {
		return
	}

	defer func() {
		err = f.Close()
	}()

	err = bare.UnmarshalReader(f, &b)

	return
// Write will output the Bin to the provided io writer
func (d Bin) Write(writer io.Writer) error {
	w := bare.NewWriter(writer)
	return bare.MarshalWriter(w, &d)
}

//func writeFromArchive(tf *tar.Reader, p string) (exit bool, err error) {
//	var hdr *tar.Header
//	hdr, err = tf.Next()
//	if err == io.EOF {
//		err = nil
//		exit = true
//		return
//	} else if err != nil {
//		return
//	}
//
//	path := filepath.Join(p, hdr.Name)
//	info := hdr.FileInfo()
//	if info.IsDir() {
//		if err = os.MkdirAll(path, info.Mode()); err != nil {
//			return
//		}
//		return
//	}
//
//	var file *os.File
//	file, err = os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
//	if err != nil {
//		return
//	}
//
//	defer func() {
//		err = file.Close()
//	}()
//
//	_, err = io.Copy(file, tf)
//
//	return
//}