Merge branch 'develop' of https://github.com/jrnl-org/jrnl into dayone2

This commit is contained in:
dbxnr 2020-02-11 17:41:03 +00:00
commit d86bbaf861
26 changed files with 439 additions and 200 deletions

View file

@ -1,5 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
BRANCH=$TRAVIS_BRANCH
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
BRANCH='master'
fi
# Check if branch has been updated since this build started
# This tends to happen if multiple things have been merged in at the same time.
if [[ -z $TRAVIS_TAG ]]; then
git fetch origin
if [[ $(git rev-parse "origin/${BRANCH}") != $TRAVIS_COMMIT ]]; then
echo "${BRANCH} has been updated since build started. Aborting changelog."
exit 0
fi
fi
FILENAME='CHANGELOG.md' FILENAME='CHANGELOG.md'
# get the latest git tags # get the latest git tags
@ -40,11 +55,6 @@ docker run -it --rm -v "$(pwd)":/usr/local/src/your-app ferrarimarco/github-chan
# Put back our link (instead of the broken one) # Put back our link (instead of the broken one)
sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME" sed -i 's!https://pypi.org/project/jrnl/HEAD/!https://github.com/jrnl-org/jrnl/!' "$FILENAME"
BRANCH=$TRAVIS_BRANCH
if [[ $TRAVIS_BRANCH == $TRAVIS_TAG ]]; then
BRANCH='master'
fi
git config --global user.email "jrnl.bot@gmail.com" git config --global user.email "jrnl.bot@gmail.com"
git config --global user.name "Jrnl Bot" git config --global user.name "Jrnl Bot"
git checkout $BRANCH git checkout $BRANCH

1
.gitignore vendored
View file

@ -52,4 +52,3 @@ exp/
_extras/ _extras/
*.sublime-* *.sublime-*
site/ site/
jrnl/__version__.py

View file

@ -7,12 +7,13 @@ cache:
git: git:
depth: false depth: false
autocrlf: false
before_install: before_install:
- date - date
install: install:
- pip install poetry~=0.12.17 - pip install poetry
- poetry install - poetry install
- poetry run python --version - poetry run python --version
@ -50,7 +51,6 @@ jobs:
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- python: nightly - python: nightly
- os: windows
include: include:
- name: Lint, via Black - name: Lint, via Black
@ -73,6 +73,7 @@ jobs:
env: env:
- JRNL_PYTHON_VERSION=3.6.8 - JRNL_PYTHON_VERSION=3.6.8
- PATH=/c/Python36:/c/Python36/Scripts:$PATH - PATH=/c/Python36:/c/Python36/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# Python 3.7 Tests # Python 3.7 Tests
- name: Python 3.7 on Linux - name: Python 3.7 on Linux
@ -88,6 +89,7 @@ jobs:
env: env:
- JRNL_PYTHON_VERSION=3.7.5 - JRNL_PYTHON_VERSION=3.7.5
- PATH=/c/Python37:/c/Python37/Scripts:$PATH - PATH=/c/Python37:/c/Python37/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# Python 3.8 Tests # Python 3.8 Tests
- name: Python 3.8 on Linux - name: Python 3.8 on Linux
@ -103,6 +105,7 @@ jobs:
env: env:
- JRNL_PYTHON_VERSION=3.8.0 - JRNL_PYTHON_VERSION=3.8.0
- PATH=/c/Python38:/c/Python38/Scripts:$PATH - PATH=/c/Python38:/c/Python38/Scripts:$PATH
- PYTHONIOENCODING=UTF-8
# ... and beyond! # ... and beyond!
- name: Python nightly on Linux - name: Python nightly on Linux
@ -128,6 +131,8 @@ jobs:
- poetry version "$TRAVIS_TAG" - poetry version "$TRAVIS_TAG"
- echo __version__ = \"$TRAVIS_TAG\" > jrnl/__version__.py - echo __version__ = \"$TRAVIS_TAG\" > jrnl/__version__.py
- poetry build - poetry build
script:
- echo "Deployment starting..."
deploy: deploy:
- provider: script - provider: script
script: poetry publish script: poetry publish

View file

@ -2,10 +2,41 @@
## [Unreleased](https://github.com/jrnl-org/jrnl/) ## [Unreleased](https://github.com/jrnl-org/jrnl/)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1...HEAD) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.2...HEAD)
**Implemented enhancements:** **Implemented enhancements:**
- Update YAML exporter to handle Dayone format [\#773](https://github.com/jrnl-org/jrnl/pull/773) ([MinchinWeb](https://github.com/MinchinWeb))
**Fixed bugs:**
- Listing all entries in DayOne Classic journal throws IndexError [\#786](https://github.com/jrnl-org/jrnl/pull/786) ([MinchinWeb](https://github.com/MinchinWeb))
- Add UTC support for failing DayOne tests [\#785](https://github.com/jrnl-org/jrnl/pull/785) ([MinchinWeb](https://github.com/MinchinWeb))
**Build:**
- Stop multipe changelog generators from crashing into each other [\#845](https://github.com/jrnl-org/jrnl/pull/845) ([wren](https://github.com/wren))
- Don't re-run tests on deployment [\#839](https://github.com/jrnl-org/jrnl/pull/839) ([wren](https://github.com/wren))
- Put back build lines in Poetry config [\#838](https://github.com/jrnl-org/jrnl/pull/838) ([wren](https://github.com/wren))
- Restore emoji test [\#837](https://github.com/jrnl-org/jrnl/pull/837) ([micahellison](https://github.com/micahellison))
- Fix crashing unicode Travis tests on Windows and fail build if Windows tests fail [\#836](https://github.com/jrnl-org/jrnl/pull/836) ([micahellison](https://github.com/micahellison))
- Remove poetry from build system in pyproject config to fix `brew install` [\#830](https://github.com/jrnl-org/jrnl/pull/830) ([wren](https://github.com/wren))
- Fix all skipped tests on Travis Windows builds by preserving newlines [\#823](https://github.com/jrnl-org/jrnl/pull/823) ([micahellison](https://github.com/micahellison))
**Updated documentation:**
- Update site description [\#841](https://github.com/jrnl-org/jrnl/pull/841) ([wren](https://github.com/wren))
- Get rid of dumb sex joke [\#840](https://github.com/jrnl-org/jrnl/pull/840) ([wren](https://github.com/wren))
- Updating/clarifying template explanation [\#829](https://github.com/jrnl-org/jrnl/pull/829) ([heymajor](https://github.com/heymajor))
## [v2.2](https://pypi.org/project/jrnl/v2.2/) (2020-02-01)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1...v2.2)
**Implemented enhancements:**
- Update YAML exporter to handle Dayone format [\#773](https://github.com/jrnl-org/jrnl/pull/773) ([MinchinWeb](https://github.com/MinchinWeb))
- Full text search \(case insensitive\) with "-contains" [\#740](https://github.com/jrnl-org/jrnl/pull/740) ([empireshades](https://github.com/empireshades)) - Full text search \(case insensitive\) with "-contains" [\#740](https://github.com/jrnl-org/jrnl/pull/740) ([empireshades](https://github.com/empireshades))
- Reduce startup time by 55% [\#719](https://github.com/jrnl-org/jrnl/pull/719) ([maebert](https://github.com/maebert)) - Reduce startup time by 55% [\#719](https://github.com/jrnl-org/jrnl/pull/719) ([maebert](https://github.com/maebert))
- Refactor password logic to prevent accidental password leakage [\#708](https://github.com/jrnl-org/jrnl/pull/708) ([pspeter](https://github.com/pspeter)) - Refactor password logic to prevent accidental password leakage [\#708](https://github.com/jrnl-org/jrnl/pull/708) ([pspeter](https://github.com/pspeter))
@ -18,6 +49,9 @@
**Build:** **Build:**
- Fix issue where jrnl would always out 'source' for version, fix Poetry config to build and publish properly [\#820](https://github.com/jrnl-org/jrnl/pull/820) ([wren](https://github.com/wren))
- Unpin poetry [\#808](https://github.com/jrnl-org/jrnl/pull/808) ([wren](https://github.com/wren))
- Fix all skipped tests on Travis Windows builds by preserving newlines [\#823](https://github.com/jrnl-org/jrnl/pull/823) ([micahellison](https://github.com/micahellison))
- Change PyPI auth method in build pipeline [\#807](https://github.com/jrnl-org/jrnl/pull/807) ([wren](https://github.com/wren)) - Change PyPI auth method in build pipeline [\#807](https://github.com/jrnl-org/jrnl/pull/807) ([wren](https://github.com/wren))
- Automagically update the changelog you see before your very eyes! [\#806](https://github.com/jrnl-org/jrnl/pull/806) ([wren](https://github.com/wren)) - Automagically update the changelog you see before your very eyes! [\#806](https://github.com/jrnl-org/jrnl/pull/806) ([wren](https://github.com/wren))
- Update Black version and lock file to fix builds on develop branch [\#784](https://github.com/jrnl-org/jrnl/pull/784) ([wren](https://github.com/wren)) - Update Black version and lock file to fix builds on develop branch [\#784](https://github.com/jrnl-org/jrnl/pull/784) ([wren](https://github.com/wren))
@ -30,13 +64,14 @@
**Updated documentation:** **Updated documentation:**
- Explain how fish can be configured to exclude jrnl commands from history by default [\#809](https://github.com/jrnl-org/jrnl/pull/809) ([aureooms](https://github.com/aureooms))
- Remove merge marker in recipes.md [\#782](https://github.com/jrnl-org/jrnl/pull/782) ([markphelps](https://github.com/markphelps)) - Remove merge marker in recipes.md [\#782](https://github.com/jrnl-org/jrnl/pull/782) ([markphelps](https://github.com/markphelps))
- Fix merge conflict left-over [\#767](https://github.com/jrnl-org/jrnl/pull/767) ([thejspr](https://github.com/thejspr)) - Fix merge conflict left-over [\#767](https://github.com/jrnl-org/jrnl/pull/767) ([thejspr](https://github.com/thejspr))
- Display header in docs on mobile devices [\#763](https://github.com/jrnl-org/jrnl/pull/763) ([maebert](https://github.com/maebert)) - Display header in docs on mobile devices [\#763](https://github.com/jrnl-org/jrnl/pull/763) ([maebert](https://github.com/maebert))
## [v2.1.1](https://pypi.org/project/jrnl/v2.1.1/) (2019-11-26) ## [v2.1.1](https://pypi.org/project/jrnl/v2.1.1/) (2019-11-26)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.1-beta...v2.1.1) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1.post2...v2.1.1)
**Implemented enhancements:** **Implemented enhancements:**
@ -59,7 +94,7 @@
## [v2.1.post2](https://pypi.org/project/jrnl/v2.1.post2/) (2019-11-11) ## [v2.1.post2](https://pypi.org/project/jrnl/v2.1.post2/) (2019-11-11)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.1-beta6...v2.1.post2) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.1...v2.1.post2)
**Fixed bugs:** **Fixed bugs:**
@ -77,7 +112,7 @@
## [v2.0.1](https://pypi.org/project/jrnl/v2.0.1/) (2019-09-26) ## [v2.0.1](https://pypi.org/project/jrnl/v2.0.1/) (2019-09-26)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.1-beta...v2.0.1) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0.0...v2.0.1)
**Implemented enhancements:** **Implemented enhancements:**
@ -95,7 +130,9 @@
## [v2.0.0](https://pypi.org/project/jrnl/v2.0.0/) (2019-08-24) ## [v2.0.0](https://pypi.org/project/jrnl/v2.0.0/) (2019-08-24)
[Full Changelog](https://github.com/jrnl-org/jrnl/compare/v2.0-rc4...v2.0.0) [Full Changelog](https://github.com/jrnl-org/jrnl/compare/1.9.8...v2.0.0)
🚨 **BREAKING CHANGES** 🚨
**Implemented enhancements:** **Implemented enhancements:**
- Change cryptographic backend from PyCrypto to cryptography.io - Change cryptographic backend from PyCrypto to cryptography.io

View file

@ -56,10 +56,14 @@ setopt HIST_IGNORE_SPACE
alias jrnl=" jrnl" alias jrnl=" jrnl"
``` ```
The fish shell does not support automatically preventing logging like If you are using `fish` instead of `bash` or `zsh`, you can get the same behaviour by
this. To prevent `jrnl` commands being logged by fish, you must make adding this to your `fish` configuration:
sure to type a space before every `jrnl` command you enter. To delete
existing `jrnl` commands from fishs history, run ``` sh
abbr jrnl " jrnl"
```
To delete existing `jrnl` commands from `fish`s history, run
`history delete --prefix 'jrnl '`. `history delete --prefix 'jrnl '`.
## Manual decryption ## Manual decryption

View file

@ -70,17 +70,59 @@ jrnlimport () {
### Using templates ### Using templates
Say you always want to use the same template for creating new entries. !!! note
If you have an [external editor](../advanced) set up, you can use this: Templates require an [external editor](../advanced) be configured.
A template is a code snippet that makes it easier to enter use repeated text
each time a new journal entry is started. There are two ways you can utilize
templates in your entries.
#### 1. Command line arguments
If you had a `template.txt` file with the following contents:
```sh ```sh
jrnl < my_template.txt My Personal Journal
jrnl -1 --edit Title:
Body:
``` ```
Another nice solution that allows you to define individual prompts comes The `template.txt` file could be used to create a new entry with these
from [Jacobo de command line arguements:
Vera](https://github.com/maebert/jrnl/issues/194#issuecomment-47402869):
```sh
jrnl < template.txt # Imports template.txt as the most recent entry
jrnl -1 --edit # Opens the most recent entry in the editor
```
#### 2. Include the template file in `jrnl.yaml`
A more efficient way to work with a template file is to declare the file
in your config file by changing the `template` setting from `false` to the
template file's path in double quotes:
```sh
...
template: "/path/to/template.txt"
...
```
Changes can be saved as you continue writing the journal entry and will be
logged as a new entry in the journal you specified in the original argument.
!!! tip
To read your journal entry or to verify the entry saved, you can use this
command: `jrnl -n 1` (Check out [Import and Export](../export/#export-to-files) for more export options).
```sh
jrnl -n 1
```
### Prompts on shell reload
If you'd like to be prompted each time you refresh your shell, you can include
this in your `.bash_profile`:
```sh ```sh
function log_question() function log_question()
@ -93,6 +135,11 @@ log_question 'What did I achieve today?'
log_question 'What did I make progress with?' log_question 'What did I make progress with?'
``` ```
Whenever your shell is reloaded, you will be prompted to answer each of the
questions in the example above. Each answer will be logged as a separate
journal entry at the `default_hour` and `default_minute` listed in your
`jrnl.yaml` [config file](../advanced/#configuration-file).
### Display random entry ### Display random entry
You can use this to select one title at random and then display the whole You can use this to select one title at random and then display the whole
@ -107,10 +154,11 @@ jrnl -on "$(jrnl --short | shuf -n 1 | cut -d' ' -f1,2)"
## External editors ## External editors
To use external editors for writing and editing journal entries, set Configure your preferred external editor by updating the `editor` option
them up in your `jrnl.yaml` (see `advanced usage <advanced>` for in your `jrnl.yaml` file. (See [advanced usage](../advanced) for details).
details). Generally, after writing an entry, you will have to save and
close the file to save the changes to jrnl. !!! note
To save and log any entry edits, save and close the file.
### Sublime Text ### Sublime Text

View file

@ -34,7 +34,7 @@
"operatingSystem": ["macOS", "Windows", "Linux"], "operatingSystem": ["macOS", "Windows", "Linux"],
"thumbnailUrl": "https://jrnl.sh/img/banner_og.png", "thumbnailUrl": "https://jrnl.sh/img/banner_og.png",
"installUrl": "https://jrnl.sh/installation", "installUrl": "https://jrnl.sh/installation",
"softwareVersion": "2.0.0rc2" "softwareVersion": "2.2"
} }
</script> </script>
</head> </head>
@ -42,7 +42,7 @@
<body> <body>
<header> <header>
<aside> <aside>
<a id="twitter" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh&via=maebert"><i class="icon twitter"></i>Tell your friends</a> <a id="twitter" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh"><i class="icon twitter"></i>Tell your friends</a>
</aside> </aside>
<div id="title"> <div id="title">
<img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" /> <img id="logo" src="img/jrnl_white.svg" width="90px" height="98px" title="jrnl" />
@ -58,7 +58,7 @@
<nav> <nav>
<a href="overview">Documentation</a> <a href="overview">Documentation</a>
<a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork me on GitHub</a> <a href="http://github.com/jrnl-org/jrnl" title="View on Github">Fork me on GitHub</a>
<a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh&via=maebert">Tell your friends on twitter</a> <a id="twitter-nav" href="https://twitter.com/intent/tweet?text=Write+your+memoirs+on+the+command+line.+Like+a+boss.+%23jrnl&url=http%3A%2F%2Fjrnl.sh">Tell your friends on twitter</a>
<a href="installation" class="cta">Download</a> <a href="installation" class="cta">Download</a>
</nav> </nav>
<div class="flex"> <div class="flex">

View file

@ -119,10 +119,10 @@ Will print all entries in which either `@pinkie` or `@WorldDomination`
occurred. occurred.
```sh ```sh
jrnl -n 5 -and @pineapple @lubricant jrnl -n 5 -and @pinkie @WorldDomination
``` ```
the last five entries containing both `@pineapple` **and** `@lubricant`. the last five entries containing both `@pinkie` **and** `@worldDomination`.
You can change which symbols you'd like to use for tagging in the You can change which symbols you'd like to use for tagging in the
configuration. configuration.
@ -154,7 +154,7 @@ encrypt) your edited journal after you save and exit the editor.
You can also use this feature for deleting entries from your journal You can also use this feature for deleting entries from your journal
```sh ```sh
jrnl @girlfriend -until 'june 2012' --edit jrnl @texas -until 'june 2012' --edit
``` ```
Just select all text, press delete, and everything is gone... Just select all text, press delete, and everything is gone...

View file

@ -41,6 +41,14 @@ Feature: Basic reading and writing to a journal
When we run "jrnl -on 'june 6 2013' --short" When we run "jrnl -on 'june 6 2013' --short"
Then the output should be "2013-06-10 15:40 Life is good." Then the output should be "2013-06-10 15:40 Life is good."
Scenario: Emoji support
Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: 🌞 sunny day. Saw an 🐘"
Then we should see the message "Entry added"
When we run "jrnl -n 1"
Then the output should contain "🌞"
and the output should contain "🐘"
Scenario: Writing an entry at the prompt Scenario: Writing an entry at the prompt
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive." When we run "jrnl" and enter "25 jul 2013: I saw Elvis. He's alive."

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: ''
encrypt: false
highlight: true
journals:
default: features/journals/bug780.dayone
linewrap: 80
tagsymbols: '@'
template: false
timeformat: '%Y-%m-%d %H:%M'
indent_character: "|"

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Activity</key>
<string>Stationary</string>
<key>Creation Date</key>
<date>2019-12-30T21:28:54Z</date>
<key>Entry Text</key>
<string></string>
<key>Starred</key>
<false />
<key>UUID</key>
<string>48A25033B34047C591160A4480197D8B</string>
<key>Creator</key>
<dict>
<key>Device Agent</key>
<string>PC</string>
<key>Generation Date</key>
<date>2019-12-30T21:28:54Z</date>
<key>Host Name</key>
<string>LE-TREPORT</string>
<key>OS Agent</key>
<string>Microsoft Windows/10 Home</string>
<key>Software Agent</key>
<string>Journaley/2.1</string>
</dict>
<key>Tags</key>
<array>
<string>i_have_no_body</string>
</array>
</dict>
</plist>

View file

@ -1,7 +1,5 @@
Feature: Dayone specific implementation details. Feature: Dayone specific implementation details.
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading a DayOne Journal Scenario: Loading a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl -from 'feb 2013'" When we run "jrnl -from 'feb 2013'"
@ -15,7 +13,7 @@ Feature: Dayone specific implementation details.
2013-07-17 11:38 This entry is starred! 2013-07-17 11:38 This entry is starred!
""" """
# fails when system time is UTC (as on Travis-CI) # broken still
@skip @skip
Scenario: Entries without timezone information will be interpreted as in the current timezone Scenario: Entries without timezone information will be interpreted as in the current timezone
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
@ -23,7 +21,6 @@ Feature: Dayone specific implementation details.
Then we should get no error Then we should get no error
and the output should contain "2013-01-17T18:37Z" in the local time and the output should contain "2013-01-17T18:37Z" in the local time
@skip
Scenario: Writing into Dayone Scenario: Writing into Dayone
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl 01 may 1979: Being born hurts." When we run "jrnl 01 may 1979: Being born hurts."
@ -33,8 +30,6 @@ Feature: Dayone specific implementation details.
1979-05-01 09:00 Being born hurts. 1979-05-01 09:00 Being born hurts.
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Loading tags from a DayOne Journal Scenario: Loading tags from a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl --tags" When we run "jrnl --tags"
@ -44,8 +39,6 @@ Feature: Dayone specific implementation details.
@play : 1 @play : 1
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Saving tags from a DayOne Journal Scenario: Saving tags from a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl A hard day at @work" When we run "jrnl A hard day at @work"
@ -56,8 +49,6 @@ Feature: Dayone specific implementation details.
@play : 1 @play : 1
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Filtering by tags from a DayOne Journal Scenario: Filtering by tags from a DayOne Journal
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl @work" When we run "jrnl @work"
@ -66,8 +57,6 @@ Feature: Dayone specific implementation details.
2013-05-17 11:39 This entry has tags! 2013-05-17 11:39 This entry has tags!
""" """
# fails when system time is UTC (as on Travis-CI)
@skip
Scenario: Exporting dayone to json Scenario: Exporting dayone to json
Given we use the config "dayone.yaml" Given we use the config "dayone.yaml"
When we run "jrnl --export json" When we run "jrnl --export json"

View file

@ -24,7 +24,6 @@ Feature: Zapped Dayone bugs stay dead!
| I'm feeling sore because I forgot to stretch. | I'm feeling sore because I forgot to stretch.
""" """
@skip_win
Scenario: Opening an folder that's not a DayOne folder gives a nice error message Scenario: Opening an folder that's not a DayOne folder gives a nice error message
Given we use the config "empty_folder.yaml" Given we use the config "empty_folder.yaml"
When we run "jrnl Herro" When we run "jrnl Herro"

View file

@ -12,7 +12,6 @@
Then we should see the message "Journal decrypted" Then we should see the message "Journal decrypted"
And the journal should have 2 entries And the journal should have 2 entries
@skip_win
Scenario: Encrypting a journal Scenario: Encrypting a journal
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl --encrypt" and enter When we run "jrnl --encrypt" and enter
@ -27,7 +26,6 @@
Then the output should contain "Password" Then the output should contain "Password"
And the output should contain "2013-06-10 15:40 Life is good" And the output should contain "2013-06-10 15:40 Life is good"
@skip_win
Scenario: Mistyping your password Scenario: Mistyping your password
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl --encrypt" and enter When we run "jrnl --encrypt" and enter
@ -45,7 +43,6 @@
Then the output should contain "Password" Then the output should contain "Password"
And the output should contain "2013-06-10 15:40 Life is good" And the output should contain "2013-06-10 15:40 Life is good"
@skip_win
Scenario: Storing a password in Keychain Scenario: Storing a password in Keychain
Given we use the config "multiple.yaml" Given we use the config "multiple.yaml"
When we run "jrnl simple --encrypt" and enter When we run "jrnl simple --encrypt" and enter

View file

@ -4,21 +4,20 @@ Feature: Exporting a Journal
Given we use the config "tags.yaml" Given we use the config "tags.yaml"
When we run "jrnl --export json" When we run "jrnl --export json"
Then we should get no error Then we should get no error
and the output should be parsable as json And the output should be parsable as json
and "entries" in the json output should have 2 elements And "entries" in the json output should have 2 elements
and "tags" in the json output should contain "@idea" And "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal" And "tags" in the json output should contain "@journal"
and "tags" in the json output should contain "@dan" And "tags" in the json output should contain "@dan"
Scenario: Exporting using filters should only export parts of the journal Scenario: Exporting using filters should only export parts of the journal
Given we use the config "tags.yaml" Given we use the config "tags.yaml"
When we run "jrnl -until 'may 2013' --export json" When we run "jrnl -until 'may 2013' --export json"
# Then we should get no error
Then the output should be parsable as json Then the output should be parsable as json
and "entries" in the json output should have 1 element And "entries" in the json output should have 1 element
and "tags" in the json output should contain "@idea" And "tags" in the json output should contain "@idea"
and "tags" in the json output should contain "@journal" And "tags" in the json output should contain "@journal"
and "tags" in the json output should not contain "@dan" And "tags" in the json output should not contain "@dan"
Scenario: Exporting using custom templates Scenario: Exporting using custom templates
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
@ -83,3 +82,57 @@ Feature: Exporting a Journal
More stuff More stuff
more stuff again more stuff again
""" """
Scenario: Exporting to XML
Given we use the config "tags.yaml"
When we run "jrnl --export xml"
Then the output should be a valid XML string
And "entries" node in the xml output should have 2 elements
And "tags" in the xml output should contain ["@idea", "@journal", "@dan"]
Scenario: Exporting tags
Given we use the config "tags.yaml"
When we run "jrnl --export tags"
Then the output should be
"""
@idea : 2
@journal : 1
@dan : 1
"""
Scenario: Exporting fancy
Given we use the config "tags.yaml"
When we run "jrnl --export fancy"
Then the output should be
"""
2013-04-09 15:39
I have an @idea:
(1) write a command line @journal software
(2) ???
(3) PROFIT!
2013-06-10 15:40
I met with @dan.
As alway's he shared his latest @idea on how to rule the world with me.
inst
"""
Scenario: Export to yaml
Given we use the config "tags.yaml"
And we created a directory named "exported_journal"
When we run "jrnl --export yaml -o exported_journal"
Then "exported_journal" should contain the files ["2013-04-09_i-have-an-idea.md", "2013-06-10_i-met-with-dan.md"]
And the content of exported yaml "exported_journal/2013-04-09_i-have-an-idea.md" should be
"""
title: I have an @idea:
date: 2013-04-09 15:39
stared: False
tags: idea, journal
(1) write a command line @journal software
(2) ???
(3) PROFIT!
"""

View file

@ -1,7 +1,7 @@
Feature: Zapped bugs should stay dead. Feature: Zapped bugs should stay dead.
Scenario: Writing an entry does not print the entire journal Scenario: Writing an entry does not print the entire journal
# https://github.com/maebert/jrnl/issues/87 # https://github.com/jrnl-org/jrnl/issues/87
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa." When we run "jrnl 23 july 2013: A cold and stormy day. I ate crisps on the sofa."
Then we should see the message "Entry added" Then we should see the message "Entry added"
@ -9,21 +9,14 @@ Feature: Zapped bugs should stay dead.
Then the output should not contain "Life is good" Then the output should not contain "Life is good"
Scenario: Date with time should be parsed correctly Scenario: Date with time should be parsed correctly
# https://github.com/maebert/jrnl/issues/117 # https://github.com/jrnl-org/jrnl/issues/117
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 2013-11-30 15:42: Project Started." When we run "jrnl 2013-11-30 15:42: Project Started."
Then we should see the message "Entry added" Then we should see the message "Entry added"
and the journal should contain "[2013-11-30 15:42] Project Started." and the journal should contain "[2013-11-30 15:42] Project Started."
Scenario: Date in the future should be parsed correctly
# https://github.com/maebert/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Loading entry with ambiguous time stamp Scenario: Loading entry with ambiguous time stamp
#https://github.com/maebert/jrnl/issues/153 #https://github.com/jrnl-org/jrnl/issues/153
Given we use the config "bug153.yaml" Given we use the config "bug153.yaml"
When we run "jrnl -1" When we run "jrnl -1"
Then we should get no error Then we should get no error
@ -32,6 +25,19 @@ Feature: Zapped bugs should stay dead.
2013-10-27 03:27 Some text. 2013-10-27 03:27 Some text.
""" """
Scenario: Date in the future should be parsed correctly
# https://github.com/jrnl-org/jrnl/issues/185
Given we use the config "basic.yaml"
When we run "jrnl 26/06/2019: Planet? Earth. Year? 2019."
Then we should see the message "Entry added"
and the journal should contain "[2019-06-26 09:00] Planet?"
Scenario: Empty DayOne entry bodies should not error
# https://github.com/jrnl-org/jrnl/issues/780
Given we use the config "bug780.yaml"
When we run "jrnl --short"
Then we should get no error
Scenario: Title with an embedded period. Scenario: Title with an embedded period.
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic." When we run "jrnl 04-24-2014: Created a new website - empty.com. Hope to get a lot of traffic."

View file

@ -3,7 +3,6 @@ from unittest.mock import patch
from behave import given, when, then from behave import given, when, then
from jrnl import cli, install, Journal, util, plugins from jrnl import cli, install, Journal, util, plugins
from jrnl import __version__ from jrnl import __version__
from dateutil import parser as date_parser
from collections import defaultdict from collections import defaultdict
try: try:
@ -185,53 +184,6 @@ def no_error(context):
assert context.exit_status == 0, context.exit_status assert context.exit_status == 0, context.exit_status
@then("the output should be parsable as json")
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split("."):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then("the output should be") @then("the output should be")
@then('the output should be "{text}"') @then('the output should be "{text}"')
def check_output(context, text=None): def check_output(context, text=None):

View file

@ -0,0 +1,124 @@
import json
import os
import shutil
from xml.etree import ElementTree
from behave import then, given
@then("the output should be parsable as json")
def check_output_json(context):
out = context.stdout_capture.getvalue()
assert json.loads(out), out
@then('"{field}" in the json output should have {number:d} elements')
@then('"{field}" in the json output should have 1 element')
def check_output_field(context, field, number=1):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json, [field, out_json]
assert len(out_json[field]) == number, len(out_json[field])
@then('"{field}" in the json output should not contain "{key}"')
def check_output_field_not_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key not in out_json[field]
@then('"{field}" in the json output should contain "{key}"')
def check_output_field_key(context, field, key):
out = context.stdout_capture.getvalue()
out_json = json.loads(out)
assert field in out_json
assert key in out_json[field]
@then('the json output should contain {path} = "{value}"')
def check_json_output_path(context, path, value):
""" E.g.
the json output should contain entries.0.title = "hello"
"""
out = context.stdout_capture.getvalue()
struct = json.loads(out)
for node in path.split("."):
try:
struct = struct[int(node)]
except ValueError:
struct = struct[node]
assert struct == value, struct
@then("the output should be a valid XML string")
def assert_valid_xml_string(context):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
assert xml_tree, output
@then('"entries" node in the xml output should have {number:d} elements')
def assert_xml_output_entries_count(context, number):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "entries" in xml_tags, str(list(xml_tags))
actual_entry_count = len(xml_tree.find("entries"))
assert actual_entry_count == number, actual_entry_count
@then('"tags" in the xml output should contain {expected_tags_json_list}')
def assert_xml_output_tags(context, expected_tags_json_list):
output = context.stdout_capture.getvalue()
xml_tree = ElementTree.fromstring(output)
xml_tags = (node.tag for node in xml_tree)
assert "tags" in xml_tags, str(list(xml_tags))
expected_tags = json.loads(expected_tags_json_list)
actual_tags = set(t.attrib["name"] for t in xml_tree.find("tags"))
assert actual_tags == set(expected_tags), [actual_tags, set(expected_tags)]
@given('we created a directory named "{dir_name}"')
def create_directory(context, dir_name):
if os.path.exists(dir_name):
shutil.rmtree(dir_name)
os.mkdir(dir_name)
@then('"{dir_name}" should contain the files {expected_files_json_list}')
def assert_dir_contains_files(context, dir_name, expected_files_json_list):
actual_files = os.listdir(dir_name)
expected_files = json.loads(expected_files_json_list)
assert actual_files == expected_files, [actual_files, expected_files]
@then('the content of exported yaml "{file_path}" should be')
def assert_exported_yaml_file_content(context, file_path):
expected_content = context.text.strip().splitlines()
with open(file_path, "r") as f:
actual_content = f.read().strip().splitlines()
for actual_line, expected_line in zip(actual_content, expected_content):
if actual_line.startswith("tags: ") and expected_line.startswith("tags: "):
assert_equal_tags_ignoring_order(actual_line, expected_line)
else:
assert actual_line.strip() == expected_line.strip(), [
actual_line.strip(),
expected_line.strip(),
]
def assert_equal_tags_ignoring_order(actual_line, expected_line):
actual_tags = set(tag.strip() for tag in actual_line[len("tags: ") :].split(","))
expected_tags = set(
tag.strip() for tag in expected_line[len("tags: ") :].split(",")
)
assert actual_tags == expected_tags, [actual_tags, expected_tags]

View file

@ -1,6 +1,5 @@
Feature: Upgrading Journals from 1.x.x to 2.x.x Feature: Upgrading Journals from 1.x.x to 2.x.x
@skip_win
Scenario: Upgrade and parse journals with square brackets Scenario: Upgrade and parse journals with square brackets
Given we use the config "upgrade_from_195.json" Given we use the config "upgrade_from_195.json"
When we run "jrnl -9" and enter "Y" When we run "jrnl -9" and enter "Y"
@ -12,7 +11,6 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
""" """
Then the journal should have 2 entries Then the journal should have 2 entries
@skip_win
Scenario: Upgrading a journal encrypted with jrnl 1.x Scenario: Upgrading a journal encrypted with jrnl 1.x
Given we use the config "encrypted_old.json" Given we use the config "encrypted_old.json"
When we run "jrnl -n 1" and enter When we run "jrnl -n 1" and enter
@ -24,7 +22,6 @@ Feature: Upgrading Journals from 1.x.x to 2.x.x
Then the output should contain "Password" Then the output should contain "Password"
and the output should contain "2013-06-10 15:40 Life is good" and the output should contain "2013-06-10 15:40 Life is good"
@skip_win
Scenario: Upgrade and parse journals with little endian date format Scenario: Upgrade and parse journals with little endian date format
Given we use the config "upgrade_from_195_little_endian_dates.json" Given we use the config "upgrade_from_195_little_endian_dates.json"
When we run "jrnl -9" and enter "Y" When we run "jrnl -9" and enter "Y"

View file

@ -52,7 +52,11 @@ class DayOne(Journal.Journal):
except (KeyError, pytz.exceptions.UnknownTimeZoneError): except (KeyError, pytz.exceptions.UnknownTimeZoneError):
timezone = tzlocal.get_localzone() timezone = tzlocal.get_localzone()
date = dict_entry["Creation Date"] date = dict_entry["Creation Date"]
date = date + timezone.utcoffset(date, is_dst=False) # convert the date to UTC rather than keep messing with
# timezones
if timezone.zone != "UTC":
date = date + timezone.utcoffset(date, is_dst=False)
entry = Entry.Entry( entry = Entry.Entry(
self, self,
date, date,

View file

@ -22,7 +22,7 @@ class Entry:
def _parse_text(self): def _parse_text(self):
raw_text = self.text raw_text = self.text
lines = raw_text.splitlines() lines = raw_text.splitlines()
if lines[0].strip().endswith("*"): if lines and lines[0].strip().endswith("*"):
self.starred = True self.starred = True
raw_text = lines[0].strip("\n *") + "\n" + "\n".join(lines[1:]) raw_text = lines[0].strip("\n *") + "\n" + "\n".join(lines[1:])
self._title, self._body = split_title(raw_text) self._title, self._body = split_title(raw_text)

1
jrnl/__version__.py Normal file
View file

@ -0,0 +1 @@
__version__ = "v2.2-beta"

View file

@ -1,62 +0,0 @@
#!/usr/bin/env python
from .util import ERROR_COLOR, RESET_COLOR
from .util import slugify
from .plugins.template import Template
import os
class Exporter:
"""This Exporter can convert entries and journals into text files."""
def __init__(self, format):
with open("jrnl/templates/" + format + ".template") as f:
front_matter, body = f.read().strip("-\n").split("---", 2)
self.template = Template(body)
def export_entry(self, entry):
"""Returns a string representation of a single entry."""
return str(entry)
def _get_vars(self, journal):
return {"journal": journal, "entries": journal.entries, "tags": journal.tags}
def export_journal(self, journal):
"""Returns a string representation of an entire journal."""
return self.template.render_block("journal", **self._get_vars(journal))
def write_file(self, journal, path):
"""Exports a journal into a single file."""
try:
with open(path, "w", encoding="utf-8") as f:
f.write(self.export_journal(journal))
return f"[Journal exported to {path}]"
except OSError as e:
return f"[{ERROR_COLOR}ERROR{RESET_COLOR}: {e.filename} {e.strerror}]"
def make_filename(self, entry):
return entry.date.strftime(
"%Y-%m-%d_{}.{}".format(slugify(entry.title), self.extension)
)
def write_files(self, journal, path):
"""Exports a journal into individual files for each entry."""
for entry in journal.entries:
try:
full_path = os.path.join(path, self.make_filename(entry))
with open(full_path, "w", encoding="utf-8") as f:
f.write(self.export_entry(entry))
except OSError as e:
return f"[{ERROR_COLOR}ERROR{RESET_COLOR}: {e.filename} {e.strerror}]"
return f"[Journal exported to {path}]"
def export(self, journal, format="text", output=None):
"""Exports to individual files if output is an existing path, or into
a single file if output is a file name, or returns the exporter's
representation as string if output is None."""
if output and os.path.isdir(output): # multiple files
return self.write_files(journal, output)
elif output: # single file
return self.write_file(journal, output)
else:
return self.export_journal(journal)

View file

@ -19,11 +19,10 @@ class YAMLExporter(TextExporter):
"""Returns a markdown representation of a single entry, with YAML front matter.""" """Returns a markdown representation of a single entry, with YAML front matter."""
if to_multifile is False: if to_multifile is False:
print( print(
"{}ERROR{}: YAML export must be to individual files. " "{}ERROR{}: YAML export must be to individual files. Please \
"Please specify a directory to export to.".format( specify a directory to export to.".format(
"\033[31m", "\033[0m" ERROR_COLOR, RESET_COLOR, file=sys.stderr
), )
file=sys.stderr,
) )
return return
@ -33,16 +32,14 @@ class YAMLExporter(TextExporter):
tagsymbols = entry.journal.config["tagsymbols"] tagsymbols = entry.journal.config["tagsymbols"]
# see also Entry.Entry.rag_regex # see also Entry.Entry.rag_regex
multi_tag_regex = re.compile( multi_tag_regex = re.compile(fr"(?u)^\s*([{tagsymbols}][-+*#/\w]+\s*)+$")
r"(?u)^\s*([{tags}][-+*#/\w]+\s*)+$".format(tags=tagsymbols)
)
"""Increase heading levels in body text""" """Increase heading levels in body text"""
newbody = "" newbody = ""
heading = "#" heading = "#"
previous_line = "" previous_line = ""
warn_on_heading_level = False warn_on_heading_level = False
for line in entry.body.splitlines(True): for line in body.splitlines(True):
if re.match(r"^#+ ", line): if re.match(r"^#+ ", line):
"""ATX style headings""" """ATX style headings"""
newbody = newbody + previous_line + heading + line newbody = newbody + previous_line + heading + line
@ -80,9 +77,32 @@ class YAMLExporter(TextExporter):
dayone_attributes = "" dayone_attributes = ""
if hasattr(entry, "uuid"): if hasattr(entry, "uuid"):
dayone_attributes += "uuid: " + entry.uuid + "\n" dayone_attributes += "uuid: " + entry.uuid + "\n"
# TODO: copy over pictures, if present if (
# source directory is entry.journal.config['journal'] hasattr(entry, "creator_device_agent")
# output directory is...? or hasattr(entry, "creator_generation_date")
or hasattr(entry, "creator_host_name")
or hasattr(entry, "creator_os_agent")
or hasattr(entry, "creator_software_agent")
):
dayone_attributes += "creator:\n"
if hasattr(entry, "creator_device_agent"):
dayone_attributes += f" device agent: {entry.creator_device_agent}\n"
if hasattr(entry, "creator_generation_date"):
dayone_attributes += " generation date: {}\n".format(
str(entry.creator_generation_date)
)
if hasattr(entry, "creator_host_name"):
dayone_attributes += f" host name: {entry.creator_host_name}\n"
if hasattr(entry, "creator_os_agent"):
dayone_attributes += f" os agent: {entry.creator_os_agent}\n"
if hasattr(entry, "creator_software_agent"):
dayone_attributes += (
f" software agent: {entry.creator_software_agent}\n"
)
# TODO: copy over pictures, if present
# source directory is entry.journal.config['journal']
# output directory is...?
return "title: {title}\ndate: {date}\nstared: {stared}\ntags: {tags}\n{dayone} {body} {space}".format( return "title: {title}\ndate: {date}\nstared: {stared}\ntags: {tags}\n{dayone} {body} {space}".format(
date=date_str, date=date_str,

View file

@ -12,7 +12,7 @@ markdown_extensions:
- admonition - admonition
repo_url: https://github.com/jrnl-org/jrnl/ repo_url: https://github.com/jrnl-org/jrnl/
site_author: Manuel Ebert site_author: Manuel Ebert
site_description: Never Worry about Money Again. site_description: Collect your thoughts and notes without leaving the command line.
nav: nav:
- Overview: overview.md - Overview: overview.md
- Quickstart: installation.md - Quickstart: installation.md

View file

@ -1,12 +1,15 @@
[tool.poetry] [tool.poetry]
name = "jrnl" name = "jrnl"
version = "v2.1.1" version = "v2.2.1-beta2"
description = "Collect your thoughts and notes without leaving the command line." description = "Collect your thoughts and notes without leaving the command line."
authors = [ authors = [
"Manuel Ebert <manuel@1450.me>", "Manuel Ebert <manuel@1450.me>",
"Jonathan Wren <jonathan@nowandwren.com>", "Jonathan Wren <jonathan@nowandwren.com>",
"Micah Ellison <micahellison@gmail.com>" "Micah Ellison <micahellison@gmail.com>"
] ]
maintainers = [
"Jonathan Wren and Micah Ellison <jrnl-sh@googlegroups.com>",
]
license = "MIT" license = "MIT"
readme = "README.md" readme = "README.md"
homepage = "https://jrnl.sh" homepage = "https://jrnl.sh"
@ -30,7 +33,7 @@ pyyaml = "^5.1"
behave = "^1.2" behave = "^1.2"
mkdocs = "^1.0" mkdocs = "^1.0"
flake8 = "^3.7" flake8 = "^3.7"
black = {version = "^19.10b0",allows-prereleases = true} black = {version = "^19.10b0",allow-prereleases = true}
[tool.poetry.scripts] [tool.poetry.scripts]
jrnl = 'jrnl.cli:run' jrnl = 'jrnl.cli:run'