3 from namespaces
import *
6 from logging
import debug
, info
9 #from logging import getLogger, DEBUG
10 #getLogger().setLevel(DEBUG)
12 _interfaces
= {} # URI -> Interface
15 __slots__
= ['root', 'implementation', 'watchers',
16 'help_with_testing', 'network_use', 'updates']
18 def __init__(self
, root
):
19 assert isinstance(root
, (str, unicode))
21 self
.implementation
= {} # Interface -> Implementation
23 self
.help_with_testing
= False
24 self
.network_use
= network_full
27 path
= basedir
.load_first_config(config_site
, config_prog
, 'global')
29 config
= ConfigParser
.ConfigParser()
31 self
.help_with_testing
= config
.getboolean('global',
33 self
.network_use
= config
.get('global', 'network_use')
34 assert self
.network_use
in network_levels
36 def save_config(self
):
37 config
= ConfigParser
.ConfigParser()
38 config
.add_section('global')
40 config
.set('global', 'help_with_testing', self
.help_with_testing
)
41 config
.set('global', 'network_use', self
.network_use
)
43 path
= basedir
.save_config_path(config_site
, config_prog
)
44 path
= os
.path
.join(path
, 'global')
45 config
.write(file(path
+ '.new', 'w'))
46 os
.rename(path
+ '.new', path
)
48 def recalculate(self
):
49 self
.implementation
= {}
52 impl
= self
.get_best_implementation(iface
)
54 self
.implementation
[iface
] = impl
55 for d
in impl
.dependencies
.values():
56 process(self
.get_interface(d
.interface
))
57 process(self
.get_interface(self
.root
))
58 for w
in self
.watchers
: w()
60 def get_best_implementation(self
, iface
):
61 if not iface
.implementations
:
63 impls
= iface
.implementations
.values()
66 if self
.compare(iface
, x
, best
) < 0:
68 if self
.is_unusable(best
):
72 def compare(self
, interface
, b
, a
):
73 a_stab
= a
.get_stability()
74 b_stab
= b
.get_stability()
76 # Usable ones come first
77 r
= cmp(self
.is_unusable(b
), self
.is_unusable(a
))
80 # Preferred versions come first
81 r
= cmp(a_stab
== preferred
, b_stab
== preferred
)
84 if self
.network_use
!= network_full
:
85 r
= cmp(a
.get_cached(), b
.get_cached())
89 stab_policy
= interface
.stability_policy
91 if self
.help_with_testing
: stab_policy
= testing
92 else: stab_policy
= stable
94 if a_stab
>= stab_policy
: a_stab
= preferred
95 if b_stab
>= stab_policy
: b_stab
= preferred
97 r
= cmp(a_stab
, b_stab
)
100 r
= cmp(a
.version
, b
.version
)
103 if self
.network_use
!= network_full
:
104 r
= cmp(a
.get_cached(), b
.get_cached())
107 return cmp(a
.path
, b
.path
)
109 def get_ranked_implementations(self
, iface
):
110 impls
= iface
.implementations
.values()
111 impls
.sort(lambda a
, b
: self
.compare(iface
, a
, b
))
114 def is_unusable(self
, impl
):
115 if impl
.get_stability() <= buggy
:
117 if self
.network_use
== network_offline
and not impl
.get_cached():
121 def get_interface(self
, uri
):
122 """Get the interface for uri. If it's in the cache, read that.
123 If it's not in the cache or network use is full, start downloading
124 the latest version."""
127 assert isinstance(uri
, unicode)
129 if uri
not in _interfaces
:
130 # Haven't used this interface so far. Initialise from cache.
131 _interfaces
[uri
] = Interface(uri
)
132 self
.init_interface(_interfaces
[uri
])
134 if self
.network_use
== network_full
and not _interfaces
[uri
].uptodate
:
135 self
.begin_iface_download(_interfaces
[uri
])
137 return _interfaces
[uri
]
139 def init_interface(self
, iface
):
140 """We've just created a new Interface. Update from disk cache/network."""
141 debug("Created " + iface
.uri
)
142 cached
= reader
.update_from_cache(iface
)
144 if self
.network_use
!= network_offline
:
145 debug("Interface not cached and not off-line. Downloading...")
146 self
.begin_iface_download(iface
)
148 debug("Nothing known about interface, but we are off-line.")
150 def begin_iface_download(self
, interface
, force
= False):
151 dl
= download
.begin_download(interface
, force
)
154 return # Already in progress
156 # Calls update_interface_from_network eventually on success
157 self
.monitor_download(dl
)
159 def monitor_download(self
, dl
):
160 raise NotImplementedError("Abstract method")
162 def update_interface_from_network(self
, interface
, stream
):
163 """stream is the new XML (after the signature has been checked and
165 debug("Updating '%s' from network" % (interface
.name
or interface
.uri
))
166 assert interface
.uri
.startswith('/')
168 upstream_dir
= basedir
.save_config_path(config_site
, config_prog
, 'interfaces')
169 cached
= os
.path
.join(upstream_dir
, escape(interface
.uri
))
171 new_xml
= stream
.read()
173 if os
.path
.exists(cached
):
174 old_xml
= file(cached
).read()
175 if old_xml
== new_xml
:
178 self
.confirm_diff(old_xml
, new_xml
, interface
.uri
)
180 stream
= file(cached
+ '.new', 'w')
181 stream
.write(new_xml
)
183 reader
.update(interface
, cached
+ '.new')
184 os
.rename(cached
+ '.new', cached
)
185 debug("Saved as " + cached
)
187 interface
.uptodate
= True
189 reader
.update_user_overrides(interface
)
192 def get_implementation(self
, interface
):
193 if not interface
.name
:
194 raise SafeException("We don't have enough information to "
195 "run this program yet. "
196 "Need to download:\n%s" % interface
.uri
)
198 return self
.implementation
[interface
]
200 if interface
.implementations
:
202 if self
.network_use
== network_offline
:
203 offline
= "\nThis may be because 'Network Use' is set to Off-line."
204 raise SafeException("No usable implementation found for '%s'.%s" %
205 (interface
.name
, offline
))
208 def walk_interfaces(self
):
211 impl
= self
.get_best_implementation(iface
)
213 for d
in impl
.dependencies
.values():
214 for idep
in walk(self
.get_interface(d
.interface
)):
216 return walk(self
.get_interface(self
.root
))
218 def check_signed_data(self
, download
, signed_data
):
219 """Downloaded data is a GPG-signed message. Check that the signature is trusted
220 and call self.update_interface_from_network() when done."""
222 data
= gpg
.check_stream(signed_data
)
223 self
.update_interface_from_network(download
.interface
, data
)
225 def confirm_diff(self
, old
, new
, uri
):
227 diff
= difflib
.unified_diff(old
.split('\n'), new
.split('\n'), uri
, "",