Until now products could declare multiple auto-update methods, but they all had to be of the same kind. For example if you used the git auto-update method, you could not use an additional github_releases or custom auto-update method. This is an issue as it prevents us to extend the auto-update process, for example by having a product using the 'git' auto-update method to retrieve all the versions, and a custom script to retrieve support and EOL dates. This improve the scripts execution orchestration to be able to support auto configurations using a mix of methods, meaning: - multiple kind of methods, such as git and github_release, - or multiple custom methods. A side-effect of those changes is that now a failure in a generic script does not cancel the update of subsequent products. Another side-effect, unwanted this time, is that now custom scripts managing multiple products, such as apple.py, are now executed multiple times instead of once.
80 lines
3.8 KiB
Python
80 lines
3.8 KiB
Python
import logging
|
|
import re
|
|
|
|
from bs4 import BeautifulSoup
|
|
from common import dates, http, releasedata
|
|
|
|
"""Fetches and parses version and release date information from Apple's support website for macOS,
|
|
iOS, iPadOS, and watchOS. While all URLs are fetched once for performance reasons, the actual
|
|
parsing for each product is done in a separate loop for having easier-to-read logs."""
|
|
|
|
URLS = [
|
|
"https://support.apple.com/en-us/HT201222", # latest
|
|
"https://support.apple.com/kb/HT213078", # 2018-2019
|
|
"https://support.apple.com/kb/HT213077", # 2016-2017
|
|
"https://support.apple.com/kb/HT209441", # 2015
|
|
"https://support.apple.com/kb/HT205762", # 2014
|
|
"https://support.apple.com/kb/HT205759", # 2013
|
|
"https://support.apple.com/kb/HT204611", # 2011 to 2012
|
|
# Apple still links to the following articles, but they are 404:
|
|
"http://web.archive.org/web/20230404214605_/https://support.apple.com/en-us/HT5165", # 2010
|
|
"http://web.archive.org/web/20230327200842_/https://support.apple.com/en-us/HT4218", # 2008-2009
|
|
"http://web.archive.org/web/20230204234533_/https://support.apple.com/en-us/HT1263", # 2005-2007
|
|
]
|
|
|
|
# If you are changing these, please use
|
|
# https://gist.githubusercontent.com/captn3m0/e7cb1f4fc3c07a5da0296ebda2b33e15/raw/5747e42ad611ec9ffdb7a2d1c0e3946bb87ab6d7/apple.txt
|
|
# as your corpus to validate your changes
|
|
VERSION_PATTERNS = {
|
|
"macos": [
|
|
# This covers Sierra and beyond
|
|
re.compile(r"^macOS[\D]+(?P<version>\d+(?:\.\d+)*)", re.MULTILINE),
|
|
# This covers Mavericks - El Capitan
|
|
re.compile(r"OS\s+X\s[\w\s]+\sv?(?P<version>\d+(?:\.\d+)+)", re.MULTILINE),
|
|
# This covers even older versions (OS X)
|
|
re.compile(r"^Mac\s+OS\s+X\s[\w\s]+\sv?(?P<version>\d{2}(?:\.\d+)+)", re.MULTILINE),
|
|
],
|
|
"ios": [
|
|
re.compile(r"iOS\s+(?P<version>\d+)", re.MULTILINE),
|
|
re.compile(r"iOS\s+(?P<version>\d+(?:\.\d+)+)", re.MULTILINE),
|
|
re.compile(r"iPhone\s+v?(?P<version>\d+(?:\.\d+)+)", re.MULTILINE),
|
|
],
|
|
"ipados": [
|
|
re.compile(r"iPadOS\s+(?P<version>\d+)", re.MULTILINE),
|
|
re.compile(r"iPadOS\s+(?P<version>\d+(?:\.\d+)+)", re.MULTILINE),
|
|
],
|
|
"watchos": [
|
|
re.compile(r"watchOS\s+(?P<version>\d+)", re.MULTILINE),
|
|
re.compile(r"watchOS\s+(?P<version>\d+(?:\.\d+)+)", re.MULTILINE),
|
|
],
|
|
}
|
|
|
|
DATE_PATTERN = re.compile(r"\b\d+\s[A-Za-z]+\s\d+\b")
|
|
|
|
soups = [BeautifulSoup(response.text, features="html5lib") for response in http.fetch_urls(URLS)]
|
|
for product_name in VERSION_PATTERNS:
|
|
with releasedata.ProductData(product_name) as product_data:
|
|
for soup in soups:
|
|
versions_table = soup.find(id="tableWraper")
|
|
versions_table = versions_table if versions_table else soup.find('table', class_="gb-table")
|
|
|
|
for row in versions_table.findAll("tr")[1:]:
|
|
cells = row.findAll("td")
|
|
version_text = cells[0].get_text().strip()
|
|
date_text = cells[2].get_text().strip()
|
|
|
|
date_match = DATE_PATTERN.search(date_text)
|
|
if not date_match:
|
|
logging.info(f"ignoring version {version_text} ({date_text}), date pattern don't match")
|
|
continue
|
|
|
|
date_str = date_match.group(0).replace("Sept ", "Sep ")
|
|
date = dates.parse_date(date_str)
|
|
for version_pattern in VERSION_PATTERNS[product_data.name]:
|
|
for version_str in version_pattern.findall(version_text):
|
|
version = product_data.get_version(version_str)
|
|
if not version or version.date() > date:
|
|
product_data.declare_version(version_str, date)
|
|
else:
|
|
logging.info(f"ignoring version {version_str} ({date}) for {product_data.name}")
|