Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package seafile for openSUSE:Factory checked in at 2021-06-29 22:42:49
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/seafile (Old)
and /work/SRC/openSUSE:Factory/.seafile.new.2625 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "seafile"
Tue Jun 29 22:42:49 2021 rev:8 rq:902681 version:8.0.3
Changes:
--------
--- /work/SRC/openSUSE:Factory/seafile/seafile.changes 2021-06-01 10:38:55.188961990 +0200
+++ /work/SRC/openSUSE:Factory/.seafile.new.2625/seafile.changes 2021-06-29 22:42:51.710842130 +0200
@@ -1,0 +2,5 @@
+Sun Jun 27 19:06:20 UTC 2021 - Christophe Giboudeaux
+
+- Update to 8.0.3. No changelog.
+
+-------------------------------------------------------------------
Old:
----
v8.0.2.tar.gz
New:
----
v8.0.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ seafile.spec ++++++
--- /var/tmp/diff_new_pack.WuYJYC/_old 2021-06-29 22:42:52.286842890 +0200
+++ /var/tmp/diff_new_pack.WuYJYC/_new 2021-06-29 22:42:52.290842895 +0200
@@ -17,7 +17,7 @@
Name: seafile
-Version: 8.0.2
+Version: 8.0.3
Release: 0
Summary: Cloud storage client
License: GPL-2.0-only
++++++ v8.0.2.tar.gz -> v8.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/common/fs-mgr.c new/seafile-8.0.3/common/fs-mgr.c
--- old/seafile-8.0.2/common/fs-mgr.c 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/common/fs-mgr.c 2021-06-24 08:03:18.000000000 +0200
@@ -390,6 +390,16 @@
seaf_warning ("Failed to rename %s to %s: %s. "
"Failed to move backup file to conflict file.\n",
backup_path, conflict_path, strerror(errno));
+ if (mtime > 0) {
+ /*
+ * Set the checked out file mtime to what it has to be.
+ */
+ if (seaf_set_file_time (file_path, mtime) < 0) {
+ seaf_warning ("Failed to set mtime for %s.\n", file_path);
+ }
+ }
+ //Don't delete local file when failed to rename backup file to conflict file.
+ goto out;
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/configure.ac new/seafile-8.0.3/configure.ac
--- old/seafile-8.0.2/configure.ac 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/configure.ac 2021-06-24 08:03:18.000000000 +0200
@@ -2,7 +2,7 @@
AC_PREREQ(2.61)
-AC_INIT([seafile], [8.0.2], [info@seafile.com])
+AC_INIT([seafile], [8.0.3], [info@seafile.com])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/daemon/http-tx-mgr.c new/seafile-8.0.3/daemon/http-tx-mgr.c
--- old/seafile-8.0.2/daemon/http-tx-mgr.c 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/daemon/http-tx-mgr.c 2021-06-24 08:03:18.000000000 +0200
@@ -38,10 +38,12 @@
#define HTTP_OK 200
#define HTTP_BAD_REQUEST 400
+#define HTTP_REQUEST_TIME_OUT 408
#define HTTP_FORBIDDEN 403
#define HTTP_NOT_FOUND 404
#define HTTP_NO_QUOTA 443
#define HTTP_REPO_DELETED 444
+#define HTTP_REPO_TOO_LARGE 447
#define HTTP_REPO_CORRUPTED 445
#define HTTP_INTERNAL_SERVER_ERROR 500
@@ -1089,6 +1091,8 @@
return SYNC_ERROR_ID_SERVER_REPO_DELETED;
else if (status == HTTP_REPO_CORRUPTED)
return SYNC_ERROR_ID_SERVER_REPO_CORRUPT;
+ else if (status == HTTP_REPO_TOO_LARGE || status == HTTP_REQUEST_TIME_OUT)
+ return SYNC_ERROR_ID_LIBRARY_TOO_LARGE;
else
return SYNC_ERROR_ID_GENERAL_ERROR;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/daemon/seafile-error.c new/seafile-8.0.3/daemon/seafile-error.c
--- old/seafile-8.0.2/daemon/seafile-error.c 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/daemon/seafile-error.c 2021-06-24 08:03:18.000000000 +0200
@@ -169,6 +169,11 @@
SYNC_ERROR_LEVEL_FILE,
"File or directory is invalid on Windows"
},
+ {
+ SYNC_ERROR_ID_LIBRARY_TOO_LARGE,
+ SYNC_ERROR_LEVEL_REPO,
+ "Library is too large to sync"
+ },
};
const char *
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/debian/changelog new/seafile-8.0.3/debian/changelog
--- old/seafile-8.0.2/debian/changelog 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/debian/changelog 2021-06-24 08:03:18.000000000 +0200
@@ -1,3 +1,8 @@
+seafile-daemon (8.0.3) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu Tue, 24 Jun 2021 11:26:24 +0800
seafile-daemon (8.0.2) unstable; urgency=low
* new upstream release
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/include/seafile-error.h new/seafile-8.0.3/include/seafile-error.h
--- old/seafile-8.0.2/include/seafile-error.h 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/include/seafile-error.h 2021-06-24 08:03:18.000000000 +0200
@@ -61,6 +61,7 @@
#define SYNC_ERROR_ID_NO_ERROR 29
#define SYNC_ERROR_ID_REMOVE_UNCOMMITTED_FOLDER 30
#define SYNC_ERROR_ID_INVALID_PATH_ON_WINDOWS 31
-#define N_SYNC_ERROR_ID 32
+#define SYNC_ERROR_ID_LIBRARY_TOO_LARGE 32
+#define N_SYNC_ERROR_ID 33
#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/msi/Includes.wxi new/seafile-8.0.3/msi/Includes.wxi
--- old/seafile-8.0.2/msi/Includes.wxi 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/msi/Includes.wxi 2021-06-24 08:03:18.000000000 +0200
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Include Id="SeafileInclude">
- <?define CurrentSeafileVersion="8.0.2" ?>
+ <?define CurrentSeafileVersion="8.0.3" ?>
<!-- Update Guid ��������� -->
<?define CurrentUpdateGuid="65DED1C8-A5F1-4C49-8E7E-B0A8A5A6535C" ?>
@@ -145,7 +145,8 @@
<!-- <?define ProductGuid="D21D1108-878F-43D9-A3A2-39F4B38A5694" ?> (7.0.10) -->
<!-- <?define ProductGuid="CE032912-6DCF-4C5F-A447-AC303D0530A7" ?> (8.0.0) -->
<!-- <?define ProductGuid="93B20E38-EFF9-4CD8-BFF4-F0DF21DEADB8" ?> (8.0.1) -->
- <?define ProductGuid="8F8A6FBA-EAD1-4B16-B074-03C1BA4E1109" ?>
+ <!-- <?define ProductGuid="8F8A6FBA-EAD1-4B16-B074-03C1BA4E1109" ?> (8.0.2) -->
+ <?define ProductGuid="82A1C721-6B4E-473B-B515-8D0B9242C6A6" ?>
<?define GuidOfCustomComponent="AD201805-3CBD-4834-9097-5D934F7E0000" ?>
<?define GuidOfAutoStartComponent="AD201805-3CBD-4834-9097-5D934F7E0001" ?>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/scripts/build/build-mac-local.py new/seafile-8.0.3/scripts/build/build-mac-local.py
--- old/seafile-8.0.2/scripts/build/build-mac-local.py 1970-01-01 01:00:00.000000000 +0100
+++ new/seafile-8.0.3/scripts/build/build-mac-local.py 2021-06-24 08:03:18.000000000 +0200
@@ -0,0 +1,884 @@
+#!/usr/bin/env python
+# coding: UTF-8
+
+'''This script builds the seafile mac client.
+'''
+
+import atexit
+import logging
+import commands
+from contextlib import contextmanager
+import glob
+import multiprocessing
+import optparse
+import os
+from os.path import abspath, basename, dirname, join, exists, expanduser
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+FINAL_APP = 'Seafile Client.app'
+FSPLUGIN_APPEX_NAME = 'Seafile FinderSync.appex'
+CERT_ID = '79AB1AF435DD2CBC5FDB3EBBD45B0DA17727B299'
+
+BUILDDIR = join(os.getcwd(), "../../../")
+
+####################
+### Requires Python 2.6+
+####################
+if sys.version_info[0] == 3:
+ print 'Python 3 not supported yet. Quit now.'
+ sys.exit(1)
+if sys.version_info[1] < 6:
+ print 'Python 2.6 or above is required. Quit now.'
+ sys.exit(1)
+
+####################
+### Global variables
+####################
+# command line configuartion
+conf = {}
+
+# key names in the conf dictionary.
+# pylint: disable=bad-whitespace
+CONF_VERSION = 'version'
+CONF_NO_STRIP = 'nostrip'
+CONF_BRAND = 'brand'
+
+NUM_CPU = multiprocessing.cpu_count()
+PID = os.getpid()
+
+####################
+### Common helper functions
+####################
+def highlight(content, is_error=False):
+ '''Add ANSI color to content to get it highlighted on terminal'''
+ if is_error:
+ return '\x1b[1;31m%s\x1b[m' % content
+ else:
+ return '\x1b[1;32m%s\x1b[m' % content
+
+def info(msg):
+ logging.info(highlight('[INFO][{}] ').format(msg))
+
+@contextmanager
+def cd(path):
+ oldpwd = os.getcwd()
+ os.chdir(path)
+ try:
+ yield
+ finally:
+ os.chdir(oldpwd)
+
+def exist_in_path(prog):
+ '''Test whether prog exists in system path'''
+ return bool(find_in_path(prog))
+
+def prepend_env_value(name, value, seperator=':'):
+ '''append a new value to a list'''
+ try:
+ current_value = os.environ[name]
+ except KeyError:
+ current_value = ''
+
+ new_value = value
+ if current_value:
+ new_value += seperator + current_value
+
+ os.environ[name] = new_value
+
+def find_in_path(prog):
+ '''Find a file in system path'''
+ dirs = os.environ['PATH'].split(':')
+ for d in dirs:
+ if d == '':
+ continue
+ path = join(d, prog)
+ if exists(path):
+ return path
+
+ return None
+
+def error(msg=None, usage=None):
+ if msg:
+ print highlight('[ERROR] ') + msg
+ if usage:
+ print usage
+ sys.exit(1)
+
+def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False):
+ '''Run a program and wait it to finish, and return its exit code. The
+ standard output of this program is supressed.
+
+ '''
+ info('running %s, cwd=%s' % (' '.join(['"{}"'.format(a) for a in argv]), cwd or os.getcwd()))
+ with open(os.devnull, 'w') as devnull:
+ if suppress_stdout:
+ stdout = devnull
+ else:
+ stdout = sys.stdout
+
+ if suppress_stderr:
+ stderr = devnull
+ else:
+ stderr = sys.stderr
+
+ proc = subprocess.Popen(argv,
+ cwd=cwd,
+ stdout=stdout,
+ stderr=stderr,
+ env=env)
+ return proc.wait()
+
+def run(cmdline, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False):
+ '''Like run_argv but specify a command line string instead of argv'''
+ info('running %s, cwd=%s' % (cmdline, cwd or os.getcwd()))
+ with open(os.devnull, 'w') as devnull:
+ if suppress_stdout:
+ stdout = devnull
+ else:
+ stdout = sys.stdout
+
+ if suppress_stderr:
+ stderr = devnull
+ else:
+ stderr = sys.stderr
+
+ proc = subprocess.Popen(cmdline,
+ cwd=cwd,
+ stdout=stdout,
+ stderr=stderr,
+ env=env,
+ shell=True)
+ return proc.wait()
+
+def must_run(cmdline, *a, **kw):
+ ret = run(cmdline, *a, **kw)
+ if ret != 0:
+ error('failed to run %s' % cmdline)
+
+def check_remove(path):
+ """
+ Remove the file/dir specified by `path`, if exists.
+ """
+ path = abspath(path)
+ assert path.count('/') >= 2
+ if exists(path):
+ is_dir = os.path.isdir(path)
+ info('removing {} {}'.format('dir' if is_dir else 'file', path))
+ if is_dir:
+ shutil.rmtree(path)
+ else:
+ os.unlink(path)
+
+def must_mkdir(path):
+ '''Create a directory, exit on failure'''
+ try:
+ if not exists(path):
+ os.mkdir(path)
+ except OSError, e:
+ error('failed to create directory %s:%s' % (path, e))
+
+def must_copy(src, dst):
+ '''Copy src to dst, exit on failure'''
+ try:
+ shutil.copy(src, dst)
+ except Exception, e:
+ error('failed to copy %s to %s: %s' % (src, dst, e))
+
+def must_copytree(src, dst):
+ '''Copy src tree to dst, exit on failure'''
+ try:
+ shutil.copytree(src, dst)
+ except Exception, e:
+ error('failed to copy %s to %s: %s' % (src, dst, e))
+
+def check_project_version(version):
+ '''A valid version must be like 1.2.2, 1.3'''
+ if not re.match(r'^[0-9]+(\.[0-9]+)+$', version):
+ error('%s is not a valid version' % version, usage="build-mac-local.py 8.0.0")
+
+def check_cmd_para():
+ args = sys.argv
+ if len(args) != 2:
+ error('The number of parameters is incorrect', usage="build-mac-local.py 8.0.0")
+ global version
+ version = args[1]
+ check_project_version(version)
+
+
+class Project(object):
+ '''Base class for a project'''
+ # Probject name, i.e. libseaprc/seafile/
+ name = ''
+
+ # A list of shell commands to configure/build the project
+ build_commands = []
+
+ def __init__(self):
+ # the path to pass to --prefix=/<prefix>
+ self.prefix = join(BUILDDIR, 'usr')
+ # project dir, like <builddir>/seafile/
+ self.projdir = join(BUILDDIR, '{}' .format(self.name))
+
+ def get_version(self):
+ # libsearpc can have different versions from seafile.
+ raise NotImplementedError
+
+ def get_source_commit_id(self):
+ '''By convetion, we record the commit id of the source code in the
+ file "<projdir>/latest_commit"
+
+ '''
+ latest_commit_file = join(self.projdir, 'latest_commit')
+ with open(latest_commit_file, 'r') as fp:
+ commit_id = fp.read().strip('\n\r\t ')
+
+ return commit_id
+
+ def append_cflags(self, macros):
+ cflags = ' '.join(['-D%s=%s' % (k, macros[k]) for k in macros])
+ prepend_env_value('CPPFLAGS',
+ cflags,
+ seperator=' ')
+
+ def before_build(self):
+ '''Hook method to do project-specific stuff before running build commands'''
+ pass
+
+ def build(self):
+ '''Build the source'''
+ self.before_build()
+ info('Building %s' % self.name)
+ for cmd in self.build_commands:
+ if run(cmd, cwd=self.projdir) != 0:
+ error('error when running command:\n\t%s\n' % cmd)
+
+def concurrent_make():
+ return 'make -j%s' % NUM_CPU
+
+class Libsearpc(Project):
+ name = 'libsearpc'
+
+ def __init__(self):
+ Project.__init__(self)
+ self.build_commands = [
+ './autogen.sh',
+ './configure --prefix=%s --disable-compile-demo' % self.prefix,
+ concurrent_make(),
+ 'make install'
+ ]
+
+class Seafile(Project):
+ name = 'seafile'
+ def __init__(self):
+ Project.__init__(self)
+ self.build_commands = [
+ './autogen.sh',
+ './configure --prefix=%s --disable-fuse' % self.prefix,
+ concurrent_make(),
+ 'make install'
+ ]
+
+ def update_cli_version(self):
+ '''Substitute the version number in seaf-cli'''
+ cli_py = join(self.projdir, 'app', 'seaf-cli')
+ with open(cli_py, 'r') as fp:
+ lines = fp.readlines()
+
+ ret = []
+ for line in lines:
+ old = '''SEAF_CLI_VERSION = ""'''
+ new = '''SEAF_CLI_VERSION = "%s"''' %conf[CONF_VERSION]
+ line = line.replace(old, new)
+ ret.append(line)
+
+ with open(cli_py, 'w') as fp:
+ fp.writelines(ret)
+
+ def before_build(self):
+ self.update_cli_version()
+ macros = {}
+ # SET SEAFILE_SOURCE_COMMIT_ID, so it can be printed in the log
+ # macros['SEAFILE_SOURCE_COMMIT_ID'] = '\\"%s\\"' % self.get_source_commit_id()
+ # self.append_cflags(macros)
+
+class SeafileClient(Project):
+
+ name = 'seafile-client'
+
+ def __init__(self):
+ Project.__init__(self)
+ cmake_defines = {
+ 'CMAKE_OSX_ARCHITECTURES': 'x86_64',
+ 'CMAKE_OSX_DEPLOYMENT_TARGET': '10.9',
+ 'CMAKE_BUILD_TYPE': 'Release',
+ 'BUILD_SHIBBOLETH_SUPPORT': 'ON',
+ 'BUILD_SPARKLE_SUPPORT': 'ON',
+ }
+ cmake_defines_formatted = ' '.join(['-D{}={}'.format(k, v) for k, v in cmake_defines.iteritems()])
+ self.build_commands = [
+ 'rm -f CMakeCache.txt',
+ 'cmake -GXcode {}'.format(cmake_defines_formatted),
+ 'xcodebuild -target seafile-applet -configuration Release -jobs {}'.format(NUM_CPU),
+ 'rm -rf seafile-applet.app',
+ 'cp -r Release/seafile-applet.app seafile-applet.app',
+ 'mkdir -p seafile-applet.app/Contents/Frameworks',
+ 'macdeployqt seafile-applet.app',
+ ]
+
+ def before_build(self):
+ pass
+
+class SeafileDMGLayout(Seafile):
+
+ def __init__(self):
+ Seafile.__init__(self)
+ self.build_commands = [
+ ]
+
+class SeafileFinderSyncPlugin(SeafileClient):
+
+ def __init__(self):
+ SeafileClient.__init__(self)
+ self.build_commands = [
+ 'fsplugin/build.sh'
+ ]
+
+def prepare_builddir(builddir):
+ must_mkdir(builddir)
+
+ # if not conf[CONF_KEEP]:
+ # def remove_builddir():
+ # '''Remove the builddir when exit'''
+ # info('remove builddir before exit')
+ # shutil.rmtree(builddir, ignore_errors=True)
+ # atexit.register(remove_builddir)
+
+ os.chdir(builddir)
+
+ must_mkdir(join(builddir, 'usr'))
+
+def parse_args():
+ parser = optparse.OptionParser()
+ def long_opt(opt):
+ return '--' + opt
+
+ parser.add_option(long_opt(CONF_VERSION),
+ dest=CONF_VERSION,
+ nargs=1,
+ help='the version to build. Must be digits delimited by dots, like 1.3.0')
+
+ parser.add_option(long_opt(CONF_NO_STRIP),
+ dest=CONF_NO_STRIP,
+ action='store_true',
+ help='''do not strip debug symbols''')
+
+ parser.add_option(long_opt(CONF_BRAND),
+ dest=CONF_BRAND,
+ help='the brand')
+
+ usage = parser.format_help()
+ options, remain = parser.parse_args()
+ if remain:
+ error(usage=usage)
+
+ validate_args(usage, options)
+
+def validate_args(usage, options):
+ required_args = [
+ CONF_VERSION,
+ CONF_NO_STRIP,
+ CONF_BRAND,
+ ]
+
+ # fist check required args
+ for optname in required_args:
+ if getattr(options, optname, None) is None:
+ error('%s must be specified' % optname, usage=usage)
+
+ def get_option(optname):
+ return getattr(options, optname)
+
+ # [ version ]
+ def check_project_version(version):
+ '''A valid version must be like 1.2.2, 1.3'''
+ if not re.match(r'^[0-9]+(\.[0-9]+)+$', version):
+ error('%s is not a valid version' % version, usage=usage)
+
+ version = get_option(CONF_VERSION)
+ check_project_version(version)
+
+ # [ no strip]
+ nostrip = get_option(CONF_NO_STRIP)
+
+ brand = get_option(CONF_BRAND)
+
+ conf[CONF_VERSION] = version
+ conf[CONF_NO_STRIP] = nostrip
+ conf[CONF_BRAND] = brand
+
+def setup_build_env():
+ '''Setup environment variables, such as export PATH=$BUILDDDIR/bin:$PATH'''
+ # os.environ.update({
+ # })
+ prefix = join(BUILDDIR, 'usr')
+
+ prepend_env_value('CFLAGS',
+ '-Wall -O2 -g -DNDEBUG -I/opt/local/include -mmacosx-version-min=10.7',
+ seperator=' ')
+
+ prepend_env_value('CXXFLAGS',
+ '-Wall -O2 -g -DNDEBUG -I/opt/local/include -mmacosx-version-min=10.7',
+ seperator=' ')
+
+ prepend_env_value('CPPFLAGS',
+ '-I%s' % join(prefix, 'include'),
+ seperator=' ')
+
+ prepend_env_value('CPPFLAGS',
+ '-DSEAFILE_CLIENT_VERSION=\\"%s\\"' % conf[CONF_VERSION],
+ seperator=' ')
+
+ if conf[CONF_NO_STRIP]:
+ prepend_env_value('CPPFLAGS',
+ '-g -O0',
+ seperator=' ')
+
+ prepend_env_value('LDFLAGS',
+ '-L%s' % join(prefix, 'lib'),
+ seperator=' ')
+
+ prepend_env_value('LDFLAGS',
+ '-L%s' % join(prefix, 'lib64'),
+ seperator=' ')
+
+ prepend_env_value('LDFLAGS',
+ '-L/opt/local/lib -Wl,-headerpad_max_install_names -mmacosx-version-min=10.7',
+ seperator=' ')
+
+ prepend_env_value('PATH', join(prefix, 'bin'))
+ prepend_env_value('PKG_CONFIG_PATH', join(prefix, 'lib', 'pkgconfig'))
+ prepend_env_value('PKG_CONFIG_PATH', join(prefix, 'lib64', 'pkgconfig'))
+
+path_pattern = re.compile(r'^\s+(\S+)\s+\(compatibility.*')
+def get_dependent_libs(executable):
+ def is_syslib(lib):
+ if lib.startswith('/usr/lib'):
+ return True
+ if lib.startswith('/System/'):
+ return True
+ return False
+
+ otool_output = commands.getoutput('otool -L %s' % executable)
+ libs = set()
+ for line in otool_output.splitlines():
+ m = path_pattern.match(line)
+ if not m:
+ continue
+ path = m.group(1)
+ if not is_syslib(path):
+ libs.add(path)
+ return libs
+
+def copy_shared_libs():
+ '''copy shared c libs, such as libevent, glib'''
+ builddir = BUILDDIR
+ frameworks_dir = join(SeafileClient().projdir, 'seafile-applet.app/Contents/Frameworks')
+
+ must_mkdir(frameworks_dir)
+ seafile_path = join(builddir, 'usr/bin/seaf-daemon')
+
+ libs = set()
+ libs.update(get_dependent_libs(seafile_path))
+
+ # Get deps of deps recursively until no more deps can be included
+ while True:
+ newlibs = set(libs)
+ for lib in libs:
+ newlibs.update(get_dependent_libs(lib))
+ if newlibs == libs:
+ break
+ libs = newlibs
+
+ for lib in libs:
+ dst_file = join(frameworks_dir, basename(lib))
+ if exists(dst_file):
+ continue
+ info('Copying %s' % lib)
+ shutil.copy(lib, frameworks_dir)
+
+ change_rpaths()
+
+def change_rpaths():
+ """
+ Chagne the rpath of the referenced dylibs so the app can be relocated
+ anywhere in the user's system.
+ See:
+ - https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac
+ - https://developer.apple.com/library/content/documentation/DeveloperTools/Con...
+ """
+ contents_dir = join(SeafileClient().projdir, 'seafile-applet.app/Contents')
+ frameworks_dir = join(contents_dir, 'Frameworks')
+ resources_dir = join(contents_dir, 'Resources')
+ macos_dir = join(contents_dir, 'MacOS')
+
+ seafile_applet = join(macos_dir, 'seafile-applet')
+ binaries = [
+ seafile_applet,
+ join(resources_dir, 'seaf-daemon')
+ ]
+
+ RPATH_RE = re.compile(r'^path\s+(\S+)\s+\(offset .*$')
+ def get_rpaths(fn):
+ rpaths = []
+ output = commands.getoutput('otool -l {} | grep -A2 RPATH || true'.format(fn))
+ # The output is like
+ # cmd LC_RPATH
+ # cmdsize 24
+ # path /usr/local (offset 12)
+ # --
+ # cmd LC_RPATH
+ # cmdsize 48
+ # path @executable_path/../Frameworks (offset 12)
+ for line in output.splitlines():
+ m = RPATH_RE.match(line.strip())
+ if m:
+ rpaths.append(m.group(1))
+ return rpaths
+
+ def has_rpath(fn, path):
+ return path in get_rpaths(fn)
+
+ def add_frameworks_dir_to_rpath(fn, executable=True):
+ relpath = 'executable_path' if executable else 'loader_path'
+ relative_frameworks_dir = '@{}/../Frameworks'.format(relpath)
+ if not has_rpath(fn, relative_frameworks_dir):
+ must_run('install_name_tool -add_rpath {} {}' .format(relative_frameworks_dir, fn))
+
+ def remove_local_rpaths(fn):
+ local_paths = ['/usr/local/lib', '/opt/local/lib']
+ for path in local_paths:
+ if has_rpath(fn, path):
+ must_run('install_name_tool -delete_rpath {} {}'.format(path, fn))
+
+ def change_deps_rpath(fn):
+ deps = get_dependent_libs(fn)
+ for dep in deps:
+ bn = basename(dep)
+ if 'framework' in bn or bn.startswith('Qt') or bn == 'Sparkle':
+ continue
+ must_run('install_name_tool -change {} @rpath/{} {}'.format(dep, basename(dep), fn))
+
+ for binary in binaries:
+ add_frameworks_dir_to_rpath(binary)
+ remove_local_rpaths(binary)
+ change_deps_rpath(binary)
+
+ libs = os.listdir(frameworks_dir)
+ for lib_name in libs:
+ lib = join(frameworks_dir, lib_name)
+ if os.path.isdir(lib):
+ continue
+ must_run('install_name_tool -id @rpath/{} {}'.format(basename(lib), lib))
+ add_frameworks_dir_to_rpath(lib, executable=False)
+ change_deps_rpath(lib)
+ remove_local_rpaths(lib)
+
+DROPDMG = '/Applications/DropDMG.app/Contents/Frameworks/DropDMGFramework.framework/Versions/A/dropdmg'
+
+def gen_dmg():
+ output_dmg = 'app-{}.dmg'.format(conf[CONF_VERSION])
+ parentdir = 'app-{}'.format(conf[CONF_VERSION])
+ appdir = join(parentdir, 'seafile-applet.app')
+ app_plugins_dir = join(appdir, 'Contents/PlugIns')
+
+ layout = SeafileDMGLayout()
+ layout_folder = join(layout.projdir, 'dmg/seafileLayout')
+
+ args = [
+ DROPDMG,
+ parentdir,
+ '--format', 'bzip2',
+ '--layout-folder', layout_folder,
+ '--volume-name', conf[CONF_BRAND] or 'Seafile Client',
+ ]
+
+ with cd(BUILDDIR):
+ check_remove(parentdir)
+ check_remove(output_dmg)
+ must_mkdir(parentdir)
+ must_run('tar xf seafile-applet.app.tar.gz -C {}'.format(parentdir))
+ # Remove the Qt Bearer plugin because it would run a background thread
+ # to scan wifi networks. See
+ # https://trello.com/c/j28eOIo1/359-explicitly-exclude-qt-bearer-plugins-for-t...
+ # for details.
+ must_run('rm -rf "{}"'.format(join(app_plugins_dir, 'bearer')))
+ # fsplugin must be copied before we sign the final .app dir
+ copy_fsplugin(app_plugins_dir)
+ sign_files(appdir)
+
+ # Rename the .app dir to 'Seafile Client.app', and create the shortcut
+ # to '/Applications' so the user can drag into it when opening the DMG.
+ brand = conf.get('CONF_BRAND')
+ if brand:
+ final_app = '{}.app'.format(brand)
+ else:
+ final_app = FINAL_APP
+ must_run('mv {}/seafile-applet.app "{}/{}"'.format(parentdir, parentdir, final_app))
+ must_run('ln -sf /Applications {}/'.format(parentdir))
+
+ # Open DropDMG manually, or dropdmg command line may fail.
+ run(''' osascript -e 'tell application "DropDMG" to quit' || true ''')
+ run(''' osascript -e 'open application "DropDMG"' || true ''')
+ run(''' osascript -e 'activate application "DropDMG"' || true ''')
+
+ # Sometimes DropDmg would fail if there are two many Finder windows.
+ run(''' osascript -e 'tell application "Finder" to close every window' ''')
+ if run_argv(args) != 0:
+ error('failed to run {}'.format(args))
+
+def sign_in_parallel(files_to_sign):
+ import threading
+ import Queue
+ queue = Queue.Queue()
+ POISON_PILL = ''
+
+ class SignThread(threading.Thread):
+ def __init__(self, index):
+ threading.Thread.__init__(self)
+ self.index = index
+
+ def run(self):
+ info('sign thread {} started'.format(self.index))
+ while True:
+ try:
+ fn = queue.get(timeout=1)
+ except Queue.Empty:
+ continue
+ else:
+ if fn == POISON_PILL:
+ break
+ else:
+ do_sign(fn)
+ info('sign thread {} stopped'.format(self.index))
+
+ TOTAL_THREADS = max(NUM_CPU / 2, 1)
+ threads = []
+ for i in xrange(TOTAL_THREADS):
+ t = SignThread(i)
+ t.start()
+ threads.append(t)
+
+ for fn in files_to_sign:
+ queue.put(fn)
+
+ for _ in xrange(TOTAL_THREADS):
+ queue.put(POISON_PILL)
+
+ for i in xrange(TOTAL_THREADS):
+ threads[i].join()
+
+def sign_files(appdir):
+ webengine_app = join(
+ appdir,
+ 'Contents/Frameworks/QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app'
+ )
+
+ def _glob(pattern, *a, **kw):
+ return glob.glob(join(appdir, pattern), *a, **kw)
+
+ # The webengine app must be signed first, otherwise the sign of
+ # QtWebengineCore.framework would fail.
+ if exists(webengine_app):
+ entitlements = join(Seafile().projdir, 'scripts/build/osx.entitlements')
+ do_sign(
+ webengine_app,
+ extra_args=['--entitlements', entitlements]
+ )
+
+ # Strip the get-task-allow entitlements for Sparkle binaries
+ for fn in _glob('Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app/Contents/MacOS/*'):
+ do_sign(fn, preserve_entitlemenets=False)
+
+ # Sign the nested contents of Sparkle before we sign
+ # Sparkle.Framework in the thread pool.
+ for fn in (
+ 'Contents/Frameworks/Sparkle.framework/Versions/A/Resources/Autoupdate.app',
+ 'Contents/Frameworks/Sparkle.framework/Versions/A/Sparkle',
+ ):
+ do_sign(join(appdir, fn))
+
+ patterns = [
+ 'Contents/Frameworks/*.framework',
+ 'Contents/PlugIns/*/*.dylib',
+ 'Contents/Frameworks/*.dylib',
+ 'Contents/Resources/seaf-daemon',
+ 'Contents/MacOS/seadrive-gui',
+ ]
+
+ files_to_sign = []
+ for p in patterns:
+ files_to_sign.extend(_glob(p))
+
+ info('{} files to sign'.format(len(files_to_sign)))
+
+ sign_in_parallel(files_to_sign)
+ # for fn in files_to_sign:
+ # do_sign(fn)
+
+ do_sign(appdir)
+ # do_sign(appdir, extra_args=['--deep'])
+
+_keychain_unlocked = False
+def unlock_keychain():
+ """
+ Unlock the keychain when we're using ssh instead of using the terminal from
+ GUI. See http://stackoverflow.com/a/20208104/1467959
+ """
+ global _keychain_unlocked
+ if not _keychain_unlocked:
+ _keychain_unlocked = True
+ run('security -v unlock-keychain -p vagrant || true')
+
+def do_sign(path, extra_args=None, preserve_entitlemenets=True):
+ unlock_keychain()
+ args = [
+ 'codesign',
+ '--verbose=4',
+ '-o', 'runtime',
+ '--timestamp',
+ '--verify',
+ # '--no-strict',
+ '--force',
+ '-s', CERT_ID,
+ ]
+ if preserve_entitlemenets:
+ args += ['--preserve-metadata=entitlements']
+ extra_args = extra_args or []
+ if extra_args:
+ args.extend(extra_args)
+
+ args.append(path)
+
+ if run_argv(args) != 0:
+ error('failed to sign {}'.format(path))
+
+def copy_dmg():
+ brand = 'seafile-client'
+ branded_dmg = '{}-{}.dmg'.format(brand, conf[CONF_VERSION])
+ src_dmg = os.path.join(BUILDDIR, 'app-{}.dmg'.format(conf[CONF_VERSION]))
+ dst_dmg = os.path.join(BUILDDIR, branded_dmg)
+
+ # move msi to outputdir
+ must_copy(src_dmg, dst_dmg)
+
+ print '---------------------------------------------'
+ print 'The build is successfully. Output is:'
+ print '>>\t%s' % dst_dmg
+ print '---------------------------------------------'
+
+def notarize_dmg():
+ pkg = os.path.join(BUILDDIR, 'app-{}.dmg'.format(conf[CONF_VERSION]))
+ info('Try to notarize {}'.format(pkg))
+ notarize_script = join(Seafile().projdir, 'scripts/build/notarize.sh')
+ cmdline = '{} {}'.format(notarize_script, pkg)
+ ret = run(cmdline)
+ if ret != 0:
+ error('failed to notarize: %s' % cmdline)
+ info('Successfully notarized {}'.format(pkg))
+
+def build_and_sign_fsplugin():
+ """
+ Build and sign the fsplugin. The final output would be "${buildder}/Seafile FinderSync.appex"
+ """
+ fsplugin = SeafileFinderSyncPlugin()
+ fsplugin.build()
+ with cd(fsplugin.projdir):
+ appex_src = 'fsplugin/{}'.format(FSPLUGIN_APPEX_NAME)
+ appex_dst = join(BUILDDIR, basename(appex_src))
+
+ check_remove(appex_dst)
+ must_copytree(appex_src, appex_dst)
+
+ entitlements_src = 'fsplugin/seafile-fsplugin.entitlements'
+ entitlements_dst = join(BUILDDIR, basename(entitlements_src))
+
+ check_remove(entitlements_dst)
+ must_copy(entitlements_src, entitlements_dst)
+
+ do_sign(
+ appex_dst,
+ extra_args=['--entitlements', entitlements_dst]
+ )
+
+def copy_fsplugin(plugins_dir):
+ src = join(BUILDDIR, FSPLUGIN_APPEX_NAME)
+ dst = join(plugins_dir, FSPLUGIN_APPEX_NAME)
+ check_remove(dst)
+ must_copytree(src, dst)
+
+def copy_sparkle_framework():
+ src = '/usr/local/Sparkle.framework'
+ dst = join(SeafileClient().projdir, 'seafile-applet.app/Contents/Frameworks', basename(src))
+ check_remove(dst)
+ # Here we use the `cp` command instead of shutil to do the copy, because `cp
+ # -P` would keep symlinks as is.
+ must_run('cp -R -P "{}" "{}"'.format(src, dst))
+
+def build_projects():
+ prepare_builddir(BUILDDIR)
+ libsearpc = Libsearpc()
+ seafile = Seafile()
+ seafile_client = SeafileClient()
+
+ libsearpc.build()
+
+ seafile.build()
+
+ seafile_client.build()
+
+ copy_sparkle_framework()
+
+ copy_shared_libs()
+
+def local_workflow():
+ build_projects()
+ generate_app_tar_gz()
+
+ build_and_sign_fsplugin()
+ gen_dmg()
+ notarize_dmg()
+ copy_dmg()
+
+
+def generate_app_tar_gz():
+ output_app_tgz = join(BUILDDIR, 'seafile-applet.app.tar.gz')
+ with cd(SeafileClient().projdir):
+ run('tar czf {} seafile-applet.app'.format(output_app_tgz))
+
+def setup_logging(level=logging.INFO):
+ kw = {
+ 'format': '[%(asctime)s][%(module)s]: %(message)s',
+ 'datefmt': '%m/%d/%Y %H:%M:%S',
+ 'level': level,
+ 'stream': sys.stdout
+ }
+
+ logging.basicConfig(**kw)
+ logging.getLogger('requests.packages.urllib3.connectionpool').setLevel(
+ logging.WARNING)
+
+def main():
+ setup_logging()
+ parse_args()
+ # check_cmd_para()
+ info('{} script started'.format(abspath(__file__)))
+ info('NUM_CPU = {}'.format(NUM_CPU))
+ setup_build_env()
+ local_workflow()
+
+if __name__ == '__main__':
+ main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/scripts/build/build-mac.py new/seafile-8.0.3/scripts/build/build-mac.py
--- old/seafile-8.0.2/scripts/build/build-mac.py 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/scripts/build/build-mac.py 2021-06-24 08:03:18.000000000 +0200
@@ -221,13 +221,6 @@
except Exception, e:
error('failed to copy %s to %s: %s' % (src, dst, e))
-def must_rmtree(path):
- '''Recurse rm dir, exit on failure'''
- try:
- shutil.rmtree(path)
- except Exception as e:
- error('failed rm dir %s : %s' % (path, e))
-
class Project(object):
'''Base class for a project'''
# Probject name, i.e. libseaprc/seafile/
@@ -795,17 +788,6 @@
must_run('rm -rf "{}"'.format(join(app_plugins_dir, 'bearer')))
# fsplugin must be copied before we sign the final .app dir
copy_fsplugin(app_plugins_dir)
-
- # Delete ~/seafpkg/build/seafile-mac-build/app-8.0.1/seafile-applet.app/Contents/Frameworks/QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app
-
- # Copy new QtWebEngineCoreProcess.app from Qt dir
- # ~/Qt/5.15.1/clang_64/lib/QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app
-
- webengineprocess_path = join(appdir, 'Contents/Frameworks/QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app')
- QT_WEBENGINEPROCESS_PATH = '/Users/vagrant/Qt/5.15.1/clang_64/lib/QtWebEngineCore.framework/Versions/5/Helpers/QtWebEngineProcess.app'
- must_rmtree(webengineprocess_path)
- must_copytree(QT_WEBENGINEPROCESS_PATH, webengineprocess_path)
-
sign_files(appdir)
# Rename the .app dir to 'Seafile Client.app', and create the shortcut
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/seafile-8.0.2/seafile.vcxproj new/seafile-8.0.3/seafile.vcxproj
--- old/seafile-8.0.2/seafile.vcxproj 2021-05-27 03:58:11.000000000 +0200
+++ new/seafile-8.0.3/seafile.vcxproj 2021-06-24 08:03:18.000000000 +0200
@@ -92,7 +92,7 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>
</SDLCheck>
- <PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.2";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.3";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<AdditionalOptions>/utf-8 %(AdditionalOptions)</AdditionalOptions>
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir)common;$(ProjectDir)lib;$(ProjectDir)include;$(ProjectDir)daemon;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -110,7 +110,7 @@
<WarningLevel>Level1</WarningLevel>
<SDLCheck>
</SDLCheck>
- <PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.2";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WIN32;UNICODE;WIN32_LEAN_AND_MEAN;SEAFILE_CLIENT;PACKAGE_VERSION="8.0.3";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir)common;$(ProjectDir)include;$(ProjectDir)daemon;$(ProjectDir)lib;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -131,7 +131,7 @@
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
- <PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.2";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.3";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir);$(ProjectDir)daemon;$(ProjectDir)include;$(ProjectDir)lib;$(ProjectDir)common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -158,7 +158,7 @@
<IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>
</SDLCheck>
- <PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.2";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;ENABLE_BREAKPAD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WIN32;PACKAGE_VERSION="8.0.3";WIN32_LEAN_AND_MEAN;UNICODE;SEAFILE_CLIENT;ENABLE_BREAKPAD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)..\libsearpc\lib;$(ProjectDir);$(ProjectDir)common;$(ProjectDir)lib;$(ProjectDir)include;$(ProjectDir)daemon;$(ProjectDir)..\breakpad\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>