Passed
Push — master ( ba6342...71f198 )
by P.R.
07:12
created

backuppc_clone.command.BaseCommand   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 118
Duplicated Lines 85.59 %

Importance

Changes 0
Metric Value
eloc 53
dl 101
loc 118
rs 10
c 0
b 0
f 0
wmc 13

7 Methods

Rating   Name   Duplication   Size   Complexity  
A BaseCommand.handle() 16 16 2
A BaseCommand.__init__() 8 8 1
A BaseCommand.__validate_user() 8 8 2
A BaseCommand._handle_command() 8 8 1
A BaseCommand._init_singletons() 6 6 1
A BaseCommand.ask() 17 17 3
A BaseCommand.__validate_config() 18 18 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
"""
2
BackupPC Clone
3
"""
4
import abc
5
import configparser
6
import os
7
from typing import Optional
8
9
from cleo import Command
10
11
from backuppc_clone.Config import Config
12
from backuppc_clone.DataLayer import DataLayer
13
from backuppc_clone.exception.BackupPcCloneException import BackupPcCloneException
14
from backuppc_clone.style.BackupPcCloneStyle import BackupPcCloneStyle
15
16
17 View Code Duplication
class BaseCommand(Command, metaclass=abc.ABCMeta):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
18
    """
19
    Abstract parent command for (almost) all BackupPC Clone commands.
20
    """
21
22
    # ------------------------------------------------------------------------------------------------------------------
23
    def __init__(self, name: Optional[str] = None) -> None:
24
        """
25
        Object constructor.
26
        """
27
        Command.__init__(self, name)
28
29
        self._io: Optional[BackupPcCloneStyle] = None
30
        """
31
        The output style.
32
        """
33
34
    # ------------------------------------------------------------------------------------------------------------------
35
    def __validate_user(self) -> None:
36
        """
37
        Validates that this command is not run under root.
38
        """
39
        self._io.log_very_verbose('testing user')
40
41
        if os.getuid() == 0:
42
            raise BackupPcCloneException('Will not run this command under root')
43
44
    # ------------------------------------------------------------------------------------------------------------------
45
    def __validate_config(self) -> None:
46
        """
47
        Validates the configuration files.
48
        """
49
        if self.input.has_argument('clone.cfg'):
50
            self._io.log_very_verbose('validation configuration')
51
52
            config_filename_clone = self.input.get_argument('clone.cfg')
53
            config_clone = configparser.ConfigParser()
54
            config_clone.read(config_filename_clone)
55
56
            config_original = configparser.ConfigParser()
57
            config_original.read(config_clone['Original']['config'])
58
59
            if config_clone['Original']['name'] != config_original['BackupPC Clone']['name']:
60
                raise BackupPcCloneException(
61
                        'Clone {} is not a clone of original {}'.format(config_clone['Original']['name'],
62
                                                                        config_original['BackupPC Clone']['name']))
63
64
    # ------------------------------------------------------------------------------------------------------------------
65
    def ask(self, question: str, default: Optional[str] = None) -> Optional[str]:
66
        """
67
        Prompt the user for input.
68
69
        :param str question: The question to ask
70
        :param str|None default: The default value
71
72
        :rtype: str|None
73
        """
74
        if default is not None:
75
            question = question + ' [' + default + ']'
76
77
        answer = self._io.ask(question, default)
78
        if answer is None:
79
            answer = default
80
81
        return answer
82
83
    # ------------------------------------------------------------------------------------------------------------------
84
    def _init_singletons(self) -> None:
85
        """
86
        Initializes the singleton objects.
87
        """
88
        Config(self.argument('clone.cfg'))
89
        DataLayer(os.path.join(Config.instance.top_dir_clone, 'clone.db'))
90
91
    # ------------------------------------------------------------------------------------------------------------------
92
    @abc.abstractmethod
93
    def _handle_command(self) -> int:
94
        """
95
        Executes the command.
96
97
        :rtype: int
98
        """
99
        raise NotImplementedError()
100
101
    # ------------------------------------------------------------------------------------------------------------------
102
    def handle(self) -> int:
103
        """
104
        Executes the command.
105
        """
106
        try:
107
            self._io = BackupPcCloneStyle(self.input, self.output)
108
109
            self.__validate_user()
110
            self.__validate_config()
111
            self._init_singletons()
112
113
            return self._handle_command()
114
115
        except BackupPcCloneException as error:
116
            self._io.error(str(error))
117
            return -1
118
119
# ----------------------------------------------------------------------------------------------------------------------
120