Skip to content

Commit 51326b5

Browse files
committed
Merge remote-tracking branch 'origin/main' into rename_jabkit_pck
2 parents a140e7b + 59355d2 commit 51326b5

File tree

10 files changed

+161
-19
lines changed

10 files changed

+161
-19
lines changed

.github/workflows/tests-code.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ jobs:
469469
run: |
470470
echo "cache_key=jbang-$(date +%F)" >> $GITHUB_OUTPUT
471471
- name: Use cache
472+
if: steps.changed-jablib-files.outputs.any_changed != 'true'
472473
uses: actions/cache@v4
473474
with:
474475
path: ~/.jbang
@@ -522,6 +523,7 @@ jobs:
522523
with:
523524
files: |
524525
.jbang/*.java
526+
jabkit/src/main/java/**/*.java
525527
jablib/src/main/java/**/*.java
526528
jablib-examples/**/*.java
527529
files_ignore: |
@@ -553,7 +555,16 @@ jobs:
553555
# We modify the JBang scripts directly to avoid issues with relative paths
554556
for f in ${{ steps.changed-jablib-files.outputs.all_changed_files }}; do
555557
case "$f" in
556-
jablib-examples/*) continue ;; # skip scripts
558+
jablib-examples/*)
559+
# skip scripts
560+
continue
561+
;;
562+
jabkit/*)
563+
# only JabKit needs its modified sources
564+
if [ "${{ matrix.script }}" != ".jbang/JabKitLauncher.java" ]; then
565+
continue
566+
fi
567+
;;
557568
esac
558569
echo "//SOURCES ../$f" >> "${{ matrix.script }}"
559570
done

CHANGELOG.md

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

1414
- We added "IEEE" as another option for parsing plain text citations. [#14233](github.com/JabRef/jabref/pull/14233)
1515
- We added automatic date-based groups that create year/month/day subgroups from an entry’s date fields. [#10822](https://github.com/JabRef/jabref/issues/10822)
16+
- We added `doi-to-bibtex` to `JabKit`. [#14244](https://github.com/JabRef/jabref/pull/14244)
1617

1718
### Changed
1819

20+
- `JabKit`: `--porcelain` does not output any logs to the console anymore. [#14244](https://github.com/JabRef/jabref/pull/14244)
1921
- <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>L</kbd> now opens the terminal in the active library directory. [#14130](https://github.com/JabRef/jabref/issues/14130)
2022

2123
### Fixed

jabkit/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ application {
6868

6969
// Also passed to launcher by java-module-packaging plugin
7070
applicationDefaultJvmArgs = listOf(
71+
// JEP 158: Disable all java util logging
72+
"-Xlog:disable",
73+
7174
// Enable JEP 450: Compact Object Headers
7275
"-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders",
7376

jabkit/src/main/java/org/jabref/toolkit/JabKit.java

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.nio.file.Path;
88
import java.util.Arrays;
99
import java.util.List;
10-
import java.util.Map;
1110
import java.util.Set;
1211
import java.util.stream.Collectors;
1312

@@ -58,6 +57,8 @@ public class JabKit {
5857

5958
private static final String JABKIT_BRAND = "JabKit - command line toolkit for JabRef";
6059

60+
/// Note: To test with gradle, use jabkit -> Tasks -> application -> run
61+
/// Use `--args="..."` as parameters to "Run"
6162
public static void main(String[] args) {
6263
initLogging(args);
6364

@@ -143,11 +144,10 @@ public static void initLogging(String[] args) {
143144

144145
// We must configure logging as soon as possible, which is why we cannot wait for the usual
145146
// argument parsing workflow to parse logging options e.g. --debug or --porcelain
147+
boolean isPorcelain = Arrays.stream(args).anyMatch("--porcelain"::equalsIgnoreCase);
146148
Level logLevel;
147149
if (Arrays.stream(args).anyMatch("--debug"::equalsIgnoreCase)) {
148150
logLevel = Level.DEBUG;
149-
} else if (Arrays.stream(args).anyMatch("--porcelain"::equalsIgnoreCase)) {
150-
logLevel = Level.ERROR;
151151
} else {
152152
logLevel = Level.INFO;
153153
}
@@ -163,18 +163,23 @@ public static void initLogging(String[] args) {
163163
return;
164164
}
165165

166+
String fileWriterName;
167+
if (isPorcelain) {
168+
fileWriterName = "writer";
169+
} else {
170+
fileWriterName = "writerFile";
171+
}
172+
166173
// The "Shared File Writer" is explained at
167174
// https://tinylog.org/v2/configuration/#shared-file-writer
168-
Map<String, String> configuration = Map.of(
169-
"level", logLevel.name().toLowerCase(),
170-
"writerFile", "rolling file",
171-
"writerFile.logLevel", logLevel == Level.DEBUG ? "debug" : "info",
172-
// We need to manually join the path, because ".resolve" does not work on Windows, because ":" is not allowed in file names on Windows
173-
"writerFile.file", directory + File.separator + "log_{date:yyyy-MM-dd_HH-mm-ss}.txt",
174-
"writerFile.charset", "UTF-8",
175-
"writerFile.policies", "startup",
176-
"writerFile.backups", "30");
177-
configuration.forEach(Configuration::set);
175+
Configuration.set("level", logLevel.name().toLowerCase());
176+
Configuration.set(fileWriterName, "rolling file");
177+
Configuration.set("%s.logLevel".formatted(fileWriterName), logLevel == Level.DEBUG ? "debug" : "info");
178+
// We need to manually join the path, because ".resolve" does not work on Windows, because ":" is not allowed in file names on Windows
179+
Configuration.set("%s.file".formatted(fileWriterName), directory + File.separator + "log_{date:yyyy-MM-dd_HH-mm-ss}.txt");
180+
Configuration.set("%s.charset".formatted(fileWriterName), "UTF-8");
181+
Configuration.set("%s.policies".formatted(fileWriterName), "startup");
182+
Configuration.set("%s.backups".formatted(fileWriterName), "30");
178183

179184
LOGGER = LoggerFactory.getLogger(JabKit.class);
180185
}

jabkit/src/main/java/org/jabref/toolkit/cli/ArgumentProcessor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
CheckConsistency.class,
4444
CheckIntegrity.class,
4545
Convert.class,
46+
DoiToBibtex.class,
4647
Fetch.class,
4748
GenerateBibFromAux.class,
4849
GenerateCitationKeys.class,
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package org.jabref.toolkit.cli;
2+
3+
import java.io.IOException;
4+
import java.io.OutputStreamWriter;
5+
import java.nio.charset.StandardCharsets;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Optional;
9+
import java.util.concurrent.Callable;
10+
11+
import org.jabref.logic.exporter.BibDatabaseWriter;
12+
import org.jabref.logic.importer.FetcherException;
13+
import org.jabref.logic.importer.fetcher.CrossRef;
14+
import org.jabref.logic.l10n.Localization;
15+
import org.jabref.model.database.BibDatabase;
16+
import org.jabref.model.database.BibDatabaseContext;
17+
import org.jabref.model.entry.BibEntry;
18+
import org.jabref.model.entry.identifier.DOI;
19+
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
import picocli.CommandLine;
23+
import picocli.CommandLine.Command;
24+
import picocli.CommandLine.Parameters;
25+
26+
@Command(name = "doi-to-bibtex", description = "Converts a DOI to BibTeX")
27+
public class DoiToBibtex implements Callable<Integer> {
28+
29+
private static final Logger LOGGER = LoggerFactory.getLogger(DoiToBibtex.class);
30+
31+
@CommandLine.ParentCommand
32+
private ArgumentProcessor argumentProcessor;
33+
34+
@CommandLine.Mixin
35+
private ArgumentProcessor.SharedOptions sharedOptions = new ArgumentProcessor.SharedOptions();
36+
37+
@Parameters(paramLabel = "DOI", description = "one or more DOIs to fetch", arity = "1..*")
38+
private String[] dois;
39+
40+
@Override
41+
public Integer call() {
42+
CrossRef fetcher = new CrossRef();
43+
List<BibEntry> entries = new ArrayList<>(dois.length);
44+
45+
for (String doiString : dois) {
46+
Optional<DOI> doiParsed = DOI.parse(doiString);
47+
if (doiParsed.isEmpty()) {
48+
LOGGER.warn("Skipped DOI {}, because it is not a valid DOI string", doiString);
49+
System.out.println(Localization.lang("DOI %0 is invalid", doiString));
50+
System.err.println();
51+
continue;
52+
}
53+
Optional<BibEntry> entry;
54+
try {
55+
entry = fetcher.performSearchById(doiParsed.get().asString());
56+
} catch (FetcherException e) {
57+
LOGGER.error("Could not fetch BibTeX based on DOI", e);
58+
System.err.print(Localization.lang("No data was found for the identifier"));
59+
System.err.println(" - " + doiString);
60+
System.err.println(e.getLocalizedMessage());
61+
System.err.println();
62+
continue;
63+
}
64+
65+
if (entry.isEmpty()) {
66+
LOGGER.error("Could not fetch BibTeX based on DOI - entry is empty");
67+
System.err.print(Localization.lang("No data was found for the identifier"));
68+
System.err.println(" - " + doiString);
69+
System.err.println();
70+
continue;
71+
}
72+
73+
entries.add(entry.get());
74+
}
75+
76+
try (OutputStreamWriter writer = new OutputStreamWriter(System.out, StandardCharsets.UTF_8)) {
77+
BibDatabaseContext context = new BibDatabaseContext(new BibDatabase(entries));
78+
BibDatabaseWriter bibWriter = new BibDatabaseWriter(writer, context, argumentProcessor.cliPreferences);
79+
bibWriter.writeDatabase(context);
80+
} catch (IOException e) {
81+
LOGGER.error("Could not write BibTeX", e);
82+
System.err.println(Localization.lang("Unable to write to %0.", "stdout"));
83+
return 1;
84+
}
85+
return 0;
86+
}
87+
}

jablib-examples/doi_to_bibtex.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
3+
import org.jabref.logic.exporter.BibWriter;
4+
import org.jabref.logic.exporter.BibDatabaseWriter;
5+
import org.jabref.logic.importer.fetcher.CrossRef;
6+
import org.jabref.logic.preferences.JabRefCliPreferences;
7+
import org.jabref.model.database.BibDatabase;
8+
import org.jabref.model.database.BibDatabaseContext;
9+
10+
import org.tinylog.Logger;
11+
12+
//DESCRIPTION Converts a DOI to BibTeX
13+
14+
//JAVA 25+
15+
//RUNTIME_OPTIONS --enable-native-access=ALL-UNNAMED
16+
//FILES tinylog.properties=tinylog.properties
17+
18+
//DEPS org.jabref:jablib:6.0-SNAPSHOT
19+
//REPOS mavencentral,mavencentralsnapshots=https://central.sonatype.com/repository/maven-snapshots/,s01oss=https://s01.oss.sonatype.org/content/repositories/snapshots/,oss=https://oss.sonatype.org/content/repositories,jitpack=https://jitpack.io,oss2=https://oss.sonatype.org/content/groups/public,ossrh=https://oss.sonatype.org/content/repositories/snapshots,raw=https://raw.githubusercontent.com/JabRef/jabref/refs/heads/main/jablib/lib/
20+
21+
void main() throws Exception {
22+
var preferences = JabRefCliPreferences.getInstance();
23+
24+
// All `IdParserFetcher<DOI>` can do. In JabRef, there is currently only one implemented
25+
26+
var fetcher = new CrossRef();
27+
var entry = fetcher.performSearchById("10.47397/tb/44-3/tb138kopp-jabref").get(); // will throw an exception if not found
28+
29+
try (var writer = new OutputStreamWriter(System.out, StandardCharsets.UTF_8)) {
30+
var context = new BibDatabaseContext(new BibDatabase(List.of(entry)));
31+
var bibWriter = new BibDatabaseWriter(writer, context, preferences);
32+
bibWriter.writeDatabase(context);
33+
}
34+
}

jablib/src/main/java/org/jabref/logic/exporter/BibDatabaseWriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import org.jabref.logic.cleanup.FieldFormatterCleanups;
3333
import org.jabref.logic.cleanup.NormalizeWhitespacesCleanup;
3434
import org.jabref.logic.formatter.bibtexfields.TrimWhitespaceFormatter;
35-
import org.jabref.logic.preferences.JabRefCliPreferences;
35+
import org.jabref.logic.preferences.CliPreferences;
3636
import org.jabref.logic.util.strings.StringUtil;
3737
import org.jabref.model.FieldChange;
3838
import org.jabref.model.database.BibDatabase;
@@ -95,7 +95,7 @@ public BibDatabaseWriter(@NonNull BibWriter bibWriter,
9595
/// @param preferences - used to read all the preferences
9696
public BibDatabaseWriter(@NonNull Writer writer,
9797
@NonNull BibDatabaseContext bibDatabaseContext,
98-
@NonNull JabRefCliPreferences preferences) {
98+
@NonNull CliPreferences preferences) {
9999
this(new BibWriter(writer, bibDatabaseContext.getDatabase().getNewLineSeparator()),
100100
preferences.getSelfContainedExportConfiguration(),
101101
preferences.getFieldPreferences(),

jablib/src/main/java/org/jabref/logic/importer/plaincitation/PlainCitationParser.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.util.List;
44
import java.util.Optional;
5-
import java.util.stream.Collectors;
65

76
import org.jabref.logic.importer.FetcherException;
87
import org.jabref.model.entry.BibEntry;
@@ -19,7 +18,7 @@ default List<BibEntry> parseMultiplePlainCitations(String text) throws FetcherEx
1918
return CitationSplitter.splitCitations(text)
2019
.map(Unchecked.function(this::parsePlainCitation))
2120
.flatMap(Optional::stream)
22-
.collect(Collectors.toList());
21+
.toList();
2322
} catch (UncheckedException e) {
2423
throw (FetcherException) e.getCause();
2524
}

jablib/src/main/resources/l10n/JabRef_en.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,7 @@ No\ problems\ found.=No problems found.
14501450
Print\ entry\ preview=Print entry preview
14511451

14521452
Invalid\ DOI\:\ '%0'.=Invalid DOI: '%0'.
1453+
DOI\ %0\ is\ invalid=DOI %0 is invalid
14531454
Same\ DOI\ used\ in\ multiple\ entries=Same DOI used in multiple entries
14541455
should\ start\ with\ a\ name=should start with a name
14551456
should\ end\ with\ a\ name=should end with a name
@@ -1974,7 +1975,6 @@ Update\ with\ bibliographic\ information\ from\ the\ web=Update with bibliograph
19741975
19751976
Could\ not\ find\ any\ bibliographic\ information.=Could not find any bibliographic information.
19761977
Citation\ key\ deviates\ from\ generated\ key=Citation key deviates from generated key
1977-
DOI\ %0\ is\ invalid=DOI %0 is invalid
19781978
19791979
Select\ all\ customized\ types\ to\ be\ stored\ in\ local\ preferences\:=Select all customized types to be stored in local preferences\:
19801980
Different\ customization,\ current\ settings\ will\ be\ overwritten=Different customization, current settings will be overwritten

0 commit comments

Comments
 (0)