munkilib.py:

- changes to pythonScriptRunning() to allow the tools to detect if another instance of themselves is running
- updated getBundlePackageInfo() to handle pre-dist style .mpkgs

removepackages.py:
- changes to handle multiple receipts with the same packageid

installcheck:
- removed random sleep option - this will move to another tool so we don't have installcheck itself sleeping; this prevented the other tools from running if you happened to, say, call managedinstaller while installcheck was sleeping.
- installcheck checks to see if another instance of itself is running and exits if so
- suppress errors when getting the primary manifest and trying long hostname, then short hostname, then "site_default".

makecatalogs:
- don't try to process ._ files or .DS_Store files.

makepkginfo:
- try to generate a better installer_item_location if the path has "/pkgs" in it




git-svn-id: http://munki.googlecode.com/svn/trunk@110 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
Greg Neagle
2009-07-09 06:13:01 +00:00
parent f508ad9f88
commit 07fc86c9d7
6 changed files with 168 additions and 91 deletions
+29 -21
View File
@@ -369,12 +369,15 @@ def getInstalledVersion(pl):
Attempts to determine the currently installed version of the item
described by pl
"""
if 'receipts' in pl:
if len(pl['receipts']) == 1:
pkgid = pl['receipts'][0]['packageid']
installedvers = munkilib.getInstalledPackageVersion(pkgid)
if installedvers:
return installedvers
maxversion = "0.0.0.0.0"
for receipt in pl['receipts']:
pkgvers = munkilib.getInstalledPackageVersion(receipt['packageid'])
if compareVersions(pkgvers, maxversion) == 2:
# version is higher
maxversion = pkgvers
return maxversion
if 'installs' in pl:
for install_item in pl['installs']:
@@ -1118,6 +1121,7 @@ def getPrimaryManifest(alternate_id):
"""
Gets the client manifest from the server
"""
global errors
managedinstallprefs = munkilib.prefs()
manifesturl = managedinstallprefs['ManifestURL']
clientidentifier = managedinstallprefs.get('ClientIdentifier','')
@@ -1134,18 +1138,21 @@ def getPrimaryManifest(alternate_id):
# no client identifier specified, so use the hostname
hostname = os.uname()[1]
manifest = getmanifest(manifesturl + hostname)
if manifest:
return manifest
else:
if not manifest:
# try the short hostname
manifest = getmanifest(manifesturl + hostname.split('.')[0])
if manifest:
return manifest
else:
if not manifest:
# last resort - try for the site_default manifest
manifesturl = manifesturl + "site_default"
return getmanifest(manifesturl)
if not manifest:
manifest = getmanifest(manifesturl)
if manifest:
# clear out any errors we got while try to find
# the primary manifest
errors = ""
return manifest
def getInstallCount(installinfo):
@@ -1289,8 +1296,6 @@ p.add_option('--id', '-i', default='',
help='Alternate identifier for catalog retreival')
p.add_option('--quiet', '-q', action='store_true',
help='Quiet mode. Logs messages, but nothing to stdout.')
p.add_option('--randomsleep', '-r', type='int', default=0,
help='Randomly sleeps up to the given number of seconds before checking.')
p.add_option('--verbose', '-v', action='count', default=0,
help='More verbose output. May be specified multiple times.')
options, arguments = p.parse_args()
@@ -1323,17 +1328,20 @@ def main():
exit(-1)
log("### Beginning managed software check ###")
if options.randomsleep:
randomsleepseconds = random.randrange(options.randomsleep+1)
printandlog("Sleeping %i seconds..." % randomsleepseconds)
time.sleep(randomsleepseconds)
if munkilib.pythonScriptRunning("managedinstaller"):
# managedinstaller is running, so we should quit
printandlog("managedinstaller is running. Exiting.")
log("### End managed software check ###")
exit(0)
# check to see if another instance of this script is running
myname = os.path.basename(sys.argv[0])
if munkilib.pythonScriptRunning(myname):
# another instance of this script is running, so we should quit
printandlog("Another instance of %s is running. Exiting." % myname)
log("### End managed software check ###")
exit(0)
mainmanifestpath = getPrimaryManifest(options.id)
if not mainmanifestpath:
logerror("Could not retreive managed install primary manifest.")
@@ -1342,7 +1350,7 @@ def main():
# logging to a local file isn't really sufficient.
reporterrors()
exit(-1)
# initialize our installinfo record
installinfo = {}
installinfo['managed_installs'] = []
+19 -18
View File
@@ -52,24 +52,25 @@ def makeCatalogs(repopath):
for dirpath, dirnames, filenames in os.walk(pkgsinfopath):
subdir = dirpath[len(pkgsinfopath):]
for name in filenames:
filepath = os.path.join(dirpath,name)
if validPlist(filepath):
#if it's a valid plist, assume it's a pkginfo file
pkginfo = plistlib.readPlist(filepath)
#simple sanity checking
if 'installer_item_location' in pkginfo:
installeritempath = os.path.join(repopath, "pkgs", pkginfo['installer_item_location'])
if os.path.exists(installeritempath):
catalogs['all'].append(pkginfo)
for catalogname in pkginfo.get("catalogs",[]):
if not catalogname in catalogs:
catalogs[catalogname] = []
catalogs[catalogname].append(pkginfo)
print "Adding %s to %s..." % (filepath[len(pkgsinfopath)+1:], catalogname)
else:
print >>sys.stderr, "WARNING: Info file %s refers to missing installer item: %s" % (filepath[len(pkgsinfopath)+1:], pkginfo['installer_item_location'])
else:
print >>sys.stderr, "WARNING: file %s is not a valid plist" % filepath
if not name.startswith("._") and name != ".DS_Store":
filepath = os.path.join(dirpath,name)
if validPlist(filepath):
#if it's a valid plist, assume it's a pkginfo file
pkginfo = plistlib.readPlist(filepath)
#simple sanity checking
if 'installer_item_location' in pkginfo:
installeritempath = os.path.join(repopath, "pkgs", pkginfo['installer_item_location'])
if os.path.exists(installeritempath):
catalogs['all'].append(pkginfo)
for catalogname in pkginfo.get("catalogs",[]):
if not catalogname in catalogs:
catalogs[catalogname] = []
catalogs[catalogname].append(pkginfo)
print "Adding %s to %s..." % (filepath[len(pkgsinfopath)+1:], catalogname)
else:
print >>sys.stderr, "WARNING: Info file %s refers to missing installer item: %s" % (filepath[len(pkgsinfopath)+1:], pkginfo['installer_item_location'])
else:
print >>sys.stderr, "WARNING: file %s is not a valid plist" % filepath
# clear out old catalogs
path = os.path.join(repopath, "catalogs")
+15 -2
View File
@@ -217,8 +217,21 @@ def main():
print >>sys.stderr, "Item %s doesn't exist. Skipping." % fitem
catinfo['installs'] = installs
name = os.path.split(item)[1]
catinfo['installer_item_location'] = name
# try to generate the correct item location
temppath = item
location = ""
while len(temppath) > 4:
if temppath.endswith('/pkgs'):
location = item[len(temppath)+1:]
break
else:
temppath = os.path.dirname(temppath)
if not location:
#just the filename
location = os.path.split(item)[1]
catinfo['installer_item_location'] = location
if minosversion:
catinfo['minimum_os_version'] = minosversion
else:
+9
View File
@@ -416,6 +416,15 @@ def main():
log("installcheck is running. Exiting.")
log("### End managed installer session ###")
exit(0)
# check to see if another instance of this script is running
myname = os.path.basename(sys.argv[0])
if munkilib.pythonScriptRunning(myname):
# another instance of this script is running, so we should quit
print "Another instance of %s is running. Exiting." % myname
log("Another instance of %s is running. Exiting." % myname)
log("### End managed installer session ###")
exit(0)
installinfo = os.path.join(managedinstallbase, 'InstallInfo.plist')
if os.path.exists(installinfo):
+89 -45
View File
@@ -70,18 +70,21 @@ def getconsoleuser():
def pythonScriptRunning(scriptname):
cmd = ['/bin/ps', '-eo', 'command=']
cmd = ['/bin/ps', '-eo', 'pid=,command=']
p = subprocess.Popen(cmd, shell=False, bufsize=1, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = p.communicate()
mypid = os.getpid()
lines = out.splitlines()
for line in lines:
(pid, proc) = line.split(None,1)
# first look for Python processes
if line.find("MacOS/Python ") != -1:
if line.find(scriptname) != -1:
return True
if proc.find("MacOS/Python ") != -1:
if proc.find(scriptname) != -1:
if int(pid) != int(mypid):
return pid
return False
return 0
# dmg helpers
@@ -233,19 +236,22 @@ def getExtendedVersion(bundlepath):
pl = {}
if os.path.exists(versionPlist):
pl = plistlib.readPlist(versionPlist)
elif os.path.exists(infoPlist):
if pl:
shortVers = "0.0.0"
sourceVers = "0"
buildVers = "0"
if "CFBundleShortVersionString" in pl:
shortVers = padVersionString(pl["CFBundleShortVersionString"],3)
if "SourceVersion" in pl:
sourceVers = padVersionString(pl["SourceVersion"],1)
if "BuildVersion" in pl:
buildVers = padVersionString(pl["BuildVersion"],1)
return shortVers + "." + sourceVers + "." + buildVers
if os.path.exists(infoPlist):
pl = plistlib.readPlist(infoPlist)
if pl:
shortVers = "0.0.0"
sourceVers = "0"
buildVers = "0"
if "CFBundleShortVersionString" in pl:
shortVers = padVersionString(pl["CFBundleShortVersionString"],3)
if "SourceVersion" in pl:
sourceVers = padVersionString(pl["SourceVersion"],1)
if "BuildVersion" in pl:
buildVers = padVersionString(pl["BuildVersion"],1)
return shortVers + "." + sourceVers + "." + buildVers
return padVersionString(pl["CFBundleShortVersionString"],5)
else:
return "0.0.0.0.0"
@@ -314,27 +320,36 @@ def getFlatPackageInfo(pkgpath):
return infoarray
def getOnePackageInfo(pkgpath):
pkginfo = {}
plistpath = os.path.join(pkgpath, "Contents", "Info.plist")
if os.path.exists(plistpath):
pkginfo['filename'] = os.path.basename(pkgpath)
pl = plistlib.readPlist(plistpath)
if "CFBundleIdentifier" in pl:
pkginfo['id'] = pl["CFBundleIdentifier"]
else:
pkginfo['id'] = os.path.basename(pkgpath)
if "CFBundleName" in pl:
pkginfo['name'] = pl["CFBundleName"]
if "IFPkgFlagInstalledSize" in pl:
pkginfo['installed_size'] = pl["IFPkgFlagInstalledSize"]
pkginfo['version'] = getExtendedVersion(pkgpath)
return pkginfo
def getBundlePackageInfo(pkgpath):
infoarray = []
pkginfo = {}
if pkgpath.endswith(".pkg"):
plistpath = os.path.join(pkgpath, "Contents", "Info.plist")
if os.path.exists(plistpath):
pl = plistlib.readPlist(plistpath)
if debug:
for key in pl:
print key, "=>", pl[key]
if "CFBundleIdentifier" in pl:
pkginfo['id'] = pl["CFBundleIdentifier"]
if "IFPkgFlagInstalledSize" in pl:
pkginfo['installed_size'] = pl["IFPkgFlagInstalledSize"]
pkginfo['version'] = getExtendedVersion(pkgpath)
infoarray.append(pkginfo)
return infoarray
pkginfo = getOnePackageInfo(pkgpath)
if pkginfo:
infoarray.append(pkginfo)
return infoarray
bundlecontents = os.path.join(pkgpath, "Contents")
if os.path.exists(bundlecontents):
@@ -343,7 +358,27 @@ def getBundlePackageInfo(pkgpath):
filename = os.path.join(bundlecontents, item)
infoarray = parsePkgRefs(filename)
return infoarray
# no .dist file found, look for packages in subdirs
dirsToSearch = []
plistpath = os.path.join(pkgpath, "Contents", "Info.plist")
if os.path.exists(plistpath):
pl = plistlib.readPlist(plistpath)
if 'IFPkgFlagComponentDirectory' in pl:
dirsToSearch.append(pl['IFPkgFlagComponentDirectory'])
if dirsToSearch == []:
dirsToSearch = ['Contents', 'Contents/Packages', 'Contents/Resources', 'Contents/Resources/Packages']
for subdir in dirsToSearch:
searchdir = os.path.join(pkgpath, subdir)
if os.path.exists(searchdir):
for item in os.listdir(searchdir):
itempath = os.path.join(searchdir, item)
if os.path.isdir(itempath) and itempath.endswith(".pkg"):
pkginfo = getOnePackageInfo(itempath)
if pkginfo:
infoarray.append(pkginfo)
return infoarray
@@ -401,6 +436,7 @@ def getInstalledPackageVersion(pkgid):
receiptsdir = "/Library/Receipts"
if os.path.exists(receiptsdir):
installitems = os.listdir(receiptsdir)
highestversion = "0"
for item in installitems:
if item.endswith(".pkg"):
info = getBundlePackageInfo(os.path.join(receiptsdir, item))
@@ -409,7 +445,11 @@ def getInstalledPackageVersion(pkgid):
foundbundleid = infoitem['id']
foundvers = infoitem['version']
if pkgid == foundbundleid:
return foundvers
if version.LooseVersion(foundvers) > version.LooseVersion(highestversion):
highestversion = foundvers
if highestversion != "0":
return highestversion
# If we got to this point, we haven't found the pkgid yet.
# Now check new (Leopard) package database
@@ -492,20 +532,22 @@ def getPackageMetaData(pkgitem):
installerinfo = getInstallerPkgInfo(pkgitem)
info = getPkgInfo(pkgitem)
name = os.path.split(pkgitem)[1]
shortname = os.path.splitext(name)[0]
metaversion = getExtendedVersion(pkgitem)
if metaversion == "0.0.0.0.0":
metaversion = nameAndVersion(shortname)[1]
highestpkgversion = "0.0"
for infoitem in info:
if version.LooseVersion(infoitem['version']) > version.LooseVersion(highestpkgversion):
highestpkgversion = infoitem['version']
if "installed_size" in infoitem:
# note this is in KBytes
installedsize += infoitem['installed_size']
name = os.path.split(pkgitem)[1]
shortname = os.path.splitext(name)[0]
metaversion = nameAndVersion(shortname)[1]
if not len(metaversion):
# there is no version number in the filename
if "installed_size" in infoitem:
# note this is in KBytes
installedsize += infoitem['installed_size']
if metaversion == "0.0.0.0.0":
metaversion = highestpkgversion
elif len(info) == 1:
# there is only one package in this item
@@ -531,6 +573,8 @@ def getPackageMetaData(pkgitem):
cataloginfo['receipts'] = []
for infoitem in info:
pkginfo = {}
if 'filename' in infoitem:
pkginfo['filename'] = infoitem['filename']
pkginfo['packageid'] = infoitem['id']
pkginfo['version'] = infoitem['version']
cataloginfo['receipts'].append(pkginfo)
+7 -5
View File
@@ -614,15 +614,17 @@ def getpkgkeys(pkgnames):
pkgkeyslist = []
for pkg in pkgnames:
t = (pkg, )
pkg_key = c.execute('select pkg_key from pkgs where pkgname = ?', t).fetchone()
if pkg_key is None:
pkg_keys = c.execute('select pkg_key from pkgs where pkgname = ?', t).fetchall()
if not pkg_keys:
# try pkgid
pkg_key = c.execute('select pkg_key from pkgs where pkgid = ?', t).fetchone()
if pkg_key is None:
pkg_keys = c.execute('select pkg_key from pkgs where pkgid = ?', t).fetchall()
if not pkg_keys:
display_error("%s not found in database." % pkg)
pkgerror = True
else:
pkgkeyslist.append(pkg_key[0])
for row in pkg_keys:
# only want first column
pkgkeyslist.append(row[0])
if pkgerror:
pkgkeyslist = []
c.close