def _SetUserPolicyMac(self, user_policy=None): """Writes the given user policy to the plist policy file read by Chrome.""" assert self.IsMac() sudo_cmd_file = os.path.join(os.path.dirname(__file__), 'policy_posix_util.py') if self._branding == 'Google Chrome': policies_file_base = 'com.google.Chrome.plist' else: policies_file_base = 'org.chromium.Chromium.plist' policies_location = os.path.join('/Library', 'Managed Preferences', getpass.getuser()) if os.path.exists(policies_location): logging.debug('Removing directory %s' % policies_location) subprocess.call(['suid-python', sudo_cmd_file, 'remove_dir', policies_location]) if user_policy is not None: policies_tmp_file = os.path.join('/tmp', policies_file_base) plistlib.writePlist(user_policy, policies_tmp_file) subprocess.call(['suid-python', sudo_cmd_file, 'setup_dir', policies_location]) # Copy policy file to the managed directory subprocess.call(['suid-python', sudo_cmd_file, 'copy', policies_tmp_file, policies_location]) os.remove(policies_tmp_file)
def writeLocalCatalogs(applecatalogpath): '''Writes our local catalogs based on the Apple catalog''' catalog = plistlib.readPlist(applecatalogpath) # rewrite the URLs within the catalog to point to the items on our # local server instead of Apple's rewriteURLs(catalog) # remove the '.apple' from the end of the localcatalogpath if applecatalogpath.endswith('.apple'): localcatalogpath = applecatalogpath[0:-6] else: localcatalogpath = applecatalogpath print_stdout('Building %s...' % os.path.basename(localcatalogpath)) downloaded_products_list = getDownloadStatus() downloaded_products = {} product_keys = list(catalog['Products'].keys()) # filter Products, removing those that haven't been downloaded for product_key in product_keys: if product_key in downloaded_products_list: downloaded_products[product_key] = \ catalog['Products'][product_key] else: print_stderr('WARNING: did not add product %s to ' 'catalog %s because it has not been downloaded.', product_key, os.path.basename(applecatalogpath)) catalog['Products'] = downloaded_products # write raw (unstable/development) catalog # with all downloaded Apple updates enabled plistlib.writePlist(catalog, localcatalogpath) # now write filtered catalogs (branches) based on this catalog writeBranchCatalogs(localcatalogpath)
def __init__(self, cmd, environment_vars=None): tmpdir = _temp_dir LABELPREFIX = 'com.toppatch.agent.' # create a unique id for this job jobid = str(uuid.uuid1()) self.label = LABELPREFIX + jobid self.stdout_path = os.path.join(tmpdir, self.label + '.stdout') self.stderr_path = os.path.join(tmpdir, self.label + '.stderr') self.plist_path = os.path.join(tmpdir, self.label + '.plist') self.stdout = None self.stderr = None self.plist = {} self.plist['Label'] = self.label self.plist['ProgramArguments'] = cmd self.plist['StandardOutPath'] = self.stdout_path self.plist['StandardErrorPath'] = self.stderr_path if environment_vars: self.plist['EnvironmentVariables'] = environment_vars # write out launchd plist #FoundationPlist.writePlist(self.plist, self.plist_path) plistlib.writePlist(self.plist, self.plist_path) # set owner, group and mode to those required # by launchd os.chown(self.plist_path, 0, 0) os.chmod(self.plist_path, int('644', 8)) launchctl_cmd = ['/bin/launchctl', 'load', self.plist_path] proc = subprocess.Popen(launchctl_cmd, shell=False, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (unused_out, err) = proc.communicate() if proc.returncode: raise LaunchdJobException(err)
def addto_startup_osx(): if os.getuid() != 0: print 'please use sudo run this script' sys.exit() import plistlib plist = dict( GroupName = 'wheel', Label = 'org.goagent.macos', ProgramArguments = list([ '/usr/bin/python', os.path.join(os.path.abspath(os.path.dirname(__file__)), 'proxy.py') ]), RunAtLoad = True, UserName = '******', WorkingDirectory = os.path.dirname(__file__), StandardOutPath = '/var/log/goagent.log', StandardErrorPath = '/var/log/goagent.log', KeepAlive = dict( SuccessfulExit = False, ) ) filename = '/Library/LaunchDaemons/org.goagent.macos.plist' print 'write plist to %s' % filename plistlib.writePlist(plist, filename) print 'write plist to %s done' % filename print 'Adding CA.crt to system keychain, You may need to input your password...' cmd = 'sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "%s/CA.crt"' % os.path.abspath(os.path.dirname(__file__)) if os.system(cmd) != 0: print 'Adding CA.crt to system keychain Failed!' sys.exit(0) print 'Adding CA.crt to system keychain Done' print 'To start goagent right now, try this command: sudo launchctl load /Library/LaunchDaemons/org.goagent.macos.plist' print 'To checkout log file: using Console.app to locate /var/log/goagent.log' install_sharp_osx()
def database_write(db_data,sw_bundle,value): """ Add/update application's info in plist file """ db_data[sw_bundle] = value plistlib.writePlist(db_data, db_file) return 0
def create_plist(self): from calibre.ebooks import BOOK_EXTENSIONS env = dict(**ENV) env['CALIBRE_LAUNCHED_FROM_BUNDLE']='1' docs = [{'CFBundleTypeName':'E-book', 'CFBundleTypeExtensions':list(BOOK_EXTENSIONS), 'CFBundleTypeRole':'Viewer', }] pl = dict( CFBundleDevelopmentRegion='English', CFBundleDisplayName=APPNAME, CFBundleName=APPNAME, CFBundleIdentifier='net.kovidgoyal.calibre', CFBundleVersion=VERSION, CFBundleShortVersionString=VERSION, CFBundlePackageType='APPL', CFBundleSignature='????', CFBundleExecutable='calibre', CFBundleDocumentTypes=docs, LSMinimumSystemVersion='10.5.2', LSRequiresNativeExecution=True, NSAppleScriptEnabled=False, NSHumanReadableCopyright='Copyright 2010, Kovid Goyal', CFBundleGetInfoString=('calibre, an E-book management ' 'application. Visit http://calibre-ebook.com for details.'), CFBundleIconFile='library.icns', LSMultipleInstancesProhibited=True, NSHighResolutionCapable=True, LSApplicationCategoryType='public.app-category.utilities', LSEnvironment=env ) plistlib.writePlist(pl, join(self.contents_dir, 'Info.plist'))
def update_plist(config_filepath , u): f = open(config_filepath, 'r') plist = plistlib.readPlist(f) nested_update(plist, u) f.close() f = open(config_filepath, 'w') plistlib.writePlist(plist, f)
def _InstallEntitlements(self, entitlements, substitutions, overrides): """Generates and install the ${BundleName}.xcent entitlements file. Expands variables "$(variable)" pattern in the source entitlements file, add extra entitlements defined in the .mobileprovision file and the copy the generated plist to "${BundlePath}.xcent". Args: entitlements: string, optional, path to the Entitlements.plist template to use, defaults to "${SDKROOT}/Entitlements.plist" substitutions: dictionary, variable substitutions overrides: dictionary, values to add to the entitlements Returns: Path to the generated entitlements file. """ source_path = entitlements target_path = os.path.join(os.environ["BUILT_PRODUCTS_DIR"], os.environ["PRODUCT_NAME"] + ".xcent") if not source_path: source_path = os.path.join(os.environ["SDKROOT"], "Entitlements.plist") shutil.copy2(source_path, target_path) data = self._LoadPlistMaybeBinary(target_path) data = self._ExpandVariables(data, substitutions) if overrides: for key in overrides: if key not in data: data[key] = overrides[key] plistlib.writePlist(data, target_path) return target_path
def SaveRaycastingPreset(self, pubsub_evt): preset_name = pubsub_evt.data preset = prj.Project().raycasting_preset preset['name'] = preset_name preset_dir = os.path.join(const.USER_RAYCASTING_PRESETS_DIRECTORY, preset_name + '.plist') plistlib.writePlist(preset, preset_dir)
def create_app_clone(self, name, specialise_plist, remove_doc_types=True): info('\nCreating ' + name) cc_dir = os.path.join(self.contents_dir, name, 'Contents') exe_dir = join(cc_dir, 'MacOS') os.makedirs(exe_dir) for x in os.listdir(self.contents_dir): if x.endswith('.app'): continue if x == 'Info.plist': plist = plistlib.readPlist(join(self.contents_dir, x)) specialise_plist(plist) if remove_doc_types: plist.pop('CFBundleDocumentTypes') exe = plist['CFBundleExecutable'] # We cannot symlink the bundle executable as if we do, # codesigning fails nexe = plist['CFBundleExecutable'] = exe + '-placeholder-for-codesigning' shutil.copy2(join(self.contents_dir, 'MacOS', exe), join(exe_dir, nexe)) exe = join(exe_dir, plist['CFBundleExecutable']) plistlib.writePlist(plist, join(cc_dir, x)) elif x == 'MacOS': for item in os.listdir(join(self.contents_dir, 'MacOS')): os.symlink('../../../MacOS/'+item, join(exe_dir, item)) else: os.symlink(join('../..', x), join(cc_dir, x))
def ExecMergeInfoPlist(self, output, *inputs): """Merge multiple .plist files into a single .plist file.""" merged_plist = {} for path in inputs: plist = self._LoadPlistMaybeBinary(path) self._MergePlist(merged_plist, plist) plistlib.writePlist(merged_plist, output)
def makeMpkgPlist(path): vers = getFullVersion() major, minor = map(int, getVersion().split('.', 2)) pl = Plist( CFBundleGetInfoString="Python %s"%(vers,), CFBundleIdentifier='org.python.Python', CFBundleName='Python', CFBundleShortVersionString=vers, IFMajorVersion=major, IFMinorVersion=minor, IFPkgFlagComponentDirectory="Contents/Packages", IFPkgFlagPackageList=[ dict( IFPkgFlagPackageLocation='%s-%s.pkg'%(item['name'], getVersion()), IFPkgFlagPackageSelection=item.get('selected', 'selected'), ) for item in pkg_recipes() ], IFPkgFormatVersion=0.10000000149011612, IFPkgFlagBackgroundScaling="proportional", IFPkgFlagBackgroundAlignment="left", IFPkgFlagAuthorizationAction="RootAuthorization", ) writePlist(pl, path)
def test_bytesio(self): from io import BytesIO b = BytesIO() pl = self._create() plistlib.writePlist(pl, b) pl2 = plistlib.readPlist(BytesIO(b.getvalue())) self.assertEqual(dict(pl), dict(pl2))
def main(): try: # Create calendar ServerRoot os.mkdir(CALENDAR_SERVER_ROOT) except OSError: # Already exists pass try: # Create calendar ConfigRoot os.mkdir(DEST_CONFIG_DIR) except OSError: # Already exists pass plistPath = os.path.join(DEST_CONFIG_DIR, CALDAVD_PLIST) if os.path.exists(plistPath): try: plistData = readPlist(plistPath) updatePlist(plistData) writePlist(plistData, plistPath) except Exception, e: print "Unable to disable update values in %s: %s" % (plistPath, e)
def run(self, testname): super(Test, self).run(testname) plist = get_plist(self._config, testname, test=True) path = os.path.join(os.getcwd(), 'build', self._config['name'] + '_' + testname) try: plistlib.writePlist(plist, os.path.join(path, 'Info.plist')) except: raise FileNotWritableError('Could not write plist to target location: ', path) icon_name = 'Icon.svg' icon_path = os.path.join(os.getcwd(), 'assets', icon_name) if not os.path.exists(icon_path): icon_path = os.path.join(os.getcwd(), icon_name) if not os.path.exists(icon_path): icon_name = 'Icon.png' icon_path = os.path.join(os.getcwd(), 'assets', icon_name) if not os.path.exists(icon_path): icon_path = os.path.join(os.getcwd(), icon_name) if not os.path.exists(icon_path): print('Could not find an Icon for your test dizmo. It is strongly recommended to add "Icon.svg" in the assets folder.') try: copy(icon_path, os.path.join(path, icon_name)) except: raise FileNotWritableError('Could not write the icon "' + icon_name + '" to its target location')
def prepare_docset(args, dest): """Create boilerplate files & directories and copy vanilla docs inside. Return a tuple of path to resources and connection to sqlite db. """ resources = os.path.join(dest, 'Contents/Resources/') docs = os.path.join(resources, 'Documents') os.makedirs(resources) db_conn = sqlite3.connect(os.path.join(resources, 'docSet.dsidx')) db_conn.row_factory = sqlite3.Row db_conn.execute( 'CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, ' 'type TEXT, path TEXT)' ) db_conn.commit() plist_cfg = { 'CFBundleIdentifier': args.name, 'CFBundleName': args.name, 'DocSetPlatformFamily': args.name.lower(), 'DashDocSetFamily': 'python', 'isDashDocset': True, } if args.index_page is not None: plist_cfg['dashIndexFilePath'] = args.index_page plistlib.writePlist( plist_cfg, os.path.join(dest, 'Contents/Info.plist') ) shutil.copytree(args.source, docs) return docs, db_conn
def SavePlist(self, dir_temp, filelist): filename = "surface_%d" % self.index vtp_filename = filename + ".vtp" vtp_filepath = os.path.join(dir_temp, vtp_filename) pu.Export(self.polydata, vtp_filepath, bin=True) filelist[vtp_filepath] = vtp_filename surface = { "colour": self.colour, "index": self.index, "name": self.name, "polydata": vtp_filename, "transparency": self.transparency, "visible": bool(self.is_shown), "volume": self.volume, "area": self.area, } plist_filename = filename + ".plist" # plist_filepath = os.path.join(dir_temp, filename + '.plist') temp_plist = tempfile.mktemp() plistlib.writePlist(surface, temp_plist) filelist[temp_plist] = plist_filename return plist_filename
def save(self, entry, with_location=True, debug=False): """Saves a DayOneEntry as a plist""" entry_dict = {} if isinstance(entry, DayOneEntry): # Get a dict of the DayOneEntry entry_dict = entry.as_dict() else: entry_dict = entry # Set the UUID entry_dict['UUID'] = uuid.uuid4().get_hex() if with_location and not entry_dict['Location']: entry_dict['Location'] = self.get_location() # Do we have everything needed? if not all ((entry_dict['UUID'], entry_dict['Time Zone'], entry_dict['Entry Text'])): print "You must provide: Time zone, UUID, Creation Date, Entry Text" return False if debug is False: file_path = self._file_path(entry_dict['UUID']) plistlib.writePlist(entry_dict, file_path) else: plist = plistlib.writePlistToString(entry_dict) print plist return True
def configure(prompt_list): """Gets configuration options and saves them to preferences store""" darwin_vers = int(os.uname()[2].split('.')[0]) edited_prefs = {} for (key, prompt) in prompt_list: newvalue = raw_input_with_default('%15s: ' % prompt, pref(key)) if darwin_vers == 10: # old behavior in SL: hitting return gives you an empty string, # and means accept the default value. edited_prefs[key] = newvalue or pref(key) or '' else: # just use the edited value as-is edited_prefs[key] = newvalue if FOUNDATION_SUPPORT: for key, value in edited_prefs.items(): try: CFPreferencesSetAppValue(key, value, BUNDLE_ID) except BaseException: print >> sys.stderr, 'Could not save configuration!' raise ConfigurationSaveError CFPreferencesAppSynchronize(BUNDLE_ID) else: try: existing_prefs = plistlib.readPlist(PREFSPATH) existing_prefs.update(edited_prefs) plistlib.writePlist(existing_prefs, PREFSPATH) except (IOError, OSError, ExpatError): print >> sys.stderr, ( 'Could not save configuration to %s' % PREFSPATH) raise ConfigurationSaveError
def configure_prefs(): """Configures prefs for use""" _prefs = {} keysAndPrompts = [ ("UpdatesRootDir", "Path to store replicated catalogs and updates"), ("UpdatesMetadataDir", "Path to store Reposado metadata"), ( "LocalCatalogURLBase", "Base URL for your local Software Update Service\n(Example: http://su.your.org -- leave empty if you are not replicating updates)", ), ] if not os.path.exists(pref("CurlPath")): keysAndPrompts.append(("CurlPath", "Path to curl tool (Example: /usr/bin/curl)")) for (key, prompt) in keysAndPrompts: newvalue = raw_input("%15s [%s]: " % (prompt, pref(key))) _prefs[key] = newvalue or pref(key) or "" prefspath = prefsFilePath() # retrieve current preferences try: prefs = plistlib.readPlist(prefspath) except (IOError, ExpatError): prefs = {} # merge edited preferences for key in _prefs.keys(): prefs[key] = _prefs[key] # write preferences to our file try: plistlib.writePlist(prefs, prefspath) except (IOError, ExpatError): print_stderr("Could not save configuration to %s", prefspath) else: # check to make sure they're valid unused_value = validPreferences()
def makeMpkgPlist(path): vers = getFullVersion() major, minor = map(int, getVersion().split(".", 2)) pl = Plist( CFBundleGetInfoString="MacPython %s" % (vers,), CFBundleIdentifier="org.python.MacPython", CFBundleName="MacPython", CFBundleShortVersionString=vers, IFMajorVersion=major, IFMinorVersion=minor, IFPkgFlagComponentDirectory="Contents/Packages", IFPkgFlagPackageList=[ dict( IFPkgFlagPackageLocation="%s-%s.pkg" % (item["name"], getVersion()), IFPkgFlagPackageSelection="selected", ) for item in PKG_RECIPES ], IFPkgFormatVersion=0.10000000149011612, IFPkgFlagBackgroundScaling="proportional", IFPkgFlagBackgroundAlignment="left", IFPkgFlagAuthorizationAction="RootAuthorization", ) writePlist(pl, path)
def main(): FullVersionStr = "" for line in fileinput.input(scriptpath + "/JuceLibraryCode/AppConfig.h",inplace=0): if "#define JucePlugin_Version " in line: FullVersionStr = line.lstrip("#define JucePlugin_Version ").strip() today = datetime.date.today() CFBundleGetInfoString = FullVersionStr + ", Copyright MatthieuBrucher, " + str(today.year) CFBundleVersion = FullVersionStr print("update_version.py - setting version to " + FullVersionStr) print("Updating plist version info...") import glob for plistpath in glob.glob(scriptpath + "/Builds/MacOSX/*.plist"): update_plist(plistpath, CFBundleGetInfoString, CFBundleVersion) print("Updating Mac Installer version info...") plistpath = scriptpath + "/installer/ATKColoredExpander.pkgproj" installer = plistlib.readPlist(plistpath) for x in installer['PACKAGES']: x['PACKAGE_SETTINGS']['VERSION'] = FullVersionStr plistlib.writePlist(installer, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//"); print("Updating Windows Installer version info...") for line in fileinput.input(scriptpath + "/installer/ATKColoredExpander.iss",inplace=1): if "AppVersion" in line: line="AppVersion=" + FullVersionStr + "\n" sys.stdout.write(line)
def normalizeReferenceResults(Dir, SBOutputDir, ProjectBuildMode): """ Make the absolute paths relative in the reference results. """ for (DirPath, Dirnames, Filenames) in os.walk(SBOutputDir): for F in Filenames: if (not F.endswith('plist')): continue Plist = os.path.join(DirPath, F) Data = plistlib.readPlist(Plist) PathPrefix = Dir if (ProjectBuildMode == 1): PathPrefix = os.path.join(Dir, PatchedSourceDirName) Paths = [SourceFile[len(PathPrefix) + 1:] if SourceFile.startswith(PathPrefix) else SourceFile for SourceFile in Data['files']] Data['files'] = Paths # Remove transient fields which change from run to run. for Diag in Data['diagnostics']: if 'HTMLDiagnostics_files' in Diag: Diag.pop('HTMLDiagnostics_files') if 'clang_version' in Data: Data.pop('clang_version') plistlib.writePlist(Data, Plist)
def killSafariCookies(): """ remove all cookies from ~/Library/Cookies/Cookies.plist matching the domain of .*crunchyroll.com and save the result. """ import os import plistlib #Plex's sandboxing doesn't allow me to import platform, # so let's not check for darwin and just fail. # import platform # isDarwin = "darwin" in platform.system().lower() isDarwin = True # assume if isDarwin: filename = os.path.expanduser("~/Library/Cookies/Cookies.plist") try: theList = plistlib.readPlist(filename) except IOError: #hm, okay, whatev, no file or gimpiness, let's bail return theSavedList = [] for item in theList: if not "crunchyroll.com" in item['Domain']: theSavedList.append(item) else: #Log.Debug("######removing cookie:") #Log.Debug(item) pass plistlib.writePlist(theSavedList, filename)
def test_cstringio(self): from cStringIO import StringIO f = StringIO() pl = self._create() plistlib.writePlist(pl, f) pl2 = plistlib.readPlist(StringIO(f.getvalue())) self.assertEqual(dict(pl), dict(pl2))
def bundle(self, app_path): self.check(app_path) contents = os.path.join(app_path, 'Contents', ) macos = os.path.join(contents, 'MacOS') resources = os.path.join(contents, 'Resources') info_plist = os.path.join(contents, 'Info.plist') exe_path = os.path.join(macos, self.script_name) info = self._build_info() print 'Creating app directories...' os.makedirs(macos) os.mkdir(resources) print 'Copying executable...' shutil.copyfile(self.script_path, exe_path) print 'Setting executable attributes...' os.lchmod(exe_path, 0755) if self.icon is not None: print 'Copying icon...' icon_dst = os.path.join(resources, self.icon_name) shutil.copy(self.icon, icon_dst) print 'Creating Info.plist...' plistlib.writePlist(info, info_plist)
def make_component_property_list(self): """Use pkgutil --analyze to build a component property list; then turn off package relocation""" self.component_plist = os.path.join(self.tmproot, "component.plist") try: p = subprocess.Popen(("/usr/bin/pkgbuild", "--analyze", "--root", self.tmp_pkgroot, self.component_plist), stdout=subprocess.PIPE, stderr=subprocess.PIPE) (out, err) = p.communicate() except OSError as e: raise PackagerError( "pkgbuild execution failed with error code %d: %s" % (e.errno, e.strerror)) if p.returncode != 0: raise PackagerError( "pkgbuild failed with exit code %d: %s" % (p.returncode, " ".join(str(err).split()))) try: plist = plistlib.readPlist(self.component_plist) except BaseException as err: raise PackagerError("Couldn't read %s" % self.component_plist) # plist is an array of dicts, iterate through for bundle in plist: if bundle.get("BundleIsRelocatable"): bundle["BundleIsRelocatable"] = False try: plistlib.writePlist(plist, self.component_plist) except BaseException as err: raise PackagerError("Couldn't write %s" % self.component_plist)
def update_plist(plistpath, CFBundleGetInfoString, CFBundleVersion): plist = plistlib.readPlist(plistpath) plist['CFBundleGetInfoString'] = CFBundleGetInfoString plist['CFBundleVersion'] = CFBundleVersion plist['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(plist, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//");
def writeDHCPPlist(plistPath,offer): ''' Write DHCP info to Plist for Serice Discovery Tool ''' dhcpServer = offer.DHCPServerIdentifier ipAdd = offer.offerIP # Check for existing DHCP Info if os.path.exists(plistPath): try: pldata = plistlib.readPlist(plistPath) except: print("Can't read plist.") try: # Update to current values pldata["dhcp"]["dhcpserverip"] = dhcpServer pldata["dhcp"]["ipaddress"] = ipAdd #print("Found existing DHCP Settings, Updating Plist...") except: print("Couldn't Write DHCP Settings.") else: pldata = dict(bsdp = [],dhcp = dict(dhcpserverip=dhcpServer, ipaddress=ipAdd)) try: plistlib.writePlist(pldata, plistPath) except NameError as e: print("Failed to write plist!") print(e)
def main(): '''Main''' # Create cache dir if it does not exist cachedir = '%s/cache' % os.path.dirname(os.path.realpath(__file__)) if not os.path.exists(cachedir): os.makedirs(cachedir) # Check for existance of /usr/local/bin/mbbr before going further mbbr_dir = '/usr/local/bin/mbbr' if not os.path.exists(mbbr_dir): print 'Client is missing the mbbr tool at /usr/local/bin/mbbr. Exiting' exit(0) # Skip manual check if len(sys.argv) > 1: if sys.argv[1] == 'manualcheck': print 'Manual check: skipping' exit(0) # Get results result = dict() info = get_mbbr_info() result = flatten_mbbr_info(info) # Write mbbr results to cache output_plist = os.path.join(cachedir, 'malwarebytes.plist') plistlib.writePlist(result, output_plist)
def create_appbundle( destdir, name, extension=".app", module=py2app.apptemplate, platform="MacOS", copy=mergecopy, mergetree=mergetree, condition=skipscm, plist=None, arch=None, redirect_stdout=False, ): if plist is None: plist = {} kw = module.plist_template.infoPlistDict( plist.get("CFBundleExecutable", name), plist) app = os.path.join(destdir, kw["CFBundleName"] + extension) if os.path.exists(app): # Remove any existing build artifacts to ensure that # we're getting a clean build shutil.rmtree(app) contents = os.path.join(app, "Contents") resources = os.path.join(contents, "Resources") platdir = os.path.join(contents, platform) dirs = [contents, resources, platdir] plist = {} plist.update(kw) plistPath = os.path.join(contents, "Info.plist") if os.path.exists(plistPath): with open(plistPath, "rb") as fp: if hasattr(plistlib, "load"): contents = plistlib.load(fp) else: # 2.7 contents = plistlib.readPlist(fp) if plist != contents: for d in dirs: shutil.rmtree(d, ignore_errors=True) for d in dirs: makedirs(d) with open(plistPath, "wb") as fp: if hasattr(plistlib, "dump"): plistlib.dump(plist, fp) else: plistlib.writePlist(plist, fp) srcmain = module.setup.main(arch=arch, redirect_asl=redirect_stdout) if sys.version_info[0] == 2 and isinstance( kw["CFBundleExecutable"], unicode # noqa: F821 ): destmain = os.path.join(platdir, kw["CFBundleExecutable"].encode("utf-8")) else: destmain = os.path.join(platdir, kw["CFBundleExecutable"]) with open(os.path.join(contents, "PkgInfo"), "w") as fp: fp.write(kw["CFBundlePackageType"] + kw["CFBundleSignature"]) print("Copy %r -> %r" % (srcmain, destmain)) copy(srcmain, destmain) make_exec(destmain) mergetree( resource_filename(module.__name__, "lib"), resources, condition=condition, copyfn=copy, ) return app, plist
def main(): argparser = ArgumentParser(description='Restore lost kerning') argparser.add_argument( '-dry', dest='dryRun', action='store_const', const=True, default=False, help='Do not modify anything, but instead just print what would happen.') argparser.add_argument( 'srcFont', metavar='<fontfile>', type=str, help='TrueType, OpenType or UFO fonts to gather glyph info from') argparser.add_argument( 'diffFile', metavar='<diffile>', type=str, help='Diff file') args = argparser.parse_args() dryRun = args.dryRun agl = parseAGL('src/glyphlist.txt') diacriticComps = loadGlyphCompositions('src/diacritics.txt') altUc2names, altName2ucs = loadAltNamesDB(agl, args.srcFont) localUc2Names, localName2ucs = loadLocalNamesDB(agl, diacriticComps) canonicalGlyphName = lambda name: _canonicalGlyphName( name, localName2ucs, localUc2Names, altName2ucs) deletedNames = loadNamesFromDiff(args.diffFile) # 10e15297b.diff deletedDiacriticNames = OrderedDict() for glyphName, comp in diacriticComps.iteritems(): if glyphName in deletedNames: deletedDiacriticNames[glyphName] = comp for fontPath in srcFontPaths: addedGroupNames = set() oldFilenamePrefix = 'regular' if fontPath.find('Bold') != -1: oldFilenamePrefix = 'bold' oldGroups, oldNameToGroups = loadGroups( oldFilenamePrefix + '-groups.plist') oldKerning, oldLIndex, oldRIndex, oldRGroupIndex = loadKerning( oldFilenamePrefix + '-kerning.plist') # lIndex : { name => <ref to plist right-hand side dict> } # rIndex : { name => [(left-hand-side-name, kernVal), ...] } currGroupFilename = os.path.join(fontPath, 'groups.plist') currKerningFilename = os.path.join(fontPath, 'kerning.plist') currGroups, currNameToGroups = loadGroups(currGroupFilename) currKerning, currLIndex, currRIndex, currRGroupIndex = loadKerning(currKerningFilename) for glyphName, comp in deletedDiacriticNames.iteritems(): oldGroupMemberships = oldNameToGroups.get(glyphName) localGlyphName, localUc = canonicalGlyphName(glyphName) # if glyphName != 'dcaron': # continue # XXX DEBUG if localGlyphName is None: # glyph does no longer exist -- ignore print('[IGNORE]', glyphName) continue if oldGroupMemberships: # print('group', localGlyphName, # '=>', localUc, # 'in old group:', oldGroupMemberships, ', curr group:', currGroupMemberships) for oldGroupName in oldGroupMemberships: currGroup = currGroups.get(oldGroupName) # None|[glyphname, ...] # print('GM ', localGlyphName, oldGroupName, len(currGroup) if currGroup else 0) if currGroup is not None: if localGlyphName not in currGroup: # print('[UPDATE group]', oldGroupName, 'append', localGlyphName) currGroup.append(localGlyphName) else: # group does not currently exist if currNameToGroups.get(localGlyphName): raise Exception('TODO: case where glyph is in some current groups, but not the' + 'original-named group') print('[ADD group]', oldGroupName, '=> [', localGlyphName, ']') currGroups[oldGroupName] = [localGlyphName] addedGroupNames.add(oldGroupName) # if oldGroupName in oldKerning: # print('TODO: effects of oldGroupName being in oldKerning:', # oldKerning[oldGroupName]) if oldGroupName in oldRGroupIndex: print('TODO: effects of oldGroupName being in oldRGroupIndex:', oldRGroupIndex[oldGroupName]) else: # if not oldGroupMemberships ucs = localName2ucs.get(glyphName) if not ucs: raise Exception( 'TODO non-group, non-local name ' + glyphName + ' -- lookup in alt names') asLeft = oldLIndex.get(glyphName) atRightOf = oldRIndex.get(glyphName) # print('individual', glyphName, # '=>', ', '.join([str(uc) for uc in ucs]), # '\n as left:', asLeft is not None, # '\n at right of:', atRightOf is not None) if asLeft: currKern = currKerning.get(localGlyphName) if currKern is None: rightValues = {} for rightName, kernValue in asLeft.iteritems(): if rightName[0] == '@': currGroup = currGroups.get(rightName) if currGroup and localGlyphName not in currGroup: rightValues[rightName] = kernValue else: localName, localUc = canonicalGlyphName(rightName) if localName: rightValues[localName] = kernValue if len(rightValues) > 0: print('[ADD currKerning]', localGlyphName, '=>', rightValues) currKerning[localGlyphName] = rightValues if atRightOf: for parentLeftName, kernVal in atRightOf: # print('atRightOf:', parentLeftName, kernVal) if parentLeftName[0] == '@': if parentLeftName in currGroups: k = currKerning.get(parentLeftName) if k: if localGlyphName not in k: print('[UPDATE currKerning g]', parentLeftName, '+= {', localGlyphName, ':', kernVal, '}') k[localGlyphName] = kernVal else: print('TODO: left-group is NOT in currKerning; left-group', parentLeftName) else: localParentLeftGlyphName, _ = canonicalGlyphName(parentLeftName) if localParentLeftGlyphName: k = currKerning.get(localParentLeftGlyphName) if k: if localGlyphName not in k: print('[UPDATE currKerning i]', localParentLeftGlyphName, '+= {', localGlyphName, ':', kernVal, '}') k[localGlyphName] = kernVal else: print('[ADD currKerning i]', localParentLeftGlyphName, '=> {', localGlyphName, ':', kernVal, '}') currKerning[localParentLeftGlyphName] = {localGlyphName: kernVal} for groupName in addedGroupNames: print('————————————————————————————————————————————') print('re-introduce group', groupName, 'to kerning') oldRKern = oldKerning.get(groupName) if oldRKern is not None: newRKern = {} for oldRightName, kernVal in oldRKern.iteritems(): if oldRightName[0] == '@': if oldRightName in currGroups: newRKern[oldRightName] = kernVal else: # Note: (oldRightName in addedGroupNames) should always be False here # as we would have added it to currGroups already. print('[DROP group]', oldRightName, kernVal) if oldRightName in currGroups: del currGroups[oldRightName] else: localGlyphName, _ = canonicalGlyphName(oldRightName) if localGlyphName: newRKern[localGlyphName] = kernVal print('localGlyphName', localGlyphName) if len(newRKern): print('[ADD currKerning g]', groupName, newRKern) currKerning[groupName] = newRKern # oldRGroupIndex : { group-name => [(left-hand-side-name, kernVal), ...] } oldLKern = oldRGroupIndex.get(groupName) if oldLKern: for oldRightName, kernVal in oldLKern: if oldRightName[0] == '@': if oldRightName in currGroups: k = currKerning.get(oldRightName) if k is not None: print('[UPDATE kerning g]', oldRightName, '+= {', groupName, ':', kernVal, '}') k[groupName] = kernVal else: currKerning[oldRightName] = {groupName: kernVal} print('[ADD kerning g]', oldRightName, '= {', groupName, ':', kernVal, '}') else: localGlyphName, _ = canonicalGlyphName(oldRightName) if localGlyphName: k = currKerning.get(localGlyphName) if k is not None: print('[UPDATE kerning i]', localGlyphName, '+= {', groupName, ':', kernVal, '}') k[groupName] = kernVal else: currKerning[localGlyphName] = {groupName: kernVal} print('[ADD kerning i]', localGlyphName, '= {', groupName, ':', kernVal, '}') print('Write', currGroupFilename) if not dryRun: plistlib.writePlist(currGroups, currGroupFilename) print('Write', currKerningFilename) if not dryRun: plistlib.writePlist(currKerning, currKerningFilename)
def SaveRaycastingPreset(self, preset_name): preset = prj.Project().raycasting_preset preset['name'] = preset_name preset_dir = os.path.join(inv_paths.USER_RAYCASTING_PRESETS_DIRECTORY, preset_name + '.plist') plistlib.writePlist(preset, preset_dir)
#!/usr/bin/env python import plistlib import json import tkFileDialog import re import sys file_to_open = tkFileDialog.askopenfilename( message="Select an existing plist or json file to convert.") converted = None if file_to_open.endswith('json'): converted = "plist" converted_dict = json.load(open(file_to_open)) file_to_write = tkFileDialog.asksaveasfilename( message="Select a filename to save the converted file.", defaultextension=converted) plistlib.writePlist(converted_dict, file_to_write) elif file_to_open.endswith('plist'): converted = "json" converted_dict = plistlib.readPlist(file_to_open) converted_string = json.dumps(converted_dict, sort_keys=True, indent=4) file_to_write = tkFileDialog.asksaveasfilename( message="Select a filename to save the converted file.", defaultextension=converted) open(file_to_write, 'w').write(converted_string) else: print("WHAT THE F*** ARE YOU TRYING TO DO??????") sys.exit(1)
def __exit__(self, exc_type, exc_value, exc_tb): if self._rewrite and not exc_type: plistlib.writePlist(self._plist, self._path) self._plist = None
def main(): MajorStr = "" MinorStr = "" BugfixStr = "" for line in fileinput.input(scriptpath + "/resource.h", inplace=0): if "#define PLUG_VER " in line: FullVersion = int(string.lstrip(line, "#define PLUG_VER "), 16) major = FullVersion & 0xFFFF0000 MajorStr = str(major >> 16) minor = FullVersion & 0x0000FF00 MinorStr = str(minor >> 8) BugfixStr = str(FullVersion & 0x000000FF) FullVersionStr = MajorStr + "." + MinorStr + "." + BugfixStr today = datetime.date.today() CFBundleGetInfoString = FullVersionStr + ", Copyright jo12bar, " + str( today.year) CFBundleVersion = FullVersionStr print "update_version.py - setting version to " + FullVersionStr print "Updating plist version info..." plistpath = scriptpath + "/resources/Bluesend-VST2-Info.plist" vst2 = plistlib.readPlist(plistpath) vst2['CFBundleGetInfoString'] = CFBundleGetInfoString vst2['CFBundleVersion'] = CFBundleVersion vst2['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(vst2, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/Bluesend-AU-Info.plist" au = plistlib.readPlist(plistpath) au['CFBundleGetInfoString'] = CFBundleGetInfoString au['CFBundleVersion'] = CFBundleVersion au['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(au, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/Bluesend-VST3-Info.plist" vst3 = plistlib.readPlist(plistpath) vst3['CFBundleGetInfoString'] = CFBundleGetInfoString vst3['CFBundleVersion'] = CFBundleVersion vst3['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(vst3, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/Bluesend-OSXAPP-Info.plist" app = plistlib.readPlist(plistpath) app['CFBundleGetInfoString'] = CFBundleGetInfoString app['CFBundleVersion'] = CFBundleVersion app['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(app, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/Bluesend-RTAS-Info.plist" rtas = plistlib.readPlist(plistpath) rtas['CFBundleGetInfoString'] = CFBundleGetInfoString rtas['CFBundleVersion'] = CFBundleVersion rtas['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(rtas, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/Bluesend-AAX-Info.plist" aax = plistlib.readPlist(plistpath) aax['CFBundleGetInfoString'] = CFBundleGetInfoString aax['CFBundleVersion'] = CFBundleVersion aax['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(aax, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") # plistpath = scriptpath + "/resources/Bluesend-IOSAPP-Info.plist" # iosapp = plistlib.readPlist(plistpath) # iosapp['CFBundleGetInfoString'] = CFBundleGetInfoString # iosapp['CFBundleVersion'] = CFBundleVersion # iosapp['CFBundleShortVersionString'] = CFBundleVersion # plistlib.writePlist(iosapp, plistpath) # replacestrs(plistpath, "//Apple//", "//Apple Computer//"); print "Updating Mac Installer version info..." plistpath = scriptpath + "/installer/Bluesend.pkgproj" installer = plistlib.readPlist(plistpath) for x in range(0, 6): installer['PACKAGES'][x]['PACKAGE_SETTINGS'][ 'VERSION'] = FullVersionStr plistlib.writePlist(installer, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") print "Updating Windows Installer version info..." for line in fileinput.input(scriptpath + "/installer/Bluesend.iss", inplace=1): if "AppVersion" in line: line = "AppVersion=" + FullVersionStr + "\n" sys.stdout.write(line)
def save_plist(data, output_path): """Save data as Plist to output_path.""" with open(output_path, 'wb') as output_file: plistlib.writePlist(data, output_file)
def packageFromRecipe(targetDir, recipe): curdir = os.getcwd() try: # The major version (such as 2.5) is included in the package name # because having two version of python installed at the same time is # common. pkgname = '%s-%s' % (recipe['name'], getVersion()) srcdir = recipe.get('source') pkgroot = recipe.get('topdir', srcdir) postflight = recipe.get('postflight') readme = textwrap.dedent(recipe['readme']) isRequired = recipe.get('required', True) print "- building package %s" % (pkgname, ) # Substitute some variables textvars = dict( VER=getVersion(), FULLVER=getFullVersion(), ) readme = readme % textvars if pkgroot is not None: pkgroot = pkgroot % textvars else: pkgroot = '/' if srcdir is not None: srcdir = os.path.join(WORKDIR, '_root', srcdir[1:]) srcdir = srcdir % textvars if postflight is not None: postflight = os.path.abspath(postflight) packageContents = os.path.join(targetDir, pkgname + '.pkg', 'Contents') os.makedirs(packageContents) if srcdir is not None: os.chdir(srcdir) runCommand( "pax -wf %s . 2>&1" % (shellQuote(os.path.join(packageContents, 'Archive.pax')), )) runCommand( "gzip -9 %s 2>&1" % (shellQuote(os.path.join(packageContents, 'Archive.pax')), )) runCommand( "mkbom . %s 2>&1" % (shellQuote(os.path.join(packageContents, 'Archive.bom')), )) fn = os.path.join(packageContents, 'PkgInfo') fp = open(fn, 'w') fp.write('pmkrpkg1') fp.close() rsrcDir = os.path.join(packageContents, "Resources") os.mkdir(rsrcDir) fp = open(os.path.join(rsrcDir, 'ReadMe.txt'), 'w') fp.write(readme) fp.close() if postflight is not None: patchScript(postflight, os.path.join(rsrcDir, 'postflight')) vers = getFullVersion() major, minor = map(int, getVersion().split('.', 2)) pl = Plist( CFBundleGetInfoString="MacPython.%s %s" % ( pkgname, vers, ), CFBundleIdentifier='org.python.MacPython.%s' % (pkgname, ), CFBundleName='MacPython.%s' % (pkgname, ), CFBundleShortVersionString=vers, IFMajorVersion=major, IFMinorVersion=minor, IFPkgFormatVersion=0.10000000149011612, IFPkgFlagAllowBackRev=False, IFPkgFlagAuthorizationAction="RootAuthorization", IFPkgFlagDefaultLocation=pkgroot, IFPkgFlagFollowLinks=True, IFPkgFlagInstallFat=True, IFPkgFlagIsRequired=isRequired, IFPkgFlagOverwritePermissions=False, IFPkgFlagRelocatable=False, IFPkgFlagRestartAction="NoRestart", IFPkgFlagRootVolumeOnly=True, IFPkgFlagUpdateInstalledLangauges=False, ) writePlist(pl, os.path.join(packageContents, 'Info.plist')) pl = Plist( IFPkgDescriptionDescription=readme, IFPkgDescriptionTitle=recipe.get('long_name', "MacPython.%s" % (pkgname, )), IFPkgDescriptionVersion=vers, ) writePlist( pl, os.path.join(packageContents, 'Resources', 'Description.plist')) finally: os.chdir(curdir)
#!/usr/bin/env python """Alter Inselect's existing plist file """ # https://developer.apple.com/library/mac/documentation/Carbon/Conceptual/LaunchServicesConcepts/LSCConcepts/LSCConcepts.html#//apple_ref/doc/uid/TP30000999-CH202-CIHHEGGE import plistlib import sys import inselect plist = plistlib.readPlist(sys.argv[1]) plist['CFBundleShortVersionString'] = inselect.__version__ plist['CFBundleDisplayName'] = 'Inselect' plist['CFBundleDocumentTypes'] = [{ 'CFBundleTypeName': 'Inselect document', 'CFBundleTypeIconFile': 'inselect.icns', 'CFBundleTypeExtensions': ['inselect'], 'CFBundleTypeRole': 'Editor', 'LSTypeIsPackage': 'False', }] plistlib.writePlist(plist, sys.argv[1])
def main(): demo = 0 if len(sys.argv) != 2: print("Usage: update_installer_version.py demo(0 or 1)") sys.exit(1) else: demo = int(sys.argv[1]) config = parse_config(projectpath) # MAC INSTALLER print "Updating Mac Installer version info..." plistpath = projectpath + "/installer/" + config['BUNDLE_NAME'] + ".pkgproj" installer = plistlib.readPlist(plistpath) # range = number of items in the installer (VST 2, VST 3, app, audiounit, aax) for x in range(0, 5): installer['PACKAGES'][x]['PACKAGE_SETTINGS']['VERSION'] = config[ 'FULL_VER_STR'] if demo: installer['PROJECT']['PROJECT_PRESENTATION']['TITLE']['LOCALIZATIONS'][ 0]['VALUE'] = config['BUNDLE_NAME'] + " Demo" installer['PROJECT']['PROJECT_PRESENTATION']['INTRODUCTION'][ 'LOCALIZATIONS'][0]['VALUE']['PATH'] = "intro-demo.rtf" else: installer['PROJECT']['PROJECT_PRESENTATION']['TITLE']['LOCALIZATIONS'][ 0]['VALUE'] = config['BUNDLE_NAME'] installer['PROJECT']['PROJECT_PRESENTATION']['INTRODUCTION'][ 'LOCALIZATIONS'][0]['VALUE']['PATH'] = "intro.rtf" plistlib.writePlist(installer, plistpath) # replacestrs(plistpath, "//Apple//", "//Apple Computer//"); # WIN INSTALLER print "Updating Windows Installer version info..." for line in fileinput.input(projectpath + "/installer/" + config['BUNDLE_NAME'] + ".iss", inplace=1): if "AppVersion" in line: line = "AppVersion=" + config['FULL_VER_STR'] + "\n" if "OutputBaseFilename" in line: if demo: line = "OutputBaseFilename=IGraphicsTest Demo Installer\n" else: line = "OutputBaseFilename=IGraphicsTest Installer\n" if 'Source: "readme' in line: if demo: line = 'Source: "readme-win-demo.rtf"; DestDir: "{app}"; DestName: "readme.rtf"; Flags: isreadme\n' else: line = 'Source: "readme-win.rtf"; DestDir: "{app}"; DestName: "readme.rtf"; Flags: isreadme\n' if "WelcomeLabel1" in line: if demo: line = "WelcomeLabel1=Welcome to the IGraphicsTest Demo installer\n" else: line = "WelcomeLabel1=Welcome to the IGraphicsTest installer\n" if "SetupWindowTitle" in line: if demo: line = "SetupWindowTitle=IGraphicsTest Demo installer\n" else: line = "SetupWindowTitle=IGraphicsTest installer\n" sys.stdout.write(line)
else: print >> sys.stderr, concat_message(msg, *args) def writeDataToPlist(data, filename): '''Writes a dict or list to a plist in our metadata dir''' metadata_dir = pref('UpdatesMetadataDir') if not os.path.exists(metadata_dir): try: os.makedirs(metadata_dir) except OSError, errmsg: print_stderr( 'Could not create missing %s because %s', metadata_dir, errmsg) try: plistlib.writePlist(data, os.path.join(metadata_dir, filename)) except (IOError, OSError, TypeError), errmsg: print_stderr( 'Could not write %s because %s', filename, errmsg) def getDataFromPlist(filename): '''Reads data from a plist in our metadata dir''' metadata_dir = pref('UpdatesMetadataDir') try: return plistlib.readPlist( os.path.join(metadata_dir, filename)) except (IOError, ExpatError): return {}
def Main(argv): parser = optparse.OptionParser('%prog [options]') parser.add_option('--plist', dest='plist_path', action='store', type='string', default=None, help='The path of the plist to tweak.') parser.add_option('--output', dest='plist_output', action='store', type='string', default=None, help='If specified, the path to output ' + \ 'the tweaked plist, rather than overwriting the input.') parser.add_option('--breakpad', dest='use_breakpad', action='store', type='int', default=False, help='Enable Breakpad [1 or 0]') parser.add_option('--breakpad_staging', dest='use_breakpad_staging', action='store_true', default=False, help='Use staging breakpad to upload reports. Ignored if --breakpad=0.') parser.add_option('--keystone', dest='use_keystone', action='store', type='int', default=False, help='Enable Keystone [1 or 0]') parser.add_option('--scm', dest='add_scm_info', action='store', type='int', default=True, help='Add SCM metadata [1 or 0]') parser.add_option('--branding', dest='branding', action='store', type='string', default=None, help='The branding of the binary') parser.add_option('--bundle_id', dest='bundle_identifier', action='store', type='string', default=None, help='The bundle id of the binary') parser.add_option('--platform', choices=('ios', 'mac'), default='mac', help='The target platform of the bundle') parser.add_option('--version-overrides', action='append', help='Key-value pair to override specific component of version ' 'like key=value (can be passed multiple time to configure ' 'more than one override)') parser.add_option('--format', choices=('binary1', 'xml1', 'json'), default='xml1', help='Format to use when writing property list ' '(default: %(default)s)') parser.add_option('--version', dest='version', action='store', type='string', default=None, help='The version string [major.minor.build.patch]') (options, args) = parser.parse_args(argv) if len(args) > 0: print >>sys.stderr, parser.get_usage() return 1 if not options.plist_path: print >>sys.stderr, 'No --plist specified.' return 1 # Read the plist into its parsed format. Convert the file to 'xml1' as # plistlib only supports that format in Python 2.7. with tempfile.NamedTemporaryFile() as temp_info_plist: retcode = _ConvertPlist(options.plist_path, temp_info_plist.name, 'xml1') if retcode != 0: return retcode plist = plistlib.readPlist(temp_info_plist.name) # Convert overrides. overrides = {} if options.version_overrides: for pair in options.version_overrides: if not '=' in pair: print >>sys.stderr, 'Invalid value for --version-overrides:', pair return 1 key, value = pair.split('=', 1) overrides[key] = value if key not in ('MAJOR', 'MINOR', 'BUILD', 'PATCH'): print >>sys.stderr, 'Unsupported key for --version-overrides:', key return 1 if options.platform == 'mac': version_format_for_key = { # Add public version info so "Get Info" works. 'CFBundleShortVersionString': '@MAJOR@.@MINOR@.@BUILD@.@PATCH@', # Honor the 429496.72.95 limit. The maximum comes from splitting 2^32 - 1 # into 6, 2, 2 digits. The limitation was present in Tiger, but it could # have been fixed in later OS release, but hasn't been tested (it's easy # enough to find out with "lsregister -dump). # http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html # BUILD will always be an increasing value, so BUILD_PATH gives us # something unique that meetings what LS wants. 'CFBundleVersion': '@BUILD@.@PATCH@', } else: version_format_for_key = { 'CFBundleShortVersionString': '@MAJOR@.@BUILD@.@PATCH@', 'CFBundleVersion': '@MAJOR@.@MINOR@.@BUILD@.@PATCH@' } if options.use_breakpad: version_format_for_key['BreakpadVersion'] = \ '@MAJOR@.@MINOR@.@BUILD@.@PATCH@' # Insert the product version. if not _AddVersionKeys( plist, version_format_for_key, version=options.version, overrides=overrides): return 2 # Add Breakpad if configured to do so. if options.use_breakpad: if options.branding is None: print >>sys.stderr, 'Use of Breakpad requires branding.' return 1 # Map "target_os" passed from gn via the --platform parameter # to the platform as known by breakpad. platform = {'mac': 'Mac', 'ios': 'iOS'}[options.platform] _AddBreakpadKeys(plist, options.branding, platform, options.use_breakpad_staging) else: _RemoveBreakpadKeys(plist) # Add Keystone if configured to do so. if options.use_keystone: if options.bundle_identifier is None: print >>sys.stderr, 'Use of Keystone requires the bundle id.' return 1 _AddKeystoneKeys(plist, options.bundle_identifier) else: _RemoveKeystoneKeys(plist) # Adds or removes any SCM keys. if not _DoSCMKeys(plist, options.add_scm_info): return 3 output_path = options.plist_path if options.plist_output is not None: output_path = options.plist_output # Now that all keys have been mutated, rewrite the file. with tempfile.NamedTemporaryFile() as temp_info_plist: plistlib.writePlist(plist, temp_info_plist.name) # Convert Info.plist to the format requested by the --format flag. Any # format would work on Mac but iOS requires specific format. return _ConvertPlist(temp_info_plist.name, output_path, options.format)
"matplotlib", "PIL", "pygame", "wx", "sphinx", "jinja2", ] ) ) ) # fix the icon path = os.path.join(os.path.dirname(__file__), "dist", "%s.app" % appName, "Contents", "Info.plist") appPlist = readPlist(path) appPlist["CFBundleIconFile"] = iconFile writePlist(appPlist, path) # get relevant paths drawBotRoot = os.path.dirname(os.path.abspath(__file__)) distLocation = os.path.join(drawBotRoot, "dist") appLocation = os.path.join(distLocation, "%s.app" % appName) imgLocation = os.path.join(distLocation, "img_%s" % appName) existingDmgLocation = os.path.join(distLocation, "%s.dmg" % appName) dmgLocation = os.path.join(distLocation, appName) if "-A" not in sys.argv: # make sure the external tools have the correct permissions externalTools = ("ffmpeg", "gifsicle", "mkbitmap", "potrace") for externalTool in externalTools:
def writeBranchCatalogs(localcatalogpath): '''Writes our branch catalogs''' catalog = plistlib.readPlist(localcatalogpath) downloaded_products = catalog['Products'] product_info = getProductInfo() localcatalogname = os.path.basename(localcatalogpath) # now strip the '.sucatalog' bit from the name # so we can use it to construct our branch catalog names if localcatalogpath.endswith('.sucatalog'): localcatalogpath = localcatalogpath[0:-10] # now write filtered catalogs (branches) catalog_branches = getCatalogBranches() for branch in catalog_branches.keys(): branchcatalogpath = localcatalogpath + '_' + branch + '.sucatalog' print_stdout('Building %s...' % os.path.basename(branchcatalogpath)) # embed branch catalog name into the catalog for troubleshooting # and validation catalog['_CatalogName'] = os.path.basename(branchcatalogpath) catalog['Products'] = {} for product_key in catalog_branches[branch]: if product_key in downloaded_products.keys(): # add the product to the Products dict # for this catalog catalog['Products'][product_key] = \ downloaded_products[product_key] elif pref('LocalCatalogURLBase') and product_key in product_info: # Product has probably been deprecated by Apple, # so we're using cached product info # First check to see if this product was ever in this # catalog original_catalogs = product_info[product_key].get( 'OriginalAppleCatalogs', []) for original_catalog in original_catalogs: if original_catalog.endswith(localcatalogname): # this item was originally in this catalog, so # we can add it to the branch catalog_entry = \ product_info[product_key].get('CatalogEntry') title = product_info[product_key].get('title') version = product_info[product_key].get('version') if catalog_entry: print_stderr( 'WARNING: Product %s (%s-%s) in branch %s ' 'has been deprecated. Will use cached info ' 'and packages.', product_key, title, version, branch) rewriteURLsForProduct(catalog_entry) catalog['Products'][product_key] = catalog_entry continue else: if pref('LocalCatalogURLBase') : print_stderr( 'WARNING: Product %s not added to branch %s of %s. ' 'It is not in the corresponding Apple catalogs ' 'and is not in the ProductInfo cache.', product_key, branch, localcatalogname) else: print_stderr( 'WARNING: Product %s not added to branch %s of %s. ' 'It is not in the corresponding Apple catalog.', product_key, branch, localcatalogname) plistlib.writePlist(catalog, branchcatalogpath)
import sys import plistlib ## ## update version in Info.plist ## ## usage: python ./plist.py 6 ## version = sys.argv[1] infoPlist = 'Info.plist' info = plistlib.readPlist(infoPlist) info['CFBundleShortVersionString'] = version info['CFBundleVersion'] = version plistlib.writePlist(info, infoPlist)
def WriteTo(self, target_path): plistlib.writePlist(self._data, target_path)
def main(): config = parse_config(projectpath) today = datetime.date.today() CFBundleGetInfoString = config['BUNDLE_NAME'] + " v" + config[ 'FULL_VER_STR'] + " " + config['PLUG_COPYRIGHT_STR'] CFBundleVersion = config['FULL_VER_STR'] print "update_version.py - setting version to " + config['FULL_VER_STR'] print "Updating plist version info..." plistpath = scriptpath + "/resources/BitReKt-VST2-Info.plist" vst2 = plistlib.readPlist(plistpath) vst2['CFBundleGetInfoString'] = CFBundleGetInfoString vst2['CFBundleVersion'] = CFBundleVersion vst2['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(vst2, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/BitReKt-AU-Info.plist" au = plistlib.readPlist(plistpath) au['CFBundleGetInfoString'] = CFBundleGetInfoString au['CFBundleVersion'] = CFBundleVersion au['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(au, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/BitReKt-VST3-Info.plist" vst3 = plistlib.readPlist(plistpath) vst3['CFBundleGetInfoString'] = CFBundleGetInfoString vst3['CFBundleVersion'] = CFBundleVersion vst3['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(vst3, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/BitReKt-macOS-Info.plist" app = plistlib.readPlist(plistpath) app['CFBundleGetInfoString'] = CFBundleGetInfoString app['CFBundleVersion'] = CFBundleVersion app['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(app, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/BitReKt-AAX-Info.plist" aax = plistlib.readPlist(plistpath) aax['CFBundleGetInfoString'] = CFBundleGetInfoString aax['CFBundleVersion'] = CFBundleVersion aax['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(aax, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") print "Updating Mac Installer version info..." plistpath = scriptpath + "/installer/BitReKt.pkgproj" installer = plistlib.readPlist(plistpath) for x in range(0, 5): installer['PACKAGES'][x]['PACKAGE_SETTINGS']['VERSION'] = config[ 'FULL_VER_STR'] plistlib.writePlist(installer, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") print "Updating Windows Installer version info..." for line in fileinput.input(scriptpath + "/installer/BitReKt.iss", inplace=1): if "AppVersion" in line: line = "AppVersion=" + config['FULL_VER_STR'] + "\n" sys.stdout.write(line)
print >> sys.stderr, 'Error %s in file %s' % (err, filename) if facts: # Read the location of the ManagedInstallDir from ManagedInstall.plist bundle_id = 'ManagedInstalls' pref_name = 'ManagedInstallDir' managedinstalldir = CFPreferencesCopyAppValue(pref_name, bundle_id) conditionalitemspath = os.path.join( managedinstalldir, 'ConditionalItems.plist') conditional_items = {} # read the current conditional items if os.path.exists(conditionalitemspath): try: conditional_items = plistlib.readPlist(conditionalitemspath) except (IOError, OSError, ExpatError), err: pass # update the conditional items conditional_items.update(facts) # and write them out try: plistlib.writePlist(conditional_items, conditionalitemspath) except (IOError, OSError), err: print >> sys.stderr, 'Couldn\'t save conditional items: %s' % err if __name__ == "__main__": sys.exit(main())
def main(): config = parse_config(projectpath) today = datetime.date.today() CFBundleGetInfoString = config['BUNDLE_NAME'] + " v" + config[ 'FULL_VER_STR'] + " " + config['PLUG_COPYRIGHT_STR'] CFBundleVersion = config['FULL_VER_STR'] print("update_version.py - setting version to " + config['FULL_VER_STR']) print("Updating plist version info...") plistpath = scriptpath + "/resources/IPlugWebUI-VST2-Info.plist" with open(plistpath, 'rb') as fp: vst2 = plistlib.load(fp) vst2['CFBundleGetInfoString'] = CFBundleGetInfoString vst2['CFBundleVersion'] = CFBundleVersion vst2['CFBundleShortVersionString'] = CFBundleVersion with open(plistpath, 'wb') as fp: plistlib.dump(vst2, fp) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/IPlugWebUI-AU-Info.plist" with open(plistpath, 'rb') as fp: au = plistlib.load(fp) au['CFBundleGetInfoString'] = CFBundleGetInfoString au['CFBundleVersion'] = CFBundleVersion au['CFBundleShortVersionString'] = CFBundleVersion with open(plistpath, 'wb') as fp: plistlib.dump(au, fp) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/IPlugWebUI-VST3-Info.plist" with open(plistpath, 'rb') as fp: vst3 = plistlib.load(fp) vst3['CFBundleGetInfoString'] = CFBundleGetInfoString vst3['CFBundleVersion'] = CFBundleVersion vst3['CFBundleShortVersionString'] = CFBundleVersion with open(plistpath, 'wb') as fp: plistlib.dump(vst3, fp) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/IPlugWebUI-macOS-Info.plist" with open(plistpath, 'rb') as fp: app = plistlib.load(fp) app['CFBundleGetInfoString'] = CFBundleGetInfoString app['CFBundleVersion'] = CFBundleVersion app['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(app, plistpath) replacestrs(plistpath, "//Apple//", "//Apple Computer//") plistpath = scriptpath + "/resources/IPlugWebUI-AAX-Info.plist" with open(plistpath, 'rb') as fp: aax = plistlib.load(fp) aax['CFBundleGetInfoString'] = CFBundleGetInfoString aax['CFBundleVersion'] = CFBundleVersion aax['CFBundleShortVersionString'] = CFBundleVersion with open(plistpath, 'wb') as fp: plistlib.dump(aax, fp) replacestrs(plistpath, "//Apple//", "//Apple Computer//") print("Updating Mac Installer version info...") plistpath = scriptpath + "/installer/IPlugWebUI.pkgproj" with open(plistpath, 'rb') as fp: installer = plistlib.load(fp) for x in range(0, 5): installer['PACKAGES'][x]['PACKAGE_SETTINGS']['VERSION'] = config[ 'FULL_VER_STR'] with open(plistpath, 'wb') as fp: plistlib.dump(installer, fp) replacestrs(plistpath, "//Apple//", "//Apple Computer//") print("Updating Windows Installer version info...") for line in fileinput.input(scriptpath + "/installer/IPlugWebUI.iss", inplace=1): if "AppVersion" in line: line = "AppVersion=" + config['FULL_VER_STR'] + "\n" sys.stdout.write(line)
def _saveChanges(self) -> None: """ Save changes to Plist """ writePlist(self.info, "info.plist")
def write(self): plistlib.writePlist(self.hDict, self.file)
def make_unrelocatable(plist): '''Changes BundleIsRelocatable in component plist to false''' p = plistlib.readPlist(plist) p[0]['BundleIsRelocatable'] = False plistlib.writePlist(p, plist)
def Main(argv): parser = optparse.OptionParser('%prog [options]') parser.add_option( '--breakpad', dest='use_breakpad', action='store', type='int', default=False, help='Enable Breakpad [1 or 0]') parser.add_option( '--breakpad_uploads', dest='breakpad_uploads', action='store', type='int', default=False, help='Enable Breakpad\'s uploading of crash dumps [1 or 0]') parser.add_option( '--keystone', dest='use_keystone', action='store', type='int', default=False, help='Enable Keystone [1 or 0]') parser.add_option( '--scm', dest='add_scm_info', action='store', type='int', default=True, help='Add SCM metadata [1 or 0]') parser.add_option( '--branding', dest='branding', action='store', type='string', default=None, help='The branding of the binary') parser.add_option( '--bundle_id', dest='bundle_identifier', action='store', type='string', default=None, help='The bundle id of the binary') parser.add_option( '--version', dest='version', action='store', type='string', default=None, help='The version string [major.minor.build.patch]') (options, args) = parser.parse_args(argv) if len(args) > 0: print >> sys.stderr, parser.get_usage() return 1 # Read the plist into its parsed format. DEST_INFO_PLIST = os.path.join(env['TARGET_BUILD_DIR'], env['INFOPLIST_PATH']) plist = plistlib.readPlist(DEST_INFO_PLIST) # Insert the product version. if not _AddVersionKeys(plist, version=options.version): return 2 # Add Breakpad if configured to do so. if options.use_breakpad: if options.branding is None: print >> sys.stderr, 'Use of Breakpad requires branding.' return 1 _AddBreakpadKeys(plist, options.branding) if options.breakpad_uploads: plist['BreakpadURL'] = 'https://clients2.google.com/cr/report' else: # This allows crash dumping to a file without uploading the # dump, for testing purposes. Breakpad does not recognise # "none" as a special value, but this does stop crash dump # uploading from happening. We need to specify something # because if "BreakpadURL" is not present, Breakpad will not # register its crash handler and no crash dumping will occur. plist['BreakpadURL'] = 'none' else: _RemoveBreakpadKeys(plist) # Only add Keystone in Release builds. if options.use_keystone and env['CONFIGURATION'] == 'Release': if options.bundle_identifier is None: print >> sys.stderr, 'Use of Keystone requires the bundle id.' return 1 _AddKeystoneKeys(plist, options.bundle_identifier) else: _RemoveKeystoneKeys(plist) # Adds or removes any SCM keys. if not _DoSCMKeys(plist, options.add_scm_info): return 3 # Now that all keys have been mutated, rewrite the file. temp_info_plist = tempfile.NamedTemporaryFile() plistlib.writePlist(plist, temp_info_plist.name) # Info.plist will work perfectly well in any plist format, but traditionally # applications use xml1 for this, so convert it to ensure that it's valid. proc = subprocess.Popen([ 'plutil', '-convert', 'xml1', '-o', DEST_INFO_PLIST, temp_info_plist.name ]) proc.wait() return proc.returncode
def create_group(): '''Method to make a group from a template.''' # Prompt: type of group: print ''' Creating a new group. Please select a template: - individual: for groups to be used for individually-assigned computers, including faculty and staff - lab: for labs and classrooms ''' group_template_type = raw_input("Group Type: ").strip().lower() if group_template_type not in ["individual", "lab"]: print "Invalid group type; please try again." return False # Prompt: Group Filesystem Name: print ''' Please choose a filesystem name for this group. Names should be lower-case and exclude spaces. ''' group_filesystem_name = raw_input( "Group Filesystem Name: ").strip().lower() if not group_filesystem_name: print "Group Filesystem Name cannot be blank; please try again." return False group_file_path = os.path.join(MUNKI_GROUP_MANIFESTS_PATH, group_filesystem_name) if os.path.exists(group_file_path): print "File named %s already exists in Munki group manifests directory; please try again." % group_filesystem_name return False # Prompt: Group Display Name: print ''' Provide a display name for this group. This is the user-visible name that appears in the Munki Enrollment Client. ''' group_display_name = raw_input("Group Display Name: ") if not group_display_name: print "Group Display Name cannot be blank; please try again." return False # Prompt: Group Description: print ''' Provide a description for this group. This appears in the Munki Enrollment Client. ''' group_description = raw_input("Group Description: ") # Prompt: Default Computer Name Prefix: print ''' Provide a default naming prefix that the Munki Enrollment Client can suggest for names. Must be 8 characters or less. ''' group_computer_name_prefix = raw_input("Computer Name Prefix: ") if len(group_computer_name_prefix) > 8: print "Computer Name Prefix must be 8 characters or less; please try again." return False # Create group dict starting with base: group_manifest_dict = TEMPLATE_GROUP_BASE # Add _metadata:display_name (manditory): group_manifest_dict["_metadata"]["display_name"] = group_display_name # Add _metadata:description (optional): if group_description: group_manifest_dict["_metadata"]["description"] = group_description # Add _metadata:computer_name_prefix (optional): if group_computer_name_prefix: group_manifest_dict["_metadata"][ "computer_name_prefix"] = group_computer_name_prefix # Lab group: if group_template_type == "lab": # Additional includes manifests: if INCLUDES_MANIFESTS_LABS: group_manifest_dict["included_manifests"].extend( INCLUDES_MANIFESTS_LABS) # Managed installs: if MANAGED_INSTALLS_LABS: group_manifest_dict["managed_installs"] = MANAGED_INSTALLS_LABS # Other dict items to merge: if MANIFEST_EXTENSION_DICT_LABS: group_manifest_dict.update(MANIFEST_EXTENSION_DICT_LABS) # Individual group: elif group_template_type == "individual": # Additional includes manifests: if INCLUDES_MANIFESTS_INDIVIDUALS: group_manifest_dict["included_manifests"].extend( INCLUDES_MANIFESTS_INDIVIDUALS) # Managed installs: if MANAGED_INSTALLS_INDIVIDUALS: group_manifest_dict[ "managed_installs"] = MANAGED_INSTALLS_INDIVIDUALS # Other dict items to merge: if MANIFEST_EXTENSION_DICT_INDIVIDUALS: group_manifest_dict.update(MANIFEST_EXTENSION_DICT_INDIVIDUALS) # Write group manifest: try: plistlib.writePlist(group_manifest_dict, group_file_path) return True except IOError: print "ERROR: Could not save new group to %s!" % group_file_path return False
def done(self): plistlib.writePlist(self.infoplist, self.infopath) print ' * Done!' print ''
def build(args): returncode = 0 copy_config_file(args) src_dir = os.path.join(cwd, "src") build_dir = os.path.join(cwd, "build", args.platform) requirements = get_value_for_platform("requirements", args.platform, []) requirements = requirements + get_value_for_platform("requirements", "common", []) ignore_paths = [] if args.config != "": ignore_dirs = get_value_for_config("ignore_dirs", args.config) print("Ignore dirs specified: %r" % ignore_dirs) if ignore_dirs: for ignore_dir in ignore_dirs: ignore_paths.append(os.path.abspath(ignore_dir)) if args.platform == "android": filename = info_json["name"].replace(" ", "") if args.config and args.config.strip() != "": build_dir = os.path.join(build_dir, args.config) icon_dir = os.path.join(cwd, "icons", "android") icon = os.path.join(icon_dir, get_value_for_platform("icons", "android", "fakefile")) print("Icon is %s" % icon) whitelist = os.path.abspath(get_value_for_platform("whitelist_file", "android", "fakefile")) launch = os.path.abspath(get_value_for_platform("launch_images", "android", "fakefile")) orientation = get_value_for_platform("orientation", "android", "sensor") intent_filters = get_value_for_platform("intent_filters", "android", '') if len(intent_filters) > 0: intent_filters = os.path.abspath(intent_filters) keystore = "" keyalias = "" keypasswd = "" build_type = "" if args.release: build_type = "release" signing = get_value_for_platform("codesign", "android", "") keystore = os.path.abspath(signing['keystore']) keyalias = signing['alias'] print("signing = %r" % (signing,)) print("keystore = %r, alias = %r" % (keystore, keyalias)) if 'passwd' in signing: keypasswd = signing['passwd'] else: keypasswd = getpass.getpass() if len(requirements) > 0: requirements = ",".join(requirements) else: requirements = "" if os.path.exists(build_dir): shutil.rmtree(build_dir) parent_dir = os.path.dirname(build_dir) if not os.path.exists(parent_dir): os.makedirs(parent_dir) copy_files(src_dir, build_dir, ignore_paths) venv_dir = os.path.join(build_dir, "venv") if not os.path.exists(venv_dir): os.makedirs(venv_dir) if "packages" in info_json: python = None if args.platform in ["ios", "android"]: python = "python2.7" pewtools.copy_deps_to_build(info_json["packages"], venv_dir, build_dir, python) copy_pew_module(build_dir) shutil.rmtree(venv_dir) cmd = ["bash", os.path.join(android_dir, "build.sh"), info_json["identifier"], filename, info_json["version"], build_dir, icon, launch, whitelist, orientation, requirements, build_type, intent_filters, keystore, keyalias, keypasswd] returncode = run_command(cmd) if args.platform == "ios": project_dir = os.path.join(cwd, "native", "ios", "PythonistaAppTemplate-master") if not os.path.exists(project_dir): print("iOS support files not downloaded for this project. Run 'pew init ios' first.") sys.exit(1) if os.path.exists(build_dir): shutil.rmtree(build_dir) project_build_dir = os.path.join(build_dir, os.path.basename(project_dir)) shutil.copytree(project_dir, project_build_dir) project_xcode_dir = os.path.join(project_build_dir, "PythonistaAppTemplate") plist_file = os.path.join(project_xcode_dir, "Info.plist") if os.path.exists(plist_file): version_short = info_json["version"].split(".") version_short = ".".join(version_short[:3]) plist = plistlib.readPlist(plist_file) plist['CFBundleIdentifier'] = info_json["identifier"] plist['CFBundleName'] = plist['CFBundleDisplayName'] = info_json["name"] plist['CFBundleVersion'] = info_json["version"] plist['CFBundleIconName'] = 'AppIcon' plist['CFBundleShortVersionString'] = version_short plist['UIStatusBarHidden'] = get_value_for_platform("hide_status_bar", "ios", True) # These are needed because the Python libraries contain references to # libs which need permissions. plist['NSCalendarsUsageDescription'] = "This app requires access to your calendar information." plist['NSPhotoLibraryUsageDescription'] = "This app requires access to your photo library." plist['NSBluetoothPeripheralUsageDescription'] = "This app requires access to a bluetooth peripheral." icons = get_value_for_platform("icons", "ios", []) if len(icons) > 0: appicon_dir = os.path.join(project_xcode_dir, "Assets.xcassets", "AppIcon.appiconset") contents_file = os.path.join(appicon_dir, "Contents.json") contents = json.loads(open(contents_file).read()) for icon_data in contents["images"]: scale = 1 if "scale" in icon_data: scale = int(icon_data["scale"].replace("x", "")) if "size" in icon_data: width, height = icon_data["size"].split("x") scaled_width = float(width) * scale # FIXME: switch to parsing the png header to get image dimensions # rather than expecting a certain filename convention. See here for info: # https://stackoverflow.com/questions/8032642/how-to-obtain-image-size-using-standard-python-class-without-using-external-lib best_icon = None for icon in icons: basename = os.path.splitext(icon)[0] last_dash = basename.rfind("-") size = basename[last_dash+1:] try: size = int(size) except: continue if size == scaled_width: best_icon = icon break elif size > scaled_width: if best_icon: icon_size = os.path.splitext(best_icon)[0].split("-")[1] if int(icon_size) < size: continue best_icon = icon if best_icon: full_icon_path = os.path.join(cwd, "icons", "ios", best_icon) filename = None if "filename" in icon_data: dest_icon_path = os.path.join(appicon_dir, icon_data["filename"]) shutil.copyfile(full_icon_path, dest_icon_path) else: print("No filename listed for {}".format(scaled_width)) else: print("Could not find icon for size {}".format(scaled_width)) orientation_value = get_value_for_platform("orientation", "ios", "both") orientations = [orientation_value] if orientation_value == 'all' or orientation_value == 'sensor': orientations = ['landscape', 'portrait'] else: plist['UIRequiresFullScreen'] = True launch_images = get_value_for_platform("launch_images", "ios", []) if len(launch_images) > 0: del plist['UILaunchStoryboardName'] images = [] for image in launch_images: image_path = os.path.abspath(os.path.join("icons", "ios", image)) width, height = get_image_info(image_path) orientation = 'Portrait' size = '{%d, %d}' % (width, height) if width > height: orientation = 'Landscape' # The dimensions for the ImageSize must be specified as if the # image was portrait, even when it's a landscape image. size = '{%d, %d}' % (height, width) filename = os.path.basename(image_path) basename = os.path.splitext(filename)[0] image_keys = { 'UILaunchImageMinimumOSVersion': '7.0', 'UILaunchImageOrientation': orientation, 'UILaunchImageName': basename, 'UILaunchImageSize': size } images.append(image_keys) plist['UILaunchImages'] = images ios_orientations = [] for orientation in orientations: if orientation == 'landscape': ios_orientations.extend(['UIInterfaceOrientationLandscapeLeft', 'UIInterfaceOrientationLandscapeRight']) if orientation == 'portrait': ios_orientations.extend(['UIInterfaceOrientationPortrait', 'UIInterfaceOrientationPortraitUpsideDown']) plist['UISupportedInterfaceOrientations'] = ios_orientations plist['UISupportedInterfaceOrientations~ipad'] = ios_orientations plistlib.writePlist(plist, plist_file) dest_dir = os.path.join(project_build_dir, "Script") files_src_dir = os.path.join(src_dir, "files") script_ignore_paths = ignore_paths + [files_src_dir] copy_files(src_dir, dest_dir, script_ignore_paths) copy_pew_module(dest_dir) files_dest_dir = os.path.join(project_build_dir, "files") # FIXME: We shouldn't need any logic to copy hardcoded directories such as this one. if os.path.exists(files_src_dir): copy_files(files_src_dir, files_dest_dir, ignore_paths) project_file = os.path.join(project_build_dir, "PythonistaAppTemplate.xcodeproj") config_file = os.path.join(project_file, "project.pbxproj") project = pbxproj.XcodeProject.load(config_file) for icon_file in glob.glob(os.path.join("icons", "ios", "*")): icon_path = os.path.abspath(icon_file) icon_filename = os.path.basename(icon_file) dest_path = os.path.join(project_build_dir, icon_filename) shutil.copy(icon_path, dest_path) project.add_file(icon_filename, force=False) if "codesign" in info_json and "ios" in info_json["codesign"]: ios_codesign = info_json["codesign"]["ios"] # Don't use the pre-defined app icon project.remove_flags('PRODUCT_BUNDLE_IDENTIFIER', 'com.omz-software.PythonistaAppTemplate') project.remove_flags('ASSETCATALOG_COMPILER_APPICON_NAME', 'AppIcon') # TODO: Add support for manual signing for target in project.objects.get_targets(): project_root = project.objects[project.rootObject] project_root.set_provisioning_style('Automatic', target) project_root.attributes.TargetAttributes[target.get_id()]["DevelopmentTeam"] = ios_codesign["development_team"] project.save() # FIXME: This currently only works for pure-Python modules. pewtools.copy_deps_to_build(requirements, build_dir, dest_dir) if os.path.exists(config_file): f = open(config_file, 'r') config = f.read() f.close() config = config.replace("My App", info_json["name"]) f = open(config_file, 'w') f.write(config) f.close() else: print("Unable to update XCode project config file. You may need to manually change some settings.") run_command(["open", project_file.replace(" ", "\\ ")]) elif args.platform in ["mac", "win"]: if args.platform == 'mac': import py2app sys.argv = [sys.argv[0], "py2app"] else: import py2exe sys.argv = [sys.argv[0], "py2exe"] excludes = [] packages = [] plist = { 'CFBundleIdentifier': info_json["identifier"], # Make sure the browser will load localhost URLs 'NSAppTransportSecurity': { 'NSAllowsArbitraryLoads': True, 'NSExceptionDomains': { 'localhost': { 'NSExceptionAllowsInsecureHTTPLoads': True } } } } if "packages" in info_json: packages.extend(info_json["packages"]) dist_dir = "dist/%s" % args.platform if not os.path.exists(dist_dir): os.makedirs(dist_dir) dll_excludes = ["combase.dll", "credui.dll", "crypt32.dll", "dhcpcsvc.dll", "msvcp90.dll", "mpr.dll", "oleacc.dll", "powrprof.dll", "psapi.dll", "setupapi.dll", "userenv.dll", "usp10.dll", "wtsapi32.dll"] dll_excludes.extend(["iertutil.dll", "iphlpapi.dll", "nsi.dll", "psapi.dll", "oleacc.dll", "urlmon.dll", "Secur32.dll", "setupapi.dll", "userenv.dll", "webio.dll","wininet.dll", "winhttp.dll", "winnsi.dll", "wtsapi.dll"]) dll_excludes.extend(["cryptui.dll", "d3d9.dll", "d3d11.dll", "dbghelp.dll", "dwmapi.dll", "dwrite.dll", "dxgi.dll", "dxva2.dll", "fontsub.dll", "ncrypt.dll", "wintrust.dll"]) # this is needed on Windows for py2exe to find scripts in the src directory sys.path.append(src_dir) data_files = [('.', [os.path.join(cwd, "project_info.json")])] asset_dirs = [] if "asset_dirs" in info_json: asset_dirs = info_json["asset_dirs"] else: message = "Specifying asset_dirs with a list of directories for your app's static files is now required. Please add \"asset_dirs\": ['src/files'] to your project_info.json file." print(message) sys.exit(1) for asset_dir in asset_dirs: for root, dirs, files in os.walk(asset_dir): files_in_dir = [] for afile in files: if not afile.startswith("."): files_in_dir.append(os.path.join(root, afile)) if len(files_in_dir) > 0: data_files.append((root.replace("src/", ""), files_in_dir)) try: import cefpython3 cefp = os.path.dirname(cefpython3.__file__) cef_files = ['%s/icudtl.dat' % cefp] cef_files.extend(glob.glob('%s/*.exe' % cefp)) cef_files.extend(glob.glob('%s/*.dll' % cefp)) cef_files.extend(glob.glob('%s/*.pak' % cefp)) cef_files.extend(glob.glob('%s/*.bin' % cefp)) data_files.extend([('', cef_files), ('locales', ['%s/locales/en-US.pak' % cefp]), ] ) for cef_pyd in glob.glob(os.path.join(cefp, 'cefpython_py*.pyd')): version_str = "{}{}.pyd".format(sys.version_info[0], sys.version_info[1]) if not cef_pyd.endswith(version_str): module_name = 'cefpython3.' + os.path.basename(cef_pyd).replace('.pyd', '') print("Excluding pyd: {}".format(module_name)) excludes.append(module_name) except: # TODO: Print the error information if verbose is set. pass # if cefpython is not found, we fall back to the stock OS browser print("data_files = %r" % data_files) name = info_json["name"] # workaround a bug in py2exe where it expects strings instead of Unicode if args.platform == 'win': name = name.encode('utf-8') # Make sure py2exe bundles the modules that six references # the Py3 version of py2exe natively supports this so this is a 2.x only fix includes = [] if sys.version_info[0] == 2: includes = ["urllib", "SimpleHTTPServer"] py2exe_opts = { "dll_excludes": dll_excludes, "packages": packages, "excludes": excludes, "includes": includes } py2app_opts = { "dist_dir": dist_dir, 'plist': plist, "packages": packages, "site_packages": True, } setup(name=name, version=info_json["version"], options={ 'py2app': py2app_opts, 'py2exe': py2exe_opts }, app=['src/main.py'], windows=['src/main.py'], data_files=data_files ) if sys.platform.startswith("darwin") and "codesign" in info_json: base_path = os.path.join(dist_dir, "%s.app" % info_json["name"]) print("base_path = %r" % base_path) # remove the .py files and the .pyo files as we shouldn't use them # running a .py file in the bundle can modify it. for root, dirs, files in os.walk(os.path.join(base_path, "Contents", "Resources", "lib", "python2.7")): for afile in files: fullpath = os.path.join(root, afile) ext = os.path.splitext(fullpath)[1] if ext in ['.py', '.pyo']: os.remove(fullpath) sign_paths = [] sign_paths.extend(glob.glob(os.path.join(base_path, "Contents", "Frameworks", "*.framework"))) sign_paths.extend(glob.glob(os.path.join(base_path, "Contents", "Frameworks", "*.dylib"))) exes = ["Python"] for exe in exes: sign_paths.append(os.path.join(base_path, 'Contents', 'MacOS', exe)) sign_paths.append(base_path) # the main app needs to be signed last for path in sign_paths: codesign_mac(path, info_json["codesign"]["osx"]["identity"]) return returncode
def main(): MajorStr = "" MinorStr = "" BugfixStr = "" for line in fileinput.input(scriptpath + "/resource.h", inplace=0): if "#define PLUG_VER " in line: FullVersion = int(string.lstrip(line, "#define PLUG_VER "), 16) major = FullVersion & 0xFFFF0000 MajorStr = str(major >> 16) minor = FullVersion & 0x0000FF00 MinorStr = str(minor >> 8) BugfixStr = str(FullVersion & 0x000000FF) FullVersionStr = MajorStr + "." + MinorStr + "." + BugfixStr CFBundleGetInfoString = FullVersionStr + ", Copyright OliLarkin, 2011" CFBundleVersion = FullVersionStr print "update_version.py - setting version to " + FullVersionStr print "Updating plist version info..." plistpath = scriptpath + "/resources/MostBasicGUI-VST2-Info.plist" vst2 = plistlib.readPlist(plistpath) vst2['CFBundleGetInfoString'] = CFBundleGetInfoString vst2['CFBundleVersion'] = CFBundleVersion vst2['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(vst2, plistpath) plistpath = scriptpath + "/resources/MostBasicGUI-AU-Info.plist" au = plistlib.readPlist(plistpath) au['CFBundleGetInfoString'] = CFBundleGetInfoString au['CFBundleVersion'] = CFBundleVersion au['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(au, plistpath) plistpath = scriptpath + "/resources/MostBasicGUI-VST3-Info.plist" vst3 = plistlib.readPlist(plistpath) vst3['CFBundleGetInfoString'] = CFBundleGetInfoString vst3['CFBundleVersion'] = CFBundleVersion vst3['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(vst3, plistpath) plistpath = scriptpath + "/resources/MostBasicGUI-OSXAPP-Info.plist" app = plistlib.readPlist(plistpath) app['CFBundleGetInfoString'] = CFBundleGetInfoString app['CFBundleVersion'] = CFBundleVersion app['CFBundleShortVersionString'] = CFBundleVersion plistlib.writePlist(app, plistpath) # plistpath = scriptpath + "/resources/MostBasicGUI-IOSAPP-Info.plist" # iosapp = plistlib.readPlist(plistpath) # iosapp['CFBundleGetInfoString'] = CFBundleGetInfoString # iosapp['CFBundleVersion'] = CFBundleVersion # iosapp['CFBundleShortVersionString'] = CFBundleVersion # plistlib.writePlist(iosapp, plistpath) print "Updating Mac Installer version info..." plistpath = scriptpath + "/installer/MostBasicGUI.packproj" installer = plistlib.readPlist(plistpath) installer['Hierarchy']['Attributes']['Settings']['Description'][ 'International']['IFPkgDescriptionVersion'] = FullVersionStr installer['Hierarchy']['Attributes']['Settings']['Display Information'][ 'CFBundleGetInfoString'] = CFBundleGetInfoString installer['Hierarchy']['Attributes']['Settings']['Display Information'][ 'CFBundleShortVersionString'] = CFBundleVersion installer['Hierarchy']['Attributes']['Settings']['Version'][ 'IFMajorVersion'] = int(MajorStr) installer['Hierarchy']['Attributes']['Settings']['Version'][ 'IFMinorVersion'] = int(MinorStr) for x in range(0, 5): installer['Hierarchy']['Attributes']['Components'][x]['Attributes'][ 'Settings']['Description']['International'][ 'IFPkgDescriptionVersion'] = FullVersionStr installer['Hierarchy']['Attributes']['Components'][x]['Attributes'][ 'Settings']['Display Information'][ 'CFBundleGetInfoString'] = CFBundleGetInfoString installer['Hierarchy']['Attributes']['Components'][x]['Attributes'][ 'Settings']['Display Information'][ 'CFBundleShortVersionString'] = CFBundleVersion installer['Hierarchy']['Attributes']['Components'][x]['Attributes'][ 'Settings']['Version']['IFMajorVersion'] = int(MajorStr) installer['Hierarchy']['Attributes']['Components'][x]['Attributes'][ 'Settings']['Version']['IFMinorVersion'] = int(MinorStr) plistlib.writePlist(installer, plistpath) print "Updating Windows Installer version info..." for line in fileinput.input(scriptpath + "/installer/MostBasicGUI.iss", inplace=1): if "AppVersion" in line: line = "AppVersion=" + FullVersionStr + "\n" sys.stdout.write(line)
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # LAUNCH DAEMON # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # place launchd plist to call JSS policy to remove admin rights. print 'Creating LaunchDaemon...' launchDaemon = { 'Label': 'com.jamfps.adminremove', 'ProgramArguments': ['/usr/local/jamf/bin/jamf', 'policy', '-trigger', policyCustomTrigger], 'StartInterval': adminTimer, } plistlib.writePlist(launchDaemon, '/Library/LaunchDaemons/' + launchdFile) # set the permission on the file just made. userID = pwd.getpwnam("root").pw_uid groupID = grp.getgrnam("wheel").gr_gid os.chown('/Library/LaunchDaemons/' + launchdFile, userID, groupID) os.chmod('/Library/LaunchDaemons/' + launchdFile, 0644) # load the removal plist timer. print 'Loading LaunchDaemon...' subprocess.call( ["launchctl", "load", "-w", '/Library/LaunchDaemons/' + launchdFile]) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # APPLICATION # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
def main(): if (len(sys.argv) == 2): if (sys.argv[1] == "app"): print "Copying resources ..." dst = os.environ["TARGET_BUILD_DIR"] + "/" + os.environ[ "UNLOCALIZED_RESOURCES_FOLDER_PATH"] if os.path.exists(projectpath + "/resources/img/"): imgs = os.listdir(projectpath + "/resources/img/") for img in imgs: print "copying " + img + " to " + dst shutil.copy(projectpath + "/resources/img/" + img, dst) if os.path.exists(projectpath + "/resources/fonts/"): fonts = os.listdir(projectpath + "/resources/fonts/") for font in fonts: print "copying " + font + " to " + dst shutil.copy(projectpath + "/resources/fonts/" + font, dst) config = parse_config(projectpath) xcconfig = parse_xcconfig( os.path.join(os.getcwd(), IPLUG2_ROOT + '/common-ios.xcconfig')) CFBundleGetInfoString = config['BUNDLE_NAME'] + " v" + config[ 'FULL_VER_STR'] + " " + config['PLUG_COPYRIGHT_STR'] CFBundleVersion = config['FULL_VER_STR'] CFBundlePackageType = "BNDL" CSResourcesFileMapped = True LSMinimumSystemVersion = xcconfig['DEPLOYMENT_TARGET'] print "Processing Info.plist files..." # AUDIOUNIT v3 if config['PLUG_TYPE'] == 0: if config['PLUG_DOES_MIDI_IN']: COMPONENT_TYPE = kAudioUnitType_MusicEffect else: COMPONENT_TYPE = kAudioUnitType_Effect elif config['PLUG_TYPE'] == 1: COMPONENT_TYPE = kAudioUnitType_MusicDevice elif config['PLUG_TYPE'] == 2: COMPONENT_TYPE = kAudioUnitType_MIDIProcessor NSEXTENSIONPOINTIDENTIFIER = "com.apple.AudioUnit-UI" plistpath = projectpath + "/resources/" + config[ 'BUNDLE_NAME'] + "-iOS-AUv3-Info.plist" auv3 = plistlib.readPlist(plistpath) auv3['CFBundleExecutable'] = config['BUNDLE_NAME'] + "AppExtension" auv3['CFBundleIdentifier'] = "$(PRODUCT_BUNDLE_IDENTIFIER)" auv3['CFBundleName'] = config['BUNDLE_NAME'] + "AppExtension" auv3['CFBundleDisplayName'] = config['BUNDLE_NAME'] + "AppExtension" auv3['CFBundleVersion'] = CFBundleVersion auv3['CFBundleShortVersionString'] = CFBundleVersion auv3['CFBundlePackageType'] = "XPC!" auv3['NSExtension'] = dict( NSExtensionAttributes=dict(AudioComponents=[{}]), NSExtensionMainStoryboard=config['BUNDLE_NAME'] + "-iOS-MainInterface", NSExtensionPointIdentifier=NSEXTENSIONPOINTIDENTIFIER) auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'] = [{}] auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'description'] = config['PLUG_NAME'] auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'manufacturer'] = config['PLUG_MFR_ID'] auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'factoryFunction'] = "IPlugAUViewController" auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'name'] = config['PLUG_MFR'] + ": " + config['PLUG_NAME'] auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'subtype'] = config['PLUG_UNIQUE_ID'] auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'type'] = COMPONENT_TYPE auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'version'] = config['PLUG_VERSION_INT'] auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'sandboxSafe'] = True auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'tags'] = ["", ""] if config['PLUG_TYPE'] == 1: auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'tags'][0] = "Synth" else: auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0][ 'tags'][0] = "Effects" auv3['NSExtension']['NSExtensionAttributes']['AudioComponents'][0]['tags'][ 1] = "size:{" + str(config['PLUG_WIDTH']) + "," + str( config['PLUG_HEIGHT']) + "}" plistlib.writePlist(auv3, plistpath) # Standalone APP plistpath = projectpath + "/resources/" + config[ 'BUNDLE_NAME'] + "-iOS-Info.plist" iOSapp = plistlib.readPlist(plistpath) iOSapp['CFBundleExecutable'] = config['BUNDLE_NAME'] iOSapp['CFBundleIdentifier'] = "$(PRODUCT_BUNDLE_IDENTIFIER)" iOSapp['CFBundleName'] = config['BUNDLE_NAME'] iOSapp['CFBundleVersion'] = CFBundleVersion iOSapp['CFBundleShortVersionString'] = CFBundleVersion iOSapp['CFBundlePackageType'] = "APPL" iOSapp['LSApplicationCategoryType'] = "public.app-category.music" plistlib.writePlist(iOSapp, plistpath)
def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths): """ Reads information from the built app and uses it to set the SMJobBless setup in the specified app and tool Info.plist source files. """ if not os.path.isdir(appPath): raise CheckException("app not found", appPath) if not os.path.isfile(appInfoPlistPath): raise CheckException("app 'Info.plist' not found", appInfoPlistPath) for toolInfoPlistPath in toolInfoPlistPaths: if not os.path.isfile(toolInfoPlistPath): raise CheckException("app 'Info.plist' not found", toolInfoPlistPath) # Get the designated requirement for the app and each of the tools. appReq = readDesignatedRequirement(appPath, "app") toolDirPath = os.path.join(appPath, "Contents", "Library", "LaunchServices") if not os.path.isdir(toolDirPath): raise CheckException("tool directory not found", toolDirPath) toolNameToReqMap = {} for toolName in os.listdir(toolDirPath): req = readDesignatedRequirement(os.path.join(toolDirPath, toolName), "tool") toolNameToReqMap[toolName] = req if len(toolNameToReqMap) > len(toolInfoPlistPaths): raise CheckException( "tool directory has more tools (%d) than you've supplied tool 'Info.plist' paths (%d)" % (len(toolNameToReqMap), len(toolInfoPlistPaths)), toolDirPath) if len(toolNameToReqMap) < len(toolInfoPlistPaths): raise CheckException( "tool directory has fewer tools (%d) than you've supplied tool 'Info.plist' paths (%d)" % (len(toolNameToReqMap), len(toolInfoPlistPaths)), toolDirPath) # Build the new value for SMPrivilegedExecutables. appToolDict = {} toolInfoPlistPathToToolInfoMap = {} for toolInfoPlistPath in toolInfoPlistPaths: toolInfo = readInfoPlistFromPath(toolInfoPlistPath) toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] = toolInfo if not toolInfo.has_key("CFBundleIdentifier"): raise CheckException("'CFBundleIdentifier' not found", toolInfoPlistPath) bundleID = toolInfo["CFBundleIdentifier"] if not isinstance(bundleID, basestring): raise CheckException("'CFBundleIdentifier' must be a string", toolInfoPlistPath) appToolDict[bundleID] = toolNameToReqMap[bundleID] # Set the SMPrivilegedExecutables value in the app "Info.plist". appInfo = readInfoPlistFromPath(appInfoPlistPath) needsUpdate = not appInfo.has_key("SMPrivilegedExecutables") if not needsUpdate: oldAppToolDict = appInfo["SMPrivilegedExecutables"] if not isinstance(oldAppToolDict, dict): raise CheckException( "'SMPrivilegedExecutables' must be a dictionary", appInfoPlistPath) appToolDictSorted = sorted(appToolDict.iteritems(), key=operator.itemgetter(0)) oldAppToolDictSorted = sorted(oldAppToolDict.iteritems(), key=operator.itemgetter(0)) needsUpdate = (appToolDictSorted != oldAppToolDictSorted) if needsUpdate: appInfo["SMPrivilegedExecutables"] = appToolDict plistlib.writePlist(appInfo, appInfoPlistPath) print >> sys.stdout, "%s: updated" % appInfoPlistPath # Set the SMAuthorizedClients value in each tool's "Info.plist". toolAppListSorted = [appReq] # only one element, so obviously sorted (-: for toolInfoPlistPath in toolInfoPlistPaths: toolInfo = toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] needsUpdate = not toolInfo.has_key("SMAuthorizedClients") if not needsUpdate: oldToolAppList = toolInfo["SMAuthorizedClients"] if not isinstance(oldToolAppList, list): raise CheckException("'SMAuthorizedClients' must be an array", toolInfoPlistPath) oldToolAppListSorted = sorted(oldToolAppList) needsUpdate = (toolAppListSorted != oldToolAppListSorted) if needsUpdate: toolInfo["SMAuthorizedClients"] = toolAppListSorted plistlib.writePlist(toolInfo, toolInfoPlistPath) print >> sys.stdout, "%s: updated" % toolInfoPlistPath