~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to config/pandora-plugin

fixes to Transforms to make them subselect-compatible

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
 
3
 
#  Copyright (C) 2009 Sun Microsystems, Inc.
4
 
#  Copyright (C) 2010, 2011 Monty Taylor
5
 
#
6
 
#  This program is free software; you can redistribute it and/or modify
7
 
#  it under the terms of the GNU General Public License as published by
8
 
#  the Free Software Foundation; version 2 of the License.
9
 
#
10
 
#  This program is distributed in the hope that it will be useful,
11
 
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
#  GNU General Public License for more details.
14
 
#
15
 
#  You should have received a copy of the GNU General Public License
16
 
#  along with this program; if not, write to the Free Software
17
 
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 
19
 
pandora_plugin_file = 'config/pandora-plugin.ini'
20
 
 
21
 
# Find plugins in the tree and add them to the build system
22
 
 
23
 
import ConfigParser, os, sys
24
 
import datetime, time
25
 
import subprocess
26
 
 
27
 
plugin_am_file=None
28
 
plugin_ac_file=None
29
 
plugin_doc_index=None
30
 
 
31
 
class ChangeProtectedFile(object):
32
 
 
33
 
  def __init__(self, fname):
34
 
    self.bogus_file= False
35
 
    self.real_fname= fname
36
 
    self.new_fname= "%s.new" % fname
37
 
    try:
38
 
      self.new_file= open(self.new_fname,'w+')
39
 
    except IOError:
40
 
      self.bogus_file= True
41
 
 
42
 
  def write(self, text):
43
 
    if not self.bogus_file:
44
 
      self.new_file.write(text)
45
 
 
46
 
  # We've written all of this out into .new files, now we only copy them
47
 
  # over the old ones if they are different, so that we don't cause
48
 
  # unnecessary recompiles
49
 
  def close(self):
50
 
    """Return True if the file had changed."""
51
 
    if self.bogus_file:
52
 
      return
53
 
    self.new_file.seek(0)
54
 
    new_content = self.new_file.read()
55
 
    self.new_file.close()
56
 
    try:
57
 
        old_file = file(self.real_fname, 'r')
58
 
        old_content = old_file.read()
59
 
        old_file.close()
60
 
    except IOError:
61
 
        old_content = None
62
 
    if new_content != old_content:
63
 
      if old_content != None:
64
 
        os.unlink(self.real_fname)
65
 
      os.rename(self.new_fname, self.real_fname)
66
 
      return True
67
 
    else:
68
 
        try:
69
 
          os.unlink(self.new_fname)
70
 
        except:
71
 
          pass
72
 
 
73
 
 
74
 
def write_external_configure(plugin, plugin_file):
75
 
  """Write the initial bits of the configure.ac file"""
76
 
  if not os.path.exists('m4'):
77
 
    os.mkdir('m4')
78
 
  plugin_file.write("""
79
 
AC_PREREQ(2.59)dnl              Minimum Autoconf version required.
80
 
AC_INIT([%(name)s],[%(version)s],[%(url)s])
81
 
AC_CONFIG_SRCDIR([%(main_source)s])
82
 
AC_CONFIG_AUX_DIR(config)
83
 
 
84
 
PANDORA_CANONICAL_TARGET(less-warnings, warnings-always-on, require-cxx, force-gcc42,skip-visibility)
85
 
 
86
 
PANDORA_REQUIRE_LIBPROTOBUF
87
 
PANDORA_PROTOBUF_REQUIRE_VERSION([2.1.0])
88
 
PANDORA_REQUIRE_PROTOC
89
 
 
90
 
AC_LANG_PUSH(C++)
91
 
PANDORA_REQUIRE_PTHREAD
92
 
PANDORA_REQUIRE_LIBDL
93
 
AC_LANG_POP
94
 
 
95
 
PANDORA_USE_BETTER_MALLOC
96
 
 
97
 
PANDORA_DRIZZLE_BUILD
98
 
""" % plugin)
99
 
 
100
 
  write_plugin_ac(plugin, plugin_file)
101
 
 
102
 
  plugin_file.write("""
103
 
AC_CONFIG_FILES(Makefile)
104
 
 
105
 
AC_OUTPUT
106
 
 
107
 
echo "---"
108
 
echo "Configuration summary for $PACKAGE_NAME version $VERSION $PANDORA_RELEASE_COMMENT"
109
 
echo ""
110
 
echo "   * Installation prefix:       $prefix"
111
 
echo "   * System type:               $host_vendor-$host_os"
112
 
echo "   * Host CPU:                  $host_cpu"
113
 
echo "   * C Compiler:                $CC_VERSION"
114
 
echo "   * C++ Compiler:              $CXX_VERSION"
115
 
echo "   * Debug enabled:             $with_debug"
116
 
echo "   * Warnings as failure:       $ac_cv_warnings_as_errors"
117
 
echo "   * C++ cstdint location:      $ac_cv_cxx_cstdint"
118
 
echo "   * C++ hash_map location:     $ac_cv_cxx_hash_map"
119
 
echo "   * C++ hash namespace:        $ac_cv_cxx_hash_namespace"
120
 
echo "   * C++ shared_ptr namespace:  $ac_cv_shared_ptr_namespace"
121
 
echo ""
122
 
echo "---"
123
 
 
124
 
  """ % plugin)
125
 
 
126
 
def write_external_makefile(plugin, plugin_file):
127
 
 
128
 
  plugin_file.write("""
129
 
ACLOCAL_AMFLAGS = -I m4 --force
130
 
VERSION=$(PANDORA_RELEASE_VERSION)
131
 
 
132
 
pkgplugindir=%(pkgplugindir)s
133
 
EXTRA_DIST = plugin.ini
134
 
 
135
 
noinst_HEADERS=
136
 
nobase_include_HEADERS=
137
 
nobase_pkginclude_HEADERS=
138
 
check_PROGRAMS=
139
 
noinst_LTLIBRARIES=
140
 
bin_PROGRAMS=
141
 
 
142
 
 
143
 
""" % plugin)
144
 
  if plugin['headers'] != "":
145
 
    plugin_file.write("noinst_HEADERS += %(headers)s\n" % plugin)
146
 
  if plugin['install_headers'] != "":
147
 
    plugin_file.write("nobase_pkginclude_HEADERS += %(install_headers)s\n" % plugin)
148
 
  if plugin['testsuite']:
149
 
    if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
150
 
      plugin_file.write("EXTRA_DIST += %(testsuitedir)s\n" % plugin)
151
 
  plugin_file.write("""
152
 
pkgplugin_LTLIBRARIES=%(libname)s.la
153
 
%(libname)s_la_LDFLAGS=-avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
154
 
%(libname)s_la_LIBADD=%(libs)s
155
 
%(libname)s_la_DEPENDENCIES=%(libs)s
156
 
%(libname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_DYNAMIC_PLUGIN -DPANDORA_MODULE_NAME=%(module_name)s -DPANDORA_MODULE_AUTHOR='%(author)s' -DPANDORA_MODULE_TITLE='%(title)s' -DPANDORA_MODULE_VERSION='%(version)s' -DPANDORA_MODULE_LICENSE=%(license)s %(cppflags)s
157
 
%(libname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
158
 
%(libname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
159
 
%(libname)s_la_SOURCES=%(sources)s
160
 
check_PROGRAMS += %(tests)s
161
 
""" % plugin)
162
 
  plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
163
 
  if os.path.exists(plugin_am_file):
164
 
    plugin_file.write('include %s\n' % plugin_am_file)
165
 
 
166
 
def write_external_plugin():
167
 
  """Return True if the plugin had changed."""
168
 
  plugin = read_plugin_ini('.')
169
 
  expand_plugin_ini(plugin)
170
 
  plugin_file = ChangeProtectedFile('configure.ac')
171
 
  write_external_configure(plugin, plugin_file)
172
 
  result = plugin_file.close()
173
 
  plugin_file = ChangeProtectedFile('Makefile.am')
174
 
  write_external_makefile(plugin, plugin_file)
175
 
  # Write some stub configure.ac and Makefile.am files that include the above
176
 
  result = plugin_file.close() or result
177
 
  return result
178
 
 
179
 
def write_plugin(plugin, plugin_ini_list):
180
 
  # Since this function is recursive, make sure we're not already in it.
181
 
  if plugin.has_key('writing_status'):
182
 
    if plugin['writing_status'] == 'done':
183
 
      return
184
 
    else:
185
 
      print "Dependency loop detected with %s" % plugin['name']
186
 
      exit(1)
187
 
 
188
 
  plugin['writing_status'] = 'dependencies'
189
 
 
190
 
  # Write all dependencies first to get around annoying automake bug
191
 
  for dependency in plugin['dependency_list']:
192
 
    found = False
193
 
    for find_plugin in plugin_ini_list:
194
 
      if find_plugin['module_name'] == dependency:
195
 
        found = True
196
 
        write_plugin(find_plugin, plugin_ini_list)
197
 
        break
198
 
    if found is False:
199
 
      print "Could not find dependency %s: %s" % (plugin['name'], dependency)
200
 
      exit(1)
201
 
 
202
 
  write_plugin_ac(plugin, plugin_ac_file)
203
 
  write_plugin_am(plugin, plugin_am_file)
204
 
  write_plugin_docs(plugin, plugin_doc_index, plugin_am_file)
205
 
  plugin['writing_status'] = 'done'
206
 
 
207
 
def write_plugin_docs(plugin, doc_index, plugin_am):
208
 
  if plugin['docs'] is not None and os.path.isdir("docs/plugins"):
209
 
    if not os.path.exists(os.path.join("docs/plugins",plugin["name"])):
210
 
      os.symlink(os.path.abspath(plugin["docs"]), os.path.join("docs/plugins",plugin["name"]))
211
 
    doc_index.write("""
212
 
   %(name)s/index""" % plugin)
213
 
    plugin_am.write("""
214
 
EXTRA_DIST+=${top_srcdir}/docs/plugins/%(name)s/*.rst
215
 
""" % plugin)
216
 
 
217
 
def write_plugin_ac(plugin, plugin_ac):
218
 
  #
219
 
  # Write plugin config instructions into plugin.ac file.
220
 
  #
221
 
  plugin_ac_file=os.path.join(plugin['rel_path'],'plugin.ac')
222
 
  plugin_m4_dir=os.path.join(plugin['rel_path'],'m4')
223
 
  plugin_m4_files=[]
224
 
  if os.path.exists(plugin_m4_dir) and os.path.isdir(plugin_m4_dir):
225
 
    for m4_file in os.listdir(plugin_m4_dir):
226
 
      if os.path.splitext(m4_file)[-1] == '.m4':
227
 
        plugin_m4_files.append(os.path.join(plugin['rel_path'], m4_file))
228
 
  plugin_ac.write("""
229
 
dnl Config for %(title)s
230
 
""" % plugin)
231
 
  for m4_file in plugin_m4_files:
232
 
    plugin_ac.write('m4_sinclude([%s])\n' % m4_file)
233
 
  plugin['plugin_dep_libs']=" ".join(["\${top_builddir}/%s" % f for f in plugin['libs'].split()])
234
 
 
235
 
  plugin_ac.write("""
236
 
AC_ARG_WITH([%(name_with_dashes)s-plugin],[
237
 
dnl indented wierd to make the help output correct
238
 
AS_HELP_STRING([--with-%(name_with_dashes)s-plugin],[Build %(title)s. @<:@default=%(enabled)s@:>@])
239
 
AS_HELP_STRING([--without-%(name_with_dashes)s-plugin],[Disable building %(title)s])
240
 
  ],[
241
 
    with_%(name)s_plugin="$withval"
242
 
    AS_IF([test "x$with_%(name)s_plugin" = "xyes"],[
243
 
      requested_%(name)s_plugin="yes"
244
 
    ],[
245
 
      requested_%(name)s_plugin="no"
246
 
    ])
247
 
  ],[
248
 
    with_%(name)s_plugin="%(enabled)s"
249
 
    requested_%(name)s_plugin="no"
250
 
  ])
251
 
AC_ARG_WITH([static-%(name_with_dashes)s-plugin],[
252
 
AS_HELP_STRING([--with-static-%(name_with_dashes)s-plugin],[Build Archive Storage Engine. @<:@default=%(static_yesno)s@:>@])
253
 
AS_HELP_STRING([--without-static-%(name_with_dashes)s-plugin],[Disable building Archive Storage Engine])
254
 
  ],[
255
 
    with_static_%(name)s_plugin=${withval}
256
 
  ],[
257
 
    with_static_%(name)s_plugin=%(static_yesno)s
258
 
])
259
 
AS_IF([test "x${with_static_%(name)s_plugin}" = "xyes" -o "x${with_all_static}" = "xyes"],[
260
 
  shared_%(name)s_plugin=no
261
 
  ],[
262
 
  shared_%(name)s_plugin=yes
263
 
])
264
 
AC_ARG_ENABLE([%(name_with_dashes)s-plugin],[
265
 
dnl indented wierd to make the help output correct
266
 
AS_HELP_STRING([--enable-%(name_with_dashes)s-plugin],[Enable loading %(title)s by default. @<:@default=%(default_yesno)s@:>@])
267
 
AS_HELP_STRING([--disable-%(name_with_dashes)s-plugin],[Disable loading %(title)s by default.])
268
 
  ],
269
 
  [enable_%(name)s_plugin="$enableval"],
270
 
  [enable_%(name)s_plugin=%(default_yesno)s])
271
 
 
272
 
""" % plugin)
273
 
  if os.path.exists(plugin_ac_file):
274
 
    plugin_ac.write('m4_sinclude([%s])\n' % plugin_ac_file)
275
 
  # The plugin author has specified some check to make to determine
276
 
  # if the plugin can be built. If the plugin is turned on and this
277
 
  # check fails, then configure should error out. If the plugin is not
278
 
  # turned on, then the normal conditional build stuff should just let
279
 
  # it silently not build
280
 
  if plugin['has_build_conditional']:
281
 
    plugin_ac.write("""
282
 
AS_IF([test %(build_conditional)s],
283
 
      [], dnl build_conditional can only negate
284
 
      [
285
 
        AS_IF([test "x${requested_%(name)s_plugin}" = "xyes"],
286
 
              [AC_MSG_ERROR([Plugin %(name)s was explicitly requested, yet failed build dependency checks. Aborting!])])
287
 
        with_%(name)s_plugin=no
288
 
      ])
289
 
 
290
 
""" % plugin)
291
 
  if not plugin['unconditional']:
292
 
    plugin_ac.write("""
293
 
AM_CONDITIONAL([%(static_build_conditional_tag)s],
294
 
               [test %(build_conditional)s -a ! %(shared_build)s])
295
 
AM_CONDITIONAL([%(shared_build_conditional_tag)s],
296
 
               [test %(build_conditional)s -a %(shared_build)s])
297
 
AM_CONDITIONAL([%(build_conditional_tag)s],
298
 
               [test %(build_conditional)s])
299
 
    """ % plugin)
300
 
 
301
 
  plugin_ac.write("""
302
 
AS_IF([test "x$with_%(name)s_plugin" = "xyes"],[
303
 
""" % plugin)
304
 
  if plugin['testsuite']:
305
 
    plugin_ac.write("""
306
 
      pandora_plugin_test_list="%(name)s,${pandora_plugin_test_list}"
307
 
    """ % plugin)
308
 
  plugin_ac.write("""
309
 
      AS_IF([test "x${with_static_%(name)s_plugin}" = "xyes" -o "x${with_all_static}" = "xyes"],[
310
 
 
311
 
        AS_IF([test "x$enable_%(name)s_plugin" = "xyes"],[
312
 
          pandora_builtin_load_list="%(module_name)s,${pandora_builtin_load_list}"
313
 
          pandora_builtin_load_symbols_list="_drizzled_%(module_name)s_plugin_,${pandora_builtin_load_symbols_list}"
314
 
          PANDORA_PLUGIN_DEP_LIBS="${PANDORA_PLUGIN_DEP_LIBS} %(plugin_dep_libs)s"
315
 
        ])
316
 
        pandora_builtin_list="%(module_name)s,${pandora_builtin_list}"
317
 
        pandora_builtin_symbols_list="_drizzled_%(module_name)s_plugin_,${pandora_builtin_symbols_list}"
318
 
        pandora_plugin_libs="${pandora_plugin_libs} \${top_builddir}/%(root_plugin_dir)s/%(libname)s.la"
319
 
     ],[
320
 
        AS_IF([test "x$enable_%(name)s_plugin" = "xyes"],[
321
 
          pandora_default_plugin_list="%(name)s,${pandora_default_plugin_list}"
322
 
        ])
323
 
    ])
324
 
    """ % plugin)
325
 
  plugin_ac.write("])\n")
326
 
 
327
 
def fix_file_paths(plugin, files):
328
 
  # TODO: determine path to plugin dir relative to top_srcdir... append it to
329
 
  # source files if they don't already have it
330
 
  new_files=""
331
 
  if plugin['plugin_dir'] != ".":
332
 
    for file in files.split():
333
 
      if not file.startswith(plugin['rel_path']):
334
 
        file= os.path.join(plugin['rel_path'], file)
335
 
        new_files= "%s %s" % (new_files, file)
336
 
  else:
337
 
    new_files= " ".join(plugin['sources'].split())
338
 
  if new_files != "":
339
 
    return new_files
340
 
  return files
341
 
 
342
 
def expand_plugin_ini(plugin):
343
 
    if plugin['name'] == "**OUT-OF-TREE**":
344
 
      print "Out of tree plugins require the name field to be specified in plugin.ini"
345
 
      sys.exit(1)
346
 
 
347
 
    if plugin['plugin_dir'] == ".":
348
 
      plugin['rel_path']= plugin['plugin_dir']
349
 
      plugin['unconditional']=True
350
 
    else:
351
 
      plugin['rel_path']= plugin['plugin_dir'][len(config['top_srcdir'])+len(os.path.sep):]
352
 
      plugin['unconditional']=False
353
 
 
354
 
    plugin['sources']= fix_file_paths(plugin, plugin['sources'])
355
 
    plugin['main_source']= plugin['sources'].split()[0]
356
 
    plugin['headers']= fix_file_paths(plugin, plugin['headers'])
357
 
    plugin['install_headers']= fix_file_paths(plugin, plugin['install_headers'])
358
 
    plugin['tests']= fix_file_paths(plugin, plugin['tests'])
359
 
 
360
 
    # Make a yes/no version for autoconf help messages
361
 
    if plugin['load_by_default']:
362
 
      plugin['default_yesno']="yes"
363
 
    else:
364
 
      plugin['default_yesno']="no"
365
 
 
366
 
    if plugin.has_key('extra_dist'):
367
 
      plugin['extra_dist']=" ".join([os.path.join(plugin['rel_path'],f) for f in plugin['extra_dist'].split()])
368
 
 
369
 
 
370
 
    if plugin['static']:
371
 
      plugin['static_yesno']="yes"
372
 
    else:
373
 
      plugin['static_yesno']="no"
374
 
    plugin['build_conditional_tag']= "BUILD_%s_PLUGIN" % plugin['name'].upper()
375
 
    plugin['shared_build_conditional_tag']= "BUILD_%s_PLUGIN_SHARED" % plugin['name'].upper()
376
 
    plugin['static_build_conditional_tag']= "BUILD_%s_PLUGIN_STATIC" % plugin['name'].upper()
377
 
    plugin['name_with_dashes']= plugin['name'].replace('_','-')
378
 
    if plugin.has_key('build_conditional'):
379
 
      plugin['has_build_conditional']=True
380
 
      plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes" -a %(build_conditional)s' % plugin
381
 
    else:
382
 
      plugin['has_build_conditional']=False
383
 
      plugin['build_conditional']='"x${with_%(name)s_plugin}" = "xyes"' %plugin
384
 
    plugin['shared_build']='"x${shared_%(name)s_plugin}" = "xyes"' %plugin
385
 
 
386
 
    if plugin['install']:
387
 
      plugin['library_type']= 'pkgplugin'
388
 
    else:
389
 
      plugin['library_type']= 'noinst'
390
 
 
391
 
def find_testsuite(plugin_dir):
392
 
  for testdir in ['drizzle-tests','tests']:
393
 
    if os.path.isdir(os.path.join(plugin_dir,testdir)):
394
 
      return testdir
395
 
  if os.path.isdir(os.path.join('tests','suite',os.path.basename(plugin_dir))):
396
 
    return ""
397
 
  return None
398
 
 
399
 
def find_docs(plugin_dir):
400
 
  if os.path.isfile(os.path.join(plugin_dir, "docs", "index.rst")):
401
 
    return os.path.join(plugin_dir, "docs")
402
 
 
403
 
def read_plugin_ini(plugin_dir):
404
 
    sources_default=""
405
 
    if plugin_dir == ".":
406
 
      plugin_name="**OUT-OF-TREE**"
407
 
      module_name="**OUT-OF-TREE**"
408
 
    else:
409
 
      sources_default="%s.cc" % os.path.basename(plugin_dir)
410
 
      plugin_name = plugin_dir[plugin_dir.index(config['root_plugin_dir']) + len(config['root_plugin_dir']) + 1:]
411
 
      module_name = plugin_name.replace("/", config['module_name_separator']).replace("\\", config['module_name_separator'])
412
 
      plugin_name = plugin_name.replace("/", config['plugin_name_separator']).replace("\\", config['plugin_name_separator'])
413
 
 
414
 
 
415
 
    plugin_file= os.path.join(plugin_dir,config['plugin_ini_fname'])
416
 
    plugin_defaults= dict(sources=sources_default,
417
 
                          headers="",
418
 
                          install_headers="",
419
 
                          cflags="",
420
 
                          cppflags="",
421
 
                          cxxflags="",
422
 
                          libs="",
423
 
                          ldflags="",
424
 
                          author="",
425
 
                          title="",
426
 
                          description="",
427
 
                          license="PLUGIN_LICENSE_GPL",
428
 
                          name=plugin_name,
429
 
                          module_name=module_name,
430
 
                          load_by_default=config['default_load_by_default'],
431
 
                          disabled="False",
432
 
                          static="False",
433
 
                          dependencies="",
434
 
                          dependency_aliases="",
435
 
                          tests="",
436
 
                          install=config['default_install'])
437
 
    parser=ConfigParser.ConfigParser(defaults= plugin_defaults)
438
 
    parser.read(plugin_file)
439
 
    plugin=dict(parser.items('plugin'))
440
 
    plugin['plugin_dir'] = plugin_dir
441
 
    if plugin_dir == '.':
442
 
      if not plugin.has_key('url'):
443
 
        print "External Plugins are required to specifiy a url"
444
 
        plugin['url']= 'http://launchpad.net/%(name)s' % plugin
445
 
        sys.exit(1)
446
 
      if plugin_dir == '.' and not plugin.has_key('version'):
447
 
        print "External Plugins are required to specifiy a version"
448
 
        sys.exit(1)
449
 
    if not plugin.has_key('version'):
450
 
      plugin['version'] = config['default_plugin_version']
451
 
    if plugin.has_key('load_by_default'):
452
 
      plugin['load_by_default']=parser.getboolean('plugin','load_by_default')
453
 
    if plugin.has_key('disabled'):
454
 
      plugin['disabled']=parser.getboolean('plugin','disabled')
455
 
    if plugin['disabled']:
456
 
      plugin['enabled']="no"
457
 
    else:
458
 
      plugin['enabled']="yes"
459
 
    if plugin.has_key('static'):
460
 
      try:
461
 
        plugin['static']= parser.getboolean('plugin','static')
462
 
      except:
463
 
        if plugin['static'][:5] == os.sys.platform[:5]:
464
 
          plugin['static']= True
465
 
        else:
466
 
          plugin['static']= False
467
 
    if plugin.has_key('install'):
468
 
      plugin['install']= parser.getboolean('plugin','install')
469
 
    if plugin.has_key('testsuite'):
470
 
      if plugin['testsuite'] == 'disable':
471
 
        plugin['testsuite']= False
472
 
        plugin['dist_testsuite']= find_testsuite(plugin_dir)
473
 
    else:
474
 
      plugin_testsuite= find_testsuite(plugin_dir)
475
 
      plugin['testsuitedir']=plugin_testsuite
476
 
      if plugin_testsuite is not None:
477
 
        plugin['testsuite']=True
478
 
      else:
479
 
        plugin['testsuite']=False
480
 
    plugin['docs']= find_docs(plugin_dir)
481
 
 
482
 
    plugin['cflags']+= ' ' + config['extra_cflags']
483
 
    plugin['cppflags']+= ' ' + config['extra_cppflags']
484
 
    plugin['cxxflags']+= ' ' + config['extra_cxxflags']
485
 
 
486
 
    plugin['libname']= "lib%s%s%s" % (config['plugin_prefix'],
487
 
                                      plugin['name'],
488
 
                                      config['plugin_suffix'])
489
 
    if config['force_lowercase_libname']:
490
 
      plugin['libname']= plugin['libname'].lower()
491
 
 
492
 
    plugin['root_plugin_dir']= config['root_plugin_dir']
493
 
    plugin['plugin_prefix']= config['plugin_prefix']
494
 
    plugin['plugin_suffix']= config['plugin_suffix']
495
 
    plugin['pkgplugindir']= config['pkgplugindir']
496
 
 
497
 
    # Dependencies must have a module but dependency aliases are simply added
498
 
    # to the variable passed during compile.
499
 
    plugin['dependency_list'] = plugin['dependencies'].split()
500
 
    dependency_aliases = plugin['dependency_aliases'].split()
501
 
    plugin['dependencies'] = ','.join(plugin['dependency_list'] +
502
 
                                      plugin['dependency_aliases'].split())
503
 
    dependency_libs = ["%s/lib%s%s.la" % (config['root_plugin_dir'],
504
 
                                          dependency.lower().replace('::', '_'),
505
 
                                          config['plugin_suffix'])
506
 
                       for dependency in plugin['dependency_list']]
507
 
    plugin['libs'] = " ".join(plugin['libs'].split() + dependency_libs);
508
 
 
509
 
# Libtool is going to expand:
510
 
#      -DPANDORA_MODULE_AUTHOR='"Padraig O'"'"'Sullivan"'
511
 
# to:
512
 
# "-DPANDORA_MODULE_AUTHOR=\"Padraig O'Sullivan\""
513
 
# So we have to replace internal ''s to '"'"'
514
 
    for key in ('author','title','description','version'):
515
 
      plugin[key]=plugin[key].replace('"','\\"')
516
 
      plugin[key]=plugin[key].replace("'","'\"'\"'")
517
 
    return plugin
518
 
 
519
 
 
520
 
def write_plugin_am(plugin, plugin_am):
521
 
  """Write an automake fragment for this plugin.
522
 
 
523
 
  :param plugin: The plugin dict.
524
 
  :param plugin_am: The file to write to.
525
 
  """
526
 
  # The .plugin.ini.stamp avoids changing the datestamp on plugin.ini which can
527
 
  # confuse VCS systems.
528
 
  plugin_am.write("""
529
 
EXTRA_DIST += %(rel_path)s/plugin.ini
530
 
 
531
 
# Prevent errors when a plugin dir is removed
532
 
%(rel_path)s/plugin.ini:
533
 
 
534
 
""" % plugin)
535
 
  if plugin.has_key('extra_dist') and plugin['extra_dist'] != "":
536
 
    plugin_am.write("EXTRA_DIST += %(extra_dist)s\n" % plugin)
537
 
  if plugin['headers'] != "":
538
 
    plugin_am.write("noinst_HEADERS += %(headers)s\n" % plugin)
539
 
  if plugin['install_headers'] != "":
540
 
    plugin_am.write("nobase_pkginclude_HEADERS += %(install_headers)s\n" % plugin)
541
 
  if plugin['testsuite']:
542
 
    if plugin.has_key('testsuitedir') and plugin['testsuitedir'] != "":
543
 
      plugin_am.write("EXTRA_DIST += %(rel_path)s/%(testsuitedir)s\n" % plugin)
544
 
  if plugin.has_key('dist_testsuite') and plugin['dist_testsuite'] != "":
545
 
    plugin_am.write("EXTRA_DIST += %(rel_path)s/%(dist_testsuite)s\n" % plugin)
546
 
  if plugin['docs'] is not None:
547
 
    plugin_am.write("EXTRA_DIST += ${top_srcdir}/%(rel_path)s/docs/*.rst\n" % plugin)
548
 
  plugin_am.write("""
549
 
%(root_plugin_dir)s_%(plugin_prefix)s%(name)s_dir=${top_srcdir}/%(rel_path)s
550
 
# Include sources in EXTRA_DIST because we might not build this, but we
551
 
# still want the sources to wind up in a tarball
552
 
EXTRA_DIST += %(rel_path)s/plugin.ini %(sources)s
553
 
if %(static_build_conditional_tag)s
554
 
  noinst_LTLIBRARIES+=%(root_plugin_dir)s/%(libname)s.la
555
 
  %(root_plugin_dir)s_%(libname)s_la_LIBADD=%(libs)s
556
 
  %(root_plugin_dir)s_%(libname)s_la_DEPENDENCIES=%(libs)s
557
 
  %(root_plugin_dir)s_%(libname)s_la_LDFLAGS=$(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
558
 
  %(root_plugin_dir)s_%(libname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_MODULE_NAME=%(module_name)s -DPANDORA_MODULE_AUTHOR='%(author)s' -DPANDORA_MODULE_TITLE='%(title)s' -DPANDORA_MODULE_VERSION='%(version)s' -DPANDORA_MODULE_LICENSE=%(license)s -DPANDORA_MODULE_DEPENDENCIES='%(dependencies)s' %(cppflags)s
559
 
  %(root_plugin_dir)s_%(libname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
560
 
  %(root_plugin_dir)s_%(libname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
561
 
  %(root_plugin_dir)s_%(libname)s_la_SOURCES=%(sources)s
562
 
  check_PROGRAMS += %(tests)s
563
 
  PANDORA_DYNAMIC_LDADDS+=${top_builddir}/%(root_plugin_dir)s/%(libname)s.la
564
 
endif
565
 
EXTRA_DIST += %(rel_path)s/plugin.ini
566
 
if %(shared_build_conditional_tag)s
567
 
  %(library_type)s_LTLIBRARIES+=%(root_plugin_dir)s/%(libname)s.la
568
 
  %(root_plugin_dir)s_%(libname)s_la_LDFLAGS=-avoid-version -rpath $(pkgplugindir) $(AM_LDFLAGS) %(ldflags)s $(GCOV_LIBS)
569
 
  %(root_plugin_dir)s_%(libname)s_la_LIBADD=%(libs)s
570
 
  %(root_plugin_dir)s_%(libname)s_la_DEPENDENCIES=%(libs)s
571
 
  %(root_plugin_dir)s_%(libname)s_la_CPPFLAGS=$(AM_CPPFLAGS) -DPANDORA_DYNAMIC_PLUGIN -DPANDORA_MODULE_NAME=%(module_name)s -DPANDORA_MODULE_AUTHOR='%(author)s' -DPANDORA_MODULE_TITLE='%(title)s' -DPANDORA_MODULE_VERSION='%(version)s' -DPANDORA_MODULE_LICENSE=%(license)s -DPANDORA_MODULE_DEPENDENCIES='%(dependencies)s' %(cppflags)s
572
 
  %(root_plugin_dir)s_%(libname)s_la_CXXFLAGS=$(AM_CXXFLAGS) %(cxxflags)s
573
 
  %(root_plugin_dir)s_%(libname)s_la_CFLAGS=$(AM_CFLAGS) %(cflags)s
574
 
  %(root_plugin_dir)s_%(libname)s_la_SOURCES=%(sources)s
575
 
  check_PROGRAMS += %(tests)s
576
 
endif
577
 
""" % plugin)
578
 
  plugin_am_file=os.path.join(plugin['rel_path'],'plugin.am')
579
 
  if os.path.exists(plugin_am_file):
580
 
    plugin_am.write('include %s\n' % plugin_am_file)
581
 
 
582
 
#
583
 
# MAIN STARTS HERE:
584
 
#
585
 
 
586
 
# Parse the pandora-plugin config file
587
 
 
588
 
config_defaults= dict(
589
 
  top_srcdir='.',
590
 
  top_builddir='.',
591
 
  plugin_ini_fname='plugin.ini',
592
 
  plugin_prefix='',
593
 
  plugin_suffix='',
594
 
  extra_cflags='',
595
 
  extra_cppflags='',
596
 
  extra_cxxflags='',
597
 
  root_plugin_dir='',
598
 
  pkgplugindir='',
599
 
  default_install='True',
600
 
  default_plugin_version='',
601
 
  default_load_by_default='False',
602
 
  force_lowercase_libname='True',
603
 
  plugin_name_separator='_',
604
 
  module_name_separator='::'
605
 
)
606
 
 
607
 
config_parser = ConfigParser.ConfigParser(defaults=config_defaults)
608
 
config_parser.read(pandora_plugin_file)
609
 
config = dict(config_parser.items('pandora-plugin'))
610
 
config['force_lowercase_libname']=config_parser.getboolean('pandora-plugin','force_lowercase_libname')
611
 
 
612
 
# I'm 3 seconds away from writing a comprehensive build solution
613
 
if not os.path.exists('config/pandora_vc_revinfo'):
614
 
  if os.path.exists('.bzr'):
615
 
    bzr_revno= subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE).communicate()[0].strip()
616
 
    rev_date= datetime.date.fromtimestamp(time.time())
617
 
    config['default_plugin_version'] = "%d.%02d.%s" % (rev_date.year, rev_date.month, bzr_revno)
618
 
  else:
619
 
    config['default_plugin_version']=datetime.date.fromtimestamp(time.time()).isoformat()
620
 
else:
621
 
  # need to read config/pandora_vc_revno
622
 
  pandora_vc_revno=open('config/pandora_vc_revinfo','r').read().split()
623
 
  rev_date=""
624
 
  bzr_revno=""
625
 
  for revno_line in pandora_vc_revno:
626
 
    (revno_key,revno_val)= revno_line.split("=")
627
 
    if revno_key == 'PANDORA_VC_REVNO':
628
 
      bzr_revno=revno_val.strip()
629
 
    elif revno_key == 'PANDORA_RELEASE_DATE':
630
 
      rev_date=revno_val.strip()
631
 
 
632
 
  config['default_plugin_version'] = "%s.%s" % (rev_date, bzr_revno)
633
 
 
634
 
actions=[]
635
 
for arg in sys.argv:
636
 
  if arg.startswith('--top_srcdir='):
637
 
    config['top_srcdir']=arg[12:]
638
 
  elif arg.startswith('--top_builddir='):
639
 
    config['top_builddir']=arg[14:]
640
 
  elif arg == "--force-all":
641
 
    actions=['plugin-list','pandora-plugin.am','write']
642
 
    break
643
 
  else:
644
 
    actions.append(arg)
645
 
if len(actions) == 0:
646
 
  actions.append('write')
647
 
 
648
 
plugin_list=[]
649
 
 
650
 
def accumulate_plugins(arg, dirname, fnames):
651
 
  # plugin_ini_fname is a name in dirname indicating dirname is a plugin.
652
 
  if config['plugin_ini_fname'] in fnames:
653
 
    arg.append(dirname)
654
 
 
655
 
os.path.walk(os.path.join(config['top_srcdir'],
656
 
                          config['root_plugin_dir']),
657
 
             accumulate_plugins,
658
 
             plugin_list)
659
 
 
660
 
if not os.path.exists("config/pandora-plugin.am") or "write" in actions:
661
 
  plugin_am_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.am'))
662
 
  plugin_am_file.write("""
663
 
# always the current list, generated every build so keep this lean.
664
 
# pandora-plugin.list: datestamp preserved list
665
 
${srcdir}/config/pandora-plugin.list: .plugin.scan
666
 
.plugin.scan:
667
 
        @cd ${top_srcdir} && python config/pandora-plugin plugin-list
668
 
 
669
 
# Plugins affect configure; so to prevent configure running twice in a tarball
670
 
# build (once up front, once with the right list of plugins, we ship the
671
 
# generated list of plugins and the housekeeping material for that list so it
672
 
# is likewise not updated.
673
 
EXTRA_DIST += \
674
 
        config/pandora-plugin.am \
675
 
        config/pandora-plugin.ac \
676
 
        config/pandora-plugin \
677
 
        config/pandora-plugin.ini
678
 
 
679
 
 
680
 
# Seed the list of plugin LDADDS which plugins may extend.
681
 
PANDORA_DYNAMIC_LDADDS=
682
 
 
683
 
# plugin.stamp: graph dominator for creating all per pandora-plugin.ac/am
684
 
# files. This is invoked when the code to generate such files has altered.""")
685
 
 
686
 
if not os.path.exists("config/pandora-plugin.ac") or "write" in actions:
687
 
  plugin_ac_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.ac'))
688
 
  plugin_ac_file.write("dnl Generated file, run make to rebuild\n")
689
 
  plugin_ac_file.write("""
690
 
AC_ARG_WITH([all-static],[
691
 
AS_HELP_STRING([--with-all-static],[Link all plugins staticly into the server @<:@default=no@:>@])
692
 
],[
693
 
    with_all_static="$withval"
694
 
    ],[
695
 
    with_all_static=no
696
 
])
697
 
  """)
698
 
 
699
 
if os.path.exists("docs/plugins"):
700
 
  if not os.path.exists("docs/plugins/list.rst") or "write" in actions:
701
 
    plugin_doc_index = ChangeProtectedFile("docs/plugins/list.rst")
702
 
    plugin_doc_index.write("""
703
 
Plugin Documentation
704
 
====================
705
 
 
706
 
.. toctree::
707
 
   :maxdepth: 2
708
 
""")
709
 
 
710
 
 
711
 
if os.path.exists('plugin.ini'):
712
 
  # Are we in a plugin dir which wants to have a self-sufficient build system?
713
 
  plugin_list=['.']
714
 
 
715
 
  write_external_plugin()
716
 
else:
717
 
  plugin_list_file = ChangeProtectedFile(os.path.join('config', 'pandora-plugin.list'))
718
 
  for p in plugin_list:
719
 
    plugin_list_file.write(p)
720
 
    plugin_list_file.write("\n")
721
 
  plugin_list.sort()
722
 
  plugin_list_file.close()
723
 
 
724
 
if not os.path.exists("config/pandora-plugin.am") or 'write' in actions:
725
 
  plugin_am_file.write("\n${top_srcdir}/config/pandora-plugin.am: ${top_srcdir}/config/pandora-plugin.list ${top_srcdir}/config/pandora-plugin ")
726
 
  for plugin_dir in plugin_list:
727
 
    plugin_am_file.write("\\\n\t%s/plugin.ini " % plugin_dir)
728
 
  plugin_am_file.write("\n\tcd ${top_srcdir} && python config/pandora-plugin write\n")
729
 
  plugin_ini_list=[]
730
 
 
731
 
  # Load all plugin.ini files first so we can do dependency tracking.
732
 
  for plugin_dir in plugin_list:
733
 
    plugin = read_plugin_ini(plugin_dir)
734
 
    expand_plugin_ini(plugin)
735
 
    plugin_ini_list.append(plugin)
736
 
 
737
 
  # Check for duplicates
738
 
  plugin_name_list = [plugin['libname'] for plugin in plugin_ini_list]
739
 
  for plugin in plugin_ini_list:
740
 
    if plugin_name_list.count(plugin['libname']) != 1:
741
 
      print "Duplicate module name %s" % plugin['libname']
742
 
      exit(1)
743
 
 
744
 
  for plugin in plugin_ini_list:
745
 
    write_plugin(plugin, plugin_ini_list)
746
 
 
747
 
if plugin_am_file is not None:
748
 
  plugin_am_file.close()
749
 
if plugin_ac_file is not None:
750
 
  plugin_ac_file.close()
751
 
if plugin_doc_index is not None:
752
 
  plugin_doc_index.close()