Skip to content

Commit f3bf7ef

Browse files
committed
Allow specifying a config file
1 parent 9dec913 commit f3bf7ef

13 files changed

Lines changed: 240 additions & 2 deletions

File tree

src/main/java/com/thebuzzmedia/exiftool/ExecutionStrategy.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ public interface ExecutionStrategy extends AutoCloseable {
6060
*/
6161
void execute(CommandExecutor executor, String exifTool, List<String> arguments, OutputHandler handler) throws IOException;
6262

63+
/**
64+
* Set the ExifTool config file path.
65+
* The default is {@code .ExifTool_config}.
66+
* <p>
67+
* Use {@code null} to specify no custom config path,
68+
* and an empty string to disable loading the default config file.
69+
*
70+
* @param configPath Path to the new config path, or {@code null} for no config path.
71+
* @implNote The default implementation does nothing, and only exists for backwards compatibility.
72+
* Implementers should always override it.
73+
* @see <a href="https://exiftool.org/config.html">exiftool.org/config.html</a>
74+
*/
75+
default void setConfigFilePath(String configPath) {
76+
}
77+
6378
/**
6479
* Check if exiftool process is currently running.
6580
* This method is important especially if {@code stay_open} flag has been enabled.

src/main/java/com/thebuzzmedia/exiftool/ExifToolBuilder.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ public class ExifToolBuilder {
153153
*/
154154
private String path;
155155

156+
/**
157+
* ExifTool config file path.
158+
*/
159+
private String configPath;
160+
156161
/**
157162
* ExifTool executor.
158163
*/
@@ -229,6 +234,39 @@ public ExifToolBuilder withPath(File path) {
229234
return this;
230235
}
231236

237+
/**
238+
* Override the default ExifTool config path.
239+
* The default path is {@code .ExifTool_config}.
240+
* <p>
241+
* Set this to an empty string to disable loading the default config file.
242+
*
243+
* @param configPath New config path.
244+
* @return Current builder.
245+
* @see <a href="https://exiftool.org/config.html">exiftool.org/config.html</a>
246+
*/
247+
public ExifToolBuilder withConfig(String configPath) {
248+
log.debug("Set configPath: {}", configPath);
249+
this.configPath = configPath;
250+
return this;
251+
}
252+
253+
/**
254+
* Override the default ExifTool config path.
255+
* The default path is {@code .ExifTool_config}.
256+
* <p>
257+
* Call {@link #withConfig(String)} with an empty string to
258+
* disable loading the default config file.
259+
*
260+
* @param configPath New config path.
261+
* @return Current builder.
262+
* @see <a href="https://exiftool.org/config.html">exiftool.org/config.html</a>
263+
*/
264+
public ExifToolBuilder withConfig(File configPath) {
265+
log.debug("Set configPath: {}", configPath);
266+
this.configPath = configPath.getAbsolutePath();
267+
return this;
268+
}
269+
232270
/**
233271
* Override default exifTool executor.
234272
*
@@ -405,6 +443,7 @@ public ExifTool build() {
405443
String path = firstNonNull(this.path, PATH);
406444
CommandExecutor executor = firstNonNull(this.executor, EXECUTOR);
407445
ExecutionStrategy strategy = firstNonNull(this.strategy, new StrategyFunction(stayOpen, cleanupDelay, scheduler, poolSize));
446+
strategy.setConfigFilePath(configPath);
408447

409448
// Add some debugging information
410449
if (log.isDebugEnabled()) {

src/main/java/com/thebuzzmedia/exiftool/core/strategies/DefaultStrategy.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ public class DefaultStrategy implements ExecutionStrategy {
4949
*/
5050
private static final Logger log = LoggerFactory.getLogger(DefaultStrategy.class);
5151

52+
/**
53+
* Path to the ExifTool config file,
54+
* or {@code null} if no custom config file is specified.
55+
*/
56+
private String configPath;
57+
5258
/**
5359
* Create strategy.
5460
*/
@@ -59,14 +65,23 @@ public DefaultStrategy() {
5965
public void execute(CommandExecutor executor, String exifTool, List<String> arguments, OutputHandler handler) throws IOException {
6066
log.debug("Using ExifTool in non-daemon mode (-stay_open False)...");
6167

62-
Command cmd = CommandBuilder.builder(exifTool, arguments.size() + 2)
68+
CommandBuilder cmdBuilder = CommandBuilder.builder(exifTool, arguments.size() + (configPath == null ? 2 : 4));
69+
if (configPath != null) {
70+
cmdBuilder.addArgument("-config", configPath);
71+
}
72+
Command cmd = cmdBuilder
6373
.addArgument("-sep", Constants.SEPARATOR)
6474
.addAll(arguments)
6575
.build();
6676

6777
executor.execute(cmd, handler);
6878
}
6979

80+
@Override
81+
public void setConfigFilePath(String configPath) {
82+
this.configPath = configPath;
83+
}
84+
7085
@Override
7186
public boolean isSupported(Version version) {
7287
// Always true.

src/main/java/com/thebuzzmedia/exiftool/core/strategies/PoolStrategy.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ public void execute(CommandExecutor executor, String exifTool, List<String> argu
9494
}
9595
}
9696

97+
@Override
98+
public void setConfigFilePath(String configPath) {
99+
for (ExecutionStrategy executionStrategy : pool) {
100+
executionStrategy.setConfigFilePath(configPath);
101+
}
102+
}
103+
97104
@Override
98105
public boolean isRunning() {
99106
return pool.size() < poolSize;

src/main/java/com/thebuzzmedia/exiftool/core/strategies/StayOpenStrategy.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ public class StayOpenStrategy implements ExecutionStrategy {
6060
*/
6161
private CommandProcess process;
6262

63+
/**
64+
* Path to the ExifTool config file,
65+
* or {@code null} if no custom config file is specified.
66+
*/
67+
private String configPath;
68+
6369
/**
6470
* Create strategy.
6571
* Scheduler provided in parameter will be used to clean resources (exiftool process).
@@ -82,7 +88,11 @@ public void execute(CommandExecutor executor, String exifTool, List<String> argu
8288
// ready to receive commands from us.
8389
if (process == null || process.isClosed()) {
8490
log.debug("Start exiftool process");
85-
process = executor.start(CommandBuilder.builder(exifTool, 6)
91+
CommandBuilder cmdBuilder = CommandBuilder.builder(exifTool, (configPath == null ? 6 : 8));
92+
if (configPath != null) {
93+
cmdBuilder.addArgument("-config", configPath);
94+
}
95+
process = executor.start(cmdBuilder
8696
.addArgument("-stay_open", "True")
8797
.addArgument("-sep", Constants.SEPARATOR)
8898
.addArgument("-@")
@@ -106,6 +116,11 @@ public void execute(CommandExecutor executor, String exifTool, List<String> argu
106116
}
107117
}
108118

119+
@Override
120+
public void setConfigFilePath(String configPath) {
121+
this.configPath = configPath;
122+
}
123+
109124
@Override
110125
public synchronized boolean isRunning() {
111126
return process != null && process.isRunning();

src/test/java/com/thebuzzmedia/exiftool/ExifToolBuilderTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class ExifToolBuilderTest {
5757
private ExecutionStrategy strategy;
5858
private Scheduler scheduler;
5959
private String path;
60+
private String configPath;
6061

6162
private ExifToolBuilder builder;
6263

@@ -68,6 +69,7 @@ void setUp() throws Exception {
6869

6970
builder = new ExifToolBuilder();
7071
path = "/foo";
72+
configPath = "/bar";
7173

7274
// Mock ExifTool Version
7375
CommandResult v9_36 = new CommandResultBuilder()
@@ -93,6 +95,21 @@ void it_should_update_path_with_file() {
9395
assertThat(builder).extracting("path").isEqualTo(file.getAbsolutePath());
9496
}
9597

98+
@Test
99+
void it_should_update_config_path() {
100+
ExifToolBuilder res = builder.withConfig(configPath);
101+
assertThat(res).isSameAs(builder);
102+
assertThat(builder).extracting("configPath").isEqualTo(configPath);
103+
}
104+
105+
@Test
106+
void it_should_update_config_path_with_file() {
107+
File file = new FileBuilder("config.config").build();
108+
ExifToolBuilder res = builder.withConfig(file);
109+
assertThat(res).isSameAs(builder);
110+
assertThat(builder).extracting("configPath").isEqualTo(file.getAbsolutePath());
111+
}
112+
96113
@Test
97114
void it_should_update_executor() {
98115
ExifToolBuilder res = builder.withExecutor(executor);
@@ -149,13 +166,15 @@ void it_should_override_strategy() {
149166
void it_should_create_exiftool_with_custom_props() {
150167
ExifTool exifTool = builder
151168
.withPath(path)
169+
.withConfig(configPath)
152170
.withExecutor(executor)
153171
.enableStayOpen()
154172
.build();
155173

156174
assertThat(exifTool).extracting("path").isEqualTo(path);
157175
assertThat(exifTool).extracting("executor").isEqualTo(executor);
158176
assertThat(exifTool).extracting("strategy").isExactlyInstanceOf(StayOpenStrategy.class);
177+
assertThat(exifTool).extracting("strategy").extracting("configPath").isEqualTo(configPath);
159178
}
160179

161180
@Test

src/test/java/com/thebuzzmedia/exiftool/core/strategies/DefaultStrategyTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
@SuppressWarnings("resource")
3636
class DefaultStrategyTest {
37+
private final String configPath = "config.config";
3738

3839
@Test
3940
void it_should_execute_command() throws Exception {
@@ -58,6 +59,45 @@ void it_should_execute_command() throws Exception {
5859
assertThat(cmd.getArguments()).hasSameSizeAs(expectedArguments).isEqualTo(expectedArguments);
5960
}
6061

62+
@Test
63+
void it_should_execute_command_with_config_path() throws Exception {
64+
String exifTool = "exiftool";
65+
List<String> args = asList("-S", "-n", "-XArtist", "-XComment", "-execute");
66+
CommandExecutor executor = mock(CommandExecutor.class);
67+
OutputHandler handler = mock(OutputHandler.class);
68+
69+
DefaultStrategy strategy = new DefaultStrategy();
70+
strategy.setConfigFilePath(configPath);
71+
strategy.execute(executor, exifTool, args, handler);
72+
73+
ArgumentCaptor<Command> cmdCaptor = ArgumentCaptor.forClass(Command.class);
74+
verify(executor).execute(cmdCaptor.capture(), same(handler));
75+
76+
List<String> expectedArguments = new ArrayList<>();
77+
expectedArguments.add(exifTool);
78+
expectedArguments.add("-config");
79+
expectedArguments.add(configPath);
80+
expectedArguments.add("-sep");
81+
expectedArguments.add("|>☃");
82+
expectedArguments.addAll(args);
83+
84+
Command cmd = cmdCaptor.getValue();
85+
assertThat(cmd.getArguments()).hasSameSizeAs(expectedArguments).isEqualTo(expectedArguments);
86+
}
87+
88+
89+
@Test
90+
void it_should_not_have_config_path_if_none_is_set() {
91+
assertThat(new DefaultStrategy()).extracting("configPath").isNull();
92+
}
93+
94+
@Test
95+
void it_should_set_config_path() {
96+
DefaultStrategy strategy = new DefaultStrategy();
97+
strategy.setConfigFilePath(configPath);
98+
assertThat(strategy).extracting("configPath").isEqualTo(configPath);
99+
}
100+
61101
@Test
62102
void it_should_never_be_running() {
63103
DefaultStrategy strategy = new DefaultStrategy();

src/test/java/com/thebuzzmedia/exiftool/core/strategies/PoolStrategyTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class PoolStrategyTest {
5151

5252
private CommandExecutor executor;
5353
private String exifTool;
54+
private String configPath;
5455
private List<String> arguments;
5556
private OutputHandler handler;
5657

@@ -60,6 +61,7 @@ class PoolStrategyTest {
6061
void setUp() {
6162
executor = mock(CommandExecutor.class);
6263
exifTool = "exiftool";
64+
configPath = "config.config";
6365
arguments = singletonList("-ver");
6466
handler = mock(OutputHandler.class);
6567
}
@@ -129,6 +131,31 @@ void it_should_check_that_version_is_supported() {
129131
assertThat(pool.isSupported(version)).isTrue();
130132
}
131133

134+
@Test
135+
void it_should_not_set_config_path_if_none_is_set() {
136+
ExecutionStrategy s1 = mock(ExecutionStrategy.class);
137+
ExecutionStrategy s2 = mock(ExecutionStrategy.class);
138+
Collection<ExecutionStrategy> strategies = asList(s1, s2);
139+
140+
pool = new PoolStrategy(strategies);
141+
142+
verify(s1, never()).setConfigFilePath(configPath);
143+
verify(s2, never()).setConfigFilePath(configPath);
144+
}
145+
146+
@Test
147+
void it_should_set_config_path() {
148+
ExecutionStrategy s1 = mock(ExecutionStrategy.class);
149+
ExecutionStrategy s2 = mock(ExecutionStrategy.class);
150+
Collection<ExecutionStrategy> strategies = asList(s1, s2);
151+
152+
pool = new PoolStrategy(strategies);
153+
pool.setConfigFilePath(configPath);
154+
155+
verify(s1).setConfigFilePath(configPath);
156+
verify(s2).setConfigFilePath(configPath);
157+
}
158+
132159
@Test
133160
void it_should_execute_strategies_in_parallel() throws Exception {
134161
CountDownLatch executionLock = new CountDownLatch(1);

src/test/java/com/thebuzzmedia/exiftool/core/strategies/StayOpenStrategyTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class StayOpenStrategyTest {
5252
private OutputHandler outputHandler;
5353

5454
private String exifTool;
55+
private String configPath;
5556
private List<String> args;
5657
private StayOpenStrategy strategy;
5758

@@ -62,6 +63,7 @@ void setUp() throws Exception {
6263
executor = mock(CommandExecutor.class);
6364
outputHandler = mock(OutputHandler.class);
6465
exifTool = "exiftool";
66+
configPath = "config.config";
6567

6668
// Mock withExecutor
6769
when(executor.start(any(Command.class))).thenReturn(process);
@@ -87,6 +89,14 @@ void it_should_create_stay_open_strategy() {
8789
strategy = new StayOpenStrategy(scheduler);
8890
assertThat(strategy).extracting("scheduler").isSameAs(scheduler);
8991
assertThat(strategy).extracting("process").isNull();
92+
assertThat(strategy).extracting("configPath").isNull();
93+
}
94+
95+
@Test
96+
void it_should_set_config_path() {
97+
StayOpenStrategy strategy = new StayOpenStrategy(scheduler);
98+
strategy.setConfigFilePath(configPath);
99+
assertThat(strategy).extracting("configPath").isEqualTo(configPath);
90100
}
91101

92102
@SuppressWarnings("unchecked")
@@ -111,6 +121,31 @@ void it_should_execute_command() throws Exception {
111121
verifyExecutionArguments(argsCaptor);
112122
}
113123

124+
@Test
125+
void it_should_execute_command_with_config_path() throws Exception {
126+
strategy = new StayOpenStrategy(scheduler);
127+
strategy.setConfigFilePath(configPath);
128+
strategy.execute(executor, exifTool, args, outputHandler);
129+
130+
ArgumentCaptor<Command> cmdCaptor = ArgumentCaptor.forClass(Command.class);
131+
ArgumentCaptor<List<String>> argsCaptor = ArgumentCaptor.forClass(List.class);
132+
InOrder inOrder = inOrder(scheduler, executor, process);
133+
inOrder.verify(executor).start(cmdCaptor.capture());
134+
inOrder.verify(scheduler).stop();
135+
inOrder.verify(scheduler).start(any(Runnable.class));
136+
inOrder.verify(process).write(argsCaptor.capture());
137+
inOrder.verify(process).flush();
138+
inOrder.verify(process).read(any(OutputHandler.class));
139+
140+
assertThat(strategy).extracting("process").isSameAs(process);
141+
142+
Command startCmd = cmdCaptor.getValue();
143+
assertThat(startCmd.getArguments()).hasSize(9).containsExactly(
144+
exifTool, "-config", configPath, "-stay_open", "True", "-sep", "|>☃", "-@", "-"
145+
);
146+
verifyExecutionArguments(argsCaptor);
147+
}
148+
114149
@SuppressWarnings("unchecked")
115150
@Test
116151
void it_should_not_start_process_twice_if_it_is_running() throws Exception {

0 commit comments

Comments
 (0)