~ubuntu-branches/ubuntu/oneiric/command-not-found/oneiric

« back to all changes in this revision

Viewing changes to CommandNotFound/CommandNotFound.py

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt, Zygmunt Krynicki
  • Date: 2011-08-25 15:15:50 UTC
  • Revision ID: james.westby@ubuntu.com-20110825151550-m6gycva2g7fnn91m
Tags: 0.2.43ubuntu1
[ Zygmunt Krynicki ]
* lp:~zkrynicki/command-not-found/rework-locale-support:
  - improved gettext handling

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# (c) Zygmunt Krynicki 2005, 2006, 2007, 2008
2
2
# Licensed under GPL, see COPYING for the whole text
3
3
 
4
 
import sys, os, os.path, gdbm, posix, grp, string
5
 
from util import gettext_wrapper as _
6
 
 
7
 
class BinaryDatabase:
 
4
import gdbm
 
5
import gettext
 
6
import grp
 
7
import os
 
8
import os.path
 
9
import posix
 
10
import string
 
11
import sys
 
12
 
 
13
_ = gettext.translation("command-not-found", fallback=True).ugettext
 
14
 
 
15
 
 
16
class BinaryDatabase(object):
 
17
 
8
18
    def __init__(self, filename):
9
19
        self.db = None
10
20
        if filename.endswith(".db"):
11
21
            try:
12
22
                self.db = gdbm.open(filename, "r")
13
23
            except gdbm.error, err:
14
 
                print >>sys.stderr, "Unable to open binary database %s: %s" % (filename, err)
 
24
                print >> sys.stderr, "Unable to open binary database %s: %s" % (filename, err)
 
25
 
15
26
    def lookup(self, key):
16
27
        if self.db and self.db.has_key(key):
17
28
            return self.db[key]
18
29
        else:
19
30
            return None
20
31
 
21
 
class FlatDatabase:
 
32
 
 
33
class FlatDatabase(object):
 
34
 
22
35
    def __init__(self, filename):
23
36
        self.rows = []
24
37
        dbfile = file(filename)
25
38
        for line in (line.strip() for line in dbfile):
26
39
            self.rows.append(line.split("|"))
27
40
        dbfile.close()
 
41
 
28
42
    def lookup(self, column, text):
29
43
        result = []
30
44
        for row in self.rows:
31
45
            if row[column] == text:
32
46
                result.append(row)
33
47
        return result
 
48
 
34
49
    def createColumnByCallback(self, cb, column):
35
50
        for row in self.rows:
36
51
            row.append(cb(row[column]))
 
52
 
37
53
    def lookupWithCallback(self, column, cb, text):
38
54
        result = []
39
55
        for row in self.rows:
40
 
            if cb(row[column],text):
 
56
            if cb(row[column], text):
41
57
                result.append(row)
42
58
        return result
43
59
 
44
 
class ProgramDatabase:
 
60
 
 
61
class ProgramDatabase(object):
 
62
 
45
63
    (PACKAGE, BASENAME_PATH) = range(2)
 
64
 
46
65
    def __init__(self, filename):
47
66
        basename = os.path.basename(filename)
48
67
        (self.arch, self.component) = basename.split(".")[0].split("-")
49
68
        self.db = BinaryDatabase(filename)
 
69
 
50
70
    def lookup(self, command):
51
71
        result = self.db.lookup(command)
52
72
        if result:
54
74
        else:
55
75
            return []
56
76
 
 
77
 
57
78
def similar_words(word):
58
 
    """ return a set with spelling1 distance alternative spellings
 
79
    """
 
80
    return a set with spelling1 distance alternative spellings
59
81
 
60
 
        based on http://norvig.com/spell-correct.html"""
 
82
    based on http://norvig.com/spell-correct.html
 
83
    """
61
84
    alphabet = 'abcdefghijklmnopqrstuvwxyz-_0123456789'
62
85
    s = [(word[:i], word[i:]) for i in range(len(word) + 1)]
63
 
    deletes    = [a + b[1:] for a, b in s if b]
64
 
    transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b)>1]
65
 
    replaces   = [a + c + b[1:] for a, b in s for c in alphabet if b]
66
 
    inserts    = [a + c + b     for a, b in s for c in alphabet]
 
86
    deletes = [a + b[1:] for a, b in s if b]
 
87
    transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b) > 1]
 
88
    replaces = [a + c + b[1:] for a, b in s for c in alphabet if b]
 
89
    inserts = [a + c + b     for a, b in s for c in alphabet]
67
90
    return set(deletes + transposes + replaces + inserts)
68
91
 
69
 
class CommandNotFound:
 
92
 
 
93
class CommandNotFound(object):
 
94
 
70
95
    programs_dir = "programs.d"
71
 
    prefixes = ("/bin", 
72
 
                "/usr/bin", 
73
 
                "/usr/local/bin", 
74
 
                "/sbin", "/usr/sbin",
75
 
                "/usr/local/sbin", 
76
 
                "/usr/games")
77
 
    def __init__(self, data_dir=os.sep.join(
78
 
            ('/','usr','share','command-not-found'))):
 
96
 
 
97
    prefixes = (
 
98
        "/bin",
 
99
        "/usr/bin",
 
100
        "/usr/local/bin",
 
101
        "/sbin",
 
102
        "/usr/sbin",
 
103
        "/usr/local/sbin",
 
104
        "/usr/games")
 
105
 
 
106
    def __init__(self, data_dir="/usr/share/command-not-found"):
79
107
        self.programs = []
80
108
        self.priority_overrides = []
81
109
        p = os.path.join(data_dir, "priority.txt")
82
110
        if os.path.exists(p):
83
111
            self.priority_overrides = map(string.strip, open(p).readlines())
84
 
        self.components = ['main','universe','contrib','restricted','non-free',
85
 
                           'multiverse']
 
112
        self.components = ['main', 'universe', 'contrib', 'restricted',
 
113
                           'non-free', 'multiverse']
86
114
        self.components.reverse()
87
115
        self.sources_list = self._getSourcesList()
88
116
        for filename in os.listdir(os.path.sep.join([data_dir, self.programs_dir])):
102
130
            for (package, comp) in packages:
103
131
                possible_alternatives.append((w, package, comp))
104
132
        if len(possible_alternatives) > max_len:
105
 
            print >>sys.stderr, _("No command '%s' found, but there are %s similar ones") % (word, len(possible_alternatives))
 
133
            print >> sys.stderr, _("No command '%s' found, but there are %s similar ones") % (word, len(possible_alternatives))
106
134
        elif len(possible_alternatives) > 0:
107
 
            print >>sys.stderr, _("No command '%s' found, did you mean:") % word
 
135
            print >> sys.stderr, _("No command '%s' found, did you mean:") % word
108
136
            for (w, p, c) in possible_alternatives:
109
 
                print >>sys.stderr, _(" Command '%s' from package '%s' (%s)") % (w, p, c)
 
137
                print >> sys.stderr, _(" Command '%s' from package '%s' (%s)") % (w, p, c)
110
138
 
111
139
    def getPackages(self, command):
112
140
        result = set()
113
141
        for db in self.programs:
114
 
            result.update([(pkg,db.component) for pkg in db.lookup(command)])
 
142
            result.update([(pkg, db.component) for pkg in db.lookup(command)])
115
143
        return list(result)
 
144
 
116
145
    def getBlacklist(self):
117
146
        try:
118
147
            blacklist = file(os.sep.join((os.getenv("HOME", "/root"), ".command-not-found.blacklist")))
121
150
            return []
122
151
        else:
123
152
            blacklist.close()
 
153
 
124
154
    def _getSourcesList(self):
125
155
        try:
126
156
            import apt_pkg
127
157
            from aptsources.sourceslist import SourcesList
128
158
            apt_pkg.init()
129
 
        except (SystemError, ImportError), e:
 
159
        except (SystemError, ImportError):
130
160
            return []
131
161
        sources_list = set([])
132
162
        # The matcher parses info files from
133
163
        # /usr/share/python-apt/templates/
134
164
        # But we don't use the calculated data, skip it
135
165
        for source in SourcesList(withMatcher=False):
136
 
             if not source.disabled and not source.invalid:
137
 
                 for component in source.comps:
138
 
                     sources_list.add(component)
 
166
            if not source.disabled and not source.invalid:
 
167
                for component in source.comps:
 
168
                    sources_list.add(component)
139
169
        return sources_list
 
170
 
140
171
    def sortByComponent(self, x, y):
141
172
        # check overrides
142
173
        if (x[0] in self.priority_overrides and
156
187
            yidx = self.components.index(y[1])
157
188
        except:
158
189
            xidx = -1
159
 
        return (yidx-xidx) or cmp(x,y)
 
190
        return (yidx - xidx) or cmp(x, y)
 
191
 
160
192
    def advise(self, command, ignore_installed=False):
161
193
        " give advice where to find the given command to stderr "
162
194
        def _in_prefix(prefix, command):
163
195
            " helper that returns if a command is found in the given prefix "
164
 
            return (os.path.exists(os.path.join(prefix, command)) and 
165
 
                    not os.path.isdir(os.path.join(prefix, command)))
 
196
            return (os.path.exists(os.path.join(prefix, command))
 
197
                    and not os.path.isdir(os.path.join(prefix, command)))
166
198
 
167
199
        if command.startswith("/"):
168
200
            if os.path.exists(command):
175
207
        # check if we have it in a common prefix that may not be in the PATH
176
208
        if prefixes and not ignore_installed:
177
209
            if len(prefixes) == 1:
178
 
                print >>sys.stderr, _("Command '%(command)s' is available in '%(place)s'") % {"command": command, "place": os.path.join(prefixes[0], command)}
 
210
                print >> sys.stderr, _("Command '%(command)s' is available in '%(place)s'") % {"command": command, "place": os.path.join(prefixes[0], command)}
179
211
            else:
180
 
                print >>sys.stderr, _("Command '%(command)s' is available in the following places") % {"command": command}
 
212
                print >> sys.stderr, _("Command '%(command)s' is available in the following places") % {"command": command}
181
213
                for prefix in prefixes:
182
 
                    print >>sys.stderr, " * %s" % os.path.join(prefix, command)
 
214
                    print >> sys.stderr, " * %s" % os.path.join(prefix, command)
183
215
            missing = list(set(prefixes) - set(os.getenv("PATH", "").split(":")))
184
216
            if len(missing) > 0:
185
 
                print >>sys.stderr, _("The command could not be located because '%s' is not included in the PATH environment variable.") % ":".join(missing)
 
217
                print >> sys.stderr, _("The command could not be located because '%s' is not included in the PATH environment variable.") % ":".join(missing)
186
218
                if "sbin" in ":".join(missing):
187
 
                    print >>sys.stderr, _("This is most likely caused by the lack of administrative privileges associated with your user account.")
 
219
                    print >> sys.stderr, _("This is most likely caused by the lack of administrative privileges associated with your user account.")
188
220
            return False
189
221
 
190
222
        # do not give advice if we are in a situation where apt-get
199
231
        if len(packages) == 0:
200
232
            self.print_spelling_suggestion(command)
201
233
        elif len(packages) == 1:
202
 
            print >>sys.stderr, _("The program '%s' is currently not installed. ") % command,
 
234
            print >> sys.stderr, _("The program '%s' is currently not installed. ") % command,
203
235
            if posix.geteuid() == 0:
204
 
                print >>sys.stderr, _("You can install it by typing:")
205
 
                print >>sys.stderr, "apt-get install %s" %  packages[0][0]
 
236
                print >> sys.stderr, _("You can install it by typing:")
 
237
                print >> sys.stderr, "apt-get install %s" % packages[0][0]
206
238
            elif self.user_can_sudo:
207
 
                print >>sys.stderr, _("You can install it by typing:")
208
 
                print >>sys.stderr, "sudo apt-get install %s" %  packages[0][0]
 
239
                print >> sys.stderr, _("You can install it by typing:")
 
240
                print >> sys.stderr, "sudo apt-get install %s" % packages[0][0]
209
241
            else:
210
 
                print >>sys.stderr, _("To run '%(command)s' please ask your administrator to install the package '%(package)s'") % {'command': command, 'package': packages[0][0]}
 
242
                print >> sys.stderr, _("To run '%(command)s' please ask your administrator to install the package '%(package)s'") % {'command': command, 'package': packages[0][0]}
211
243
            if not packages[0][1] in self.sources_list:
212
 
                print >>sys.stderr, _("You will have to enable the component called '%s'") % packages[0][1]
 
244
                print >> sys.stderr, _("You will have to enable the component called '%s'") % packages[0][1]
213
245
        elif len(packages) > 1:
214
246
            packages.sort(self.sortByComponent)
215
 
            print >>sys.stderr, _("The program '%s' can be found in the following packages:") % command
 
247
            print >> sys.stderr, _("The program '%s' can be found in the following packages:") % command
216
248
            for package in packages:
217
249
                if package[1] in self.sources_list:
218
 
                    print >>sys.stderr, " * %s" % package[0]
 
250
                    print >> sys.stderr, " * %s" % package[0]
219
251
                else:
220
 
                    print >>sys.stderr, " * %s" % package[0] + " (" + _("You will have to enable component called '%s'") % package[1] + ")"
 
252
                    print >> sys.stderr, " * %s" % package[0] + " (" + _("You will have to enable component called '%s'") % package[1] + ")"
221
253
            if posix.geteuid() == 0:
222
 
                print >>sys.stderr, _("Try: %s <selected package>") % "apt-get install"
 
254
                print >> sys.stderr, _("Try: %s <selected package>") % "apt-get install"
223
255
            elif self.user_can_sudo:
224
 
                print >>sys.stderr, _("Try: %s <selected package>") % "sudo apt-get install"
 
256
                print >> sys.stderr, _("Try: %s <selected package>") % "sudo apt-get install"
225
257
            else:
226
 
                print >>sys.stderr, _("Ask your administrator to install one of them")
 
258
                print >> sys.stderr, _("Ask your administrator to install one of them")
227
259
        return len(packages) > 0