-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
318 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.