예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
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)