예제 #1
0
    def get_latest_build_date(self):
        """Return date of latest available nightly build."""
        if self.application not in ('fennec'):
            url = urljoin(self.base_url, 'nightly', 'latest-%s/' % self.branch)
        else:
            url = urljoin(self.base_url, 'nightly', 'latest-%s-%s/' %
                          (self.branch, self.platform))

        self.logger.info('Retrieving the build status file from %s' % url)
        parser = self._create_directory_parser(url)
        parser.entries = parser.filter(r'.*%s\.txt' % self.platform_regex)
        if not parser.entries:
            message = 'Status file for %s build cannot be found' % \
                self.platform_regex
            raise errors.NotFoundError(message, url)

        # Read status file for the platform, retrieve build id,
        # and convert to a date
        headers = {'Cache-Control': 'max-age=0'}

        r = self.session.get(url + parser.entries[-1], headers=headers)
        try:
            r.raise_for_status()

            return datetime.strptime(r.text.split('\n')[0], '%Y%m%d%H%M%S')
        finally:
            r.close()
예제 #2
0
    def get_build_info(self):
        """Define additional build information."""
        ReleaseScraper.get_build_info(self)

        # Internally we access builds via index
        url = urljoin(self.base_url, self.candidate_build_list_regex)
        self.logger.info('Retrieving list of candidate builds from %s' % url)

        parser = self._create_directory_parser(url)
        if not parser.entries:
            message = 'Folder for specific candidate builds at %s has not' \
                'been found' % url
            raise errors.NotFoundError(message, url)

        self.show_matching_builds(parser.entries)
        self.builds = parser.entries
        self.build_index = len(parser.entries) - 1

        if self.build_number and \
                ('build%s' % self.build_number) in self.builds:
            self.builds = ['build%s' % self.build_number]
            self.build_index = 0
            self.logger.info('Selected build: build%s' % self.build_number)
        else:
            self.logger.info('Selected build: %s' %
                             (parser.entries[self.build_index]))
예제 #3
0
    def get_build_info(self):
        """Define additional build information."""
        # Retrieve build by revision
        if self.revision:
            th = treeherder.Treeherder(
                APPLICATIONS_TO_FTP_DIRECTORY.get(self.application,
                                                  self.application),
                self.branch, self.platform)
            builds = th.query_builds_by_revision(
                self.revision,
                job_type_name='L10n Nightly'
                if self.locale_build else 'Nightly')

            if not builds:
                raise errors.NotFoundError(
                    'No builds have been found for revision', self.revision)

            # Extract the build folders which are prefixed with the buildid
            self.builds = [build.rsplit('/', 2)[1] for build in builds]
            self.show_matching_builds(self.builds)

            # There is only a single build per revision and platform
            self.build_index = 0
            self.logger.info('Selected build: %s' %
                             self.builds[self.build_index])

            # Retrieve the date from the build folder which is always 19 chars long
            self.date = datetime.strptime(self.builds[self.build_index][:19],
                                          '%Y-%m-%d-%H-%M-%S')

            return

        # Internally we access builds via index
        if self.build_number is not None:
            self.build_index = int(self.build_number) - 1
        else:
            self.build_index = None

        if self.build_id:
            # A build id has been specified. Split up its components so the
            # date and time can be extracted:
            # '20111212042025' -> '2011-12-12 04:20:25'
            self.date = datetime.strptime(self.build_id, '%Y%m%d%H%M%S')

        elif self.date:
            # A date (without time) has been specified. Use its value and the
            # build index to find the requested build for that day.
            try:
                self.date = datetime.strptime(self.date, '%Y-%m-%d')
            except Exception:
                raise ValueError('%s is not a valid date' % self.date)
        else:
            # If no querying option has been specified the latest available
            # build of the given branch has to be identified. We also have to
            # retrieve the date of the build via its build id.
            self.date = self.get_latest_build_date()

        self.builds, self.build_index = self.get_build_info_for_date(
            self.date, self.build_index)
예제 #4
0
        def _get_binary():
            # Retrieve all entries from the remote virtual folder
            parser = self._create_directory_parser(self.path)
            if not parser.entries:
                raise errors.NotFoundError('No entries found', self.path)

            # Download the first matched directory entry
            pattern = re.compile(self.binary_regex, re.IGNORECASE)
            for entry in parser.entries:
                try:
                    self._binary = pattern.match(entry).group()
                    break
                except Exception:
                    # No match, continue with next entry
                    continue
            else:
                raise errors.NotFoundError("Binary not found in folder",
                                           self.path)
예제 #5
0
    def get_build_info(self):
        """Define additional build information."""
        # Retrieve build by revision
        if self.revision:
            th = treeherder.Treeherder(
                APPLICATIONS_TO_FTP_DIRECTORY.get(self.application,
                                                  self.application),
                self.branch, self.platform)
            builds = th.query_builds_by_revision(self.revision,
                                                 job_type_name='Build',
                                                 debug_build=self.debug_build)

            if not builds:
                raise errors.NotFoundError(
                    'No builds have been found for revision', self.revision)

            # Extract timestamp from each build folder
            self.builds = [build.rsplit('/', 2)[1] for build in builds]
            self.show_matching_builds(self.builds)

            # There is only a single build
            self.build_index = 0
            self.logger.info('Selected build: %s' %
                             self.builds[self.build_index])

            return

        # Internally we access builds via index
        if self.build_number is not None:
            self.build_index = int(self.build_number) - 1
        else:
            self.build_index = None

        if self.date is not None:
            try:
                # date is provided in the format 2013-07-23
                self.date = datetime.strptime(self.date, '%Y-%m-%d')
            except Exception:
                try:
                    # date is provided as a unix timestamp
                    datetime.fromtimestamp(float(self.date))
                    self.timestamp = self.date
                except Exception:
                    raise ValueError('%s is not a valid date' % self.date)

        # For localized builds we do not have to retrieve the list of builds
        # because only the last build is available
        if not self.locale_build:
            self.builds, self.build_index = self.get_build_info_for_index(
                self.build_index)
            # Always force a timestamp prefix in the filename
            self.timestamp = self.builds[self.build_index]
예제 #6
0
 def path_regex(self):
     """Return the regex for the path to the build folder."""
     try:
         path = '%s/' % urljoin(self.monthly_build_list_regex,
                                self.builds[self.build_index])
         if self.application in APPLICATIONS_MULTI_LOCALE \
                 and self.locale != 'multi':
             path = '%s/' % urljoin(path, self.locale)
         return path
     except Exception:
         folder = urljoin(self.base_url, self.monthly_build_list_regex)
         raise errors.NotFoundError("Specified sub folder cannot be found",
                                    folder)
예제 #7
0
 def _retry_check_404(self, func,
                      err_message="Specified build has not been found",
                      **retry_kwargs):
     retry_kwargs.setdefault('retry_exceptions',
                             (errors.NotFoundError,
                              requests.exceptions.RequestException))
     try:
         self._retry(func, **retry_kwargs)
     except requests.exceptions.HTTPError as exc:
         if exc.response.status_code == 404:
             raise errors.NotFoundError(err_message, exc.response.url)
         else:
             raise
예제 #8
0
    def get_build_info_for_date(self, date, build_index=None):
        """Return the build information for a given date."""
        url = urljoin(self.base_url, self.monthly_build_list_regex)
        has_time = date and date.time(
        ) and date.strftime('%H-%M-%S') != '00-00-00'

        self.logger.info('Retrieving list of builds from %s' % url)
        parser = self._create_directory_parser(url)
        regex = r'%(DATE)s-(\d+-)+%(BRANCH)s%(L10N)s%(PLATFORM)s$' % {
            'DATE':
            date.strftime('%Y-%m-%d'),
            'BRANCH':
            self.branch,
            # ensure to select the correct subfolder for localized builds
            'L10N':
            '(-l10n)?' if self.locale_build else '',
            'PLATFORM':
            '' if self.application not in ('fennec') else '-' + self.platform
        }

        parser.entries = parser.filter(regex)
        parser.entries = parser.filter(self.is_build_dir)

        if has_time:
            # If a time is included in the date, use it to determine the
            # build's index
            regex = r'.*%s.*' % date.strftime('%H-%M-%S')
            parser.entries = parser.filter(regex)

        if not parser.entries:
            date_format = '%Y-%m-%d-%H-%M-%S' if has_time else '%Y-%m-%d'
            message = 'Folder for builds on %s has not been found' % \
                      self.date.strftime(date_format)
            raise errors.NotFoundError(message, url)

        # If no index has been given, set it to the last build of the day.
        self.show_matching_builds(parser.entries)
        # If no index has been given, set it to the last build of the day.
        if build_index is None:
            # Find the most recent non-empty entry.
            build_index = len(parser.entries)
            for build in reversed(parser.entries):
                build_index -= 1
                if not build_index or self.is_build_dir(build):
                    break
        self.logger.info('Selected build: %s' % parser.entries[build_index])

        return (parser.entries, build_index)
예제 #9
0
        def _download():
            try:
                start_time = datetime.now()

                # Enable streaming mode so we can download content in chunks
                r = self.session.get(self.url, stream=True)
                r.raise_for_status()

                content_length = r.headers.get('Content-length')
                # ValueError: Value out of range if only total_size given
                if content_length:
                    total_size = int(content_length.strip())
                    max_value = ((total_size / CHUNK_SIZE) + 1) * CHUNK_SIZE

                bytes_downloaded = 0

                log_level = self.logger.getEffectiveLevel()
                if log_level <= logging.INFO and content_length:
                    widgets = [pb.Percentage(), ' ', pb.Bar(), ' ', pb.ETA(),
                               ' ', pb.FileTransferSpeed()]
                    pbar = pb.ProgressBar(widgets=widgets,
                                          maxval=max_value).start()

                with open(tmp_file, 'wb') as f:
                    for chunk in r.iter_content(CHUNK_SIZE):
                        f.write(chunk)
                        bytes_downloaded += CHUNK_SIZE

                        if log_level <= logging.INFO and content_length:
                            pbar.update(bytes_downloaded)

                        t1 = total_seconds(datetime.now() - start_time)
                        if self.timeout_download and \
                                t1 >= self.timeout_download:
                            raise errors.TimeoutError

                if log_level <= logging.INFO and content_length:
                    pbar.finish()

            except Exception as ex:
                if os.path.isfile(tmp_file):
                    os.remove(tmp_file)
                if type(ex) is requests.exceptions.HTTPError and \
                        ex.response.status_code == 404:
                    raise errors.NotFoundError("The requested url was not found", self.url)
                else:
                    raise
예제 #10
0
    def get_build_info(self):
        """Define additional build information."""
        # Retrieve build by revision
        th = treeherder.Treeherder(
            APPLICATIONS_TO_FTP_DIRECTORY.get(self.application, self.application),
            'try',
            self.platform)
        builds = th.query_builds_by_revision(
            self.revision, job_type_name='Build', debug_build=self.debug_build)

        if not builds:
            raise errors.NotFoundError('No builds have been found for revision', self.revision)

        # Extract username and revision from build folders
        self.builds = [build.rsplit('/', 3)[1] for build in builds]
        self.show_matching_builds(self.builds)

        # There is only a single build per revision and platform
        self.build_index = 0
        self.logger.info('Selected build: %s' % self.builds[self.build_index])
예제 #11
0
    def get_build_info_for_index(self, build_index=None):
        """Get additional information for the build at the given index."""
        url = urljoin(self.base_url, self.build_list_regex)

        self.logger.info('Retrieving list of builds from %s' % url)
        parser = self._create_directory_parser(url)
        parser.entries = parser.filter(r'^\d+$')

        if self.timestamp:
            # If a timestamp is given, retrieve the folder with the timestamp
            # as name
            parser.entries = self.timestamp in parser.entries and \
                [self.timestamp]

        elif self.date:
            # If date is given, retrieve the subset of builds on that date
            parser.entries = filter(self.date_matches, parser.entries)

        if not parser.entries:
            message = 'No builds have been found'
            raise errors.NotFoundError(message, url)

        self.show_matching_builds(parser.entries)

        # If no index has been given, set it to the last build of the day.
        if build_index is None:
            # Find the most recent non-empty entry.
            build_index = len(parser.entries)
            for build in reversed(parser.entries):
                build_index -= 1
                if not build_index or self.is_build_dir(build):
                    break

        self.logger.info('Selected build: %s' % parser.entries[build_index])

        return (parser.entries, build_index)