]> kaliko git repositories - mpd-sima.git/blob - sima/utils/startopt.py
c3fb161a67aca583b5907057d974a1d09cf25530
[mpd-sima.git] / sima / utils / startopt.py
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2009-2015, 2022 kaliko <kaliko@azylum.org>
4 #
5 #  This file is part of sima
6 #
7 #  sima is free software: you can redistribute it and/or modify
8 #  it under the terms of the GNU General Public License as published by
9 #  the Free Software Foundation, either version 3 of the License, or
10 #  (at your option) any later version.
11 #
12 #  sima is distributed in the hope that it will be useful,
13 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #  GNU General Public License for more details.
16 #
17 #  You should have received a copy of the GNU General Public License
18 #  along with sima.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 #
21
22 from argparse import ArgumentParser, RawDescriptionHelpFormatter
23
24 from .utils import Wfile, Rfile, Wdir
25
26 DESCRIPTION = """
27 MPD_sima automagicaly queue new tracks in MPD playlist.
28
29 Command line options override their equivalent in configuration file.
30 If a positional arguments is provided MPD_sima execute the command and returns.
31 """
32
33
34 def clean_dict(to_clean):
35     """Remove items which values are set to None/False"""
36     for k in list(to_clean.keys()):
37         if not to_clean.get(k):
38             to_clean.pop(k)
39
40 # OPTIONS LIST
41 # pop out 'sw' value before creating Parser object.
42 # PAY ATTENTION:
43 #   If an option has to override its dual in conf file, the destination
44 #   identifier "dest" is to be named after that option in the conf file.
45 #   The supersedes_config_with_cmd_line_options method in ConfMan() (config.py)
46 #   is looking for command line option names identical to config file option
47 #   name it is meant to override.
48 OPTS = [
49     {
50         'sw': ['-l', '--log'],
51         'type': str,
52         'dest': 'logfile',
53         'action': Wfile,
54         'metavar': 'LOG',
55         'help': 'file to log message to, default is stdout/stderr'},
56     {
57         'sw': ['-v', '--log-level'],
58         'type': str,
59         'dest': 'verbosity',
60         'choices': ['debug', 'info', 'warning', 'error'],
61         'help': 'log messages verbosity, default is info'},
62     {
63         'sw': ['-p', '--pid'],
64         'dest': 'pidfile',
65         'action': Wfile,
66         'metavar': 'FILE',
67         'help': 'file to save PID to, default is not to store pid'},
68     {
69         'sw': ['-d', '--daemon'],
70         'dest': 'daemon',
71         'action': 'store_true',
72         'help': 'daemonize process'},
73     {
74         'sw': ['-S', '--host'],
75         'dest': 'host',
76         'help': 'host MPD in running on (IP or FQDN)'},
77     {
78         'sw': ['-P', '--port'],
79         'type': int,
80         'dest': 'port',
81         'help': 'port MPD in listening on'},
82     {
83         'sw': ['-c', '--config'],
84         'dest': 'conf_file',
85         'action': Rfile,
86         'metavar': 'CONFIG',
87         'help': 'configuration file to load'},
88     {
89         'sw': ['--var-dir', '--var_dir'],
90         'dest': 'var_dir',
91         'action': Wdir,
92         'help': 'directory to store var content (ie. database, cache)'},
93 ]
94 # Commands
95 CMDS = [
96         {'config-test': [{}], 'help': 'Test configuration (MPD connection and Tags plugin only)'},
97         {'create-db': [{}], 'help': 'Create the database'},
98         {'generate-config': [{}], 'help': 'Generate a configuration file to stdout'},
99         {'purge-history': [{}], 'help': 'Remove play history'},
100         {'bl-view': [{}], 'help': 'List blocklist IDs'},
101         {'bl-add-artist': [
102             {'name': 'artist', 'type': str, 'nargs': '?',
103              'help': 'If artist is provided use it else use currently playing value'}
104             ], 'help': 'Add artist to the blocklist'},
105         {'bl-add-album': [
106             {'name': 'album', 'type': str, 'nargs': '?',
107              'help': 'If album is provided use it else use currently playing value'}
108          ], 'help': 'Add album to the blocklist'},
109         {'bl-add-track': [
110             {'name': 'track', 'type': str, 'nargs': '?',
111              'help': 'If track is provided use it else use currently playing value'}
112          ], 'help': 'Add track to the blocklist'},
113         {'bl-delete': [
114             {'name': 'id', 'type': int, 'nargs': '?',
115              'help': 'blocklist ID to suppress (use bl-view to list IDs)'}
116          ], 'help': 'Remove entries from the blocklist'},
117         {'random': [
118             {'name': 'nbtracks', 'type': int, 'nargs': '?',
119              'help': 'Number of tracks to add'}
120          ], 'help': 'Start in random auto queuing'},
121 ]
122
123
124 class StartOpt:
125     """Command line management.
126     """
127
128     def __init__(self, script_info,):
129         self.parser = None
130         self.info = dict(script_info)
131         self.options = {}
132         self.main()
133
134     def declare_opts(self):
135         """
136         Declare options in ArgumentParser object.
137         """
138         self.parser = ArgumentParser(description=DESCRIPTION,
139                                      prog=self.info.get('prog'),
140                                      epilog='Happy Listening',
141                                      formatter_class=RawDescriptionHelpFormatter,
142                                      )
143         self.parser.add_argument('--version', action='version',
144                         version='%(prog)s {version}'.format(**self.info))
145         # Add all options declare in OPTS
146         for opt in OPTS:
147             opt_names = opt.pop('sw')
148             self.parser.add_argument(*opt_names, **opt)
149         # Add sub commands
150         spa = self.parser.add_subparsers(
151                 title=f'{self.info["prog"]} commands as positional arguments',
152                 description=f"""Use them after optionnal arguments.\n"{self.info["prog"]} command -h" for more info.""",
153                 metavar='', dest='command')
154         for cmd in CMDS:
155             helpmsg = cmd.pop('help')
156             cmd, args = cmd.popitem()
157             _ = spa.add_parser(cmd, description=helpmsg, help=helpmsg)
158             for arg in args:
159                 name = arg.pop('name', None)
160                 if name:
161                     _.add_argument(name, **arg)
162
163     def main(self):
164         """
165         Look for env. var and parse command line.
166         """
167         self.declare_opts()
168         options = vars(self.parser.parse_args())
169         # Set log file to os.devnull in daemon mode to avoid logging to
170         # std(out|err).
171         # TODO: Probably useless. To be checked
172         #if options.__dict__.get('daemon', False) and \
173         #        not options.__dict__.get('logfile', False):
174         #    options.__dict__['logfile'] = devnull
175         self.options.update(options)
176         clean_dict(self.options)
177
178
179 # VIM MODLINE
180 # vim: ai ts=4 sw=4 sts=4 expandtab