From 870cc8d8d51c600d1b9faa0a2d6a5a9dba8b5354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Touceda?= Date: Thu, 21 Nov 2013 12:31:23 -0300 Subject: Create bundler for OSX --- bundler/actions.py | 443 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 bundler/actions.py (limited to 'bundler/actions.py') diff --git a/bundler/actions.py b/bundler/actions.py new file mode 100644 index 0000000..6b977d4 --- /dev/null +++ b/bundler/actions.py @@ -0,0 +1,443 @@ +import os +import stat +import sys + +from abc import ABCMeta, abstractmethod +from contextlib import contextmanager +from distutils import file_util, dir_util + +from sh import git, cd, python, mkdir, make, cp, glob, pip, rm +from sh import find, SetFile, hdiutil, ln + +from utils import IS_MAC +from depcollector import collect_deps +from darwin_dyliber import fix_all_dylibs + +class Action(object): + __metaclass__ = ABCMeta + + def __init__(self, name, basedir, skip=[], do=[]): + self._name = name + self._basedir = basedir + self._skip = skip + self._do = do + + @property + def name(self): + return self._name + + @property + def skip(self): + return self._name in self._skip + + @property + def do(self): + if len(self._do) > 0: + return self._name in self._do + return True + + @abstractmethod + def run(self, *args, **kwargs): + pass + +def skippable(func): + def skip_func(self, *args, **kwargs): + if self.skip: + print "Skipping...", self.name + return + if not self.do: + print "Skipping...", self.name + return + return func(self, *args, **kwargs) + return skip_func + +def platform_dir(basedir, *args): + dir = os.path.join(basedir, + "Bitmask", + *args) + if IS_MAC: + dir = os.path.join(basedir, + "Bitmask", + "Bitmask.app", + "Contents", + "MacOS", + *args) + return dir + +@contextmanager +def push_pop(*directories): + cd(os.path.join(*directories)) + yield + cd(os.path.join(*(("..",)*len(directories)))) + +class GitCloneAll(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "gitclone", basedir, skip, do) + + def _repo_url(self, repo_name): + if repo_name == "leap_assets": + return "git://leap.se/leap_assets" + return "https://github.com/leapcode/{0}".format(repo_name) + + @skippable + def run(self, sorted_repos, nightly): + print "Cloning repositories..." + cd(self._basedir) + for repo in sorted_repos: + print "Cloning", repo + rm("-rf", repo) + git.clone(self._repo_url(repo), repo) + with push_pop(repo): + # Thandy is a special case regarding branches, we'll just use + # develop + if repo in ["thandy", "leap_assets"]: + continue + if not nightly: + git.checkout("master") + git.pull("--ff-only", "origin", "master") + git.fetch() + git.reset("--hard", "origin/master") + latest_tag = git.describe("--abbrev=0").strip() + git.checkout("--quiet", latest_tag) + else: + git.checkout("develop") + + print "Done cloning repos..." + +class PythonSetupAll(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "pythonsetup", basedir, skip, do) + + @skippable + def run(self, sorted_repos): + cd(self._basedir) + for repo in sorted_repos: + print "Setting up", repo + if repo == "soledad": + for subrepo in ["common", "client"]: + with push_pop(repo, subrepo): + pip("install", "-r", "pkg/requirements.pip") + python("setup.py", "develop") + sys.path.append(os.path.join(self._basedir, repo, subrepo, "src")) + elif repo in ["bitmask_launcher", "leap_assets"]: + print "Skipping launcher..." + continue + else: + with push_pop(repo): + if repo != "thandy": + pip("install", "-r", "pkg/requirements.pip") + else: + # Thandy is a special kid at this point in + # terms of packaging. So we install + # dependencies ourselves for the time being + pip("install", "pycrypto") + if repo == "bitmask_client": + print "Running make on the client..." + make() + print "Running build to get correct version..." + python("setup.py", "build") + python("setup.py", "develop") + sys.path.append(os.path.join(self._basedir, repo, "src")) + +class CreateDirStructure(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "createdirs", basedir, skip, do) + + @skippable + def run(self): + print "Creating directory structure..." + if IS_MAC: + self._darwin_create_dir_structure() + self._create_dir_structure(os.path.join(self._basedir, "Bitmask.app", "Contents", "MacOS")) + else: + self._create_dir_structure(self._basedir) + print "Done" + + def _create_dir_structure(self, basedir): + mkdirp = mkdir.bake("-p") + apps = os.path.join(basedir, "apps") + mkdirp(apps) + if not IS_MAC: + mkdirp(os.path.join(apps, "eip", "files")) + mkdirp(os.path.join(apps, "mail")) + mkdirp(os.path.join(basedir, "lib")) + + def _darwin_create_dir_structure(self): + mkdirp = mkdir.bake("-p") + app_path = os.path.join(self._basedir, "Bitmask.app") + mkdirp(app_path) + mkdirp(os.path.join(app_path, "Contents", "MacOS")) + mkdirp(os.path.join(app_path, "Contents", "Resources")) + mkdirp(os.path.join(app_path, "Contents", "PlugIns")) + mkdirp(os.path.join(app_path, "Contents", "StartupItems")) + ln("-s", "/Applications", os.path.join(self._basedir, "Applications")) + +class CollectAllDeps(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "collectdeps", basedir, skip, do) + + def _remove_unneeded(self, lib_dir): + print "Removing unneeded files..." + files = find(lib_dir).strip().splitlines() + for f in files: + if f.find("PySide") > 0: + if os.path.split(f)[1] not in ["QtCore.so", + "QtGui.so", + "__init__.py", + "_utils.py", + "PySide", + ""]: # empty means the whole pyside dir + rm("-rf", f) + print "Done" + + @skippable + def run(self, path_file): + print "Collecting dependencies..." + app_py = os.path.join(self._basedir, + "bitmask_client", + "src", + "leap", + "bitmask", + "app.py") + dest_lib_dir = platform_dir(self._basedir, "lib") + collect_deps(app_py, dest_lib_dir, path_file) + + self._remove_unneeded(dest_lib_dir) + print "Done" + +class CopyBinaries(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "copybinaries", basedir, skip, do) + + @skippable + def run(self, binaries_path): + print "Copying binaries..." + dest_lib_dir = platform_dir(self._basedir, "lib") + cp(glob(os.path.join(binaries_path, "Qt*")), dest_lib_dir) + cp(glob(os.path.join(binaries_path, "*.dylib")), dest_lib_dir) + cp(glob(os.path.join(binaries_path, "Python")), dest_lib_dir) + + if IS_MAC: + resources_dir = os.path.join(self._basedir, + "Bitmask", + "Bitmask.app", + "Contents", + "Resources") + cp(glob(os.path.join(binaries_path, "openvpn.leap*")), resources_dir) + + mkdir("-p", os.path.join(resources_dir, "openvpn")) + cp("-r", glob(os.path.join(binaries_path, "openvpn.files", "*")), os.path.join(resources_dir, "openvpn")) + + cp(os.path.join(binaries_path, "cocoasudo"), resources_dir) + + cp("-r", os.path.join(binaries_path, "qt_menu.nib"), resources_dir) + cp("-r", os.path.join(binaries_path, "tuntap-installer.app"), resources_dir) + else: + eip_dir = platform_dir(self._basedir, "apps", "eip") + cp(glob(os.path.join(binaries_path, "openvpn.leap*")), eip_dir) + + mkdir(os.path.join(resources_dir, "openvpn")) + cp("-r", glob(os.path.join(binaries_path, "openvpn.files", "*")), os.path.join(eip_dir, "files")) + + mail_dir = platform_dir(self._basedir, "apps", "mail") + cp(os.path.join(binaries_path, "gpg"), mail_dir) + cp(os.path.join(binaries_path, "Bitmask"), platform_dir(self._basedir)) + print "Done" + +class PLister(Action): + plist = """ + + + + CFBundleDisplayName + Bitmask + CFBundleExecutable + MacOS/bitmask-launcher + CFBundleIconFile + bitmask.icns + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Bitmask + CFBundlePackageType + APPL + CFBundleShortVersionString + 1 + LSBackgroundOnly + + +""".split("\n") + + qtconf = """[Paths] +Plugins = PlugIns""" + + def __init__(self, basedir, skip, do): + Action.__init__(self, "plister", basedir, skip, do) + + @skippable + def run(self): + print "Generating Info.plist file..." + file_util.write_file(os.path.join(self._basedir, + "Bitmask", + "Bitmask.app", + "Contents", + "Info.plist"), + self.plist) + print "Generating qt.conf file..." + file_util.write_file(os.path.join(self._basedir, + "Bitmask", + "Bitmask.app", + "Contents", + "Resources", + "qt.conf"), + self.qtconf) + print "Done" + +class SeededConfig(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "seededconfig", basedir, skip, do) + + @skippable + def run(self, seeded_config): + print "Copying seeded config..." + dir_util.copy_tree(seeded_config, + platform_dir(self._basedir, "config")) + print "Done" + +class DarwinLauncher(Action): + launcher = """#!/bin/bash +# +# Launcher for the LEAP Client under OSX +# +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +export DYLD_LIBRARY_PATH=$DIR/lib +export PATH=$DIR/../Resources/:$PATH +# --------------------------- +# DEBUG Info -- enable this if you +# are having problems with dynamic libraries loading + +cd "${DIR}" && ./Bitmask $1 $2 $3 $4 $5""".split("\n") + + def __init__(self, basedir, skip, do): + Action.__init__(self, "darwinlauncher", basedir, skip, do) + + @skippable + def run(self): + print "Generating launcher script for OSX..." + launcher_path = os.path.join(self._basedir, + "Bitmask", + "Bitmask.app", + "Contents", + "MacOS", + "bitmask-launcher") + file_util.write_file(launcher_path, self.launcher) + os.chmod(launcher_path, stat.S_IRGRP | stat.S_IROTH | stat.S_IRUSR \ + | stat.S_IWGRP | stat.S_IWOTH | stat.S_IWUSR \ + | stat.S_IXGRP | stat.S_IXOTH | stat.S_IXUSR) + print "Done" + +class CopyAssets(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "copyassets", basedir, skip, do) + + @skippable + def run(self): + print "Copying assets..." + resources_dir = os.path.join(self._basedir, + "Bitmask", + "Bitmask.app", + "Contents", + "Resources") + cp(os.path.join(self._basedir, "leap_assets", "mac", "bitmask.icns"), + resources_dir) + cp(os.path.join(self._basedir, "leap_assets", "mac", "leap-client.tiff"), + resources_dir) + print "Done" + +class CopyMisc(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "copymisc", basedir, skip, do) + + @skippable + def run(self): + print "Copying misc files..." + apps_dir = platform_dir(self._basedir, "apps") + cp(os.path.join(self._basedir, "bitmask_launcher", "src", "launcher.py"), + apps_dir) + cp("-r", os.path.join(self._basedir, "thandy", "lib", "thandy"), + apps_dir) + cp("-r", os.path.join(self._basedir, "bitmask_client", "src", "leap"), + apps_dir) + lib_dir = platform_dir(self._basedir, "lib") + cp(os.path.join(self._basedir, + "leap_pycommon", + "src", "leap", "common", "cacert.pem"), + os.path.join(lib_dir, "leap", "common")) + cp(os.path.join(self._basedir, + "bitmask_client", "build", + "lib", "leap", "bitmask", "_version.py"), + os.path.join(apps_dir, "leap", "bitmask")) + + cp(os.path.join(self._basedir, + "bitmask_client", "relnotes.txt"), + os.path.join(self._basedir, "Bitmask")) + print "Done" + +class FixDylibs(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "fixdylibs", basedir, skip, do) + + @skippable + def run(self): + fix_all_dylibs(platform_dir(self._basedir)) + +class DmgIt(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "dmgit", basedir, skip, do) + + @skippable + def run(self): + cd(self._basedir) + version = "unknown" + with push_pop("bitmask_client"): + version = git("describe").strip() + dmg_dir = os.path.join(self._basedir, "dmg") + template_dir = os.path.join(self._basedir, "Bitmask") + mkdir("-p", dmg_dir) + cp("-R", os.path.join(template_dir, "Applications"), dmg_dir) + cp("-R", os.path.join(template_dir, "relnotes.txt"), dmg_dir) + cp("-R", os.path.join(template_dir, "Bitmask.app"), dmg_dir) + cp(os.path.join(self._basedir, + "leap_assets", + "mac", "bitmask.icns"), + os.path.join(dmg_dir, ".VolumeIcon.icns")) + SetFile("-c", "icnC", os.path.join(dmg_dir, ".VolumeIcon.icns")) + + vol_name = "Bitmask" + dmg_name = "Bitmask-OSX-{0}.dmg".format(version) + raw_dmg_path = os.path.join(self._basedir, "raw-{0}".format(dmg_name)) + dmg_path = os.path.join(self._basedir, dmg_name) + + hdiutil("create", "-srcfolder", dmg_dir, "-volname", vol_name, + "-format", "UDRW", "-ov", + raw_dmg_path) + rm("-rf", dmg_dir) + mkdir(dmg_dir) + hdiutil("attach", raw_dmg_path, "-mountpoint", dmg_dir) + SetFile("-a", "C", dmg_dir) + hdiutil("detach", dmg_dir) + + rm("-rf", dmg_dir) + hdiutil("convert", raw_dmg_path, "-format", "UDZO", "-o", + dmg_path) + rm("-f", raw_dmg_path) + +class PycRemover(Action): + def __init__(self, basedir, skip, do): + Action.__init__(self, "removepyc", basedir, skip, do) + + @skippable + def run(self): + print "Removing .pyc files..." + find(self._basedir, "-name", "\"*.pyc\"", "-delete") + print "Done" -- cgit v1.2.3