7
\$\begingroup\$

I am looking to see if someone is willing to take the challenge in optimizing this noob Python script.

The purpose of the script is to:

  1. Check if Google Drive File Stream is installed
  2. Check if Google Drive is installed
  3. Check if user's Google Drive folder has been renamed

Then the actions begin:

  1. Install Google Drive File Stream
  2. Quit Google Drive if running
  3. Uninstall Google Drive
  4. Rename user's Google Drive folder

Logging is needed, of course, and some double checks for various commands you'll see in the script.

import commands
import subprocess
import os, logging, sys, signal, time, shutil
from SystemConfiguration import SCDynamicStoreCopyConsoleUser
##################################################################################
# Variables
##################################################################################
userName = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]
userName = [userName,""][userName in [u"loginwindow", None, u""]]
googleDriveDir = ""
gdfsInstaller = "/Library/Scripts/Company/GoogleDriveFileStream.dmg"
# Logging File
#logFile = "/Library/Logs/Company/googleDrive_Migration.log"
logFile = "/Users/" + userName + "/Library/Logs/Company/googleDrive_Migration.log"
basedir = os.path.dirname(logFile)
if not os.path.exists(basedir):
 os.makedirs(basedir)
if not os.path.exists(logFile):
 with open(logFile, 'a'):
 os.utime(logFile, None)
logging.basicConfig(filename=logFile, level=logging.DEBUG, format='%(asctime)s - %(levelname)s: %(message)s')
# Console Handler
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
gstream = "/Applications/Google Drive File Stream.app"
gdrive = "/Applications/Google Drive.app"
##################################################################################
# Functions
##################################################################################
def appExist(appName):
 logging.info("Checking for the existence of: %s", appName)
 return os.path.exists(appName)
def appProcessID(appPath, action):
 # the "action" item takes either a "kill" or "check" action.
 global appName
 #appName = os.path.splitext(os.path.basename(appPath))[0]
 appName = os.path.basename(appPath)
 logging.debug('AppName variable and action to be taken is: %s, %s', appName, action)
 if action == "check":
 logging.info('Looking for Process ID(s) for %s', appName)
 process = subprocess.Popen(['pgrep', '-i', appName], stdout=subprocess.PIPE)
 global my_pid
 my_pid, err = process.communicate()
 # Check if the application is running and log status
 #my_pid = appProcessID(gdrive)
 if my_pid:
 logging.debug('Application %s is running with process ID(s): %s', gdrive, my_pid)
 else:
 logging.debug('Application %s, is not running. Could not find any process id(s)', appName)
 return my_pid
 elif action == "kill":
 if not my_pid:
 appExit('No Process ID was found.')
 try:
 pid = int(my_pid)
 logging.debug('Converted %s to an integar acceptable for signal killing.', pid)
 #print "that worked"
 except ValueError:
 appExit('Could not confirm ' + my_pid + 'as an integar value acceptable for signal kill.')
 #print "did not work"
 os.kill(pid, signal.SIGKILL)
 else:
 appExit('Could not run the function appProcessID wihtout an action argument.')
def googleDirLookup(directory):
 #UsersGoogleDriveDir = "/Users/" + userName + "/" + appName + "/"
 logging.info('Verifying if this path exists: %s', directory)
 if os.path.exists(directory):
 googleDriveDir = directory
 if os.path.islink(googleDriveDir):
 dir = os.path.realpath(googleDriveDir)
 googleDriveDir = dir + "/"
 logging.info('The path was a symlink and has been updated to use the real path.')
 else:
 googleDriveDir = directory + "/"
 logging.info('Found the directory %s', googleDriveDir)
 return googleDriveDir
 else:
 logging.info('Could not find the path: %s', directory)
def renameDir(olddir, newdir):
 logging.info('Renaming %s to %s', olddir, newdir)
 os.rename(olddir, newdir)
 time.sleep(3)
def Uninstall(appName):
 logging.info('Killing any processes from %s', appName)
 appProcessID(appName, "kill")
 logging.info('Checking if process was killed successfully...')
 appProcessID(appName, "check")
 logging.info('Deleting %s...', appName)
 time.sleep(5)
 if os.path.exists(appName):
 shutil.rmtree(appName)
 else:
 logging.info('Could not find the path: %s', appName)
 # Rename Google Drive folder if it exists
 if not os.path.exists(RenamedUsersGoogleDriveDir):
 renameDir(UsersGoogleDriveDir, RenamedUsersGoogleDriveDir)
 appExit('Successful! New path is set to ' + RenamedUsersGoogleDriveDir)
 else:
 appExit('Failed! Could not find the path: ' + RenamedUsersGoogleDriveDir)
def openFileCheck(directory):
 p1=subprocess.Popen(['lsof', '-Fn'], stdout=subprocess.PIPE)
 p2=subprocess.Popen(['grep', directory + "/"], stdin=p1.stdout, stdout=subprocess.PIPE)
 p3=subprocess.Popen(['grep', '-v', '.DS_Store'], stdin=p2.stdout, stdout=subprocess.PIPE)
 process = p3.communicate()[0]
 if process:
 return process
def installApp(appName):
 if not appExist(appName):
 print appName
 appExit('FAILED to find the installer from ' + appName)
 mountedGDFS = "/Volumes/GoogleDriveFileStream"
 logging.info('Found %s...mounting to %s...', appName, mountedGDFS)
 # Mount DMG
 p1=subprocess.Popen(['hdiutil', 'attach', '-mountpoint', mountedGDFS, appName], stdout=subprocess.PIPE).wait()
 if not os.path.exists(mountedGDFS + "/GoogleDriveFileStream.pkg"):
 appExit('FAILED to mount directory')
 gdfsPKG = mountedGDFS + "/GoogleDriveFileStream.pkg"
 logging.info('Successfully mounted %s.', mountedGDFS)
 logging.info('Installing PKG from %s...', gdfsPKG)
 p1=subprocess.Popen(['installer', '-pkg', gdfsPKG, '-target', '/'], stdout=subprocess.PIPE).wait()
 if not appExist(gstream):
 p2=subprocess.Popen(['hdiutil', 'attach', '-mountpoint', mountedGDFS, appName], stdout=subprocess.PIPE).wait()
 appExit('FAILED could not find Google Drive File Stream in ' + gstream)
 # Detach mounted DMG
 logging.info('Unmounting Installer DMG...')
 d1=subprocess.Popen(['df', '-h'], stdout=subprocess.PIPE)
 d2=subprocess.Popen(['grep', mountedGDFS], stdin=d1.stdout, stdout=subprocess.PIPE)
 diskDrive = d2.stdout.readline()[0:12]
 detachCommand=subprocess.Popen(['hdiutil', 'detach', diskDrive], stderr=subprocess.PIPE, stdout=subprocess.PIPE).wait()
 if not os.path.exists(mountedGDFS):
 logging.info('Successfully unmounted %s', appName)
 else:
 logging.info('Failed to unmount %s', appName)
def appExit(exitstatement):
 logging.info("%s", exitstatement)
 logging.info('==============END==========================')
 logging.info(' ')
 sys.exit()
##################################################################################
# Check Logic
##################################################################################
# Check and create log files if they do not exist.
logging.info('==============START========================')
logging.info('Location of logs: %s', logFile)
logging.info('Current logged in user: %s', userName)
# Check for the existence of the application before installing.
logging.info('Checking for the existence of application: %s', gstream)
gStreamExist = "FALSE"
if os.path.exists(gstream):
 logging.info('Found the application %s', gstream)
 gStreamExist="TRUE"
 # DO NOT EXIT HERE FOR PRODUCTION
 #appExit(gstream + ", is installed on this system, no need to continue.")
else:
 logging.info('Could not find the application: %s', gstream)
# Check if Google Drive is installed.
logging.info('Checking for the existence of application: %s', gdrive)
gDriveExist = "TRUE"
if not os.path.exists(gdrive):
 gDriveExist="FALSE"
 # DO NOT EXIT HERE FOR PRODUCTION
 #appExit(gdrive + ", is installed on this system")
else:
 logging.info('Found the application: %s', gdrive)
# Check if the application is running and log status
appProcessID(gdrive, "check")
appName = os.path.splitext(os.path.basename(appName))[0]
# Check for Google Drive folder and for any open files from the application's directory.
UsersGoogleDriveDir = "/Users/" + userName + "/" + appName
RenamedUsersGoogleDriveDir = os.path.dirname(UsersGoogleDriveDir) + "/.RENAMED_" + appName
folderRenamed = "FALSE"
if googleDirLookup(UsersGoogleDriveDir):
 logging.info('Checking to see if any open files exist for %s in %s', appName, UsersGoogleDriveDir)
 openFiles = openFileCheck(UsersGoogleDriveDir)
 if openFiles:
 logging.debug('Currently open files include: %s', openFiles)
 appExit("Found actively open files in the directory. Cannot continue at this time. Quitting script...")
 logging.info('No open files found, continuing...')
elif googleDirLookup(RenamedUsersGoogleDriveDir):
 logging.info('Already renamed user\'s home folder. No need to continue.')
 folderRenamed = "TRUE"
else:
 logging.info('No Google Drive folder found in users home directory.')
##################################################################################
# Action Logic
##################################################################################
if gStreamExist =='FALSE' and gDriveExist =='FALSE' and folderRenamed =='FALSE':
 # Install Google Drive File Stream
 # 1) Check if installer is in place
 # 2) Install if found
 logging.info('== Taking action to Install Google Drive File Stream ==')
 installApp(gdfsInstaller)
 appExit('Successful!')
elif gStreamExist =='FALSE' and gDriveExist =='TRUE' and folderRenamed =='FALSE':
 logging.info('== Taking action to Install GDFS & Uninstall GDrive ==')
 # Install Google Drive File Stream
 # 1) Check if installer is in place
 # 2) Install if found
 installApp(gdfsInstaller)
 # Uninstall Google Drive
 # 1) Kill Process
 # 2) Remove delete application from Applications folder
 # 3) Rename Google Drive folder in user's home directory
 Uninstall(gdrive)
 appExit('Successful!')
elif gStreamExist =='TRUE' and gDriveExist =='TRUE' and folderRenamed =='FALSE':
 logging.info('== Taking action to Uninstall Gdrive ==')
 # Uninstall Google Drive
 # 1) Kill Process
 # 2) Remove delete application from Applications folder
 # 3) Rename Google Drive folder in user's home directory
 Uninstall(gdrive)
 appExit('Successful!')
elif gStreamExist =='TRUE' and gDriveExist =='FALSE' and folderRenamed =='FALSE':
 logging.info('== Taking action to Rename Gdrive Directory ==')
 # 3) Rename Google Drive folder in user's home directory
 renameDir(UsersGoogleDriveDir, RenamedUsersGoogleDriveDir)
 appExit('Successful!')
 #else gStreamExist =='TRUE' and gDriveExist =='FALSE' and folderRenamed =='TRUE':
 # Ideal scenario, do nothing!
else:
 appExit('== NO ACTION TAKEN: Google Drive File Stream is installed, Google Drive is uninstalled, and ' + userName + " Google Drive folder is renamed.")
toolic
14.9k5 gold badges29 silver badges207 bronze badges
asked Jan 9, 2018 at 17:39
\$\endgroup\$
0

1 Answer 1

5
\$\begingroup\$

Portability

I realize this question was posted many years ago when Python version 2.x was prevalent, but now that it is deprecated, consider porting to 3.x.

Change this line:

print appName

to:

print(appName)

There are also syntax errors; perhaps your version of Python was more forgiving. In the googleDirLookup function, there is illegal indentation:

googleDriveDir = dir + "/"
 logging.info('The path was a symlink and has been updated to use the real path.')

it should be:

googleDriveDir = dir + "/"
logging.info('The path was a symlink and has been updated to use the real path.')

In the appProcessID function, there is an else followed by an elif:

if my_pid:
 logging.debug('Application %s is running with process ID(s): %s', gdrive, my_pid)
else:
 logging.debug('Application %s, is not running. Could not find any process id(s)', appName)
 return my_pid
elif action == "kill":

This is illegal. If you did not get a syntax error there, I assume the code between the elif and the end of the function was unreachable. In any case, that should be cleaned up.

Tools

You could run code development tools to automatically find some style issues with your code.

For example, ruff identifies unused imports. This line can be deleted:

import commands

Remove the unused signal import. Also, split imports onto multiple lines. Change:

import os, logging, sys, signal, time, shutil

to:

import os
import logging
import sys
import time
import shutil

You could also use ruff to automatically reorder the import lines (similar to the isort tool) as follows:

ruff check --select I --fix

Comments

All commented-out code should be deleted to reduce clutter. For example:

#logFile = "/Library/Logs/Company/googleDrive_Migration.log"
#appName = os.path.splitext(os.path.basename(appPath))[0]
#my_pid = appProcessID(gdrive)

Simpler

Since you only set the gStreamExist variable to the 2 strings "TRUE" and "FALSE", it would be more natural to make the variable a boolean type instead of a string type by assigning boolean values:

gDriveExist = True
if not os.path.exists(gdrive):
 gDriveExist = False

Then comparisons like:

elif gStreamExist =='TRUE'

can be simplified as:

elif gStreamExist

Naming

The PEP 8 style guide recommends snake_case for function and variable names.

For example, appExist would be app_exist, and appName would be app_name.

The variable named dir is the same name as a Python built-in function. This can be confusing. To eliminate the confusion, rename the variable as something like google_dir. The first clue is that "dir" has special coloring (syntax highlighting) in the question, as it does when I copy the code into my editor.

Documentation

The PEP 8 style guide recommends adding docstrings for classes and functions.

answered Aug 12 at 10:16
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.