1
0
mirror of https://github.com/haiwen/seafile-server.git synced 2025-09-17 23:59:44 +00:00

Upadte to python3.

This commit is contained in:
ly1217
2019-06-27 22:30:31 -07:00
parent d6fec719c7
commit c73916ef77
109 changed files with 407 additions and 14614 deletions

View File

@@ -1,696 +0,0 @@
#!/usr/bin/env python
# coding: UTF-8
'''This scirpt builds the seafile command line client (With no gui).
Some notes:
'''
import sys
####################
### 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)
import os
import commands
import tempfile
import shutil
import re
import subprocess
import optparse
import atexit
####################
### Global variables
####################
# command line configuartion
conf = {}
# key names in the conf dictionary.
CONF_VERSION = 'version'
CONF_SEAFILE_VERSION = 'seafile_version'
CONF_LIBSEARPC_VERSION = 'libsearpc_version'
CONF_CCNET_VERSION = 'ccnet_version'
CONF_SRCDIR = 'srcdir'
CONF_KEEP = 'keep'
CONF_BUILDDIR = 'builddir'
CONF_OUTPUTDIR = 'outputdir'
CONF_THIRDPARTDIR = 'thirdpartdir'
CONF_NO_STRIP = 'nostrip'
####################
### 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):
print highlight('[INFO] ') + msg
def exist_in_path(prog):
'''Test whether prog exists in system path'''
dirs = os.environ['PATH'].split(':')
for d in dirs:
if d == '':
continue
path = os.path.join(d, prog)
if os.path.exists(path):
return True
return False
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 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.
'''
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'''
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_mkdir(path):
'''Create a directory, exit on failure'''
try:
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))
class Project(object):
'''Base class for a project'''
# Probject name, i.e. libseaprc/ccnet/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 = os.path.join(conf[CONF_BUILDDIR], 'seafile-cli')
self.version = self.get_version()
self.src_tarball = os.path.join(conf[CONF_SRCDIR],
'%s-%s.tar.gz' % (self.name, self.version))
# project dir, like <builddir>/seafile-1.2.2/
self.projdir = os.path.join(conf[CONF_BUILDDIR], '%s-%s' % (self.name, self.version))
def get_version(self):
# libsearpc and ccnet 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 = os.path.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 uncompress(self):
'''Uncompress the source from the tarball'''
info('Uncompressing %s' % self.name)
if run('tar xf %s' % self.src_tarball) < 0:
error('failed to uncompress source of %s' % self.name)
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)
class Libsearpc(Project):
name = 'libsearpc'
def __init__(self):
Project.__init__(self)
self.build_commands = [
'./configure --prefix=%s --disable-compile-demo' % self.prefix,
'make',
'make install'
]
def get_version(self):
return conf[CONF_LIBSEARPC_VERSION]
class Ccnet(Project):
name = 'ccnet'
def __init__(self):
Project.__init__(self)
self.build_commands = [
'./configure --prefix=%s --disable-compile-demo' % self.prefix,
'make',
'make install'
]
def get_version(self):
return conf[CONF_CCNET_VERSION]
def before_build(self):
macros = {}
# SET CCNET_SOURCE_COMMIT_ID, so it can be printed in the log
macros['CCNET_SOURCE_COMMIT_ID'] = '\\"%s\\"' % self.get_source_commit_id()
self.append_cflags(macros)
class Seafile(Project):
name = 'seafile'
def __init__(self):
Project.__init__(self)
self.build_commands = [
'./configure --prefix=%s --disable-gui' % self.prefix,
'make',
'make install'
]
def get_version(self):
return conf[CONF_SEAFILE_VERSION]
def update_cli_version(self):
'''Substitute the version number in seaf-cli'''
cli_py = os.path.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)
def check_targz_src(proj, version, srcdir):
src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version))
if not os.path.exists(src_tarball):
error('%s not exists' % src_tarball)
def validate_args(usage, options):
required_args = [
CONF_VERSION,
CONF_LIBSEARPC_VERSION,
CONF_CCNET_VERSION,
CONF_SEAFILE_VERSION,
CONF_SRCDIR,
]
# fist check required args
for optname in required_args:
if getattr(options, optname, None) == 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('^[0-9]+(\.([0-9])+)+$', version):
error('%s is not a valid version' % version, usage=usage)
version = get_option(CONF_VERSION)
seafile_version = get_option(CONF_SEAFILE_VERSION)
libsearpc_version = get_option(CONF_LIBSEARPC_VERSION)
ccnet_version = get_option(CONF_CCNET_VERSION)
check_project_version(version)
check_project_version(libsearpc_version)
check_project_version(ccnet_version)
check_project_version(seafile_version)
# [ srcdir ]
srcdir = get_option(CONF_SRCDIR)
check_targz_src('libsearpc', libsearpc_version, srcdir)
check_targz_src('ccnet', ccnet_version, srcdir)
check_targz_src('seafile', seafile_version, srcdir)
# [ builddir ]
builddir = get_option(CONF_BUILDDIR)
if not os.path.exists(builddir):
error('%s does not exist' % builddir, usage=usage)
builddir = os.path.join(builddir, 'seafile-cli-build')
# [ outputdir ]
outputdir = get_option(CONF_OUTPUTDIR)
if outputdir:
if not os.path.exists(outputdir):
error('outputdir %s does not exist' % outputdir, usage=usage)
else:
outputdir = os.getcwd()
# [ keep ]
keep = get_option(CONF_KEEP)
# [ no strip]
nostrip = get_option(CONF_NO_STRIP)
conf[CONF_VERSION] = version
conf[CONF_LIBSEARPC_VERSION] = libsearpc_version
conf[CONF_SEAFILE_VERSION] = seafile_version
conf[CONF_CCNET_VERSION] = ccnet_version
conf[CONF_BUILDDIR] = builddir
conf[CONF_SRCDIR] = srcdir
conf[CONF_OUTPUTDIR] = outputdir
conf[CONF_KEEP] = keep
conf[CONF_NO_STRIP] = nostrip
prepare_builddir(builddir)
show_build_info()
def show_build_info():
'''Print all conf information. Confirm before continue.'''
info('------------------------------------------')
info('Seafile command line client %s: BUILD INFO' % conf[CONF_VERSION])
info('------------------------------------------')
info('seafile: %s' % conf[CONF_SEAFILE_VERSION])
info('ccnet: %s' % conf[CONF_CCNET_VERSION])
info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION])
info('builddir: %s' % conf[CONF_BUILDDIR])
info('outputdir: %s' % conf[CONF_OUTPUTDIR])
info('source dir: %s' % conf[CONF_SRCDIR])
info('strip symbols: %s' % (not conf[CONF_NO_STRIP]))
info('clean on exit: %s' % (not conf[CONF_KEEP]))
info('------------------------------------------')
info('press any key to continue ')
info('------------------------------------------')
dummy = raw_input()
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(os.path.join(builddir, 'seafile-cli'))
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_SEAFILE_VERSION),
dest=CONF_SEAFILE_VERSION,
nargs=1,
help='the version of seafile as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_LIBSEARPC_VERSION),
dest=CONF_LIBSEARPC_VERSION,
nargs=1,
help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_CCNET_VERSION),
dest=CONF_CCNET_VERSION,
nargs=1,
help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_BUILDDIR),
dest=CONF_BUILDDIR,
nargs=1,
help='the directory to build the source. Defaults to /tmp',
default=tempfile.gettempdir())
parser.add_option(long_opt(CONF_OUTPUTDIR),
dest=CONF_OUTPUTDIR,
nargs=1,
help='the output directory to put the generated tarball. Defaults to the current directory.',
default=os.getcwd())
parser.add_option(long_opt(CONF_SRCDIR),
dest=CONF_SRCDIR,
nargs=1,
help='''Source tarballs must be placed in this directory.''')
parser.add_option(long_opt(CONF_KEEP),
dest=CONF_KEEP,
action='store_true',
help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''')
parser.add_option(long_opt(CONF_NO_STRIP),
dest=CONF_NO_STRIP,
action='store_true',
help='''do not strip debug symbols''')
usage = parser.format_help()
options, remain = parser.parse_args()
if remain:
error(usage=usage)
validate_args(usage, options)
def setup_build_env():
'''Setup environment variables, such as export PATH=$BUILDDDIR/bin:$PATH'''
prefix = os.path.join(conf[CONF_BUILDDIR], 'seafile-cli')
prepend_env_value('CPPFLAGS',
'-I%s' % os.path.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' % os.path.join(prefix, 'lib'),
seperator=' ')
prepend_env_value('LDFLAGS',
'-L%s' % os.path.join(prefix, 'lib64'),
seperator=' ')
prepend_env_value('PATH', os.path.join(prefix, 'bin'))
prepend_env_value('PKG_CONFIG_PATH', os.path.join(prefix, 'lib', 'pkgconfig'))
prepend_env_value('PKG_CONFIG_PATH', os.path.join(prefix, 'lib64', 'pkgconfig'))
def copy_scripts_and_libs():
'''Copy scripts and shared libs'''
builddir = conf[CONF_BUILDDIR]
seafile_dir = os.path.join(builddir, Seafile().projdir)
scripts_srcdir = os.path.join(seafile_dir, 'scripts')
doc_dir = os.path.join(seafile_dir, 'doc')
cli_dir = os.path.join(builddir, 'seafile-cli')
# copy the wrapper shell script for seaf-cli.py
src = os.path.join(scripts_srcdir, 'seaf-cli-wrapper.sh')
dst = os.path.join(cli_dir, 'seaf-cli')
must_copy(src, dst)
# copy Readme for cli client
src = os.path.join(doc_dir, 'cli-readme.txt')
dst = os.path.join(cli_dir, 'Readme.txt')
must_copy(src, dst)
# rename seaf-cli to seaf-cli.py to avoid confusing users
src = os.path.join(cli_dir, 'bin', 'seaf-cli')
dst = os.path.join(cli_dir, 'bin', 'seaf-cli.py')
try:
shutil.move(src, dst)
except Exception, e:
error('failed to move %s to %s: %s' % (src, dst, e))
# copy shared c libs
copy_shared_libs()
def get_dependent_libs(executable):
syslibs = ['libsearpc', 'libccnet', 'libseafile', 'libpthread.so', 'libc.so', 'libm.so', 'librt.so', 'libdl.so', 'libselinux.so']
def is_syslib(lib):
for syslib in syslibs:
if syslib in lib:
return True
return False
ldd_output = commands.getoutput('ldd %s' % executable)
ret = []
for line in ldd_output.splitlines():
tokens = line.split()
if len(tokens) != 4:
continue
if is_syslib(tokens[0]):
continue
ret.append(tokens[2])
return ret
def copy_shared_libs():
'''copy shared c libs, such as libevent, glib, libmysqlclient'''
builddir = conf[CONF_BUILDDIR]
dst_dir = os.path.join(builddir,
'seafile-cli',
'lib')
ccnet_daemon_path = os.path.join(builddir,
'seafile-cli',
'bin',
'ccnet')
seaf_daemon_path = os.path.join(builddir,
'seafile-cli',
'bin',
'seaf-daemon')
ccnet_daemon_libs = get_dependent_libs(ccnet_daemon_path)
seaf_daemon_libs = get_dependent_libs(seaf_daemon_path)
libs = ccnet_daemon_libs
for lib in seaf_daemon_libs:
if lib not in libs:
libs.append(lib)
for lib in libs:
info('Copying %s' % lib)
shutil.copy(lib, dst_dir)
def strip_symbols():
def do_strip(fn):
run('chmod u+w %s' % fn)
info('stripping: %s' % fn)
run('strip "%s"' % fn)
def remove_static_lib(fn):
info('removing: %s' % fn)
os.remove(fn)
builddir = conf[CONF_BUILDDIR]
topdir = os.path.join(builddir, 'seafile-cli')
for parent, dnames, fnames in os.walk(topdir):
dummy = dnames # avoid pylint 'unused' warning
for fname in fnames:
fn = os.path.join(parent, fname)
if os.path.isdir(fn):
continue
if fn.endswith(".a") or fn.endswith(".la"):
remove_static_lib(fn)
continue
if os.path.islink(fn):
continue
finfo = commands.getoutput('file "%s"' % fn)
if 'not stripped' in finfo:
do_strip(fn)
def create_tarball(tarball_name):
'''call tar command to generate a tarball'''
version = conf[CONF_VERSION]
cli_dir = 'seafile-cli'
versioned_cli_dir = 'seafile-cli-' + version
# move seafile-cli to seafile-cli-${version}
try:
shutil.move(cli_dir, versioned_cli_dir)
except Exception, e:
error('failed to move %s to %s: %s' % (cli_dir, versioned_cli_dir, e))
ignored_patterns = [
# common ignored files
'*.pyc',
'*~',
'*#',
# seafile
os.path.join(versioned_cli_dir, 'share*'),
os.path.join(versioned_cli_dir, 'include*'),
os.path.join(versioned_cli_dir, 'lib', 'pkgconfig*'),
os.path.join(versioned_cli_dir, 'lib64', 'pkgconfig*'),
os.path.join(versioned_cli_dir, 'bin', 'ccnet-demo*'),
os.path.join(versioned_cli_dir, 'bin', 'ccnet-tool'),
os.path.join(versioned_cli_dir, 'bin', 'ccnet-servtool'),
os.path.join(versioned_cli_dir, 'bin', 'searpc-codegen.py'),
os.path.join(versioned_cli_dir, 'bin', 'seafile-admin'),
os.path.join(versioned_cli_dir, 'bin', 'seafile'),
]
excludes_list = [ '--exclude=%s' % pattern for pattern in ignored_patterns ]
excludes = ' '.join(excludes_list)
tar_cmd = 'tar czvf %(tarball_name)s %(versioned_cli_dir)s %(excludes)s' \
% dict(tarball_name=tarball_name,
versioned_cli_dir=versioned_cli_dir,
excludes=excludes)
if run(tar_cmd) != 0:
error('failed to generate the tarball')
def gen_tarball():
# strip symbols of libraries to reduce size
if not conf[CONF_NO_STRIP]:
try:
strip_symbols()
except Exception, e:
error('failed to strip symbols: %s' % e)
# determine the output name
# 64-bit: seafile-cli_1.2.2_x86-64.tar.gz
# 32-bit: seafile-cli_1.2.2_i386.tar.gz
version = conf[CONF_VERSION]
arch = os.uname()[-1].replace('_', '-')
if arch != 'x86-64':
arch = 'i386'
dbg = ''
if conf[CONF_NO_STRIP]:
dbg = '.dbg'
tarball_name = 'seafile-cli_%(version)s_%(arch)s%(dbg)s.tar.gz' \
% dict(version=version, arch=arch, dbg=dbg)
dst_tarball = os.path.join(conf[CONF_OUTPUTDIR], tarball_name)
# generate the tarball
try:
create_tarball(tarball_name)
except Exception, e:
error('failed to generate tarball: %s' % e)
# move tarball to outputdir
try:
shutil.copy(tarball_name, dst_tarball)
except Exception, e:
error('failed to copy %s to %s: %s' % (tarball_name, dst_tarball, e))
print '---------------------------------------------'
print 'The build is successfully. Output is:\t%s' % dst_tarball
print '---------------------------------------------'
def main():
parse_args()
setup_build_env()
libsearpc = Libsearpc()
ccnet = Ccnet()
seafile = Seafile()
libsearpc.uncompress()
libsearpc.build()
ccnet.uncompress()
ccnet.build()
seafile.uncompress()
seafile.build()
copy_scripts_and_libs()
gen_tarball()
if __name__ == '__main__':
main()

View File

@@ -1,496 +0,0 @@
#!/usr/bin/env python
# coding: UTF-8
'''This scirpt builds the seafile server tarball.
Some notes:
1. The working directory is always the 'builddir'. 'os.chdir' is only called
to change to the 'builddir'. We make use of the 'cwd' argument in
'subprocess.Popen' to run a command in a specific directory.
'''
import sys
####################
### 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)
import os
import glob
import tempfile
import shutil
import re
import subprocess
import optparse
import atexit
####################
### Global variables
####################
# command line configuartion
conf = {}
# key names in the conf dictionary.
CONF_VERSION = 'version'
CONF_LIBSEARPC_VERSION = 'libsearpc_version'
CONF_CCNET_VERSION = 'ccnet_version'
CONF_SEAFILE_VERSION = 'seafile_version'
CONF_SEAFILE_CLIENT_VERSION = 'seafile_client_version'
CONF_SRCDIR = 'srcdir'
CONF_KEEP = 'keep'
CONF_BUILDDIR = 'builddir'
CONF_OUTPUTDIR = 'outputdir'
CONF_NO_STRIP = 'nostrip'
####################
### 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):
print highlight('[INFO] ') + msg
def exist_in_path(prog):
'''Test whether prog exists in system path'''
dirs = os.environ['PATH'].split(':')
for d in dirs:
if d == '':
continue
path = os.path.join(d, prog)
if os.path.exists(path):
return True
return False
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 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.
'''
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'''
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_mkdir(path):
'''Create a directory, exit on failure'''
try:
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))
class Project(object):
'''Base class for a project'''
# Probject name, i.e. libseaprc/ccnet/seafile/seahub
name = ''
# A list of shell commands to configure/build the project
build_commands = []
def __init__(self):
self.version = self.get_version()
self.src_tarball = os.path.join(conf[CONF_SRCDIR],
'%s-%s.tar.gz' % (self.name, self.version))
# project dir, like <builddir>/seafile-1.2.2/
self.projdir = os.path.join(conf[CONF_BUILDDIR], '%s-%s' % (self.name, self.version))
def get_version(self):
# libsearpc and ccnet 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 = os.path.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('DEB_CPPFLAGS_APPEND',
cflags,
seperator=' ')
def uncompress(self):
'''Uncompress the source from the tarball'''
info('Uncompressing %s' % self.name)
if run('tar xf %s' % self.src_tarball) < 0:
error('failed to uncompress source of %s' % self.name)
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)
class Libsearpc(Project):
name = 'libsearpc'
def get_version(self):
return conf[CONF_LIBSEARPC_VERSION]
class Ccnet(Project):
name = 'ccnet'
def get_version(self):
return conf[CONF_CCNET_VERSION]
def before_build(self):
macros = {}
# SET CCNET_SOURCE_COMMIT_ID, so it can be printed in the log
macros['CCNET_SOURCE_COMMIT_ID'] = '\\"%s\\"' % self.get_source_commit_id()
self.append_cflags(macros)
class SeafileClient(Project):
name = 'seafile-client'
def get_version(self):
return conf[CONF_SEAFILE_CLIENT_VERSION]
def before_build(self):
pass
class Seafile(Project):
name = 'seafile'
def __init__(self):
Project.__init__(self)
self.build_commands = [
'dpkg-buildpackage -B -nc -uc -us',
]
def get_version(self):
return conf[CONF_SEAFILE_VERSION]
def before_build(self):
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)
def check_targz_src(proj, version, srcdir):
src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version))
if not os.path.exists(src_tarball):
error('%s not exists' % src_tarball)
def validate_args(usage, options):
required_args = [
CONF_VERSION,
CONF_LIBSEARPC_VERSION,
CONF_CCNET_VERSION,
CONF_SEAFILE_VERSION,
CONF_SEAFILE_CLIENT_VERSION,
CONF_SRCDIR,
]
# fist check required args
for optname in required_args:
if getattr(options, optname, None) == 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('^[0-9]+(\.([0-9])+)+$', version):
error('%s is not a valid version' % version, usage=usage)
version = get_option(CONF_VERSION)
libsearpc_version = get_option(CONF_LIBSEARPC_VERSION)
ccnet_version = get_option(CONF_CCNET_VERSION)
seafile_version = get_option(CONF_SEAFILE_VERSION)
seafile_client_version = get_option(CONF_SEAFILE_CLIENT_VERSION)
check_project_version(version)
check_project_version(libsearpc_version)
check_project_version(ccnet_version)
check_project_version(seafile_version)
# [ srcdir ]
srcdir = get_option(CONF_SRCDIR)
check_targz_src('libsearpc', libsearpc_version, srcdir)
check_targz_src('ccnet', ccnet_version, srcdir)
check_targz_src('seafile', seafile_version, srcdir)
check_targz_src('seafile-client', seafile_client_version, srcdir)
# [ builddir ]
builddir = get_option(CONF_BUILDDIR)
if not os.path.exists(builddir):
error('%s does not exist' % builddir, usage=usage)
builddir = os.path.join(builddir, 'seafile-deb-build')
# [ outputdir ]
outputdir = get_option(CONF_OUTPUTDIR)
if outputdir:
if not os.path.exists(outputdir):
error('outputdir %s does not exist' % outputdir, usage=usage)
else:
outputdir = os.getcwd()
# [ keep ]
keep = get_option(CONF_KEEP)
# [ no strip]
nostrip = get_option(CONF_NO_STRIP)
conf[CONF_VERSION] = version
conf[CONF_LIBSEARPC_VERSION] = libsearpc_version
conf[CONF_CCNET_VERSION] = ccnet_version
conf[CONF_SEAFILE_VERSION] = seafile_version
conf[CONF_SEAFILE_CLIENT_VERSION] = seafile_client_version
conf[CONF_BUILDDIR] = builddir
conf[CONF_SRCDIR] = srcdir
conf[CONF_OUTPUTDIR] = outputdir
conf[CONF_KEEP] = True
conf[CONF_NO_STRIP] = nostrip
prepare_builddir(builddir)
show_build_info()
def show_build_info():
'''Print all conf information. Confirm before continue.'''
info('------------------------------------------')
info('Seafile debian package: BUILD INFO')
info('------------------------------------------')
info('seafile: %s' % conf[CONF_SEAFILE_VERSION])
info('seafile-client: %s' % conf[CONF_SEAFILE_CLIENT_VERSION])
info('ccnet: %s' % conf[CONF_CCNET_VERSION])
info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION])
info('builddir: %s' % conf[CONF_BUILDDIR])
info('outputdir: %s' % conf[CONF_OUTPUTDIR])
info('source dir: %s' % conf[CONF_SRCDIR])
info('strip symbols: %s' % (not conf[CONF_NO_STRIP]))
info('clean on exit: %s' % (not conf[CONF_KEEP]))
info('------------------------------------------')
info('press any key to continue ')
info('------------------------------------------')
dummy = raw_input()
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)
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_LIBSEARPC_VERSION),
dest=CONF_LIBSEARPC_VERSION,
nargs=1,
help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_CCNET_VERSION),
dest=CONF_CCNET_VERSION,
nargs=1,
help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_VERSION),
dest=CONF_SEAFILE_VERSION,
nargs=1,
help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_CLIENT_VERSION),
dest=CONF_SEAFILE_CLIENT_VERSION,
nargs=1,
help='the version of seafile-client. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_BUILDDIR),
dest=CONF_BUILDDIR,
nargs=1,
help='the directory to build the source. Defaults to /tmp',
default=tempfile.gettempdir())
parser.add_option(long_opt(CONF_OUTPUTDIR),
dest=CONF_OUTPUTDIR,
nargs=1,
help='the output directory to put the generated server tarball. Defaults to the current directory.',
default=os.getcwd())
parser.add_option(long_opt(CONF_SRCDIR),
dest=CONF_SRCDIR,
nargs=1,
help='''Source tarballs must be placed in this directory.''')
parser.add_option(long_opt(CONF_KEEP),
dest=CONF_KEEP,
action='store_true',
help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''')
parser.add_option(long_opt(CONF_NO_STRIP),
dest=CONF_NO_STRIP,
action='store_true',
help='''do not strip debug symbols''')
usage = parser.format_help()
options, remain = parser.parse_args()
if remain:
error(usage=usage)
validate_args(usage, options)
def setup_build_env():
'''Setup environment variables, such as export PATH=$BUILDDDIR/bin:$PATH'''
prefix = os.path.join(Seafile().projdir, 'debian', 'seafile', 'usr')
prepend_env_value('DEB_CPPFLAGS_APPEND',
'-DSEAFILE_CLIENT_VERSION=\\"%s\\"' % conf[CONF_VERSION],
seperator=' ')
if conf[CONF_NO_STRIP]:
prepend_env_value('DEB_CPPFLAGS_APPEND',
'-g -O0',
seperator=' ')
os.environ['SEAFILE_NOSTRIP'] = 'true'
os.environ['DEB_CFLAGS_SET'] = ''
os.environ['DEB_CXXFLAGS_SET'] = ''
prepend_env_value('PATH', os.path.join(prefix, 'bin'))
prepend_env_value('PKG_CONFIG_PATH', os.path.join(prefix, 'lib', 'pkgconfig'))
os.environ['LIBSEARPC_SOURCE_DIR'] = Libsearpc().projdir
os.environ['CCNET_SOURCE_DIR'] = Ccnet().projdir
os.environ['SEAFILE_CLIENT_SOURCE_DIR'] = SeafileClient().projdir
def move_deb():
builddir = conf[CONF_BUILDDIR]
deb_name = glob.glob('*.deb')[0]
src_deb = os.path.join(builddir, deb_name)
dst_deb = os.path.join(conf[CONF_OUTPUTDIR], deb_name)
# move deb to outputdir
try:
shutil.move(src_deb, dst_deb)
except Exception, e:
error('failed to copy %s to %s: %s' % (src_deb, dst_deb, e))
print '---------------------------------------------'
print 'The build is successfully. Output is:\t%s' % dst_deb
print '---------------------------------------------'
def main():
parse_args()
setup_build_env()
libsearpc = Libsearpc()
ccnet = Ccnet()
seafile = Seafile()
seafile_client = SeafileClient()
libsearpc.uncompress()
ccnet.uncompress()
seafile.uncompress()
seafile_client.uncompress()
libsearpc.build()
ccnet.build()
seafile.build()
seafile_client.build()
move_deb()
if __name__ == '__main__':
main()

View File

@@ -1,942 +0,0 @@
#!/usr/bin/env python
# coding: UTF-8
'''This scirpt builds the seafile windows msi installer.
Some notes:
1. The working directory is always the 'builddir'. 'os.chdir' is only called
to change to the 'builddir'. We make use of the 'cwd' argument in
'subprocess.Popen' to run a command in a specific directory.
2. When invoking commands like 'tar', we must convert the path to posix path with the function to_mingw_path. E.g., 'c:\\seafile' should be converted to '/c/seafile'.
'''
import sys
####################
### 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)
import os
import glob
import shutil
import re
import subprocess
import optparse
import atexit
import csv
error_exit = False
####################
### Global variables
####################
# command line configuartion
conf = {}
# key names in the conf dictionary.
CONF_VERSION = 'version'
CONF_LIBSEARPC_VERSION = 'libsearpc_version'
CONF_CCNET_VERSION = 'ccnet_version'
CONF_SEAFILE_VERSION = 'seafile_version'
CONF_SEAFILE_CLIENT_VERSION = 'seafile_client_version'
CONF_SRCDIR = 'srcdir'
CONF_KEEP = 'keep'
CONF_BUILDDIR = 'builddir'
CONF_OUTPUTDIR = 'outputdir'
CONF_DEBUG = 'debug'
CONF_ONLY_CHINESE = 'onlychinese'
CONF_QT_ROOT = 'qt_root'
CONF_QT5 = 'qt5'
CONF_WITH_SHIB = 'with_shib'
CONF_BRAND = 'brand'
####################
### Common helper functions
####################
def to_mingw_path(path):
if len(path) < 2 or path[1] != ':' :
return path.replace('\\', '/')
drive = path[0]
return '/%s%s' % (drive.lower(), path[2:].replace('\\', '/'))
def to_win_path(path):
if len(path) < 2 or path[1] == ':' :
return path.replace('/', '\\')
drive = path[1]
return '%s:%s' % (drive.lower(), path[2:].replace('/', '\\'))
def highlight(content, is_error=False):
'''Add ANSI color to content to get it highlighted on terminal'''
dummy = is_error
return content
# if is_error:
# return '\x1b[1;31m%s\x1b[m' % content
# else:
# return '\x1b[1;32m%s\x1b[m' % content
def info(msg):
print highlight('[INFO] ') + msg
def find_in_path(prog):
'''Test whether prog exists in system path'''
dirs = os.environ['PATH'].split(';')
for d in dirs:
if d == '':
continue
path = os.path.join(d, prog)
if os.path.exists(path):
return path
return None
def prepend_env_value(name, value, seperator=':'):
'''prepend 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 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.
'''
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 if cwd else 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)
ret = proc.wait()
if 'depend' not in cmdline and ret != 0:
global error_exit
error_exit = True
return ret
def must_mkdir(path):
'''Create a directory, exit on failure'''
try:
os.makedirs(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 dir src to dst, exit on failure'''
try:
shutil.copytree(src, dst)
except Exception, e:
error('failed to copy dir %s to %s: %s' % (src, dst, e))
def must_move(src, dst):
'''Move src to dst, exit on failure'''
try:
shutil.move(src, dst)
except Exception, e:
error('failed to move %s to %s: %s' % (src, dst, e))
class Project(object):
'''Base class for a project'''
# Probject name, i.e. libseaprc/ccnet/seafile/seahub
name = ''
# A list of shell commands to configure/build the project
build_commands = []
def __init__(self):
self.prefix = os.path.join(conf[CONF_BUILDDIR], 'usr')
self.version = self.get_version()
self.src_tarball = os.path.join(conf[CONF_SRCDIR],
'%s-%s.tar.gz' % (self.name, self.version))
# project dir, like <builddir>/seafile-1.2.2/
self.projdir = os.path.join(conf[CONF_BUILDDIR], '%s-%s' % (self.name, self.version))
def get_version(self):
# libsearpc and ccnet 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 = os.path.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 uncompress(self):
'''Uncompress the source from the tarball'''
info('Uncompressing %s' % self.name)
tarball = to_mingw_path(self.src_tarball)
if run('tar xf %s' % tarball) != 0:
error('failed to uncompress source of %s' % self.name)
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)
dump_env()
for cmd in self.build_commands:
if run(cmd, cwd=self.projdir) != 0:
error('error when running command:\n\t%s\n' % cmd)
def get_make_path():
return find_in_path('make.exe')
class Libsearpc(Project):
name = 'libsearpc'
def __init__(self):
Project.__init__(self)
self.build_commands = [
'sh ./configure --prefix=%s --disable-compile-demo' % to_mingw_path(self.prefix),
get_make_path(),
'%s install' % get_make_path(),
]
def get_version(self):
return conf[CONF_LIBSEARPC_VERSION]
class Ccnet(Project):
name = 'ccnet'
def __init__(self):
Project.__init__(self)
self.build_commands = [
'sh ./configure --prefix=%s --disable-compile-demo' % to_mingw_path(self.prefix),
get_make_path(),
'%s install' % get_make_path(),
]
def get_version(self):
return conf[CONF_CCNET_VERSION]
def before_build(self):
macros = {}
# SET CCNET_SOURCE_COMMIT_ID, so it can be printed in the log
macros['CCNET_SOURCE_COMMIT_ID'] = '\\"%s\\"' % self.get_source_commit_id()
self.append_cflags(macros)
class Seafile(Project):
name = 'seafile'
def __init__(self):
Project.__init__(self)
if breakpad_enabled():
enable_breakpad = '--enable-breakpad'
else:
enable_breakpad = ''
self.build_commands = [
'sh ./configure %s --prefix=%s' % (enable_breakpad, to_mingw_path(self.prefix)),
get_make_path(),
'%s install' % get_make_path(),
]
def get_version(self):
return conf[CONF_SEAFILE_VERSION]
def before_build(self):
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)
ninja = find_in_path('ninja.exe')
seafile_prefix = Seafile().prefix
generator = 'Ninja' if ninja else 'MSYS Makefiles'
flags = {
'USE_QT5': 'ON' if conf[CONF_QT5] else 'OFF',
'BUILD_SHIBBOLETH_SUPPORT': 'ON' if conf[CONF_WITH_SHIB] else 'OFF',
# ninja invokes cmd.exe which doesn't support msys/mingw path
# change the value but don't override CMAKE_EXE_LINKER_FLAGS,
# which is in use
'CMAKE_EXE_LINKER_FLAGS_RELEASE': '-L%s' % (os.path.join(seafile_prefix, 'lib') if ninja else to_mingw_path(os.path.join(seafile_prefix, 'lib'))),
}
flags = ' '.join(['-D%s=%s' % (k, v) for k, v in flags.iteritems()])
make = ninja or get_make_path()
self.build_commands = [
'cmake -G "%s" %s -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=%s .' % (generator, flags, to_mingw_path(self.prefix)),
make,
'%s install' % make,
"bash extensions/build.sh",
]
def get_version(self):
return conf[CONF_SEAFILE_CLIENT_VERSION]
def before_build(self):
pass
def check_targz_src(proj, version, srcdir):
src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version))
if not os.path.exists(src_tarball):
error('%s not exists' % src_tarball)
def validate_args(usage, options):
required_args = [
CONF_VERSION,
CONF_LIBSEARPC_VERSION,
CONF_CCNET_VERSION,
CONF_SEAFILE_VERSION,
CONF_SEAFILE_CLIENT_VERSION,
CONF_SRCDIR,
CONF_QT_ROOT,
]
# fist check required args
for optname in required_args:
if getattr(options, optname, None) == 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('^[0-9]+(\.([0-9])+)+$', version):
error('%s is not a valid version' % version, usage=usage)
version = get_option(CONF_VERSION)
libsearpc_version = get_option(CONF_LIBSEARPC_VERSION)
ccnet_version = get_option(CONF_CCNET_VERSION)
seafile_version = get_option(CONF_SEAFILE_VERSION)
seafile_client_version = get_option(CONF_SEAFILE_CLIENT_VERSION)
check_project_version(version)
check_project_version(libsearpc_version)
check_project_version(ccnet_version)
check_project_version(seafile_version)
check_project_version(seafile_client_version)
# [ srcdir ]
srcdir = to_win_path(get_option(CONF_SRCDIR))
check_targz_src('libsearpc', libsearpc_version, srcdir)
check_targz_src('ccnet', ccnet_version, srcdir)
check_targz_src('seafile', seafile_version, srcdir)
check_targz_src('seafile-client', seafile_client_version, srcdir)
# [ builddir ]
builddir = to_win_path(get_option(CONF_BUILDDIR))
if not os.path.exists(builddir):
error('%s does not exist' % builddir, usage=usage)
builddir = os.path.join(builddir, 'seafile-msi-build')
# [ outputdir ]
outputdir = to_win_path(get_option(CONF_OUTPUTDIR))
if not os.path.exists(outputdir):
error('outputdir %s does not exist' % outputdir, usage=usage)
# [ keep ]
keep = get_option(CONF_KEEP)
# [ no strip]
debug = get_option(CONF_DEBUG)
# [only chinese]
onlychinese = get_option(CONF_ONLY_CHINESE)
# [ qt root]
qt_root = get_option(CONF_QT_ROOT)
def check_qt_root(qt_root):
if not os.path.exists(os.path.join(qt_root, 'plugins')):
error('%s is not a valid qt root' % qt_root)
check_qt_root(qt_root)
# [qt5]
qt5 = get_option(CONF_QT5)
with_shib = get_option(CONF_WITH_SHIB)
brand = get_option(CONF_BRAND)
conf[CONF_VERSION] = version
conf[CONF_LIBSEARPC_VERSION] = libsearpc_version
conf[CONF_CCNET_VERSION] = ccnet_version
conf[CONF_SEAFILE_VERSION] = seafile_version
conf[CONF_SEAFILE_CLIENT_VERSION] = seafile_client_version
conf[CONF_BUILDDIR] = builddir
conf[CONF_SRCDIR] = srcdir
conf[CONF_OUTPUTDIR] = outputdir
conf[CONF_KEEP] = True
conf[CONF_DEBUG] = debug
conf[CONF_ONLY_CHINESE] = onlychinese
conf[CONF_QT_ROOT] = qt_root
conf[CONF_QT5] = qt5
conf[CONF_WITH_SHIB] = with_shib
conf[CONF_BRAND] = brand
prepare_builddir(builddir)
show_build_info()
def show_build_info():
'''Print all conf information. Confirm before continue.'''
info('------------------------------------------')
info('Seafile msi installer: BUILD INFO')
info('------------------------------------------')
info('seafile: %s' % conf[CONF_VERSION])
info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION])
info('ccnet: %s' % conf[CONF_CCNET_VERSION])
info('seafile: %s' % conf[CONF_SEAFILE_VERSION])
info('seafile-client: %s' % conf[CONF_SEAFILE_CLIENT_VERSION])
info('qt-root: %s' % conf[CONF_QT_ROOT])
info('builddir: %s' % conf[CONF_BUILDDIR])
info('outputdir: %s' % conf[CONF_OUTPUTDIR])
info('source dir: %s' % conf[CONF_SRCDIR])
info('debug: %s' % conf[CONF_DEBUG])
info('build english version: %s' % (not conf[CONF_ONLY_CHINESE]))
info('clean on exit: %s' % (not conf[CONF_KEEP]))
info('------------------------------------------')
info('press any key to continue ')
info('------------------------------------------')
dummy = raw_input()
def prepare_builddir(builddir):
must_mkdir(builddir)
if not conf[CONF_KEEP]:
def remove_builddir():
'''Remove the builddir when exit'''
if not error_exit:
info('remove builddir before exit')
shutil.rmtree(builddir, ignore_errors=True)
atexit.register(remove_builddir)
os.chdir(builddir)
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_LIBSEARPC_VERSION),
dest=CONF_LIBSEARPC_VERSION,
nargs=1,
help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_CCNET_VERSION),
dest=CONF_CCNET_VERSION,
nargs=1,
help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_VERSION),
dest=CONF_SEAFILE_VERSION,
nargs=1,
help='the version of seafile as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_CLIENT_VERSION),
dest=CONF_SEAFILE_CLIENT_VERSION,
nargs=1,
help='the version of seafile-client. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_BUILDDIR),
dest=CONF_BUILDDIR,
nargs=1,
help='the directory to build the source. Defaults to /c',
default='c:\\')
parser.add_option(long_opt(CONF_OUTPUTDIR),
dest=CONF_OUTPUTDIR,
nargs=1,
help='the output directory to put the generated server tarball. Defaults to the current directory.',
default=os.getcwd())
parser.add_option(long_opt(CONF_SRCDIR),
dest=CONF_SRCDIR,
nargs=1,
help='''Source tarballs must be placed in this directory.''')
parser.add_option(long_opt(CONF_QT_ROOT),
dest=CONF_QT_ROOT,
nargs=1,
help='''qt root directory.''')
parser.add_option(long_opt(CONF_KEEP),
dest=CONF_KEEP,
action='store_true',
help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''')
parser.add_option(long_opt(CONF_DEBUG),
dest=CONF_DEBUG,
action='store_true',
help='''compile in debug mode''')
parser.add_option(long_opt(CONF_ONLY_CHINESE),
dest=CONF_ONLY_CHINESE,
action='store_true',
help='''only build the Chinese version. By default both Chinese and English versions would be built.''')
parser.add_option(long_opt(CONF_QT5),
dest=CONF_QT5,
action='store_true',
help='''build seafile client with qt5''')
parser.add_option(long_opt(CONF_WITH_SHIB),
dest=CONF_WITH_SHIB,
action='store_true',
help='''build seafile client with shibboleth support''')
parser.add_option(long_opt(CONF_BRAND),
dest=CONF_BRAND,
default='seafile',
help='''brand name of the package''')
usage = parser.format_help()
options, remain = parser.parse_args()
if remain:
error(usage=usage)
validate_args(usage, options)
def setup_build_env():
'''Setup environment variables, such as export PATH=$BUILDDDIR/bin:$PATH'''
prefix = Seafile().prefix
prepend_env_value('CPPFLAGS',
'-I%s' % to_mingw_path(os.path.join(prefix, 'include')),
seperator=' ')
prepend_env_value('CPPFLAGS',
'-DSEAFILE_CLIENT_VERSION=\\"%s\\"' % conf[CONF_VERSION],
seperator=' ')
prepend_env_value('CPPFLAGS',
'-g -fno-omit-frame-pointer',
seperator=' ')
if conf[CONF_DEBUG]:
prepend_env_value('CPPFLAGS', '-O0', seperator=' ')
prepend_env_value('LDFLAGS',
'-L%s' % to_mingw_path(os.path.join(prefix, 'lib')),
seperator=' ')
prepend_env_value('PATH',
os.path.join(prefix, 'bin'),
seperator=';')
prepend_env_value('PKG_CONFIG_PATH',
os.path.join(prefix, 'lib', 'pkgconfig'),
seperator=';')
# to_mingw_path(os.path.join(prefix, 'lib', 'pkgconfig')))
# specifiy the directory for wix temporary files
wix_temp_dir = os.path.join(conf[CONF_BUILDDIR], 'wix-temp')
os.environ['WIX_TEMP'] = wix_temp_dir
must_mkdir(wix_temp_dir)
def dependency_walk(applet):
output = os.path.join(conf[CONF_BUILDDIR], 'depends.csv')
cmd = 'depends.exe -c -f 1 -oc %s %s' % (output, applet)
# See the manual of Dependency walker
if run(cmd) > 0x100:
error('failed to run dependency walker for %s' % applet)
if not os.path.exists(output):
error('failed to run dependency walker for %s' % applet)
shared_libs = parse_depends_csv(output)
return shared_libs
def parse_depends_csv(path):
'''parse the output of dependency walker'''
libs = set()
our_libs = ['libsearpc', 'libccnet', 'libseafile']
def should_ignore_lib(lib):
lib = lib.lower()
if not os.path.exists(lib):
return True
if lib.startswith('c:\\windows'):
return True
if lib.endswith('exe'):
return True
for name in our_libs:
if name in lib:
return True
return False
with open(path, 'r') as fp:
reader = csv.reader(fp)
for row in reader:
if len(row) < 2:
continue
lib = row[1]
if not should_ignore_lib(lib):
libs.add(lib)
return set(libs)
def copy_shared_libs(exes):
'''Copy shared libs need by seafile-applet.exe, such as libccnet,
libseafile, etc. First we use Dependency walker to analyse
seafile-applet.exe, and get an output file in csv format. Then we parse
the csv file to get the list of shared libs.
'''
shared_libs = set()
for exectuable in exes:
shared_libs.update(dependency_walk(exectuable))
pack_bin_dir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'bin')
for lib in shared_libs:
must_copy(lib, pack_bin_dir)
ssleay32 = find_in_path('ssleay32.dll')
must_copy(ssleay32, pack_bin_dir)
def copy_dll_exe():
prefix = Seafile().prefix
destdir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'bin')
filelist = [
os.path.join(prefix, 'bin', 'libsearpc-1.dll'),
os.path.join(prefix, 'bin', 'libccnet-0.dll'),
os.path.join(prefix, 'bin', 'libseafile-0.dll'),
os.path.join(prefix, 'bin', 'ccnet.exe'),
os.path.join(prefix, 'bin', 'seaf-daemon.exe'),
os.path.join(SeafileClient().projdir, 'seafile-applet.exe'),
]
for name in filelist:
must_copy(name, destdir)
extdlls = [
os.path.join(SeafileClient().projdir, 'extensions', 'lib', 'seafile_shell_ext.dll'),
os.path.join(SeafileClient().projdir, 'extensions', 'lib', 'seafile_shell_ext64.dll'),
]
customdir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'custom')
for dll in extdlls:
must_copy(dll, customdir)
copy_shared_libs([ f for f in filelist if f.endswith('.exe') ])
copy_qt_plugins_imageformats()
copy_qt_plugins_platforms()
copy_qt_translations()
def copy_qt_plugins_imageformats():
destdir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'bin', 'imageformats')
must_mkdir(destdir)
qt_plugins_srcdir = os.path.join(conf[CONF_QT_ROOT], 'plugins', 'imageformats')
src = os.path.join(qt_plugins_srcdir, 'qico4.dll')
if conf[CONF_QT5]:
src = os.path.join(qt_plugins_srcdir, 'qico.dll')
must_copy(src, destdir)
src = os.path.join(qt_plugins_srcdir, 'qgif4.dll')
if conf[CONF_QT5]:
src = os.path.join(qt_plugins_srcdir, 'qgif.dll')
must_copy(src, destdir)
def copy_qt_plugins_platforms():
if not conf[CONF_QT5]:
return
destdir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'bin', 'platforms')
must_mkdir(destdir)
qt_plugins_srcdir = os.path.join(conf[CONF_QT_ROOT], 'plugins', 'platforms')
src = os.path.join(qt_plugins_srcdir, 'qwindows.dll')
must_copy(src, destdir)
src = os.path.join(qt_plugins_srcdir, 'qminimal.dll')
must_copy(src, destdir)
def copy_qt_translations():
destdir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'bin')
qt_translation_dir = os.path.join(conf[CONF_QT_ROOT], 'translations')
i18n_dir = os.path.join(SeafileClient().projdir, 'i18n')
qm_pattern = os.path.join(i18n_dir, 'seafile_*.qm')
qt_qms = set()
def add_lang(lang):
if not lang:
return
qt_qm = os.path.join(qt_translation_dir, 'qt_%s.qm' % lang)
if os.path.exists(qt_qm):
qt_qms.add(qt_qm)
elif '_' in lang:
add_lang(lang[:lang.index('_')])
for fn in glob.glob(qm_pattern):
name = os.path.basename(fn)
m = re.match(r'seafile_(.*)\.qm', name)
lang = m.group(1)
add_lang(lang)
for src in qt_qms:
must_copy(src, destdir)
def prepare_msi():
pack_dir = os.path.join(conf[CONF_BUILDDIR], 'pack')
msi_dir = os.path.join(Seafile().projdir, 'msi')
must_copytree(msi_dir, pack_dir)
must_mkdir(os.path.join(pack_dir, 'bin'))
if run('make', cwd=os.path.join(pack_dir, 'custom')) != 0:
error('Error when compiling seafile msi custom dlls')
copy_dll_exe()
def strip_symbols():
bin_dir = os.path.join(conf[CONF_BUILDDIR], 'pack', 'bin')
def do_strip(fn, stripcmd='strip'):
run('%s "%s"' % (stripcmd, fn))
info('stripping: %s' % fn)
for dll in glob.glob(os.path.join(bin_dir, '*.dll')):
name = os.path.basename(dll).lower()
if 'qt' in name:
do_strip(dll)
if name == 'seafile_shell_ext.dll':
do_strip(dll)
elif name == 'seafile_shell_ext64.dll':
do_strip(dll, stripcmd='x86_64-w64-mingw32-strip')
def edit_fragment_wxs():
'''In the main wxs file(seafile.wxs) we need to reference to the id of
seafile-applet.exe, which is listed in fragment.wxs. Since fragments.wxs is
auto generated, the id is sequentially generated, so we need to change the
id of seafile-applet.exe manually.
'''
file_path = os.path.join(conf[CONF_BUILDDIR], 'pack', 'fragment.wxs')
new_lines = []
with open(file_path, 'r') as fp:
for line in fp:
if 'seafile-applet.exe' in line:
# change the id of 'seafile-applet.exe' to 'seafileapplet.exe'
new_line = re.sub('file_bin_[\d]+', 'seafileapplet.exe', line)
new_lines.append(new_line)
else:
new_lines.append(line)
content = '\r\n'.join(new_lines)
with open(file_path, 'w') as fp:
fp.write(content)
def breakpad_enabled():
return conf[CONF_VERSION] >= '5.0.3'
def generate_breakpad_symbols():
seafiledir = Seafile().projdir
script = os.path.join(seafiledir, 'scripts/breakpad.py')
symbol_file = 'seaf-daemon.exe.sym-%s' % conf[CONF_VERSION]
output = os.path.join(seafiledir, symbol_file)
# generate the breakpad symbols
if run('python %s --output %s' % (script, output)) != 0:
error('Error when generating breakpad symbols')
# move symbols to output directory
dst_symbol_file = os.path.join(conf[CONF_OUTPUTDIR], symbol_file)
must_copy(output, dst_symbol_file)
def build_msi():
prepare_msi()
if breakpad_enabled():
generate_breakpad_symbols()
strip_symbols()
pack_dir = os.path.join(conf[CONF_BUILDDIR], 'pack')
if run('make fragment.wxs', cwd=pack_dir) != 0:
error('Error when make fragement.wxs')
edit_fragment_wxs()
if run('make', cwd=pack_dir) != 0:
error('Error when make seafile.msi')
def build_english_msi():
'''The extra work to build the English msi.'''
pack_dir = os.path.join(conf[CONF_BUILDDIR], 'pack')
if run('make en', cwd=pack_dir) != 0:
error('Error when make seafile-en.msi')
def build_german_msi():
'''The extra work to build the German msi.'''
pack_dir = os.path.join(conf[CONF_BUILDDIR], 'pack')
if run('make de', cwd=pack_dir) != 0:
error('Error when make seafile-de.msi')
def move_msi():
pack_dir = os.path.join(conf[CONF_BUILDDIR], 'pack')
src_msi = os.path.join(pack_dir, 'seafile.msi')
brand = conf[CONF_BRAND]
if not conf[CONF_WITH_SHIB]:
dst_msi = os.path.join(conf[CONF_OUTPUTDIR], '%s-%s.msi' % (brand, conf[CONF_VERSION]))
else:
dst_msi = os.path.join(conf[CONF_OUTPUTDIR], '%s-%s-shibboleth.msi' % (brand, conf[CONF_VERSION]))
# move msi to outputdir
must_copy(src_msi, dst_msi)
if not conf[CONF_ONLY_CHINESE]:
src_msi_en = os.path.join(pack_dir, 'seafile-en.msi')
if not conf[CONF_WITH_SHIB]:
dst_msi_en = os.path.join(conf[CONF_OUTPUTDIR], '%s-%s-en.msi' % (brand, conf[CONF_VERSION]))
else:
dst_msi_en = os.path.join(conf[CONF_OUTPUTDIR], '%s-%s-en-shibboleth.msi' % (brand, conf[CONF_VERSION]))
must_copy(src_msi_en, dst_msi_en)
src_msi_de = os.path.join(pack_dir, 'seafile-de.msi')
if not conf[CONF_WITH_SHIB]:
dst_msi_de = os.path.join(conf[CONF_OUTPUTDIR], '%s-%s-de.msi' % (brand, conf[CONF_VERSION]))
else:
dst_msi_de = os.path.join(conf[CONF_OUTPUTDIR], '%s-%s-de-shibboleth.msi' % (brand, conf[CONF_VERSION]))
must_copy(src_msi_de, dst_msi_de)
print '---------------------------------------------'
print 'The build is successfully. Output is:'
print '>>\t%s' % dst_msi
if not conf[CONF_ONLY_CHINESE]:
print '>>\t%s' % dst_msi_en
print '>>\t%s' % dst_msi_de
print '---------------------------------------------'
def check_tools():
tools = [
'Paraffin',
'candle',
'light',
'depends',
]
for prog in tools:
if not find_in_path(prog + '.exe'):
error('%s not found' % prog)
def dump_env():
print 'Dumping environment variables:'
for k, v in os.environ.iteritems():
print '%s: %s' % (k, v)
def main():
dump_env()
parse_args()
setup_build_env()
check_tools()
libsearpc = Libsearpc()
ccnet = Ccnet()
seafile = Seafile()
seafile_client = SeafileClient()
libsearpc.uncompress()
libsearpc.build()
ccnet.uncompress()
ccnet.build()
seafile.uncompress()
seafile.build()
seafile_client.uncompress()
seafile_client.build()
build_msi()
if not conf[CONF_ONLY_CHINESE]:
build_english_msi()
build_german_msi()
move_msi()
if __name__ == '__main__':
main()

View File

@@ -1,396 +0,0 @@
#!/usr/bin/env python
# coding: UTF-8
'''This scirpt builds the seafile debian source tarball. In this tarball,
libsearpc and ccnet is also included.
'''
import sys
####################
### 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)
import os
import tempfile
import glob
import shutil
import re
import subprocess
import optparse
import atexit
####################
### Global variables
####################
# command line configuartion
conf = {}
# key names in the conf dictionary.
CONF_VERSION = 'version'
CONF_LIBSEARPC_VERSION = 'libsearpc_version'
CONF_CCNET_VERSION = 'ccnet_version'
CONF_SEAFILE_VERSION = 'seafile_version'
CONF_SRCDIR = 'srcdir'
CONF_KEEP = 'keep'
CONF_BUILDDIR = 'builddir'
CONF_OUTPUTDIR = 'outputdir'
####################
### 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):
print highlight('[INFO] ') + msg
def exist_in_path(prog):
'''Test whether prog exists in system path'''
dirs = os.environ['PATH'].split(':')
for d in dirs:
if d == '':
continue
path = os.path.join(d, prog)
if os.path.exists(path):
return True
return False
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(argv), cwd if cwd else 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'''
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_mkdir(path):
'''Create a directory, exit on failure'''
try:
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 check_targz_src(proj, version, srcdir):
src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version))
if not os.path.exists(src_tarball):
error('%s not exists' % src_tarball)
def remove_unused_files():
srcdir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION])
web_sh_files = glob.glob(os.path.join(srcdir, 'web', '*.sh'))
files = [
os.path.join(srcdir, 'web', 'pygettext.py'),
]
files.extend(web_sh_files)
for f in files:
run('rm -f %s' % f)
def gen_tarball():
output = os.path.join(conf[CONF_OUTPUTDIR], 'seafile-server-latest.tar.gz')
dirname = 'seafile-%s' % conf[CONF_VERSION]
ignored_patterns = [
# windows msvc dlls
os.path.join(dirname, 'msi', 'bin*'),
]
excludes_list = [ '--exclude=%s' % pattern for pattern in ignored_patterns ]
argv = [
'tar',
'czvf',
output,
dirname,
]
argv.append(*excludes_list)
if run_argv(argv) != 0:
error('failed to gen %s' % output)
print '---------------------------------------------'
print 'The build is successfully. Output is:\t%s' % output
print '---------------------------------------------'
def uncompress_seafile():
src = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_SEAFILE_VERSION])
dst = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION])
if os.path.exists(src):
error('dir %s already exists' % src)
if os.path.exists(dst):
error('dir %s already exists' % dst)
tarball = os.path.join(conf[CONF_SRCDIR], 'seafile-%s.tar.gz' % conf[CONF_SEAFILE_VERSION])
argv = [ 'tar', 'xf',
tarball,
'-C', conf[CONF_BUILDDIR],
]
if run_argv(argv) != 0:
error('failed to uncompress seafile')
if conf[CONF_VERSION] != conf[CONF_SEAFILE_VERSION]:
shutil.move(src, dst)
def uncompress_libsearpc():
tarball = os.path.join(conf[CONF_SRCDIR], 'libsearpc-%s.tar.gz' % conf[CONF_LIBSEARPC_VERSION])
dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'libsearpc')
must_mkdir(dst_dir)
argv = [ 'tar', 'xf',
tarball,
'--strip-components=1',
'-C', dst_dir,
]
if run_argv(argv) != 0:
error('failed to uncompress libsearpc')
def uncompress_ccnet():
tarball = os.path.join(conf[CONF_SRCDIR], 'ccnet-%s.tar.gz' % conf[CONF_CCNET_VERSION])
dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'ccnet')
must_mkdir(dst_dir)
argv = [ 'tar', 'xf',
tarball,
'--strip-components=1',
'-C', dst_dir,
]
if run_argv(argv) != 0:
error('failed to uncompress ccnet')
def remove_debian_subdir():
debian_subdir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'debian')
argv = [ 'rm', '-rf', debian_subdir ]
if run_argv(argv) != 0:
error('failed to uncompress ccnet')
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 of seafile source. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_VERSION),
dest=CONF_SEAFILE_VERSION,
nargs=1,
help='the version of seafile. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_LIBSEARPC_VERSION),
dest=CONF_LIBSEARPC_VERSION,
nargs=1,
help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_CCNET_VERSION),
dest=CONF_CCNET_VERSION,
nargs=1,
help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_BUILDDIR),
dest=CONF_BUILDDIR,
nargs=1,
help='the directory to build the source. Defaults to /tmp',
default=tempfile.gettempdir())
parser.add_option(long_opt(CONF_OUTPUTDIR),
dest=CONF_OUTPUTDIR,
nargs=1,
help='the output directory to put the generated server tarball. Defaults to the current directory.',
default=os.getcwd())
parser.add_option(long_opt(CONF_SRCDIR),
dest=CONF_SRCDIR,
nargs=1,
help='''Source tarballs must be placed in this directory.''')
parser.add_option(long_opt(CONF_KEEP),
dest=CONF_KEEP,
action='store_true',
help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''')
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_SEAFILE_VERSION,
CONF_LIBSEARPC_VERSION,
CONF_CCNET_VERSION,
CONF_SRCDIR,
]
# fist check required args
for optname in required_args:
if getattr(options, optname, None) == 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('^[0-9](\.[0-9])+$', version):
error('%s is not a valid version' % version, usage=usage)
version = get_option(CONF_VERSION)
libsearpc_version = get_option(CONF_LIBSEARPC_VERSION)
ccnet_version = get_option(CONF_CCNET_VERSION)
seafile_version = get_option(CONF_SEAFILE_VERSION)
check_project_version(version)
check_project_version(libsearpc_version)
check_project_version(ccnet_version)
check_project_version(seafile_version)
# [ srcdir ]
srcdir = get_option(CONF_SRCDIR)
check_targz_src('libsearpc', libsearpc_version, srcdir)
check_targz_src('ccnet', ccnet_version, srcdir)
check_targz_src('seafile', seafile_version, srcdir)
# [ builddir ]
builddir = get_option(CONF_BUILDDIR)
if not os.path.exists(builddir):
error('%s does not exist' % builddir, usage=usage)
builddir = os.path.join(builddir, 'seafile-deb-src')
# [ outputdir ]
outputdir = get_option(CONF_OUTPUTDIR)
if not os.path.exists(outputdir):
error('outputdir %s does not exist' % outputdir, usage=usage)
# [ keep ]
keep = get_option(CONF_KEEP)
conf[CONF_VERSION] = version
conf[CONF_LIBSEARPC_VERSION] = libsearpc_version
conf[CONF_CCNET_VERSION] = ccnet_version
conf[CONF_SEAFILE_VERSION] = seafile_version
conf[CONF_BUILDDIR] = builddir
conf[CONF_SRCDIR] = srcdir
conf[CONF_OUTPUTDIR] = outputdir
conf[CONF_KEEP] = keep
prepare_builddir(builddir)
show_build_info()
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)
def show_build_info():
'''Print all conf information. Confirm before continue.'''
info('------------------------------------------')
info('Seafile debian source tarball %s:' % conf[CONF_VERSION])
info('------------------------------------------')
info('seafile: %s' % conf[CONF_SEAFILE_VERSION])
info('ccnet: %s' % conf[CONF_CCNET_VERSION])
info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION])
info('builddir: %s' % conf[CONF_BUILDDIR])
info('outputdir: %s' % conf[CONF_OUTPUTDIR])
info('source dir: %s' % conf[CONF_SRCDIR])
info('clean on exit: %s' % (not conf[CONF_KEEP]))
info('------------------------------------------')
info('press any key to continue ')
info('------------------------------------------')
dummy = raw_input()
def main():
parse_args()
uncompress_seafile()
uncompress_libsearpc()
uncompress_ccnet()
remove_debian_subdir()
remove_unused_files()
gen_tarball()
if __name__ == '__main__':
main()

View File

@@ -14,22 +14,27 @@ a directory before running this script. That directory is passed in as the
'--thirdpartdir' arguments.
'''
from __future__ import print_function
from future import standard_library
standard_library.install_aliases()
from builtins import input
from builtins import object
import sys
####################
### Requires Python 2.6+
####################
if sys.version_info[0] == 3:
print 'Python 3 not supported yet. Quit now.'
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.'
print('Python 2.6 or above is required. Quit now.')
sys.exit(1)
import os
import glob
import commands
import subprocess
import tempfile
import shutil
import re
@@ -72,7 +77,7 @@ def highlight(content, is_error=False):
return '\x1b[1;32m%s\x1b[m' % content
def info(msg):
print highlight('[INFO] ') + msg
print(highlight('[INFO] ') + msg)
def find_in_path(prog):
'''Find a file in system path'''
@@ -88,9 +93,9 @@ def find_in_path(prog):
def error(msg=None, usage=None):
if msg:
print highlight('[ERROR] ') + msg
print(highlight('[ERROR] ') + msg)
if usage:
print usage
print(usage)
sys.exit(1)
def run_argv(argv, cwd=None, env=None, suppress_stdout=False, suppress_stderr=False):
@@ -141,14 +146,14 @@ def must_mkdir(path):
'''Create a directory, exit on failure'''
try:
os.mkdir(path)
except OSError, e:
except OSError as 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:
except Exception as e:
error('failed to copy %s to %s: %s' % (src, dst, e))
class Project(object):
@@ -423,7 +428,7 @@ def show_build_info():
info('------------------------------------------')
info('press any key to continue ')
info('------------------------------------------')
raw_input()
input()
def prepare_builddir(builddir):
must_mkdir(builddir)
@@ -625,7 +630,7 @@ def copy_scripts_and_libs():
dst_update_scriptsdir = os.path.join(serverdir, 'upgrade')
try:
shutil.copytree(update_scriptsdir, dst_update_scriptsdir)
except Exception, e:
except Exception as e:
error('failed to copy upgrade scripts: %s' % e)
# copy sql scripts
@@ -633,7 +638,7 @@ def copy_scripts_and_libs():
dst_sql_scriptsdir = os.path.join(serverdir, 'sql')
try:
shutil.copytree(sql_scriptsdir, dst_sql_scriptsdir)
except Exception, e:
except Exception as e:
error('failed to copy sql scripts: %s' % e)
# copy runtime/seahub.conf
@@ -647,7 +652,7 @@ def copy_scripts_and_libs():
dst_seahubdir = os.path.join(serverdir, 'seahub')
try:
shutil.move(src_seahubdir, dst_seahubdir)
except Exception, e:
except Exception as e:
error('failed to move seahub to seafile-server/seahub: %s' % e)
# copy seahub thirdpart libs
@@ -695,7 +700,7 @@ def get_dependent_libs(executable):
return True
return False
ldd_output = commands.getoutput('ldd %s' % executable)
ldd_output = subprocess.getoutput('ldd %s' % executable)
ret = set()
for line in ldd_output.splitlines():
tokens = line.split()
@@ -763,7 +768,7 @@ def copy_seahub_thirdpart_libs(seahub_thirdpart):
shutil.copytree(src_path, target_path)
else:
shutil.copy(src_path, target_path)
except Exception, e:
except Exception as e:
error('failed to copy seahub thirdpart libs: %s' % e)
def strip_symbols():
@@ -790,7 +795,7 @@ def strip_symbols():
if os.path.islink(fn):
continue
finfo = commands.getoutput('file "%s"' % fn)
finfo = subprocess.getoutput('file "%s"' % fn)
if 'not stripped' in finfo:
do_strip(fn)
@@ -805,7 +810,7 @@ def create_tarball(tarball_name):
# move seafile-server to seafile-server-${version}
try:
shutil.move(serverdir, versioned_serverdir)
except Exception, e:
except Exception as e:
error('failed to move %s to %s: %s' % (serverdir, versioned_serverdir, e))
ignored_patterns = [
@@ -848,7 +853,7 @@ def gen_tarball():
if not conf[CONF_NO_STRIP]:
try:
strip_symbols()
except Exception, e:
except Exception as e:
error('failed to strip symbols: %s' % e)
# determine the output name
@@ -872,18 +877,18 @@ def gen_tarball():
# generate the tarball
try:
create_tarball(tarball_name)
except Exception, e:
except Exception as e:
error('failed to generate tarball: %s' % e)
# move tarball to outputdir
try:
shutil.copy(tarball_name, dst_tarball)
except Exception, e:
except Exception as e:
error('failed to copy %s to %s: %s' % (tarball_name, dst_tarball, e))
print '---------------------------------------------'
print 'The build is successful. Output is:\t%s' % dst_tarball
print '---------------------------------------------'
print('---------------------------------------------')
print('The build is successful. Output is:\t%s' % dst_tarball)
print('---------------------------------------------')
def main():
parse_args()

View File

@@ -1,420 +0,0 @@
#!/usr/bin/env python
# coding: UTF-8
'''This scirpt builds the seafile debian source tarball. In this tarball,
libsearpc and ccnet is also included.
'''
import sys
####################
### 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)
import os
import tempfile
import glob
import shutil
import re
import subprocess
import optparse
import atexit
####################
### Global variables
####################
# command line configuartion
conf = {}
# key names in the conf dictionary.
CONF_VERSION = 'version'
CONF_LIBSEARPC_VERSION = 'libsearpc_version'
CONF_CCNET_VERSION = 'ccnet_version'
CONF_SEAFILE_VERSION = 'seafile_version'
CONF_SEAFILE_CLIENT_VERSION = 'seafile_client_version'
CONF_SRCDIR = 'srcdir'
CONF_KEEP = 'keep'
CONF_BUILDDIR = 'builddir'
CONF_OUTPUTDIR = 'outputdir'
####################
### 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):
print highlight('[INFO] ') + msg
def exist_in_path(prog):
'''Test whether prog exists in system path'''
dirs = os.environ['PATH'].split(':')
for d in dirs:
if d == '':
continue
path = os.path.join(d, prog)
if os.path.exists(path):
return True
return False
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(argv), cwd if cwd else 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'''
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_mkdir(path):
'''Create a directory, exit on failure'''
try:
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 check_targz_src(proj, version, srcdir):
src_tarball = os.path.join(srcdir, '%s-%s.tar.gz' % (proj, version))
if not os.path.exists(src_tarball):
error('%s not exists' % src_tarball)
def remove_unused_files():
srcdir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION])
web_sh_files = glob.glob(os.path.join(srcdir, 'web', '*.sh'))
files = [
os.path.join(srcdir, 'web', 'pygettext.py'),
]
files.extend(web_sh_files)
for f in files:
run('rm -f %s' % f)
def gen_tarball():
output = os.path.join(conf[CONF_OUTPUTDIR], 'seafile-client-latest.tar.gz')
dirname = 'seafile-%s' % conf[CONF_VERSION]
ignored_patterns = [
# windows msvc dlls
os.path.join(dirname, 'msi', 'bin*'),
]
excludes_list = [ '--exclude=%s' % pattern for pattern in ignored_patterns ]
argv = [
'tar',
'czvf',
output,
dirname,
]
argv.append(*excludes_list)
if run_argv(argv) != 0:
error('failed to gen %s' % output)
print '---------------------------------------------'
print 'The build is successfully. Output is:\t%s' % output
print '---------------------------------------------'
def uncompress_seafile():
src = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_SEAFILE_VERSION])
dst = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION])
if os.path.exists(src):
error('dir %s already exists' % src)
if os.path.exists(dst):
error('dir %s already exists' % dst)
tarball = os.path.join(conf[CONF_SRCDIR], 'seafile-%s.tar.gz' % conf[CONF_SEAFILE_VERSION])
argv = [ 'tar', 'xf',
tarball,
'-C', conf[CONF_BUILDDIR],
]
if run_argv(argv) != 0:
error('failed to uncompress seafile')
if conf[CONF_VERSION] != conf[CONF_SEAFILE_VERSION]:
shutil.move(src, dst)
def uncompress_libsearpc():
tarball = os.path.join(conf[CONF_SRCDIR], 'libsearpc-%s.tar.gz' % conf[CONF_LIBSEARPC_VERSION])
dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'libsearpc')
must_mkdir(dst_dir)
argv = [ 'tar', 'xf',
tarball,
'--strip-components=1',
'-C', dst_dir,
]
if run_argv(argv) != 0:
error('failed to uncompress libsearpc')
def uncompress_ccnet():
tarball = os.path.join(conf[CONF_SRCDIR], 'ccnet-%s.tar.gz' % conf[CONF_CCNET_VERSION])
dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'ccnet')
must_mkdir(dst_dir)
argv = [ 'tar', 'xf',
tarball,
'--strip-components=1',
'-C', dst_dir,
]
if run_argv(argv) != 0:
error('failed to uncompress ccnet')
def uncompress_seafile_client():
tarball = os.path.join(conf[CONF_SRCDIR], 'seafile-client-%s.tar.gz' % conf[CONF_SEAFILE_CLIENT_VERSION])
dst_dir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'seafile-client')
must_mkdir(dst_dir)
argv = [ 'tar', 'xf',
tarball,
'--strip-components=1',
'-C', dst_dir,
]
if run_argv(argv) != 0:
error('failed to uncompress ccnet')
def remove_debian_subdir():
debian_subdir = os.path.join(conf[CONF_BUILDDIR], 'seafile-%s' % conf[CONF_VERSION], 'debian')
argv = [ 'rm', '-rf', debian_subdir ]
if run_argv(argv) != 0:
error('failed to uncompress ccnet')
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 of seafile source. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_VERSION),
dest=CONF_SEAFILE_VERSION,
nargs=1,
help='the version of seafile. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_LIBSEARPC_VERSION),
dest=CONF_LIBSEARPC_VERSION,
nargs=1,
help='the version of libsearpc as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_CCNET_VERSION),
dest=CONF_CCNET_VERSION,
nargs=1,
help='the version of ccnet as specified in its "configure.ac". Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_SEAFILE_CLIENT_VERSION),
dest=CONF_SEAFILE_CLIENT_VERSION,
nargs=1,
help='the version of seafile-client. Must be digits delimited by dots, like 1.3.0')
parser.add_option(long_opt(CONF_BUILDDIR),
dest=CONF_BUILDDIR,
nargs=1,
help='the directory to build the source. Defaults to /tmp',
default=tempfile.gettempdir())
parser.add_option(long_opt(CONF_OUTPUTDIR),
dest=CONF_OUTPUTDIR,
nargs=1,
help='the output directory to put the generated server tarball. Defaults to the current directory.',
default=os.getcwd())
parser.add_option(long_opt(CONF_SRCDIR),
dest=CONF_SRCDIR,
nargs=1,
help='''Source tarballs must be placed in this directory.''')
parser.add_option(long_opt(CONF_KEEP),
dest=CONF_KEEP,
action='store_true',
help='''keep the build directory after the script exits. By default, the script would delete the build directory at exit.''')
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_SEAFILE_VERSION,
CONF_LIBSEARPC_VERSION,
CONF_CCNET_VERSION,
CONF_SEAFILE_CLIENT_VERSION,
CONF_SRCDIR,
]
# fist check required args
for optname in required_args:
if getattr(options, optname, None) == 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('^[0-9](\.[0-9])+$', version):
error('%s is not a valid version' % version, usage=usage)
version = get_option(CONF_VERSION)
libsearpc_version = get_option(CONF_LIBSEARPC_VERSION)
ccnet_version = get_option(CONF_CCNET_VERSION)
seafile_version = get_option(CONF_SEAFILE_VERSION)
seafile_client_version = get_option(CONF_SEAFILE_CLIENT_VERSION)
check_project_version(version)
check_project_version(libsearpc_version)
check_project_version(ccnet_version)
check_project_version(seafile_version)
check_project_version(seafile_client_version)
# [ srcdir ]
srcdir = get_option(CONF_SRCDIR)
check_targz_src('libsearpc', libsearpc_version, srcdir)
check_targz_src('ccnet', ccnet_version, srcdir)
check_targz_src('seafile', seafile_version, srcdir)
check_targz_src('seafile-client', seafile_client_version, srcdir)
# [ builddir ]
builddir = get_option(CONF_BUILDDIR)
if not os.path.exists(builddir):
error('%s does not exist' % builddir, usage=usage)
builddir = os.path.join(builddir, 'seafile-deb-src')
# [ outputdir ]
outputdir = get_option(CONF_OUTPUTDIR)
if not os.path.exists(outputdir):
error('outputdir %s does not exist' % outputdir, usage=usage)
# [ keep ]
keep = get_option(CONF_KEEP)
conf[CONF_VERSION] = version
conf[CONF_LIBSEARPC_VERSION] = libsearpc_version
conf[CONF_CCNET_VERSION] = ccnet_version
conf[CONF_SEAFILE_VERSION] = seafile_version
conf[CONF_SEAFILE_CLIENT_VERSION] = seafile_client_version
conf[CONF_BUILDDIR] = builddir
conf[CONF_SRCDIR] = srcdir
conf[CONF_OUTPUTDIR] = outputdir
conf[CONF_KEEP] = keep
prepare_builddir(builddir)
show_build_info()
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)
def show_build_info():
'''Print all conf information. Confirm before continue.'''
info('------------------------------------------')
info('Seafile debian source tarball %s:' % conf[CONF_VERSION])
info('------------------------------------------')
info('seafile: %s' % conf[CONF_SEAFILE_VERSION])
info('seafile-client: %s' % conf[CONF_SEAFILE_CLIENT_VERSION])
info('ccnet: %s' % conf[CONF_CCNET_VERSION])
info('libsearpc: %s' % conf[CONF_LIBSEARPC_VERSION])
info('builddir: %s' % conf[CONF_BUILDDIR])
info('outputdir: %s' % conf[CONF_OUTPUTDIR])
info('source dir: %s' % conf[CONF_SRCDIR])
info('clean on exit: %s' % (not conf[CONF_KEEP]))
info('------------------------------------------')
info('press any key to continue ')
info('------------------------------------------')
dummy = raw_input()
def main():
parse_args()
uncompress_seafile()
uncompress_libsearpc()
uncompress_ccnet()
uncompress_seafile_client()
remove_debian_subdir()
remove_unused_files()
gen_tarball()
if __name__ == '__main__':
main()