From 3fd414fa81f92d8d53540a39109593da26d07de2 Mon Sep 17 00:00:00 2001 From: NeedsSoySauce Date: Fri, 15 Nov 2024 12:42:40 +1300 Subject: [PATCH] Add method to configure system process attributes --- exiftool.go | 58 +++++++++++++++++++++++++++++++--------- exiftool_windows_test.go | 28 +++++++++++++++++++ 2 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 exiftool_windows_test.go diff --git a/exiftool.go b/exiftool.go index fb9dc27..e05518f 100644 --- a/exiftool.go +++ b/exiftool.go @@ -11,6 +11,7 @@ import ( "os/exec" "strings" "sync" + "syscall" "time" ) @@ -48,6 +49,7 @@ type Exiftool struct { cmd *exec.Cmd backupOriginal bool clearFieldsBeforeWriting bool + sysProcAttr *syscall.SysProcAttr } // NewExiftool instanciates a new Exiftool with configuration functions. If anything went @@ -70,6 +72,7 @@ func NewExiftool(opts ...func(*Exiftool) error) (*Exiftool, error) { } e.cmd = exec.Command(e.exiftoolBinPath, args...) + e.cmd.SysProcAttr = e.sysProcAttr r, w := io.Pipe() e.stdMergedOut = r @@ -210,7 +213,8 @@ func (e *Exiftool) ExtractMetadata(files ...string) []FileMetadata { // WriteMetadata writes the given metadata for each file. // Any errors will be saved to FileMetadata.Err // Note: If you're reusing an existing FileMetadata instance, -// you should nil the Err before passing it to WriteMetadata +// +// you should nil the Err before passing it to WriteMetadata func (e *Exiftool) WriteMetadata(fileMetadata []FileMetadata) { e.lock.Lock() defer e.lock.Unlock() @@ -316,8 +320,9 @@ func handleWriteMetadataResponse(resp string) error { // Buffer defines the buffer used to read from stdout and stderr, see https://golang.org/pkg/bufio/#Scanner.Buffer // Sample : -// buf := make([]byte, 128*1000) -// e, err := NewExiftool(Buffer(buf, 64*1000)) +// +// buf := make([]byte, 128*1000) +// e, err := NewExiftool(Buffer(buf, 64*1000)) func Buffer(buf []byte, max int) func(*Exiftool) error { return func(e *Exiftool) error { e.bufferSet = true @@ -329,7 +334,8 @@ func Buffer(buf []byte, max int) func(*Exiftool) error { // Charset defines the -charset value to pass to Exiftool, see https://exiftool.org/faq.html#Q10 and https://exiftool.org/faq.html#Q18 // Sample : -// e, err := NewExiftool(Charset("filename=utf8")) +// +// e, err := NewExiftool(Charset("filename=utf8")) func Charset(charset string) func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-charset", charset) @@ -339,7 +345,8 @@ func Charset(charset string) func(*Exiftool) error { // Api defines an -api value to pass to Exiftool, see https://www.exiftool.org/exiftool_pod.html#Advanced-options // Sample : -// e, err := NewExiftool(Api("QuickTimeUTC")) +// +// e, err := NewExiftool(Api("QuickTimeUTC")) func Api(apiValue string) func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-api", apiValue) @@ -349,7 +356,8 @@ func Api(apiValue string) func(*Exiftool) error { // NoPrintConversion enables 'No print conversion' mode, see https://exiftool.org/exiftool_pod.html. // Sample : -// e, err := NewExiftool(NoPrintConversion()) +// +// e, err := NewExiftool(NoPrintConversion()) func NoPrintConversion() func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-n") @@ -359,7 +367,8 @@ func NoPrintConversion() func(*Exiftool) error { // ExtractEmbedded extracts embedded metadata from files (activates Exiftool's '-ee' paramater) // Sample : -// e, err := NewExiftool(ExtractEmbedded()) +// +// e, err := NewExiftool(ExtractEmbedded()) func ExtractEmbedded() func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-ee") @@ -369,7 +378,8 @@ func ExtractEmbedded() func(*Exiftool) error { // ExtractAllBinaryMetadata extracts all binary metadata (activates Exiftool's '-b' paramater) // Sample : -// e, err := NewExiftool(ExtractAllBinaryMetadata()) +// +// e, err := NewExiftool(ExtractAllBinaryMetadata()) func ExtractAllBinaryMetadata() func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-b") @@ -379,7 +389,8 @@ func ExtractAllBinaryMetadata() func(*Exiftool) error { // DateFormant defines the -dateFormat value to pass to Exiftool, see https://exiftool.org/ExifTool.html#DateFormat // Sample : -// e, err := NewExiftool(DateFormant("%s")) +// +// e, err := NewExiftool(DateFormant("%s")) func DateFormant(format string) func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-dateFormat", format) @@ -389,7 +400,8 @@ func DateFormant(format string) func(*Exiftool) error { // CoordFormant defines the -coordFormat value to pass to Exiftool, see https://exiftool.org/ExifTool.html#CoordFormat // Sample : -// e, err := NewExiftool(CoordFormant("%+f")) +// +// e, err := NewExiftool(CoordFormant("%+f")) func CoordFormant(format string) func(*Exiftool) error { return func(e *Exiftool) error { e.extraInitArgs = append(e.extraInitArgs, "-coordFormat", format) @@ -399,6 +411,7 @@ func CoordFormant(format string) func(*Exiftool) error { // PrintGroupNames prints the group names for each tag based on the pass group number(s), (activates Exiftool's '-G' paramater) // Sample : +// // e, err := NewExiftool(PrintGroupNames("0")) func PrintGroupNames(groupNumbers string) func(*Exiftool) error { return func(e *Exiftool) error { @@ -410,7 +423,8 @@ func PrintGroupNames(groupNumbers string) func(*Exiftool) error { // BackupOriginal backs up the original file when writing the file metadata // instead of overwriting the original (activates Exiftool's '-overwrite_original' parameter) // Sample : -// e, err := NewExiftool(BackupOriginal()) +// +// e, err := NewExiftool(BackupOriginal()) func BackupOriginal() func(*Exiftool) error { return func(e *Exiftool) error { e.backupOriginal = true @@ -421,7 +435,8 @@ func BackupOriginal() func(*Exiftool) error { // ClearFieldsBeforeWriting will clear existing fields (e.g. tags) in the file before writing any // new tags // Sample : -// e, err := NewExiftool(ClearFieldsBeforeWriting()) +// +// e, err := NewExiftool(ClearFieldsBeforeWriting()) func ClearFieldsBeforeWriting() func(*Exiftool) error { return func(e *Exiftool) error { e.clearFieldsBeforeWriting = true @@ -431,7 +446,8 @@ func ClearFieldsBeforeWriting() func(*Exiftool) error { // SetExiftoolBinaryPath sets exiftool's binary path. When not specified, the binary will have to be in $PATH // Sample : -// e, err := NewExiftool(SetExiftoolBinaryPath("/usr/bin/exiftool")) +// +// e, err := NewExiftool(SetExiftoolBinaryPath("/usr/bin/exiftool")) func SetExiftoolBinaryPath(p string) func(*Exiftool) error { return func(e *Exiftool) error { if _, err := os.Stat(p); err != nil { @@ -441,3 +457,19 @@ func SetExiftoolBinaryPath(p string) func(*Exiftool) error { return nil } } + +// SystemProcessAttributes sets system process attributes that will be used when starting Exiftool +// Sample : +// +// const CreateNoWindow = 0x08000000 +// var sysProcAttr = syscall.SysProcAttr{ +// HideWindow: true, +// CreationFlags: CreateNoWindow, +// } +// e, err := NewExiftool(SetCommandSystemProcessAttributes(&sysProcAttr)) +func SystemProcessAttributes(sysProcAttr *syscall.SysProcAttr) func(*Exiftool) error { + return func(e *Exiftool) error { + e.sysProcAttr = sysProcAttr + return nil + } +} diff --git a/exiftool_windows_test.go b/exiftool_windows_test.go new file mode 100644 index 0000000..9a76c87 --- /dev/null +++ b/exiftool_windows_test.go @@ -0,0 +1,28 @@ +package exiftool + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "syscall" + "testing" +) + +func TestSystemProcessAttributes(t *testing.T) { + t.Parallel() + + const CreateNoWindow = 0x08000000 + + var sysProcAttr = &syscall.SysProcAttr{ + HideWindow: true, + CreationFlags: CreateNoWindow, + } + + // I don't know what a good solution is to verify the process attributes are set on the actual process + et, err := NewExiftool(SystemProcessAttributes(sysProcAttr)) + require.Nil(t, err, fmt.Sprintf("%v", err)) + defer et.Close() + + assert.Equal(t, sysProcAttr, et.sysProcAttr) + assert.Equal(t, sysProcAttr, et.cmd.SysProcAttr) +}