drawio-export/pkg/drawio/export.go
Алексей Бадяев 8d18d7291e
All checks were successful
drawio-export/pipeline/head This commit looks good
Автоматическая сборка пакетов Debian (#4)
This PR closes #2

Reviewed-on: #4
2023-04-12 22:37:54 +07:00

188 lines
4.6 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"
"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 {
exp := Exporter{opts: opts}
if opts.openFile == nil {
exp.openFile = func(name string) (io.ReadCloser, error) {
return os.Open(name)
}
} else {
exp.openFile = opts.openFile
}
if opts.readDir == nil {
exp.readDir = func(name string) ([]os.DirEntry, error) {
return os.ReadDir(name)
}
} else {
exp.readDir = opts.readDir
}
return exp
}
// Экспортёр диаграмм
type Exporter struct {
opts *Options // Параметры экспортёра диаграмм
openFile OpenFileFunc // Открыть файл
readDir ReadDirFunc // Прочитать папку на диске
}
// Экспорт диаграмм из указанный файлов или папок
func (exp Exporter) Export(fileOrDir ...string) error {
var (
commands = []*exec.Cmd{}
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
}
var addCommands []*exec.Cmd
if info.IsDir() {
addCommands, err = exp.ExportDir(item, args)
} else {
addCommands, err = exp.ExportFile(item, args)
}
commands = append(commands, addCommands...)
if err != nil {
errs = append(errs, err)
}
}
if err = RunSequence(commands...); err != nil {
errs = append(errs, err)
}
return errors.Join(errs...)
}
// Экспорт диаграмм из всех файлов в папке
func (exp Exporter) ExportDir(
dirPath string, args []string, subDir ...string,
) ([]*exec.Cmd, error) {
var (
commands = []*exec.Cmd{}
err error
entries []fs.DirEntry
errs []error
)
if entries, err = exp.readDir(dirPath); err != nil {
return commands, err
}
for _, entry := range entries {
name := entry.Name()
var addCommands []*exec.Cmd
if entry.IsDir() {
if exp.opts.Recursive {
deep := len(subDir)
outDir := make([]string, deep+1)
copy(outDir, subDir)
outDir[deep] = name
addCommands, err = exp.ExportDir(path.Join(dirPath, name), args, outDir...)
} else {
continue
}
} else {
addCommands, err = exp.ExportFile(path.Join(dirPath, name), args, subDir...)
}
commands = append(commands, addCommands...)
if err != nil {
errs = append(errs, err)
}
}
return commands, errors.Join(errs...)
}
// Экспорт файла с диаграммами
func (exp Exporter) ExportFile(
filePath string, args []string, subDir ...string,
) ([]*exec.Cmd, error) {
var (
commands = []*exec.Cmd{}
err error
file io.ReadCloser
diagrams []string
)
if file, err = exp.openFile(filePath); err != nil {
return commands, err
}
defer file.Close()
if diagrams, err = Diagrams(file); err != nil {
return commands, err
}
outDirs := make([]string, 1, len(subDir)+1)
outDirs[0] = exp.opts.OutDir()
outDirs = append(outDirs, subDir...)
output := path.Join(outDirs...)
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
commands = append(commands, cmd)
}
return commands, err
}
// Разбирает данные и возвращает срез имён диаграмм в них
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
}