bin/synchb.py
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 19 Apr 2010 14:02:13 +0300
changeset 0 16d8024aca5e
child 3 11d3954df52a
permissions -rw-r--r--
Revision: 201011 Kit: 201015

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#############################################################################
##
## Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
## All rights reserved.
## Contact: Nokia Corporation (developer.feedback@nokia.com)
##
## This file is part of the UI Extensions for Mobile.
##
## GNU Lesser General Public License Usage
## This file may be used under the terms of the GNU Lesser General Public
## License version 2.1 as published by the Free Software Foundation and
## appearing in the file LICENSE.LGPL included in the packaging of this file.
## Please review the following information to ensure the GNU Lesser General
## Public License version 2.1 requirements will be met:
## http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
##
## In addition, as a special exception, Nokia gives you certain additional
## rights.  These rights are described in the Nokia Qt LGPL Exception
## version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
##
## If you have questions regarding the use of this file, please contact
## Nokia at developer.feedback@nokia.com.
##
#############################################################################

import os
import re
import sys
import shutil
import optparse

# ============================================================================
# Globals
# ============================================================================
VERBOSE = False
EXCLUDE = ["hbplugins", "hbservers", "3rdparty", "internal", "tsrc", "debug", "release"]
COLLECTIONS = {"hbcore": "HbCore",
               "hbfeedback": "HbFeedback",
               "hbinput": "HbInput",
               "hbutils": "HbUtils",
               "hbwidgets": "HbWidgets"}

# ============================================================================
# OptionParser
# ============================================================================
class OptionParser(optparse.OptionParser):
    def __init__(self):
        optparse.OptionParser.__init__(self)
        self.add_option("-v", "--verbose", action="store_true", dest="verbose",
                        help="print verbose information about each step of the sync process")

        group = optparse.OptionGroup(self, "Input/output options")
        self.add_option("-i", "--input", dest="inputdir", metavar="dir",
                        help="specify the input <dir>")
        self.add_option("-o", "--output", dest="outputdir", metavar="dir",
                        help="specify the output <dir>")
        self.add_option_group(group)

        self.set_defaults(verbose=VERBOSE)

# ============================================================================
# Utils
# ============================================================================
if not hasattr(os.path, "relpath"):
    def relpath(path, start=os.curdir):
        return path
    os.path.relpath = relpath

def read_file(filepath):
    content = ""
    try:
        file = open(filepath, "r")
        content = file.read()
        file.close()
    except IOError, e:
        print(e)
    return content

def write_file(filepath, content):
    try:
        file = open(filepath, "w")
        file.write(content)
        file.close()
    except IOError, e:
        print(e)

def write_header(filepath, include):
    write_file(filepath, "#include \"%s\"\n" % include)

# ============================================================================
# Component
# ============================================================================
class Component:
    def __init__(self, name):
        self.name = name
        self.headers = list()
        self.privates = list()

    def read(self, path):
        entries = os.listdir(path)
        for entry in entries:
            entrypath = os.path.join(path, entry)
            if os.path.isdir(entrypath):
                self.read(entrypath)
            elif os.path.isfile(entrypath):
                if entry.endswith("_p_p.h"):
                    continue
                elif entry.endswith("_p.h"):
                    self.privates.append(entrypath)
                elif entry.endswith(".h"):
                    self.headers.append(entrypath)

    def write(self, path):
        if len(self.headers) > 0:
            self._makedirs(path)
            self._write(path, self.headers, True)

        if len(self.privates) > 0:
            privpath = os.path.join(path, "private")
            self._makedirs(privpath)
            self._write(privpath, self.privates, False)

    def _write(self, path, headers, convenience):
        global VERBOSE
        if VERBOSE:
            print("INFO: Writing headers to '%s'" % path)
        for header in headers:
            filename = os.path.basename(header)
            filepath = os.path.join(path, filename)
            relpath = os.path.relpath(header, path)
            if VERBOSE:
                print("INFO:\t ==> %s" % os.path.basename(filepath))
            write_header(filepath, relpath.replace("\\", "/"))
            if convenience:
                classes = list()
                content = read_file(header)
                for match in re.finditer("(?:class|namespace)\s+(?:HB_[^_]+_EXPORT\s+)?(Hb\w*)(\s*;)?", content):
                    if not match.group(2):
                        classes.append(match.group(1))
                for match in re.finditer("#pragma hb_header\((\w+)\)", content):
                    classes.append(match.group(1))
                for cls in classes:
                    filepath = os.path.join(path, cls)
                    write_header(filepath, filename)

    def _makedirs(self, path):
        global VERBOSE
        if not os.path.exists(path):
            if VERBOSE:
                print("INFO: Creating include dir '%s'" % path)
            os.makedirs(path)

# ============================================================================
# Collection
# ============================================================================
class Collection:
    def __init__(self, name):
        self.name = name
        self.components = []

    def read(self, path):
        global EXCLUDE
        for entry in os.listdir(path):
            entrypath = os.path.join(path, entry)
            if not entry in EXCLUDE and os.path.isdir(entrypath):
                component = Component(entry)
                component.read(entrypath)
                self.components.append(component)

    def write(self, path):
        global COLLECTIONS
        # include/hbcore
        includes = list()
        path = os.path.join(path, self.name)
        for component in self.components:
            component.write(path)
            for header in component.headers:
                includes.append("#include \"%s\"\n" % os.path.basename(header))
        if self.name in COLLECTIONS:
            write_file(os.path.join(path, self.name + ".h"), "".join(includes))
            write_header(os.path.join(path, COLLECTIONS[self.name]), self.name + ".h")

# ============================================================================
# Package
# ============================================================================
class Package:
    def __init__(self, name):
        self.path = name
        self.collections = list()

    def read(self, path):
        global EXCLUDE
        for entry in os.listdir(path):
            # hbcore, hbwidgets, hbutils...
            entrypath = os.path.join(path, entry)
            if not entry in EXCLUDE and os.path.isdir(entrypath):
                collection = Collection(entry)
                collection.read(entrypath)
                self.collections.append(collection)

    def write(self, path):
        for collection in self.collections:
            collection.write(path)

# ============================================================================
# main()
# ============================================================================
def main():
    global VERBOSE

    parser = OptionParser()
    (options, args) = parser.parse_args()

    VERBOSE = options.verbose

    if not options.inputdir:
        options.inputdir = os.path.abspath(sys.path[0])
    if os.path.basename(os.path.normpath(options.inputdir)) == "bin":
        options.inputdir = os.path.normpath(os.path.join(options.inputdir, os.pardir))
    if not os.path.basename(os.path.normpath(options.inputdir)) == "src":
        options.inputdir = os.path.join(options.inputdir, "src")

    if not options.outputdir:
        options.outputdir = os.getcwd()
    if not os.path.basename(os.path.normpath(options.outputdir)) == "include":
        options.outputdir = os.path.join(options.outputdir, "include")

    if os.path.exists(options.outputdir):
        if VERBOSE:
            print("INFO: Removing include dir '%s'" % options.outputdir)
        shutil.rmtree(options.outputdir, ignore_errors=True)

    package = Package("hb")
    package.read(options.inputdir)
    package.write(options.outputdir)

if __name__ == "__main__":
    main()