mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 16:48:31 +02:00
Move import to be standalone command to reduce clutter in cli.py
This commit is contained in:
parent
1d5c065b1f
commit
41d06bfc65
9 changed files with 113 additions and 84 deletions
|
@ -136,6 +136,40 @@ Feature: Basic reading and writing to a journal
|
|||
Then the output should contain "jrnl"
|
||||
And the output should contain "Python"
|
||||
|
||||
Scenario: Version warning appears for versions below 3.7
|
||||
When we run "jrnl --diagnostic"
|
||||
Then the Python version warning should appear if our version is below 3.7
|
||||
Scenario: --import allows new entry to journal
|
||||
Given we use the config "basic.yaml"
|
||||
When we run "jrnl --import" and pipe "[2020-07-05 15:00] Observe and import."
|
||||
And we run "jrnl -1"
|
||||
Then the journal should contain "[2020-07-05 15:00] Observe and import."
|
||||
And the output should contain "Observe and import"
|
||||
|
||||
Scenario: --import allows new large entry to journal
|
||||
Given we use the config "basic.yaml"
|
||||
When we run "jrnl --import" and pipe
|
||||
"""
|
||||
[2020-07-05 15:00] Observe and import.
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent malesuada quis
|
||||
est ac dignissim. Aliquam dignissim rutrum pretium. Phasellus pellentesque augue
|
||||
et venenatis facilisis. Suspendisse potenti. Sed dignissim sed nisl eu consequat.
|
||||
Aenean ante ex, elementum ut interdum et, mattis eget lacus. In commodo nulla nec
|
||||
tellus placerat, sed ultricies metus bibendum. Duis eget venenatis erat. In at
|
||||
dolor dui end of entry.
|
||||
"""
|
||||
And we run "jrnl -1"
|
||||
Then the journal should contain "[2020-07-05 15:00] Observe and import."
|
||||
And the output should contain "Observe and import"
|
||||
And the output should contain "Lorem ipsum"
|
||||
And the output should contain "end of entry."
|
||||
|
||||
Scenario: --import allows import of multiple entries to journal
|
||||
Given we use the config "basic.yaml"
|
||||
When we run "jrnl --import" and pipe
|
||||
"""
|
||||
[2020-07-05 15:00] Observe and import.
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
|
||||
[2020-07-05 15:01] Twice as nice.
|
||||
Sed dignissim sed nisl eu consequat.
|
||||
"""
|
||||
Then the journal should contain "[2020-07-05 15:00] Observe and import."
|
||||
Then the journal should contain "[2020-07-05 15:01] Twice as nice."
|
||||
|
|
|
@ -210,8 +210,12 @@ def run_with_input(context, command, inputs=""):
|
|||
|
||||
|
||||
@when('we run "{command}"')
|
||||
@when('we run "{command}" and pipe')
|
||||
@when('we run "{command}" and pipe "{text}"')
|
||||
@when('we run "{command}" with cache directory "{cache_dir}"')
|
||||
def run(context, command, cache_dir=None):
|
||||
def run(context, command, text="", cache_dir=None):
|
||||
text = text or context.text or ""
|
||||
|
||||
if cache_dir is not None:
|
||||
cache_dir = os.path.join("features", "cache", cache_dir)
|
||||
command = command.format(cache_dir=cache_dir)
|
||||
|
@ -224,7 +228,7 @@ def run(context, command, cache_dir=None):
|
|||
try:
|
||||
with patch("sys.argv", args), patch(
|
||||
"subprocess.call", side_effect=_mock_editor
|
||||
):
|
||||
), patch("sys.stdin.read", side_effect=lambda: text):
|
||||
cli.run(args[1:])
|
||||
context.exit_status = 0
|
||||
except SystemExit as e:
|
||||
|
|
|
@ -371,7 +371,7 @@ class LegacyJournal(Journal):
|
|||
return entries
|
||||
|
||||
|
||||
def open_journal(name, config, legacy=False):
|
||||
def open_journal(journal_name, config, legacy=False):
|
||||
"""
|
||||
Creates a normal, encrypted or DayOne journal based on the passed config.
|
||||
If legacy is True, it will open Journals with legacy classes build for
|
||||
|
@ -394,11 +394,18 @@ def open_journal(name, config, legacy=False):
|
|||
|
||||
if not config["encrypt"]:
|
||||
if legacy:
|
||||
return LegacyJournal(name, **config).open()
|
||||
return PlainJournal(name, **config).open()
|
||||
else:
|
||||
return LegacyJournal(journal_name, **config).open()
|
||||
return PlainJournal(journal_name, **config).open()
|
||||
|
||||
from . import EncryptedJournal
|
||||
|
||||
try:
|
||||
if legacy:
|
||||
return EncryptedJournal.LegacyEncryptedJournal(name, **config).open()
|
||||
return EncryptedJournal.EncryptedJournal(name, **config).open()
|
||||
return EncryptedJournal.LegacyEncryptedJournal(
|
||||
journal_name, **config
|
||||
).open()
|
||||
return EncryptedJournal.EncryptedJournal(journal_name, **config).open()
|
||||
except KeyboardInterrupt:
|
||||
# Since encrypted journals prompt for a password, it's easy for a user to ctrl+c out
|
||||
print("[Interrupted while opening journal]", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
|
62
jrnl/cli.py
62
jrnl/cli.py
|
@ -25,10 +25,10 @@ import platform
|
|||
import sys
|
||||
|
||||
from . import install, plugins, util
|
||||
from .parsing import parse_args_before_config
|
||||
from .parsing import parse_args_after_config
|
||||
from .parsing import parse_args
|
||||
from .Journal import PlainJournal, open_journal
|
||||
from .util import WARNING_COLOR, ERROR_COLOR, RESET_COLOR, UserAbort
|
||||
from .util import get_journal_name
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
logging.getLogger("keyring.backend").setLevel(logging.ERROR)
|
||||
|
@ -38,12 +38,7 @@ def guess_mode(args, config):
|
|||
"""Guesses the mode (compose, read or export) from the given arguments"""
|
||||
compose = True
|
||||
export = False
|
||||
import_ = False
|
||||
if args.import_ is not False:
|
||||
compose = False
|
||||
export = False
|
||||
import_ = True
|
||||
elif (
|
||||
if (
|
||||
args.decrypt is not False
|
||||
or args.encrypt is not False
|
||||
or args.export is not False
|
||||
|
@ -70,7 +65,7 @@ def guess_mode(args, config):
|
|||
# No date and only tags?
|
||||
compose = False
|
||||
|
||||
return compose, export, import_
|
||||
return compose, export
|
||||
|
||||
|
||||
def encrypt(journal, filename=None):
|
||||
|
@ -139,7 +134,7 @@ Python 3.7 (or higher) soon.
|
|||
if manual_args is None:
|
||||
manual_args = sys.argv[1:]
|
||||
|
||||
args = parse_args_before_config(manual_args)
|
||||
args = parse_args(manual_args)
|
||||
configure_logger(args.debug)
|
||||
|
||||
# Run command if possible before config is available
|
||||
|
@ -150,38 +145,24 @@ Python 3.7 (or higher) soon.
|
|||
# Load the config
|
||||
try:
|
||||
config = install.load_or_install_jrnl()
|
||||
original_config = config.copy()
|
||||
args = get_journal_name(args, config)
|
||||
config = util.scope_config(config, args.journal_name)
|
||||
except UserAbort as err:
|
||||
print(f"\n{err}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Run command now that config is available
|
||||
# Run post-config command now that config is ready
|
||||
if callable(args.postconfig_cmd):
|
||||
args.postconfig_cmd(config=config, args=args)
|
||||
args.postconfig_cmd(args=args, config=config)
|
||||
sys.exit(0)
|
||||
|
||||
args = parse_args_after_config(args, config)
|
||||
# --- All the standalone commands are now done --- #
|
||||
|
||||
log.debug('Using configuration "%s"', config)
|
||||
original_config = config.copy()
|
||||
|
||||
config = util.scope_config(config, args.journal_name)
|
||||
|
||||
log.debug('Using journal "%s"', args.journal_name)
|
||||
|
||||
mode_compose, mode_export, mode_import = guess_mode(args, config)
|
||||
|
||||
# How to quit writing?
|
||||
if "win32" in sys.platform:
|
||||
_exit_multiline_code = "on a blank line, press Ctrl+Z and then Enter"
|
||||
else:
|
||||
_exit_multiline_code = "press Ctrl+D"
|
||||
|
||||
# This is where we finally open the journal!
|
||||
try:
|
||||
# Get the journal we're going to be working with
|
||||
journal = open_journal(args.journal_name, config)
|
||||
except KeyboardInterrupt:
|
||||
print("[Interrupted while opening journal]", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
mode_compose, mode_export = guess_mode(args, config)
|
||||
|
||||
if mode_compose and not args.text:
|
||||
if not sys.stdin.isatty():
|
||||
|
@ -201,25 +182,24 @@ Python 3.7 (or higher) soon.
|
|||
raw = util.get_text_from_editor(config, template)
|
||||
else:
|
||||
try:
|
||||
_how_to_quit = (
|
||||
"Ctrl+z and then Enter" if "win32" in sys.platform else "Ctrl+d"
|
||||
)
|
||||
print(
|
||||
"[Compose Entry; " + _exit_multiline_code + " to finish writing]\n",
|
||||
f"[Writing Entry; on a blank line, press {_how_to_quit} to finish writing]\n",
|
||||
file=sys.stderr,
|
||||
)
|
||||
raw = sys.stdin.read()
|
||||
except KeyboardInterrupt:
|
||||
print("[Entry NOT saved to journal.]", file=sys.stderr)
|
||||
print("[Entry NOT saved to journal]", file=sys.stderr)
|
||||
sys.exit(0)
|
||||
if raw:
|
||||
args.text = [raw]
|
||||
else:
|
||||
sys.exit()
|
||||
|
||||
# Import mode
|
||||
if mode_import:
|
||||
plugins.get_importer(args.import_).import_(journal, args.input)
|
||||
|
||||
# Writing mode
|
||||
elif mode_compose:
|
||||
if mode_compose:
|
||||
raw = " ".join(args.text).strip()
|
||||
log.debug('Appending raw line "%s" to journal "%s"', raw, args.journal_name)
|
||||
journal.new_entry(raw)
|
||||
|
@ -242,7 +222,7 @@ Python 3.7 (or higher) soon.
|
|||
journal.limit(args.limit)
|
||||
|
||||
# Reading mode
|
||||
if not mode_compose and not mode_export and not mode_import:
|
||||
if not mode_compose and not mode_export:
|
||||
print(journal.pprint())
|
||||
|
||||
# Various export modes
|
||||
|
|
|
@ -21,3 +21,14 @@ def postconfig_list(config, **kwargs):
|
|||
from .util import list_journals
|
||||
|
||||
print(list_journals(config))
|
||||
|
||||
|
||||
def postconfig_import(args, config, **kwargs):
|
||||
from .plugins import get_importer
|
||||
from .Journal import open_journal
|
||||
|
||||
# Requires opening the journal
|
||||
journal = open_journal(args.journal_name, config)
|
||||
|
||||
format = args.export if args.export else "jrnl"
|
||||
get_importer(format).import_(journal, args.input)
|
||||
|
|
|
@ -117,13 +117,14 @@ def load_or_install_jrnl():
|
|||
upgrade_config(config)
|
||||
verify_config(config)
|
||||
|
||||
return config
|
||||
else:
|
||||
log.debug("Configuration file not found, installing jrnl...")
|
||||
try:
|
||||
config = install()
|
||||
except KeyboardInterrupt:
|
||||
raise UserAbort("Installation aborted")
|
||||
|
||||
log.debug('Using configuration "%s"', config)
|
||||
return config
|
||||
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ from .plugins import EXPORT_FORMATS
|
|||
from .commands import preconfig_version
|
||||
from .commands import preconfig_diagnostic
|
||||
from .commands import postconfig_list
|
||||
from .commands import postconfig_import
|
||||
from .util import deprecated_cmd
|
||||
from .util import get_journal_name
|
||||
|
||||
|
||||
class WrappingFormatter(argparse.RawDescriptionHelpFormatter):
|
||||
|
@ -18,7 +18,7 @@ class WrappingFormatter(argparse.RawDescriptionHelpFormatter):
|
|||
return textwrap.wrap(text, width=56)
|
||||
|
||||
|
||||
def parse_args_before_config(args=[]):
|
||||
def parse_args(args=[]):
|
||||
"""
|
||||
Argument parsing that is doable before the config is available.
|
||||
Everything else goes into "text" for later parsing.
|
||||
|
@ -27,7 +27,12 @@ def parse_args_before_config(args=[]):
|
|||
formatter_class=WrappingFormatter,
|
||||
add_help=False,
|
||||
description="The command-line note-taking and journaling app.",
|
||||
epilog="",
|
||||
epilog=textwrap.dedent(
|
||||
"""
|
||||
Thank you to all of our contributors! Come see the whole list of code and
|
||||
financial contributors at https://github.com/jrnl-org/jrnl. And special
|
||||
thanks to Bad Lip Reading for the Yoda joke in the Writing section above."""
|
||||
),
|
||||
)
|
||||
|
||||
optional = parser.add_argument_group("Optional Arguments")
|
||||
|
@ -108,13 +113,11 @@ def parse_args_before_config(args=[]):
|
|||
)
|
||||
standalone.add_argument(
|
||||
"--import",
|
||||
action="store_const",
|
||||
metavar="TYPE",
|
||||
dest="import_",
|
||||
choices=IMPORT_FORMATS,
|
||||
dest="postconfig_cmd",
|
||||
const=postconfig_import,
|
||||
help=f"Import entries into your journal. TYPE can be: {util.oxford_list(IMPORT_FORMATS)} (default: jrnl)",
|
||||
default=False,
|
||||
const="jrnl",
|
||||
nargs="?",
|
||||
)
|
||||
standalone.add_argument(
|
||||
"-i",
|
||||
|
@ -132,17 +135,17 @@ def parse_args_before_config(args=[]):
|
|||
The date and the following colon ("yesterday:") are optional. If you leave
|
||||
them out, "now" will be used:
|
||||
|
||||
jrnl Then I rolled the log over, and underneath was a tiny little stick.
|
||||
jrnl Then I rolled the log over.
|
||||
|
||||
Also, you can mark extra special entries ("star" them) with an asterisk:
|
||||
|
||||
jrnl *That log had a child!
|
||||
jrnl *And underneath was a tiny little stick.
|
||||
|
||||
Please note that asterisks might be a special character in your shell, so you
|
||||
might have to escape them. When in doubt about escaping, put single quotes
|
||||
around your entire entry:
|
||||
might have to escape them. When in doubt about escaping, put quotes around
|
||||
your entire entry:
|
||||
|
||||
jrnl 'saturday at 8pm: *Always pass on what you have learned. -Yoda'"""
|
||||
jrnl "saturday at 2am: *Then I was like 'That log had a child!'" """
|
||||
|
||||
composing = parser.add_argument_group(
|
||||
"Writing", textwrap.dedent(compose_msg).strip()
|
||||
|
@ -270,11 +273,3 @@ def parse_args_before_config(args=[]):
|
|||
|
||||
# return parser.parse_args(args)
|
||||
return parser.parse_intermixed_args(args)
|
||||
|
||||
|
||||
def parse_args_after_config(args, config):
|
||||
# print(str(args)) # @todo take this out
|
||||
|
||||
args = get_journal_name(args, config)
|
||||
|
||||
return args
|
||||
|
|
|
@ -150,7 +150,6 @@ def scope_config(config, journal_name):
|
|||
else:
|
||||
# But also just give them a string to point to the journal file
|
||||
config["journal"] = journal_conf
|
||||
config.pop("journals")
|
||||
return config
|
||||
|
||||
|
||||
|
@ -335,4 +334,5 @@ def get_journal_name(args, config):
|
|||
print(list_journals(config), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
log.debug("Using journal name: %s", args.journal_name)
|
||||
return args
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from jrnl.cli import parse_args_before_config
|
||||
from jrnl.cli import parse_args
|
||||
|
||||
import pytest
|
||||
import shlex
|
||||
|
@ -6,7 +6,7 @@ import shlex
|
|||
|
||||
def cli_as_dict(str):
|
||||
cli = shlex.split(str)
|
||||
args = parse_args_before_config(cli)
|
||||
args = parse_args(cli)
|
||||
return vars(args)
|
||||
|
||||
|
||||
|
@ -21,7 +21,6 @@ def expected_args(**kwargs):
|
|||
"end_date": None,
|
||||
"excluded": [],
|
||||
"export": False,
|
||||
"import_": False,
|
||||
"input": False,
|
||||
"limit": None,
|
||||
"on_date": None,
|
||||
|
@ -106,11 +105,9 @@ def test_export_alone():
|
|||
|
||||
|
||||
def test_import_alone():
|
||||
assert cli_as_dict("--import jrnl") == expected_args(import_="jrnl")
|
||||
from jrnl.commands import postconfig_import
|
||||
|
||||
|
||||
def test_import_defaults_to_jrnl():
|
||||
assert cli_as_dict("--import") == expected_args(import_="jrnl")
|
||||
assert cli_as_dict("--import") == expected_args(postconfig_cmd=postconfig_import)
|
||||
|
||||
|
||||
def test_input_flag_alone():
|
||||
|
|
Loading…
Add table
Reference in a new issue