# Python System Update Script



## devilock76 (Aug 8, 2011)

So I coded this last night and been playing around and tweaking the concept.  Before anyone asks my purposes are academic.  I wanted something that worked like I have been doing so manually and wanted more hands on time with python so I figured why not start on something like this that would be useful to me.

Posting the script code as I would love comments, critique, or good ideas for addition, and of course if it is useful to you, have at it.


```
#!/usr/bin/env python
#
# sysupdate.py
#
# Version 0.1
#
# Author: Ken MacKenzie
#
# This script uses portsnap to fetch and update the ports tree.  The pkg_version to determine packages that are out of date.
# The user can then specify a line number, No or Yes (to upgrade all) to upgrade packages in the system.  Portupgrade is called
# to perform the upgrade.
#
# Requires:
#
# 1.  Portsnap
# 2.  Portupgrade
# 3.  Python 2.6+
#
# To do:
#
# 1.  Check for sudo/root privledges
# 2.  Add pkg search and listing features as well as installation of new patches
# 3.  Add version numbers old and new
# 4,  Once a fully functioning and stable CLI tool a GUI tool will be added.

import os, shlex, subprocess

def PkgsToUpdate():
	print "Checking Package Versions..."
	pvList = []
	pvCmd = "pkg_version -l \"<\""
	pvReturn, pvError = subprocess.Popen([pvCmd], shell=True, stdout=subprocess.PIPE).communicate()
	pvReturn = pvReturn.strip()
	if len(pvReturn):
		pvList = pvReturn.split("<")
		pvCount = len(pvList)
		del pvList[pvCount-1]
		for pvItem in pvList:
			pvItem = pvItem.strip()
	return pvList

os.chdir("/usr/ports")
print "Refreshing Ports Tree..."
psCmd = "portsnap fetch update"
psArgs = shlex.split(psCmd)
psReturn = subprocess.call(psArgs)
#print psReturn

pkList = []
pkgList = PkgsToUpdate()
puExit = 0
while not(puExit):
	if len(pkgList) == 0:
		print "All packages current."
		puExit = 1
	else:
		print "Packages to upgrade:"
		for x in range ( len(pkgList)):
			print (x+1), " : ", pkgList[x]
		uCmd = input("Enter all (Y)es or (N)o, or enter line number to upgrade individually:")
		if isinstance(uCmd, str):
			uCmd = uCmd.upper
		if uCmd == "N":
			puExit = 1
		elif uCmd == "Y":
			for pkgItem in pkgList:
				print "Upgrading package: ", pkgItem
				pkgCmd = "portupgrade " + pkgItem
				pkgArgs = shlex.split(pkgCmd)
				pkgReturn = subprocess.call(pkgArgs)
				#pkgReturn, pkgError = subprocess.Popen([pkgCmd], shell=True, stdout=subprocess.PIPE).communicate()
				#print pkgReturn
			pkgList = PkgsToUpdate()
		elif uCmd in range (1, len(pkgList)+1):
			print "Upgrading package: ",  pkgList[uCmd - 1]
			pkgCmd = "portupgrade " + pkgList[uCmd - 1]
			pkgArgs = shlex.split(pkgCmd)
			pkgReturn = subprocess.call(pkgArgs)
			#pkgReturn, pkgError = subprocess.Popen([pkgCmd], shell=True, stdout=subprocess.PIPE).communicate()
			#print pkgReturn
			pkgList = PkgsToUpdate()
		else:
			print "Invalid Input!!!"
```

Ken


----------



## devilock76 (Aug 8, 2011)

Just noticed a typo, corrected:


```
#!/usr/bin/env python
#
# sysupdate.py
#
# Version 0.1
#
# Author: Ken MacKenzie
#
# This script uses portsnap to fetch and update the ports tree.  The pkg_version to determine packages that are out of date.
# The user can then specify a line number, No or Yes (to upgrade all) to upgrade packages in the system.  Portupgrade is called
# to perform the upgrade.
#
# Requires:
#
# 1.  Portsnap
# 2.  Portupgrade
# 3.  Python 2.6+
#
# To do:
#
# 1.  Check for sudo/root privledges
# 2.  Add pkg search and listing features as well as installation of new patches
# 3.  Add version numbers old and new
# 4,  Once a fully functioning and stable CLI tool a GUI tool will be added.

import os, shlex, subprocess

def PkgsToUpdate():
	print "Checking Package Versions..."
	pvList = []
	pvCmd = "pkg_version -l \"<\""
	pvReturn, pvError = subprocess.Popen([pvCmd], shell=True, stdout=subprocess.PIPE).communicate()
	pvReturn = pvReturn.strip()
	if len(pvReturn):
		pvList = pvReturn.split("<")
		pvCount = len(pvList)
		del pvList[pvCount-1]
		for pvItem in pvList:
			pvItem = pvItem.strip()
	return pvList

os.chdir("/usr/ports")
print "Refreshing Ports Tree..."
psCmd = "portsnap fetch update"
psArgs = shlex.split(psCmd)
psReturn = subprocess.call(psArgs)
#print psReturn

pkgList = []
pkgList = PkgsToUpdate()
puExit = 0
while not(puExit):
	if len(pkgList) == 0:
		print "All packages current."
		puExit = 1
	else:
		print "Packages to upgrade:"
		for x in range ( len(pkgList)):
			print (x+1), " : ", pkgList[x]
		uCmd = input("Enter all (Y)es or (N)o, or enter line number to upgrade individually:")
		if isinstance(uCmd, str):
			uCmd = uCmd.upper
		if uCmd == "N":
			puExit = 1
		elif uCmd == "Y":
			for pkgItem in pkgList:
				print "Upgrading package: ", pkgItem
				pkgCmd = "portupgrade " + pkgItem
				pkgArgs = shlex.split(pkgCmd)
				pkgReturn = subprocess.call(pkgArgs)
				#pkgReturn, pkgError = subprocess.Popen([pkgCmd], shell=True, stdout=subprocess.PIPE).communicate()
				#print pkgReturn
			pkgList = PkgsToUpdate()
		elif uCmd in range (1, len(pkgList)+1):
			print "Upgrading package: ",  pkgList[uCmd - 1]
			pkgCmd = "portupgrade " + pkgList[uCmd - 1]
			pkgArgs = shlex.split(pkgCmd)
			pkgReturn = subprocess.call(pkgArgs)
			#pkgReturn, pkgError = subprocess.Popen([pkgCmd], shell=True, stdout=subprocess.PIPE).communicate()
			#print pkgReturn
			pkgList = PkgsToUpdate()
		else:
			print "Invalid Input!!!"
```

The line in question was pkList = [] should be pkgList[].  And since it was working with the typo then that is probably one of many extra and redundant lines I don't need in the code.  Sorry, it is work in progress.

Ken


----------



## devilock76 (Aug 8, 2011)

pkgList = []

grrr.


----------



## devilock76 (Aug 9, 2011)

Here is an update, further testing revealed many bad mistakes in that.  Nothing that would be damaging to the system, just stuff that would have crashed or bad results.

Anyway here is a fixed version, this one also includes checks for root privileges.


```
#!/usr/bin/env python
#
# sysupdate.py
#
# Version 0.1
#
# Author: Ken MacKenzie
#
# This script uses portsnap to fetch and update the ports tree.  The pkg_version to determine packages that are out of date.
# The user can then specify a line number, No or Yes (to upgrade all) to upgrade packages in the system.  Portupgrade is called
# to perform the upgrade.
#
# Requires:
#
# 1.  Portsnap
# 2.  Portupgrade
# 3.  Python 2.6+
#
# To do:
#
# 1.  Check for sudo/root privledges - DONE
# 2.  Add pkg search and listing features as well as installation of new patches
# 3.  Add version numbers old and new
# 4.  Add log file usage
# 5,  Once a fully functioning and stable CLI tool a GUI tool will be added.

import os, shlex, subprocess, sys

def PkgsToUpdate():
	print "Checking Package Versions..."
	pvList = []
	pvCmd = "pkg_version -l \"<\""
	pvReturn, pvError = subprocess.Popen([pvCmd], shell=True, stdout=subprocess.PIPE).communicate()
	pvReturn = pvReturn.strip()
	if len(pvReturn):
		pvList = pvReturn.split("\n")
		pvCount = len(pvList)
		pvList = [pvItem.strip(" <") for pvItem in pvList]
	return pvList

os.chdir("/usr/ports")
if not os.getuid()==0:
	print "You do not have root privileges, no system changes can be made."
else:
	print "Refreshing Ports Tree..."
	psCmd = "portsnap fetch update"
	psArgs = shlex.split(psCmd)
	psReturn = subprocess.call(psArgs)
pkgList = []
pkgList = PkgsToUpdate()
if not os.getuid()==0:
	sys.exit("\nRun with root privileges to make changes.\n")
else:
	puExit = 0
	while not(puExit):
		if len(pkgList) == 0:
			print "All packages current."
			puExit = 1
		else:
			print "Packages to upgrade:"
			for x in range ( len(pkgList)):
				print (x+1), " : ", pkgList[x]
			uCmd = raw_input("Enter all (Y)es or (N)o, or enter line number to upgrade individually: ")
			uCmd = uCmd.upper()
			if uCmd == "N":
				puExit = 1
			elif uCmd == "Y":
				for pkgItem in pkgList:
					print "Upgrading package: ", pkgItem
					pkgCmd = "portupgrade " + pkgItem
					pkgArgs = shlex.split(pkgCmd)
					pkgReturn = subprocess.call(pkgArgs)
				pkgList = PkgsToUpdate()
			elif int(uCmd) in range (1, len(pkgList)+1):
				iCmd = int(uCmd)
				print "Upgrading package: ",  pkgList[iCmd - 1]
				pkgCmd = "portupgrade " + pkgList[iCmd - 1]
				pkgArgs = shlex.split(pkgCmd)
				pkgReturn = subprocess.call(pkgArgs)
				pkgList = PkgsToUpdate()
			else:
				print "Invalid Input!!!"
```

Ken


----------



## moxie (Aug 12, 2013)

Just found this script, pretty neat.  Here is some help with the logging; also added _very_ basic cron functionality. It's proof of concept as I haven't had any updates to the ports tree to test it against, but it should work.


```
--- temp.2	2013-08-12 02:00:18.833160641 -0400
+++ temp.1	2013-08-12 02:07:49.382160361 -0400
@@ -1,10 +1,11 @@
-#!/usr/bin/env python
+#!/usr/local/bin/python
 #
 # sysupdate.py
 #
-# Version 0.1
+# Version 0.1-r1
 #
 # Author: Ken MacKenzie
+# Cron and Logging Facilities: Michael Beasley
 #
 # This script uses portsnap to fetch and update the ports tree.  The pkg_version to determine packages that are out of date.
 # The user can then specify a line number, No or Yes (to upgrade all) to upgrade packages in the system.  Portupgrade is called
@@ -18,13 +19,63 @@
 #
 # To do:
 #
-# 1.  Check for sudo/root privledges - DONE
 # 2.  Add pkg search and listing features as well as installation of new patches
 # 3.  Add version numbers old and new
-# 4.  Add log file usage
 # 5,  Once a fully functioning and stable CLI tool a GUI tool will be added.
 
-import os, shlex, subprocess, sys
+
+import os
+import shlex
+import subprocess
+import logging
+import sys
+import optparse
+import getopt
+
+class TeeFile(object):
+     def __init__(self, name, mode):
+         self.file = open(name, mode)
+         self.stdout = sys.stdout
+         sys.stdout = self
+     def close(self):
+         if self.stdout is not None:
+             sys.stdout = self.stdout
+             self.stdout = None
+         if self.file is not None:
+             self.file.close()
+             self.file = None
+     def write(self, data):
+         self.file.write(data)
+         self.stdout.write(data)
+     def flush(self):
+         self.file.flush()
+         self.stdout.flush()
+     def __del__(self):
+         self.close()
+
+tee=TeeFile('/var/log/sysupdate_py.log', 'w')
+
+if os.geteuid() != 0:
+	print "You need root privileges to run this script"
+	exit()
+
+parser = optparse.OptionParser()
+parser.add_option('--cron', action='store_false', help='Enables cron function, assumes yes for package upgrades')
+(opts, args) = parser.parse_args()
+
+if __name__ == '__main__':
+	cron = 0
+	args = sys.argv[1:]
+try:
+	(opts, getopts) = getopt.getopt(args, 'c', ["cron"])
+except:
+	print "\nInvalid Option."
+	usage()
+	sys.exit(1)
+for opt, arg in opts:
+	if opt in ('--cron'):
+		cron = 1
+		print "Using Cron Option"
 
 def PkgsToUpdate():
 	print "Checking Package Versions..."
@@ -33,50 +84,55 @@
 	pvReturn, pvError = subprocess.Popen([pvCmd], shell=True, stdout=subprocess.PIPE).communicate()
 	pvReturn = pvReturn.strip()
 	if len(pvReturn):
-		pvList = pvReturn.split("\n")
+		pvList = pvReturn.split("<")
 		pvCount = len(pvList)
-		pvList = [pvItem.strip(" <") for pvItem in pvList]
+		del pvList[pvCount-1]
+		for pvItem in pvList:
+			pvItem = pvItem.strip()
 	return pvList
 
-os.chdir("/usr/ports")
-if not os.getuid()==0:
-	print "You do not have root privileges, no system changes can be made."
-else:
-	print "Refreshing Ports Tree..."
-	psCmd = "portsnap fetch update"
-	psArgs = shlex.split(psCmd)
-	psReturn = subprocess.call(psArgs)
-pkgList = []
+print "Refreshing Ports Tree..."
+psCmd = "portsnap fetch update"
+psArgs = shlex.split(psCmd)
+psReturn = subprocess.call(psArgs)
+
+pkList = []
 pkgList = PkgsToUpdate()
-if not os.getuid()==0:
-	sys.exit("\nRun with root privileges to make changes.\n")
-else:
-	puExit = 0
-	while not(puExit):
-		if len(pkgList) == 0:
-			print "All packages current."
+puExit = 0
+while not(puExit):
+	if len(pkgList) == 0:
+		print "All packages current."
+		puExit = 1
+	else:
+		print "Packages to upgrade:"
+		for x in range ( len(pkgList)):
+			print (x+1), " : ", pkgList[x]
+		uCmd = input("Enter all (Y)es or (N)o, or enter line number to upgrade individually:")
+		if isinstance(uCmd, str):
+			uCmd = uCmd.upper
+		if uCmd == "N":
 			puExit = 1
-		else:
-			print "Packages to upgrade:"
-			for x in range ( len(pkgList)):
-				print (x+1), " : ", pkgList[x]
-			uCmd = raw_input("Enter all (Y)es or (N)o, or enter line number to upgrade individually: ")
-			uCmd = uCmd.upper()
-			if uCmd == "N":
-				puExit = 1
-			elif uCmd == "Y":
-				for pkgItem in pkgList:
-					print "Upgrading package: ", pkgItem
-					pkgCmd = "portupgrade " + pkgItem
-					pkgArgs = shlex.split(pkgCmd)
-					pkgReturn = subprocess.call(pkgArgs)
-				pkgList = PkgsToUpdate()
-			elif int(uCmd) in range (1, len(pkgList)+1):
-				iCmd = int(uCmd)
-				print "Upgrading package: ",  pkgList[iCmd - 1]
-				pkgCmd = "portupgrade " + pkgList[iCmd - 1]
+		elif cron:
+			for pkgItem in pkgList:
+				print "Checking Package Versions", pkList
+				pkgCmd = "portupgrade " + pkgItem
 				pkgArgs = shlex.split(pkgCmd)
 				pkgReturn = subprocess.call(pkgArgs)
-				pkgList = PkgsToUpdate()
-			else:
-				print "Invalid Input!!!"
+				pkgReturn = subprocess.call(pkgArgs)	
+		elif uCmd == "Y":
+			for pkgItem in pkgList:
+				print "Upgrading package: ", pkgItem
+				pkgCmd = "portupgrade " + pkgItem
+				pkgArgs = shlex.split(pkgCmd)
+				pkgReturn = subprocess.call(pkgArgs)
+			pkgList = PkgsToUpdate()
+		elif uCmd in range (1, len(pkgList)+1):
+			print "Upgrading package: ",  pkgList[uCmd - 1]
+			pkgCmd = "portupgrade " + pkgList[uCmd - 1]
+			pkgArgs = shlex.split(pkgCmd)
+			pkgReturn = subprocess.call(pkgArgs)
+			pkgList = PkgsToUpdate()
+		else:
+			print "Invalid Input!!!"
+tee.close()
+del tee
```


----------

