Пример #1
0
 def makedmg(self, d, volname, internet_enable=True):
     ''' Copy a directory d into a dmg named volname '''
     print('\nSigning...')
     sys.stdout.flush()
     destdir = OUTPUT_DIR
     try:
         shutil.rmtree(destdir)
     except EnvironmentError as err:
         if err.errno != errno.ENOENT:
             raise
     os.mkdir(destdir)
     dmg = join(destdir, volname + '.dmg')
     if os.path.exists(dmg):
         os.unlink(dmg)
     tdir = tempfile.mkdtemp()
     appdir = join(tdir, os.path.basename(d))
     shutil.copytree(d, appdir, symlinks=True)
     if self.sign_installers or self.notarize:
         with timeit() as times:
             sign_app(appdir, self.notarize)
         print('Signing completed in %d minutes %d seconds' % tuple(times))
     os.symlink('/Applications', join(tdir, 'Applications'))
     size_in_mb = int(
         subprocess.check_output(['du', '-s', '-k', tdir
                                  ]).decode('utf-8').split()[0]) / 1024.
     # UDBZ gives the best compression, better than ULFO
     cmd = [
         '/usr/bin/hdiutil', 'create', '-srcfolder', tdir, '-volname',
         volname, '-format', 'UDBZ'
     ]
     if 190 < size_in_mb < 250:
         # We need -size 255m because of a bug in hdiutil. When the size of
         # srcfolder is close to 200MB hdiutil fails with
         # diskimages-helper: resize request is above maximum size allowed.
         cmd += ['-size', '255m']
     print('\nCreating dmg...')
     with timeit() as times:
         subprocess.check_call(cmd + [dmg])
         if internet_enable:
             subprocess.check_call(
                 ['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
     print('dmg created in %d minutes and %d seconds' % tuple(times))
     shutil.rmtree(tdir)
     size = os.stat(dmg).st_size / (1024 * 1024.)
     print('\nInstaller size: %.2fMB\n' % size)
     return dmg
Пример #2
0
 def makedmg(self, d, volname, format='ULFO'):
     ''' Copy a directory d into a dmg named volname '''
     print('\nMaking dmg...')
     sys.stdout.flush()
     destdir = os.path.join(SW, 'dist')
     try:
         shutil.rmtree(destdir)
     except FileNotFoundError:
         pass
     os.mkdir(destdir)
     dmg = os.path.join(destdir, volname + '.dmg')
     if os.path.exists(dmg):
         os.unlink(dmg)
     tdir = tempfile.mkdtemp()
     appdir = os.path.join(tdir, os.path.basename(d))
     shutil.copytree(d, appdir, symlinks=True)
     if self.sign_installers:
         with timeit() as times:
             sign_app(appdir, self.notarize)
         print('Signing completed in %d minutes %d seconds' % tuple(times))
     os.symlink('/Applications', os.path.join(tdir, 'Applications'))
     size_in_mb = int(
         subprocess.check_output(['du', '-s', '-k', tdir
                                  ]).decode('utf-8').split()[0]) / 1024.
     cmd = [
         '/usr/bin/hdiutil', 'create', '-srcfolder', tdir, '-volname',
         volname, '-format', format
     ]
     if 190 < size_in_mb < 250:
         # We need -size 255m because of a bug in hdiutil. When the size of
         # srcfolder is close to 200MB hdiutil fails with
         # diskimages-helper: resize request is above maximum size allowed.
         cmd += ['-size', '255m']
     print('\nCreating dmg...')
     with timeit() as times:
         subprocess.check_call(cmd + [dmg])
     print('dmg created in %d minutes and %d seconds' % tuple(times))
     shutil.rmtree(tdir)
     size = os.stat(dmg).st_size / (1024 * 1024.)
     print('\nInstaller size: %.2fMB\n' % size)
     return dmg
Пример #3
0
def notarize_app(app_path):
    # See
    # https://developer.apple.com/documentation/xcode/notarizing_your_app_before_distribution/customizing_the_notarization_workflow?language=objc
    # and
    # https://developer.apple.com/documentation/xcode/notarizing_your_app_before_distribution/resolving_common_notarization_issues?language=objc
    with open(APPLE_ID) as f:
        un, pw = f.read().strip().split(':')

    with open(os.path.join(app_path, 'Contents', 'Info.plist'), 'rb') as f:
        primary_bundle_id = plistlib.load(f)['CFBundleIdentifier']

    zip_path = os.path.join(os.path.dirname(app_path), 'calibre.zip')
    print('Creating zip file for notarization')
    with timeit() as times:
        run('ditto', '-c', '-k', '--zlibCompressionLevel', '9', '--keepParent',
            app_path, zip_path)
    print('ZIP file of {} MB created in {} minutes and {} seconds'.format(
        os.path.getsize(zip_path) // 1024**2, *times))

    def altool(*args):
        args = ['xcrun', 'altool'
                ] + list(args) + ['--username', un, '--password', pw]
        p = subprocess.Popen(args,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
        stdout = stdout.decode('utf-8')
        stderr = stderr.decode('utf-8')
        output = stdout + '\n' + stderr
        print(output)
        if p.wait() != 0:
            print('The command {} failed with error code: {}'.format(
                args, p.returncode))
            try:
                run_shell()
            finally:
                raise SystemExit(1)
        return output

    print('Submitting for notarization')
    with timeit() as times:
        try:
            stdout = altool('--notarize-app', '-f', zip_path,
                            '--primary-bundle-id', primary_bundle_id)
        finally:
            os.remove(zip_path)
        request_id = re.search(r'RequestUUID = (\S+)', stdout).group(1)
        status = 'in progress'
    print('Submission done in {} minutes and {} seconds'.format(*times))

    print('Waiting for notarization')
    with timeit() as times:
        start_time = time.monotonic()
        while status == 'in progress':
            time.sleep(30)
            print(
                'Checking if notarization is complete, time elapsed: {:.1f} seconds',
                time.monotonic() - start_time)
            stdout = altool('--notarization-info', request_id)
            status = re.search(r'Status\s*:\s+(.+)', stdout).group(1).strip()
    print('Notarization done in {} minutes and {} seconds'.format(*times))

    if status.lower() != 'success':
        log_url = re.search(r'LogFileURL\s*:\s+(.+)', stdout).group(1).strip()
        if log_url != '(null)':
            log = json.loads(urlopen(log_url).read())
            pprint(log)
        raise SystemExit('Notarization failed, see JSON log above')
    with timeit() as times:
        print('Stapling notarization ticket')
        run('xcrun', 'stapler', 'staple', '-v', app_path)
        run('xcrun', 'stapler', 'validate', '-v', app_path)
        run('spctl', '--verbose=4', '--assess', '--type', 'execute', app_path)
    print('Stapling took {} minutes and {} seconds'.format(*times))