mirror of
https://github.com/xonsh/xonsh.git
synced 2025-03-04 16:34:47 +01:00
added uptime
This commit is contained in:
parent
e2bdc263d0
commit
ac40750c04
8 changed files with 380 additions and 15 deletions
|
@ -2,6 +2,7 @@ import os
|
|||
import tempfile
|
||||
|
||||
from xonsh.xoreutils import _which
|
||||
from xonsh.xoreutils import uptime
|
||||
from xonsh.tools import ON_WINDOWS
|
||||
|
||||
|
||||
|
@ -85,3 +86,17 @@ class TestWhich:
|
|||
return path1 == path2
|
||||
else:
|
||||
return os.path.samefile(path1, path2)
|
||||
|
||||
|
||||
def test_uptime():
|
||||
up = uptime.uptime()
|
||||
assert up is not None
|
||||
assert up > 0.0
|
||||
|
||||
|
||||
def test_boottime():
|
||||
bt = uptime.boottime()
|
||||
assert bt is not None
|
||||
assert bt > 0.0
|
||||
assert uptime._BOOTTIME is not None
|
||||
assert uptime._BOOTTIME > 0.0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
__version__ = '0.5.3'
|
||||
|
||||
# amalgamate exclude jupyter_kernel parser_table parser_test_table pyghooks
|
||||
# amalgamate exclude winutils wizard pytest_plugin fs
|
||||
# amalgamate exclude winutils wizard pytest_plugin fs macutils
|
||||
import os as _os
|
||||
if _os.getenv('XONSH_DEBUG', ''):
|
||||
pass
|
||||
|
|
|
@ -11,7 +11,7 @@ import subprocess
|
|||
import collections
|
||||
|
||||
from xonsh.lazyasd import LazyObject
|
||||
from xonsh.platform import ON_DARWIN, ON_WINDOWS, ON_CYGWIN
|
||||
from xonsh.platform import ON_DARWIN, ON_WINDOWS, ON_CYGWIN, LIBC
|
||||
|
||||
|
||||
tasks = LazyObject(collections.deque, globals(), 'tasks')
|
||||
|
@ -134,9 +134,6 @@ else:
|
|||
# give_terminal_to from bash 4.3 source, jobs.c, line 4030
|
||||
# this will give the terminal to the process group pgid
|
||||
if ON_CYGWIN:
|
||||
_libc = LazyObject(lambda: ctypes.CDLL('cygwin1.dll'),
|
||||
globals(), '_libc')
|
||||
|
||||
# on cygwin, signal.pthread_sigmask does not exist in Python, even
|
||||
# though pthread_sigmask is defined in the kernel. thus, we use
|
||||
# ctypes to mimic the calls in the "normal" version below.
|
||||
|
@ -145,16 +142,16 @@ else:
|
|||
if st is not None and os.isatty(st):
|
||||
omask = ctypes.c_ulong()
|
||||
mask = ctypes.c_ulong()
|
||||
_libc.sigemptyset(ctypes.byref(mask))
|
||||
LIBC.sigemptyset(ctypes.byref(mask))
|
||||
for i in _block_when_giving:
|
||||
_libc.sigaddset(ctypes.byref(mask), ctypes.c_int(i))
|
||||
_libc.sigemptyset(ctypes.byref(omask))
|
||||
_libc.sigprocmask(ctypes.c_int(signal.SIG_BLOCK),
|
||||
ctypes.byref(mask),
|
||||
ctypes.byref(omask))
|
||||
_libc.tcsetpgrp(ctypes.c_int(st), ctypes.c_int(pgid))
|
||||
_libc.sigprocmask(ctypes.c_int(signal.SIG_SETMASK),
|
||||
ctypes.byref(omask), None)
|
||||
LIBC.sigaddset(ctypes.byref(mask), ctypes.c_int(i))
|
||||
LIBC.sigemptyset(ctypes.byref(omask))
|
||||
LIBC.sigprocmask(ctypes.c_int(signal.SIG_BLOCK),
|
||||
ctypes.byref(mask),
|
||||
ctypes.byref(omask))
|
||||
LIBC.tcsetpgrp(ctypes.c_int(st), ctypes.c_int(pgid))
|
||||
LIBC.sigprocmask(ctypes.c_int(signal.SIG_SETMASK),
|
||||
ctypes.byref(omask), None)
|
||||
else:
|
||||
def _give_terminal_to(pgid):
|
||||
st = _shell_tty()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Lazy imports that may apply across the xonsh package."""
|
||||
import importlib
|
||||
|
||||
from xonsh.platform import ON_WINDOWS
|
||||
from xonsh.platform import ON_WINDOWS, ON_DARWIN
|
||||
from xonsh.lazyasd import LazyObject, lazyobject
|
||||
|
||||
pygments = LazyObject(lambda: importlib.import_module('pygments'),
|
||||
|
@ -69,6 +69,15 @@ def winutils():
|
|||
return m
|
||||
|
||||
|
||||
@lazyobject
|
||||
def macutils():
|
||||
if ON_DARWIN:
|
||||
import xonsh.macutils as m
|
||||
else:
|
||||
m = None
|
||||
return m
|
||||
|
||||
|
||||
@lazyobject
|
||||
def terminal256():
|
||||
return importlib.import_module('pygments.formatters.terminal256')
|
||||
|
|
22
xonsh/macutils.py
Normal file
22
xonsh/macutils.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
"""Provides some Mac / Darwin based utility functions for xonsh."""
|
||||
from ctypes import c_uint, byref, create_string_buffer
|
||||
|
||||
from xonsh.platform import LIBC
|
||||
|
||||
|
||||
def sysctlbyname(name, return_str=True):
|
||||
"""Gets a sysctrl value by name. If return_str is true, this will return
|
||||
a string representation, else it will return the raw value.
|
||||
"""
|
||||
# forked from https://gist.github.com/pudquick/581a71425439f2cf8f09
|
||||
size = c_uint(0)
|
||||
# Find out how big our buffer will be
|
||||
LIBC.sysctlbyname(name, None, byref(size), None, 0)
|
||||
# Make the buffer
|
||||
buf = create_string_buffer(size.value)
|
||||
# Re-run, but provide the buffer
|
||||
LIBC.sysctlbyname(name, buf, byref(size), None, 0)
|
||||
if return_str:
|
||||
return buf.value
|
||||
else:
|
||||
return buf.raw
|
|
@ -4,6 +4,7 @@ on a platform.
|
|||
"""
|
||||
import os
|
||||
import sys
|
||||
import ctypes
|
||||
import signal
|
||||
import pathlib
|
||||
import builtins
|
||||
|
@ -55,6 +56,11 @@ ON_BSD = LazyBool(lambda: ON_FREEBSD or ON_NETBSD,
|
|||
globals(), 'ON_BSD')
|
||||
"""``True`` if on a BSD operating system, else ``False``."""
|
||||
|
||||
@lazybool
|
||||
def ON_BEOS():
|
||||
"""True if we are on BeOS or Haiku."""
|
||||
return sys.platform == 'beos5' or sys.platform == 'haiku1'
|
||||
|
||||
|
||||
#
|
||||
# Python & packages
|
||||
|
@ -361,3 +367,59 @@ def PATH_DEFAULT():
|
|||
else:
|
||||
pd = ()
|
||||
return pd
|
||||
|
||||
#
|
||||
# libc
|
||||
#
|
||||
@lazyobject
|
||||
def LIBC():
|
||||
"""The platform dependent libc implementation."""
|
||||
if ON_DARWIN:
|
||||
libc = ctypes.CDLL(ctypes.util.find_library("c"))
|
||||
elif ON_CYGWIN:
|
||||
libc = ctypes.CDLL('cygwin1.dll')
|
||||
elif ON_BSD:
|
||||
try:
|
||||
libc = ctypes.CDLL('libc.so')
|
||||
except AttributeError:
|
||||
libc = None
|
||||
except OSError:
|
||||
# OS X; can't use ctypes.util.find_library because that creates
|
||||
# a new process on Linux, which is undesirable.
|
||||
try:
|
||||
libc = ctypes.CDLL('libc.dylib')
|
||||
except OSError:
|
||||
libc = None
|
||||
elif ON_POSIX:
|
||||
try:
|
||||
libc = ctypes.CDLL('libc.so')
|
||||
except AttributeError:
|
||||
libc = None
|
||||
except OSError:
|
||||
# Debian and derivatives do the wrong thing because /usr/lib/libc.so
|
||||
# is a GNU ld script rather than an ELF object. To get around this, we
|
||||
# have to be more specific.
|
||||
# We don't want to use ctypes.util.find_library because that creates a
|
||||
# new process on Linux. We also don't want to try too hard because at
|
||||
# this point we're already pretty sure this isn't Linux.
|
||||
try:
|
||||
libc = ctypes.CDLL('libc.so.6')
|
||||
except OSError:
|
||||
libc = None
|
||||
if not hasattr(libc, 'sysinfo'):
|
||||
# Not Linux.
|
||||
libc = None
|
||||
elif ON_WINDOWS:
|
||||
if hasattr(ctypes, 'windll') and hasattr(ctypes.windll, 'kernel32'):
|
||||
libc = ctypes.windll.kernel32
|
||||
else:
|
||||
try:
|
||||
# Windows CE uses the cdecl calling convention.
|
||||
libc = ctypes.CDLL('coredll.lib')
|
||||
except (AttributeError, OSError):
|
||||
libc = None
|
||||
elif ON_BEOS:
|
||||
libc = ctypes.CDLL('libroot.so')
|
||||
else:
|
||||
libc = None
|
||||
return libc
|
|
@ -0,0 +1,2 @@
|
|||
# amalgamate
|
||||
# amalgamate end
|
258
xonsh/xoreutils/uptime.py
Normal file
258
xonsh/xoreutils/uptime.py
Normal file
|
@ -0,0 +1,258 @@
|
|||
"""
|
||||
Provides a cross-platform way to figure out the system uptime.
|
||||
|
||||
Should work on damned near any operating system you can realistically expect
|
||||
to be asked to write Python code for.
|
||||
If this module is invoked as a stand-alone script, it will print the current
|
||||
uptime in a human-readable format, or display an error message if it can't,
|
||||
to standard output.
|
||||
|
||||
This file was forked from the uptime project: https://github.com/Cairnarvon/uptime
|
||||
Copyright (c) 2012, Koen Crolla, All rights reserved.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import ctypes
|
||||
import struct
|
||||
|
||||
import xonsh.platform as xp
|
||||
import xonsh.lazyimps as xlimps
|
||||
|
||||
|
||||
_BOOTTIME = None
|
||||
|
||||
|
||||
def _uptime_osx():
|
||||
"""Returns the uptime on mac / darwin."""
|
||||
global _BOOTTIME
|
||||
bt = xlimps.macutils.sysctlbyname("kern.boottime", return_str=False)
|
||||
bt = struct.unpack('@LL', bt)
|
||||
bt = bt[0] + bt[1]*1e-6
|
||||
if bt == 0.0:
|
||||
return None
|
||||
_BOOTTIME = bt
|
||||
return time.time() - bt
|
||||
|
||||
|
||||
def _uptime_linux():
|
||||
"""Returns uptime in seconds or None, on Linux."""
|
||||
# With procfs
|
||||
try:
|
||||
with open('/proc/uptime', 'r') as f:
|
||||
up = float(f.readline().split()[0])
|
||||
return up
|
||||
except (IOError, ValueError):
|
||||
pass
|
||||
buf = ctypes.create_string_buffer(128) # 64 suffices on 32-bit, whatever.
|
||||
if xp.LIBC.sysinfo(buf) < 0:
|
||||
return None
|
||||
up = struct.unpack_from('@l', buf.raw)[0]
|
||||
if up < 0:
|
||||
up = None
|
||||
return up
|
||||
|
||||
|
||||
def _boottime_linux():
|
||||
"""A way to figure out the boot time directly on Linux."""
|
||||
global _BOOTTIME
|
||||
try:
|
||||
with open('/proc/stat', 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith('btime'):
|
||||
_BOOTTIME = float(line.split()[1])
|
||||
return _BOOTTIME
|
||||
except (IOError, IndexError):
|
||||
return None
|
||||
|
||||
|
||||
def _uptime_amiga():
|
||||
"""Returns uptime in seconds or None, on AmigaOS."""
|
||||
global _BOOTTIME
|
||||
try:
|
||||
_BOOTTIME = os.stat('RAM:').st_ctime
|
||||
return time.time() - _BOOTTIME
|
||||
except (NameError, OSError):
|
||||
return None
|
||||
|
||||
|
||||
def _uptime_beos():
|
||||
"""Returns uptime in seconds on None, on BeOS/Haiku."""
|
||||
if not hasattr(xp.LIBC, 'system_time'):
|
||||
return None
|
||||
xp.LIBC.system_time.restype = ctypes.c_int64
|
||||
return xp.LIBC.system_time() / 1000000.
|
||||
|
||||
|
||||
def _uptime_bsd():
|
||||
"""Returns uptime in seconds or None, on BSD (including OS X)."""
|
||||
global _BOOTTIME
|
||||
if not hasattr(xp.LIBC, 'sysctlbyname'):
|
||||
# Not BSD.
|
||||
return None
|
||||
# Determine how much space we need for the response.
|
||||
sz = ctypes.c_uint(0)
|
||||
libc.sysctlbyname('kern.boottime', None, ctypes.byref(sz), None, 0)
|
||||
if sz.value != struct.calcsize('@LL'):
|
||||
# Unexpected, let's give up.
|
||||
return None
|
||||
# For real now.
|
||||
buf = ctypes.create_string_buffer(sz.value)
|
||||
libc.sysctlbyname('kern.boottime', buf, ctypes.byref(sz), None, 0)
|
||||
sec, usec = struct.unpack('@LL', buf.raw)
|
||||
# OS X disagrees what that second value is.
|
||||
if usec > 1000000:
|
||||
usec = 0.
|
||||
_BOOTTIME = sec + usec / 1000000.
|
||||
up = time.time() - _BOOTTIME
|
||||
if up < 0:
|
||||
up = None
|
||||
return up
|
||||
|
||||
|
||||
def _uptime_minix():
|
||||
"""Returns uptime in seconds or None, on MINIX."""
|
||||
try:
|
||||
with open('/proc/uptime', 'r') as f:
|
||||
up = float(f.read())
|
||||
return up
|
||||
except (IOError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _uptime_plan9():
|
||||
"""Returns uptime in seconds or None, on Plan 9."""
|
||||
# Apparently Plan 9 only has Python 2.2, which I'm not prepared to
|
||||
# support. Maybe some Linuxes implement /dev/time, though, someone was
|
||||
# talking about it somewhere.
|
||||
try:
|
||||
# The time file holds one 32-bit number representing the sec-
|
||||
# onds since start of epoch and three 64-bit numbers, repre-
|
||||
# senting nanoseconds since start of epoch, clock ticks, and
|
||||
# clock frequency.
|
||||
# -- cons(3)
|
||||
with open('/dev/time', 'r') as f:
|
||||
s, ns, ct, cf = f.read().split()
|
||||
return float(ct) / float(cf)
|
||||
except (IOError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _uptime_solaris():
|
||||
"""Returns uptime in seconds or None, on Solaris."""
|
||||
global _BOOTTIME
|
||||
try:
|
||||
kstat = ctypes.CDLL('libkstat.so')
|
||||
except (AttributeError, OSError):
|
||||
return None
|
||||
|
||||
# kstat doesn't have uptime, but it does have boot time.
|
||||
# Unfortunately, getting at it isn't perfectly straightforward.
|
||||
# First, let's pretend to be kstat.h
|
||||
|
||||
# Constant
|
||||
KSTAT_STRLEN = 31 # According to every kstat.h I could find.
|
||||
|
||||
# Data structures
|
||||
class anon_union(ctypes.Union):
|
||||
# The ``value'' union in kstat_named_t actually has a bunch more
|
||||
# members, but we're only using it for boot_time, so we only need
|
||||
# the padding and the one we're actually using.
|
||||
_fields_ = [('c', ctypes.c_char * 16),
|
||||
('time', ctypes.c_int)]
|
||||
|
||||
class kstat_named_t(ctypes.Structure):
|
||||
_fields_ = [('name', ctypes.c_char * KSTAT_STRLEN),
|
||||
('data_type', ctypes.c_char),
|
||||
('value', anon_union)]
|
||||
|
||||
# Function signatures
|
||||
kstat.kstat_open.restype = ctypes.c_void_p
|
||||
kstat.kstat_lookup.restype = ctypes.c_void_p
|
||||
kstat.kstat_lookup.argtypes = [ctypes.c_void_p,
|
||||
ctypes.c_char_p,
|
||||
ctypes.c_int,
|
||||
ctypes.c_char_p]
|
||||
kstat.kstat_read.restype = ctypes.c_int
|
||||
kstat.kstat_read.argtypes = [ctypes.c_void_p,
|
||||
ctypes.c_void_p,
|
||||
ctypes.c_void_p]
|
||||
kstat.kstat_data_lookup.restype = ctypes.POINTER(kstat_named_t)
|
||||
kstat.kstat_data_lookup.argtypes = [ctypes.c_void_p,
|
||||
ctypes.c_char_p]
|
||||
|
||||
# Now, let's do something useful.
|
||||
# Initialise kstat control structure.
|
||||
kc = kstat.kstat_open()
|
||||
if not kc:
|
||||
return None
|
||||
# We're looking for unix:0:system_misc:boot_time.
|
||||
ksp = kstat.kstat_lookup(kc, 'unix', 0, 'system_misc')
|
||||
if ksp and kstat.kstat_read(kc, ksp, None) != -1:
|
||||
data = kstat.kstat_data_lookup(ksp, 'boot_time')
|
||||
if data:
|
||||
_BOOTTIME = data.contents.value.time
|
||||
# Clean-up.
|
||||
kstat.kstat_close(kc)
|
||||
if _BOOTTIME is not None:
|
||||
return time.time() - _BOOTTIME
|
||||
return None
|
||||
|
||||
def _uptime_syllable():
|
||||
"""Returns uptime in seconds or None, on Syllable."""
|
||||
global _BOOTTIME
|
||||
try:
|
||||
_BOOTTIME = os.stat('/dev/pty/mst/pty0').st_mtime
|
||||
return time.time() - _BOOTTIME
|
||||
except (NameError, OSError):
|
||||
return None
|
||||
|
||||
def _uptime_windows():
|
||||
"""
|
||||
Returns uptime in seconds or None, on Windows. Warning: may return
|
||||
incorrect answers after 49.7 days on versions older than Vista.
|
||||
"""
|
||||
if hasattr(xp.LIBC, 'GetTickCount64'):
|
||||
# Vista/Server 2008 or later.
|
||||
xp.LIBC.GetTickCount64.restype = ctypes.c_uint64
|
||||
return xp.LIBC.GetTickCount64() / 1000.
|
||||
if hasattr(xp.LIBC, 'GetTickCount'):
|
||||
# WinCE and Win2k or later; gives wrong answers after 49.7 days.
|
||||
xp.LIBC.GetTickCount.restype = ctypes.c_uint32
|
||||
return xp.LIBC.GetTickCount() / 1000.
|
||||
return None
|
||||
|
||||
|
||||
def uptime():
|
||||
"""Returns uptime in seconds if even remotely possible, or None if not."""
|
||||
if _BOOTTIME is not None:
|
||||
return time.time() - _BOOTTIME
|
||||
return {'amiga': _uptime_amiga,
|
||||
'aros12': _uptime_amiga,
|
||||
'beos5': _uptime_beos,
|
||||
'cygwin': _uptime_linux,
|
||||
'darwin': _uptime_osx,
|
||||
'haiku1': _uptime_beos,
|
||||
'linux': _uptime_linux,
|
||||
'linux-armv71': _uptime_linux,
|
||||
'linux2': _uptime_linux,
|
||||
'minix3': _uptime_minix,
|
||||
'sunos5': _uptime_solaris,
|
||||
'syllable': _uptime_syllable,
|
||||
'win32': _uptime_windows,
|
||||
'wince': _uptime_windows}.get(sys.platform, _uptime_bsd)() or \
|
||||
_uptime_bsd() or _uptime_plan9() or _uptime_linux() or \
|
||||
_uptime_windows() or _uptime_solaris() or _uptime_beos() or \
|
||||
_uptime_amiga() or \
|
||||
_uptime_syllable() or _uptime_osx()
|
||||
|
||||
|
||||
def boottime():
|
||||
"""Returns boot time if remotely possible, or None if not."""
|
||||
global _BOOTTIME
|
||||
if _BOOTTIME is None:
|
||||
up = uptime()
|
||||
if up is None:
|
||||
return None
|
||||
_BOOTTIME = time.time() - up
|
||||
return _BOOTTIME
|
Loading…
Add table
Reference in a new issue