-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
include processing + execute statement
- Loading branch information
1 parent
e05d25e
commit d8a744e
Showing
17 changed files
with
610 additions
and
15 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
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,113 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Mandelsoft. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package execute | ||
|
||
import ( | ||
"fmt" | ||
"os/exec" | ||
|
||
"github.com/mandelsoft/filepath/pkg/filepath" | ||
|
||
"github.com/mandelsoft/mdgen/scanner" | ||
"github.com/mandelsoft/mdgen/statements/include" | ||
) | ||
|
||
func init() { | ||
scanner.Tokens.RegisterStatement(NewStatement()) | ||
} | ||
|
||
type Statement struct { | ||
scanner.StatementBase | ||
} | ||
|
||
func NewStatement() scanner.Statement { | ||
return &Statement{scanner.NewStatementBase("execute")} | ||
} | ||
|
||
func (s *Statement) Start(p scanner.Parser, e scanner.Element) (scanner.Element, error) { | ||
if !e.HasTags() { | ||
return nil, e.Errorf("command missing") | ||
} | ||
|
||
n := NewExecuteNode(p.State.Container, p.Document(), e.Location(), e.Tags()) | ||
p.State.Container.AddNode(n) | ||
return scanner.ParseElementsUntil(p, func(p scanner.Parser, e scanner.Element) (scanner.Element, error) { | ||
switch e.Token() { | ||
case "range": | ||
return include.ParseRange(p, &n.ContentHandler, e) | ||
case "pattern": | ||
return include.ParsePattern(p, &n.ContentHandler, e) | ||
case "filter": | ||
return include.ParseFilter(p, &n.ContentHandler, e) | ||
} | ||
return e, nil | ||
}) | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
|
||
type ExecuteNodeContext struct { | ||
scanner.NodeContextBase[*executenode] | ||
command []string | ||
dir string | ||
} | ||
|
||
func NewExecuteNodeContext(n *executenode, ctx scanner.ResolutionContext, command []string, dir string) *ExecuteNodeContext { | ||
return &ExecuteNodeContext{ | ||
NodeContextBase: scanner.NewNodeContextBase(n, ctx), | ||
command: command, | ||
dir: dir, | ||
} | ||
} | ||
|
||
type ExecuteNode = *executenode | ||
|
||
type executenode struct { | ||
scanner.NodeBase | ||
tags []string | ||
|
||
include.ContentHandler | ||
} | ||
|
||
func NewExecuteNode(p scanner.NodeContainer, d scanner.Document, location scanner.Location, tags []string) ExecuteNode { | ||
return &executenode{ | ||
NodeBase: scanner.NewNodeBase(d, location), | ||
tags: tags, | ||
} | ||
} | ||
|
||
func (n *executenode) Print(gap string) { | ||
fmt.Printf("%sEXECUTE %v\n", gap, n.tags) | ||
} | ||
|
||
func (n *executenode) Register(ctx scanner.ResolutionContext) error { | ||
dir := filepath.Dir(n.Source()) | ||
cmd := n.tags | ||
|
||
nctx := NewExecuteNodeContext(n, ctx, cmd, dir) | ||
ctx.SetNodeContext(n, nctx) | ||
return nil | ||
} | ||
|
||
func (n *executenode) Emit(ctx scanner.ResolutionContext) error { | ||
nctx := scanner.GetNodeContext[*ExecuteNodeContext](ctx, n) | ||
|
||
cmd := exec.Command(nctx.command[0], nctx.command[1:]...) | ||
cmd.Dir = nctx.dir | ||
data, err := cmd.Output() | ||
if err != nil { | ||
return n.Errorf("cannot execute %v: %s", nctx.command, err) | ||
} | ||
|
||
data, err = n.Process(data) | ||
if err != nil { | ||
return n.Errorf("%v: %s", n.tags, err) | ||
} | ||
|
||
fmt.Fprintf(ctx.Writer(), "%s\n", string(data)) | ||
return 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,66 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2023 Mandelsoft. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package include | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"strings" | ||
|
||
"github.com/mandelsoft/mdgen/scanner" | ||
) | ||
|
||
func init() { | ||
scanner.Keywords.Register("filter", true) | ||
|
||
} | ||
|
||
func ParseFilter(p scanner.Parser, n *ContentHandler, e scanner.Element) (scanner.Element, error) { | ||
key, err := e.Tag("filter expression") | ||
if err != nil { | ||
return nil, err | ||
} | ||
if n.filter != nil { | ||
return nil, e.Errorf("filter already set") | ||
} | ||
|
||
m, err := regexp.Compile(key) | ||
if err != nil { | ||
return nil, e.Errorf("invalid filter key (%s): %s", key, err) | ||
} | ||
|
||
n.filter = &RegExpFilter{ | ||
pattern: m, | ||
} | ||
return p.NextElement() | ||
} | ||
|
||
//////////////////////////////////////////////////////////////////////////////// | ||
|
||
type RegExpFilter struct { | ||
pattern *regexp.Regexp | ||
} | ||
|
||
func (i *RegExpFilter) Filter(data []byte) ([]byte, error) { | ||
if i == nil || i.pattern == nil { | ||
return data, nil | ||
} | ||
sep := "" | ||
if strings.HasPrefix(i.pattern.String(), "(?m)") { | ||
sep = "\n" | ||
} | ||
matches := i.pattern.FindAllSubmatch(data, -1) | ||
var result []byte | ||
for _, m := range matches { | ||
if len(m) != 2 { | ||
return nil, fmt.Errorf("regular expression must contain one matching group") | ||
} | ||
result = append(result, m[1]...) | ||
result = append(result, []byte(sep)...) | ||
} | ||
return result, nil | ||
} |
Oops, something went wrong.