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:
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
@@ -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()
|
||||
|
@@ -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()
|
Reference in New Issue
Block a user