All checks were successful
drawio-export/pipeline/head This commit looks good
PR closes #1 Reviewed-on: #3
156 lines
3.7 KiB
Go
156 lines
3.7 KiB
Go
package drawio
|
||
|
||
import (
|
||
"bufio"
|
||
"errors"
|
||
"fmt"
|
||
"io"
|
||
"io/fs"
|
||
"os"
|
||
"os/exec"
|
||
"path"
|
||
"strconv"
|
||
"strings"
|
||
|
||
xmlparser "github.com/tamerh/xml-stream-parser"
|
||
)
|
||
|
||
// Создать нового экспортёра диаграмм
|
||
func New(opt ...Option) Exporter {
|
||
options := &Options{
|
||
Application: "drawio",
|
||
Output: "export",
|
||
Format: Format("pdf"),
|
||
}
|
||
for _, opt := range opt {
|
||
opt.apply(options)
|
||
}
|
||
return NewWithOptions(options)
|
||
}
|
||
|
||
// Создать нового экспортёра с параметрами
|
||
func NewWithOptions(opts *Options) Exporter {
|
||
return Exporter{opts: opts}
|
||
}
|
||
|
||
// Экспортёр диаграмм
|
||
type Exporter struct {
|
||
opts *Options
|
||
}
|
||
|
||
// Экспорт диаграмм из указанный файлов или папок
|
||
func (exp Exporter) Export(fileOrDir ...string) error {
|
||
var (
|
||
err error
|
||
errs = []error{}
|
||
args = exp.opts.Args()
|
||
info fs.FileInfo
|
||
)
|
||
for _, item := range fileOrDir {
|
||
if info, err = os.Stat(item); err != nil {
|
||
errs = append(errs, err)
|
||
continue
|
||
}
|
||
if info.IsDir() {
|
||
err = exp.exportDir(item, args)
|
||
} else {
|
||
err = exp.exportFile(item, args)
|
||
}
|
||
if err != nil {
|
||
errs = append(errs, err)
|
||
}
|
||
}
|
||
return errors.Join(errs...)
|
||
}
|
||
|
||
// Разбирает данные и возвращает срез имён диаграмм в них
|
||
func Diagrams(reader io.Reader) ([]string, error) {
|
||
var (
|
||
result = []string{}
|
||
br = bufio.NewReader(reader)
|
||
parser = xmlparser.NewXMLParser(
|
||
br, "mxfile", "diagram",
|
||
).ParseAttributesOnly("diagram")
|
||
)
|
||
for xml := range parser.Stream() {
|
||
if xml.Err != nil {
|
||
return result, xml.Err
|
||
}
|
||
if items, ok := xml.Childs["diagram"]; ok {
|
||
for _, item := range items {
|
||
result = append(result, item.Attrs["name"])
|
||
}
|
||
}
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
// Экспорт диаграмм из всех файлов в папке
|
||
func (exp Exporter) exportDir(dirPath string, args []string, subDir ...string) error {
|
||
var (
|
||
entries []fs.DirEntry
|
||
err error
|
||
errs []error
|
||
)
|
||
if entries, err = os.ReadDir(dirPath); err != nil {
|
||
return err
|
||
}
|
||
for _, entry := range entries {
|
||
name := entry.Name()
|
||
outDir := make([]string, len(subDir), len(subDir)+1)
|
||
outDir = append(outDir, name)
|
||
if entry.IsDir() && exp.opts.Recursive {
|
||
err = exp.exportDir(path.Join(dirPath, name), args, outDir...)
|
||
} else {
|
||
err = exp.exportFile(path.Join(dirPath, name), args, outDir...)
|
||
}
|
||
if err != nil {
|
||
errs = append(errs, err)
|
||
}
|
||
}
|
||
return errors.Join(errs...)
|
||
}
|
||
|
||
// Экспорт файла с диаграммами
|
||
func (exp Exporter) exportFile(filePath string, args []string, subDir ...string) error {
|
||
var (
|
||
file *os.File
|
||
diagrams []string
|
||
err error
|
||
)
|
||
if file, err = os.Open(filePath); err != nil {
|
||
return err
|
||
}
|
||
defer file.Close()
|
||
if diagrams, err = Diagrams(file); err != nil {
|
||
return err
|
||
}
|
||
outDirs := make([]string, 1, len(subDir)+1)
|
||
outDirs[0] = exp.opts.Output
|
||
outDirs = append(outDirs, subDir...)
|
||
output := path.Join(outDirs...)
|
||
errs := []error{}
|
||
for i, name := range diagrams {
|
||
outName := strings.TrimSuffix(path.Base(filePath), path.Ext(filePath))
|
||
if !exp.opts.RemovePageSuffix || len(diagrams) > 1 {
|
||
outName += "-" + name
|
||
}
|
||
outName += exp.opts.OutExt()
|
||
drawioArgs := make([]string, len(args), len(args)+4)
|
||
copy(drawioArgs, args)
|
||
drawioArgs = append(drawioArgs,
|
||
"--page-index", strconv.Itoa(i),
|
||
"--output", path.Join(output, outName),
|
||
"--export", filePath,
|
||
)
|
||
cmd := exec.Command(exp.opts.App(), drawioArgs...)
|
||
cmd.Stdout = os.Stdout
|
||
cmd.Stderr = os.Stderr
|
||
fmt.Println("Run command:", cmd.Path, cmd.Args)
|
||
if err = cmd.Run(); err != nil {
|
||
errs = append(errs, err)
|
||
}
|
||
}
|
||
return errors.Join(errs...)
|
||
}
|