summaryrefslogtreecommitdiffstats
path: root/bin/update
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /bin/update
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bin/update')
-rwxr-xr-xbin/update/create_build_config.py59
-rwxr-xr-xbin/update/create_full_mar.py80
-rwxr-xr-xbin/update/create_full_mar_for_languages.py71
-rwxr-xr-xbin/update/create_partial_update.py169
-rw-r--r--bin/update/path.py68
-rw-r--r--bin/update/signing.py15
-rw-r--r--bin/update/tools.py61
-rwxr-xr-xbin/update/uncompress_mar.py58
-rwxr-xr-xbin/update/upload_build_config.py42
-rwxr-xr-xbin/update/upload_builds.py34
10 files changed, 657 insertions, 0 deletions
diff --git a/bin/update/create_build_config.py b/bin/update/create_build_config.py
new file mode 100755
index 0000000000..de39b645ce
--- /dev/null
+++ b/bin/update/create_build_config.py
@@ -0,0 +1,59 @@
+#! /usr/bin/env python3
+
+import json
+import sys
+import os
+
+from tools import replace_variables_in_string
+
+
+def update_all_url_entries(data, **kwargs):
+ data['complete']['url'] = replace_variables_in_string(data['complete']['url'], **kwargs)
+
+ if sys.platform != "cygwin":
+ for language in data['languages']:
+ language['complete']['url'] = replace_variables_in_string(language['complete']['url'], **kwargs)
+
+ if 'partials' in data:
+ for partial in data['partials']:
+ partial['file']['url'] = replace_variables_in_string(partial['file']['url'], **kwargs)
+
+ if sys.platform == "cygwin":
+ continue
+
+ for lang, lang_file in partial['languages'].items():
+ lang_file['url'] = replace_variables_in_string(lang_file['url'], **kwargs)
+
+
+def main(argv):
+ if len(argv) < 7:
+ print("Usage: create_build_config.py $PRODUCTNAME $VERSION $BUILDID $PLATFORM $TARGETDIR $CHANNEL")
+ sys.exit(1)
+
+ data = {'productName': argv[1],
+ 'version': argv[2],
+ 'buildNumber': argv[3],
+ 'updateChannel': argv[6],
+ 'platform': argv[4]
+ }
+
+ extra_data_files = ['complete_info.json', 'partial_update_info.json']
+ if sys.platform != "cygwin":
+ extra_data_files.append('complete_lang_info.json')
+
+ for extra_file in extra_data_files:
+ extra_file_path = os.path.join(argv[5], extra_file)
+ if not os.path.exists(extra_file_path):
+ continue
+ with open(extra_file_path, "r") as f:
+ extra_data = json.load(f)
+ data.update(extra_data)
+
+ update_all_url_entries(data, channel=argv[6], platform=argv[4], buildid=argv[3], version=argv[2])
+
+ with open(os.path.join(argv[5], "build_config.json"), "w") as f:
+ json.dump(data, f, indent=4)
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/bin/update/create_full_mar.py b/bin/update/create_full_mar.py
new file mode 100755
index 0000000000..b4f53c48f1
--- /dev/null
+++ b/bin/update/create_full_mar.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+
+import sys
+import glob
+import os
+import re
+import subprocess
+import json
+import argparse
+
+from tools import uncompress_file_to_dir, get_file_info, make_complete_mar_name
+from signing import sign_mar_file
+from path import UpdaterPath, convert_to_unix, convert_to_native
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('product_name')
+ parser.add_argument('workdir')
+ parser.add_argument('filename_prefix')
+ parser.add_argument('certificate_path')
+ parser.add_argument('certificate_name')
+ parser.add_argument('base_url')
+ parser.add_argument('version')
+ args = parser.parse_args()
+
+ certificate_path = args.certificate_path
+ certificate_name = args.certificate_name
+ base_url = args.base_url
+ filename_prefix = args.filename_prefix
+ workdir = args.workdir
+ product_name = args.product_name
+ version = args.version
+
+ update_path = UpdaterPath(workdir)
+ update_path.ensure_dir_exist()
+
+ target_dir = update_path.get_update_dir()
+ temp_dir = update_path.get_current_build_dir()
+
+ tar_file_glob = os.path.join(update_path.get_workdir(), "installation", product_name, "archive", "install", "*", f'{product_name}_*_archive*')
+ tar_files = glob.glob(tar_file_glob)
+ if len(tar_files) != 1:
+ raise Exception(f'`{tar_file_glob}` does not match exactly one file')
+ tar_file = tar_files[0]
+
+ uncompress_dir = uncompress_file_to_dir(tar_file, temp_dir)
+
+ metadatafile = os.path.join(
+ update_path.get_workdir(), 'installation', product_name, 'archive', 'install', 'metadata')
+ ifsfile = os.path.join(update_path.get_mar_dir(), 'ifs')
+ with open(metadatafile) as meta, open(ifsfile, 'w') as ifs:
+ for l in meta:
+ m = re.fullmatch('(skip|cond) (.*)', l.rstrip())
+ if m and m.group(2).startswith(f'{product_name}/'):
+ path = m.group(2)[len(f'{product_name}/'):]
+ if m.group(1) == 'skip':
+ os.remove(os.path.join(uncompress_dir, path))
+ else:
+ ifs.write(f'"{path}" "{path}"\n')
+
+ mar_file = make_complete_mar_name(target_dir, filename_prefix)
+ path = os.path.join(
+ workdir, 'UnpackedTarball/onlineupdate/tools/update-packaging/make_full_update.sh')
+ os.putenv('MOZ_PRODUCT_VERSION', version)
+ os.putenv('MAR_CHANNEL_ID', 'LOOnlineUpdater')
+ subprocess.call([
+ path, convert_to_native(mar_file), convert_to_native(uncompress_dir),
+ convert_to_native(ifsfile)])
+
+ sign_mar_file(target_dir, certificate_path, certificate_name, mar_file, filename_prefix)
+
+ file_info = {'complete': get_file_info(mar_file, base_url)}
+
+ with open(os.path.join(target_dir, 'complete_info.json'), "w") as complete_info_file:
+ json.dump(file_info, complete_info_file, indent=4)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/update/create_full_mar_for_languages.py b/bin/update/create_full_mar_for_languages.py
new file mode 100755
index 0000000000..d431ecaf6d
--- /dev/null
+++ b/bin/update/create_full_mar_for_languages.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+import subprocess
+import json
+
+from tools import uncompress_file_to_dir, get_file_info
+
+from path import UpdaterPath
+from signing import sign_mar_file
+
+
+def make_complete_mar_name(target_dir, filename_prefix, language):
+ filename = filename_prefix + "_" + language + "_complete_langpack.mar"
+ return os.path.join(target_dir, filename)
+
+
+def create_lang_infos(mar_file_name, language, url):
+ data = {'lang': language,
+ 'complete': get_file_info(mar_file_name, url)
+ }
+ return data
+
+
+def main():
+ if len(sys.argv) < 8:
+ print(
+ "Usage: create_full_mar_for_languages.py $PRODUCTNAME $WORKDIR $TARGETDIR $TEMPDIR $FILENAMEPREFIX $CERTIFICATEPATH $CERTIFICATENAME $BASEURL $VERSION")
+ sys.exit(1)
+
+ certificate_path = sys.argv[4]
+ certificate_name = sys.argv[5]
+ base_url = sys.argv[6]
+ filename_prefix = sys.argv[3]
+ workdir = sys.argv[2]
+ product_name = sys.argv[1]
+ version = sys.argv[7]
+
+ updater_path = UpdaterPath(workdir)
+ target_dir = updater_path.get_update_dir()
+ temp_dir = updater_path.get_language_dir()
+
+ language_pack_dir = os.path.join(workdir, "installation", product_name + "_languagepack", "archive", "install")
+ language_packs = os.listdir(language_pack_dir)
+ lang_infos = []
+ for language in language_packs:
+ if language == 'log':
+ continue
+
+ language_dir = os.path.join(language_pack_dir, language)
+ language_file = os.path.join(language_dir, os.listdir(language_dir)[0])
+
+ directory = uncompress_file_to_dir(language_file, os.path.join(temp_dir, language))
+
+ mar_file_name = make_complete_mar_name(target_dir, filename_prefix, language)
+
+ os.putenv('MOZ_PRODUCT_VERSION', version)
+ os.putenv('MAR_CHANNEL_ID', 'LOOnlineUpdater')
+ subprocess.call([os.path.join(workdir, 'UnpackedTarball/onlineupdate/tools/update-packaging/make_full_update.sh'), mar_file_name, directory])
+
+ sign_mar_file(target_dir, certificate_path, certificate_name, mar_file_name, filename_prefix)
+
+ lang_infos.append(create_lang_infos(mar_file_name, language, base_url))
+
+ with open(os.path.join(target_dir, "complete_lang_info.json"), "w") as language_info_file:
+ json.dump({'languages': lang_infos}, language_info_file, indent=4)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/update/create_partial_update.py b/bin/update/create_partial_update.py
new file mode 100755
index 0000000000..2730c4765f
--- /dev/null
+++ b/bin/update/create_partial_update.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+import json
+import os
+import subprocess
+import sys
+
+import requests
+
+from path import UpdaterPath, mkdir_p, convert_to_unix, convert_to_native
+from signing import sign_mar_file
+from tools import get_file_info, get_hash
+from uncompress_mar import extract_mar
+
+BUF_SIZE = 1024
+current_dir_path = os.path.dirname(os.path.realpath(convert_to_unix(__file__)))
+
+
+class InvalidFileException(Exception):
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(self, *args, **kwargs)
+
+
+def download_file(filepath, url, hash_string):
+ with open(filepath, "wb") as f:
+ response = requests.get(url, stream=True)
+
+ if not response.ok:
+ return
+
+ for block in response.iter_content(1024):
+ f.write(block)
+
+ file_hash = get_hash(filepath)
+
+ if file_hash != hash_string:
+ raise InvalidFileException(
+ "file hash does not match for file %s: Expected %s, Got: %s" % (url, hash_string, file_hash))
+
+
+def handle_language(lang_entries, filedir):
+ langs = {}
+ for lang, data in lang_entries.items():
+ lang_dir = os.path.join(filedir, lang)
+ lang_file = os.path.join(lang_dir, "lang.mar")
+ mkdir_p(lang_dir)
+ download_file(lang_file, data["url"], data["hash"])
+ dir_path = os.path.join(lang_dir, "lang")
+ mkdir_p(dir_path)
+ extract_mar(lang_file, dir_path)
+ langs[lang] = dir_path
+
+ return langs
+
+
+def download_mar_for_update_channel_and_platform(server_url, channel, platform, temp_dir):
+ base_url = server_url + "update/partial-targets/1/"
+ url = base_url + platform + "/" + channel
+ r = requests.get(url)
+ if r.status_code != 200:
+ print(r.content)
+ raise Exception("download failed")
+
+ update_info = json.loads(r.content.decode("utf-8"))
+ update_files = update_info['updates']
+ downloaded_updates = {}
+ for update_file in update_files:
+ build = update_file["build"]
+ filedir = os.path.join(temp_dir, build)
+
+ mkdir_p(filedir)
+
+ filepath = filedir + "/complete.mar"
+ url = update_file["update"]["url"]
+ expected_hash = update_file["update"]["hash"]
+ download_file(filepath, url, expected_hash)
+
+ dir_path = os.path.join(filedir, "complete")
+ mkdir_p(dir_path)
+ extract_mar(filepath, dir_path)
+
+ downloaded_updates[build] = {"complete": dir_path}
+
+ langs = handle_language(update_file["languages"], filedir)
+ downloaded_updates[build]["languages"] = langs
+
+ return downloaded_updates
+
+
+def generate_file_name(old_build_id, mar_name_prefix):
+ name = "%s_from_%s_partial.mar" % (mar_name_prefix, old_build_id)
+ return name
+
+
+def generate_lang_file_name(old_build_id, mar_name_prefix, lang):
+ name = "%s_%s_from_%s_partial.mar" % (mar_name_prefix, lang, old_build_id)
+ return name
+
+
+def add_single_dir(path):
+ dir_name = [os.path.join(path, name) for name in os.listdir(path) if os.path.isdir(os.path.join(path, name))]
+ return dir_name[0]
+
+
+def main():
+ workdir = sys.argv[1]
+
+ updater_path = UpdaterPath(workdir)
+ updater_path.ensure_dir_exist()
+
+ mar_name_prefix = sys.argv[2]
+ server_url = sys.argv[3]
+ channel = sys.argv[4]
+ certificate_path = sys.argv[5]
+ certificate_name = sys.argv[6]
+ base_url = sys.argv[7]
+ platform = sys.argv[8]
+ build_id = sys.argv[9]
+
+ current_build_path = updater_path.get_current_build_dir()
+ mar_dir = updater_path.get_mar_dir()
+ temp_dir = updater_path.get_previous_build_dir()
+ update_dir = updater_path.get_update_dir()
+
+ current_build_path = add_single_dir(current_build_path)
+ if sys.platform == "cygwin":
+ current_build_path = add_single_dir(current_build_path)
+
+ updates = download_mar_for_update_channel_and_platform(server_url, channel, platform, temp_dir)
+
+ data = {"partials": []}
+
+ for build, update in updates.items():
+ file_name = generate_file_name(build, mar_name_prefix)
+ mar_file = os.path.join(update_dir, file_name)
+ subprocess.call([os.path.join(current_dir_path, 'make_incremental_update.sh'), convert_to_native(mar_file),
+ convert_to_native(update["complete"]), convert_to_native(current_build_path)])
+ sign_mar_file(update_dir, certificate_path, certificate_name, mar_file, mar_name_prefix)
+
+ partial_info = {"file": get_file_info(mar_file, base_url), "from": build, "to": build_id,
+ "languages": {}}
+
+ # on Windows we don't use language packs
+ if sys.platform != "cygwin":
+ for lang, lang_info in update["languages"].items():
+ lang_name = generate_lang_file_name(build, mar_name_prefix, lang)
+
+ # write the file into the final directory
+ lang_mar_file = os.path.join(update_dir, lang_name)
+
+ # the directory of the old language file is of the form
+ # workdir/mar/language/en-US/LibreOffice_<version>_<os>_archive_langpack_<lang>/
+ language_dir = add_single_dir(os.path.join(mar_dir, "language", lang))
+ subprocess.call(
+ [os.path.join(current_dir_path, 'make_incremental_update.sh'), convert_to_native(lang_mar_file),
+ convert_to_native(lang_info), convert_to_native(language_dir)])
+ sign_mar_file(update_dir, certificate_path, certificate_name, lang_mar_file, mar_name_prefix)
+
+ # add the partial language info
+ partial_info["languages"][lang] = get_file_info(lang_mar_file, base_url)
+
+ data["partials"].append(partial_info)
+
+ with open(os.path.join(update_dir, "partial_update_info.json"), "w") as f:
+ json.dump(data, f)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/update/path.py b/bin/update/path.py
new file mode 100644
index 0000000000..d91e9e7fba
--- /dev/null
+++ b/bin/update/path.py
@@ -0,0 +1,68 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import os
+import errno
+import subprocess
+from sys import platform
+
+def mkdir_p(path):
+ try:
+ os.makedirs(path)
+ except OSError as exc: # Python >2.5
+ if exc.errno == errno.EEXIST and os.path.isdir(path):
+ pass
+ else:
+ raise
+
+def convert_to_unix(path):
+ if platform == "cygwin":
+ return subprocess.check_output(["cygpath", "-u", path]).decode("utf-8", "strict").rstrip()
+ else:
+ return path
+
+
+def convert_to_native(path):
+ if platform == "cygwin":
+ return subprocess.check_output(["cygpath", "-m", path]).decode("utf-8", "strict").rstrip()
+ else:
+ return path
+
+
+class UpdaterPath(object):
+
+ def __init__(self, workdir):
+ self._workdir = convert_to_unix(workdir)
+
+ def get_workdir(self):
+ return self._workdir
+
+ def get_update_dir(self):
+ return os.path.join(self._workdir, "update-info")
+
+ def get_current_build_dir(self):
+ return os.path.join(self._workdir, "mar", "current-build")
+
+ def get_mar_dir(self):
+ return os.path.join(self._workdir, "mar")
+
+ def get_previous_build_dir(self):
+ return os.path.join(self._workdir, "mar", "previous-build")
+
+ def get_language_dir(self):
+ return os.path.join(self.get_mar_dir(), "language")
+
+ def ensure_dir_exist(self):
+ os.makedirs(self.get_update_dir(), exist_ok=True)
+ os.makedirs(self.get_current_build_dir(), exist_ok=True)
+ os.makedirs(self.get_mar_dir(), exist_ok=True)
+ os.makedirs(self.get_previous_build_dir(), exist_ok=True)
+ os.makedirs(self.get_language_dir(), exist_ok=True)
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bin/update/signing.py b/bin/update/signing.py
new file mode 100644
index 0000000000..e8546dc83b
--- /dev/null
+++ b/bin/update/signing.py
@@ -0,0 +1,15 @@
+from tools import make_complete_mar_name
+
+import os
+import subprocess
+import path
+
+
+def sign_mar_file(target_dir, certificate_path, certificate_name, mar_file, filename_prefix):
+ signed_mar_file = make_complete_mar_name(target_dir, filename_prefix + '_signed')
+ mar_executable = os.environ.get('MAR', 'mar')
+ subprocess.check_call([mar_executable, '-C', path.convert_to_native(target_dir), '-d',
+ path.convert_to_native(certificate_path), '-n', certificate_name, '-s',
+ path.convert_to_native(mar_file), path.convert_to_native(signed_mar_file)])
+
+ os.rename(signed_mar_file, mar_file)
diff --git a/bin/update/tools.py b/bin/update/tools.py
new file mode 100644
index 0000000000..ab38d10f4b
--- /dev/null
+++ b/bin/update/tools.py
@@ -0,0 +1,61 @@
+import os
+import hashlib
+import zipfile
+import tarfile
+
+
+def uncompress_file_to_dir(compressed_file, uncompress_dir):
+ extension = os.path.splitext(compressed_file)[1]
+
+ os.makedirs(uncompress_dir, exist_ok=True)
+
+ if extension == '.gz':
+ with tarfile.open(compressed_file) as tar:
+ tar.extractall(uncompress_dir)
+ elif extension == '.zip':
+ with zipfile.ZipFile(compressed_file) as zip_file:
+ zip_file.extractall(uncompress_dir)
+
+ uncompress_dir = os.path.join(uncompress_dir, os.listdir(uncompress_dir)[0])
+ if " " in os.listdir(uncompress_dir)[0]:
+ print("replacing whitespace in directory name")
+ os.rename(os.path.join(uncompress_dir, os.listdir(uncompress_dir)[0]),
+ os.path.join(uncompress_dir, os.listdir(uncompress_dir)[0].replace(" ", "_")))
+ else:
+ print("Error: unknown extension " + extension)
+
+ return os.path.join(uncompress_dir, os.listdir(uncompress_dir)[0])
+
+
+BUF_SIZE = 1048576
+
+
+def get_hash(file_path):
+ sha512 = hashlib.sha512()
+ with open(file_path, 'rb') as f:
+ while data := f.read(BUF_SIZE):
+ sha512.update(data)
+ return sha512.hexdigest()
+
+
+def get_file_info(mar_file, url):
+ filesize = os.path.getsize(mar_file)
+ data = {'hash': get_hash(mar_file),
+ 'hash_function': 'sha512',
+ 'size': filesize,
+ 'url': url + os.path.basename(mar_file)}
+
+ return data
+
+
+def replace_variables_in_string(string, **kwargs):
+ new_string = string
+ for key, val in kwargs.items():
+ new_string = new_string.replace('$(%s)' % key, val)
+
+ return new_string
+
+
+def make_complete_mar_name(target_dir, filename_prefix):
+ filename = filename_prefix + "_complete.mar"
+ return os.path.join(target_dir, filename)
diff --git a/bin/update/uncompress_mar.py b/bin/update/uncompress_mar.py
new file mode 100755
index 0000000000..14726dd961
--- /dev/null
+++ b/bin/update/uncompress_mar.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+# Extract a mar file and uncompress the content
+
+import os
+import re
+import sys
+import subprocess
+from path import convert_to_native
+
+
+def uncompress_content(file_path):
+ bzip2 = os.environ.get('BZIP2', 'bzip2')
+ file_path_compressed = file_path + ".bz2"
+ os.rename(file_path, file_path_compressed)
+ subprocess.check_call([bzip2, "-d", convert_to_native(file_path_compressed)])
+
+
+def extract_mar(mar_file, target_dir):
+ mar = os.environ.get('MAR', 'mar')
+ subprocess.check_call([mar, "-C", convert_to_native(target_dir), "-x", convert_to_native(mar_file)])
+ file_info = subprocess.check_output([mar, "-t", convert_to_native(mar_file)])
+ lines = file_info.splitlines()
+ prog = re.compile(r"\d+\s+\d+\s+(.+)")
+ for line in lines:
+ match = prog.match(line.decode("utf-8", "strict"))
+ if match is None:
+ continue
+ info = match.groups()[0]
+ # ignore header line
+ if info == b'NAME':
+ continue
+
+ uncompress_content(os.path.join(target_dir, info))
+
+
+def main():
+ if len(sys.argv) != 3:
+ print("Help: This program takes exactly two arguments pointing to a mar file and a target location")
+ sys.exit(1)
+
+ mar_file = sys.argv[1]
+ target_dir = sys.argv[2]
+ extract_mar(mar_file, target_dir)
+
+
+if __name__ == "__main__":
+ main()
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/bin/update/upload_build_config.py b/bin/update/upload_build_config.py
new file mode 100755
index 0000000000..ec5a94bf3e
--- /dev/null
+++ b/bin/update/upload_build_config.py
@@ -0,0 +1,42 @@
+#! /usr/bin/env python3
+
+import sys
+import os
+import configparser
+import requests
+
+dir_path = os.path.dirname(os.path.realpath(__file__))
+
+
+def main(argv):
+ updater_config = argv[2]
+
+ config = configparser.ConfigParser()
+ config.read(os.path.expanduser(updater_config))
+
+ user = config["Updater"]["User"]
+ password = config["Updater"]["Password"]
+ base_address = config["Updater"]["ServerURL"]
+
+ login_url = base_address + "accounts/login/"
+
+ session = requests.session()
+ session.get(login_url)
+ csrftoken = session.cookies['csrftoken']
+
+ login_data = {'username': user, 'password': password,
+ 'csrfmiddlewaretoken': csrftoken}
+ session.post(login_url, data=login_data, headers={"Referer": login_url})
+
+ url = base_address + "update/upload/release"
+ data = {'csrfmiddlewaretoken': csrftoken}
+
+ build_config = os.path.join(argv[1], "build_config.json")
+ r = session.post(url, files={'release_config': open(build_config, "r")}, data=data)
+ print(r.content)
+ if r.status_code != 200:
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/bin/update/upload_builds.py b/bin/update/upload_builds.py
new file mode 100755
index 0000000000..97a2f28484
--- /dev/null
+++ b/bin/update/upload_builds.py
@@ -0,0 +1,34 @@
+#! /usr/bin/env python3
+
+import sys
+import os
+import subprocess
+
+from path import convert_to_unix
+
+from tools import replace_variables_in_string
+
+
+def main():
+ # product_name = sys.argv[1]
+ buildid = sys.argv[2]
+ platform = sys.argv[3]
+ update_dir = sys.argv[4]
+ upload_url_arg = sys.argv[5]
+ channel = sys.argv[6]
+
+ upload_url = replace_variables_in_string(upload_url_arg, channel=channel, buildid=buildid,
+ platform=platform)
+
+ target_url, target_dir = upload_url.split(':')
+
+ command = "ssh %s 'mkdir -p %s'" % (target_url, target_dir)
+ print(command)
+ subprocess.call(command, shell=True)
+ for file in os.listdir(update_dir):
+ if file.endswith('.mar'):
+ subprocess.call(['scp', convert_to_unix(os.path.join(update_dir, file)), upload_url])
+
+
+if __name__ == '__main__':
+ main()