Files
jellyfin-desktop/scripts/fetch-binaries.py
T
Vincent Lang f1487a06f3 Codecs on demand
PMP will now download codec binaries from nightlies on playback start if
built with -DENABLE_CODECS=on. With "off" (the default), most codecs on
demand code will be built, but the list of downloadable codecs will be
empty.

This uses a hardcoded CODECS_BUILD_NUMBER. This is sort of ok, as long
as the list of codecs/names on nightlies doesn't change. If there's a
change, it should be updated manually. (Same if new platforms are added
etc.) Note that even if this is not changed, the code will download the
correct codecs by looking at the FFmpeg version number libmpv is linked
against.
2016-04-07 17:57:30 +02:00

279 lines
11 KiB
Python
Executable File

#!/usr/bin/env python
# Sample CI usage: scripts\common\fetch-binaries.py -p windows -b release -t abc123 -n 33
# Sample desktop usage: scripts\common\fetch-binaries.py -i ..\plex-dependency-builder\output\Packages\pms-depends-windows-i386-debug-dev.bz2
import hashlib
import optparse
import ConfigParser
import os, re
import platform
import subprocess
import sys
import shutil
import urllib2
import base64
import glob
# Edit these to set a new default dependencies build
default_tag = "auto"
default_release_build_number = "109"
default_release_dir = "plexmediaplayer-dependencies-codecs"
default_branch = "master"
def sha1_for_file(path):
hash=hashlib.sha1()
fp=file(path, "rb")
while True:
data=fp.read(4096)
if not data:
break
hash.update(data)
return hash.hexdigest()
def exec_cmd(args, env={}, supress_output=False):
""" main exec_cmd function """
# forward SSH_AUTH_SOCK, so that ssh-agent works
if os.name != "nt" and "SSH_AUTH_SOCK" in os.environ:
env = os.environ
extra_env={"SSH_AUTH_SOCK":os.environ["SSH_AUTH_SOCK"]}
env.update(extra_env)
else:
env = os.environ
cmd = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = env)
output = ''
while True:
out = cmd.stdout.read(1)
if out == '' and cmd.poll() != None:
break
if out != '':
if not supress_output:
sys.stdout.write(out)
output += out
if cmd.wait() != 0:
raise Exception("Command failed: \"%s\"" % " ".join(args), output)
return output
platform_map={"linux-synology-i386":"synology-i686",
"linux-readynas-arm":"ubuntu-arm",
"linux-debian-4-i386":"debian-i686",
"linux-control4-arm":"control4-arm",
"linux-apm-ppc":"apm-ppc",
"linux-armada-arm7":"armada-arm7",
"linux-synology-arm":"synology-arm"}
def platform_str():
if "BUILD_TAG" in os.environ:
for (k, v) in platform_map.iteritems():
if k in os.environ["BUILD_TAG"]:
return "linux-"+v
return "linux-%s-%s"%(platform.linux_distribution()[0].strip().lower(), platform.machine())
def merge_directories(src, dest, move = False):
for src_dir, dirs, files in os.walk(src):
dst_dir = src_dir.replace(src, dest)
if not os.path.exists(dst_dir):
os.mkdir(dst_dir)
for file_ in files:
src_file = os.path.join(src_dir, file_)
dst_file = os.path.join(dst_dir, file_)
if os.path.exists(dst_file):
os.remove(dst_file)
if move:
shutil.move(src_file, dst_dir)
else:
shutil.copy(src_file, dst_dir)
if move and os.path.exists(src):
shutil.rmtree(src)
def unpack_and_install(download, inputfile, installed_filepath):
# Make paths absolute before changing directories
inputfile = os.path.abspath(inputfile)
if not os.path.exists(inputfile):
print "Input file %s does not exist" % inputfile
sys.exit(1)
shafile = "%s.sha.txt" % inputfile
installed_filepath = os.path.abspath(installed_filepath)
# Go to directory.
old_cwd = os.getcwd()
os.chdir(options.output)
# Check the SHA
if options.nochecksha:
print "-- Skipping SHA verification"
elif os.path.exists(shafile):
f = open(shafile, "r")
sha = f.readline().strip()
computed = sha1_for_file(inputfile)
if not computed == sha:
print "-- SHA didn't match: %s != %s" % (sha, computed)
sys.exit(1)
else:
print "-- SHA %s matches" % sha
f.close()
else:
print "-- ERROR - No SHA file is available to verify the file's integrity"
sys.exit(1)
# Untar the package file
inputfile_tarfriendly = inputfile
if os.name == "nt":
pattern = re.compile(r'([a-z]):\\', re.IGNORECASE)
inputfile_tarfriendly = pattern.sub('/\\1/', inputfile).replace('\\','/')
# The final destination directory is the filename without a version number
# The version number is the last element in the filename (by convention)
packagename = os.path.splitext(os.path.basename(inputfile))[0]
packagename_elements = packagename.split("-")
del packagename_elements[-1]
packagename_noversion = "-".join(packagename_elements)
if os.path.exists(packagename_noversion):
shutil.rmtree(packagename_noversion, ignore_errors=True)
os.makedirs(packagename_noversion)
print "-- Unpacking %s... to %s" % (os.path.basename(inputfile), packagename_noversion)
if os.name == "nt":
# Touch files from the package, which often arrive from the future when freshly built on our Windows build machine
exec_cmd(["tar", "xjf", inputfile_tarfriendly, "-C", packagename_noversion, "--touch", "--strip-components", "1", "--no-same-owner"])
else:
exec_cmd(["tar", "xjf", inputfile_tarfriendly, "-C", packagename_noversion, "--strip-components", "1", "--no-same-owner"])
if download and installed_filepath:
# Create the installed stamp file to note our success
open(installed_filepath, "wb")
# Restore directory.
os.chdir(old_cwd)
return packagename
if __name__=='__main__':
parser=optparse.OptionParser()
parser.add_option("-p", "--platform", action="store", type="string",
dest="platform", help="Platform identifier (e.g. windows-i386)", default=None)
parser.add_option("-b", "--buildconfig", action="store", type="string",
dest="buildconfig", help="Build configuration (release or debug). Default is release", default="release")
parser.add_option("-t", "--tag", action="store", type="string",
dest="tag", help="Build tag. Default is %s" % default_tag, default=default_tag)
parser.add_option("-n", "--buildnumber", action="store", type="string",
dest="buildnumber", help="Build number. Default is %s for release builds" % (default_release_build_number), default=None)
parser.add_option("-d", "--dir", action="store", type="string",
dest="dir", help="CI build dir. Default is %s for release builds" % (default_release_dir), default=None)
parser.add_option("-i", "--inputfile", action="store", type="string",
dest="inputfile", help="Dependencies package filename, can be supplied instead of platform, buildconfig, tag and buildnumber", default=None)
parser.add_option("-o", "--output", action="store", type="string",
dest="output", help="Output directory. Default is Dependencies",
default="Dependencies")
parser.add_option("-x", "--nochecksha", action="store_true",
dest="nochecksha", help="Don't check the SHA. Default is false",
default=False)
parser.add_option("-r", "--branch", action="store", type="string",
dest="branch", help="Git branch", default=None)
(options, args)=parser.parse_args(sys.argv)
if not os.path.exists(options.output):
os.makedirs(options.output)
# Fail early if platform is not known
download = not options.inputfile
if download and not options.platform:
print "ERROR - A platform must be specified"
sys.exit(1)
installed_filepath = None
if download:
if not options.buildnumber:
if options.buildconfig == "release":
options.buildnumber = default_release_build_number
else:
options.buildnumber = default_debug_build_number
if not options.dir:
if options.buildconfig == "release":
options.dir = default_release_dir
else:
options.dir = default_debug_dir
installed_filepath = os.path.join(options.output, "konvergo-depends-%s-%s-%s.installed" % (options.platform, options.buildconfig, options.buildnumber))
if os.path.exists(installed_filepath) and options.buildnumber != "latest":
print "The required deps bundle was already downloaded and installed."
print "You can delete %s to force a reinstall." % installed_filepath
sys.exit(0)
# Delete previous installed stamps
cont = ["-c"]
for path in glob.iglob(os.path.join(options.output, "konvergo-depends-%s-%s-*.installed") % (options.platform, options.buildconfig)):
match = re.search("-(\d+)\.installed", path, re.DOTALL)
if match:
if not match.group(1) == options.buildnumber:
cont = []
os.remove(path)
if options.tag == "auto":
req = urllib2.Request("https://nightlies.plex.tv/directdl/plex-dependencies/%s/%s/hash.txt" % (options.dir, options.buildnumber))
try:
match = urllib2.urlopen(req).read().rstrip()
except urllib2.URLError, err:
print err
print "ERROR - Download failed"
sys.exit(1)
options.tag = match
base_filename = "konvergo-depends-%s-%s-%s" % (options.platform, options.buildconfig, options.tag)
filename = "%s.tbz2" % base_filename
installed_filepath = os.path.join(options.output, "konvergo-depends-%s-%s-%s.installed" % (options.platform, options.buildconfig, options.buildnumber))
if os.path.exists(installed_filepath):
print "%s was already downloaded and installed." % filename
print "You can delete %s to force a reinstall." % installed_filepath
sys.exit(0)
url = "https://nightlies.plex.tv/directdl/plex-dependencies/%s/%s/%s" % (options.dir, options.buildnumber, filename)
inputfile = os.path.join(options.output, filename)
print "-- Downloading %s ..." % url
exec_cmd(["wget", "--no-check-certificate"] + cont + ["-O", inputfile, url])
shaurl = "%s.sha.txt" % url
shafile = "%s.sha.txt" % inputfile
print "-- Downloading %s ..." % shaurl
exec_cmd(["wget", "--no-check-certificate"] + ["-O", shafile, shaurl])
else:
inputfile = options.inputfile
# Unpack and install
packagename = unpack_and_install(download, inputfile, installed_filepath)
# On OS X, we need to postprocess the dependencies.
if platform.system() == 'Darwin':
root = os.path.realpath(os.path.join(os.getcwd()))
script = os.path.join(root, "scripts", "fix-install-names.py")
for p in ("lib", "bin", "update_installer"):
path = os.path.join(root, "Dependencies", "konvergo-depends-" + options.platform + "-" + options.buildconfig, p)
exec_cmd([script, path])
# Done!
print "-- Done with %s" % packagename