~ubuntu-branches/ubuntu/trusty/serf/trusty-proposed

« back to all changes in this revision

Viewing changes to serfmake

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2013-12-31 13:17:16 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: package-import@ubuntu.com-20131231131716-z7lpavv1il3sxb7g
Tags: upstream-1.3.3
ImportĀ upstreamĀ versionĀ 1.3.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
2
 
 
3
 
import os
4
 
import re
5
 
import shutil
6
 
import sys
7
 
import stat
8
 
import copy
9
 
 
10
 
### use get_version() ?
11
 
MAJOR = 1
12
 
 
13
 
# Basic defines for our outputs.
14
 
LIBNAME = 'libserf-%d' % (MAJOR,)
15
 
INCLUDES = 'serf-%d' % (MAJOR,)
16
 
PCFILE = 'serf-%d' % (MAJOR,)
17
 
 
18
 
 
19
 
FILES_HDR = [
20
 
  ('.', 'serf'),
21
 
  ('.', 'serf_bucket_types'),
22
 
  ('.', 'serf_bucket_util'),
23
 
  ]
24
 
 
25
 
LIB_FILES = [
26
 
  ('.', 'context'),
27
 
  ('.', 'incoming'),
28
 
  ('.', 'outgoing'),
29
 
  ('.', 'ssltunnel'),
30
 
 
31
 
  ('buckets', 'aggregate_buckets'),
32
 
  ('buckets', 'request_buckets'),
33
 
  ('buckets', 'buckets'),
34
 
  ('buckets', 'simple_buckets'),
35
 
  ('buckets', 'file_buckets'),
36
 
  ('buckets', 'mmap_buckets'),
37
 
  ('buckets', 'socket_buckets'),
38
 
  ('buckets', 'response_buckets'),
39
 
  ('buckets', 'headers_buckets'),
40
 
  ('buckets', 'allocator'),
41
 
  ('buckets', 'dechunk_buckets'),
42
 
  ('buckets', 'deflate_buckets'),
43
 
  ('buckets', 'limit_buckets'),
44
 
  ('buckets', 'ssl_buckets'),
45
 
  ('buckets', 'barrier_buckets'),
46
 
  ('buckets', 'chunk_buckets'),
47
 
  ('buckets', 'iovec_buckets'),
48
 
  ('auth', 'auth'),
49
 
  ('auth', 'auth_basic'),
50
 
  ('auth', 'auth_digest'),
51
 
  ('auth', 'auth_kerb'),
52
 
  ('auth', 'auth_kerb_gss'),
53
 
  ]
54
 
 
55
 
TEST_DEPS = [
56
 
  ('test', 'CuTest'),
57
 
  ('test', 'test_util'),
58
 
  ('test', 'test_context'),
59
 
  ('test', 'test_buckets'),
60
 
  ('test', 'test_ssl'),
61
 
  ('test/server', 'test_server'),
62
 
  ]
63
 
 
64
 
TEST_HDR_FILES = [
65
 
  ('test', 'CuTest'),
66
 
  ('test', 'test_serf'),
67
 
  ]
68
 
 
69
 
TEST_FILES = [
70
 
  ('test', 'serf_get'),
71
 
  ('test', 'serf_response'),
72
 
  ('test', 'serf_request'),
73
 
  ('test', 'serf_spider'),
74
 
  ('test', 'test_all'),
75
 
  ]
76
 
 
77
 
TESTCASES = [
78
 
  ('test/testcases', 'simple.response'),
79
 
  ('test/testcases', 'chunked-empty.response'),
80
 
  ('test/testcases', 'chunked.response'),
81
 
  ('test/testcases', 'chunked-trailers.response'),
82
 
  ('test/testcases', 'deflate.response'),
83
 
  ]
84
 
 
85
 
 
86
 
def main(argv):
87
 
  params = {}
88
 
 
89
 
  commands = []
90
 
 
91
 
  for arg in argv[1:]:
92
 
    idx = arg.find('=')
93
 
    if idx > 0:
94
 
      start = arg.rfind('-', 0, idx)
95
 
      if start > 0:
96
 
        params[arg[start+1:idx]] = arg[idx+1:].strip()
97
 
    else:
98
 
      func = globals().get('cmd_' + arg)
99
 
      if func:
100
 
        commands.append(func)
101
 
      else:
102
 
        print('ERROR: unknown argument: ' + arg)
103
 
        usage()
104
 
 
105
 
  if not commands:
106
 
    usage()
107
 
 
108
 
  for func in commands:
109
 
    try:
110
 
      func(params)
111
 
    except:
112
 
      print('ERROR: exception:')
113
 
      print(sys.exc_info()[1])
114
 
      print("")
115
 
      usage()
116
 
 
117
 
 
118
 
def usage():
119
 
  ### print something
120
 
  print('serfmake [cmd] [options]')
121
 
  print('Commands:')
122
 
  print('\tbuild\tBuilds (default)')
123
 
  print('\tcheck\tRuns test cases')
124
 
  print('\tinstall\tInstalls serf into PREFIX')
125
 
  print('\tclean\tCleans')
126
 
  print('Options:')
127
 
  print('\t--with-apr=PATH\tprefix for installed APR and APR-util')
128
 
  print('\t\t\t(needs apr-1-config and apu-1-config; will look in PATH)')
129
 
  print('\t--prefix=PATH\tinstall serf into PATH (default: /usr/local)')
130
 
  print('Quick guide:')
131
 
  print('\tserfmake --prefix=/usr/local/serf --with-apr=/usr/local/apr install')
132
 
  sys.exit(1)
133
 
 
134
 
 
135
 
def cmd_build(param):
136
 
  builder = Builder(param)
137
 
  builder.build_target(File('.', LIBNAME, 'la'), False)
138
 
  builder.build_target(File('.', PCFILE, 'pc'), False)
139
 
 
140
 
 
141
 
def cmd_install(param):
142
 
  builder = Builder(param)
143
 
  ### should be called .install_all()
144
 
  builder.install_target(File('.', LIBNAME, 'la'), False)
145
 
 
146
 
 
147
 
def cmd_check(param):
148
 
  builder = Builder(param)
149
 
  for dirpath, fname in TEST_FILES:
150
 
    builder.build_target(File(dirpath, fname, None), False)
151
 
 
152
 
  for dirpath, fname in TESTCASES:
153
 
    case = os.path.join(dirpath, fname)
154
 
    print('== Testing %s ==' % case)
155
 
    result = os.system('%s %s' % (os.path.join('test', 'serf_response'), case))
156
 
    if result:
157
 
      raise TestError("", result)
158
 
 
159
 
  # run the test suite based on the CuTest framework
160
 
  result = os.system(os.path.join('test', 'test_all'))
161
 
  if result:
162
 
    raise TestError(case, result)  
163
 
 
164
 
def cmd_clean(param):
165
 
  targets = [File(dirpath, fname, 'o') for dirpath, fname in LIB_FILES]
166
 
  targets += [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
167
 
  targets += [File('.', LIBNAME, 'la'),
168
 
              File('.', PCFILE, 'pc'),
169
 
              ]
170
 
  targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_FILES]
171
 
  targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_FILES]
172
 
  targets += [File(dirpath, fname, None) for dirpath, fname in TEST_FILES]
173
 
  targets += [File(dirpath, fname, 'o') for dirpath, fname in TEST_DEPS]
174
 
  targets += [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
175
 
 
176
 
  clean = [file for file in targets if file.mtime]
177
 
  if clean:
178
 
    sys.stdout.write('Cleaning %d files... ' % len(clean))
179
 
    for i in clean:
180
 
      if i.mtime:
181
 
        os.remove(i.fname)
182
 
    print('done.')
183
 
  else:
184
 
    print('Clean.')
185
 
 
186
 
 
187
 
class Builder(object):
188
 
  def __init__(self, params):
189
 
    if 'apr' in params:
190
 
      self.apr = APRConfig(params['apr'])
191
 
      self.apu = APUConfig(params['apr'])
192
 
    else:
193
 
      self.apr = APRConfig(None)
194
 
      self.apu = APUConfig(None)
195
 
 
196
 
    try:
197
 
      self.prefix = params['prefix']
198
 
    except:
199
 
      self.prefix = '/usr/local'
200
 
 
201
 
    ### no way to tweak these
202
 
    self.libdir = os.path.join(self.prefix, 'lib')
203
 
    self.pkgconfigdir = os.path.join(self.prefix, 'lib', 'pkgconfig')
204
 
    self.includedir = os.path.join(self.prefix, 'include', INCLUDES)
205
 
 
206
 
    self.load_vars()
207
 
    self.load_deps()
208
 
 
209
 
  def load_vars(self):
210
 
    self.CC = self.apr.get_value('CC', '--cc')
211
 
    self.CFLAGS = self.apr.get_value('CFLAGS', '--cflags')
212
 
    self.CPPFLAGS = self.apr.get_value('CPPFLAGS', '--cppflags')
213
 
    self.LIBTOOL = self.apr.get_value('LIBTOOL', '--apr-libtool')
214
 
    self.LDFLAGS = self.apr.get_value('LDFLAGS', '--ldflags') \
215
 
                   + ' ' + self.apu.get_value('LDFLAGS', '--ldflags')
216
 
 
217
 
    self.INCLUDES = '-I%s -I%s -I%s' % (
218
 
      '.',
219
 
      self.apr.get_value(None, '--includedir'),
220
 
      self.apu.get_value(None, '--includedir'),
221
 
      )
222
 
    if os.getenv('EXTRA_INCLUDES'):
223
 
      self.INCLUDES += ' -I' + os.getenv('EXTRA_INCLUDES')
224
 
 
225
 
    self.LIBS = self.apu.get_value(None, '--link-libtool') \
226
 
                + ' ' + self.apu.get_value(None, '--libs') \
227
 
                + ' ' + self.apr.get_value(None, '--link-libtool') \
228
 
                + ' ' + self.apr.get_value(None, '--libs') \
229
 
                + ' -lz'
230
 
    self.SSL_LIBS = '-lssl -lcrypto'
231
 
 
232
 
    self.MODE = 644
233
 
 
234
 
  def load_deps(self):
235
 
    self.deps = { }
236
 
 
237
 
    hdrs = [File(dirpath, fname, 'h') for dirpath, fname in FILES_HDR]
238
 
    libfiles = [File(dirpath, fname, 'c') for dirpath, fname in LIB_FILES]
239
 
    libobjs = [File(dirpath, fname, 'lo') for dirpath, fname in LIB_FILES]
240
 
    for src, obj in zip(libfiles, libobjs):
241
 
      self._add_compile(src, obj, hdrs)
242
 
 
243
 
    self.hdrs = hdrs
244
 
 
245
 
    all_libs = self.LIBS + ' ' + self.SSL_LIBS
246
 
 
247
 
    lib = File('.', LIBNAME, 'la')
248
 
    cmd = '%s --silent --mode=link %s %s -rpath %s -o %s %s %s' % (
249
 
      self.LIBTOOL, self.CC, self.LDFLAGS, self.libdir,
250
 
      lib.fname, ' '.join([l.fname for l in libobjs]), all_libs)
251
 
    self._add_dep(lib, libobjs, cmd)
252
 
 
253
 
    # load the test program dependencies now
254
 
    testhdrs = copy.deepcopy(hdrs)
255
 
    testhdrs += [File(dirpath, fname, 'h') for dirpath, fname in TEST_HDR_FILES]
256
 
    testdeps = [File(dirpath, fname, 'c') for dirpath, fname in TEST_DEPS]
257
 
    testobjs = [File(dirpath, fname, 'lo') for dirpath, fname in TEST_DEPS]
258
 
 
259
 
    for testsrc, testobj in zip(testdeps, testobjs):
260
 
      self._add_compile(testsrc, testobj, testhdrs)
261
 
 
262
 
    for dirpath, fname in TEST_FILES:
263
 
      src = File(dirpath, fname, 'c')
264
 
      obj = File(dirpath, fname, 'lo')
265
 
      prog = File(dirpath, fname, None)
266
 
 
267
 
      self._add_compile(src, obj, hdrs)
268
 
 
269
 
      # test_all requires extra dependencies
270
 
      if fname == "test_all":
271
 
        cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
272
 
          self.LIBTOOL, self.CC, self.LDFLAGS,
273
 
          prog.fname, lib.fname, ' '.join([l.fname for l in [obj] + testobjs]), 
274
 
          all_libs)
275
 
        self._add_dep(prog, [lib, obj] + testobjs, cmd)
276
 
      else:
277
 
        cmd = '%s --silent --mode=link %s %s -static -o %s %s %s %s' % (
278
 
          self.LIBTOOL, self.CC, self.LDFLAGS,
279
 
          prog.fname, lib.fname, obj.fname, all_libs)
280
 
        self._add_dep(prog, [lib, obj], cmd)
281
 
 
282
 
    # create 'serf-1.pc' if it doesn't exist.
283
 
    pcfile = File('.', PCFILE, 'pc')
284
 
    self._add_dep(pcfile, [], self._write_pcfile)
285
 
 
286
 
  def _add_compile(self, src, obj, hdrs):
287
 
    cmd = '%s --silent --mode=compile %s %s %s %s -c -o %s %s' % (
288
 
      self.LIBTOOL, self.CC, self.CFLAGS, self.CPPFLAGS, self.INCLUDES,
289
 
      obj.fname, src.fname)
290
 
    self._add_dep(obj, [src] + hdrs, cmd)
291
 
 
292
 
  def _add_dep(self, target, deps, cmd):
293
 
    if target.mtime:
294
 
      for dep in deps:
295
 
        if dep in self.deps or (dep.mtime and dep.mtime > target.mtime):
296
 
          # a dep is newer. this needs to be rebuilt.
297
 
          break
298
 
      else:
299
 
        # this is up to date. don't add it to the deps[] structure.
300
 
        return
301
 
    # else non-existent, so it must be rebuilt.
302
 
 
303
 
    # Commands that are strings are cmdline invocations. Otherwise, it
304
 
    # should be a callable.
305
 
    if isinstance(cmd, str):
306
 
      cmd = CommandLine(cmd)
307
 
 
308
 
    # register the dependency so this will get built
309
 
    self.deps[target] = deps, cmd
310
 
 
311
 
  def _write_pcfile(self):
312
 
    """Generating serf-1.pc ..."""
313
 
 
314
 
    open(PCFILE + '.pc', 'w').write(
315
 
"""SERF_MAJOR_VERSION=%d
316
 
prefix=%s
317
 
exec_prefix=${prefix}
318
 
libdir=${exec_prefix}/lib
319
 
includedir=${prefix}/include/%s
320
 
 
321
 
Name: serf
322
 
Description: HTTP client library
323
 
Version: %s
324
 
Requires.private: libssl libcrypto
325
 
Libs: -L${libdir} -lserf-${SERF_MAJOR_VERSION}
326
 
Libs.private: %s
327
 
Cflags: -I${includedir}
328
 
""" % (MAJOR, self.prefix, INCLUDES, get_version(), self.LIBS))
329
 
 
330
 
  def build_target(self, target, dry_run):
331
 
    deps, cmd = self.deps.get(target, (None, None))
332
 
    if cmd is None:
333
 
      # it's already up to date. all done.
334
 
      return
335
 
 
336
 
    for f in deps:
337
 
      subdep = self.deps.get(f)
338
 
      if subdep:
339
 
        self.build_target(f, dry_run)
340
 
 
341
 
    # build the target now
342
 
    print(cmd.__doc__)
343
 
    if not dry_run:
344
 
      result = cmd()
345
 
      if result:
346
 
        raise BuildError(cmd.__doc__, result)
347
 
      # FALLTHROUGH
348
 
 
349
 
    # it's a dry run. pretend we built the target.
350
 
    del self.deps[target]
351
 
    return 0
352
 
 
353
 
  def install_target(self, target, dry_run):
354
 
    self.build_target(target, dry_run)
355
 
 
356
 
    # install the target now
357
 
    if not dry_run:
358
 
 
359
 
      for path in (self.libdir, self.pkgconfigdir, self.includedir):
360
 
        if not os.path.exists(path):
361
 
          try:
362
 
            os.makedirs(path)
363
 
          except OSError:
364
 
            raise BuildError('os.makedirs',
365
 
                             'can not create install directories')
366
 
 
367
 
      for f in self.hdrs:
368
 
        print("Installing: %s" % (os.path.basename(f.fname),))
369
 
        shutil.copy(f.fname, self.includedir)
370
 
 
371
 
      print("Installing: %s.pc" % (PCFILE,))
372
 
      shutil.copy(PCFILE + '.pc', self.pkgconfigdir)
373
 
 
374
 
      cmd = '%s --silent --mode=install %s -c -m %d %s %s' % (
375
 
            self.LIBTOOL, '/usr/bin/install', self.MODE, target.fname,
376
 
            self.libdir)
377
 
 
378
 
      print("Installing: %s" % (os.path.basename(target.fname),))
379
 
      result = os.system(cmd)
380
 
      if result:
381
 
        raise BuildError(cmd, result)
382
 
      # FALLTHROUGH
383
 
 
384
 
    return 0
385
 
 
386
 
 
387
 
class ConfigScript(object):
388
 
  script_name = None
389
 
  locations = [
390
 
    '/usr/bin',
391
 
    '/usr/local/bin',
392
 
    '/usr/local/apache2/bin',
393
 
    ]
394
 
 
395
 
  def __init__(self, search_dir):
396
 
    if search_dir:
397
 
      locations = [search_dir, os.path.join(search_dir, 'bin')]
398
 
    else:
399
 
      locations = self.locations
400
 
 
401
 
    for dirname in locations:
402
 
      bin = os.path.join(dirname, self.script_name)
403
 
      if os.access(bin, os.X_OK):
404
 
        self.bin = bin
405
 
        break
406
 
    else:
407
 
      raise ConfigScriptNotFound(self.script_name)
408
 
 
409
 
  def get_value(self, env_name, switch):
410
 
    if env_name and os.getenv(env_name):
411
 
      return os.getenv(env_name)
412
 
    return os.popen('%s %s' % (self.bin, switch), 'r').read().strip()
413
 
 
414
 
 
415
 
class APRConfig(ConfigScript):
416
 
  script_name = 'apr-1-config'
417
 
 
418
 
 
419
 
class APUConfig(ConfigScript):
420
 
  script_name = 'apu-1-config'
421
 
 
422
 
 
423
 
class CommandLine(object):
424
 
  """Simple helper to invoke a system command when called."""
425
 
 
426
 
  def __init__(self, cmd):
427
 
    self.cmd = cmd
428
 
    self.__doc__ = cmd  # when we print the execution of this command
429
 
 
430
 
  def __call__(self):
431
 
    return os.system(self.cmd)
432
 
 
433
 
 
434
 
class File:
435
 
  def __init__(self, dirpath, fname, ext):
436
 
    if ext:
437
 
      self.fname = os.path.join(dirpath, fname + '.' + ext)
438
 
    else:
439
 
      self.fname = os.path.join(dirpath, fname)
440
 
 
441
 
    try:
442
 
      s = os.stat(self.fname)
443
 
    except OSError:
444
 
      self.mtime = None
445
 
    else:
446
 
      self.mtime = s[stat.ST_MTIME]
447
 
 
448
 
  def __eq__(self, other):
449
 
    return self.fname == other.fname
450
 
 
451
 
  def __hash__(self):
452
 
    return hash(self.fname)
453
 
 
454
 
 
455
 
def get_version():
456
 
  match = re.search('SERF_MAJOR_VERSION ([0-9]+).*'
457
 
                    'SERF_MINOR_VERSION ([0-9]+).*'
458
 
                    'SERF_PATCH_VERSION ([0-9]+)',
459
 
                    open('serf.h').read(),
460
 
                    re.DOTALL)
461
 
  major, minor, patch = match.groups()
462
 
  return '%s.%s.%s' % (major, minor, patch)
463
 
 
464
 
 
465
 
class BuildError(Exception):
466
 
  "An error occurred while building a target."
467
 
class TestError(Exception):
468
 
  "An error occurred while running a unit test."
469
 
class ConfigScriptNotFound(Exception):
470
 
  def __init__(self, value):
471
 
    self.value = "ERROR: A configuration script was not found: " + value
472
 
  def __str__(self):
473
 
    return self.value
474
 
 
475
 
 
476
 
if __name__ == '__main__':
477
 
  main(sys.argv)
478
 
 
479
 
 
480
 
###
481
 
### TODO:
482
 
### * obey DESTDIR
483
 
### * arfrever says LDFLAGS is passed twice
484
 
### * be able to specify libdir and includedir
485
 
###