jrnl.upgrade.upgrade_jrnl()   F
last analyzed

Complexity

Conditions 19

Size

Total Lines 130
Code Lines 81

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 81
nop 1
dl 0
loc 130
rs 0.5999
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like jrnl.upgrade.upgrade_jrnl() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import os
2
import sys
3
4
from . import Journal
5
from . import __version__
6
from .EncryptedJournal import EncryptedJournal
7
from .config import is_config_json
8
from .config import load_config
9
from .config import scope_config
10
from .exception import UpgradeValidationException
11
from .exception import UserAbort
12
from .prompt import yesno
13
14
15
def backup(filename, binary=False):
16
    print(f"  Created a backup at {filename}.backup", file=sys.stderr)
17
    filename = os.path.expanduser(os.path.expandvars(filename))
18
19
    try:
20
        with open(filename, "rb" if binary else "r") as original:
21
            contents = original.read()
22
23
        with open(filename + ".backup", "wb" if binary else "w") as backup:
24
            backup.write(contents)
25
    except FileNotFoundError:
26
        print(f"\nError: {filename} does not exist.")
27
        try:
28
            cont = yesno(f"\nCreate {filename}?", default=False)
29
            if not cont:
30
                raise KeyboardInterrupt
31
32
        except KeyboardInterrupt:
33
            raise UserAbort("jrnl NOT upgraded, exiting.")
34
35
36
def check_exists(path):
37
    """
38
    Checks if a given path exists.
39
    """
40
    return os.path.exists(path)
41
42
43
def upgrade_jrnl(config_path):
44
    config = load_config(config_path)
45
46
    print(
47
        f"""Welcome to jrnl {__version__}.
48
49
It looks like you've been using an older version of jrnl until now. That's
50
okay - jrnl will now upgrade your configuration and journal files. Afterwards
51
you can enjoy all of the great new features that come with jrnl 2:
52
53
- Support for storing your journal in multiple files
54
- Faster reading and writing for large journals
55
- New encryption back-end that makes installing jrnl much easier
56
- Tons of bug fixes
57
58
Please note that jrnl 1.x is NOT forward compatible with this version of jrnl.
59
If you choose to proceed, you will not be able to use your journals with
60
older versions of jrnl anymore.
61
"""
62
    )
63
64
    encrypted_journals = {}
65
    plain_journals = {}
66
    other_journals = {}
67
    all_journals = []
68
69
    for journal_name, journal_conf in config["journals"].items():
70
        if isinstance(journal_conf, dict):
71
            path = journal_conf.get("journal")
72
            encrypt = journal_conf.get("encrypt")
73
        else:
74
            encrypt = config.get("encrypt")
75
            path = journal_conf
76
77
        if os.path.exists(os.path.expanduser(path)):
78
            path = os.path.expanduser(path)
79
        else:
80
            print(f"\nError: {path} does not exist.")
81
            continue
82
83
        if encrypt:
84
            encrypted_journals[journal_name] = path
85
        elif os.path.isdir(path):
86
            other_journals[journal_name] = path
87
        else:
88
            plain_journals[journal_name] = path
89
90
    longest_journal_name = max([len(journal) for journal in config["journals"]])
91
    if encrypted_journals:
92
        print(
93
            f"\nFollowing encrypted journals will be upgraded to jrnl {__version__}:",
94
            file=sys.stderr,
95
        )
96
        for journal, path in encrypted_journals.items():
97
            print(
98
                "    {:{pad}} -> {}".format(journal, path, pad=longest_journal_name),
99
                file=sys.stderr,
100
            )
101
102
    if plain_journals:
103
        print(
104
            f"\nFollowing plain text journals will upgraded to jrnl {__version__}:",
105
            file=sys.stderr,
106
        )
107
        for journal, path in plain_journals.items():
108
            print(
109
                "    {:{pad}} -> {}".format(journal, path, pad=longest_journal_name),
110
                file=sys.stderr,
111
            )
112
113
    if other_journals:
114
        print("\nFollowing journals will be not be touched:", file=sys.stderr)
115
        for journal, path in other_journals.items():
116
            print(
117
                "    {:{pad}} -> {}".format(journal, path, pad=longest_journal_name),
118
                file=sys.stderr,
119
            )
120
121
    try:
122
        cont = yesno("\nContinue upgrading jrnl?", default=False)
123
        if not cont:
124
            raise KeyboardInterrupt
125
    except KeyboardInterrupt:
126
        raise UserAbort("jrnl NOT upgraded, exiting.")
127
128
    for journal_name, path in encrypted_journals.items():
129
        print(
130
            f"\nUpgrading encrypted '{journal_name}' journal stored in {path}...",
131
            file=sys.stderr,
132
        )
133
        backup(path, binary=True)
134
        old_journal = Journal.open_journal(
135
            journal_name, scope_config(config, journal_name), legacy=True
136
        )
137
        all_journals.append(EncryptedJournal.from_journal(old_journal))
138
139
    for journal_name, path in plain_journals.items():
140
        print(
141
            f"\nUpgrading plain text '{journal_name}' journal stored in {path}...",
142
            file=sys.stderr,
143
        )
144
        backup(path)
145
        old_journal = Journal.open_journal(
146
            journal_name, scope_config(config, journal_name), legacy=True
147
        )
148
        all_journals.append(Journal.PlainJournal.from_journal(old_journal))
149
150
    # loop through lists to validate
151
    failed_journals = [j for j in all_journals if not j.validate_parsing()]
152
153
    if len(failed_journals) > 0:
154
        print(
155
            "\nThe following journal{} failed to upgrade:\n{}".format(
156
                "s" if len(failed_journals) > 1 else "",
157
                "\n".join(j.name for j in failed_journals),
158
            ),
159
            file=sys.stderr,
160
        )
161
162
        raise UpgradeValidationException
163
164
    # write all journals - or - don't
165
    for j in all_journals:
166
        j.write()
167
168
    print("\nUpgrading config...", file=sys.stderr)
169
170
    backup(config_path)
171
172
    print("\nWe're all done here and you can start enjoying jrnl 2.", file=sys.stderr)
173
174
175
def is_old_version(config_path):
176
    return is_config_json(config_path)
177