Skip to content

Commit 72d5cc2

Browse files
authored
Migrate CLI handling from Apache Commons CLI to PicoCLI (#13012)
* wip * shorten annotations and fix parsing bug * Some visual tweaks * Adapt commands * Remove code duplication and moved some code to JabRefGUI * Use common clearOldSearchIndices method * Reorder * Prototype KitCommandline in PicoCli * wip * Migrate aux * Migrate search and preferences * Convert * Reorder * Fetch * Use distinctive vars for files and citekeys and show export formats again * Remove double annotations * Cleanups * Make checkstyle happy again * Fix compile errors * Fix checkstyle * Fix GenerateBibFromAux test * Add mixins for global options * Fix tests, refactor * Fix search * Make methods static for easier testing * Cleanup * Fix banner * Adapt gui banner * Fixes to mixins * CHANGELOG.md * Added check on bib file to consistency CheckConsistency * Fit convert for porcelain mode * JabKit with capital K * Some orthographic fixes * Implement ProviderConverter * Fix fetcher usage message, undo custom converter * More porcelain * Porcelain * Remove doc comment * Move JABREF_BANNER to jablib * Change signature * Reintroduce uri parsing for inputFile * Rewrite * Branding for JabKit * CHANGELOG.md * DevDocs * Remove wrong comment * Remove deprecated comment * l10n * Remove obsolete comment * Modify JABREF_BANNER * Reword parserResult, replace System.err with LOGGER * CHANGELOG.md * Fix StringUtilTest * Remove obsolete javafx/annotations.xml * Fix javafx workflow * l10n * Remove %n --------- Co-authored-by: Carl Christian Snethlage <[email protected]>
1 parent 0eab01f commit 72d5cc2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1621
-2396
lines changed

.github/workflows/deployment-ea.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ jobs:
147147
run: |
148148
set -e
149149
set -x
150+
mkdir javafx
150151
cd javafx
151152
curl --no-progress-meter https://jdk.java.net/javafx${{ env.javafx }}/ > javafx.html
152153

.gitignore

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@ jablib/src/main/resources/csl-locales
1414

1515
.kotlin
1616

17-
javafx/javafx-sdk-*
18-
javafx/javafx-jmods-*
19-
javafx/javafx.html
20-
javafx/*.tar.gz
21-
javafx/*.zip
17+
javafx/
2218

2319
# generated by https://plugins.jetbrains.com/plugin/15991-plantuml-diagram-generator
2420
*.puml

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
1111

1212
### Added
1313

14+
- We introduced a new command line application called `jabkit`. [#13012](https://github.com/JabRef/jabref/pull/13012) [#110](https://github.com/JabRef/jabref/issues/110)
1415
- We added a new "Add JabRef suggested groups" option in the context menu of "All entries". [#12659](https://github.com/JabRef/jabref/issues/12659)
1516
- We added an option to create entries directly from Bib(La)TeX sources to the 'Create New Entry' tool. [#8808](https://github.com/JabRef/jabref/issues/8808)
1617
- We added the provision to choose different CSL bibliography body formats (e.g. First Line Indent, Hanging Indent, Bibliography 1, etc.) in the LibreOffice integration. [#13049](https://github.com/JabRef/jabref/issues/13049)
1718
- We added "Bibliography Heading" to the available CSL bibliography header formats in the LibreOffice integration. [#13049](https://github.com/JabRef/jabref/issues/13049)
1819

1920
### Changed
2021

22+
- We moved some functionality from the graphical application `jabref` with new command verbs `generate-citation-keys`, `check-consistency`, `fetch`, `search`, `convert`, `generate-bib-from-aux`, `preferences` and `pdf` to the new toolkit. [#13012](https://github.com/JabRef/jabref/pull/13012) [#110](https://github.com/JabRef/jabref/issues/110)
2123
- We merged the 'New Entry', 'Import by ID', and 'New Entry from Plain Text' tools into a single 'Create New Entry' tool. [#8808](https://github.com/JabRef/jabref/issues/8808)
2224
- We renamed the "Body Text" CSL bibliography header format name to "Text body" as per internal LibreOffice conventions. [#13074](https://github.com/JabRef/jabref/pull/13074)
2325
- We moved the "Modify bibliography title" option from the CSL styles tab of the Select Style dialog to the OpenOffice/LibreOffice side panel and renamed it to "Bibliography properties". [#13074](https://github.com/JabRef/jabref/pull/13074)
@@ -35,6 +37,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
3537

3638
### Removed
3739

40+
- We removed the ability to change internal preference values. [#13012](https://github.com/JabRef/jabref/pull/13012)
3841
- We removed support for MySQL/MariaDB and Oracle. [#12990](https://github.com/JabRef/jabref/pull/12990)
3942
- We removed library migrations (users need to use JabRef 6.0-alpha.1 to perform migrations) [#12990](https://github.com/JabRef/jabref/pull/12990)
4043

docs/code-howtos/cli.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@ parent: Code Howtos
33
---
44
# Command Line Interface
55

6-
The package `org.jabref.cli` is responsible for handling the command line options.
6+
The module `jabkit` is mainly responsible for handling the command line options. The module `jabgui` also provides some rudimentary functionality, mainly responsible for command line interaction with the gui.
7+
8+
In both modules, the package `org.jabref.cli` uses the PicoCli library to process arguments.
79

810
During development, one can configure IntelliJ to pass command line parameters:
911

1012
![IntelliJ-run-configuration](../images/intellij-run-configuration-command-line.png)
1113

12-
Passing command line arguments using gradle is currently not possible as all arguments (such as `-Dfile.encoding=windows-1252`) are passed to the application.
14+
Passing command line arguments using gradle is possible by adding the arguments to the run command with the `--args` option.
15+
16+
![IntelliJ-run-configuration](../images/gradle-run-config-with-args.png)
1317

1418
Without [jlink](https://docs.oracle.com/en/java/javase/11/tools/jlink.html), it is not possible to generate a fat jar anymore. During development, the capabilities of the IDE has to be used.
59 KB
Loading

jabgui/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import org.gradle.internal.os.OperatingSystem
2+
import org.gradle.kotlin.dsl.annotationProcessor
23
import org.javamodularity.moduleplugin.extensions.CompileModuleOptions
34
import org.javamodularity.moduleplugin.extensions.RunModuleOptions
45

@@ -109,7 +110,8 @@ dependencies {
109110

110111
implementation("com.github.javakeyring:java-keyring:1.0.4")
111112

112-
implementation("commons-cli:commons-cli:1.9.0")
113+
implementation("info.picocli:picocli:4.7.7")
114+
annotationProcessor("info.picocli:picocli-codegen:4.7.7")
113115

114116
implementation("de.undercouch:citeproc-java:3.3.0") {
115117
exclude(group = "org.antlr")

jabgui/src/main/java/module-info.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
requires com.google.common;
106106
requires io.github.javadiffutils;
107107
// requires java.string.similarity;
108-
requires org.apache.commons.cli;
108+
requires info.picocli;
109109
// requires org.apache.commons.compress;
110110
// requires org.apache.commons.csv;
111111
requires org.apache.commons.io;

jabgui/src/main/java/org/jabref/Launcher.java

Lines changed: 24 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,32 @@
33
import java.io.File;
44
import java.io.IOException;
55
import java.net.Authenticator;
6-
import java.nio.file.DirectoryStream;
76
import java.nio.file.Files;
87
import java.nio.file.Path;
9-
import java.util.ArrayList;
10-
import java.util.Comparator;
8+
import java.util.Arrays;
119
import java.util.List;
1210
import java.util.Map;
1311

1412
import org.jabref.cli.ArgumentProcessor;
15-
import org.jabref.cli.CliOptions;
1613
import org.jabref.gui.JabRefGUI;
1714
import org.jabref.gui.preferences.GuiPreferences;
1815
import org.jabref.gui.preferences.JabRefGuiPreferences;
19-
import org.jabref.gui.util.DefaultFileUpdateMonitor;
2016
import org.jabref.logic.UiCommand;
2117
import org.jabref.logic.citationstyle.CSLStyleLoader;
22-
import org.jabref.logic.journals.JournalAbbreviationLoader;
23-
import org.jabref.logic.journals.JournalAbbreviationRepository;
2418
import org.jabref.logic.net.ProxyAuthenticator;
2519
import org.jabref.logic.net.ProxyPreferences;
2620
import org.jabref.logic.net.ProxyRegisterer;
2721
import org.jabref.logic.net.ssl.SSLPreferences;
2822
import org.jabref.logic.net.ssl.TrustStoreManager;
2923
import org.jabref.logic.preferences.CliPreferences;
30-
import org.jabref.logic.protectedterms.ProtectedTermsLoader;
3124
import org.jabref.logic.remote.RemotePreferences;
3225
import org.jabref.logic.remote.client.RemoteClient;
3326
import org.jabref.logic.search.PostgreServer;
3427
import org.jabref.logic.util.BuildInfo;
3528
import org.jabref.logic.util.Directories;
36-
import org.jabref.logic.util.HeadlessExecutorService;
3729
import org.jabref.migrations.PreferencesMigrations;
38-
import org.jabref.model.entry.BibEntryTypesManager;
39-
import org.jabref.model.util.FileUpdateMonitor;
4030

4131
import com.airhacks.afterburner.injection.Injector;
42-
import org.apache.commons.cli.ParseException;
4332
import org.slf4j.Logger;
4433
import org.slf4j.LoggerFactory;
4534
import org.slf4j.bridge.SLF4JBridgeHandler;
@@ -50,23 +39,36 @@
5039
/// It has two main functions:
5140
///
5241
/// - Handle the command line arguments
53-
/// - Start the JavaFX application (if not in CLI mode)
42+
/// - Start the JavaFX application
5443
public class Launcher {
5544
private static Logger LOGGER;
5645

5746
public static void main(String[] args) {
5847
initLogging(args);
5948

60-
// Initialize preferences
49+
Injector.setModelOrService(BuildInfo.class, new BuildInfo());
50+
6151
final JabRefGuiPreferences preferences = JabRefGuiPreferences.getInstance();
6252
Injector.setModelOrService(CliPreferences.class, preferences);
6353
Injector.setModelOrService(GuiPreferences.class, preferences);
6454

65-
DefaultFileUpdateMonitor fileUpdateMonitor = new DefaultFileUpdateMonitor();
66-
HeadlessExecutorService.INSTANCE.executeInterruptableTask(fileUpdateMonitor, "FileUpdateMonitor");
55+
// Early exit in case another instance is already running
56+
if (!handleMultipleAppInstances(args, preferences.getRemotePreferences())) {
57+
systemExit();
58+
}
6759

68-
List<UiCommand> uiCommands = processArguments(args, preferences, fileUpdateMonitor);
69-
// The method `processArguments` quits the whole JVM if no GUI is needed.
60+
configureProxy(preferences.getProxyPreferences());
61+
configureSSL(preferences.getSSLPreferences());
62+
63+
ArgumentProcessor argumentProcessor = new ArgumentProcessor(
64+
args,
65+
ArgumentProcessor.Mode.INITIAL_START,
66+
preferences);
67+
68+
List<UiCommand> uiCommands = argumentProcessor.processArguments();
69+
if (argumentProcessor.shouldShutDown()) {
70+
systemExit();
71+
}
7072

7173
PreferencesMigrations.runMigrations(preferences);
7274

@@ -75,7 +77,7 @@ public static void main(String[] args) {
7577

7678
CSLStyleLoader.loadInternalStyles();
7779

78-
JabRefGUI.setup(uiCommands, preferences, fileUpdateMonitor);
80+
JabRefGUI.setup(uiCommands, preferences);
7981
JabRefGUI.launch(JabRefGUI.class, args);
8082
}
8183

@@ -89,14 +91,8 @@ public static void initLogging(String[] args) {
8991
SLF4JBridgeHandler.install();
9092

9193
// We must configure logging as soon as possible, which is why we cannot wait for the usual
92-
// argument parsing workflow to parse logging options .e.g. --debug
93-
boolean isDebugEnabled;
94-
try {
95-
CliOptions cliOptions = new CliOptions(args);
96-
isDebugEnabled = cliOptions.isDebugLogging();
97-
} catch (ParseException e) {
98-
isDebugEnabled = false;
99-
}
94+
// argument parsing workflow to parse logging options e.g. --debug
95+
boolean isDebugEnabled = Arrays.stream(args).anyMatch(arg -> "--debug".equalsIgnoreCase(arg));
10096

10197
// addLogToDisk
10298
// We cannot use `Injector.instantiateModelOrService(BuildInfo.class).version` here, because this initializes logging
@@ -132,60 +128,10 @@ private static void systemExit() {
132128
System.exit(0);
133129
}
134130

135-
public static List<UiCommand> processArguments(String[] args, JabRefGuiPreferences preferences, FileUpdateMonitor fileUpdateMonitor) {
136-
try {
137-
Injector.setModelOrService(BuildInfo.class, new BuildInfo());
138-
139-
// Early exit in case another instance is already running
140-
if (!handleMultipleAppInstances(args, preferences.getRemotePreferences())) {
141-
systemExit();
142-
}
143-
144-
BibEntryTypesManager entryTypesManager = preferences.getCustomEntryTypesRepository();
145-
Injector.setModelOrService(BibEntryTypesManager.class, entryTypesManager);
146-
147-
Injector.setModelOrService(JournalAbbreviationRepository.class, JournalAbbreviationLoader.loadRepository(preferences.getJournalAbbreviationPreferences()));
148-
Injector.setModelOrService(ProtectedTermsLoader.class, new ProtectedTermsLoader(preferences.getProtectedTermsPreferences()));
149-
150-
configureProxy(preferences.getProxyPreferences());
151-
configureSSL(preferences.getSSLPreferences());
152-
153-
clearOldSearchIndices();
154-
155-
try {
156-
Injector.setModelOrService(FileUpdateMonitor.class, fileUpdateMonitor);
157-
158-
// Process arguments
159-
ArgumentProcessor argumentProcessor = new ArgumentProcessor(
160-
args,
161-
ArgumentProcessor.Mode.INITIAL_START,
162-
preferences,
163-
fileUpdateMonitor);
164-
argumentProcessor.processArguments();
165-
if (argumentProcessor.shouldShutDown()) {
166-
LOGGER.debug("JabRef shut down after processing command line arguments");
167-
systemExit();
168-
return null;
169-
}
170-
171-
return new ArrayList<>(argumentProcessor.getUiCommands());
172-
} catch (ParseException e) {
173-
LOGGER.error("Problem parsing arguments", e);
174-
CliOptions.printUsage(preferences);
175-
systemExit();
176-
return null;
177-
}
178-
} catch (Exception ex) {
179-
LOGGER.error("Unexpected exception", ex);
180-
systemExit();
181-
return null;
182-
}
183-
}
184-
185131
/**
186132
* @return true if JabRef should continue starting up, false if it should quit.
187133
*/
188-
private static boolean handleMultipleAppInstances(String[] args, RemotePreferences remotePreferences) throws InterruptedException {
134+
private static boolean handleMultipleAppInstances(String[] args, RemotePreferences remotePreferences) {
189135
LOGGER.trace("Checking for remote handling...");
190136
if (remotePreferences.useRemoteServer()) {
191137
// Try to contact already running JabRef
@@ -225,30 +171,4 @@ private static void configureProxy(ProxyPreferences proxyPreferences) {
225171
private static void configureSSL(SSLPreferences sslPreferences) {
226172
TrustStoreManager.createTruststoreFileIfNotExist(Path.of(sslPreferences.getTruststorePath()));
227173
}
228-
229-
private static void clearOldSearchIndices() {
230-
Path currentIndexPath = Directories.getFulltextIndexBaseDirectory();
231-
Path appData = currentIndexPath.getParent();
232-
233-
try {
234-
Files.createDirectories(currentIndexPath);
235-
} catch (IOException e) {
236-
LOGGER.error("Could not create index directory {}", appData, e);
237-
}
238-
239-
try (DirectoryStream<Path> stream = Files.newDirectoryStream(appData)) {
240-
for (Path path : stream) {
241-
if (Files.isDirectory(path) && !path.toString().endsWith("ssl") && path.toString().contains("lucene")
242-
&& !path.equals(currentIndexPath)) {
243-
LOGGER.info("Deleting out-of-date fulltext search index at {}.", path);
244-
Files.walk(path)
245-
.sorted(Comparator.reverseOrder())
246-
.map(Path::toFile)
247-
.forEach(File::delete);
248-
}
249-
}
250-
} catch (IOException e) {
251-
LOGGER.error("Could not access app-directory at {}", appData, e);
252-
}
253-
}
254174
}

0 commit comments

Comments
 (0)