summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2020-10-17 00:53:59 +0200
committerGiampaolo Rodola <g.rodola@gmail.com>2020-10-17 00:53:59 +0200
commita8cd5893a920adcd5b8922b80748461fbea8dc1c (patch)
treef74c5f7cfc8ae84319f201f21528c51c5ba553e7 /scripts
parentbd4d2bf420e1dfa3298143daebd485b97335b256 (diff)
downloadpsutil-a8cd5893a920adcd5b8922b80748461fbea8dc1c.tar.gz
pypi download stats script
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/battery.py2
-rwxr-xr-xscripts/cpu_distribution.py2
-rwxr-xr-xscripts/disk_usage.py2
-rwxr-xr-xscripts/free.py2
-rwxr-xr-xscripts/ifconfig.py2
-rw-r--r--scripts/internal/download_wheels.py154
-rwxr-xr-xscripts/internal/download_wheels_appveyor.py (renamed from scripts/internal/win_download_wheels.py)26
-rwxr-xr-xscripts/internal/download_wheels_github.py81
-rwxr-xr-xscripts/internal/print_announce.py2
-rwxr-xr-xscripts/internal/print_downloads.py154
-rwxr-xr-xscripts/internal/print_wheels.py66
-rwxr-xr-xscripts/iotop.py46
-rwxr-xr-xscripts/meminfo.py2
-rwxr-xr-xscripts/netstat.py2
-rwxr-xr-xscripts/nettop.py57
-rwxr-xr-xscripts/pmap.py2
-rwxr-xr-xscripts/procinfo.py2
-rwxr-xr-xscripts/ps.py2
-rwxr-xr-xscripts/pstree.py2
-rwxr-xr-xscripts/sensors.py2
-rwxr-xr-xscripts/temperatures.py2
-rwxr-xr-xscripts/top.py79
-rwxr-xr-xscripts/who.py2
-rwxr-xr-xscripts/winservices.py2
24 files changed, 435 insertions, 260 deletions
diff --git a/scripts/battery.py b/scripts/battery.py
index 0da2b958..edf4ce8c 100755
--- a/scripts/battery.py
+++ b/scripts/battery.py
@@ -7,7 +7,7 @@
"""
Show battery information.
-$ python scripts/battery.py
+$ python3 scripts/battery.py
charge: 74%
left: 2:11:31
status: discharging
diff --git a/scripts/cpu_distribution.py b/scripts/cpu_distribution.py
index 08997797..fb39d888 100755
--- a/scripts/cpu_distribution.py
+++ b/scripts/cpu_distribution.py
@@ -7,7 +7,7 @@
"""
Shows CPU workload split across different CPUs.
-$ python scripts/cpu_workload.py
+$ python3 scripts/cpu_workload.py
CPU 0 CPU 1 CPU 2 CPU 3 CPU 4 CPU 5 CPU 6 CPU 7
19.8 20.6 18.2 15.8 6.9 17.3 5.0 20.4
gvfsd pytho kwork chrom unity kwork kwork kwork
diff --git a/scripts/disk_usage.py b/scripts/disk_usage.py
index 901dbf8c..851ae9b1 100755
--- a/scripts/disk_usage.py
+++ b/scripts/disk_usage.py
@@ -7,7 +7,7 @@
"""
List all mounted disk partitions a-la "df -h" command.
-$ python scripts/disk_usage.py
+$ python3 scripts/disk_usage.py
Device Total Used Free Use % Type Mount
/dev/sdb3 18.9G 14.7G 3.3G 77% ext4 /
/dev/sda6 345.9G 83.8G 244.5G 24% ext4 /home
diff --git a/scripts/free.py b/scripts/free.py
index 000323c5..8c3359d8 100755
--- a/scripts/free.py
+++ b/scripts/free.py
@@ -7,7 +7,7 @@
"""
A clone of 'free' cmdline utility.
-$ python scripts/free.py
+$ python3 scripts/free.py
total used free shared buffers cache
Mem: 10125520 8625996 1499524 0 349500 3307836
Swap: 0 0 0
diff --git a/scripts/ifconfig.py b/scripts/ifconfig.py
index cfd02f0d..ae137fb4 100755
--- a/scripts/ifconfig.py
+++ b/scripts/ifconfig.py
@@ -7,7 +7,7 @@
"""
A clone of 'ifconfig' on UNIX.
-$ python scripts/ifconfig.py
+$ python3 scripts/ifconfig.py
lo:
stats : speed=0MB, duplex=?, mtu=65536, up=yes
incoming : bytes=1.95M, pkts=22158, errs=0, drops=0
diff --git a/scripts/internal/download_wheels.py b/scripts/internal/download_wheels.py
deleted file mode 100644
index 1834f1b3..00000000
--- a/scripts/internal/download_wheels.py
+++ /dev/null
@@ -1,154 +0,0 @@
-#!/usr/bin/env python3
-
-# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Script which downloads wheel files hosted on GitHub:
-https://github.com/giampaolo/psutil/actions
-It needs an access token string generated from personal GitHub profile:
-https://github.com/settings/tokens
-The token must be created with at least "public_repo" scope/rights.
-If you lose it, just generate a new token.
-REST API doc:
-https://developer.github.com/v3/actions/artifacts/
-"""
-
-import argparse
-import collections
-import json
-import os
-import requests
-import shutil
-import zipfile
-
-from psutil import __version__ as PSUTIL_VERSION
-from psutil._common import bytes2human
-from psutil._common import print_color
-
-
-USER = ""
-PROJECT = ""
-TOKEN = ""
-OUTFILE = "wheels.zip"
-
-
-# --- GitHub API
-
-
-def get_artifacts():
- base_url = "https://api.github.com/repos/%s/%s" % (USER, PROJECT)
- url = base_url + "/actions/artifacts"
- res = requests.get(url=url, headers={"Authorization": "token %s" % TOKEN})
- res.raise_for_status()
- data = json.loads(res.content)
- return data
-
-
-def download_zip(url):
- print("downloading: " + url)
- res = requests.get(url=url, headers={"Authorization": "token %s" % TOKEN})
- res.raise_for_status()
- totbytes = 0
- with open(OUTFILE, 'wb') as f:
- for chunk in res.iter_content(chunk_size=16384):
- f.write(chunk)
- totbytes += len(chunk)
- print("got %s, size %s)" % (OUTFILE, bytes2human(totbytes)))
-
-
-# --- extract
-
-
-def rename_27_wheels():
- # See: https://github.com/giampaolo/psutil/issues/810
- src = 'dist/psutil-%s-cp27-cp27m-win32.whl' % PSUTIL_VERSION
- dst = 'dist/psutil-%s-cp27-none-win32.whl' % PSUTIL_VERSION
- print("rename: %s\n %s" % (src, dst))
- os.rename(src, dst)
- src = 'dist/psutil-%s-cp27-cp27m-win_amd64.whl' % PSUTIL_VERSION
- dst = 'dist/psutil-%s-cp27-none-win_amd64.whl' % PSUTIL_VERSION
- print("rename: %s\n %s" % (src, dst))
- os.rename(src, dst)
-
-
-def extract():
- with zipfile.ZipFile(OUTFILE, 'r') as zf:
- zf.extractall('dist')
-
-
-def print_wheels():
- def is64bit(name):
- return name.endswith(('x86_64.whl', 'amd64.whl'))
-
- groups = collections.defaultdict(list)
- for name in os.listdir('dist'):
- plat = name.split('-')[-1]
- pyimpl = name.split('-')[3]
- ispypy = 'pypy' in pyimpl
- if 'linux' in plat:
- if ispypy:
- groups['pypy_on_linux'].append(name)
- else:
- groups['linux'].append(name)
- elif 'win' in plat:
- if ispypy:
- groups['pypy_on_windows'].append(name)
- else:
- groups['windows'].append(name)
- elif 'macosx' in plat:
- if ispypy:
- groups['pypy_on_macos'].append(name)
- else:
- groups['macos'].append(name)
- else:
- assert 0, name
-
- totsize = 0
- templ = "%-54s %7s %7s %7s"
- for platf, names in groups.items():
- ppn = "%s (total = %s)" % (platf.replace('_', ' '), len(names))
- s = templ % (ppn, "size", "arch", "pyver")
- print_color('\n' + s, color=None, bold=True)
- for name in sorted(names):
- path = os.path.join('dist', name)
- size = os.path.getsize(path)
- totsize += size
- arch = '64' if is64bit(name) else '32'
- pyver = 'pypy' if name.split('-')[3].startswith('pypy') else 'py'
- pyver += name.split('-')[2][2:]
- s = templ % (name, bytes2human(size), arch, pyver)
- if 'pypy' in pyver:
- print_color(s, color='violet')
- else:
- print_color(s, color='brown')
-
-
-def run():
- if os.path.isdir('dist'):
- shutil.rmtree('dist')
- data = get_artifacts()
- download_zip(data['artifacts'][0]['archive_download_url'])
- os.mkdir('dist')
- extract()
- # rename_27_wheels()
- print_wheels()
-
-
-def main():
- global USER, PROJECT, TOKEN
- parser = argparse.ArgumentParser(description='GitHub wheels downloader')
- parser.add_argument('--user', required=True)
- parser.add_argument('--project', required=True)
- parser.add_argument('--tokenfile', required=True)
- args = parser.parse_args()
- USER = args.user
- PROJECT = args.project
- with open(os.path.expanduser(args.tokenfile)) as f:
- TOKEN = f.read().strip()
- run()
-
-
-if __name__ == '__main__':
- main()
diff --git a/scripts/internal/win_download_wheels.py b/scripts/internal/download_wheels_appveyor.py
index 8dae0573..b7c0aeae 100755
--- a/scripts/internal/win_download_wheels.py
+++ b/scripts/internal/download_wheels_appveyor.py
@@ -15,10 +15,8 @@ http://code.saghul.net/index.php/2015/09/09/
from __future__ import print_function
import argparse
import concurrent.futures
-import errno
import os
import requests
-import shutil
import sys
from psutil import __version__ as PSUTIL_VERSION
@@ -29,33 +27,12 @@ from psutil._common import print_color
BASE_URL = 'https://ci.appveyor.com/api'
PY_VERSIONS = ['2.7', '3.5', '3.6', '3.7', '3.8']
TIMEOUT = 30
-COLORS = True
-
-
-def safe_makedirs(path):
- try:
- os.makedirs(path)
- except OSError as err:
- if err.errno == errno.EEXIST:
- if not os.path.isdir(path):
- raise
- else:
- raise
-
-
-def safe_rmtree(path):
- def onerror(fun, path, excinfo):
- exc = excinfo[1]
- if exc.errno != errno.ENOENT:
- raise
-
- shutil.rmtree(path, onerror=onerror)
def download_file(url):
local_fname = url.split('/')[-1]
local_fname = os.path.join('dist', local_fname)
- safe_makedirs('dist')
+ os.makedirs('dist', exist_ok=True)
r = requests.get(url, stream=True, timeout=TIMEOUT)
tot_bytes = 0
with open(local_fname, 'wb') as f:
@@ -102,7 +79,6 @@ def rename_27_wheels():
def run(options):
- safe_rmtree('dist')
urls = get_file_urls(options)
completed = 0
exc = None
diff --git a/scripts/internal/download_wheels_github.py b/scripts/internal/download_wheels_github.py
new file mode 100755
index 00000000..4aa50d5d
--- /dev/null
+++ b/scripts/internal/download_wheels_github.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Script which downloads wheel files hosted on GitHub:
+https://github.com/giampaolo/psutil/actions
+It needs an access token string generated from personal GitHub profile:
+https://github.com/settings/tokens
+The token must be created with at least "public_repo" scope/rights.
+If you lose it, just generate a new token.
+REST API doc:
+https://developer.github.com/v3/actions/artifacts/
+"""
+
+import argparse
+import json
+import os
+import requests
+import zipfile
+
+from psutil._common import bytes2human
+from psutil.tests import safe_rmpath
+
+
+USER = ""
+PROJECT = ""
+TOKEN = ""
+OUTFILE = "wheels-github.zip"
+
+
+def get_artifacts():
+ base_url = "https://api.github.com/repos/%s/%s" % (USER, PROJECT)
+ url = base_url + "/actions/artifacts"
+ res = requests.get(url=url, headers={"Authorization": "token %s" % TOKEN})
+ res.raise_for_status()
+ data = json.loads(res.content)
+ return data
+
+
+def download_zip(url):
+ print("downloading: " + url)
+ res = requests.get(url=url, headers={"Authorization": "token %s" % TOKEN})
+ res.raise_for_status()
+ totbytes = 0
+ with open(OUTFILE, 'wb') as f:
+ for chunk in res.iter_content(chunk_size=16384):
+ f.write(chunk)
+ totbytes += len(chunk)
+ print("got %s, size %s)" % (OUTFILE, bytes2human(totbytes)))
+
+
+def run():
+ data = get_artifacts()
+ download_zip(data['artifacts'][0]['archive_download_url'])
+ os.makedirs('dist', exist_ok=True)
+ with zipfile.ZipFile(OUTFILE, 'r') as zf:
+ zf.extractall('dist')
+
+
+def main():
+ global USER, PROJECT, TOKEN
+ parser = argparse.ArgumentParser(description='GitHub wheels downloader')
+ parser.add_argument('--user', required=True)
+ parser.add_argument('--project', required=True)
+ parser.add_argument('--tokenfile', required=True)
+ args = parser.parse_args()
+ USER = args.user
+ PROJECT = args.project
+ with open(os.path.expanduser(args.tokenfile)) as f:
+ TOKEN = f.read().strip()
+ try:
+ run()
+ finally:
+ safe_rmpath(OUTFILE)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/internal/print_announce.py b/scripts/internal/print_announce.py
index 9569c367..180bf377 100755
--- a/scripts/internal/print_announce.py
+++ b/scripts/internal/print_announce.py
@@ -58,7 +58,7 @@ Links
--
-Giampaolo - http://grodola.blogspot.com
+Giampaolo - https://gmpy.dev/about
"""
diff --git a/scripts/internal/print_downloads.py b/scripts/internal/print_downloads.py
new file mode 100755
index 00000000..81132db9
--- /dev/null
+++ b/scripts/internal/print_downloads.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Print PYPI statistics in MarkDown format.
+Useful sites:
+* https://pepy.tech/project/psutil
+* https://pypistats.org/packages/psutil
+* https://hugovk.github.io/top-pypi-packages/
+"""
+
+from __future__ import print_function
+import json
+import os
+import subprocess
+import sys
+
+import pypinfo # NOQA
+
+from psutil._common import memoize
+
+
+AUTH_FILE = os.path.expanduser("~/.pypinfo.json")
+PKGNAME = 'psutil'
+DAYS = 30
+LIMIT = 100
+GITHUB_SCRIPT_URL = "https://github.com/giampaolo/psutil/blob/master/" \
+ "scripts/internal/pypistats.py"
+bytes_billed = 0
+
+
+# --- get
+
+@memoize
+def sh(cmd):
+ assert os.path.exists(AUTH_FILE)
+ env = os.environ.copy()
+ env['GOOGLE_APPLICATION_CREDENTIALS'] = AUTH_FILE
+ p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, universal_newlines=True)
+ stdout, stderr = p.communicate()
+ if p.returncode != 0:
+ raise RuntimeError(stderr)
+ assert not stderr, stderr
+ return stdout.strip()
+
+
+@memoize
+def query(cmd):
+ global bytes_billed
+ ret = json.loads(sh(cmd))
+ bytes_billed += ret['query']['bytes_billed']
+ return ret
+
+
+def top_packages():
+ return query(
+ f"pypinfo --all --json --days {DAYS} --limit {LIMIT} '' project")
+
+
+def ranking():
+ data = top_packages()
+ for i, line in enumerate(data['rows'], 1):
+ if line['project'] == PKGNAME:
+ return i
+ raise ValueError(f"can't find {PKGNAME}")
+
+
+def downloads():
+ data = top_packages()
+ for line in data['rows']:
+ if line['project'] == PKGNAME:
+ return line['download_count']
+ raise ValueError(f"can't find {PKGNAME}")
+
+
+def downloads_pyver():
+ return query(f"pypinfo --json --days {DAYS} {PKGNAME} pyversion")
+
+
+def downloads_by_country():
+ return query(f"pypinfo --json --days {DAYS} {PKGNAME} country")
+
+
+def downloads_by_system():
+ return query(f"pypinfo --json --days {DAYS} {PKGNAME} system")
+
+
+def downloads_by_distro():
+ return query(f"pypinfo --json --days {DAYS} {PKGNAME} distro")
+
+
+# --- print
+
+
+templ = "| %-30s | %15s |"
+
+
+def print_row(left, right):
+ if isinstance(right, int):
+ right = '{0:,}'.format(right)
+ print(templ % (left, right))
+
+
+def print_header(left, right="Downloads"):
+ print_row(left, right)
+ s = templ % ("-" * 30, "-" * 15)
+ print("|:" + s[2:-2] + ":|")
+
+
+def print_markdown_table(title, left, rows):
+ pleft = left.replace('_', ' ').capitalize()
+ print("### " + title)
+ print()
+ print_header(pleft)
+ for row in rows:
+ lval = row[left]
+ print_row(lval, row['download_count'])
+ print()
+
+
+def main():
+ last_update = top_packages()['last_update']
+ print("# Download stats")
+ print("")
+ s = f"psutil download statistics of the last {DAYS} days (last update "
+ s += f"*{last_update}*).\n"
+ s += f"Generated via [pypistats.py]({GITHUB_SCRIPT_URL}) script.\n"
+ print(s)
+
+ data = [
+ {'what': 'Per month', 'download_count': downloads()},
+ {'what': 'Per day', 'download_count': int(downloads() / 30)},
+ {'what': 'PYPI ranking', 'download_count': ranking()}
+ ]
+ print_markdown_table('Overview', 'what', data)
+ print_markdown_table('Operating systems', 'system_name',
+ downloads_by_system()['rows'])
+ print_markdown_table('Distros', 'distro_name',
+ downloads_by_distro()['rows'])
+ print_markdown_table('Python versions', 'python_version',
+ downloads_pyver()['rows'])
+ print_markdown_table('Countries', 'country',
+ downloads_by_country()['rows'])
+
+
+if __name__ == '__main__':
+ try:
+ main()
+ finally:
+ print("bytes billed: %s" % bytes_billed, file=sys.stderr)
diff --git a/scripts/internal/print_wheels.py b/scripts/internal/print_wheels.py
new file mode 100755
index 00000000..be8290e0
--- /dev/null
+++ b/scripts/internal/print_wheels.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2009 Giampaolo Rodola'. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Nicely print wheels print in dist/ directory."""
+
+import collections
+import glob
+import os
+
+from psutil._common import print_color
+from psutil._common import bytes2human
+
+
+def main():
+ def is64bit(name):
+ return name.endswith(('x86_64.whl', 'amd64.whl'))
+
+ groups = collections.defaultdict(list)
+ for path in glob.glob('dist/*.whl'):
+ name = os.path.basename(path)
+ plat = name.split('-')[-1]
+ pyimpl = name.split('-')[3]
+ ispypy = 'pypy' in pyimpl
+ if 'linux' in plat:
+ if ispypy:
+ groups['pypy_on_linux'].append(name)
+ else:
+ groups['linux'].append(name)
+ elif 'win' in plat:
+ if ispypy:
+ groups['pypy_on_windows'].append(name)
+ else:
+ groups['windows'].append(name)
+ elif 'macosx' in plat:
+ if ispypy:
+ groups['pypy_on_macos'].append(name)
+ else:
+ groups['macos'].append(name)
+ else:
+ assert 0, name
+
+ totsize = 0
+ templ = "%-54s %7s %7s %7s"
+ for platf, names in groups.items():
+ ppn = "%s (total = %s)" % (platf.replace('_', ' '), len(names))
+ s = templ % (ppn, "size", "arch", "pyver")
+ print_color('\n' + s, color=None, bold=True)
+ for name in sorted(names):
+ path = os.path.join('dist', name)
+ size = os.path.getsize(path)
+ totsize += size
+ arch = '64' if is64bit(name) else '32'
+ pyver = 'pypy' if name.split('-')[3].startswith('pypy') else 'py'
+ pyver += name.split('-')[2][2:]
+ s = templ % (name, bytes2human(size), arch, pyver)
+ if 'pypy' in pyver:
+ print_color(s, color='violet')
+ else:
+ print_color(s, color='brown')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/iotop.py b/scripts/iotop.py
index c3afd071..04683673 100755
--- a/scripts/iotop.py
+++ b/scripts/iotop.py
@@ -14,7 +14,7 @@ It doesn't work on Windows as curses module is required.
Example output:
-$ python scripts/iotop.py
+$ python3 scripts/iotop.py
Total DISK READ: 0.00 B/s | Total DISK WRITE: 472.00 K/s
PID USER DISK READ DISK WRITE COMMAND
13155 giampao 0.00 B/s 428.00 K/s /usr/bin/google-chrome-beta
@@ -30,7 +30,6 @@ PID USER DISK READ DISK WRITE COMMAND
Author: Giampaolo Rodola' <g.rodola@gmail.com>
"""
-import atexit
import time
import sys
try:
@@ -42,20 +41,11 @@ import psutil
from psutil._common import bytes2human
-def tear_down():
- win.keypad(0)
- curses.nocbreak()
- curses.echo()
- curses.endwin()
-
-
win = curses.initscr()
-atexit.register(tear_down)
-curses.endwin()
lineno = 0
-def print_line(line, highlight=False):
+def printl(line, highlight=False):
"""A thin wrapper around curses's addstr()."""
global lineno
try:
@@ -129,10 +119,10 @@ def refresh_window(procs, disks_read, disks_write):
disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \
% (bytes2human(disks_read), bytes2human(disks_write))
- print_line(disks_tot)
+ printl(disks_tot)
header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND")
- print_line(header, highlight=True)
+ printl(header, highlight=True)
for p in procs:
line = templ % (
@@ -142,21 +132,45 @@ def refresh_window(procs, disks_read, disks_write):
bytes2human(p._write_per_sec),
p._cmdline)
try:
- print_line(line)
+ printl(line)
except curses.error:
break
win.refresh()
+def setup():
+ curses.start_color()
+ curses.use_default_colors()
+ for i in range(0, curses.COLORS):
+ curses.init_pair(i + 1, i, -1)
+ curses.endwin()
+ win.nodelay(1)
+
+
+def tear_down():
+ win.keypad(0)
+ curses.nocbreak()
+ curses.echo()
+ curses.endwin()
+
+
def main():
+ global lineno
+ setup()
try:
interval = 0
while True:
+ if win.getch() == ord('q'):
+ break
args = poll(interval)
refresh_window(*args)
- interval = 1
+ lineno = 0
+ interval = 0.5
+ time.sleep(interval)
except (KeyboardInterrupt, SystemExit):
pass
+ finally:
+ tear_down()
if __name__ == '__main__':
diff --git a/scripts/meminfo.py b/scripts/meminfo.py
index 550fcd01..b98aa60b 100755
--- a/scripts/meminfo.py
+++ b/scripts/meminfo.py
@@ -7,7 +7,7 @@
"""
Print system memory information.
-$ python scripts/meminfo.py
+$ python3 scripts/meminfo.py
MEMORY
------
Total : 9.7G
diff --git a/scripts/netstat.py b/scripts/netstat.py
index fe3bfe40..5a21358e 100755
--- a/scripts/netstat.py
+++ b/scripts/netstat.py
@@ -7,7 +7,7 @@
"""
A clone of 'netstat -antp' on Linux.
-$ python scripts/netstat.py
+$ python3 scripts/netstat.py
Proto Local address Remote address Status PID Program name
tcp 127.0.0.1:48256 127.0.0.1:45884 ESTABLISHED 13646 chrome
tcp 127.0.0.1:47073 127.0.0.1:45884 ESTABLISHED 13646 chrome
diff --git a/scripts/nettop.py b/scripts/nettop.py
index ce647c9d..8cc19fda 100755
--- a/scripts/nettop.py
+++ b/scripts/nettop.py
@@ -11,7 +11,7 @@ Shows real-time network statistics.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
-$ python scripts/nettop.py
+$ python3 scripts/nettop.py
-----------------------------------------------------------
total bytes: sent: 1.49 G received: 4.82 G
total packets: sent: 7338724 received: 8082712
@@ -31,7 +31,6 @@ pkts-sent 0 0
pkts-recv 1214470 0
"""
-import atexit
import time
import sys
try:
@@ -43,20 +42,11 @@ import psutil
from psutil._common import bytes2human
-def tear_down():
- win.keypad(0)
- curses.nocbreak()
- curses.echo()
- curses.endwin()
-
-
-win = curses.initscr()
-atexit.register(tear_down)
-curses.endwin()
lineno = 0
+win = curses.initscr()
-def print_line(line, highlight=False):
+def printl(line, highlight=False):
"""A thin wrapper around curses's addstr()."""
global lineno
try:
@@ -89,59 +79,80 @@ def refresh_window(tot_before, tot_after, pnic_before, pnic_after):
global lineno
# totals
- print_line("total bytes: sent: %-10s received: %s" % (
+ printl("total bytes: sent: %-10s received: %s" % (
bytes2human(tot_after.bytes_sent),
bytes2human(tot_after.bytes_recv))
)
- print_line("total packets: sent: %-10s received: %s" % (
+ printl("total packets: sent: %-10s received: %s" % (
tot_after.packets_sent, tot_after.packets_recv))
# per-network interface details: let's sort network interfaces so
# that the ones which generated more traffic are shown first
- print_line("")
+ printl("")
nic_names = list(pnic_after.keys())
nic_names.sort(key=lambda x: sum(pnic_after[x]), reverse=True)
for name in nic_names:
stats_before = pnic_before[name]
stats_after = pnic_after[name]
templ = "%-15s %15s %15s"
- print_line(templ % (name, "TOTAL", "PER-SEC"), highlight=True)
- print_line(templ % (
+ printl(templ % (name, "TOTAL", "PER-SEC"), highlight=True)
+ printl(templ % (
"bytes-sent",
bytes2human(stats_after.bytes_sent),
bytes2human(
stats_after.bytes_sent - stats_before.bytes_sent) + '/s',
))
- print_line(templ % (
+ printl(templ % (
"bytes-recv",
bytes2human(stats_after.bytes_recv),
bytes2human(
stats_after.bytes_recv - stats_before.bytes_recv) + '/s',
))
- print_line(templ % (
+ printl(templ % (
"pkts-sent",
stats_after.packets_sent,
stats_after.packets_sent - stats_before.packets_sent,
))
- print_line(templ % (
+ printl(templ % (
"pkts-recv",
stats_after.packets_recv,
stats_after.packets_recv - stats_before.packets_recv,
))
- print_line("")
+ printl("")
win.refresh()
lineno = 0
+def setup():
+ curses.start_color()
+ curses.use_default_colors()
+ for i in range(0, curses.COLORS):
+ curses.init_pair(i + 1, i, -1)
+ curses.endwin()
+ win.nodelay(1)
+
+
+def tear_down():
+ win.keypad(0)
+ curses.nocbreak()
+ curses.echo()
+ curses.endwin()
+
+
def main():
+ setup()
try:
interval = 0
while True:
+ if win.getch() == ord('q'):
+ break
args = poll(interval)
refresh_window(*args)
- interval = 1
+ interval = 0.5
except (KeyboardInterrupt, SystemExit):
pass
+ finally:
+ tear_down()
if __name__ == '__main__':
diff --git a/scripts/pmap.py b/scripts/pmap.py
index 5f7246a1..459927bf 100755
--- a/scripts/pmap.py
+++ b/scripts/pmap.py
@@ -8,7 +8,7 @@
A clone of 'pmap' utility on Linux, 'vmmap' on macOS and 'procstat -v' on BSD.
Report memory map of a process.
-$ python scripts/pmap.py 32402
+$ python3 scripts/pmap.py 32402
Address RSS Mode Mapping
0000000000400000 1200K r-xp /usr/bin/python2.7
0000000000838000 4K r--p /usr/bin/python2.7
diff --git a/scripts/procinfo.py b/scripts/procinfo.py
index 01974513..f0605386 100755
--- a/scripts/procinfo.py
+++ b/scripts/procinfo.py
@@ -8,7 +8,7 @@
Print detailed information about a process.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
-$ python scripts/procinfo.py
+$ python3 scripts/procinfo.py
pid 4600
name chrome
parent 4554 (bash)
diff --git a/scripts/ps.py b/scripts/ps.py
index 540c032a..a234209f 100755
--- a/scripts/ps.py
+++ b/scripts/ps.py
@@ -7,7 +7,7 @@
"""
A clone of 'ps aux'.
-$ python scripts/ps.py
+$ python3 scripts/ps.py
USER PID %MEM VSZ RSS NICE STATUS START TIME CMDLINE
root 1 0.0 220.9M 6.5M sleep Mar27 09:10 /lib/systemd
root 2 0.0 0.0B 0.0B sleep Mar27 00:00 kthreadd
diff --git a/scripts/pstree.py b/scripts/pstree.py
index 0005e4a1..dba9f1bd 100755
--- a/scripts/pstree.py
+++ b/scripts/pstree.py
@@ -8,7 +8,7 @@
Similar to 'ps aux --forest' on Linux, prints the process list
as a tree structure.
-$ python scripts/pstree.py
+$ python3 scripts/pstree.py
0 ?
|- 1 init
| |- 289 cgmanager
diff --git a/scripts/sensors.py b/scripts/sensors.py
index e532beba..911d7c9b 100755
--- a/scripts/sensors.py
+++ b/scripts/sensors.py
@@ -9,7 +9,7 @@
A clone of 'sensors' utility on Linux printing hardware temperatures,
fans speed and battery info.
-$ python scripts/sensors.py
+$ python3 scripts/sensors.py
asus
Temperatures:
asus 57.0°C (high=None°C, critical=None°C)
diff --git a/scripts/temperatures.py b/scripts/temperatures.py
index e83df440..f2dd51a7 100755
--- a/scripts/temperatures.py
+++ b/scripts/temperatures.py
@@ -8,7 +8,7 @@
"""
A clone of 'sensors' utility on Linux printing hardware temperatures.
-$ python scripts/sensors.py
+$ python3 scripts/sensors.py
asus
asus 47.0 °C (high = None °C, critical = None °C)
diff --git a/scripts/top.py b/scripts/top.py
index 0b17471d..3c297d9a 100755
--- a/scripts/top.py
+++ b/scripts/top.py
@@ -9,7 +9,7 @@ A clone of top / htop.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
-$ python scripts/top.py
+$ python3 scripts/top.py
CPU0 [|||| ] 10.9%
CPU1 [||||| ] 13.1%
CPU2 [||||| ] 12.8%
@@ -33,7 +33,6 @@ PID USER NI VIRT RES CPU% MEM% TIME+ NAME
...
"""
-import atexit
import datetime
import sys
import time
@@ -46,30 +45,28 @@ import psutil
from psutil._common import bytes2human
-# --- curses stuff
-
-def tear_down():
- win.keypad(0)
- curses.nocbreak()
- curses.echo()
- curses.endwin()
-
-
win = curses.initscr()
-atexit.register(tear_down)
-curses.endwin()
lineno = 0
+colors_map = dict(
+ green=3,
+ red=10,
+ yellow=4,
+)
-def print_line(line, highlight=False):
+def printl(line, color=None, bold=False, highlight=False):
"""A thin wrapper around curses's addstr()."""
global lineno
try:
+ flags = 0
+ if color:
+ flags |= curses.color_pair(colors_map[color])
+ if bold:
+ flags |= curses.A_BOLD
if highlight:
line += " " * (win.getmaxyx()[1] - len(line))
- win.addstr(lineno, 0, line, curses.A_REVERSE)
- else:
- win.addstr(lineno, 0, line, 0)
+ flags |= curses.A_STANDOUT
+ win.addstr(lineno, 0, line, flags)
except curses.error:
lineno = 0
win.refresh()
@@ -105,6 +102,15 @@ def poll(interval):
return (processes, procs_status)
+def get_color(perc):
+ if perc <= 30:
+ return "green"
+ elif perc <= 80:
+ return "yellow"
+ else:
+ return "red"
+
+
def print_header(procs_status, num_procs):
"""Print system-related info, above the process list."""
@@ -117,8 +123,8 @@ def print_header(procs_status, num_procs):
percs = psutil.cpu_percent(interval=0, percpu=True)
for cpu_num, perc in enumerate(percs):
dashes, empty_dashes = get_dashes(perc)
- print_line(" CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes,
- perc))
+ line = " CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes, perc)
+ printl(line, color=get_color(perc))
mem = psutil.virtual_memory()
dashes, empty_dashes = get_dashes(mem.percent)
line = " Mem [%s%s] %5s%% %6s / %s" % (
@@ -127,7 +133,7 @@ def print_header(procs_status, num_procs):
str(int(mem.used / 1024 / 1024)) + "M",
str(int(mem.total / 1024 / 1024)) + "M"
)
- print_line(line)
+ printl(line, color=get_color(mem.percent))
# swap usage
swap = psutil.swap_memory()
@@ -138,7 +144,7 @@ def print_header(procs_status, num_procs):
str(int(swap.used / 1024 / 1024)) + "M",
str(int(swap.total / 1024 / 1024)) + "M"
)
- print_line(line)
+ printl(line, color=get_color(swap.percent))
# processes number and status
st = []
@@ -146,14 +152,14 @@ def print_header(procs_status, num_procs):
if y:
st.append("%s=%s" % (x, y))
st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1)
- print_line(" Processes: %s (%s)" % (num_procs, ', '.join(st)))
+ printl(" Processes: %s (%s)" % (num_procs, ', '.join(st)))
# load average, uptime
uptime = datetime.datetime.now() - \
datetime.datetime.fromtimestamp(psutil.boot_time())
av1, av2, av3 = psutil.getloadavg()
line = " Load average: %.2f %.2f %.2f Uptime: %s" \
% (av1, av2, av3, str(uptime).split('.')[0])
- print_line(line)
+ printl(line)
def refresh_window(procs, procs_status):
@@ -164,8 +170,8 @@ def refresh_window(procs, procs_status):
header = templ % ("PID", "USER", "NI", "VIRT", "RES", "CPU%", "MEM%",
"TIME+", "NAME")
print_header(procs_status, len(procs))
- print_line("")
- print_line(header, highlight=True)
+ printl("")
+ printl(header, bold=True, highlight=True)
for p in procs:
# TIME+ column shows process CPU cumulative time and it
# is expressed as: "mm:ss.ms"
@@ -197,21 +203,42 @@ def refresh_window(procs, procs_status):
p.dict['name'] or '',
)
try:
- print_line(line)
+ printl(line)
except curses.error:
break
win.refresh()
+def setup():
+ curses.start_color()
+ curses.use_default_colors()
+ for i in range(0, curses.COLORS):
+ curses.init_pair(i + 1, i, -1)
+ curses.endwin()
+ win.nodelay(1)
+
+
+def tear_down():
+ win.keypad(0)
+ curses.nocbreak()
+ curses.echo()
+ curses.endwin()
+
+
def main():
+ setup()
try:
interval = 0
while True:
+ if win.getch() == ord('q'):
+ break
args = poll(interval)
refresh_window(*args)
interval = 1
except (KeyboardInterrupt, SystemExit):
pass
+ finally:
+ tear_down()
if __name__ == '__main__':
diff --git a/scripts/who.py b/scripts/who.py
index c2299eb0..c1e40729 100755
--- a/scripts/who.py
+++ b/scripts/who.py
@@ -8,7 +8,7 @@
A clone of 'who' command; print information about users who are
currently logged in.
-$ python scripts/who.py
+$ python3 scripts/who.py
giampaolo console 2017-03-25 22:24 loginwindow
giampaolo ttys000 2017-03-25 23:28 (10.0.2.2) sshd
"""
diff --git a/scripts/winservices.py b/scripts/winservices.py
index 8792f752..5c710159 100755
--- a/scripts/winservices.py
+++ b/scripts/winservices.py
@@ -7,7 +7,7 @@
r"""
List all Windows services installed.
-$ python scripts/winservices.py
+$ python3 scripts/winservices.py
AeLookupSvc (Application Experience)
status: stopped, start: manual, username: localSystem, pid: None
binpath: C:\Windows\system32\svchost.exe -k netsvcs