1import sys
2import os
3import glob
4import re
5
6from Keywords import Keyword as Kw, Set as KwS
7from Prophet.Categories import *
8from Prophet import msg
9
10import Prophet
11
12
13class App(Prophet.App):
14
15    """A simple application that may have different executables"""
16    pref = 30
17
18    def __new__(cls):
19        try:
20            self = cls.__inst__
21            if not self:
22                raise Prophet.NotSet
23
24        except AttributeError:
25            self = cls.__inst__ = object.__new__(cls)
26            try:
27                self.__setup__()
28            except Prophet.NotSet:
29                cls.__inst__ = None
30                raise
31
32        return self
33
34    def setKeywords(self):
35        super(App, self).setKeywords()
36        self.keywords |= KwS(Legacy)
37
38    def setExename(self):
39        # Obtain known executable names for the application
40        try:
41            exes = self.exes
42        except AttributeError:
43            # If none were explicitly specified, use self class name
44            exes = [self.__class__.__name__]
45        prefixes = self.getPrefixes()
46        paths = self.getPaths()
47        valids = []
48        for x in exes:
49            for pfx, bps in prefixes.binpaths.items():
50                try:
51                    exe = bps.which(x)
52                    if self.valid(pfx, exe):
53                        valids.append((pfx, exe))
54
55                except Prophet.NotFound:
56                    pass
57
58        try:
59            self.prefix, self.exename = self.select(valids)
60        except Prophet.NotFound:
61            raise Prophet.NotSet
62
63    def valid(self, pfx, exe):
64        return True
65
66    def select(self, valids):
67        if len(valids):
68            return valids[0]
69        else:
70            raise Prophet.NotFound
71
72
73class ConsoleApp(Prophet.App):
74
75    """Mixin class for the console application that must be run in terminal"""
76
77    def setKeywords(self):
78        super(ConsoleApp, self).setKeywords()
79        self.keywords |= KwS(ConsoleOnly)
80
81
82class X11App(Prophet.App):
83
84    """Mixin class for the X11 GUI application"""
85
86
87class ZeroG(App):
88
89    """Application installed by the ZeroG LaunchAnywhere system.
90        This is usually a commercial Java application"""
91    registry = "~/.com.zerog.registry.xml"
92
93    def getPrefixes(self):
94        prefixes = super(ZeroG, self).getPrefixes()
95        try:
96            zerog = open(os.path.expanduser(self.registry), "r")
97            pattern = re.compile(
98                ".*<product.*name=\"(%s)\".*location=\"(.*)\".*last_modified=\"(.*)\".*>.*" %
99                self.magic)
100            found = []
101            for x in zerog:
102                rx = pattern.match(x)
103                if rx:
104                    found.append((rx.group(3), rx.group(1), rx.group(2)))
105
106            zerog.close()
107            found.sort()
108            found.reverse()
109            prefixes = Prophet.PrefixSet([x[2] for x in found]) + prefixes
110        except IOError:
111            pass
112        return prefixes
113
114
115class DropIn(App):
116
117    maxDepth = 3
118    dropRoots = ["~"]
119
120    class StopDescention(Exception):
121
122        def __init__(self, value):
123            self.value = value
124
125    def getPrefixes(self):
126        prefixes = super(DropIn, self).getPrefixes()
127        try:
128            for r in self.dropRoots:
129                self.descend(os.path.expanduser(r), 1)
130
131        except DropIn.StopDescention as e:
132            prefixes += e.value
133        return prefixes
134
135    def descend(self, path, depth):
136        self.relevant(path)
137        if depth > self.maxDepth:
138            return
139        try:
140            for x in os.listdir(path):
141                dir = os.path.join(path, x)
142                if not x.startswith(".") and os.path.isdir(dir):
143                    self.descend(dir, depth + 1)
144
145        except OSError:
146            pass
147
148
149__legacy__ = ["Development", "Editor", "Emulator",
150              "Multimedia", "Graphics", "Network", "Shell"]
151
152entries = []  # List of all legacy entries found
153
154
155def _register(module, this=True):
156    """Import and store the specified module along with all its submodules"""
157    try:
158        names = module.__legacy__
159    except AttributeError:
160        names = []
161    if this:
162        for k, v in module.__dict__.items():
163            if not k.startswith("_") and isinstance(
164                    v,
165                    type) and issubclass(
166                    v,
167                    Prophet.App):
168                entries.append(v)
169
170    for x in names:
171        name = module.__name__ + "." + x
172        try:
173            __import__(name)
174        except ImportError:
175            raise ImportError("No module named " + name)
176        imp = sys.modules[name]
177        _register(imp)
178
179
180def setup():
181    _register(sys.modules[__name__], this=False)
182
183
184def scan():
185    result = []
186    msg("  legacy...", newline=False)
187    for x in entries:
188        try:
189            result.append(x())
190        except Prophet.NotSet:
191            pass
192
193    msg(" %d apps found" % len(result))
194    return result
195