def _read_remote_plist(self): """Gets the property list.""" result = None _basename = os.path.basename(self._plist_url_path) _tmp_file = os.path.join(self._tmp_dir, _basename) _bad_wolf_fixes = bad_wolf.BAD_WOLF_PKGS.get(_basename, None) _bwd = None _req = curl_requests.CURL(url=self._plist_url_path) # NOTE 2019-11-04: Seems that using the 'resume' capability in cURL does not # work here now for some reason, so don't resume. if _req.status in config.HTTP_OK_STATUS: _req.get(url=self._plist_url_path, output=_tmp_file, resume=False) else: _req.get(url=self._plist_failover_url_path, output=_tmp_file, resume=False) _root = plist.readPlist(_tmp_file) if _root: result = set() # Apply 'Bad Wolf' pathches for _pkg in _root['Packages']: _new_pkg = _root['Packages'][_pkg].copy() # Work on copy # Create a new key called 'PackageName' that # contains the value '_pkg' for use with content packs. _new_pkg['PackageName'] = _pkg if _bad_wolf_fixes: _bwd = _bad_wolf_fixes.get( _pkg, None) # A dictionary from '_bad_wolf_fixes' # Merge new/existing keys from matching '_bwd' if _bwd: _new_pkg.update(_bwd) _pkg_obj = package.LoopPackage(**_new_pkg) # pylint: disable=no-member # Only add/process packages that are _not_ 'BadWolfIgnore = True' if not _pkg_obj.BadWolfIgnore: result.add(_pkg_obj) # pylint: enable=no-member # Now process option packs _opt_packs = option_packs.OptionPack(source=_root, release=_basename) self.option_packs = _opt_packs.option_packs misc.clean_up(file_path=_tmp_file) return result
def _download(self, pkg, counter_msg): """Downloads a package from the specified URL.""" if isinstance(pkg, package.LoopPackage): _url = pkg.DownloadURL curl = curl_requests.CURL() if pkg.LocalDownloadURL: _url = pkg.LocalDownloadURL elif pkg.CacheDownloadURL: _url = pkg.CacheDownloadURL # Get the status of the URL to see if it exists req = curl_requests.CURL(url=_url) if req.status: if req.status in config.HTTP_OK_STATUS: curl.get(url=_url, output=pkg.DownloadPath, counter_msg=counter_msg) elif req.status not in config.HTTP_OK_STATUS: # Fallback only if the url is either a cache or pkg server if _url in [pkg.LocalDownloadURL, pkg.CacheDownloadURL]: LOG.debug('Fell back {} to {}'.format( _url, pkg.DownloadURL)) _url = pkg.DownloadURL curl.get(url=_url, output=pkg.DownloadPath, counter_msg=counter_msg) elif not req.status or req.curl_error: # Fallback only if the url is either a cache or pkg server if _url in [pkg.LocalDownloadURL, pkg.CacheDownloadURL]: LOG.debug('Fell back {} to {}'.format( _url, pkg.DownloadURL)) _url = pkg.DownloadURL curl.get(url=_url, output=pkg.DownloadPath, counter_msg=counter_msg) else: LOG.debug('{} is {}'.format(pkg, pkg.__class__)) return NotImplemented
def __init__(self, **kwargs): # Set attributes based on 'VALID_KWARGS' for kwarg, value in self.VALID_KWARGS.items(): if kwarg in kwargs.keys(): setattr(self, kwarg, kwargs.get(kwarg, None)) else: setattr(self, kwarg, value) # pylint: disable=access-member-before-definition # Fix any instances where the 'PackageID' contains spaces. if hasattr(self, 'PackageID'): self.PackageID = self.PackageID.replace('. ', '.') # Fix the Apple 'PackageVersion' attribute to a 'LooseVersion' type. if hasattr(self, 'PackageVersion'): if isinstance(self.PackageVersion, (float, int)): self.PackageVersion = u'{}'.format(self.PackageVersion) self.PackageVersion = LooseVersion(self.PackageVersion) # Convert 'DownloadSize' and 'InstalledSize' to int if hasattr(self, 'DownloadSize'): # if self.DownloadSize: self.DownloadSize = int(self.DownloadSize) self.HumanDownloadSize = misc.bytes2hr(byte=self.DownloadSize) if hasattr(self, 'InstalledSize'): # if self.InstalledSize: self.InstalledSize = int(self.InstalledSize) self.HumanInstalledSize = misc.bytes2hr(byte=self.InstalledSize) # Now handle some of the appleloops specific attributes. if hasattr(self, 'DownloadName'): basename = path.basename(self.DownloadName) self.DownloadURL = '{}/{}/{}'.format(config.AUDIOCONTENT_URL, config.LP10_MS3_CONTENT, basename) lp10_str = 'lp10_ms3_content_2016' if '../lp10_ms3_content_2013/' in self.DownloadName: lp10_str = 'lp10_ms3_content_2013' self.DownloadURL = self.DownloadURL.replace( 'lp10_ms3_content_2016', lp10_str) # Can probably get away with removing the '2013' path from the 'DownloadName' attr. self.DownloadName = self.DownloadName.replace( '../{}/'.format(lp10_str), '') # Handle if there's a DMG to build/deploy from if config.DMG_FILE or config.HTTP_DMG: _dest_path = config.DMG_VOLUME_MOUNTPATH else: _dest_path = config.DESTINATION_PATH if config.DESTINATION_PATH else config.DEFAULT_DEST self.DownloadPath = path.join(_dest_path, lp10_str, self.DownloadName) if hasattr(self, 'DownloadURL'): if config.LOCAL_HTTP_SERVER: # If this isn't a HTTP DMG being mounted, set the download url if not config.HTTP_DMG: self.LocalDownloadURL = self.DownloadURL.replace( config.AUDIOCONTENT_URL, config.LOCAL_HTTP_SERVER) if config.CACHING_SERVER: parsed_url = urlparse(self.DownloadURL) self.CacheDownloadURL = '{}{}?source={}'.format( config.CACHING_SERVER, parsed_url.path, parsed_url.netloc) # pylint: enable=access-member-before-definition # CURL requests for actual download sizes but only if specified. if config.REAL_DOWNLOAD_SIZE: if self.LocalDownloadURL: req = curl_requests.CURL(url=self.LocalDownloadURL) elif not self.LocalDownloadURL: req = curl_requests.CURL(url=self.DownloadURL) if req.status == 200: try: self.RealDownloadSize = req.headers['Content-Length'] except KeyError: try: self.RealDownloadSize = req.headers['content-length'] except KeyError: pass if self.RealDownloadSize: self.HumanRealDownloadSize = misc.bytes2hr( byte=self.RealDownloadSize)
def _get_plist_file_path(self): """Determines the local PLIST file if the app is installed.""" result = None if self._is_app_installed(): files = glob('{}/*.plist'.format(self._resource_file_path)) matching_files = [x for x in files if re.search(r'{}\d+.plist'.format(self._app), x)] # Return the last matching file as this should be the most recent matching_files.sort(reverse=False) if isinstance(matching_files, list): try: result = matching_files[-1] except IndexError: # Oh-oh! The resource might not exist, so fall back to Apple LOG.debug('Resource file excpected in {} app folder not found. Falling back to Apple source.'.format(self._app)) _url = None _failover_url = None _tmp_dir = os.path.join(tempfile.gettempdir(), config.BUNDLE_ID) _file = None _app_ver = self._app_info.get('CFBundleShortVersionString', None).replace('.', '') _supported_plists = [_value for _key, _value in supported.SUPPORTED.items() if self._app in _value] _supported_plists.sort() _i = 0 # Index the while loop from here. while _i < len(_supported_plists): _first = int(_supported_plists[_i].replace(self._app, '').replace('.plist', '')) _second = None try: _ii = _i + 1 _second = int(_supported_plists[_ii].replace(self._app, '').replace('.plist', '')) except KeyError: _second = int(_first) + 1 if _first and _second: if int(_app_ver) in range(_first, _second): _file = _supported_plists[_i] break else: LOG.debug('Uh oh, could not find a second file in the supported files to check version range') result = None break _i += 1 if _file: _url = '{}/{}/{}'.format(config.AUDIOCONTENT_URL, config.LP10_MS3_CONTENT, _file) _failover_url = '{}/{}/{}'.format(config.AUDIOCONTENT_FAILOVER_URL, config.LP10_MS3_CONTENT, _file) _tmp_file = os.path.join(_tmp_dir, _file) _req = curl_requests.CURL(url=_url) # NOTE 2019-11-04: Seems that using the 'resume' capability in cURL does not # work here now for some reason, so don't resume. if _req.status in config.HTTP_OK_STATUS: _req.get(url=_url, output=_tmp_file, resume=False) else: _req.get(url=_failover_url, output=_tmp_file, resume=False) if os.path.exists(_tmp_file): result = _tmp_file else: LOG.debug('File {} not found.'.format(_tmp_file)) LOG.debug('URL for replacement file: {}'.format(_url)) LOG.debug('Failover URL for replacement file: {}'.format(_failover_url)) return result
def _download(self, pkg, counter_msg): """Downloads a package from the specified URL.""" if isinstance(pkg, package.LoopPackage): _url = pkg.DownloadURL _cache_race = False # Presume all caching server packages are completely downloaded _debug_msg = 'Fell back {} to {}'.format(_url, pkg.DownloadURL) curl = curl_requests.CURL() if pkg.LocalDownloadURL: _url = pkg.LocalDownloadURL elif pkg.CacheDownloadURL: _url = pkg.CacheDownloadURL # Get the status of the URL to see if it exists req = curl_requests.CURL(url=_url) # Check if a caching server package is less than the expected size, # if this is true, then it's likely the caching server hasn't completely # downloaded the file yet, and will cause problems, so fall back. if config.CACHING_SERVER: try: if config.REAL_DOWNLOAD_SIZE: _cache_race = req.headers[ 'Content-Length'] < pkg.RealDownloadSize else: _cache_race = req.headers[ 'Content-Length'] < pkg.DownloadSize except KeyError: if config.REAL_DOWNLOAD_SIZE: _cache_race = req.headers[ 'content-length'] < pkg.RealDownloadSize else: _cache_race = req.headers[ 'content-length'] < pkg.DownloadSize if _cache_race: _debug_msg = '{} (Possible Caching Server race condition when downloading package)'.format( _debug_msg) if req.status: if req.status in config.HTTP_OK_STATUS: curl.get(url=_url, output=pkg.DownloadPath, counter_msg=counter_msg) elif req.status not in config.HTTP_OK_STATUS: # Fallback only if the url is either a cache or pkg server if _url in [pkg.LocalDownloadURL, pkg.CacheDownloadURL ] or _cache_race: LOG.debug(_debug_msg) _url = pkg.DownloadURL curl.get(url=_url, output=pkg.DownloadPath, counter_msg=counter_msg) elif not req.status or req.curl_error: # Fallback only if the url is either a cache or pkg server if _url in [pkg.LocalDownloadURL, pkg.CacheDownloadURL ] or _cache_race: LOG.debug(_debug_msg) _url = pkg.DownloadURL curl.get(url=_url, output=pkg.DownloadPath, counter_msg=counter_msg) else: LOG.debug('{} is {}'.format(pkg, pkg.__class__)) return NotImplemented
def differences(file_a, file_b, detailed_info=False): """Compares the package details in 'file_a' against 'file_b' to determine what files exist in 'file_b' but not in 'file_a'. This will also display packages _removed_. This function sorts the files into smallest to largest order. So if 'garageband1021.plist' is compared to 'garageband1011.plist', the output will be based on packages that are in 'garageband1021.plist' but not in 'garageband1011.plist'. In otherwords, '1021' is the _right_ file, '1011' is the _left_ file.""" sorted_files = sorted([f for f in [file_a, file_b]]) file_a = sorted_files[0] base_a = os.path.basename(file_a) file_b = sorted_files[1] base_b = os.path.basename(file_b) _supported = [_v for _v in config.SUPPORTED_PLISTS.values()] _supported.sort() if not all(_file.endswith('.plist') for _file in [file_a, file_b]): print('Files must both be property list files.') sys.exit(1) if not all(_file in _supported for _file in [base_a, base_b]): print('Files must be from {}'.format(_supported)) sys.exit(1) # Sort the two files so if the order of 'file_a' 'file_b' is # 'garageband1021.plist' 'garageband1011.plist' it becomes # 'garageband1011.plist' 'garageband1021.plist' _tmp_dir = os.path.join(tempfile.gettempdir(), config.BUNDLE_ID) if not os.path.exists(file_a): _fa_fallback = os.path.join(config.AUDIOCONTENT_FAILOVER_URL, 'lp10_ms3_content_2016', base_a) _fa_url = misc.plist_url_path(base_a) file_a = os.path.join(_tmp_dir, base_a) _req = curl_requests.CURL(url=_fa_url) if _req.status in config.HTTP_OK_STATUS: _req.get(url=_fa_url, output=file_a) else: _req.get(url=_fa_fallback, output=file_a) file_a_plist = plist.readPlist(plist_path=file_a)['Packages'] misc.clean_up(file_a) elif os.path.exists(file_a): file_a_plist = plist.readPlist(plist_path=file_a)['Packages'] if not os.path.exists(file_b): _fb_fallback = os.path.join(config.AUDIOCONTENT_FAILOVER_URL, 'lp10_ms3_content_2016', base_b) _fb_url = misc.plist_url_path(base_b) file_b = os.path.join(_tmp_dir, base_b) _req = curl_requests.CURL(url=_fb_url) if _req.status in config.HTTP_OK_STATUS: _req.get(url=_fb_url, output=file_b) else: _req.get(url=_fb_fallback, output=file_b) file_b_plist = plist.readPlist(plist_path=file_b)['Packages'] misc.clean_up(file_b) elif os.path.exists(file_b): file_a_plist = plist.readPlist(plist_path=file_a)['Packages'] # Build a set of package names. file_a_packages = set([ os.path.basename(file_a_plist[_pkg]['DownloadName']) for _pkg in file_a_plist ]) file_b_packages = set([ os.path.basename(file_b_plist[_pkg]['DownloadName']) for _pkg in file_b_plist ]) # Get the new/removed files by using 'set_b.difference(set_a)' new_files = file_b_packages.difference(file_a_packages) rem_files = file_a_packages.difference(file_b_packages) cmn_files = file_b_packages.intersection(file_a_packages) if not detailed_info: if new_files: print('{} new packages in {} when compared to {}'.format( len(new_files), base_b, base_a)) if rem_files: print('{} packages removed from {} compared to {}'.format( len(rem_files), base_a, base_b)) if cmn_files: print('{} packages common between {} and {}'.format( len(cmn_files), base_a, base_b)) # Exit success because nothing else to do. sys.exit(0)