flamenco/cmd/addon-packer/addon-packer.go
Sybren A. Stüvel 1b40038e3d Add Go program that can create the addon ZIP file
Use Go to create the addon ZIP file, to be independent of any ZIP
executable being installed on the system.
2022-06-27 15:58:14 +02:00

166 lines
4.2 KiB
Go

package main
import (
"archive/zip"
"compress/flate"
"flag"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"time"
"github.com/mattn/go-colorable"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"git.blender.org/flamenco/internal/appinfo"
)
var cliArgs struct {
// Do-and-quit flags.
version bool
// Logging level flags.
quiet, debug, trace bool
filename string
}
func main() {
parseCliArgs()
if cliArgs.version {
fmt.Println(appinfo.ApplicationVersion)
return
}
output := zerolog.ConsoleWriter{Out: colorable.NewColorableStdout(), TimeFormat: time.RFC3339}
log.Logger = log.Output(output)
configLogLevel()
outfile, err := filepath.Abs(cliArgs.filename)
if err != nil {
log.Fatal().Err(err).Str("filepath", cliArgs.filename).Msg("unable make output file path absolute")
}
// Open the output file.
logger := log.With().Str("zipname", outfile).Logger()
logger.Info().Msg("creating ZIP file")
zipFile, err := os.Create(outfile)
if err != nil {
logger.Fatal().Err(err).Msg("error creating file")
}
defer zipFile.Close()
zipWriter := zip.NewWriter(zipFile)
zipWriter.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
return flate.NewWriter(out, flate.BestCompression)
})
// CD to the addon/flamenco dir.
if err := os.Chdir("addon/flamenco"); err != nil {
log.Fatal().Err(err).Msg("unable to cd to addon/flamenco")
}
basePath, err := os.Getwd()
if err != nil {
logger.Fatal().Err(err).Msg("error getting current working directory")
}
// Copy all the files into the ZIP.
addToZip := func(path string, d fs.DirEntry, err error) error {
sublog := log.With().Str("path", path).Logger()
if err != nil {
sublog.Error().Err(err).Msg("error received from filepath.WalkDir, aborting")
return err
}
// Construct the path inside the ZIP file.
relpath, err := filepath.Rel(basePath, path)
if err != nil {
return fmt.Errorf("making %s relative to %s: %w", path, basePath, err)
}
if d.IsDir() {
switch {
case filepath.Base(path) == "__pycache__":
return fs.SkipDir
case relpath == filepath.Join("manager", "docs"):
return fs.SkipDir
case strings.HasPrefix(filepath.Base(path), "."):
// Skip directories like .mypy_cache, etc.
return fs.SkipDir
default:
// Just recurse into this directory.
return nil
}
}
sublog.Debug().Str("path", relpath).Msg("adding file to ZIP")
// Read the file's contents. These are just Python files and maybe a Wheel,
// nothing huge.
contents, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("reading %s: %w", path, err)
}
// Write into the ZIP file.
fileInZip, err := zipWriter.Create(relpath)
if err != nil {
return fmt.Errorf("creating %s in ZIP: %w", relpath, err)
}
_, err = fileInZip.Write(contents)
if err != nil {
return fmt.Errorf("writing to %s in ZIP: %w", relpath, err)
}
return nil
}
logger.Debug().Str("cwd", basePath).Msg("walking directory")
if err := filepath.WalkDir(basePath, addToZip); err != nil {
logger.Fatal().Err(err).Msg("error filling ZIP file")
}
comment := fmt.Sprintf("%s add-on for Blender, version %s",
appinfo.ApplicationName,
appinfo.ApplicationVersion,
)
if err := zipWriter.SetComment(comment); err != nil {
logger.Fatal().Err(err).Msg("error setting ZIP comment")
}
if err := zipWriter.Close(); err != nil {
logger.Fatal().Err(err).Msg("error closing ZIP file")
}
}
func parseCliArgs() {
flag.BoolVar(&cliArgs.version, "version", false, "Shows the application version, then exits.")
flag.BoolVar(&cliArgs.quiet, "quiet", false, "Only log warning-level and worse.")
flag.BoolVar(&cliArgs.debug, "debug", false, "Enable debug-level logging.")
flag.BoolVar(&cliArgs.trace, "trace", false, "Enable trace-level logging.")
flag.StringVar(&cliArgs.filename, "filename", "web/static/flamenco-addon.zip", "Filename to save the add-on to.")
flag.Parse()
}
func configLogLevel() {
var logLevel zerolog.Level
switch {
case cliArgs.trace:
logLevel = zerolog.TraceLevel
case cliArgs.debug:
logLevel = zerolog.DebugLevel
case cliArgs.quiet:
logLevel = zerolog.WarnLevel
default:
logLevel = zerolog.InfoLevel
}
zerolog.SetGlobalLevel(logLevel)
}