]>
git.ipfire.org Git - people/stevee/pakfire.git/blob - python/pakfire/system.py
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 from __future__
import division
24 import multiprocessing
34 Class that grants access to several information about
35 the system this software is running on.
39 hn
= socket
.gethostname()
41 # If a host has got no domain part, we add one.
43 hn
= "%s.localdomain" % hn
49 if not hasattr(self
, "_distro"):
50 self
._distro
= distro
.Distribution()
55 def native_arch(self
):
57 Return the native architecture of the host we
65 Return the architecture of the host we are running on.
67 if self
.supported_arches
and not self
.native_arch
in self
.supported_arches
:
68 return self
.supported_arches
[0]
70 return self
.native_arch
73 def supported_arches(self
):
75 Check what architectures can be built on this host.
78 # Host arch : Can build these arches.
81 "x86_64" : ["x86_64", "i686",],
85 "armv5tel" : ["armv5tel",],
86 "armv5tejl" : ["armv5tel",],
87 "armv6l" : ["armv5tel",],
88 "armv7l" : ["armv7hl", "armv5tel",],
89 "armv7hl" : ["armv7hl", "armv5tel",],
93 return host_can_build
[self
.native_arch
]
97 def host_supports_arch(self
, arch
):
99 Check if this host can build for the target architecture "arch".
101 return arch
in self
.supported_arches
106 Count the number of CPU cores.
108 return multiprocessing
.cpu_count()
110 def parse_cpuinfo(self
):
113 with
open("/proc/cpuinfo") as f
:
114 for line
in f
.readlines():
116 # Split the lines by colons.
117 a
, b
= line
.split(":")
131 cpuinfo
= self
.parse_cpuinfo()
133 ret
= cpuinfo
.get("model name", None)
135 # Some ARM platforms do not provide "model name", so we
139 ret
= "%(Hardware)s - %(Processor)s" % cpuinfo
143 # Remove too many spaces.
145 ret
= " ".join(ret
.split())
147 return ret
or _("Could not be determined")
150 def cpu_bogomips(self
):
151 cpuinfo
= self
.parse_cpuinfo()
153 for key
in ("bogomips", "BogoMIPS"):
154 bogomips
= cpuinfo
.get(key
, None)
159 return float(bogomips
) * self
.cpu_count
161 def get_loadavg(self
):
162 return os
.getloadavg()
166 return self
.get_loadavg()[0]
170 return self
.get_loadavg()[1]
174 return self
.get_loadavg()[2]
176 def has_overload(self
):
178 Checks, if the load average is not too high.
180 On this is to be decided if a new job is taken.
182 # If there are more than 2 processes in the process queue per CPU
183 # core we will assume that the system has heavy load and to not request
185 return self
.loadavg5
>= self
.cpu_count
* 2
187 def parse_meminfo(self
):
190 with
open("/proc/meminfo") as f
:
191 for line
in f
.readlines():
193 a
, b
, c
= line
.split()
196 a
= a
.replace(":", "")
206 def memory_total(self
):
207 meminfo
= self
.parse_meminfo()
209 return meminfo
.get("MemTotal", None)
212 memory
= memory_total
215 def memory_free(self
):
216 meminfo
= self
.parse_meminfo()
218 free
= meminfo
.get("MemFree", None)
220 buffers
= meminfo
.get("Buffers")
221 cached
= meminfo
.get("Cached")
223 return free
+ buffers
+ cached
226 def swap_total(self
):
227 meminfo
= self
.parse_meminfo()
229 return meminfo
.get("SwapTotal", None)
233 meminfo
= self
.parse_meminfo()
235 return meminfo
.get("SwapFree", None)
237 def get_mountpoint(self
, path
):
238 return Mountpoint(path
)
241 def parallelism(self
):
243 Calculates how many processes should be run
244 simulatneously when compiling.
246 # Check how many processes would fit into the
247 # memory when each process takes up to 128MB.
248 multiplicator
= self
.memory
/ (128 * 1024 * 1024)
249 multiplicator
= round(multiplicator
)
251 # Count the number of online CPU cores.
252 cpucount
= os
.sysconf("SC_NPROCESSORS_CONF") * 2
255 return min(multiplicator
, cpucount
)
258 # Create an instance of this class to only keep it once in memory.
261 class Mountpoints(object):
262 def __init__(self
, root
="/"):
263 self
._mountpoints
= []
265 # Scan for all mountpoints on the system.
269 return iter(self
._mountpoints
)
271 def _scan(self
, root
):
272 # Get the real path of root.
273 root
= os
.path
.realpath(root
)
275 # If root is not equal to /, we are in a chroot and
276 # our root must be a mountpoint to count files.
278 mp
= Mountpoint("/", root
=root
)
279 self
._mountpoints
.append(mp
)
281 f
= open("/proc/mounts")
283 for line
in f
.readlines():
286 # The mountpoint is the second argument.
289 # Skip all mountpoints that are not in our root directory.
290 if not mountpoint
.startswith(root
):
293 mountpoint
= os
.path
.relpath(mountpoint
, root
)
294 if mountpoint
== ".":
297 mountpoint
= os
.path
.join("/", mountpoint
)
299 mp
= Mountpoint(mountpoint
, root
=root
)
301 if not mp
in self
._mountpoints
:
302 self
._mountpoints
.append(mp
)
306 # Sort all mountpoints for better searching.
307 self
._mountpoints
.sort()
309 def add_pkg(self
, pkg
):
310 for file in pkg
.filelist
:
313 def rem_pkg(self
, pkg
):
314 for file in pkg
.filelist
:
318 for mp
in reversed(self
._mountpoints
):
319 # Check if the file is located on this mountpoint.
320 if not file.name
.startswith(mp
.path
):
323 # Add file to this mountpoint.
328 for mp
in reversed(self
._mountpoints
):
329 # Check if the file is located on this mountpoint.
330 if not file.name
.startswith(mp
.path
):
333 # Remove file from this mountpoint.
338 class Mountpoint(object):
339 def __init__(self
, path
, root
="/"):
343 # Cache the statvfs call of the mountpoint.
346 # Save the amount of data that is used or freed.
349 def __cmp__(self
, other
):
350 return cmp(self
.fullpath
, other
.fullpath
)
355 while path
.startswith("/"):
358 return os
.path
.join(self
.root
, path
)
362 if self
.__stat
is None:
363 # Find the next mountpoint, because we cannot
364 # statvfs any path in the FS.
365 path
= os
.path
.realpath(self
.fullpath
)
367 # Walk to root until we find a mountpoint.
368 while not os
.path
.ismount(path
):
369 path
= os
.path
.dirname(path
)
371 # See what we can get.
372 self
.__stat
= os
.statvfs(path
)
378 return self
.stat
.f_bavail
* self
.stat
.f_bsize
381 def space_needed(self
):
382 if self
.disk_usage
> 0:
383 return self
.disk_usage
388 def space_left(self
):
389 return self
.free
- self
.space_needed
392 assert file.name
.startswith(self
.path
)
394 # Round filesize to 4k blocks.
397 blocks
= file.size
// block_size
398 if file.size
% block_size
:
401 self
.disk_usage
+= blocks
* block_size
404 assert file.name
.startswith(self
.path
)
406 self
.disk_usage
-= file.size
409 if __name__
== "__main__":
410 print "Hostname", system
.hostname
411 print "Arch", system
.arch
412 print "Supported arches", system
.supported_arches
414 print "CPU Model", system
.cpu_model
415 print "CPU count", system
.cpu_count
416 print "Memory", system
.memory