summaryrefslogtreecommitdiffstats
path: root/cnucnu/checkshell.py
blob: 84aa9ebfc542561f914be54dbe95b90ab6005df8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
#!/usr/bin/python
# vim: fileencoding=utf8 foldmethod=marker
# {{{ License header: GPLv2+
#    This file is part of cnucnu.
#
#    Cnucnu is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 2 of the License, or
#    (at your option) any later version.
#
#    Cnucnu is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with cnucnu.  If not, see <http://www.gnu.org/licenses/>.
# }}}

import cmd
import difflib
import getpass
import re
import readline
import sys
import thread

import simplemediawiki

from cnucnu.package_list import Package, PackageList, Repository
from cnucnu.bugzilla_reporter import BugzillaReporter
from cnucnu.helper import pprint
from cnucnu.scm import SCM
from cnucnu.errors import UpstreamVersionRetrievalError, PackageNotFoundError

try:
    import fedora_cert
except ImportError:
    pass


def diff(a, b):
    differ = difflib.Differ()
    diff_result = differ.compare(a.splitlines(True), b.splitlines(True))
    diff_lines = [l for l in diff_result if not l.startswith(" ")]
    return diff_lines


class WikiEditor(object):
    def __init__(self, config):

        try:
            mediawiki = config["package list"]["mediawiki"]
        except KeyError:
            raise NotImplementedError("Only mediawiki support available")

        base_url = mediawiki["base url"]
        api_url = base_url + "api.php"
        page = mediawiki["page"]

        self.logged_in = False
        self.mw = simplemediawiki.MediaWiki(api_url)
        self.page = page

    def _query(self, data):
        base_query = {'action': 'query', 'titles': self.page}
        base_query.update(data)
        return self.mw.call(base_query)['query']['pages'].popitem()[1]

    def update(self, name, data, callback, reason=""):
        if not self.logged_in:
            try:
                try:
                    fas_username = fedora_cert.read_user_cert()
                except (fedora_cert.fedora_cert_error):
                    raise NameError
            except NameError:
                fas_username = getpass.getuser("FAS username: ")

            self.mw.login(
                fas_username,
                getpass.getpass("Password for FAS user '{0}': ".format(
                    fas_username)))
            self.logged_in = True

        meta_data = self._query({'prop': 'info|revisions',
                                 'intoken': 'edit'})

        source = self._query(
            {'prop': 'revisions',
                'rvprop': 'content'})['revisions'][0]['*']

        starttimestamp = meta_data["starttimestamp"]
        edittoken = meta_data["edittoken"]

        pattern = r'\n \* {0} [^\n]*\n'.format(name)

        if data:
            repl = "\n * {0}\n".format(data)
            what = "Update"
        else:
            repl = "\n"
            what = "Remove"
        if reason:
            reason = " - {0}".format(reason)
        summary = "{0} {1}{2}".format(what, name, reason)

        new_text = re.sub(pattern, repl, source, count=1)
        diff_lines = diff(source, new_text)
        if diff_lines:
            print summary
            sys.stdout.writelines(diff_lines)
            response = raw_input("Apply? (Y/n)")

            if response in ("", "y", "Y"):
                def update_thread():
                    edit = self.mw.call({'action': 'edit',
                                        'title': self.page,
                                        'text': new_text,
                                        'summary': summary,
                                        'token': edittoken,
                                        'starttimestamp': starttimestamp})
                    callback(edit)
                thread.start_new_thread(update_thread, ())
            else:
                print "Not applied"


class CheckShell(cmd.Cmd):
    def __init__(self, config):
        cmd.Cmd.__init__(self)
        readline.set_completer_delims(' ')

        self.repo = Repository()
        self.package = Package("", None, None, self.repo)
        self._package_list = None
        self.prompt_default = " URL:"
        self.update_prompt()
        self.config = config
        self._br = None
        self.scm = SCM()
        self.we = WikiEditor(config=config.config)
        self.messages = []

    @property
    def package_list(self):
        if not self._package_list:
            self._package_list = PackageList(repo=self.repo)
            if self.package.name:
                self._package_list.append(self.package)
        return self._package_list

    @property
    def br(self):
        if not self._br:
            bugzilla_config = self.config.bugzilla_config
            try:
                self._br = BugzillaReporter(bugzilla_config)

            except Exception, e:
                print "Cannot query bugzilla, faulty/missing config?", repr(e),
                dict(e), str(e)
        return self._br

    def update_prompt(self):
        self.prompt = ""
        if "messages" in dir(self):
            while self.messages:
                message = self.messages.pop()
                self.prompt += "Message: {0}\n".format(message)
        self.prompt += "Name: {p.name}\n"\
                       "Final Regex: {p.regex}\n"\
                       "Final URL: {p.url}\n"\
                       "\x1b[1m{p.name} {p.raw_regex} {p.raw_url} ".format(
                           p=self.package)
        self.prompt += "%s>\x1b[0m " % self.prompt_default

    def default(self, line):
        if not self.package.url:
            self.do_url(line)
        else:
            self.do_regex(line)

    def do_EOF(self, args):
        self.emptyline()

    def do_fm(self, args):
        self.package.name = args
        self.package.regex = "FM-DEFAULT"
        self.package.url = "FM-DEFAULT"

    def do_html(self, args):
        print self.package.url
        print self.package.html

    def complete_inspect(self, text, line, begidx, endidx):
        package_names = [p.name for p in self.package_list if
                         p.name.startswith(text)]
        return package_names

    def do_inspect(self, args):
        try:
            self.package = self.package_list[args]
        except KeyError, ke:
            print ke

    def do_name(self, args):
        self.package = Package(args, self.package.regex, self.package.url,
                               self.repo)
        if not self.package.regex:
            self.package.regex = "DEFAULT"
        if not self.package.url:
            self.package.url = "SF-DEFAULT"

    def do_regex(self, args):
        self.package.regex = args

    def do_report(self, args):
        pprint(self.package.report_outdated(dry_run=False))

    def do_remove(self, args):
        self.do_update(args, entry="")

    def do_update(self, args, entry=None):
        if entry is None:
            entry = "{p.name} {p.raw_regex} {p.raw_url}".format(p=self.package)

        self.we.update(self.package.name, entry, self.messages.append,
                       reason=args)

    def do_url(self, args):
        self.package.url = args

    def emptyline(self):
        if self.package.url:
            self.package.url = None
        else:
            print
            sys.exit(0)

    def postcmd(self, stop, line):
        if not self.package.url:
            self.prompt_default = " URL:"
        else:
            self.prompt_default = " Regex:"

        self.update_prompt()
        if self.package.url and self.package.regex:
            try:
                print "Upstream Versions:", set(self.package.upstream_versions)
                print "Latest:", self.package.latest_upstream

                if self.package.name:
                    print "%(repo_name)s Version: %(repo_version)s"\
                        " %(repo_release)s %(status)s" % self.package

                    sourcefile = self.package.upstream_version_in_scm
                    if sourcefile:
                        print "Found in SCM:", sourcefile
                    else:
                        print "Not Found in SCM"
                    bug = self.package.exact_outdated_bug
                    if bug:
                        print "Exact Bug:", "%s %s:%s" % (self.br.bug_url(bug),
                                                          bug.bug_status,
                                                          bug.short_desc)
                    bug = self.package.open_outdated_bug
                    if bug:
                        print "Open Bug:", "%s %s:%s" % (self.br.bug_url(bug),
                                                         bug.bug_status,
                                                         bug.short_desc)
            except UpstreamVersionRetrievalError, uvre:
                print "\x1b[1mCannot retrieve upstream Version:\x1b[0m", uvre
            except PackageNotFoundError, e:
                print e
        return stop