mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 08:38:32 +02:00
Merge cbf4ed5c35
into 247129c760
This commit is contained in:
commit
44749d6ab4
6 changed files with 51 additions and 16 deletions
|
@ -22,9 +22,7 @@ use any extension. `jrnl` will automatically create the file when you save
|
||||||
your first entry.
|
your first entry.
|
||||||
|
|
||||||
## Folder
|
## Folder
|
||||||
The folder journal format organizes your entries into subfolders for the year
|
The folder journal format organizes your entries into subfolders for the year and month, and a new file for each day. If there are multiple entries in a day, they all appear in the same file. The file extension (`.txt` by default) can be configured with the `extension` configuration key.
|
||||||
and month and `.txt` files for each day. If there are multiple entries in a day,
|
|
||||||
they all appear in the same `.txt` file.
|
|
||||||
|
|
||||||
The directory tree structure is in this format: `YYYY/MM/DD.txt`. For instance, if
|
The directory tree structure is in this format: `YYYY/MM/DD.txt`. For instance, if
|
||||||
you have an entry on May 5th, 2021 in a folder journal at `~/folderjournal`, it will
|
you have an entry on May 5th, 2021 in a folder journal at `~/folderjournal`, it will
|
||||||
|
|
|
@ -57,6 +57,15 @@ for details.
|
||||||
If `true`, encrypts your journal using AES. Do not change this
|
If `true`, encrypts your journal using AES. Do not change this
|
||||||
value for journals that already have data in them.
|
value for journals that already have data in them.
|
||||||
|
|
||||||
|
### extension
|
||||||
|
|
||||||
|
For [folder journals](journal-types.md#folder), control the extension of the day
|
||||||
|
files. By default it is `.txt`.
|
||||||
|
|
||||||
|
!!! warning
|
||||||
|
Changing the extension after a folder journal has been created will prevent
|
||||||
|
`jrnl` from finding past entries.
|
||||||
|
|
||||||
### template
|
### template
|
||||||
The path to a text file to use as a template for new entries. Only works when you
|
The path to a text file to use as a template for new entries. Only works when you
|
||||||
have the `editor` field configured. If you use a template, the editor's
|
have the `editor` field configured. If you use a template, the editor's
|
||||||
|
|
|
@ -17,7 +17,9 @@ if TYPE_CHECKING:
|
||||||
DIGIT_PATTERN = "[0123456789]"
|
DIGIT_PATTERN = "[0123456789]"
|
||||||
YEAR_PATTERN = DIGIT_PATTERN * 4
|
YEAR_PATTERN = DIGIT_PATTERN * 4
|
||||||
MONTH_PATTERN = "[01]" + DIGIT_PATTERN
|
MONTH_PATTERN = "[01]" + DIGIT_PATTERN
|
||||||
DAY_PATTERN = "[0123]" + DIGIT_PATTERN + ".txt"
|
DAY_PATTERN = "[0-3][0-9]"
|
||||||
|
|
||||||
|
DEFAULT_EXTENSION = ".txt"
|
||||||
|
|
||||||
|
|
||||||
class Folder(Journal):
|
class Folder(Journal):
|
||||||
|
@ -34,7 +36,8 @@ class Folder(Journal):
|
||||||
self.entries = []
|
self.entries = []
|
||||||
|
|
||||||
if os.path.exists(self.config["journal"]):
|
if os.path.exists(self.config["journal"]):
|
||||||
filenames = Folder._get_files(self.config["journal"])
|
file_extension = self.config.get("extension", DEFAULT_EXTENSION)
|
||||||
|
filenames = Folder._get_files(self, self.config["journal"], file_extension)
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
with codecs.open(filename, "r", "utf-8") as f:
|
with codecs.open(filename, "r", "utf-8") as f:
|
||||||
journal = f.read()
|
journal = f.read()
|
||||||
|
@ -45,6 +48,8 @@ class Folder(Journal):
|
||||||
|
|
||||||
def write(self) -> None:
|
def write(self) -> None:
|
||||||
"""Writes only the entries that have been modified into proper files."""
|
"""Writes only the entries that have been modified into proper files."""
|
||||||
|
file_extension = self.config.get("extension", DEFAULT_EXTENSION)
|
||||||
|
|
||||||
# Create a list of dates of modified entries. Start with diff_entry_dates
|
# Create a list of dates of modified entries. Start with diff_entry_dates
|
||||||
modified_dates = self._diff_entry_dates
|
modified_dates = self._diff_entry_dates
|
||||||
seen_dates = set(self._diff_entry_dates)
|
seen_dates = set(self._diff_entry_dates)
|
||||||
|
@ -63,7 +68,7 @@ class Folder(Journal):
|
||||||
self.config["journal"],
|
self.config["journal"],
|
||||||
d.strftime("%Y"),
|
d.strftime("%Y"),
|
||||||
d.strftime("%m"),
|
d.strftime("%m"),
|
||||||
d.strftime("%d") + ".txt",
|
d.strftime("%d") + file_extension,
|
||||||
)
|
)
|
||||||
dirname = os.path.dirname(filename)
|
dirname = os.path.dirname(filename)
|
||||||
# create directory if it doesn't exist
|
# create directory if it doesn't exist
|
||||||
|
@ -81,7 +86,7 @@ class Folder(Journal):
|
||||||
journal_file.write(journal)
|
journal_file.write(journal)
|
||||||
# look for and delete empty files
|
# look for and delete empty files
|
||||||
filenames = []
|
filenames = []
|
||||||
filenames = Folder._get_files(self.config["journal"])
|
filenames = Folder._get_files(self, self.config["journal"], file_extension)
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if os.stat(filename).st_size <= 0:
|
if os.stat(filename).st_size <= 0:
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
@ -121,12 +126,12 @@ class Folder(Journal):
|
||||||
self.entries = mod_entries
|
self.entries = mod_entries
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_files(journal_path: str) -> list[str]:
|
def _get_files(self, journal_path: str, extension: str) -> list[str]:
|
||||||
"""Searches through sub directories starting with journal_path and find all text
|
"""Searches through sub directories starting with journal_path and find all text
|
||||||
files that look like entries"""
|
files that look like entries"""
|
||||||
for year_folder in Folder._get_year_folders(pathlib.Path(journal_path)):
|
for year_folder in Folder._get_year_folders(pathlib.Path(journal_path)):
|
||||||
for month_folder in Folder._get_month_folders(year_folder):
|
for month_folder in Folder._get_month_folders(year_folder):
|
||||||
yield from Folder._get_day_files(month_folder)
|
yield from Folder._get_day_files(month_folder, extension)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_year_folders(path: pathlib.Path) -> list[pathlib.Path]:
|
def _get_year_folders(path: pathlib.Path) -> list[pathlib.Path]:
|
||||||
|
@ -143,15 +148,16 @@ class Folder(Journal):
|
||||||
return
|
return
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_day_files(path: pathlib.Path) -> list[str]:
|
def _get_day_files(path: pathlib.Path, extension: str) -> list[str]:
|
||||||
for child in path.glob(DAY_PATTERN):
|
for child in path.glob(DAY_PATTERN + extension):
|
||||||
|
day = str(child.name).replace(extension, "")
|
||||||
if (
|
if (
|
||||||
int(child.stem) > 0
|
int(day) > 0
|
||||||
and int(child.stem) <= 31
|
and int(day) <= 31
|
||||||
and time.is_valid_date(
|
and time.is_valid_date(
|
||||||
year=int(path.parent.name),
|
year=int(path.parent.name),
|
||||||
month=int(path.name),
|
month=int(path.name),
|
||||||
day=int(child.stem),
|
day=int(day),
|
||||||
)
|
)
|
||||||
and child.is_file()
|
and child.is_file()
|
||||||
):
|
):
|
||||||
|
|
|
@ -10,13 +10,22 @@ Feature: Journals iteracting with the file system in a way that users can see
|
||||||
And the journal directory should contain
|
And the journal directory should contain
|
||||||
2013/07/23.txt
|
2013/07/23.txt
|
||||||
|
|
||||||
|
@skip_win # https://github.com/jrnl-org/jrnl/issues/1894
|
||||||
|
Scenario: Adding entries to a Folder journal with a custom extension should generate date files
|
||||||
|
Given we use the config "empty_folder_with_extension.yaml"
|
||||||
|
When we run "jrnl 23 July 2013: Testing folder journal."
|
||||||
|
Then we should get no error
|
||||||
|
And the journal directory should contain
|
||||||
|
2013/07/23.md
|
||||||
|
|
||||||
Scenario: Adding multiple entries to a Folder journal should generate multiple date files
|
Scenario: Adding multiple entries to a Folder journal should generate multiple date files
|
||||||
Given we use the config "empty_folder.yaml"
|
Given we use the config "empty_folder.yaml"
|
||||||
When we run "jrnl 23 July 2013: Testing folder journal."
|
When we run "jrnl 23 July 2013: Testing folder journal."
|
||||||
And we run "jrnl 3/7/2014: Second entry of journal."
|
And we run "jrnl 5/3/2014: Second entry of journal."
|
||||||
Then we should get no error
|
Then we should get no error
|
||||||
And the journal directory should contain
|
And the journal directory should contain
|
||||||
2013/07/23.txt
|
2013/07/23.txt
|
||||||
|
2014/05/03.txt
|
||||||
|
|
||||||
Scenario: If the journal and its parent directory don't exist, they should be created
|
Scenario: If the journal and its parent directory don't exist, they should be created
|
||||||
Given we use the config "missing_directory.yaml"
|
Given we use the config "missing_directory.yaml"
|
||||||
|
|
13
tests/data/configs/empty_folder_with_extension.yaml
Normal file
13
tests/data/configs/empty_folder_with_extension.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
default_hour: 9
|
||||||
|
default_minute: 0
|
||||||
|
editor: ''
|
||||||
|
template: false
|
||||||
|
encrypt: false
|
||||||
|
extension: .md
|
||||||
|
highlight: true
|
||||||
|
journals:
|
||||||
|
default: features/journals/empty_folder_with_extension/
|
||||||
|
linewrap: 80
|
||||||
|
tagsymbols: '@'
|
||||||
|
timeformat: '%Y-%m-%d %H:%M'
|
||||||
|
indent_character: "|"
|
|
@ -51,7 +51,7 @@ def test_get_day_files_expected_filtering(inputs_and_outputs):
|
||||||
mock.patch("pathlib.Path.glob", return_value=glob_files),
|
mock.patch("pathlib.Path.glob", return_value=glob_files),
|
||||||
mock.patch.object(pathlib.Path, "is_file", return_value=True),
|
mock.patch.object(pathlib.Path, "is_file", return_value=True),
|
||||||
):
|
):
|
||||||
actual_output = list(Folder._get_day_files(year_month_path))
|
actual_output = list(Folder._get_day_files(year_month_path, ".txt"))
|
||||||
actual_output.sort()
|
actual_output.sort()
|
||||||
|
|
||||||
expected_output.sort()
|
expected_output.sort()
|
||||||
|
|
Loading…
Add table
Reference in a new issue