# ============================================================================
#
# Copyright (C) 2007-2011 Conceptive Engineering bvba. All rights reserved.
# www.conceptive.be / project-camelot@conceptive.be
#
# This file is part of the Camelot Library.
#
# This file may be used under the terms of the GNU General Public
# License version 2.0 as published by the Free Software Foundation
# and appearing in the file license.txt included in the packaging of
# this file. Please review this information to ensure GNU
# General Public Licensing requirements will be met.
#
# If you are unsure which license is appropriate for your use, please
# visit www.python-camelot.com or contact project-camelot@conceptive.be
#
# This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# For use of this library in commercial applications, please contact
# project-camelot@conceptive.be
#
# ============================================================================
import logging
from optparse import OptionParser
from camelot.core.conf import settings
logging.basicConfig()
#
# Description of the application, out of which the help text as well as the
# __doc__ strings can be generated
#
description = """camelot_admin is a tool to assist in the creation and development of Camelot
projects. Use this application without any options to start a GUI to create
a new Camelot project.
"""
usage = "usage: %prog [options] command"
command_description = [
('startproject', """Starts a new project, use startproject project_name.
"""),
('makemessages', """Outputs a message file with all field names of all
entities. This command requires settings.py of the project to be in the
PYTHONPATH"""),
('apidoc', """Extract API documentation from source code, to be used
with sphinx.
"""),
('license_update', """Change the license header of a project,
use license_update project_directory license_file"""),
('to_pyside', """Takes a folder with PyQt4 source code and translates it to
PySide source code. A directory to_pyside will be created containing the
output of the translation"""),
]
#
# Generate a docstring in restructured text format
#
__doc__ = description
for command, desc in command_description:
__doc__ += "\n.. cmdoption:: %s\n\n" % command
for line in desc.split('\n'):
__doc__ += " %s\n" % line
#
# A custom OptionParser that generates help information on the commands
#
[docs]class CommandOptionParser(OptionParser):
[docs]def apidoc(source, destination):
import os
def is_module_directory( dirname ):
""":return: True if the directory is a python module, False otherwise"""
if not os.path.isdir( dirname ):
return False
if os.path.basename( dirname ).startswith( '.' ):
return False
return os.path.exists( os.path.join( dirname, '__init__.py' ) )
def document_directory(_arg, dirname, names):
"""create .rst files for a directory of source files"""
if is_module_directory( dirname ):
targetdir = os.path.join( destination, dirname[len(source)+1:] )
if not os.path.exists( targetdir ):
os.makedirs( targetdir )
srcs = [n for n in names if n.endswith('.py') and not n.startswith('__')]
dirs = [n for n in names if is_module_directory( os.path.join( dirname, n ) )]
title = os.path.basename( dirname )
if dirname == source:
title = '%s API'%(dirname.capitalize())
ifn = os.path.join( targetdir, 'index.rst' )
module_name = dirname.replace('/', '.')
with open( ifn, 'w' ) as index:
lines = [ '=' * len(title),
title,
'=' * len(title),
'',
'',
'.. automodule:: %s'%module_name,
' :members:'
]
toclines = []
for sn in srcs:
sname = sn[:-3]
sfn = sname + '.rst'
toclines.append( ' %s'%sfn )
with open( os.path.join( targetdir, sfn ), 'w' ) as sf:
slines = ['-' * len(sname),
sname,
'-' * len(sname),
'',
'',
'.. automodule:: %s'%(module_name + '.' + sname),
' :members:', ]
sf.writelines( '%s\n'%line for line in slines )
toclines.extend( ' %s/index.rst'%dn for dn in dirs )
if toclines:
toclines.sort()
lines.extend( ['',
'.. toctree::',
''] )
lines.extend( toclines )
index.writelines( '%s\n'%line for line in lines )
print dirname, destination, targetdir
os.path.walk(source, document_directory, None)
[docs]def license_update(project, license_file):
import os
new_license = open(license_file).read()
def translate_file(dirname, name):
"""translate a single file"""
filename = os.path.join(dirname, name)
print 'converting', filename
source = open(filename).read()
output = open(filename, 'w')
output.write(new_license)
old_license_line = True
for line in source.split('\n'):
if not len(line) or line[0]!='#':
old_license_line = False
if not old_license_line:
output.write(line)
output.write('\n')
def translate_directory(_arg, dirname, names):
"""recursively translate a directory"""
for name in names:
if name.endswith('.py'):
translate_file(dirname, name)
os.path.walk(project, translate_directory, None)
[docs]def to_pyside(project):
print 'EXPERIMENTAL !'
import os.path
import shutil
output = os.path.join('to_pyside', os.path.basename(project))
# first take a copy
if os.path.exists( output ):
shutil.rmtree( output )
shutil.copytree(project, output)
def replace_word(original_str, old_word, new_word):
return new_word.join((t for t in original_str.split(old_word)))
def translate_file(dirname, name):
"""translate a single file"""
filename = os.path.join(dirname, name)
print 'converting', filename
source = open(filename).read()
output = open(filename, 'w')
source = replace_word( source, 'PyQt4', 'PySide' )
source = replace_word( source, 'pyqtSlot', 'Slot' )
source = replace_word( source, 'pyqtSignal', 'Signal' )
source = replace_word( source, 'QtCore.QString', 'str' )
source = replace_word( source, 'QtCore.QVariant.', 'QtCore.Q')
source = replace_word( source, 'QtCore.QVariant(', '(' )
source = replace_word( source, 'QVariant', '()' )
source = replace_word( source, '.toByteArray()', '' )
source = replace_word( source, '.toString()', '' )
source = replace_word( source, '.toSize()', '' )
source = replace_word( source, '.toLongLong()', ', True' )
source = replace_word( source, ').isValid()', ')' )
output.write( source )
def translate_directory(_arg, dirname, names):
"""recursively translate a directory"""
for name in names:
if name.endswith('.py'):
translate_file(dirname, name)
os.path.walk(output, translate_directory, None)
[docs]def startproject(module):
import os
from camelot.bin.meta import CreateNewProject, NewProjectOptions
if os.path.exists(module):
raise Exception('Directory %s already exists, cannot start a project in it'%module)
options = NewProjectOptions()
options.module = module
action = CreateNewProject()
action.start_project( options )
[docs]def makemessages():
print 'Not yet implemented'
settings.setup_model()
commands = locals()
[docs]def main():
import camelot
from camelot.bin.meta import launch_meta_camelot
parser = CommandOptionParser(description=description,
usage=usage,
version=camelot.__version__,)
(_options, args) = parser.parse_args()
if not len(args):
launch_meta_camelot()
elif not len(args)>=2:
parser.print_help()
else:
command, command_args = args[0], args[1:]
commands[command](*command_args)
if __name__ == '__main__':
main()