-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Fix/copy linked files on entry transfer #13535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix/copy linked files on entry transfer #13535
Conversation
jablib/src/test/java/org/jabref/logic/externalfiles/LinkedFileTransferHelperTest.java
Outdated
Show resolved
Hide resolved
jablib/src/test/java/org/jabref/logic/externalfiles/LinkedFileTransferHelperTest.java
Outdated
Show resolved
Hide resolved
jablib/src/test/java/org/jabref/logic/externalfiles/LinkedFileTransferHelperTest.java
Outdated
Show resolved
Hide resolved
jablib/src/test/java/org/jabref/logic/externalfiles/LinkedFileTransferHelperTest.java
Outdated
Show resolved
Hide resolved
FilePreferences filePreferences | ||
) { | ||
|
||
Set<BibEntry> modifiedEntries = new HashSet<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using constructor for HashSet instead of modern Java collection factory method Set.of(). Modern Java practices recommend using factory methods for cleaner and more maintainable code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could not find a quick solution. would have to refactor the logic then.
|
||
for (BibEntry entry : targetContext.getEntries()) { | ||
boolean entryChanged = false; | ||
List<LinkedFile> linkedFiles = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using ArrayList constructor instead of modern Java collection factory methods. Should use List.of() for empty list initialization following JabRef's conventions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could not find a quick solution. would have to refactor the logic then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TracBot is wrong here 😅
@UmutAkbayin Please read the bot comment - one week old Fix the tests ![]() |
I converted the PR to draft, because a) merge conflicts b) tests failing. |
"Steps to test" seems to be AI generated. It is not a step-by-step guide. Please refine. |
I noticed that one unit test is affected by the changes in LibraryTab#pasteEntry. I’ll look into it tomorrow or over the weekend. I’ll also review the other things like code style. |
3f155a7
to
3ee3b08
Compare
Allows tracking the source BibDatabaseContext for later use in pasteEntry()
…er and setter Enables tracking the source database context for use in pasteEntry()
… CopyTo#copyEntriesWithFeedback and LibraryTab#pasteEntry
Add filePreferences parameter to CopyTo.java to enable LinkedFile#findIn functionality
… primary directory
…sferHelperTest#isReachableFromPrimaryDirectory method
Cloning the BibEntry in importEntryWithDuplicateCheck to ensure that any file path adjustments during the copy/paste process do not affect the original entry in the source database. This avoids side effects when imported entries are modified (e.g. file links), especially when the same BibEntry instance is shared between databases.
…ls in LibraryTab and CopyTo to align with new method signature
…pying logic during entry transfer
There seem to be no issues anymore. |
|
||
@Test | ||
void pathDiffers_ShouldAdjustPath() { | ||
var returnedEntries = LinkedFileTransferHelper.adjustLinkedFilesForTarget(sourceContext, targetContext, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put datatype here. No var
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
assertEquals("target/sourcefiles/test.pdf", | ||
targetContext.getEntries().getFirst().getFiles().getFirst().getLink()); | ||
Path expectedFile = targetDir.resolve("test.pdf"); | ||
assertFalse(Files.exists(expectedFile)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why retunedEntries
cannot be assertEquals({sometingExpected}, returnedEntries
);
@@ -0,0 +1,21 @@ | |||
# File Transfer Between Bib Entries | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, add that in the following "reachable" denotes: reachable using a relative path not climbing up the directory structure?
Also that it respects all configured directories for files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here’s my update to the description regarding file reachability:
“Reachable” means the linked file can be accessed via a relative path that does not climb up the directory structure (no .. segments beyond the root).
Also, this respects all configured directories for files as per JabRef’s settings (link).
According to this understanding, the implementation is aligned with these cases.
Does this match your understanding?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should move the "reachable" paragraph before the list of requirements. Reason: One often jumps directly to a requirement - and does NOT read the other requirements --> but the definition is put in another requiement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
private final FilePreferences filePreferences = mock(FilePreferences.class); | ||
|
||
@Nested | ||
class WhenFileIsReachable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would expect that all three (four?) directory cases of https://docs.jabref.org/finding-sorting-and-cleaning-entries/filelinks#directories-for-files are checked.
I see only shouldStoreFilesRelativeToBibFile
being checked. Please add other test cases
- Global latex directory
- BibFile-specific directory
- User-specific directory
If in one of these, the file is found, it is linked relative. If in mulitple, precedence is as follows:
--> user-specific directory > BibFile-specific directory > Global latex directory / relative to the bib file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I’ve pushed the updated changes, including consolidated assertions and the clarified definition of “reachable”.
Regarding the extended test cases for the different directory types:
I’d like to take a bit more time to read through the relevant code paths and documentation carefully to fully understand the requirements and write robust, meaningful tests.
I’ll plan to follow up on this in the coming days.
Thanks again for the detailed feedback!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be test cases for all four kinds of directories
- Global latex directory OR stored-relative to bib file (2 cases)
- BibFile-specific directory
- User-specific directory
Documentation at https://docs.jabref.org/finding-sorting-and-cleaning-entries/filelinks#directories-for-files and https://docs.jabref.org/setup/databaseproperties#override-default-file-directories
…ries and consolidate assertions - Replace multiple individual assertions with single assertEquals calls comparing expected and actual Sets of BibEntry - Improves test clarity and maintainability by bundling assertions into one comprehensive check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some intermediate feedback. Looking forward to the full solution.
@@ -0,0 +1,21 @@ | |||
# File Transfer Between Bib Entries | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should move the "reachable" paragraph before the list of requirements. Reason: One often jumps directly to a requirement - and does NOT read the other requirements --> but the definition is put in another requiement.
@@ -166,6 +177,10 @@ public void setContent(List<BibEntry> entries, BibEntryTypesManager entryTypesMa | |||
setContent(builder.toString()); | |||
} | |||
|
|||
public void setSourceBibDatabaseContext(@NonNull BibDatabaseContext context) { | |||
sourceDatabaseContext = Objects.requireNonNull(context, "context must not be null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No .requireNonNull
. Just copy. @NonNull
annotation is enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
importHandler.importEntriesWithDuplicateCheck(bibDatabaseContext, finalEntriesToAdd, tracker); | ||
|
||
if (clipBoardManager.getSourceBibDatabaseContext().isPresent()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use ifPresent
and directly use the available context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -117,6 +124,10 @@ public static String getContentsPrimary() { | |||
return getContents(); | |||
} | |||
|
|||
public Optional<BibDatabaseContext> getSourceBibDatabaseContext() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep setters and getters together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
ClipBoardManager clipBoardManager, | ||
JournalAbbreviationRepository abbreviationRepository, | ||
TaskExecutor taskExecutor) { | ||
Menu copySpecialMenu = factory.createMenu(StandardActions.COPY_MORE); | ||
|
||
clipBoardManager.setSourceBibDatabaseContext(libraryTab.getBibDatabaseContext()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is toatally wrong.
Every thought of switchting tabs? Ever thought about the order of calls? Ever thoght about that there are key bindings such as Ctrl+C?
--> move this to org.jabref.gui.edit.EditAction#execute
at the correct place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I hope the new approach is okay. At least the automatic and manual tests aren't breaking.
requires org.jetbrains.annotations; | ||
// endregion | ||
requires org.jetbrains.annotations; | ||
// endregion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the indent changed? Is this some Cursor generated code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using Intellij Idea. I have made use of auto-import of the IDE. Don't know why this file was touched.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed indentation and removal issues in module-info.java. Not ideal for commit history, but a straightforward fix. If you prefer a different approach, please let me know.
requires java.base; | ||
|
||
requires javafx.base; | ||
requires javafx.base; | ||
requires javafx.graphics; // because of javafx.scene.paint.Color | ||
requires afterburner.fx; | ||
requires com.tobiasdiez.easybind; | ||
|
||
// for java.awt.geom.Rectangle2D required by org.jabref.logic.pdf.TextExtractor | ||
requires java.desktop; | ||
|
||
// SQL | ||
// SQL | ||
requires java.sql; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?? I dont know why this happened. the file was not touched by me. it is also not in my commit history
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe during rebase or something? idk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed indentation and removal issues in module-info.java. Not ideal for commit history, but a straightforward fix. If you prefer a different approach, please let me know.
} | ||
} | ||
|
||
@Nested |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use // region
... // endregion
to group tests. We don't use @Nested
on JabRef.
Moreover, please do not use _
in method names; we just have camel case in JabRef
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll refactor all the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
- pulled up the reachable definition before the list of requirements
…ction#execute - Removed clipBoardManager.setSourceBibDatabaseContext(...) from RightClickMenu - Set the clipboard context dynamically in EditAction before copy and cut actions - Improves separation of concerns and ensures correct clipboard context regardless of input method (menu, keyboard shortcut, toolbar)
- Uses proper camelCase instead of underscores - Replaces nested classes with region/endregion comments - Adds comprehensive test coverage for different file preference scenarios
LOGGER.debug("Adjusted path for reachable file: {} -> {}", currentLink, newLink); | ||
return true; | ||
} | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using broad Exception catch block instead of specific exceptions. This can mask important errors and makes it harder to handle different error cases appropriately.
FilePreferences filePreferences | ||
) { | ||
|
||
Set<BibEntry> modifiedEntries = new HashSet<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using constructor for HashSet instead of modern Java collection factory method Set.of(). Modern Java practices recommend using factory methods for cleaner and more maintainable code.
|
||
for (BibEntry entry : targetContext.getEntries()) { | ||
boolean entryChanged = false; | ||
List<LinkedFile> linkedFiles = new ArrayList<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArrayList is instantiated using constructor instead of modern Java collection factory methods. Should consider using List.of() or other factory methods when possible.
…LibraryTab and EditAction
@trag-bot didn't find any issues in the code! ✅✨ |
Closes #12267
Adds a requirements specification file
files.md
documenting the linked file transfer logic between BibTeX entries in JabRef.The document captures three key scenarios for when linked files are reachable or not in the target context and the expected behavior regarding path adjustment and file copying.
This improves traceability by formally specifying requirements that are linked to implementation and tests via OpenFastTrace.
Steps to test
Verify that the new requirements specification file
docs/requirements/files.md
is present, properly formatted, and follows JabRef conventions.Run all existing and new unit tests in
LinkedFileTransferHelperTest
to ensure the linked file transfer logic behaves correctly across all covered scenarios.Manually verify the business logic in JabRef, especially for the scenario where the linked file is not reachable and a nested directory structure must be created. Reviewers should confirm that the path adjustments and file copying behavior conform to the requirements.
Provide feedback if the handling of the last case (unreachable file with differing paths) aligns with project expectations.
Mandatory checks