Skip to content

Commit f0229e7

Browse files
committed
Reorganized update functions
Made a few of them private and upated/fixed documentation
1 parent bd3c4b2 commit f0229e7

File tree

2 files changed

+134
-85
lines changed

2 files changed

+134
-85
lines changed

addons/source-python/packages/source-python/core/command/__init__.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222
from core import core_logger
2323
from core import create_checksum
2424
from core import SOURCE_ENGINE_BRANCH
25-
from core.update import clean_update_dir
26-
from core.update import download_latest_version
27-
from core.update import apply_update_stage1
25+
from core.update import do_full_update
2826
from core.version import get_last_successful_build_number
2927
from core.version import is_unversioned
3028
from core.version import VERSION
@@ -172,16 +170,7 @@ def update_sp(info):
172170
core_command_logger.log_message('No new version available.')
173171
return
174172

175-
# Make sure there is a clean update directory
176-
clean_update_dir()
177-
try:
178-
download_latest_version()
179-
apply_update_stage1()
180-
except:
181-
# Make sure to leave a clean update directory, so the loader doesn't
182-
# get confused.
183-
clean_update_dir()
184-
raise
173+
do_full_update()
185174

186175

187176
# =============================================================================

addons/source-python/packages/source-python/core/update.py

Lines changed: 132 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# ../core/update.py
22

3-
"""Provides functions to update Source.Python's data files."""
3+
"""Provides functions to update Source.Python and its data files."""
44

55
# =============================================================================
66
# >> IMPORTS
@@ -36,17 +36,13 @@
3636
'CHECKSUM_URL',
3737
'DATA_URL',
3838
'DATA_ZIP_FILE',
39-
'apply_update_stage1'
40-
'clean_update_dir'
41-
'download_file'
42-
'download_latest_data'
43-
'download_latest_version'
44-
'get_artifacts'
45-
'get_download_url'
46-
'get_latest_data_checksum'
47-
'is_new_data_available'
48-
'unpack_data'
49-
'update_data'
39+
'download_file',
40+
'get_build_artifacts',
41+
'get_download_url',
42+
'get_latest_data_checksum',
43+
'is_new_data_available',
44+
'update_in_progress',
45+
'update_data',
5046
)
5147

5248

@@ -72,95 +68,100 @@
7268
DATA_URL = 'http://data.sourcepython.com/source-python-data.zip'
7369
ARTIFACTS_URL = 'http://builds.sourcepython.com/job/Source.Python/lastSuccessfulBuild/api/json?tree=artifacts[relativePath]'
7470
BASE_DOWNLOAD_URL = 'http://builds.sourcepython.com/job/Source.Python/lastSuccessfulBuild/artifact/'
71+
DEFAULT_TIMEOUT = 3
72+
73+
#: Indicates, whether an update is in progress (stage 1 has been applied).
74+
update_in_progress = False
7575

7676

7777
# =============================================================================
7878
# >> FUNCTIONS
7979
# =============================================================================
80-
def get_latest_data_checksum(timeout=3):
81-
"""Return the MD5 checksum of the latest data from the build server.
80+
def download_file(url_path, file_path, timeout=3):
81+
"""Download a file from an URL to a specific file.
8282
83+
:param str url_path:
84+
The URL that should be opened.
85+
:param str file_path:
86+
The file where the content of the URL should be stored.
8387
:param float timeout:
8488
Number of seconds that need to pass until a timeout occurs.
85-
:rtype: str
8689
"""
87-
with urlopen(CHECKSUM_URL, timeout=timeout) as url:
88-
return url.read().decode()
90+
update_logger.log_debug(f'Downloading file ({url_path}) to {file_path} ...')
91+
now = time.time()
8992

90-
def download_latest_data(timeout=3):
91-
"""Download the latest data from the build server.
93+
with urlopen(url_path, timeout=timeout) as url:
94+
data = url.read()
9295

93-
:param float timeout:
94-
Number of seconds that need to pass until a timeout occurs.
95-
"""
96-
download_file(DATA_URL, DATA_ZIP_FILE, timeout)
96+
with file_path.open('wb') as f:
97+
f.write(data)
9798

98-
def unpack_data():
99-
"""Unpack ``source-python-data.zip``."""
100-
update_logger.log_debug('Extracting data in {} ...'.format(DATA_PATH))
101-
with ZipFile(DATA_ZIP_FILE) as zip:
102-
zip.extractall(DATA_PATH)
99+
update_logger.log_info(
100+
'File has been downloaded. Time elapsed: {:0.2f} seconds'.format(
101+
time.time()-now))
103102

104-
def update_data(timeout=3):
105-
"""Download and unpack the latest data from the build server.
106103

107-
Old data gets deleted before unpacking.
104+
# =============================================================================
105+
# >> FULL SP UPDATE
106+
# =============================================================================
107+
def do_full_update(timeout=DEFAULT_TIMEOUT):
108+
"""Starts a full update of Source.Python.
109+
110+
A restart of the server and possibly manual work is required. Please see
111+
the Source.Python log for the instructions.
108112
109113
:param float timeout:
110114
Number of seconds that need to pass until a timeout occurs.
111115
"""
112-
download_latest_data(timeout)
113-
if SP_DATA_PATH.isdir():
114-
update_logger.log_debug('Removing {} ...'.format(SP_DATA_PATH))
115-
SP_DATA_PATH.rmtree()
116-
117-
unpack_data()
118-
119-
def is_new_data_available(timeout=3):
120-
"""Return ``True`` if new data is available.
116+
global update_in_progress
117+
if update_in_progress:
118+
update_logger.log_message(
119+
'An update is already in progress. Please follow the instructions '
120+
'in the log.')
121+
return
122+
123+
# Make sure there is a clean update directory
124+
_clean_update_dir()
125+
try:
126+
_download_latest_version(timeout)
127+
_apply_update_stage1()
128+
update_in_progress = True
129+
except:
130+
# Make sure to leave a clean update directory, so the loader doesn't
131+
# get confused.
132+
_clean_update_dir()
133+
raise
134+
135+
def get_build_artifacts(timeout=DEFAULT_TIMEOUT):
136+
"""Return the artifacts of the latest Source.Python build.
121137
122138
:param float timeout:
123139
Number of seconds that need to pass until a timeout occurs.
124-
:rtype: bool
125140
"""
126-
if not DATA_ZIP_FILE.isfile():
127-
return True
128-
129-
return DATA_ZIP_FILE.read_hexhash('md5') != get_latest_data_checksum(timeout)
130-
131-
def get_artifacts():
132-
"""Return the artifacts of the latest build."""
133141
update_logger.log_debug('Getting artifacts...')
134-
with urlopen(ARTIFACTS_URL) as url:
142+
with urlopen(ARTIFACTS_URL, timeout=timeout) as url:
135143
data = json.loads(url.read())
136-
137144
for d in data['artifacts']:
138145
yield d['relativePath']
139146

140-
def get_download_url(game=SOURCE_ENGINE_BRANCH):
141-
"""Get the latest download URL for a specific game."""
142-
for relative_path in get_artifacts():
147+
def get_download_url(game=SOURCE_ENGINE_BRANCH, timeout=DEFAULT_TIMEOUT):
148+
"""Get the latest Source.Python download URL for a specific game.
149+
150+
:param str game:
151+
The game game to look for (e.g. ``css``).
152+
:param float timeout:
153+
Number of seconds that need to pass until a timeout occurs.
154+
:rtype: str
155+
:raise ValueError:
156+
Raised if the game wasn't found.
157+
"""
158+
for relative_path in get_build_artifacts(timeout):
143159
if f'-{game}-' in relative_path:
144160
return BASE_DOWNLOAD_URL + relative_path
145161

146162
raise ValueError(f'Unable to find a download URL for game "{game}".')
147163

148-
def download_file(url_path, file_path, timeout=3):
149-
"""Download a file from an URL to a specific file."""
150-
update_logger.log_debug(f'Downloading file ({url_path}) to {file_path} ...')
151-
now = time.time()
152-
153-
with urlopen(url_path, timeout=timeout) as url:
154-
data = url.read()
155-
156-
with file_path.open('wb') as f:
157-
f.write(data)
158-
159-
update_logger.log_info(
160-
'File has been downloaded. Time elapsed: {:0.2f} seconds'.format(
161-
time.time()-now))
162-
163-
def clean_update_dir():
164+
def _clean_update_dir():
164165
"""Clear or create the update directory."""
165166
if UPDATE_PATH.exists():
166167
for f in UPDATE_PATH.listdir():
@@ -171,11 +172,15 @@ def clean_update_dir():
171172
else:
172173
UPDATE_PATH.mkdir()
173174

174-
def download_latest_version(timeout=3):
175-
"""Download the latest version."""
175+
def _download_latest_version(timeout=DEFAULT_TIMEOUT):
176+
"""Download the latest Source.Python version.
177+
178+
:param float timeout:
179+
Number of seconds that need to pass until a timeout occurs.
180+
"""
176181
download_file(get_download_url(), UPDATE_ZIP_FILE, timeout)
177182

178-
def apply_update_stage1():
183+
def _apply_update_stage1():
179184
"""Apply stage 1 of the version update."""
180185
update_logger.log_message('Applying Source.Python update stage 1...')
181186

@@ -238,3 +243,58 @@ def _apply_update_stage1_linux():
238243

239244
update_logger.log_message(
240245
'Stage 1 has been applied. Restart your server to apply stage 2.')
246+
247+
248+
# =============================================================================
249+
# >> SP DATA UPDATE
250+
# =============================================================================
251+
def update_data(timeout=DEFAULT_TIMEOUT):
252+
"""Download and unpack the latest data from the build server.
253+
254+
Old data gets deleted before unpacking.
255+
256+
:param float timeout:
257+
Number of seconds that need to pass until a timeout occurs.
258+
"""
259+
_download_latest_data(timeout)
260+
if SP_DATA_PATH.isdir():
261+
update_logger.log_debug('Removing {} ...'.format(SP_DATA_PATH))
262+
SP_DATA_PATH.rmtree()
263+
264+
_unpack_data()
265+
266+
def is_new_data_available(timeout=DEFAULT_TIMEOUT):
267+
"""Return ``True`` if new data is available.
268+
269+
:param float timeout:
270+
Number of seconds that need to pass until a timeout occurs.
271+
:rtype: bool
272+
"""
273+
if not DATA_ZIP_FILE.isfile():
274+
return True
275+
276+
return DATA_ZIP_FILE.read_hexhash('md5') != get_latest_data_checksum(timeout)
277+
278+
def get_latest_data_checksum(timeout=DEFAULT_TIMEOUT):
279+
"""Return the MD5 checksum of the latest data from the build server.
280+
281+
:param float timeout:
282+
Number of seconds that need to pass until a timeout occurs.
283+
:rtype: str
284+
"""
285+
with urlopen(CHECKSUM_URL, timeout=timeout) as url:
286+
return url.read().decode()
287+
288+
def _download_latest_data(timeout=DEFAULT_TIMEOUT):
289+
"""Download the latest data from the build server.
290+
291+
:param float timeout:
292+
Number of seconds that need to pass until a timeout occurs.
293+
"""
294+
download_file(DATA_URL, DATA_ZIP_FILE, timeout)
295+
296+
def _unpack_data():
297+
"""Unpack ``source-python-data.zip``."""
298+
update_logger.log_debug('Extracting data in {} ...'.format(DATA_PATH))
299+
with ZipFile(DATA_ZIP_FILE) as zip:
300+
zip.extractall(DATA_PATH)

0 commit comments

Comments
 (0)