Example #1
0
def run_wp(build, device):
    path_to_wp_build = path.abspath(path.join('development', 'wp'))

    path_to_xap = _create_xap_from_app(build=build,
                                       path_to_wp_build=path_to_wp_build,
                                       target='development')
    LOG.info('Running: %s' % path_to_xap)

    automation = path.join(path_to_wp_build, "automation", "bin", "Release",
                           "automation.exe")
    if not path.exists(automation):
        raise WPError("Couldn't find Windows Phone deployment tool")

    if not device or device.lower() == 'simulator':
        LOG.info('Running Windows Phone Emulator')
        target = 'emulator'
    else:
        LOG.info(
            'Running on Windows Phone device: {device}'.format(device=device))
        target = 'device'

    run_shell(automation,
              path_to_xap,
              target,
              fail_silently=False,
              verbose=True,
              logger=LOG)
Example #2
0
def _create_apk_with_aapt(build, out_apk_name, path_info, package_name,
                          lib_path, dev_dir):
    LOG.info('Creating APK with aapt')

    run_shell(
        path_info.aapt,
        'p',  # create APK package
        '-F',
        out_apk_name,  # output name
        '-S',
        path.join(dev_dir, 'res'),  # uncompressed resources folder
        '-M',
        path.join(dev_dir, 'AndroidManifest.xml'),  # uncompressed xml manifest
        '-I',
        ensure_lib_available(
            build, 'android-platform.apk'
        ),  # Android platform to "compile" resources against
        '-A',
        path.join(dev_dir, 'assets'),  # Assets folder to include
        '-0',
        '',  # Don't compress any assets - Important for content provider access to assets
        '--rename-manifest-package',
        package_name,  # Package name
        '-f',  # Force overwrite
        path.join(dev_dir, 'bin'),  # Location of raw files (app binary)
        command_log_level=logging.DEBUG)
Example #3
0
def _node(build, *args, **kw):
	node = "node"
	if not utils.which(node):
		raise WebError("couldn't find {tool} on your PATH or in likely "
				"locations - is it installed?".format(tool=node))

	kw['check_for_interrupt'] = True
	run_shell(node, *args, **kw)
Example #4
0
def _align_apk(path_info, signed_zipf_name, out_apk_name):
    LOG.info('Aligning apk')

    args = [
        path.join(path_info.sdk, 'tools', 'zipalign'), '-v', '4',
        signed_zipf_name, out_apk_name
    ]
    run_shell(*args)
Example #5
0
def _node(build, *args, **kw):
    node = "node"
    if not utils.which(node):
        raise WebError("couldn't find {tool} on your PATH or in likely "
                       "locations - is it installed?".format(tool=node))

    kw['check_for_interrupt'] = True
    run_shell(node, *args, **kw)
Example #6
0
	def _sign_app(self, build, provisioning_profile, entitlements_file, certificate=None, certificate_path=None, certificate_password=None, ident=None):
		app_folder_name = self._locate_ios_app(error_message="Couldn't find iOS app in order to sign it")
		path_to_app = path.abspath(path.join(self.path_to_ios_build, 'ios', app_folder_name))

		embedded_profile = 'embedded.mobileprovision'
		path_to_embedded_profile = path.abspath(path.join(path_to_app, embedded_profile))

		path_to_pp = path.join(build.orig_wd, provisioning_profile)
		if not path.isfile(path_to_pp):
			self._missing_provisioning_profile(build, path_to_pp)

		try:
			os.remove(path_to_embedded_profile)
		except Exception:
			LOG.warning("Couldn't remove {profile}".format(profile=path_to_embedded_profile))
		shutil.copy2(path_to_pp, path_to_embedded_profile)
		
		if not sys.platform.startswith('darwin'):
			if not certificate_path:
				lib.local_config_problem(
					build,
					message="To deploy iOS apps to a device, you must specify a "
						"path to a certificate to sign with.",
					examples={
						"ios.profiles.DEFAULT.developer_certificate_path": path.abspath("/Users/Bob/certificate.pfx")
					},
					more_info="https://trigger.io/docs/current/tools/local_config.html"
				)

			if not certificate_password:
				lib.local_config_problem(
					build,
					message="To deploy iOS apps to a device, you must specify a "
						"path the password to unlock your certificate.",
					examples={
						"ios.profiles.DEFAULT.developer_certificate_password": "******"
					},
					more_info="https://trigger.io/docs/current/tools/local_config.html"
				)

			resource_rules = path.abspath(path.join(path_to_app, 'ResourceRules.plist'))
			run_shell('java', '-jar', ensure_lib_available(build, 'codesign.jar'),
					'--app', path_to_app,
					'--binary', 'Forge',
					'--certificate', certificate_path,
					'--entitlements', entitlements_file,
					'--ident', ident,
					'--password', certificate_password)
		else:
			# Local
			codesign = self._check_for_codesign()
			resource_rules = path.abspath(path.join(path_to_app, 'ResourceRules.plist'))
			run_shell(codesign, '--force', '--preserve-metadata',
					'--entitlements', entitlements_file,
					'--sign', certificate,
					'--resource-rules={0}'.format(resource_rules),
					path_to_app)
Example #7
0
def _sign_zipf(lib_path, jre, keystore, storepass, keyalias, keypass,
               signed_zipf_name, zipf_name):
    args = [
        path.join(jre, 'java'), '-jar',
        path.join(lib_path, 'apk-signer.jar'), '--keystore', keystore,
        '--storepass', storepass, '--keyalias', keyalias, '--keypass', keypass,
        '--out', signed_zipf_name, zipf_name
    ]
    run_shell(*args)
Example #8
0
def _follow_log(path_info, chosen_device):
	LOG.info('Clearing android log')

	args = [path_info.adb, '-s', chosen_device, 'logcat', '-c']
	run_shell(*args, command_log_level=logging.INFO)

	LOG.info('Showing android log')

	run_shell(path_info.adb, '-s', chosen_device, 'logcat', 'WebCore:D', 'Forge:D', '*:s', command_log_level=logging.INFO, check_for_interrupt=True)
Example #9
0
def _open_url(url):
	'''Attempt to open the provided URL in the default browser'''
	if sys.platform.startswith('darwin'):
		run_shell('open', url, fail_silently=True)
	elif sys.platform.startswith('win'):
		# 'start' seems to need shell=True to be found (probably a builtin)
		cmd = subprocess.list2cmdline(['start', url])
		subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	elif sys.platform.startswith('linux'):
		run_shell('xdg-open', url, fail_silently=True)
Example #10
0
def _npm(build, *args, **kw):
	if sys.platform.startswith("win"):
		npm = "npm.cmd"
	else:
		npm = "npm"
	if not utils.which(npm):
		raise ServeError(NODEJS_HELP.format(tool=npm))

	kw['check_for_interrupt'] = True
	run_shell(npm, *args, **kw)
Example #11
0
def run_osx(build):
    args = [
        os.path.join('development', 'osx', 'Forge.app', 'Contents', 'MacOS',
                     'ForgeInspector')
    ]
    # Bring app to foreground after 1 second
    subprocess.Popen([
        "osascript", "-e", "delay 1", "-e",
        'tell application "%s" to activate' % build.config['name']
    ])
    run_shell(*args, command_log_level=logging.INFO, check_for_interrupt=True)
Example #12
0
def _npm(build, *args, **kw):
	if sys.platform.startswith("win"):
		npm = "npm.cmd"
	else:
		npm = "npm"
	if not utils.which(npm):
		raise WebError("""Couldn't find {tool} on your PATH or in likely locations - is it installed?

You can use the 'node_path' setting in your local configuration to set a custom install directory"""
.format(tool=npm))

	kw['check_for_interrupt'] = True
	run_shell(npm, *args, **kw)
Example #13
0
def _open_url(url):
    '''Attempt to open the provided URL in the default browser'''
    if sys.platform.startswith('darwin'):
        run_shell('open', url, fail_silently=True)
    elif sys.platform.startswith('win'):
        # 'start' seems to need shell=True to be found (probably a builtin)
        cmd = subprocess.list2cmdline(['start', url])
        subprocess.call(cmd,
                        shell=True,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT)
    elif sys.platform.startswith('linux'):
        run_shell('xdg-open', url, fail_silently=True)
Example #14
0
def _kill_adb():
	if sys.platform.startswith('win'):
		run_shell('taskkill', '/T', '/IM', 'adb.exe', fail_silently=True)
		run_shell('taskkill', '/T', '/F', '/IM', 'adb.exe', fail_silently=True)
	else:
		run_shell('killall', 'adb', fail_silently=True)
		run_shell('killall', '-9', 'adb', fail_silently=True)
Example #15
0
def _kill_adb():
    if sys.platform.startswith('win'):
        run_shell('taskkill', '/T', '/IM', 'adb.exe', fail_silently=True)
        run_shell('taskkill', '/T', '/F', '/IM', 'adb.exe', fail_silently=True)
    else:
        run_shell('killall', 'adb', fail_silently=True)
        run_shell('killall', '-9', 'adb', fail_silently=True)
Example #16
0
def _npm(build, *args, **kw):
    if sys.platform.startswith("win"):
        npm = "npm.cmd"
    else:
        npm = "npm"
    if not utils.which(npm):
        raise WebError(
            """Couldn't find {tool} on your PATH or in likely locations - is it installed?

You can use the 'node_path' setting in your local configuration to set a custom install directory"""
            .format(tool=npm))

    kw['check_for_interrupt'] = True
    run_shell(npm, *args, **kw)
Example #17
0
def _create_apk_with_aapt(build, out_apk_name, path_info, package_name, lib_path, dev_dir):
	LOG.info('Creating APK with aapt')

	run_shell(path_info.aapt,
		'p', # create APK package
		'-F', out_apk_name, # output name
		'-S', path.join(dev_dir, 'res'), # uncompressed resources folder
		'-M', path.join(dev_dir, 'AndroidManifest.xml'), # uncompressed xml manifest
		'-I', ensure_lib_available(build, 'android-platform.apk'), # Android platform to "compile" resources against
		'-A', path.join(dev_dir, 'assets'), # Assets folder to include
		'-0', '', # Don't compress any assets - Important for content provider access to assets
		'--rename-manifest-package', package_name, # Package name
		'-f', # Force overwrite
		path.join(dev_dir, 'bin'), # Location of raw files (app binary)
		command_log_level=logging.DEBUG)
Example #18
0
def _git(cmd, *args, **kwargs):
	"""Runs a git command and scrapes the output for common problems, so that we can try
	to advise the user about them

	e.g. _git('push', '--all')
	"""
	try:
		output = run_shell('git', cmd, *args, **kwargs)
	except OSError as e:
		if e.errno == errno.ENOENT:
			# TODO: download portable copy of git/locate git?
			raise WebError("Can't run git commands - you need to install git and make sure it's in your PATH")
	except ShellError as e:
		def _key_problem(output):
			lines = output.split('\n')
			if len(lines) > 0:
				first = lines[0]
				return first.startswith('Permission denied (publickey)')

		if _key_problem(e.output):
			# TODO: prompt user with choice to use existing .pub in ~/.ssh
			# or create new keypair and submit to heroku
			raise WebError('Failed to access remote git repo, you need to set up key based access')

		raise WebError('Problem running git {cmd}:\n {output}'.format(cmd=cmd, output=e.output))

	return output
Example #19
0
def _git(cmd, *args, **kwargs):
    """Runs a git command and scrapes the output for common problems, so that we can try
	to advise the user about them

	e.g. _git('push', '--all')
	"""
    try:
        output = run_shell('git', cmd, *args, **kwargs)
    except OSError as e:
        if e.errno == errno.ENOENT:
            # TODO: download portable copy of git/locate git?
            raise WebError(
                "Can't run git commands - you need to install git and make sure it's in your PATH"
            )
    except ShellError as e:

        def _key_problem(output):
            lines = output.split('\n')
            if len(lines) > 0:
                first = lines[0]
                return first.startswith('Permission denied (publickey)')

        if _key_problem(e.output):
            # TODO: prompt user with choice to use existing .pub in ~/.ssh
            # or create new keypair and submit to heroku
            raise WebError(
                'Failed to access remote git repo, you need to set up key based access'
            )

        raise WebError('Problem running git {cmd}:\n {output}'.format(
            cmd=cmd, output=e.output))

    return output
Example #20
0
def _follow_log(path_info, chosen_device):
    LOG.info('Clearing android log')

    args = [path_info.adb, '-s', chosen_device, 'logcat', '-c']
    run_shell(*args, command_log_level=logging.INFO)

    LOG.info('Showing android log')

    run_shell(path_info.adb,
              '-s',
              chosen_device,
              'logcat',
              'WebCore:D',
              'Forge:D',
              '*:s',
              command_log_level=logging.INFO,
              check_for_interrupt=True)
Example #21
0
def _sign_zipf(lib_path, jre, keystore, storepass, keyalias, keypass, signed_zipf_name, zipf_name):
	args = [
		path.join(jre,'java'),
		'-jar',
		path.join(lib_path, 'apk-signer.jar'),
		'--keystore',
		keystore,
		'--storepass',
		storepass,
		'--keyalias',
		keyalias,
		'--keypass',
		keypass,
		'--out',
		signed_zipf_name,
		zipf_name
	]
	run_shell(*args)
Example #22
0
def _run_python_code(build, extra_path, entry_point):
    python_runner = ensure_lib_available(build, 'python_runner.py')

    if sys.platform.startswith("win"):
        runner = ensure_lib_available(build, 'python_runner_win.exe')
        run_shell(runner,
                  extra_path,
                  entry_point,
                  command_log_level=logging.INFO,
                  check_for_interrupt=True)
    elif sys.platform.startswith("darwin"):
        runner = ensure_lib_available(build, 'python_runner_darwin')
        run_shell(runner,
                  extra_path,
                  entry_point,
                  command_log_level=logging.INFO,
                  check_for_interrupt=True,
                  create_process_group=True)
    else:
        python = sys.executable
        run_shell(python,
                  python_runner,
                  extra_path,
                  entry_point,
                  command_log_level=logging.INFO,
                  check_for_interrupt=True)
Example #23
0
def run_wp(build, device):
        path_to_wp_build  = path.abspath(path.join('development', 'wp'))

        path_to_xap = _create_xap_from_app(
                build=build,
                path_to_wp_build=path_to_wp_build,
                target='development'
        )
        LOG.info('Running: %s' % path_to_xap)

        automation = path.join(path_to_wp_build, "automation", "bin", "Release", "automation.exe")
        if not path.exists(automation):
                raise WPError("Couldn't find Windows Phone deployment tool")
        
	if not device or device.lower() == 'simulator': 
		LOG.info('Running Windows Phone Emulator')
                target = 'emulator'
	else:
		LOG.info('Running on Windows Phone device: {device}'.format(device=device))
                target = 'device'

        run_shell(automation, path_to_xap, target, fail_silently=False, verbose=True, logger=LOG)
Example #24
0
def _run_python_code(build, extra_path, entry_point):
	python_runner = ensure_lib_available(build, 'python_runner.py')

	if sys.platform.startswith("win"):
		runner = ensure_lib_available(build, 'python_runner_win.exe')
		run_shell(runner, extra_path, entry_point, command_log_level=logging.INFO, check_for_interrupt=True)
	elif sys.platform.startswith("darwin"):
		runner = ensure_lib_available(build, 'python_runner_darwin')
		run_shell(runner, extra_path, entry_point, command_log_level=logging.INFO, check_for_interrupt=True, create_process_group=True)
	else:
		python = sys.executable
		run_shell(python, python_runner, extra_path, entry_point, command_log_level=logging.INFO, check_for_interrupt=True)
def _align_apk(path_info, signed_zipf_name, out_apk_name):
	LOG.info('Aligning apk')
	
	args = [path_info.zipalign, '-v', '4', signed_zipf_name, out_apk_name]
	run_shell(*args)
Example #26
0
def _align_apk(path_info, signed_zipf_name, out_apk_name):
	LOG.info('Aligning apk')

	args = [path.join(path_info.sdk, 'tools', 'zipalign'), '-v', '4', signed_zipf_name, out_apk_name]
	run_shell(*args)
Example #27
0
    def _sign_app(self,
                  build,
                  provisioning_profile,
                  entitlements_file,
                  certificate=None,
                  certificate_path=None,
                  certificate_password=None,
                  ident=None):
        app_folder_name = self._locate_ios_app(
            error_message="Couldn't find iOS app in order to sign it")
        path_to_app = path.abspath(
            path.join(self.path_to_ios_build, 'ios', app_folder_name))

        embedded_profile = 'embedded.mobileprovision'
        path_to_embedded_profile = path.abspath(
            path.join(path_to_app, embedded_profile))

        path_to_pp = path.join(build.orig_wd, provisioning_profile)
        if not path.isfile(path_to_pp):
            self._missing_provisioning_profile(build, path_to_pp)

        try:
            os.remove(path_to_embedded_profile)
        except Exception:
            LOG.warning("Couldn't remove {profile}".format(
                profile=path_to_embedded_profile))
        shutil.copy2(path_to_pp, path_to_embedded_profile)

        if not sys.platform.startswith('darwin'):
            if not certificate_path:
                lib.local_config_problem(
                    build,
                    message="To deploy iOS apps to a device, you must specify a "
                    "path to a certificate to sign with.",
                    examples={
                        "ios.profiles.DEFAULT.developer_certificate_path":
                        path.abspath("/Users/Bob/certificate.pfx")
                    },
                    more_info=
                    "https://trigger.io/docs/current/tools/local_config.html")

            if not certificate_password:
                lib.local_config_problem(
                    build,
                    message="To deploy iOS apps to a device, you must specify a "
                    "path the password to unlock your certificate.",
                    examples={
                        "ios.profiles.DEFAULT.developer_certificate_password":
                        "******"
                    },
                    more_info=
                    "https://trigger.io/docs/current/tools/local_config.html")

            resource_rules = path.abspath(
                path.join(path_to_app, 'ResourceRules.plist'))
            run_shell('java', '-jar',
                      ensure_lib_available(build, 'codesign.jar'), '--app',
                      path_to_app, '--binary', 'Forge', '--certificate',
                      certificate_path, '--entitlements', entitlements_file,
                      '--ident', ident, '--password', certificate_password)
        else:
            # Local
            codesign = self._check_for_codesign()
            resource_rules = path.abspath(
                path.join(path_to_app, 'ResourceRules.plist'))
            run_shell(codesign, '--force', '--preserve-metadata',
                      '--entitlements', entitlements_file, '--sign',
                      certificate,
                      '--resource-rules={0}'.format(resource_rules),
                      path_to_app)
Example #28
0
def _have_android_8_available(path_info):
	targets = run_shell(path_info.android, 'list', 'targets', '-c').split('\n')
	return 'android-8' in targets
Example #29
0
	def run_idevice(self, build, device, provisioning_profile, certificate=None, certificate_path=None, certificate_password=None):
		possible_app_location = '{0}/ios/device-*/'.format(self.path_to_ios_build)
		LOG.debug('Looking for apps at {0}'.format(possible_app_location))
		possible_apps = glob(possible_app_location)
		if not possible_apps:
			raise IOSError("Couldn't find iOS app to run on a device")
		
		path_to_app = possible_apps[0]

		LOG.debug("Signing {app}".format(app=path_to_app))
		
		plist_str = self._grab_plist_from_binary_mess(build, provisioning_profile)
		plist_dict = self._parse_plist(plist_str)
		self.check_plist_dict(plist_dict, self.path_to_ios_build)
		self.provisioning_profile = plist_dict
		LOG.info("Plist OK")

		certificate = self._select_certificate(certificate)
		self.log_profile()
		
		if sys.platform.startswith('darwin'):
			with temp_file() as temp_file_path:
				self._create_entitlements_file(build, temp_file_path, plist_dict)
				
				self._sign_app(build=build,
					provisioning_profile=provisioning_profile,
					certificate=certificate,
					entitlements_file=temp_file_path,
				)
			
			fruitstrap = [ensure_lib_available(build, 'fruitstrap'), '-d', '-u', '-t', '10', '-b', path_to_app]
			if device and device.lower() != 'device':
				# pacific device given
				fruitstrap.append('-i')
				fruitstrap.append(device)
				LOG.info('Installing app on device {device}: is it connected?'.format(device=device))
			else:
				LOG.info('Installing app on device: is it connected?')

			def filter_and_combine(logline):
				return logline.rstrip()

			ensure_lib_available(build, 'lldb_framework.zip', extract=True)

			env = deepcopy(os.environ)
			env['PATH'] = os.path.dirname(ensure_lib_available(build, 'lldb'))+":"+env['PATH']

			run_shell(*fruitstrap, fail_silently=False, command_log_level=logging.INFO, filter=filter_and_combine, check_for_interrupt=True, env=env)
		elif sys.platform.startswith('win'):
			with temp_file() as ipa_path:
				self.create_ipa_from_app(
					build=build,
					provisioning_profile=provisioning_profile,
					output_path_for_ipa=ipa_path,
					certificate_path=certificate_path,
					certificate_password=certificate_password,
				)
				win_ios_install = [ensure_lib_available(build, 'win-ios-install.exe')]
				if device and device.lower() != 'device':
					# pacific device given
					win_ios_install.append(device)
					LOG.info('Installing app on device {device}: is it connected?'.format(device=device))
				else:
					LOG.info('Installing app on device: is it connected?')

				win_ios_install.append(ipa_path)
				win_ios_install.append(_generate_package_name(build))

				run_shell(*win_ios_install, fail_silently=False, command_log_level=logging.INFO, check_for_interrupt=True)
		else:
			if not which('ideviceinstaller'):
				raise Exception("Can't find ideviceinstaller - is it installed and on your PATH?")
			with temp_file() as ipa_path:
				self.create_ipa_from_app(
					build=build,
					provisioning_profile=provisioning_profile,
					output_path_for_ipa=ipa_path,
					certificate_path=certificate_path,
					certificate_password=certificate_password,
				)
				
				linux_ios_install = ['ideviceinstaller']
				
				if device and device.lower() != 'device':
					# pacific device given
					linux_ios_install.append('-U')
					linux_ios_install.append(device)
					LOG.info('Installing app on device {device}: is it connected?'.format(device=device))
				else:
					LOG.info('Installing app on device: is it connected?')
				
				linux_ios_install.append('-i')
				linux_ios_install.append(ipa_path)
				run_shell(*linux_ios_install, fail_silently=False,
					command_log_level=logging.INFO,
					check_for_interrupt=True)
				LOG.info('App installed, you will need to run the app on the device manually.')
Example #30
0
	def _sign_app(self, build, provisioning_profile, entitlements_file, certificate=None, certificate_path=None, certificate_password=None):
		app_folder_name = self._locate_ios_app(error_message="Couldn't find iOS app in order to sign it")
		path_to_app = path.abspath(path.join(self.path_to_ios_build, 'ios', app_folder_name))

		embedded_profile = 'embedded.mobileprovision'
		path_to_embedded_profile = path.abspath(path.join(path_to_app, embedded_profile))

		path_to_pp = path.join(build.orig_wd, provisioning_profile)
		if not path.isfile(path_to_pp):
			self._missing_provisioning_profile(build, path_to_pp)

		try:
			os.remove(path_to_embedded_profile)
		except Exception:
			LOG.warning("Couldn't remove {profile}".format(profile=path_to_embedded_profile))
		shutil.copy2(path_to_pp, path_to_embedded_profile)
		
		if not sys.platform.startswith('darwin'):
			if not certificate_path:
				lib.local_config_problem(
					build,
					message="To deploy iOS apps to a device, you must specify a "
						"path to a certificate to sign with.",
					examples={
						"ios.profiles.DEFAULT.developer_certificate_path": path.abspath("/Users/Bob/certificate.pfx")
					},
					more_info="https://trigger.io/docs/current/tools/local_config.html"
				)

			if not certificate_password:
				lib.local_config_problem(
					build,
					message="To deploy iOS apps to a device, you must specify a "
						"path the password to unlock your certificate.",
					examples={
						"ios.profiles.DEFAULT.developer_certificate_password": "******"
					},
					more_info="https://trigger.io/docs/current/tools/local_config.html"
				)

			cache_file = None
			development_certificate = False
			try:
				cert_name = subprocess.check_output(['java', '-jar', ensure_lib_available(build, 'p12name.jar'), certificate_path, certificate_password]).strip()
				if cert_name.startswith('iPhone Developer:'):
					development_certificate = True
			except Exception:
				pass

			if development_certificate:
				# Development certificate signings can be cached
				# Hash for Forge binary + signing certificate + profile + info.plist
				h = hashlib.sha1()
				with open(path.join(path_to_app, 'Forge'), 'rb') as binary_file:
					h.update(binary_file.read())
				with open(path.join(path_to_app, 'Info.plist'), 'rb') as info_plist_file:
					h.update(info_plist_file.read())
				with open(certificate_path, 'rb') as certificate_file:
					h.update(certificate_file.read())
				with open(path_to_embedded_profile, 'rb') as embedded_file:
					h.update(embedded_file.read())

				if not path.exists(path.abspath(path.join(self.path_to_ios_build, '..', '.template', 'ios-signing-cache'))):
					os.makedirs(path.abspath(path.join(self.path_to_ios_build, '..', '.template', 'ios-signing-cache')))
				cache_file = path.abspath(path.join(self.path_to_ios_build, '..', '.template', 'ios-signing-cache', h.hexdigest()))

			# XXX: Currently cache file is never saved, see below.
			if cache_file is not None and path.exists(cache_file):
				with temp_file() as resource_rules_temp:
					shutil.copy2(path.join(path_to_app, 'ResourceRules.plist'), resource_rules_temp)
					zip_to_extract = ZipFile(cache_file)
					zip_to_extract.extractall(path_to_app)
					zip_to_extract.close()
					shutil.copy2(resource_rules_temp, path.join(path_to_app, 'ResourceRules.plist'))
				return

			# Remote
			LOG.info('Sending app to remote server for codesigning. Uploading may take some time.')
			
			# Zip up app
			with temp_file() as app_zip_file:
				if cache_file is None:
					with ZipFile(app_zip_file, 'w', compression=ZIP_DEFLATED) as app_zip:
						for root, dirs, files in os.walk(path_to_app, topdown=False):
							for file in files:
								app_zip.write(path.join(root, file), path.join(root[len(path_to_app):], file))
								os.remove(path.join(root, file))
							for dir in dirs:
								os.rmdir(path.join(root, dir))
				else:
					with ZipFile(app_zip_file, 'w', compression=ZIP_DEFLATED) as app_zip:
						app_zip.write(path.join(path_to_app, 'Forge'), 'Forge')
						app_zip.write(path.join(path_to_app, 'Info.plist'), 'Info.plist')
						app_zip.write(path_to_embedded_profile, 'embedded.mobileprovision')
						with temp_file() as tweaked_resource_rules:
							import biplist
							rules = biplist.readPlist(path.join(path_to_app, 'ResourceRules.plist'))
							# Don't sign anything
							rules['rules']['.*'] = False
							with open(tweaked_resource_rules, 'wb') as tweaked_resource_rules_file:
								biplist.writePlist(rules, tweaked_resource_rules_file)
							app_zip.write(tweaked_resource_rules, 'ResourceRules.plist')
								
							
				from poster.encode import multipart_encode
				from poster.streaminghttp import register_openers
				import urllib2

				class FileWithProgress:
					def __init__(self, path, flags):
						self.total_size = os.path.getsize(path)
						self.file = open(path, flags)
						self.name = self.file.name
						self.path = path
						self.amount_read = 0;
						self.last_progress = 0;
					def read(self, length):
						data = self.file.read(length)
						if data != "":
							self.amount_read = self.amount_read + len(data)
							# TODO: Nicer progress output
							progress = 10*self.amount_read/self.total_size
							if progress > self.last_progress:
								self.last_progress = progress
								LOG.info(str(10*progress) + " percent uploaded: "+self.path)
						else:
							self.file.close()
						return data
					def fileno(self):
						return self.file.fileno()
					def seek(self, pos):
						return self.file.seek(pos)

				files = {
					'app': FileWithProgress(app_zip_file, 'rb'),
					'entitlements': FileWithProgress(entitlements_file, 'rb'),
					'certificate': FileWithProgress(certificate_path, 'rb'),
					'password': certificate_password
				}

				# Register the streaming http handlers with urllib2
				register_openers()

				# headers contains the necessary Content-Type and Content-Length
				# datagen is a generator object that yields the encoded parameters
				datagen, headers = multipart_encode(files)

				# Create the Request object
				request = urllib2.Request("https://trigger.io/codesign/sign", datagen, headers)

				with temp_file() as signed_zip_file:
					resp = urllib2.urlopen(request)
					
					# Read the log lines from the start of the response
					while True:
						data = resp.readline()
						if data == "--failure\n":
							raise IOSError("Remote codesign failed")
						elif data == "--data\n" or data == "":
							break
						LOG.info(data.rstrip('\r\n'))
					
					# Read the binary data from the 2nd part of the response
					# TODO: Chunked download and progress
					with open(signed_zip_file, 'wb') as signed_zip:
						signed_zip.write(resp.read())

					# Unzip response
					zip_to_extract = ZipFile(signed_zip_file)
					zip_to_extract.extractall(path_to_app)
					zip_to_extract.close()

					# XXX: Caching currently disabled as Info.plist changes on every build
					"""if cache_file is not None:
						shutil.copy2(signed_zip_file, cache_file)"""
					LOG.info('Signed app received, continuing with packaging.')

		else:
			# Local
			codesign = self._check_for_codesign()
			resource_rules = path.abspath(path.join(path_to_app, 'ResourceRules.plist'))
			run_shell(codesign, '--force', '--preserve-metadata',
					'--entitlements', entitlements_file,
					'--sign', certificate,
					'--resource-rules={0}'.format(resource_rules),
					path_to_app)
	def run_iphone_device(self, build, device, provisioning_profile, certificate=None, certificate_path=None, certificate_password=None):

		path_to_app, app_folder_name = self._locate_device_app(build, "Couldn't find iOS app to run on a device")

		LOG.debug("Signing {app}".format(app=path_to_app))
		
		plist_str = self._grab_plist_from_binary_mess(build, provisioning_profile)
		plist_dict = self._parse_plist(plist_str)
		self.check_plist_dict(build, plist_dict, self.path_to_ios_build)
		self.provisioning_profile = plist_dict
		LOG.info("Plist OK")

		certificate = self._select_certificate(certificate)
		self.log_profile()
		
		if sys.platform.startswith('darwin'):
			with temp_file() as temp_file_path:
				self._create_entitlements_file(build, temp_file_path, plist_dict)
				
				self._sign_app(build=build,
					provisioning_profile=provisioning_profile,
					certificate=certificate,
					entitlements_file=temp_file_path,
					ident=_generate_package_name(build)
				)
			
			ios_deploy = [ensure_lib_available(build, 'ios-deploy'), '-d', '-u', '-t', '10', '-b', path_to_app]
			if device and device.lower() != 'device':
				# specific device given
				ios_deploy.append('-i')
				ios_deploy.append(device)
				LOG.info('Installing app on device {device}: is it connected?'.format(device=device))
			else:
				LOG.info('Installing app on device: is it connected?')

			def filter_and_combine(logline):
				return logline.rstrip()

			env = deepcopy(os.environ)

			run_shell(*ios_deploy, fail_silently=False, command_log_level=logging.INFO, filter=filter_and_combine, check_for_interrupt=True, env=env)
		elif sys.platform.startswith('win'):
			with temp_file() as ipa_path:
				self.create_ipa_from_app(
					build=build,
					provisioning_profile=provisioning_profile,
					output_path_for_ipa=ipa_path,
					certificate_path=certificate_path,
					certificate_password=certificate_password,
				)
				win_ios_install = [ensure_lib_available(build, 'win-ios-install.exe')]
				if device and device.lower() != 'device':
					# pacific device given
					win_ios_install.append(device)
					LOG.info('Installing app on device {device}: is it connected?'.format(device=device))
				else:
					LOG.info('Installing app on device: is it connected?')

				win_ios_install.append(ipa_path)
				win_ios_install.append(_generate_package_name(build))

				run_shell(*win_ios_install, fail_silently=False, command_log_level=logging.INFO, check_for_interrupt=True)
		else:
			if not which('ideviceinstaller'):
				raise Exception("Can't find ideviceinstaller - is it installed and on your PATH?")
			with temp_file() as ipa_path:
				self.create_ipa_from_app(
					build=build,
					provisioning_profile=provisioning_profile,
					output_path_for_ipa=ipa_path,
					certificate_path=certificate_path,
					certificate_password=certificate_password,
				)
				
				linux_ios_install = ['ideviceinstaller']
				
				if device and device.lower() != 'device':
					# pacific device given
					linux_ios_install.append('-U')
					linux_ios_install.append(device)
					LOG.info('Installing app on device {device}: is it connected?'.format(device=device))
				else:
					LOG.info('Installing app on device: is it connected?')
				
				linux_ios_install.append('-i')
				linux_ios_install.append(ipa_path)
				run_shell(*linux_ios_install, fail_silently=False,
					command_log_level=logging.INFO,
					check_for_interrupt=True)
				LOG.info('App installed, you will need to run the app on the device manually.')
Example #32
0
def run_osx(build):
	args = [os.path.join('development', 'osx', 'Forge.app', 'Contents', 'MacOS', 'ForgeInspector')]
	# Bring app to foreground after 1 second
	subprocess.Popen(["osascript", "-e", "delay 1", "-e", 'tell application "%s" to activate' % build.config['name']])
	run_shell(*args, command_log_level=logging.INFO, check_for_interrupt=True)
Example #33
0
    def run_idevice(self,
                    build,
                    device,
                    provisioning_profile,
                    certificate=None,
                    certificate_path=None,
                    certificate_password=None):
        possible_app_location = '{0}/ios/device-*/'.format(
            self.path_to_ios_build)
        LOG.debug('Looking for apps at {0}'.format(possible_app_location))
        possible_apps = glob(possible_app_location)
        if not possible_apps:
            raise IOSError("Couldn't find iOS app to run on a device")

        path_to_app = possible_apps[0]

        LOG.debug("Signing {app}".format(app=path_to_app))

        plist_str = self._grab_plist_from_binary_mess(build,
                                                      provisioning_profile)
        plist_dict = self._parse_plist(plist_str)
        self.check_plist_dict(plist_dict, self.path_to_ios_build)
        self.provisioning_profile = plist_dict
        LOG.info("Plist OK")

        certificate = self._select_certificate(certificate)
        self.log_profile()

        if sys.platform.startswith('darwin'):
            with temp_file() as temp_file_path:
                self._create_entitlements_file(build, temp_file_path,
                                               plist_dict)

                self._sign_app(build=build,
                               provisioning_profile=provisioning_profile,
                               certificate=certificate,
                               entitlements_file=temp_file_path,
                               ident=_generate_package_name(build))

            fruitstrap = [
                ensure_lib_available(build, 'fruitstrap'), '-d', '-u', '-t',
                '10', '-b', path_to_app
            ]
            if device and device.lower() != 'device':
                # pacific device given
                fruitstrap.append('-i')
                fruitstrap.append(device)
                LOG.info('Installing app on device {device}: is it connected?'.
                         format(device=device))
            else:
                LOG.info('Installing app on device: is it connected?')

            def filter_and_combine(logline):
                return logline.rstrip()

            ensure_lib_available(build, 'lldb_framework.zip', extract=True)

            env = deepcopy(os.environ)
            env['PATH'] = os.path.dirname(ensure_lib_available(
                build, 'lldb')) + ":" + env['PATH']

            run_shell(*fruitstrap,
                      fail_silently=False,
                      command_log_level=logging.INFO,
                      filter=filter_and_combine,
                      check_for_interrupt=True,
                      env=env)
        elif sys.platform.startswith('win'):
            with temp_file() as ipa_path:
                self.create_ipa_from_app(
                    build=build,
                    provisioning_profile=provisioning_profile,
                    output_path_for_ipa=ipa_path,
                    certificate_path=certificate_path,
                    certificate_password=certificate_password,
                )
                win_ios_install = [
                    ensure_lib_available(build, 'win-ios-install.exe')
                ]
                if device and device.lower() != 'device':
                    # pacific device given
                    win_ios_install.append(device)
                    LOG.info(
                        'Installing app on device {device}: is it connected?'.
                        format(device=device))
                else:
                    LOG.info('Installing app on device: is it connected?')

                win_ios_install.append(ipa_path)
                win_ios_install.append(_generate_package_name(build))

                run_shell(*win_ios_install,
                          fail_silently=False,
                          command_log_level=logging.INFO,
                          check_for_interrupt=True)
        else:
            if not which('ideviceinstaller'):
                raise Exception(
                    "Can't find ideviceinstaller - is it installed and on your PATH?"
                )
            with temp_file() as ipa_path:
                self.create_ipa_from_app(
                    build=build,
                    provisioning_profile=provisioning_profile,
                    output_path_for_ipa=ipa_path,
                    certificate_path=certificate_path,
                    certificate_password=certificate_password,
                )

                linux_ios_install = ['ideviceinstaller']

                if device and device.lower() != 'device':
                    # pacific device given
                    linux_ios_install.append('-U')
                    linux_ios_install.append(device)
                    LOG.info(
                        'Installing app on device {device}: is it connected?'.
                        format(device=device))
                else:
                    LOG.info('Installing app on device: is it connected?')

                linux_ios_install.append('-i')
                linux_ios_install.append(ipa_path)
                run_shell(*linux_ios_install,
                          fail_silently=False,
                          command_log_level=logging.INFO,
                          check_for_interrupt=True)
                LOG.info(
                    'App installed, you will need to run the app on the device manually.'
                )
def _have_android_8_available(path_info):
    targets = run_shell(path_info.android, 'list', 'targets', '-c').split('\n')
    return 'android-8' in targets