drawio-export/pkg/drawio/export.go
2023-04-09 21:08:35 +07:00

156 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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...)
}