--- /dev/null
+Was too lazy to write an initscript, so made /etc/local.d/ x.start and x.stop scripts instead.
--- /dev/null
+#!/bin/bash
+/usr/sbin/gpu_usage start
--- /dev/null
+#!/bin/bash
+/usr/sbin/gpu_usage stop
+
--- /dev/null
+#!/usr/bin/python
+#Formats gpu usage data from radeontop and dumps it in /tmp/gpu_usage.txt for use in conky et al.
+import sys
+import re
+import subprocess
+import signal
+import os
+import time
+
+def write_usage(text):
+ file_handle=open('/tmp/gpu_usage.txt','w')
+ file_handle.write('%s\n'%text)
+ file_handle.close()
+
+def exit(sig,frame):
+ sys.exit()
+
+def fupdate():
+ try:
+ file_handle=open('/tmp/gpu_usage.tmp','r')
+ lines=file_handle.readlines()
+ file_handle.close()
+ except OSError:
+ write_usage('Unknown%')
+ return
+ for line in lines:
+ if re.match('.*gpu.*',line):
+ text=re.sub('.* gpu ','',line.strip())
+ text=re.sub('%.*','%',text)
+ write_usage(text)
+ return
+
+def start(fork1):
+ if fork1:return
+ signal.signal(signal.SIGUSR1, exit)#from main script stop()
+ signal.signal(signal.SIGTERM, exit)#from start-stop-daemon
+ while True:
+ try:
+ os.remove("/tmp/gpu_usage.tmp")
+ except: pass
+ subprocess.run(['/usr/sbin/radeontop','-i1','-l1','-d','/tmp/gpu_usage.tmp'],capture_output=True)
+ fupdate()
+ #time.sleep(1)
+
+def stop():
+ running=subprocess.run(['ps','aux'],capture_output=True,text=True)
+ processes=running.stdout.split('\n')
+ for process in processes:
+ if re.match('.*%s %s.*'%(sys.argv[0],'start'),process):
+ while process!=process.replace(' ',' '):process=process.replace(' ',' ')
+ pid=int(process.split(' ')[1])
+ if pid != os.getpid():os.kill(pid,signal.SIGUSR1)
+
+try:
+ command=sys.argv[1]
+except IndexError:
+ print('Usage: %s start|stop'%sys.argv[0])
+ sys.exit(1)
+if command=='start':
+ stop()
+ start(os.fork())
+elif command=='stop':
+ stop()
+else:
+ print ('Usage: %s start|stop'%sys.argv[0])
+ sys.exit(1)
--- /dev/null
+#!/sbin/openrc-run
+#openrc wrapper for /usr/sbin/spigot_service
+extra_commands="backup reload restart"
+
+depend() {
+ need net
+}
+
+start() {
+ ebegin "Starting spigot service daemon"
+ start-stop-daemon --start --exec /usr/sbin/spigot_service \
+ --pidfile /var/run/spigot_service.pid -- start
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping spigot service daemon"
+ start-stop-daemon --stop --exec /usr/sbin/spigot_service \
+ --pidfile /var/run/spigot_service.pid --retry 90 -- stop
+ eend $?
+}
+
+status() {
+ ebegin "Checking spigot service daemon status"
+ sleep 0.1
+ /usr/sbin/spigot_service status
+ eend $?
+}
+
+backup() {
+ ebegin "Running backup helper"
+ /usr/sbin/spigot_service backup
+ eend $?
+}
+
+reload() {
+ ebegin "Reloading spigot service daemon config"
+ /usr/sbin/spigot_service reload
+ eend $?
+}
+
+restart() {
+ ebegin "Restarting spigot service daemon"
+ /usr/sbin/spigot_service restart
+ eend $?
+}
--- /dev/null
+#!/usr/bin/env python3.7
+#/usr/sbin/spigot_service
+#python and screen daemonic wrapper for spigot servers
+from subprocess import Popen, run
+import os, sys, time, signal, shlex, re
+
+class server_env:
+
+ name= 'spigot'
+ working_path= '/root/bukkit/'
+ screen_history= 4096
+ world= 'Significant_Bytes'
+ backup_path= '/data/minecraft.backups/'
+ pid_file_path= '/var/run/spigot_service.pid'
+ exec= 'spigot.current'
+ options= 'nogui'
+ java_maxheap= 4096
+ java_minheap= 1024
+ thread_count= 6
+
+ java_command= 'java -Xmx%sM -Xms%sM -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing \
+ -XX:ParallelGCThreads=%s -XX:+AggressiveOpts -jar %s %s'\
+ %(java_maxheap, java_minheap, thread_count, exec, options)
+
+class ps_aux:
+
+ def get_pids(invocation):
+ pids={}
+ p=run(['ps','aux'],capture_output=True,text=True)
+ processes=p.stdout.split('\n')
+ for process in processes:
+ if re.match('.*%s.*'%invocation, process):
+ pids.append(re.sub(" +"," ", process).split(' ')[1])
+ return pids
+
+ def is_running(pid):
+ pid=str(pid)
+ p=run(['ps','aux'],capture_output=True,text=True)
+ processes=p.stdout.split('\n')
+ for process in processes:
+ if re.match('.*%s.*'%pid, process):
+ if pid==re.sub(" +", " ",process).split(' ')[1]:
+ return True
+ return False
+
+class screen:
+
+ def __init__(self, **kwargs):
+ self.name= kwargs.get('name', '')
+ self.window= kwargs.get('window', 0)
+ self.history= kwargs.get('history', 1024)
+ self.cwd= kwargs.get('set_wd', os.getcwd())
+ self.child= None
+
+ def create(self, command=''):
+ if self.child:return
+ cmd_string='/usr/bin/screen -h %s -DmS %s %s'%(self.history, self.name, command)
+ args=shlex.split(cmd_string)
+ self.child=Popen(args,cwd=self.cwd)
+
+ def send(self, input=None):
+ if not input:return
+ cmd_string='/usr/bin/screen -p %s -S %s -X stuff "%s\n"'%(self.window, self.name, input)
+ comm_child=Popen(shlex.split(cmd_string))
+ comm_child.communicate()
+
+class daemon:
+
+ def start(self):
+ try:
+ with open(server_env.pid_file_path, 'r') as pid_file:
+ pid_file.close()
+ print('Error: PID file exists, exiting...')
+ sys.exit(1)
+ except OSError:
+ pass
+ child=os.fork()
+ if child:
+ with open(server_env.pid_file_path, 'x') as pid_file:
+ pid_file.write(str(child))
+ return
+ #we are now the child daemon subprocess
+ signal.signal(signal.SIGINT, self.stop)#from ctrl-c
+ signal.signal(signal.SIGUSR1, self.stop)#from main script stop()
+ signal.signal(signal.SIGTERM, self.stop)#from start-stop-daemon
+ self.main_process=screen(name=server_env.name, history=server_env.screen_history, set_wd=server_env.working_path)
+ self.main_process.create(server_env.java_command)
+ self.main_process.child.communicate()#lets just hang about here
+ try:
+ os.remove(server_env.pid_file_path)
+ except FileNotFoundError:
+ pass
+ sys.exit(0)
+
+ def stop(self, sig, frame):
+ self.main_process.send('say Server shutting down in 10 seconds')
+ #self.main_process.send('save-off')
+ #self.main_process.send('save-all')
+ time.sleep(5)
+ self.main_process.send('say Server shutting down in 5 seconds')
+ time.sleep(1)
+ self.main_process.send('say 4')
+ time.sleep(1)
+ self.main_process.send('say 3')
+ time.sleep(1)
+ self.main_process.send('say 2')
+ time.sleep(1)
+ self.main_process.send('say 1')
+ time.sleep(1)
+ self.main_process.send('say Server shutting down...')
+ self.main_process.send('stop')
+ try:
+ os.remove(server_env.pid_file_path)
+ except FileNotFoundError:
+ pass
+ #sys.exit(0)
+#endclass
+
+def usage():
+ print('Usage: %s start|stop|status|backup|reload|restart'%sys.argv[0][sys.argv[0].rfind('/')+1:])
+ sys.exit()
+
+def start():
+ main=daemon()
+ main.start()
+
+def stop():
+ try:
+ with open(server_env.pid_file_path, 'r') as pid_file:
+ pid=int(pid_file.read())
+ os.kill(pid, 10)
+ while ps_aux.is_running(pid):
+ time.sleep(1)
+ except ProcessLookupError:
+ print('Error: process not running, removing stale PID file')
+ os.remove(server_env.pid_file_path)
+ except FileNotFoundError:
+ print('Error: PID file not found')
+
+def status():
+ try:
+ with open(server_env.pid_file_path, 'r') as pid_file:
+ pid=pid_file.read()
+ if ps_aux.is_running(pid):
+ print('World %s is running.'%server_env.world, end='',flush=True)
+ sys.exit(0)
+ else:
+ print('World %s is not running.'%server_env.world, end='',flush=True )
+ sys.exit(1)
+ except FileNotFoundError:
+ print('World %s is not running.'%server_env.world, end='',flush=True)
+ sys.exit(1)
+
+def backup():
+ print(" \033[92m*\033[0m Starting backup process ... ")
+ comm_process=screen(name=server_env.name)
+ comm_process.send('say Starting world backup...')
+ comm_process.send('save-off')
+ comm_process.send('save-all')
+ time.sleep(25)
+ backup_filename=('%s/%s-%s')%(server_env.backup_path,server_env.world,time.strftime("%Y-%m-%d_%H-%M.tar", time.gmtime()))
+ backup_command=shlex.split('tar -C "%s" -cf "%s" %s %s_nether %s_the_end'\
+ %(server_env.working_path, backup_filename, server_env.world, server_env.world, server_env.world))
+ backup_p=Popen(backup_command)
+ backup_p.communicate()
+ comm_process.send('save-on')
+ comm_process.send('say World backup complete.')
+ #print(" \033[92m*\033[0m Compressing backup ... ")
+ #compress_p=Popen(['xz', '-fT0', backup_filename])
+ #compress_p.communicate()
+ print(" \033[92m*\033[0m Backup complete.")
+
+def reload():
+ comm_process=screen(name=server_env.name)
+ comm_process.send('say Re-loading world configuration...')
+ comm_process.send('reload')
+ comm_process.send('say Re-load complete.')
+
+try:
+ arg=sys.argv[1]
+except IndexError:
+ usage()
+
+if arg=='help':
+ usage()
+elif arg=='start':
+ start()
+elif arg=='stop':
+ stop()
+elif arg=='status':
+ status()
+elif arg=='backup':
+ backup()
+elif arg=='reload':
+ reload()
+elif arg=='restart':
+ stop()
+ start()
+else:
+ usage()
--- /dev/null
+Temperature to fan speed daemon for Pi4 with https://www.waveshare.com/wiki/Fan_HAT
+
+#ToDo Write an ebuild ( yeah, right, cos that's gonna happen ;P )
--- /dev/null
+#!/sbin/openrc-run
+extra_commands="restart monitor"
+
+depend(){
+ need rpi-i2c
+}
+
+start() {
+ ebegin "Starting pitempd daemon"
+ start-stop-daemon --start --exec /usr/sbin/pitempd \
+ --pidfile /var/run/pitempd.pid -- start
+ eend $?
+}
+
+stop() {
+ ebegin "Stopping pitempd daemon"
+ start-stop-daemon --stop --exec /usr/sbin/pitempd \
+ --pidfile /var/run/pitempd.pid --signal 10 --retry 5 --stop
+ eend $?
+}
+
+status() {
+ ebegin "Checking pitempd daemon status"
+ sleep 0.1
+ /usr/sbin/pitempd status
+ eend $?
+}
+
+restart() {
+ ebegin "Restarting pitempd daemon"
+ /usr/sbin/pitempd restart
+ eend $?
+}
+
+monitor(){
+ ebegin "Monitoring pitempd daemon"
+ /usr/sbin/pitempd monitor
+ eend $?
+}
--- /dev/null
+#!/usr/bin/env python
+
+# /*****************************************************************************
+# * | File : SSD1306.py
+# * | Author : Waveshare team
+# * | Function : SSD1306
+# * | Info :
+# *----------------
+# * | This version: V1.0
+# * | Date : 2019-11-14
+# * | Info :
+# ******************************************************************************/
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documnetation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+# ^^ Included because the SSD1306 class was directly copied from the wiki code ^^ #
+
+from PIL import Image,ImageDraw,ImageFont
+from subprocess import run
+import os, sys, signal
+import re, math, time
+import smbus, psutil
+
+class PCA9685(object):
+ # Registers/etc.
+ __SUBADR1 = 0x02
+ __SUBADR2 = 0x03
+ __SUBADR3 = 0x04
+ __MODE1 = 0x00
+ __PRESCALE = 0xFE
+ __LED0_ON_L = 0x06
+ __LED0_ON_H = 0x07
+ __LED0_OFF_L = 0x08
+ __LED0_OFF_H = 0x09
+ __ALLLED_ON_L = 0xFA
+ __ALLLED_ON_H = 0xFB
+ __ALLLED_OFF_L = 0xFC
+ __ALLLED_OFF_H = 0xFD
+
+ def __init__(self, address=0x40, debug=False):
+ self.bus = smbus.SMBus(1)
+ self.address = address
+ self.debug = debug
+ if (self.debug):
+ print("Reseting PCA9685")
+ self.write(self.__MODE1, 0x00)
+
+ def write(self, reg, value):
+ "Writes an 8-bit value to the specified register/address"
+ self.bus.write_byte_data(self.address, reg, value)
+ if (self.debug):
+ print("I2C: Write 0x%02X to register 0x%02X" % (value, reg))
+
+ def read(self, reg):
+ "Read an unsigned byte from the I2C device"
+ result = self.bus.read_byte_data(self.address, reg)
+ if (self.debug):
+ print("I2C: Device 0x%02X returned 0x%02X from reg 0x%02X" % (self.address, result & 0xFF, reg))
+ return result
+
+ def setPWMFreq(self, freq):
+ "Sets the PWM frequency"
+ prescaleval = 25000000.0 # 25MHz
+ prescaleval /= 4096.0 # 12-bit
+ prescaleval /= float(freq)
+ prescaleval -= 1.0
+ if (self.debug):
+ print("Setting PWM frequency to %d Hz" % freq)
+ print("Estimated pre-scale: %d" % prescaleval)
+ prescale = math.floor(prescaleval + 0.5)
+ if (self.debug):
+ print("Final pre-scale: %d" % prescale)
+
+ oldmode = self.read(self.__MODE1);
+ newmode = (oldmode & 0x7F) | 0x10 # sleep
+ self.write(self.__MODE1, newmode) # go to sleep
+ self.write(self.__PRESCALE, int(math.floor(prescale)))
+ self.write(self.__MODE1, oldmode)
+ time.sleep(0.005)
+ self.write(self.__MODE1, oldmode | 0x80)
+
+ def setPWM(self, channel, on, off):
+ "Sets a single PWM channel"
+ self.write(self.__LED0_ON_L+4*channel, on & 0xFF)
+ self.write(self.__LED0_ON_H+4*channel, on >> 8)
+ self.write(self.__LED0_OFF_L+4*channel, off & 0xFF)
+ self.write(self.__LED0_OFF_H+4*channel, off >> 8)
+ if (self.debug):
+ print("channel: %d LED_ON: %d LED_OFF: %d" % (channel,on,off))
+
+ def setServoPulse(self, channel, pulse):
+ pulse = pulse*4095/100
+ self.setPWM(channel, 0, int(pulse))
+#end pwm class
+
+class SSD1306(object):
+ def __init__(self, width=128, height=32, addr=0x3c):
+ self.width = width
+ self.height = height
+ self.Column = width
+ self.Page = int(height/8)
+ self.addr = addr
+ self.bus = smbus.SMBus(1)
+
+ def SendCommand(self, cmd):# write command
+ self.bus.write_byte_data(self.addr, 0x00, cmd)
+
+ def SendData(self, cmd):# write ram
+ self.bus.write_byte_data(self.addr, 0x40, cmd)
+
+ def Closebus(self):
+ self.bus.close()
+
+ def Init(self):
+ self.SendCommand(0xAE)
+
+ self.SendCommand(0x40) # set low column address
+ self.SendCommand(0xB0) # set high column address
+
+ self.SendCommand(0xC8) # not offset
+
+ self.SendCommand(0x81)
+ self.SendCommand(0xff)
+
+ self.SendCommand(0xa1)
+
+ self.SendCommand(0xa6)
+
+ self.SendCommand(0xa8)
+ self.SendCommand(0x1f)
+
+ self.SendCommand(0xd3)
+ self.SendCommand(0x00)
+
+ self.SendCommand(0xd5)
+ self.SendCommand(0xf0)
+
+ self.SendCommand(0xd9)
+ self.SendCommand(0x22)
+
+ self.SendCommand(0xda)
+ self.SendCommand(0x02)
+
+ self.SendCommand(0xdb)
+ self.SendCommand(0x49)
+
+ self.SendCommand(0x8d)
+ self.SendCommand(0x14)
+
+ self.SendCommand(0xaf)
+
+ def ClearBlack(self):
+ for i in range(0, self.Page):
+ self.SendCommand(0xb0 + i)
+ self.SendCommand(0x00)
+ self.SendCommand(0x10)
+ for j in range(0, self.Column):
+ self.SendData(0x00)
+
+ def ClearWhite(self):
+ for i in range(0, self.Page):
+ self.SendCommand(0xb0 + i)
+ self.SendCommand(0x00)
+ self.SendCommand(0x10)
+ for j in range(0, self.Column):
+ self.SendData(0xff)
+
+ def getbuffer(self, image):
+ buf = [0xff] * (self.Page * self.Column)
+ image_monocolor = image.convert('1')
+ imwidth, imheight = image_monocolor.size
+ pixels = image_monocolor.load()
+ if(imwidth == self.width and imheight == self.height):
+ # print ("Horizontal screen")
+ for y in range(imheight):
+ for x in range(imwidth):
+ # Set the bits for the column of pixels at the current position.
+ if pixels[x, y] == 0:
+ buf[x + int(y / 8) * self.width] &= ~(1 << (y % 8))
+ elif(imwidth == self.height and imheight == self.width):
+ # print ("Vertical screen")
+ for y in range(imheight):
+ for x in range(imwidth):
+ newx = y
+ newy = self.height - x - 1
+ if pixels[x, y] == 0:
+ buf[(newx + int(newy / 8 )*self.width) ] &= ~(1 << (y % 8))
+ for x in range(self.Page * self.Column):
+ buf[x] = ~buf[x]
+ return buf
+
+ def ShowImage(self, pBuf):
+ for i in range(0, self.Page):
+ self.SendCommand(0xB0 + i) # set page address
+ self.SendCommand(0x00) # set low column address
+ self.SendCommand(0x10) # set high column address
+ # write data #
+ for j in range(0, self.Column):
+ self.SendData(pBuf[j+self.width*i])
+#end oled class
+
+
+#start of #mycode
+class ps:
+
+ def get_pids(invocation):
+ pids=[]
+ p=run(['ps','aux'],capture_output=True,text=True)
+ processes=p.stdout.split('\n')
+ for process in processes:
+ if re.match('.*%s.*'%invocation, process):
+ pids.append(int(re.sub(" +"," ", process).split(' ')[1]))
+ return pids
+
+ def is_running(pid):
+ pid=str(pid)
+ p=run(['ps','aux'],capture_output=True,text=True)
+ processes=p.stdout.split('\n')
+ for process in processes:
+ if re.match('.*%s.*'%pid, process):
+ if pid==re.sub(" +", " ",process).split(' ')[1]:
+ return True
+ return False
+#end ps class
+
+class daemon:
+ pid_file_path='/var/run/pitempd.pid'
+ fan_speed_path='/var/run/pitempd.pwm'
+ cpu_temp_path='/sys/class/hwmon/hwmon0/temp1_input'
+ fan_disable_temp=45
+
+ default_fan_speed=0
+ fan_min_speed=40
+ fan_max_speed=100
+ update_time=2.5
+ debug=True
+
+ def __init__(self):
+ self.pwm=PCA9685(0x40, debug=False)
+ self.pwm.setPWMFreq(50)
+ self.pwm.setServoPulse(0,100)
+ self.oled = SSD1306()
+ self.oled.Init()
+ self.oled.ClearBlack()
+ self.image1 = Image.new('1', (self.oled.width, self.oled.height), "WHITE")
+ self.draw = ImageDraw.Draw(self.image1)
+ self.font = ImageFont.load_default()
+
+ def curve(self, x):
+ if x <= self.fan_disable_temp:
+ return self.default_fan_speed
+ #y = (((x−40)/5.5)^2.4)+40 (curve from Kmplot)
+ y=(((x-self.fan_disable_temp)/5.5)**2.4)+self.fan_min_speed
+ if y > self.fan_max_speed:
+ y=self.fan_max_speed
+ return y
+
+ def start(self):
+ try:
+ with open(self.pid_file_path, 'r') as pid_file:
+ pid_file.close()
+ print('Error: PID file exists, exiting...')
+ sys.exit(1)
+ except OSError:
+ pass
+ child=os.fork()
+ if child:
+ with open(self.pid_file_path, 'x') as pid_file:
+ pid_file.write(str(child))
+ return
+ signal.signal(signal.SIGINT, self.stop)#from ctrl-c
+ signal.signal(signal.SIGUSR1, self.stop)#from main script stop()
+ signal.signal(signal.SIGTERM, self.stop)#from start-stop-daemon
+ #Main loop
+ top_line=True
+ while True:
+ if top_line:
+ cpu_string='CPU Usage:'
+ cpu_stat='%s%%'%int(psutil.cpu_percent(interval=self.update_time))
+ else:
+ cpu_string='CPU Speed:'
+ cpu_stat='%sMHz'%int(psutil.cpu_freq().current)
+ time.sleep(self.update_time)
+ top_line=not top_line
+ temp=self.get_temp()
+ fan=self.curve(temp)
+ with open(self.fan_speed_path, 'w') as pwm_file:
+ pwm_file.write('%.1f%%\n'%fan)
+ self.set_fan(fan)
+ self.set_display( cpu_string,cpu_stat, \
+ 'CPU Temp:', '%.1f°C'%temp, \
+ 'Fan Speed:', '%.1f%%'%fan)
+
+ def get_temp(self):
+ with open(self.cpu_temp_path, 'r') as temp_file:
+ temp=int(temp_file.read())/1000
+ return temp
+
+ def set_fan(self,speed):
+ self.pwm.setServoPulse(0,speed)
+
+ def set_display(self,upper_left, upper_right,mid_left, mid_right, lower_left='test', lower_right='test'):
+ self.draw.rectangle((0,0,128,32), fill = 1)
+ self.draw.text((0,0), upper_left, font=self.font, fill = 0)
+ self.draw.text((85,0), upper_right, font=self.font, fill = 0)
+ self.draw.text((0,11), mid_left, font=self.font, fill = 0)
+ self.draw.text((85,11), mid_right, font=self.font, fill = 0)
+ self.draw.text((0,22), lower_left, font=self.font, fill = 0)
+ self.draw.text((85,22), lower_right, font=self.font, fill = 0)
+ self.oled.ShowImage(self.oled.getbuffer(self.image1.rotate(180)))
+
+ def stop(self, sig, frame):
+ self.set_fan(self.default_fan_speed)
+ with open(self.fan_speed_path, 'w') as pwm_file:
+ pwm_file.write('%.1f%%\n'%self.default_fan_speed)
+ self.draw.rectangle((0,0,128,32), fill = 1)
+ self.draw.text((40,0),'Daemon', font=self.font, fill = 0)
+ self.draw.text((38,11),'Offline', font=self.font, fill = 0)
+ self.draw.text((0,22), 'Fan Speed:', font=self.font, fill = 0)
+ self.draw.text((85,22), '%.1f%%'%self.default_fan_speed, font=self.font, fill = 0)
+ self.oled.ShowImage(self.oled.getbuffer(self.image1.rotate(180)))
+ self.oled.Closebus()
+ try:
+ os.remove(daemon.pid_file_path)
+ except FileNotFoundError:
+ pass
+ sys.exit(0)
+
+#end daemon class
+
+def usage():
+ print('Usage: %s start|stop|status|monitor|restart'%sys.argv[0][sys.argv[0].rfind('/')+1:])
+ sys.exit()
+
+def start():
+ main=daemon()
+ main.start()
+
+def stop():
+ try:
+ with open(daemon.pid_file_path, 'r') as pid_file:
+ pid=int(pid_file.read())
+ os.kill(pid, 10)
+ while ps.is_running(pid): time.sleep(1)
+ except ProcessLookupError:
+ print('Error: process not running, removing stale PID file')
+ os.remove(daemon.pid_file_path)
+ except FileNotFoundError:
+ print('Error: PID file not found, checking for process...', end='',flush=True)
+ pids=ps.get_pids('%s start'%sys.argv[0])
+ if pids:
+ for pid in pids:
+ print(' killing process: %s'%pid)
+ os.kill(pid, 10)
+ while ps.is_running(pid): time.sleep(1)
+ else:
+ print(' daemon not running.')
+ sys.exit(0)
+
+def status():
+ try:
+ with open(daemon.pid_file_path, 'r') as pid_file:
+ pid=pid_file.read()
+ if ps.is_running(pid):
+ sys.exit(0)
+ else:
+ sys.exit(1)
+ except FileNotFoundError:
+ sys.exit(1)
+
+def monstop(sig, f):
+ print('Exiting: %s'%sig)
+ sys.exit(0)
+
+def monitor():
+ signal.signal(signal.SIGINT, monstop)#from ctrl-c
+ signal.signal(signal.SIGUSR1, monstop)#from main script stop()
+ signal.signal(signal.SIGTERM, monstop)#from start-stop-daemon
+ cpu_usage='Waiting...'
+ while True:
+ with open(daemon.cpu_temp_path, 'r') as temp_file:
+ temp=int(temp_file.read())/100
+ with open(daemon.fan_speed_path, 'r') as pwm_file:
+ str=pwm_file.read()
+ pwm=float(str[:-2])
+ try:
+ with open(daemon.pid_file_path, 'r') as pid_file:
+ pid=pid_file.read()
+ except FileNotFoundError:
+ pid='Not running'
+ cpu_mhz='%sMHz'%int(psutil.cpu_freq().current)
+ print('Daemon PID:',pid)
+ print('CPU Speed: ',cpu_mhz)
+ print('CPU Usage: ',cpu_usage)
+ print('CPU Temp: ','%s°C'%(int(temp)/10))
+ print('Fan Speed: ','%.1f%%'%pwm)
+ print()
+ cpu_usage='%s%%'%int(psutil.cpu_percent(interval=daemon.update_time))
+
+try:
+ arg=sys.argv[1]
+except IndexError:
+ usage()
+
+if arg=='help':
+ usage()
+elif arg=='start':
+ start()
+elif arg=='stop':
+ stop()
+elif arg=='status':
+ status()
+elif arg=='restart':
+ stop()
+ start()
+elif arg=='monitor':
+ monitor()
+else:
+ usage()
--- /dev/null
+#!/bin/bash
+# check the files generated by the python_3_9_compat.sh script that crawls the portage tree
+# usage python3_9-py-checker <path/to/file>
+log_file="/run/user/$UID/pycheker.log"
+#stolen from something in ~/bin/
+prog=('\' '|' '/' '-' 'done!')
+prog_ind=0
+function progress(){
+ echo -ne "\033[1K\r$* ${prog[${prog_ind}]}"
+ (( ++ prog_ind ))
+ [ ${prog_ind} -gt 3 ] && prog_ind=0
+}
+function end_progress(){
+ echo -e "\033[1K\r$* ${prog[4]}"
+}
+#end-stolen
+function log(){
+ echo "DEBUG: $1 failed due to $2" >> "${log_file}"
+ return 0
+}
+echo -n > "${log_file}"
+safelist=""
+for ebuild in $*
+do
+ echo -n "Running: ebuild ${ebuild} prepare"
+ workdir=$(USE="python_single_target_python3_8 python_targets_python3_8" ebuild "${ebuild}" prepare 2>&1 |tee -a "${log_file}"|awk '/Preparing source in/{print $5};/Remove.*\.prepared/{print $3}') || break
+ workdir=${workdir#\'}
+ workdir=${workdir%.prepared\'}
+ accept=true
+ echo " done!"
+ if [ -d "${workdir}" ]
+ then
+ while read file
+ do
+ progress "Checking py files for ${ebuild}"
+
+ error="__import__() now raises ImportError instead of ValueError"
+ awk '/try:/{intry=1;impused=0};/__import__/ && intry{impused=1};intry && impused{print};/except|finally:/{intry=0}' "${file}" | grep -q "ValueError" && accept=false && log "$ebuild" "$error" && break
+
+ error="importlib.util.resolve_name() now raise ImportError"
+ grep -qw "importlib" "$file" && awk '/try:/{intry=1;impused=0};/resolve_name/{impused=1};intry && impused{print};/except|finally:/{intry=0}' "${file}" | grep -q "ValueError" && accept=false && log "$ebuild" "$error" && break
+
+ error="The venv activation scripts no longer special-case when __VENV_PROMPT__ is set to ""."
+ grep -q "from.*venv.*import\|import.*venv" "$file" && grep -q "__VENV_PROMPT__" "$file" && accept=false && log "$ebuild" "$error" && break
+ #it's set by default to non null, we only have to find it being reassigned.
+
+ #error="The compresslevel parameter of bz2.BZ2File became keyword-only"
+ grep -q "from.*bz2.*import\|import.*bz2" "$file" && grep -q "BZ2File" "$file"|grep -qv "compresslevel=" && accept=false && log "$ebuild" "$error" && break
+ #catching references
+
+ error="Simplified AST for subscription."
+ grep -q "from.*ast.*import\|import.*ast" "$file" && grep -q "issubclass\|visit_Num" "$file" && accept=false && log "$ebuild" "$error" && break #lots of manual checking needed
+
+ error="The encoding parameter has been added to the classes ftplib.FTP and ftplib.FTP_TLS"
+ grep -q "from.*ftplib.*import\|import.*ftplib" "$file" && grep -q "FTP\|FTP_TLS" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="asyncio.loop.shutdown_default_executor() has been added to AbstractEventLoop"
+ grep -q "from.*asyncio.*import\|import.*asyncio" "$file" && grep -q "class.*(.*loop):" "$file" && accept=false && log "$ebuild" "$error" && break
+ #need to refine this to instances only, unless it's inherited we don't care
+
+ error="The logging.getLogger() API now returns the root logger when passed the name 'root'" #careful, possible security issue
+ grep -q "from.*logging.*import\|import.*logging" "$file" && grep -q "getLogger(.*'root'.*)" "$file" && accept=false && log "$ebuild" "$error" && break
+ #directly exclude getLogger('root') calls
+ grep -q "from.*logging.*import\|import.*logging" "$file" && grep -qv "getLogger(.*'" "$file"| grep -q "getLogger" && accept=false && log "$ebuild" "$error" && break
+ #don't exclude if getLogger is called directly with a static name, but exclude variable and referenced calls to getLogger
+
+ error="Division handling of PurePath now returns NotImplemented instead of raising a TypeError"
+ grep -q "from.*pathlib.*import\|import.*pathlib" "$file" && grep -q "PurePath" "$file" && grep -q "TypeError" "$file" && accept=false && log "$ebuild" "$error" && break
+ #may need to awk this...
+
+ error="Starting with Python 3.9.5 the ipaddress module no longer accepts any leading zeros in IPv4 address strings."
+ grep -q "from.*ipaddress.*import\|import.*ipaddress" "$file" && grep -q "IPv4Address\|IPv4Network\|IPv4Interface\|collapse_addresses\|ip_address\|ip_interface\|ip_network\|summarize_address_range" "$file" && accept=false && log "$ebuild" "$error" && break
+ #Much grief :(
+
+ error="codecs.lookup() now normalizes the encoding name"
+ grep -q "from.*codecs.*import\|import.*codecs" "$file" && grep -q "lookup" "$file" && accept=false && log "$ebuild" "$error" && break
+ #much pain to check for :( should exclude for expediency and let upstream -> upstream sort it
+
+ done < <(find "${workdir}" -iname '*.py')
+ end_progress "Checking py files for ${ebuild}"
+ while read file
+ do
+ progress "Checking C files for ${ebuild}"
+
+ error="PyInterpreterState.eval_frame (PEP 523) now requires a new mandatory tstate parameter"
+ grep -q "PyInterpreterState" "$file" && grep -q "eval_frame" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="Extension modules: m_traverse, m_clear and m_free functions of PyModuleDef are no longer called"
+ grep -q "PyModuleDef" "$file" && "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="Removed _PyRuntime.getframe hook and removed _PyThreadState_GetFrame also PyThreadFrameGetter"
+ grep -q "_PyRuntime" "$file" && grep -q "getframe" "$file" && accept=false && log "$ebuild" "$error" && break
+ grep -q " _PyThreadState_GetFrame\|PyThreadFrameGetter" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="removed PyAsyncGen_ClearFreeLists() PyContext_ClearFreeList() PyDict_ClearFreeList() PyFloat_ClearFreeList()"
+ grep -q "PyAsyncGen_ClearFreeLists\|PyContext_ClearFreeList\|PyDict_ClearFreeList\|PyFloat_ClearFreeList" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="removed PyFrame_ClearFreeList() PyList_ClearFreeList() PyMethod_ClearFreeList() PyCFunction_ClearFreeList() "
+ grep -q "PyFrame_ClearFreeList\|PyList_ClearFreeList\|PyMethod_ClearFreeList\|PyCFunction_ClearFreeList" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="removed PySet_ClearFreeList() PyTuple_ClearFreeList() PyUnicode_ClearFreeList()"
+ grep -q "PySet_ClearFreeList\|PyTuple_ClearFreeLis\|PyUnicode_ClearFreeList" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="removed PyBytes_InsertThousandsGroupingLocale, _PyBytes_InsertThousandsGrouping, _Py_InitializeFromArgs"
+ grep -q "PyBytes_InsertThousandsGroupingLocale\|_PyBytes_InsertThousandsGrouping\|_Py_InitializeFromArgs" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="removed _Py_InitializeFromWideArgs, _PyFloat_Repr, _PyFloat_Digits, _PyFloat_DigitsInit, PyFrame_ExtendStack, "
+ grep -q "_Py_InitializeFromWideArgs\|_PyFloat_Repr\|_PyFloat_Digits\|PyFrame_ExtendStack" "$file" && accept=false && log "$ebuild" "$error" && break
+
+ error="removed PyNullImporter_Type, PyCmpWrapper_Type, PySortWrapper_Type, PyNoArgsFunction _PyAIterWrapper_Type,"
+ grep -q "PyNullImporter_Type\|PyCmpWrapper_Type\|PySortWrapper_Type\|PyNoArgsFunction\|_PyAIterWrapper_Type" "$file" && accept=false && log "$ebuild" "$error" && break
+ done < <(find "${workdir}" -regex "*.\.[c,h,cpp]")
+ end_progress "Checking C files for ${ebuild}"
+ $accept && safelist="${safelist} ${ebuild}"
+ fi
+done
+
+echo -e "${safelist// /\\n}\nare safe to add 3_9 support without patching"
+
--- /dev/null
+#!/bin/bash
+# Check the files generated by the python_3_9_compat.sh script that crawls the portage tree, and log the failure points
+# The other script exits the source code path on first failure and moves on, this one doesn't
+# usage python3_9-py-checker <path/to/file>
+log_file="/run/user/$UID/pylogger.log"
+#stolen from something in ~/bin/
+prog=('\' '|' '/' '-' 'done!')
+prog_ind=0
+function progress(){
+ echo -ne "\033[1K\r$* ${prog[${prog_ind}]}"
+ (( ++ prog_ind ))
+ [ ${prog_ind} -gt 3 ] && prog_ind=0
+}
+function end_progress(){
+ echo -e "\033[1K\r$* ${prog[4]}"
+}
+#end-stolen
+function log(){
+ echo "DEBUG: $1 failed due to $2" >> "${log_file}"
+ return 0
+}
+echo -n > "${log_file}"
+safelist=""
+for ebuild in $*
+do
+ echo -n "Running: ebuild ${ebuild} prepare"
+ workdir=$(USE="python_single_target_python3_8 python_targets_python3_8" ebuild "${ebuild}" prepare 2>&1 |awk '/Preparing source in/{print $5};/Remove.*\.prepared/{print $3}') || break
+ workdir=${workdir#\'}
+ workdir=${workdir%.prepared\'}
+ echo " done!"
+ if [ -d "${workdir}" ]
+ then
+ accept=true
+ while read file
+ do
+ progress "Checking py files for ${ebuild}"
+
+ error="__import__() now raises ImportError instead of ValueError"
+ awk '/try:/{intry=1;impused=0};/__import__/ && intry{impused=1};intry && impused{print};/except|finally:/{intry=0}' "${file}" | grep -q "ValueError" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="importlib.util.resolve_name() now raise ImportError"
+ grep -qw "importlib" "$file" && awk '/try:/{intry=1;impused=0};/resolve_name/{impused=1};intry && impused{print};/except|finally:/{intry=0}' "${file}" | grep -q "ValueError" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="The venv activation scripts no longer special-case when __VENV_PROMPT__ is set to ""."
+ grep -q "from.*venv.*import\|import.*venv" "$file" && grep -q "__VENV_PROMPT__" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ #it's set by default to non null, we only have to find it being reassigned.
+
+ #error="The compresslevel parameter of bz2.BZ2File became keyword-only"
+ grep -q "from.*bz2.*import\|import.*bz2" "$file" && grep -q "BZ2File" "$file"|grep -qv "compresslevel=" && accept=false && log "$ebuild" "$error" #&& break
+ #catching references
+
+ error="Simplified AST for subscription."
+ grep -q "from.*ast.*import\|import.*ast" "$file" && grep -q "issubclass\|visit_Num" "$file" && accept=false && log "$ebuild" "$error" #&& break #lots of manual checking needed
+
+ error="The encoding parameter has been added to the classes ftplib.FTP and ftplib.FTP_TLS"
+ grep -q "from.*ftplib.*import\|import.*ftplib" "$file" && grep -q "FTP\|FTP_TLS" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="asyncio.loop.shutdown_default_executor() has been added to AbstractEventLoop"
+ grep -q "from.*asyncio.*import\|import.*asyncio" "$file" && grep -q "class.*(.*loop):" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ #need to refine this to instances only, unless it's inherited we don't care
+
+ error="The logging.getLogger() API now returns the root logger when passed the name 'root'" #careful, possible security issue
+ grep -q "from.*logging.*import\|import.*logging" "$file" && grep -q "getLogger(.*'root'.*)" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ #directly exclude getLogger('root') calls
+ grep -q "from.*logging.*import\|import.*logging" "$file" && grep -qv "getLogger(.*'" "$file"| grep -q "getLogger" && accept=false && log "$ebuild" "$error" #&& break
+ #don't exclude if getLogger is called directly with a static name, but exclude variable and referenced calls to getLogger
+
+ error="Division handling of PurePath now returns NotImplemented instead of raising a TypeError"
+ grep -q "from.*pathlib.*import\|import.*pathlib" "$file" && grep -q "PurePath" "$file" && grep -q "TypeError" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ #may need to awk this...
+
+ error="Starting with Python 3.9.5 the ipaddress module no longer accepts any leading zeros in IPv4 address strings."
+ grep -q "from.*ipaddress.*import\|import.*ipaddress" "$file" && grep -q "IPv4Address\|IPv4Network\|IPv4Interface\|collapse_addresses\|ip_address\|ip_interface\|ip_network\|summarize_address_range" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ #Much grief :(
+
+ error="codecs.lookup() now normalizes the encoding name"
+ grep -q "from.*codecs.*import\|import.*codecs" "$file" && grep -q "lookup" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ #much pain to check for :( should exclude for expediency and let upstream -> upstream sort it
+
+ done < <(find "${workdir}" -iname '*.py')
+ end_progress "Checking py files for ${ebuild}"
+ while read file
+ do
+ progress "Checking C files for ${ebuild}"
+
+ error="PyInterpreterState.eval_frame (PEP 523) now requires a new mandatory tstate parameter"
+ grep -q "PyInterpreterState" "$file" && grep -q "eval_frame" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="Extension modules: m_traverse, m_clear and m_free functions of PyModuleDef are no longer called"
+ grep -q "PyModuleDef" "$file" && "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="Removed _PyRuntime.getframe hook and removed _PyThreadState_GetFrame also PyThreadFrameGetter"
+ grep -q "_PyRuntime" "$file" && grep -q "getframe" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ grep -q " _PyThreadState_GetFrame\|PyThreadFrameGetter" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="removed PyAsyncGen_ClearFreeLists() PyContext_ClearFreeList() PyDict_ClearFreeList() PyFloat_ClearFreeList()"
+ grep -q "PyAsyncGen_ClearFreeLists\|PyContext_ClearFreeList\|PyDict_ClearFreeList\|PyFloat_ClearFreeList" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="removed PyFrame_ClearFreeList() PyList_ClearFreeList() PyMethod_ClearFreeList() PyCFunction_ClearFreeList() "
+ grep -q "PyFrame_ClearFreeList\|PyList_ClearFreeList\|PyMethod_ClearFreeList\|PyCFunction_ClearFreeList" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="removed PySet_ClearFreeList() PyTuple_ClearFreeList() PyUnicode_ClearFreeList()"
+ grep -q "PySet_ClearFreeList\|PyTuple_ClearFreeLis\|PyUnicode_ClearFreeList" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="removed PyBytes_InsertThousandsGroupingLocale, _PyBytes_InsertThousandsGrouping, _Py_InitializeFromArgs"
+ grep -q "PyBytes_InsertThousandsGroupingLocale\|_PyBytes_InsertThousandsGrouping\|_Py_InitializeFromArgs" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="removed _Py_InitializeFromWideArgs, _PyFloat_Repr, _PyFloat_Digits, _PyFloat_DigitsInit, PyFrame_ExtendStack, "
+ grep -q "_Py_InitializeFromWideArgs\|_PyFloat_Repr\|_PyFloat_Digits\|PyFrame_ExtendStack" "$file" && accept=false && log "$ebuild" "$error" #&& break
+
+ error="removed PyNullImporter_Type, PyCmpWrapper_Type, PySortWrapper_Type, PyNoArgsFunction _PyAIterWrapper_Type,"
+ grep -q "PyNullImporter_Type\|PyCmpWrapper_Type\|PySortWrapper_Type\|PyNoArgsFunction\|_PyAIterWrapper_Type" "$file" && accept=false && log "$ebuild" "$error" #&& break
+ done < <(find "${workdir}" -regex "*.\.[c,h,cpp]")
+ end_progress "Checking C files for ${ebuild}"
+ $accept && safelist="${safelist} ${ebuild}"
+ fi
+done
+
+echo -e "${safelist// /\\n}\nare safe to add 3_9 support without patching"
+
--- /dev/null
+#!/bin/bash
+# 3.9_compat-2.sh build lists of ebuilds that need updating for python3_9 compatability
+# stuff that's maybe worth altering
+[ -d "${REPO_PATH}" ] ||\
+REPO_PATH="/var/db/repos/updating"
+[ -z "${ARCH}" ] &&\
+ARCH="amd64"
+base_path="/run/user/${UID}/py-3_9-compat-v2.${REPO_PATH##*/}"
+# stuff that's not worth altering
+stable_list="${base_path}.stable.list"
+testing_list="${base_path}.testing.list"
+wip_list="${base_path}.wip.list"
+considerlist="${base_path}.maybe-wip.list"
+commands=$*
+message=""
+function finish {
+ tput cnorm
+ echo -e "$message"
+}
+trap finish EXIT
+#stolen from something in ~/bin/
+prog=('\' '|' '/' '-' 'done!')
+prog_ind=0
+function progress(){
+ echo -ne "\033[1K\r$* ${prog[${prog_ind}]}"
+ (( ++ prog_ind ))
+ [ ${prog_ind} -gt 3 ] && prog_ind=0
+}
+function end_progress(){
+ echo -e "\033[1K\r$* ${prog[4]}"
+}
+#end-stolen
+function build(){ #create a list of all ebuilds as a starting base
+ rm -f "${base_path}"*list
+ progress "Building master ebuild lists"
+ find "${REPO_PATH}/" -mindepth 3 -maxdepth 3 -name '*.ebuild' -a ! -name '*9999*' ! -iname '*-[0-9]*alpha*'|xargs grep -lw "PYTHON_COMPAT" -- |xargs grep -lw "KEYWORD.*~${ARCH}" -- >"${testing_list}.tmp"
+ progress "Building master ebuild lists"
+ sort -Vr "${testing_list}.tmp" > "${testing_list}" && rm -f "${testing_list}.tmp"
+ progress "Building master ebuild lists"
+ find "${REPO_PATH}/" -mindepth 3 -maxdepth 3 -name '*.ebuild' -a ! -name '*9999*' ! -iname '*-[0-9]*alpha*'|xargs grep -lw "PYTHON_COMPAT" -- |xargs grep -lw "KEYWORD.* ${ARCH}\|KEYWORD.*\"${ARCH}" -- >"${stable_list}.tmp"
+ progress "Building master ebuild lists"
+ sort -Vr "${stable_list}.tmp" > "${stable_list}" && rm -f "${stable_list}.tmp"
+ end_progress "Building master ebuild lists"
+}
+function filter_list(){
+ while read ebuild
+ do
+ progress "Filtering compatible packages in ${1}"
+ atompath="${ebuild%-[0-9]*}";atompath="${atompath//\//\\/}"
+ if grep "python3_" ${ebuild}|grep -q "3_9\|,9\|\.\.9\|\.\.10"
+ then
+ [[ "${2}" == "do_wip" ]] && echo $ebuild >> $wip_list
+ sed -i "/${atompath}/d" "${1}"
+ else
+ sed -i "0,/${atompath}/{s/${atompath}/RESTORE_ME/};/${atompath}-[0-9].*/d;s/RESTORE_ME/${atompath}/" ${1}
+ fi
+ done < "${1}"
+}
+function filter_stable(){ #filter the compatible ebuilds from the stable_list
+ filter_list "${stable_list}"
+ end_progress "Filtering compatible packages in ${stable_list}"
+ [ -f $stable_list ] && message="${message}\nList of $(wc -l < ${stable_list}) non-compatible packages in: $stable_list"
+}
+function filter_testing(){ #filter the compatible ebuilds from the testing_list, build a compatible ebuilds list to further filter stable_list later
+ filter_list "${testing_list}" "do_wip"
+ end_progress "Filtering compatible packages in ${testing_list}"
+ [ -f $testing_list ] && message="${message}\nList of $(wc -l < ${testing_list}) non-compatible packages in: $testing_list"
+}
+function filter_wip(){ #remove duplicates package atoms
+ while read ebuild
+ do
+ progress "Filtering duplicate wip packages"
+ atompath="${ebuild%-[0-9]*}"
+ atompath="${atompath//\//\\/}"
+ sed -i "0,/${atompath}/{s/${atompath}/RESTORE_ME/};/${atompath}-[0-9].*/d;s/RESTORE_ME/${atompath}/" ${wip_list}
+ done < "${wip_list}"
+ end_progress "Filtering duplicate wip packages"
+}
+function check_wip(){ #filter the stable_list and log changes
+ echo -n >"${considerlist}"
+ for ebuild in $(grep -e "-r[0-9][0-9]*.ebuild" ${wip_list})
+ do
+ progress "Checking for wip packages"
+ [[ "$ebuild" =~ (.*)-r([0-9]*[0-9]).ebuild ]]
+ revision="${BASH_REMATCH[2]}"
+ (( -- revision ))
+ if [ $revision -gt 0 ]
+ then #look for a previous revision
+ temp=${revision:1}
+ revision=${revision:${#temp}}
+ poss_ebuild=$(echo "$ebuild"|sed "s/\(.*-r[0-9]*\)[0-9].ebuild/\1[0-9]*[0-$revision].ebuild/")
+ else #look for an unrevised similar version
+ poss_ebuild=$(echo "$ebuild"|sed "s/\(.*\)-r[0-9]*[0-9].ebuild/\1.ebuild/")
+ fi
+ poss_fix=$(grep "${poss_ebuild}" ${stable_list})&&\
+ echo "$(echo ${ebuild}|sed 's/.*\/\(.*\/.*\/.*\)/\1/') seems to be a fix for $(echo ${poss_fix}|sed 's/.*\/\(.*\/.*\/.*\)/\1/')" >>"${considerlist}" &&\
+ sed_fix=$(echo ${poss_fix%-[0-9]*}|sed 's/\//\\\//g')&&\
+ sed -i "/${sed_fix}-[0-9].*/d" ${stable_list}
+ done
+ end_progress "Checking for wip packages"
+ if [ -f $considerlist ]
+ then
+ message="\nList of $(wc -l <${considerlist}) already fixed stable packages in: $considerlist${message}"
+ echo -e "\n\n*** The above packages have been removed from ${stable_list} ***" >>$considerlist
+ echo "*** This file is for logging purposes only. ***" >>$considerlist
+ fi
+}
+function all(){ #do everything
+ build
+ filter_testing
+ filter_stable
+ filter_wip
+ check_wip
+}
+function main(){ #cheesy hack for now...
+ for command in $commands
+ do
+ $command
+ done
+}
+function usage(){ #need to expand
+ echo -e "Usage: ${0##*/} <command(s)>
+ Where <command(s)> is one or more of [build|filter_testing|filter_stable|filter_wip|check_wip]
+ Use commands in the shown order, as each is dependant on the previous.
+ The special command [all] can be used to run a full scan and show results.
+ REPO_PATH (default /var/db/repos/gentoo) and ARCH (default amd64) can be set on the command line, e.g.\n
+ REPO_PATH=\"/usr/aarch64-unknown-linux-gnu/var/db/repos/gentoo\" ARCH=\"arm64\" ${0##*/} all\n"
+}
+if [ $# -gt 0 ] #do shit
+then
+ tput civis
+ main
+else
+ usage
+fi
+
--- /dev/null
+#!/bin/bash
+#Force monitor into existance because X won't do as it's told.
+xrandr --setmonitor +HDMI-A-0 1920/531x1080/299+1920+0 HDMI-A-0
+xrandr --newmode "TVMode" 148.50 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync
+xrandr --addmode HDMI-A-0 TVMode
+xrandr --output HDMI-A-0 --mode TVMode --right-of DisplayPort-0
--- /dev/null
+#!/bin/bash
+#Reads /proc/mounts and performs a lazy, forced un-mount of any nfs file systems if the server does not respond to ping
+cat /proc/mounts >/tmp/NFSumount_mounts.tmp
+
+DEBUG=false
+PRETEND=false
+
+while read line;do
+ if ! echo $line |awk '{print $3}'| grep -wq "nfs4\?";then
+ continue
+ fi
+ mountpoint=$(echo ${line}|awk '{print $2}')
+ if $DEBUG;then echo -en "NFS mount at ${mountpoint} found, ";fi
+ server=$(echo ${line}|grep -wo "addr=[0-2]\?[0-9]\?[0-9]\.[0-2]\?[0-9]\?[0-9]\.[0-2]\?[0-9]\?[0-9]\.[0-2]\?[0-9]\?[0-9]"|sed 's/addr=//')
+ if $DEBUG;then echo -en "server is ${server}. ";fi
+ if ! ping -w5 -i0.2 -c10 ${server} >/dev/null;then
+ if $DEBUG;then echo -ne "$server Did not respond to ping. ";fi
+ echo "Unmounting \"${mountpoint}\""
+ if ! $PRETEND;then umount -fl ${mountpoint};fi
+ else
+ if $DEBUG; then echo $server responded to ping;fi
+ fi
+
+done < /tmp/NFSumount_mounts.tmp
+
+rm /tmp/NFSumount_mounts.tmp
--- /dev/null
+#!/bin/sh
+#redirect soundcard outputs on 'admin' host
+#generated by hdajackretask from media-sound/alsa-tools
+echo "0x12 0x411111f0" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x14 0x01014010" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x15 0x01011012" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x16 0x01016011" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x17 0x40170000" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x18 0x01a19040" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x19 0x02a19050" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x1a 0x0181304f" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x1b 0x01014013" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x1d 0x40e7e629" > /sys/class/sound/hwC1D0/user_pin_configs
+echo "0x1e 0x01456130" > /sys/class/sound/hwC1D0/user_pin_configs
+echo 1 > /sys/class/sound/hwC1D0/reconfig
--- /dev/null
+#!/bin/bash
+#The polite way of cutting down on "Unounting network filesystems", deprecates nfs_mounts.stop
+echo 1 > /proc/sys/net/ipv4/tcp_syn_retries
+
--- /dev/null
+#!/usr/bin/python
+#see what the actual commandline ues to invoke python is...
+import os,sys
+with open('/proc/%s/cmdline'%os.getpid(),'r') as file:cll=file.read().split('\x00')
+print('Does "/usr/bin/python" match "%s"?'%' '.join(cll[0:cll.index(sys.argv[0])]))
+
--- /dev/null
+#!/bin/bash
+#use google translate to convert text to speech
+rm /tmp/speech.ogg
+say() { local IFS=+;ffmpeg -i "http://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&q=$*&tl=en" /tmp/speech.ogg; }
+say $*
+ogg123 /tmp/speech.ogg
--- /dev/null
+#!/bin/bash
+#for livestream event viewing multiple streams, dump urls into the commandline, look at the pritty videos :)
+urls=$*
+for w in ${urls};do
+url=$(echo "${w}" |sed "s|'||g")
+echo "Opening : ${url}"
+ffplay $(youtube-dl -g $url) >/dev/null 2>&1 &
+done
+
+
+
+while read -p "Enter URL: " w;do
+url=$(echo "${w}" |sed "s|'||g"|sed 's/&list.*//')
+echo "Opening : ${url}"
+ffplay $(youtube-dl -g ${url}) >/dev/null 2>&1 &
+done