Skip to content

Instantly share code, notes, and snippets.

@jcristau
Last active October 26, 2021 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcristau/bbf9521fccfed846e1ea48eb9c3ee9a1 to your computer and use it in GitHub Desktop.
Save jcristau/bbf9521fccfed846e1ea48eb9c3ee9a1 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# create-channel-switch-mar.py
#
# for channel switching, replacing channel-prefs.js and/or update-settings.ini
import logging
from os import path, makedirs, getcwd, chdir
from shutil import rmtree
import subprocess
import tempfile
CHANNEL_PREFS = "default/pref/channel-prefs.js"
CHANNEL_PREFS_CONTENT = """\
/* 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/. */
pref("app.update.channel", "%s");
"""
UPDATE_SETTINGS = "update-settings.ini"
UPDATE_SETTINGS_CONTENT = """\
; If you modify this file updates may fail.
; Do not modify this file.
[Settings]
ACCEPTED_MAR_CHANNEL_IDS=%s
"""
def compress(str):
return subprocess.check_output(["xz"], input=str.encode("ascii"))
def setup_newfiles(channel=None, accepted_mar_channel_ids=None):
files = []
if channel is not None:
makedirs(path.dirname(CHANNEL_PREFS))
makedirs("Contents/Resources/" + path.dirname(CHANNEL_PREFS))
channel_prefs = compress(CHANNEL_PREFS_CONTENT % channel)
logging.info("Writing %s", CHANNEL_PREFS)
with open(CHANNEL_PREFS, "wb") as f:
f.write(channel_prefs)
with open("Contents/Resources/" + CHANNEL_PREFS, "wb") as f:
f.write(channel_prefs)
files += [CHANNEL_PREFS, "Contents/Resources/" + CHANNEL_PREFS]
if accepted_mar_channel_ids is not None:
makedirs("Contents/Resources/" + path.dirname(UPDATE_SETTINGS))
update_settings = compress(
UPDATE_SETTINGS_CONTENT % ",".join(accepted_mar_channel_ids)
)
logging.info("Writing %s", UPDATE_SETTINGS)
with open(UPDATE_SETTINGS, "wb") as f:
f.write(update_settings)
with open("Contents/Resources/" + UPDATE_SETTINGS, "wb") as f:
f.write(update_settings)
files += [UPDATE_SETTINGS, "Contents/Resources/" + UPDATE_SETTINGS]
return files
def write_manifest(files):
manifest = 'type "partial"\n'
for filename in files:
manifest += 'add-if "%s" "%s"\n' % (filename, filename)
logging.info("Writing manifest")
with open("updatev3.manifest", "wb") as f:
f.write(compress(manifest))
files.append("updatev3.manifest")
def pack_mar(tmpdir, output, version, channel, files):
logging.info("Packing mar file")
subprocess.check_call(
["mar", "-C", tmpdir, "-c", output, "-V", version, "-H", channel] + files
)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
# contents
parser.add_argument("-c", "--channel", help="update channel to switch to")
parser.add_argument(
"-i", "--accepted-channel-id", nargs="+", help="accepted mar channel id"
)
# metadata
parser.add_argument(
"-V", "--version", required=True, help="version number to use for the mar file"
)
parser.add_argument(
"-m",
"--mar-channel-id",
required=True,
help="channel id to use for the mar file",
)
parser.add_argument("-o", "--output", required=True, help="output file name")
parser.add_argument("-v", "--verbose", action="store_true", help="verbose messages")
args = parser.parse_args()
log_level = logging.INFO
if args.verbose:
log_level = logging.DEBUG
logging.basicConfig(
level=log_level, format="%(asctime)s - %(levelname)s: %(message)s"
)
log = logging.getLogger()
tmpdir = tempfile.mkdtemp()
logging.info("Working directory: %s", tmpdir)
cwd = getcwd()
chdir(tmpdir)
files = setup_newfiles(args.channel, args.accepted_channel_id)
write_manifest(files)
chdir(cwd)
pack_mar(tmpdir, args.output, args.version, args.mar_channel_id, files)
rmtree(tmpdir)
log.info("All done.")

Today's pine nightly_desktop:

  • accepted mar channel ids: firefox-mozilla-central
  • mar channel id: firefox-mozilla-central
  • update channel: nightly-pine
  • product / app name: Firefox

Today's pine nightly_pinebuild:

  • accepted mar channel ids: firefox-mozilla-central-pine
  • mar channel id: firefox-mozilla-central-pine
  • update channel: nightly-pine
  • product / app name: Firefox

We need to patch update-settings.ini to accept mars with the firefox-mozilla-central-pine channel id.

$ python3 ./create-channel-switch-mar.py -i firefox-mozilla-central-pine -V 95.0a1 -m firefox-mozilla-central -o switch-to-pine.mar
2021-10-26 13:52:09,550 - INFO: Working directory: /tmp/tmp2d56wsr9
2021-10-26 13:52:09,555 - INFO: Writing update-settings.ini
2021-10-26 13:52:09,555 - INFO: Writing manifest
2021-10-26 13:52:09,559 - INFO: Packing mar file
2021-10-26 13:52:09,634 - INFO: All done.
$ mar -T switch-pine.mar 
Compression type: xz
Signature type: unknown
Signature block found with 0 signatures

1 additional block found:
  - Product Information Block:
    - MAR channel name: firefox-mozilla-central
    - Product version: 95.0a1

SIZE    MODE    NAME   
184     0644    update-settings.ini
184     0644    Contents/Resources/update-settings.ini
140     0644    updatev3.manifest

Unsigned mar uploaded to bug 1737802

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment