CHANGELOG: Document this branch's atomic saves
[rss2email.git] / rss2email / main.py
1 # Copyright (C) 2012-2013 W. Trevor King <wking@tremily.us>
2 #
3 # This file is part of rss2email.
4 #
5 # rss2email is free software: you can redistribute it and/or modify it under
6 # the terms of the GNU General Public License as published by the Free Software
7 # Foundation, either version 2 of the License, or (at your option) version 3 of
8 # the License.
9 #
10 # rss2email is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License along with
15 # rss2email.  If not, see <http://www.gnu.org/licenses/>.
16
17 """Define the rss2email command line interface
18 """
19
20 import argparse as _argparse
21 import logging as _logging
22 import sys as _sys
23
24 from . import __doc__ as _PACKAGE_DOCSTRING
25 from . import __version__
26 from . import LOG as _LOG
27 from . import command as _command
28 from . import error as _error
29 from . import feeds as _feeds
30 from . import version as _version
31
32
33 class FullVersionAction (_argparse.Action):
34     def __call__(self, *args, **kwargs):
35         for package,version in _version.get_versions():
36             print('{} {}'.format(package, version))
37         _sys.exit(0)
38
39
40 def run(*args, **kwargs):
41     """The rss2email command line interface
42
43     Arguments passed to this function are forwarded to the parser's
44     `.parse_args()` call without modification.
45     """
46     parser = _argparse.ArgumentParser(
47         prog='rss2email', description=_PACKAGE_DOCSTRING)
48
49     parser.add_argument(
50         '-v', '--version', action='version',
51         version='%(prog)s {}'.format(__version__))
52     parser.add_argument(
53         '--full-version', action=FullVersionAction, nargs=0,
54         help='print the version information of all related packages and exit')
55     parser.add_argument(
56         '-c', '--config', metavar='PATH', default=[], action='append',
57         help='path to the configuration file')
58     parser.add_argument(
59         '-d', '--data', metavar='PATH',
60         help='path to the feed data file')
61     parser.add_argument(
62         '-V', '--verbose', default=0, action='count',
63         help='increment verbosity')
64     subparsers = parser.add_subparsers(title='commands')
65
66     new_parser = subparsers.add_parser(
67         'new', help=_command.new.__doc__.splitlines()[0])
68     new_parser.set_defaults(func=_command.new)
69     new_parser.add_argument(
70         'email', nargs='?',
71         help='default target email for the new feed database')
72
73     email_parser = subparsers.add_parser(
74         'email', help=_command.email.__doc__.splitlines()[0])
75     email_parser.set_defaults(func=_command.email)
76     email_parser.add_argument(
77         'email', default='',
78         help='default target email for the email feed database')
79
80     add_parser = subparsers.add_parser(
81         'add', help=_command.add.__doc__.splitlines()[0])
82     add_parser.set_defaults(func=_command.add)
83     add_parser.add_argument(
84         'name', help='name of the new feed')
85     add_parser.add_argument(
86         'url', help='location of the new feed')
87     add_parser.add_argument(
88         'email', nargs='?',
89         help='target email for the new feed')
90
91     run_parser = subparsers.add_parser(
92         'run', help=_command.run.__doc__.splitlines()[0])
93     run_parser.set_defaults(func=_command.run)
94     run_parser.add_argument(
95         '-n', '--no-send', dest='send',
96         default=True, action='store_const', const=False,
97         help="fetch feeds, but don't send email")
98     run_parser.add_argument(
99         'index', nargs='*',
100         help='feeds to fetch (defaults to fetching all feeds)')
101
102     list_parser = subparsers.add_parser(
103         'list', help=_command.list.__doc__.splitlines()[0])
104     list_parser.set_defaults(func=_command.list)
105
106     pause_parser = subparsers.add_parser(
107         'pause', help=_command.pause.__doc__.splitlines()[0])
108     pause_parser.set_defaults(func=_command.pause)
109     pause_parser.add_argument(
110         'index', nargs='*',
111         help='feeds to pause (defaults to pausing all feeds)')
112
113     unpause_parser = subparsers.add_parser(
114         'unpause', help=_command.unpause.__doc__.splitlines()[0])
115     unpause_parser.set_defaults(func=_command.unpause)
116     unpause_parser.add_argument(
117         'index', nargs='*',
118         help='feeds to ununpause (defaults to unpausing all feeds)')
119
120     delete_parser = subparsers.add_parser(
121         'delete', help=_command.delete.__doc__.splitlines()[0])
122     delete_parser.set_defaults(func=_command.delete)
123     delete_parser.add_argument(
124         'index', nargs='+',
125         help='feeds to delete')
126
127     reset_parser = subparsers.add_parser(
128         'reset', help=_command.reset.__doc__.splitlines()[0])
129     reset_parser.set_defaults(func=_command.reset)
130     reset_parser.add_argument(
131         'index', nargs='*',
132         help='feeds to reset (defaults to resetting all feeds)')
133
134     opmlimport_parser = subparsers.add_parser(
135         'opmlimport', help=_command.opmlimport.__doc__.splitlines()[0])
136     opmlimport_parser.set_defaults(func=_command.opmlimport)
137     opmlimport_parser.add_argument(
138         'file', metavar='PATH', nargs='?',
139         help='path for imported OPML (defaults to stdin)')
140
141     opmlexport_parser = subparsers.add_parser(
142         'opmlexport', help=_command.opmlexport.__doc__.splitlines()[0])
143     opmlexport_parser.set_defaults(func=_command.opmlexport)
144     opmlexport_parser.add_argument(
145         'file', metavar='PATH', nargs='?',
146         help='path for exported OPML (defaults to stdout)')
147
148     args = parser.parse_args(*args, **kwargs)
149
150     if args.verbose:
151         _LOG.setLevel(max(_logging.DEBUG, _logging.ERROR - 10 * args.verbose))
152
153     if not getattr(args, 'func', None):
154         parser.error('too few arguments')
155
156     try:
157         if not args.config:
158             args.config = None
159         feeds = _feeds.Feeds(datafile=args.data, configfiles=args.config)
160         if args.func != _command.new:
161             lock = args.func not in [_command.list, _command.opmlexport]
162             feeds.load(lock=lock)
163         args.func(feeds=feeds, args=args)
164     except _error.RSS2EmailError as e:
165         e.log()
166         if _logging.ERROR - 10 * args.verbose < _logging.DEBUG:
167             raise  # don't mask the traceback
168         _sys.exit(1)
169
170
171 if __name__ == '__main__':
172     run()