]>
git.ipfire.org Git - 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()
134 if self
.arch
.startswith("arm"):
136 ret
= "%(Hardware)s - %(Processor)s" % cpuinfo
140 ret
= cpuinfo
.get("model name", None)
142 # Remove too many spaces.
143 ret
= " ".join(ret
.split())
145 return ret
or _("Could not be determined")
148 def cpu_bogomips(self
):
149 cpuinfo
= self
.parse_cpuinfo()
151 for key
in ("bogomips", "BogoMIPS"):
152 bogomips
= cpuinfo
.get(key
, None)
157 return float(bogomips
) * self
.cpu_count
159 def get_loadavg(self
):
160 return os
.getloadavg()
164 return self
.get_loadavg()[0]
168 return self
.get_loadavg()[1]
172 return self
.get_loadavg()[2]
174 def has_overload(self
):
176 Checks, if the load average is not too high.
178 On this is to be decided if a new job is taken.
180 # If there are more than 2 processes in the process queue per CPU
181 # core we will assume that the system has heavy load and to not request
183 return self
.loadavg5
>= self
.cpu_count
* 2
185 def parse_meminfo(self
):
188 with
open("/proc/meminfo") as f
:
189 for line
in f
.readlines():
191 a
, b
, c
= line
.split()
194 a
= a
.replace(":", "")
204 def memory_total(self
):
205 meminfo
= self
.parse_meminfo()
207 return meminfo
.get("MemTotal", None)
210 memory
= memory_total
213 def memory_free(self
):
214 meminfo
= self
.parse_meminfo()
216 return meminfo
.get("MemFree", None)
219 def swap_total(self
):
220 meminfo
= self
.parse_meminfo()
222 return meminfo
.get("SwapTotal", None)
226 meminfo
= self
.parse_meminfo()
228 return meminfo
.get("SwapFree", None)
230 def get_mountpoint(self
, path
):
231 return Mountpoint(path
)
234 def parallelism(self
):
236 Calculates how many processes should be run
237 simulatneously when compiling.
239 # Check how many processes would fit into the
240 # memory when each process takes up to 128MB.
241 multiplicator
= self
.memory
/ (128 * 1024 * 1024)
242 multiplicator
= round(multiplicator
)
244 # Count the number of online CPU cores.
245 cpucount
= os
.sysconf("SC_NPROCESSORS_CONF") * 2
248 return min(multiplicator
, cpucount
)
251 # Create an instance of this class to only keep it once in memory.
254 class Mountpoints(object):
255 def __init__(self
, root
="/"):
256 self
._mountpoints
= []
258 # Scan for all mountpoints on the system.
262 return iter(self
._mountpoints
)
264 def _scan(self
, root
):
265 # Get the real path of root.
266 root
= os
.path
.realpath(root
)
268 # If root is not equal to /, we are in a chroot and
269 # our root must be a mountpoint to count files.
271 mp
= Mountpoint("/", root
=root
)
272 self
._mountpoints
.append(mp
)
274 f
= open("/proc/mounts")
276 for line
in f
.readlines():
279 # The mountpoint is the second argument.
282 # Skip all mountpoints that are not in our root directory.
283 if not mountpoint
.startswith(root
):
286 mountpoint
= os
.path
.relpath(mountpoint
, root
)
287 if mountpoint
== ".":
290 mountpoint
= os
.path
.join("/", mountpoint
)
292 mp
= Mountpoint(mountpoint
, root
=root
)
294 if not mp
in self
._mountpoints
:
295 self
._mountpoints
.append(mp
)
299 # Sort all mountpoints for better searching.
300 self
._mountpoints
.sort()
302 def add_pkg(self
, pkg
):
303 for file in pkg
.filelist
:
306 def rem_pkg(self
, pkg
):
307 for file in pkg
.filelist
:
311 for mp
in reversed(self
._mountpoints
):
312 # Check if the file is located on this mountpoint.
313 if not file.name
.startswith(mp
.path
):
316 # Add file to this mountpoint.
321 for mp
in reversed(self
._mountpoints
):
322 # Check if the file is located on this mountpoint.
323 if not file.name
.startswith(mp
.path
):
326 # Remove file from this mountpoint.
331 class Mountpoint(object):
332 def __init__(self
, path
, root
="/"):
336 # Cache the statvfs call of the mountpoint.
339 # Save the amount of data that is used or freed.
342 def __cmp__(self
, other
):
343 return cmp(self
.fullpath
, other
.fullpath
)
348 while path
.startswith("/"):
351 return os
.path
.join(self
.root
, path
)
355 if self
.__stat
is None:
356 # Find the next mountpoint, because we cannot
357 # statvfs any path in the FS.
358 path
= os
.path
.realpath(self
.fullpath
)
360 # Walk to root until we find a mountpoint.
361 while not os
.path
.ismount(path
):
362 path
= os
.path
.dirname(path
)
364 # See what we can get.
365 self
.__stat
= os
.statvfs(path
)
371 return self
.stat
.f_bavail
* self
.stat
.f_bsize
374 def space_needed(self
):
375 if self
.disk_usage
> 0:
376 return self
.disk_usage
381 def space_left(self
):
382 return self
.free
- self
.space_needed
385 assert file.name
.startswith(self
.path
)
387 # Round filesize to 4k blocks.
390 blocks
= file.size
// block_size
391 if file.size
% block_size
:
394 self
.disk_usage
+= blocks
* block_size
397 assert file.name
.startswith(self
.path
)
399 self
.disk_usage
+= file.size
402 if __name__
== "__main__":
403 print "Hostname", system
.hostname
404 print "Arch", system
.arch
405 print "Supported arches", system
.supported_arches
407 print "CPU Model", system
.cpu_model
408 print "CPU count", system
.cpu_count
409 print "Memory", system
.memory