Skip to content

Commit

Permalink
simple file system resource handler
Browse files Browse the repository at this point in the history
  • Loading branch information
g-pavlov committed Oct 25, 2020
1 parent a6b6ac0 commit d650149
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 13 deletions.
5 changes: 4 additions & 1 deletion cmd/app/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
//"github.com/gardener/docforge/pkg/metrics"
"github.com/gardener/docforge/pkg/processors"
"github.com/gardener/docforge/pkg/reactor"
"github.com/gardener/docforge/pkg/resourcehandlers/fs"
ghrs "github.com/gardener/docforge/pkg/resourcehandlers/github"

"github.com/google/go-github/v32/github"
Expand Down Expand Up @@ -112,7 +113,9 @@ func WithHugo(reactorOptions *reactor.Options, o *Options) {
// initResourceHandlers initializes the resource handler
// objects used by reactors
func initResourceHandlers(ctx context.Context, o *Options) []resourcehandlers.ResourceHandler {
rhs := []resourcehandlers.ResourceHandler{}
rhs := []resourcehandlers.ResourceHandler{
fs.NewFSResourceHandler(),
}
if o.GitHubTokens != nil {
if token, ok := o.GitHubTokens["github.com"]; ok {
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
Expand Down
4 changes: 3 additions & 1 deletion pkg/reactor/content_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ func (c *nodeContentProcessor) resolveLink(ctx context.Context, node *api.Node,
if handler == nil {
return &destination, text, title, nil, nil
}
absLink, err = handler.BuildAbsLink(contentSourcePath, destination)
if !u.IsAbs() {
absLink, err = handler.BuildAbsLink(contentSourcePath, destination)
}
if err != nil {
return nil, text, title, nil, err
}
Expand Down
14 changes: 3 additions & 11 deletions pkg/reactor/document_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"text/template"

"github.com/gardener/docforge/pkg/api"
Expand Down Expand Up @@ -97,17 +96,10 @@ func (w *DocumentWorker) Work(ctx context.Context, task interface{}, wq jobs.Wor
tmpl *template.Template
)
if tmpl, ok = w.templates[task.Node.Template.Path]; !ok {
// TODO: temporary solution for local templates
if !strings.HasPrefix(task.Node.Template.Path, "https") {
if templateBlob, err = ioutil.ReadFile(task.Node.Template.Path); err != nil {
return jobs.NewWorkerError(err, 0)
}
} else {
if templateBlob, err = w.Reader.Read(ctx, task.Node.Template.Path); err != nil {
return jobs.NewWorkerError(err, 0)
}
if templateBlob, err = w.Reader.Read(ctx, task.Node.Template.Path); err != nil {
return jobs.NewWorkerError(err, 0)
}
if tmpl, err = template.New("test").Parse(string(templateBlob)); err != nil {
if tmpl, err = template.New(task.Node.Template.Path).Parse(string(templateBlob)); err != nil {
return jobs.NewWorkerError(err, 0)
}
w.templates[task.Node.Template.Path] = tmpl
Expand Down
229 changes: 229 additions & 0 deletions pkg/resourcehandlers/fs/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package fs

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/gardener/docforge/pkg/api"
"github.com/gardener/docforge/pkg/git"
"github.com/gardener/docforge/pkg/resourcehandlers"
"github.com/google/go-github/v32/github"
)

type fsHandler struct{}

// NewFSResourceHandler create file system ResourceHandler
func NewFSResourceHandler() resourcehandlers.ResourceHandler {
return &fsHandler{}
}

// Accept implements resourcehandlers.ResourceHandler#Accept
func (fs *fsHandler) Accept(uri string) bool {
if _, err := os.Stat(uri); err == nil {
return true
}
return false
}

// ResolveNodeSelector implements resourcehandlers.ResourceHandler#ResolveNodeSelector
func (fs *fsHandler) ResolveNodeSelector(ctx context.Context, node *api.Node, excludePaths []string, frontMatter map[string]interface{}, excludeFrontMatter map[string]interface{}, depth int32) error {
var (
fileInfo os.FileInfo
err error
)
if node.NodeSelector == nil {
return nil
}
if fileInfo, err = os.Stat(node.NodeSelector.Path); err != nil {
return err
}
if !fileInfo.IsDir() {
return fmt.Errorf("nodeSelector path is not directory")
}
_node := &api.Node{
Nodes: []*api.Node{},
}
filepath.Walk(node.NodeSelector.Path, func(node *api.Node, parentPath string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if node.NodeSelector != nil {
return nil
}
if path != parentPath {
if len(strings.Split(path, "/"))-len(strings.Split(parentPath, "/")) != 1 {
node = node.Parent()
parentPathSegments := strings.Split(path, "/")
if len(parentPathSegments) > 0 {
parentPathSegments = parentPathSegments[:len(parentPathSegments)-1]
parentPath = filepath.Join(parentPathSegments...)
}
}
}
n := &api.Node{
Name: info.Name(),
}
n.SetParent(node)
node.Nodes = append(node.Nodes, n)
if info.IsDir() {
node = n
node.Nodes = []*api.Node{}
parentPath = path
} else {
n.Source = path
}
return nil
}
}(_node, node.NodeSelector.Path))
if len(_node.Nodes) > 0 && len(_node.Nodes[0].Nodes) > 0 {
node.Nodes = _node.Nodes[0].Nodes
for _, n := range node.Nodes {
n.SetParent(node)
}
}
return nil
}

func buildNodes(path string, info os.FileInfo) *api.Node {
return &api.Node{
Name: info.Name(),
Source: path,
}
}

// Read implements resourcehandlers.ResourceHandler#Read
func (fs *fsHandler) Read(ctx context.Context, uri string) ([]byte, error) {
return ioutil.ReadFile(uri)
}

// ReadGitInfo implements resourcehandlers.ResourceHandler#ReadGitInfo
func (fs *fsHandler) ReadGitInfo(ctx context.Context, uri string) ([]byte, error) {
var (
log []*gitLogEntry
blob []byte
err error
)
if log, err = gitLog(uri); err != nil {
return nil, err
}

if len(log) == 0 {
return []byte(""), nil
}

for _, logEntry := range log {
logEntry.Name = strings.Split(logEntry.Name, "<")[0]
logEntry.Name = strings.TrimSpace(logEntry.Name)
}
authorName := log[len(log)-1].Name
authorEmail := log[len(log)-1].Email
publishD := log[len(log)-1].Date
lastModD := log[0].Date
gitInfo := &git.GitInfo{
PublishDate: &publishD,
LastModifiedDate: &lastModD,
Author: &github.User{
Name: &authorName,
Email: &authorEmail,
},
Contributors: []*github.User{},
}

for _, logEntry := range log {
if logEntry.Email != *gitInfo.Author.Email {
name := logEntry.Name
email := logEntry.Email
gitInfo.Contributors = append(gitInfo.Contributors, &github.User{
Name: &name,
Email: &email,
})
}
}

if blob, err = json.MarshalIndent(gitInfo, "", " "); err != nil {
return nil, err
}

return blob, nil
}

// ResourceName implements resourcehandlers.ResourceHandler#ResourceName
func (fs *fsHandler) ResourceName(link string) (name string, extension string) {
_, name = filepath.Split(link)
if len(name) > 0 {
if e := filepath.Ext(name); len(e) > 0 {
extension = e[1:]
name = strings.TrimSuffix(name, e)
}
}
return
}

// BuildAbsLink implements resourcehandlers.ResourceHandler#BuildAbsLink
func (fs *fsHandler) BuildAbsLink(source, link string) (string, error) {
if filepath.IsAbs(link) {
return link, nil
}
p := filepath.Join(source, link)
p = filepath.Clean(p)
if filepath.IsAbs(p) {
return p, nil
}
return filepath.Abs(p)
}

// GetRawFormatLink implements resourcehandlers.ResourceHandler#GetRawFormatLink
func (fs *fsHandler) GetRawFormatLink(absLink string) (string, error) {
return absLink, nil
}

// SetVersion implements resourcehandlers.ResourceHandler#SetVersion
func (fs *fsHandler) SetVersion(absLink, version string) (string, error) {
return absLink, nil
}

type gitLogEntry struct {
Sha string
Author string
Date string
Message string
Email string
Name string
}

type gitLogEntryAuthor struct {
}

func gitLog(path string) ([]*gitLogEntry, error) {
var (
log []byte
err error
)

if _, err := os.Stat(path); err != nil {
return nil, err
}

git := exec.Command("git", "log", "--date=short", `--pretty=format:'{%n "sha": "%H",%n "author": "%aN <%aE>",%n "date": "%ad",%n "message": "%s",%n "email": "%aE",%n "name": "%aN"%n },'`, "--follow", path)
if log, err = git.CombinedOutput(); err != nil {
return nil, err
}

logS := string(log)
logS = strings.ReplaceAll(logS, "'{", "{")
logS = strings.ReplaceAll(logS, "},'", "},")
if strings.HasSuffix(logS, ",") {
logS = logS[:len(logS)-1]
}
logS = fmt.Sprintf("[%s]", logS)

gitLog := []*gitLogEntry{}
if err := json.Unmarshal([]byte(logS), &gitLog); err != nil {
return nil, err
}
return gitLog, nil
}
79 changes: 79 additions & 0 deletions pkg/resourcehandlers/fs/fs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package fs

import (
"path/filepath"
"testing"

"github.com/gardener/docforge/pkg/api"
"github.com/stretchr/testify/assert"
)

func TestGitLog(t *testing.T) {
var (
log []*gitLogEntry
err error
)
if log, err = gitLog(filepath.Join("testdata", "f00.md")); err != nil {
t.Fatalf("%s", err.Error())
}
assert.NotNil(t, log)
}

func TestReadGitInfo(t *testing.T) {
var (
log []byte
err error
)
fs := &fsHandler{}
if log, err = fs.ReadGitInfo(nil, filepath.Join("testdata", "f00.md")); err != nil {
t.Fatalf("%s", err.Error())
}
t.Logf("%s\n", log)
assert.NotNil(t, log)
}

func TestResolveNodeSelector(t *testing.T) {
var (
err error
)
fs := &fsHandler{}
node := &api.Node{
NodeSelector: &api.NodeSelector{
Path: "testdata",
},
}
expected := &api.Node{
NodeSelector: &api.NodeSelector{
Path: "testdata",
},
Nodes: []*api.Node{
&api.Node{
Name: "d00",
Nodes: []*api.Node{
&api.Node{
Name: "d02",
Nodes: []*api.Node{
&api.Node{
Name: "f020.md",
Source: "testdata/d00/d02/f020.md",
},
},
},
&api.Node{
Name: "f01.md",
Source: "testdata/d00/f01.md",
},
},
},
&api.Node{
Name: "f00.md",
Source: "testdata/f00.md",
},
},
}
expected.SetParentsDownwards()
if err = fs.ResolveNodeSelector(nil, node, nil, nil, nil, 0); err != nil {
t.Fatalf("%s", err.Error())
}
assert.Equal(t, expected, node)
}
Empty file.
Empty file.
Empty file.

0 comments on commit d650149

Please sign in to comment.