[ooo-build-commit] .: bin/fixguard.py bin/gob bin/gob.in configure.in

Thomas Klausner tklausner at kemper.freedesktop.org
Tue Oct 5 01:17:59 PDT 2010


 bin/fixguard.py |    2 
 bin/gob         | 1070 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bin/gob.in      | 1070 --------------------------------------------------------
 configure.in    |    1 
 4 files changed, 1071 insertions(+), 1072 deletions(-)

New commits:
commit 37efef7f873aaaae523d0fa84f96b8ebe42b96b6
Author: Thomas Klausner <wiz at NetBSD.org>
Date:   Tue Oct 5 10:17:23 2010 +0200

    Undo the remaining python changes.

diff --git a/bin/fixguard.py b/bin/fixguard.py
index 0451224..5381132 100755
--- a/bin/fixguard.py
+++ b/bin/fixguard.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 import sys
 import re
 import os
diff --git a/bin/gob b/bin/gob
new file mode 100755
index 0000000..292c17f
--- /dev/null
+++ b/bin/gob
@@ -0,0 +1,1070 @@
+#!/usr/bin/env python
+
+# gob.py - ooo-build to GIT conversion:  dump gob branch description files
+#          and create branched git
+#
+# Usage: python bin/gob --help
+
+import optparse
+import operator
+import os
+import re
+import sys
+import shutil
+
+class SystemFailed (Exception):
+    pass
+
+def log (s, threshold=1):
+    if options.verbose > threshold:
+        print >> sys.stderr, s
+
+def info (s):
+    log (s, threshold=0)
+
+def exception_string (exception=Exception ('no message')):
+    import traceback
+    return traceback.format_exc (None)
+
+def filter_out (predicate, lst):
+    return filter (lambda x: not predicate (x), lst)
+
+def makedirs (dir):
+    log ('mkdir %(dir)s' % locals ())
+    os.makedirs (dir)
+
+def symlink (src, dest):
+    log ('ln -s %(src)s %(dest)s' % locals ())
+    os.symlink (src, dest)
+
+def rename (src, dest):
+    log ('mv %(src)s %(dest)s' % locals ())
+    os.rename (src, dest)
+
+def rmdir (dir):
+    log ('rmdir %(dir)s' % locals ())
+    os.rmdir (dir)
+
+def system (command, raise_on_error=True):
+    if options.verbose > 1:
+        log ('executing: %(command)s' % locals ())
+    if options.verbose < 3:
+        command = '(%(command)s) > gob.log 2>&1' % locals ()
+    status = os.system (command)
+    if status and raise_on_error:
+        info (command)
+        info (file ('gob.log').read ())
+        raise SystemFailed ('Command failed: %(command)s' % locals ())
+    return status
+
+def read_pipe (command, raise_on_error=True):
+    log ('executing: %(command)s' % locals ())
+    if options.verbose < 3:
+        command = '(%(command)s) 2> gob.log' % locals ()
+    pipe = os.popen (command)
+    output = pipe.read ()
+    log ('pipe-output:\n%(output)s)s' % locals (), threshold=2)
+    if pipe.close () and raise_on_error:
+        info (command)
+        info (file ('gob.log').read ())
+        raise SystemFailed ('Pipe failed: %(command)s' % locals ())
+    return output
+
+def list_dirs (dir, allow_link=True):
+    return filter (lambda x: (os.path.isdir (os.path.join (dir, x))
+                              and (allow_link
+                                   or not os.path.islink (os.path.join (dir, x)))),
+                   os.listdir (dir))
+
+def find_file (root, path, name):
+    for dir in path:
+        file_name = os.path.abspath (os.path.join (root, dir, name))
+        if os.path.isfile (file_name):
+            return file_name
+    return None
+
+def _apply_patch (dir, patch):
+    system ('patch -l -p0 -d %(dir)s < %(patch)s' % locals ())
+
+def apply_patch (dir, patch):
+    if not options.split:
+        return _apply_patch (dir, patch)
+    apply_dir = os.path.join (dir, options.flat_apply_dir)
+    _apply_patch (apply_dir, patch)
+    for module in list_dirs (apply_dir, allow_link=False):
+        rename (os.path.join (apply_dir, module), os.path.join (dir, module))
+
+def get_srcpack2_dict ():
+    def modules_line (x):
+        e = x.split ("=")
+        return e[0], e[1].split (',')
+    return dict (map (modules_line, file (src_dir + 'bin/modules2.txt').readlines ()))
+
+def for_each (func, lst):
+    for i in lst:
+        func (i)
+
+def move (src):
+    src2 = get_srcpack2_dict ()
+    def move_pack (pack):
+        pack_dir = os.path.join (src, pack)
+        def move_module (module):
+            module_dir = src + '/' + module
+            pack_module_dir = pack_dir + '-/' + module
+            if os.path.exists (module_dir):
+                rename (module_dir, pack_module_dir)
+        makedirs (pack_dir + '-')
+        for_each (move_module, src2[pack])
+        rename (pack_dir + '-', pack_dir)
+    for_each (move_pack, src2.keys ())
+
+def move_back (src):
+    src2 = get_srcpack2_dict ()
+    def move_pack (pack):
+        pack_dir = os.path.join (src, pack)
+        def move_module (module):
+            print 'renaming:', module
+            module_dir = src + '/' + module
+            pack_module_dir = pack_dir + '-/' + module
+            if os.path.exists (pack_module_dir):
+                rename (pack_module_dir, module_dir)
+            else:
+                print 'no such dir:', pack_module_dir
+        rename (pack_dir, pack_dir + '-')
+        for_each (move_module, src2[pack])
+        rmdir (pack_dir + '-')
+    for_each (move_pack, src2.keys ())
+
+def setup_flat_apply_dir (src):
+    src2 = get_srcpack2_dict ()
+    apply_dir = os.path.join (src, options.flat_apply_dir)
+    shutil.rmtree (apply_dir, ignore_errors=True)
+    makedirs (apply_dir)
+    missing = ['mdbtools', 'libwpg', 'libwps', 'xalan']
+    for pack in src2.keys ():
+        for module in src2[pack]:
+            symlink (os.path.join ('..', '..', pack, module), os.path.join (apply_dir, module))
+    for pack in missing:
+        symlink (os.path.join ('..', '..', pack), os.path.join (apply_dir, pack))
+
+def patch_get_branch (patch):
+    patch_file = patch.file_name
+    if not patch_file:
+        return None
+
+    if 'vba' in options.dir_branch and int (options.milestone) > 19:
+        m = re.search ('(cws-scsheetprotection02|sc-autofilter-empty-nonempty|sc-copy-source-border|sc-datapilot|sc-move-from-origin|sc-paste-on-enter|sc-save-password-minlength|scroll-accel|xl-import-formradiobutton)', patch_file)
+        if m:
+            return 'vba'
+
+    # Prevent from going into ooxml
+    m = re.search ('(writerfilter-qnametostr-NOOPTFILES)', patch_file)
+    if m:
+        return m.group (1)
+
+    dir = os.path.basename (os.path.dirname  (patch_file))
+    base = os.path.splitext (os.path.basename (patch_file))[0]
+
+    module_re = None
+    if not module_re:
+        modules = list_dirs (options.build_dir)
+        if options.split:
+            modules = list_dirs (os.path.join (options.build_dir, options.flat_apply_dir))
+        module_re = '|'.join (modules)
+
+    # Patches with a simple digit suffix are aggregated into one branch
+    if (not re.search ('%(module_re)s$|\d\d+$' % locals (), base)
+        and re.search ('\d$', base)):
+        base = re.sub ('-*\d$', '', base)
+
+    # Patches in a separated may be aggregated into one branch
+    if dir in options.dir_branch:
+        return dir
+
+    # Pathes with a branch_prefix are aggregated into one branch
+    branch_prefix = [
+        'cjk-character-units',
+        'cws-layoutdialogs',
+        'cws-scsheetprotection02',
+        'emf+',
+        'fpicker-kde',
+        'jvmfwk-gij',
+        'lockfile',
+        'mono',
+        'sal-strintern-speed',
+        'sc-dataform',
+        'sc-datapilot',
+        'speed-configmgr',
+        'svg-import',
+        'system-lpsolve',
+        'tools-urlobj-smb-scheme',
+        'transogl',
+        'unittesting',
+        'unxsplash',
+        'vba',
+        'wpgimporter',
+        'writerfiltery'
+        ]
+
+    branch_prefix_re = '^(' + '|'.join (branch_prefix).replace ('+', '\+') + ')'
+    m = re.search (branch_prefix_re, base)
+    if m:
+        def assert_dir_group (m, s):
+            return s in options.dir_branch or m.group (1) != s
+        if (assert_dir_group (m, 'vba')
+            and assert_dir_group (m, 'emf+')
+            and assert_dir_group (m, 'unittesting')):
+            return m.group (1)
+
+    # Some patches are declared in the middle of a branch [another
+    # series of patches that form a branch] which depends on that
+    # patch, but have derogatory naming.  These patches must be
+    # categorised explicitly.  The ASSIMILATE warning helps to detect
+    # these.
+    if 'emf+' in options.dir_branch and re.search ('^(cairocanvas-alpha-pixmap-rewrite|vcl-grey-alpha-unix-sal-bitmap)', base):
+        return 'emf+'
+
+    if 'ooxml' in options.dir_branch and re.search ('^(win32-installer-register-moox-types)', base):
+        return 'ooxml'
+
+    if 'vba' in options.dir_branch and re.search ('^(default-autotext-and-form-name|sc-toggle-merge-center)', base):
+        return 'vba'
+
+    if re.search ('^(fix-linkoo|linkoo-)', base):
+        return 'linkoo'
+
+    if re.search ('^(fpicker-common-scp2)', base):
+        return 'fpicker-kde'
+
+    # Remove workspace and milestone suffixes
+    workspace = options.workspace
+    milestone = options.milestone
+    base = re.sub ('-%(workspace)s' % locals (), '', base)
+    base = re.sub ('-m%(milestone)s' % locals (), '', base)
+
+    # Patches with a -localize suffix are aggregated into one branch
+    base = re.sub ('-localize$' % locals (), '', base)
+
+    # Patches with a module suffix are aggregated into one branch
+    base = re.sub ('-(%(module_re)s)$' % locals (), '', base)
+
+    # git does not like dots in branch names
+    base = base.replace('.','-')
+
+    return base
+
+# Hard handy work for m19 gets quickly bit rotten
+# Use patch dependency calculation instead
+manual_m19_branch_dependencies = {
+    'buildfix-layoutdialogs': ['cws-layoutdialogs'],
+    'cairocanvas-fix-image-cache': ['cairo'],
+    'cws-scsheetprotection02': ['sc-datapilot', 'sc-paste-on-enter'],
+    'emf+': ['link-as-needed'],
+    'forms-radio-button-group-names': ['form-control-visibility'],
+    'layout-plugin': ['cws-layoutdialogs'],
+    'layout-tab': ['layout-plugin'],
+    'linkwarn-svtools-miscopts-bits': ['novell-win32-odma'],
+    'ooo59127.vcl.honourcairofont': ['ooo64508.vcl.honourfontconfighinting'],
+    'oosplash-etc-openoffice-sofficerc': ['unxsplash'],
+    'ooxml': ['lwp-filter-component'],
+    'sc-copy-on-merged-cells': ['sc-dataform'],
+    'sc-dataform': ['sc-hrc-ooo-build-resources'],
+    'sc-datapilot': ['sc-dataform'],
+    'sc-dp-gridlayout': ['sc-datapilot'],
+    'sc-export-shape-hlink-bindings': ['sc-export-shape-macro-bindings'],
+    'sc-simple-sort-include-format-header': ['sc-natural-sort'],
+    'sc-toggle-merge-center': ['vba'],
+    'sfx2-pre-and-postprocess-crash-fix': ['sfx2-pre-and-postprocess-during-save-load'],
+    'sfx2-pre-and-postprocess-during-save-load': ['sfx2-remove-check-update-on-fileload'],
+    'speed-bdirect': ['speed-symbolic-functions'],
+    'speed-store-lck': ['store-core'],
+    'static-libs-use-_pic': ['system-lpsolve'],
+    'ui-desktop-integration': ['linkwarn-svtools-miscopts-bits'],
+    'unittesting': ['tools-qa-urlobj-unittest', 'gnome-vfs-late-init'],
+    'vba': ['cws-npower10', 'cws-pflin10', 'cws-npower11'],
+    'vcl-linking-randr': ['autocorrect-accidental-caps-lock', 'internal-mesa-headers'],
+    'wpgimporter': ['wpsimport'],
+}
+
+def range_union (a, b, fuzz=0):
+    u = (max (a[0], b[0]) - fuzz, min (a[1], b[1]) + fuzz, a[2], b[2])
+    if u[0] > u[1]:
+        return None
+    return u
+
+class File:
+    def __init__ (self, s):
+        self.string = s
+        self.ranges = None
+        self.name = None
+        if self.string.find ('\n+++ ') >= 0:
+            self.name = re.search ('\n[+]{3}\s+([.]/)?([^\s]+)', self.string).group (2)
+    def __repr__ (self):
+        return '<File: %(name)s>' % self.__dict__
+    def get_ranges (self):
+        if not self.ranges:
+            self.numbers = re.findall ('\n(@@ -(\d+),(\d+) [+](\d+),(\d+) @@(.|\n[^@])*)', self.string)
+            self.ranges = map (lambda x: (min (int (x[1]), int (x[3])), max (int (x[1]) + int (x[2]), int (x[3]) + int (x[4])), x[0][:160]), self.numbers)
+        return self.ranges
+
+def patch_depend (p, q):
+    files = []
+    for file_name in p.files.keys ():
+        if file_name in q.files.keys ():
+            for a in p.files[file_name].get_ranges ():
+                for b in q.files[file_name].get_ranges ():
+                    union = range_union (a, b, int (options.fuzz))
+                    if union:
+                        return union
+    return False
+
+def patch_get_dependencies (patches, patch):
+    dependencies = ['pristine']
+    for p in patches:
+        if p == patch:
+            break
+        if patch_depend (patch, p):
+            dependencies += [p.name]
+    return dependencies
+
+def branch_get_dependencies (branches, patches, branch):
+    patch_dependencies = {}
+    patch_overlaps = []
+    first_patch = None
+    for patch in patches:
+        if patch in branches[branch]:
+            first_patch = patch
+            break
+    last_patch = None
+    for patch in reversed (patches):
+        if patch in branches[branch]:
+            last_patch = patch
+            break
+    for patch in branches[branch]:
+        assimilate = False
+        for p in patches:
+            if p == last_patch:
+                name = p.name
+                break
+            if p == first_patch:
+                name = p.name
+                # We cannot have a branch pre-depend on a patch/branch
+                # that does not exist yet.  FIXME: if it is really
+                # needed, it should be auto-assimilated by the branch.
+                # This is now done manually in patch_get_branch ().
+                assimilate = True
+            o = patch_depend (patch, p)
+            if assimilate and o and p not in branches[branch]:
+                name = p.name
+                ab = patch_get_branch (p)
+                print 'ASSIMILATE[%(branch)s]: %(name)s [%(ab)s]' % locals ()
+                continue
+            if o:
+                patch_dependencies[p] = p
+                patch_overlaps += [o]
+    branch_dependencies = {}
+    for patch in patch_dependencies.values ():
+        b = patch_get_branch (patch)
+        if b != branch:
+            branch_dependencies[b] = b
+    if not branch_dependencies:
+        return ['pristine']
+    return branch_dependencies.values ()
+
+# No overrides are necessary when using fuzz >= 40
+branch_override_dependencies = {
+    }
+
+def branch_get_dependencies_with_override (branches, patches, branch):
+    return branch_override_dependencies.get (branch, branch_get_dependencies (branches, patches, branch))
+
+GitFailed = SystemFailed
+
+gitignores = '''
+*-
+*-HEAD
+*-git
+*-patched
+*-pristine
+*.bak
+*.cxx-*
+*.deps
+*.git
+*.hxx-*
+*.log
+*.orig
+*.patched
+*.pristine
+*.pyc
+*.rej
+*~
+.\#*
+/Linux*Env.Set*
+/bootstrap
+/makefile.mk
+/solver
+CVS
+TAGS
+\#*
+xxx-have-in-patches-now:localize.sdf
+unxlng*.pro
+autom4te.cache/
+config.log
+config.parms
+config.status
+configure
+set_soenv
+tmon.out
+visibility.cxx
+visibility.s
+warn
+default_images/introabout/intro-save.bmp
+dmake/Makefile
+dmake/config.h
+dmake/config.log
+dmake/config.status
+dmake/dmake
+dmake/*.o
+dmake/dmakeroot.h
+dmake/stamp-h1
+dmake/startup/Makefile
+dmake/startup/config.mk
+dmake/startup/unix/Makefile
+dmake/startup/unix/cygwin/Makefile
+dmake/startup/unix/linux/Makefile
+dmake/startup/unix/macosx/Makefile
+dmake/startup/unix/solaris/Makefile
+dmake/startup/unix/sysvr4/Makefile
+dmake/startup/winnt/Makefile
+dmake/startup/winnt/mingw/Makefile
+dmake/startup/winnt/msvc6/Makefile
+dmake/tests/Makefile
+dmake/unix/.dirstamp
+instsetoo_native/res/banner_nld.bmp
+instsetoo_native/res/banner_ooop.bmp
+instsetoo_native/res/nologoinstall_nld.bmp
+instsetoo_native/res/nologoinstall_ooop.bmp
+instsetoo_native/util/OpenOffice
+sd/xml/transitions-ogl.xml
+setup_native/source/win32/nsis/ooobanner_nld.bmp
+setup_native/source/win32/nsis/ooobanner_ooop.bmp
+setup_native/source/win32/nsis/ooobitmap_nld.bmp
+setup_native/source/win32/nsis/ooobitmap_ooop.bmp
+setup_native/source/win32/nsis/ooosetup_nld.ico
+solenv/unxlng*/
+svx/res
+'''
+keep = '''
+default_images/introabout/intro-save.bmp
+default_images/introabout/intro.bmp
+default_images/svx/res/openabout_ark.png
+default_images/svx/res/openabout_translateorgza.png
+default_images/sw/res/go-oo-team.png
+'''
+
+def create_gitignores (dir):
+    for i in filter_out (operator.not_, gitignores.split ('\n')):
+        if options.split:
+            i = i.replace ('/bootstrap', '/bootstrap/bootstrap')
+        if i[0] == '/':
+            file (dir + '/.gitignore', 'a').write (i + '\n')
+        else:
+            slash = ''
+            if i[-1] == '/':
+                i = i[:-1]
+                slash = '/'
+            file (dir + '/' + os.path.dirname (i) + '/.gitignore', 'a').write (os.path.basename (i) + slash + '\n')
+
+class Setup:
+    string = None
+    vars = {}
+    def __init__ (self, file_name='config.log'):
+        if not self.string and os.path.exists (file_name):
+            self.string = file (file_name).read ()
+    def get (self, key, default=None):
+        return self.vars.get (key, self.read_ (key, default))
+    def read_ (self, key, default):
+        m = re.search ('''%(key)s=['"*]([^*"']*)''' % locals (), self.string)
+        if m:
+            self.vars[key] = m.group (1)
+        else:
+            self.vars[key] = default
+        return self.vars[key]
+
+def get_svn_revision ():
+    return re.search ('\nRevision: ([0-9]+)', read_pipe ('svn info')).group (1)
+
+def get_git_committish ():
+    return re.search ('([^ ]+)', read_pipe ('git log --pretty=oneline -1')).group (1)
+
+class Git:
+    def __init__ (self, dir, patched, clean=False):
+        self.dir = dir
+        self.patched = patched
+        self.scratch = 'work/scratch'
+        self.workspace = options.workspace
+        self.milestone = options.milestone
+        self.pristine = 'upstream/%(workspace)s-m%(milestone)s' % self.__dict__
+        self.commits = {}
+        self.log = {}
+        if not os.path.exists (self.dir):
+            drink = Setup ().get ('DRINK', 'tea')
+            info ('Unpacking source tree - [ go and have some %(drink)s ] ...' % locals ())
+            system ('cd bin && ./unpack')
+            create_gitignores (dir)
+            if options.split:
+                move (self.dir)
+                setup_flat_apply_dir (self.dir)
+            self.system ('touch unpack')
+        if not os.path.isdir (dir + '/.git/refs'):
+            drink = Setup ().get ('DRINK')
+            info ('Creating GIT archive - [ go and have some %(drink)s ] ...' % locals ())
+            self.system ('git init')
+            #svn_revision = get_svn_revision ()
+            #self.commit ('Initial svn:r%(svn_revision)s unpatched.' % locals ())
+            git_committish = get_git_committish ()
+            self.commit ('Initial ooo-build: %(git_committish)s unpatched.' % locals ())
+            self.system ('git branch %(pristine)s' % self.__dict__)
+            self.system ('git tag gob-%(workspace)s-%(milestone)s %(pristine)s' % self.__dict__)
+            self.system ('git branch pristine')
+            self.system ('git gc')
+        if clean:
+            if self.is_modified ():
+                self.system ('git reset --hard HEAD')
+                self.system ('git clean -df')
+        if self.has_branch (self.patched):
+            self.checkout (self.patched)
+        else:
+            self.system ('git checkout -b %(patched)s pristine' % self.__dict__)
+        if self.has_branch (self.scratch):
+            self.system ('git branch -D %(scratch)s' % self.__dict__)
+    def pipe (self, command, raise_on_error=True):
+        dir = self.dir
+        return read_pipe ('cd %(dir)s && %(command)s' % locals (), raise_on_error)
+    def system (self, command, raise_on_error=True):
+        dir = self.dir
+        return system ('cd %(dir)s && %(command)s' % locals (), raise_on_error)
+    def get_branches (self):
+        return filter_out (operator.not_,
+                           self.pipe ('git branch')
+                           .replace ('*', '')
+                           .replace (' ', '').split ('\n'))
+    def get_log (self, branch=''):
+        commit = self.get_current_commit (branch)
+        self.log[commit] = self.log.get (commit, self.pipe ('git log --pretty=oneline %(branch)s --' % locals ()))
+        return self.log[commit]
+    def get_current_commit (self, branch=''):
+        if not branch:
+            branch = 'HEAD'
+        return self.pipe ('git rev-parse %(branch)s' % locals ())[:-1]
+    def get_commit (self, patch):
+        if not self.commits:
+            log = self.get_log (self.patched)
+            def grok_log_line (s):
+                m = re.match ('([^ ]+) Apply.*/([^/]+[.](diff|patch))', s)
+                if not m:
+                    info ('Skipping line:%(s)s:' % locals ())
+                    return None, None
+                return m.group (2), m.group (1)
+            self.commits = dict (map (grok_log_line, log.split ('\n')[:-2]))
+        return self.commits.get (patch, None)
+    def commit (self, message):
+        self.system ('git add .')
+        self.system ('git add -u .')
+        self.system ('''git commit -m '%(message)s' ''' % locals ())
+    def is_modified (self):
+        return re.sub ('# On branch.*\nnothing to commit \(working directory clean\)\n', '',
+                       self.pipe ('git status', raise_on_error=False))
+    def assert_clean (self):
+        dir = self.dir
+        pending = self.is_modified ()
+        if pending:
+            raise GitFailed ('working directory unclean: %(dir)s\n%(pending)s' % locals ())
+    def checkout (self, branch):
+        if not self.is_on_branch (branch):
+            self.system ('git checkout %(branch)s' % locals ())
+    def get_current_branch (self):
+        return self.pipe ('git symbolic-ref HEAD', raise_on_error=False)[len ('refs/heads/'):-1]
+    def is_on_branch (self, branch):
+        return branch == self.get_current_branch ()
+    def has_branch (self, branch):
+        return branch in self.get_branches ()
+    def apply_patch (self, branches, patches, patch):
+        branch = patch_get_branch (patch)
+        info ('Applying patch[%(branch)s]: ' % locals () + patch.name)
+        patched = self.get_current_branch ()
+        apply_patch (self.dir, patch.file_name)
+        base = os.path.basename (patch.file_name)
+        self.commit ('Apply %(base)s.' % locals ())
+        if options.milestone == '19':
+            dependencies = manual_m19_branch_dependencies.get (branch, ['pristine'])
+        else:
+            dependencies = branch_get_dependencies_with_override (branches, patches, branch)
+        if not self.has_branch (branch):
+            if not options.topgit:
+                base_depend = dependencies[0]
+                self.system ('git checkout -b %(branch)s %(base_depend)s' % locals ())
+                for dependency in dependencies[1:]:
+                    self.system ('git rebase %(dependency)s' % locals ())
+            else:
+                depend_str = ' '.join (dependencies)
+                self.system ('tg create %(branch)s %(depend_str)s' % locals ())
+                self.system ('git commit -am "topgit branch info %(branch)s"' % locals ())
+        else:
+            self.checkout (branch)
+        log = self.get_log (patched)
+        commit = log[:log.index (' ')]
+        self.system ('git cherry-pick -x %(commit)s' % locals ())
+    def before_ (self):
+        self.assert_clean ()
+        self.system ('git checkout -b %(scratch)s %(patched)s' % self.__dict__)
+    def after_ (self):
+        self.system ('git push . %(scratch)s:%(patched)s' % self.__dict__)
+        self.checkout (self.patched)
+        self.system ('git branch -D %(scratch)s' % self.__dict__)
+    def pick_patch (self, patch, commit):
+        branch = patch_get_branch (patch)
+        info ('Picking patch[%(branch)s]: ' % locals () + patch.name)
+        self.system ('git cherry-pick -x %(commit)s' % locals ())
+    def add_patch (self, branches, patches, patch):
+        if patch.name in self.get_log ():
+            info ('patch already applied, skipping: ' + patch.name)
+            return
+        if file (patch.file_name).read ().find ('\n+++ ') == -1:
+            info ('patch is empty, skipping: ' + patch.name)
+            return
+        commit = None
+        branch = patch_get_branch (patch)
+        if self.has_branch (branch):
+            name = patch.name.replace ('+', '\+')
+            m = re.search ('(^|\n)([^\s]+)\s+.*(\s|/)%(name)s' % locals (), self.get_log (branch))
+            if m:
+                commit = m.group (2)
+        self.before_ ()
+        if commit:
+            self.pick_patch (patch, commit)
+        else:
+            self.apply_patch (branches, patches, patch)
+        self.after_ ()
+    def dump_gob (self, branches, patches, branch):
+        gob_dir = self.dir + '/.git/refs/gob'
+        if not os.path.exists (gob_dir):
+            makedirs (gob_dir)
+        branch_patches = branches.get (branch, [])
+        if not branch_patches:
+            return
+        owner = ''
+        for patch in branch_patches:
+            owner = patch.owner
+            if owner:
+                break
+        issues = []
+        for patch in branch_patches:
+            issues += patch.issues
+        issue_string = ', '.join (issues)
+        dependencies = filter (lambda x: x != 'pristine', branch_get_dependencies (branches, patches, branch))
+        dependencies_string = ', '.join (dependencies)
+        commit = self.get_current_commit ()
+        gob_file_name = os.path.join (gob_dir, branch)
+        info ('Writing: ' + gob_file_name)
+        file (gob_file_name, 'w').write ('''%(commit)s
+state: stable
+issue: %(issue_string)s
+owner: %(owner)s
+depend: %(dependencies_string)s
+''' % locals ())
+
+class Patch:
+    def __init__ (self, file_name):
+        self.file_name = file_name
+        if self.file_name:
+            self.set_files ()
+        self.file_name = None
+    def set_files (self):
+        self.files = dict (map (lambda x: (x.name, x), map (File, ('\n' + file (self.file_name).read ()).split ('\n---')[1:])))
+    def __repr__ (self):
+        return '<Patch: ' + str (map (str, self.files.values ())) + ' >'
+
+class Apply_patch (Patch):
+    def __init__ (self, s, section, owner, issue):
+        Patch.__init__ (self, None)
+        self.string = s
+        self.section = section
+        self.owner = owner
+        m = re.search (', (\w\w+)', self.string)
+        if m:
+            self.owner = m.group (1)
+        m = re.match ('^\s*(([^#\s].*).(diff|patch))(.*)', self.string)
+        self.name = m.group (1)
+        self.base = m.group (2)
+        self.issues = map (lambda x: x[0], re.findall ('((i|n)#[0-9]+)', self.string))
+        if issue:
+            self.issues.append (issue)
+    def __repr__ (self):
+        return '<Patch: %(file_name)s [%(section)s] %(owner)s %(issues)s>' % self.__dict__
+    def set_file_name (self, dir, path):
+        self.file_name = find_file (dir, path, self.name)
+        self.set_files ()
+        return self
+
+class Section:
+    def __init__ (self, s):
+        self.string = s
+        m = re.match ('[[\s]*(.*[^\s])\s*\]', self.string)
+        self.tag = m.group (1).replace (' ', '')
+        self.name = re.sub ('[^\w].*', '', self.tag)
+        m = re.search ('\n(SectionOwner)\s*=>\s*(.*[^\s])', self.string)
+        self.owner = ''
+        if m:
+            self.owner = m.group (2)
+        m = re.search ('\n(SectionIssue)\s*=>\s*(.*[^\s])', self.string)
+        self.issue = ''
+        if m:
+            self.issue = m.group (2)
+    def __repr__ (self):
+        return '<Section: %(tag)s %(owner)s %(issue)s>' % self.__dict__
+    def get_patches (self):
+        def create_patch (s):
+            return Apply_patch (s[0], self.tag, self.owner, self.issue)
+        return map (create_patch, re.findall ('\n\s*([^#\s].*.(diff|patch).*)', self.string))
+
+class Apply:
+    def __init__ (self, apply_file, workspace, milestone):
+        self.workspace = workspace
+        self.milestone = milestone
+        self.string = file (apply_file).read ()
+        first_section = self.string.index ('\n[')
+        self.distros_string = self.string[:first_section]
+        self.sections_string = self.string[first_section:]
+        self.path = re.search ('\nPATCHPATH=(.*)', self.string).group (1).split (':')
+        self.distro = {}
+        self.master = {}
+        self.distros_string = re.sub ('\s*\\\s*\n\s*', '', self.distros_string)
+        for distro in re.findall ('\n\s*([^#=\s:]+)\s*:\s*(.*)', self.distros_string):
+            lst = distro[1].replace (' ', '').split (',')
+            expanded = []
+            for i in lst:
+                if i in self.master.keys ():
+                    del self.master[i]
+                expanded += self.distro.get (i, [i])
+            self.master[distro[0]] = self.distro[distro[0]] = expanded
+        # convenience: add sections as distro
+        #self.distro.update (dict (map (lambda x: (x.name, x.name), self.get_sections ())))
+    def get_section_strings (self):
+        return map (lambda x: '[' + x, self.sections_string.split ('\n[')[1:])
+    def get_sections (self):
+        return map (Section, self.get_section_strings ())
+    def get_distro (self, distro_name):
+        def section_in_distro (section):
+            if distro_name not in self.distro.keys ():
+                return distro_name == section.name
+            m = re.search ('(\w+).*(<=|<|==|!=|>=|>)%(workspace)s-m([0-9]+)'
+            % self.__dict__, section.tag)
+            if m:
+                name = m.group (1)
+                if not name in self.distro[distro_name]:
+                    return False
+                left_milestone = self.milestone
+                operator = m.group (2)
+                right_milestone = int (m.group (3))
+                return eval ('%(left_milestone)s %(operator)s %(right_milestone)s' % locals ())
+            else:
+                return section.tag in self.distro[distro_name]
+        return filter (section_in_distro, self.get_sections ())
+
+class Command:
+    def __init__ (self, apply, options):
+        self.options = options
+        self.apply = apply
+        self.patches_ = []
+        self.branches_ = {}
+    def patches (self):
+        '''list patches'''
+        print '\n'.join (map (str, self.get_patches ()))
+    def sections (self):
+        '''list sections'''
+        print '\n'.join (map (str, self.get_sections ()))
+    def distros (self):
+        '''list distros'''
+        print '\n'.join (map (str, self.apply.distro.keys ()))
+    def masters (self):
+        '''list masters'''
+        print '\n'.join (map (str, self.apply.master.keys ()))
+    def branches (self):
+        '''list branches'''
+        print '\n'.join (map (str, self.get_branches ().keys ()))
+    def get_branches (self):
+        if not self.branches_:
+            for patch in self.get_patches ():
+                branch = patch_get_branch (patch)
+                self.branches_[branch] = self.branches_.get (branch, []) + [patch]
+        return self.branches_
+    def dump_gobs (self):
+        '''dump gob files'''
+        branches = self.get_branches ()
+        patches = self.get_patches ()
+        git = Git (self.options.build_dir, self.options.patched)
+        for branch in git.get_branches ():
+            git.dump_gob (branches, patches, branch)
+    def checkout (self):
+        '''checkout patched ('master') branch'''
+        git = Git (self.options.build_dir, self.options.patched)
+    def git_export (self):
+        '''export to GIT with branches'''
+        git = Git (self.options.build_dir, self.options.patched, clean=True)
+        patches = self.get_patches ()
+        branches = self.get_branches ()
+        for patch in self.get_patches ():
+            git.add_patch (branches, patches, patch)
+        git.system ('git gc')
+    def get_patches_for_distro (self, distro):
+        patches = reduce (operator.add, map (lambda section: section.get_patches (), self.get_sections_for_distro (distro)))
+        for patch in patches:
+            patch.set_file_name (self.options.apply_dir, self.apply.path)
+        return patches
+    def get_patches (self):
+        if not self.patches_:
+            self.patches_ = reduce (operator.add, map (self.get_patches_for_distro, self.options.distros))
+        return self.patches_
+    def get_sections_for_distro (self, distro):
+        return self.apply.get_distro (distro)
+    def get_sections (self):
+        return reduce (operator.add, map (self.get_sections_for_distro, self.options.distros))
+    def prepare (self):
+        '''prepare ooo-build dir for use with GIT'''
+        git = Git (self.options.build_dir, self.options.patched)
+    def postpare (self):
+        '''update ooo-build dir GIT after patching'''
+        git = Git (self.options.build_dir, self.options.patched)
+        #svn_revision = get_svn_revision ()
+        #git.commit ('Update to svn:r%(svn_revision)s patched.' % locals ())
+        git_committish = get_git_committish ()
+        git.commit ('Update to ooo-build: %(git_committish)s patched.' % locals ())
+        git.system ('git rebase patched')
+    def dependencies (self):
+        '''list branch dependencies'''
+        patches = self.get_patches ()
+        branches = self.get_branches ()
+        independent = 0
+        for branch in branches:
+            dependencies = sorted (branch_get_dependencies (branches, patches, branch))
+            if dependencies == ['pristine']:
+                independent += 1
+            print 'BRANCH:', branch, '->', dependencies
+        print 'INDEPENDENT:', independent
+    def patch_dependencies (self):
+        '''list patch dependencies'''
+        branches = self.get_branches ()
+        patches = self.get_patches ()
+        for patch in patches:
+            branch = patch_get_branch (patch)
+            name = patch.name
+            print 'PATCH[%(branch)s]: %(name)s -> ' % locals (), patch_get_dependencies (patches, patch)
+    def bump (self):
+        '''bump BRANCH TAG-NAME - bump current branch (BRANCH=new upstream)'''
+        if len (self.options.arguments) != 2:
+            print 'Usage: gob bump BRANCH TAG-NAME'
+            print 'BRANCH: new upstream'
+            print 'Example:'
+            print '    gob bump upstream/dev300-m21 my-21-update'
+            sys.exit (2)
+        branch = self.options.arguments[0]
+        tag = self.options.arguments[1]
+        git_dir = self.options.build_dir
+        system ('cd %(git_dir)s && gob-bump %(branch)s %(tag)s' % locals ())
+    def update (self):
+        '''update BRANCH - update current branch (BRANCH='master')'''
+        if len (self.options.arguments) != 1:
+            print 'Usage: gob update BRANCH'
+            print '''BRANCH: the 'master' branch'''
+            print 'Example: '
+            print '    gob update distro/SUSE'
+            sys.exit (2)
+        branch = self.options.arguments[0]
+        git_dir = self.options.build_dir
+        system ('cdi %(git_dir)s && gob-update %(branch)s' % locals ())
+    def reset (self):
+        '''reset - set GIT tree to pristine and remove all branches'''
+        git = Git (self.options.build_dir, self.options.patched)
+        git.system ('git checkout -f %(patched)s' % git.__dict__)
+        git.system ('git reset --hard pristine')
+        git.system ('git clean -df')
+        git.system ('rm -rf .git/refs/top-bases')
+        cmd = 'xargs git branch -D'
+        if options.split:
+            git.system ('''git branch | grep -Ev '/|master|patched|pristine|upstream|%(patched)s' | xargs tg delete -f ''' % git.__dict__)
+        git.system ('''git branch | grep -Ev '/|master|patched|pristine|upstream|%(patched)s' | xargs git branch -D''' % git.__dict__)
+    def patch_depend (self):
+        '''patch-depend PATCH-1 PATCH-2 - show overlap between patches'''
+        if len (self.options.arguments) != 2:
+            print 'Usage: patch-depend PATCH-1 PATCH-2'
+            sys.exit (2)
+        union = patch_depend (Patch (self.options.arguments[0]), Patch (self.options.arguments[1]))
+        if union:
+            print union[0], '--', union[1]
+            print union[2]
+            print '<<<<<<<<<<<<<<<<<<<<<<<<<=========================>>>>>>>>>>>>>>>>>>>>>>>>>'
+            print union[3]
+            sys.exit (1)
+    def statistics (self):
+        ### not advertised
+        ### show some statistics on dependensies
+        patches = self.get_patches ()
+        branches = self.get_branches ()
+        full_match = 0
+        match = 0
+        fail = 0
+        extra = 0
+        independent = 0
+        for branch in branches:
+            manual_dependencies = sorted (manual_m19_branch_dependencies.get (branch, ['pristine']))
+            auto_dependencies = sorted (branch_get_dependencies (branches, patches, branch))
+            missing = False
+            for m in manual_dependencies:
+                if m != 'pristine' and not m in auto_dependencies:
+                    missing = True
+                    break
+            if missing:
+                fail += 1
+                print
+                print 'BRANCH:', branch
+                print 'MANUAL:', manual_dependencies
+                print 'AUTO:', auto_dependencies
+                #dependencies 'OVERLAPS:', overlaps
+            if auto_dependencies == ['pristine']:
+                independent += 1
+            elif auto_dependencies == manual_dependencies:
+                full_match += 1
+            elif manual_dependencies == ['pristine']:
+                extra += 1
+                #print 'BRANCH:', branch
+                #print 'EXTRA:', auto_dependencies
+            elif not missing:
+                match += 1
+        print
+        print 'FAIL:', fail
+        print 'FULL_MATCH:', full_match
+        print 'MATCH:', match
+        print 'EXTRA:', extra
+        print 'INDEPENDENT:', independent
+    def move (self):
+        move (options.build_dir)
+        setup_flat_apply_dir (options.build_dir)
+    def move_back (self):
+        move_back (options.build_dir)
+
+def get_cli_parser ():
+    p = optparse.OptionParser ()
+
+    p.usage = '%prog [OPTION]... COMMAND\n\nCommands:\n'
+    d = Command.__dict__
+    commands = [(k, d[k].__doc__) for k in d.keys ()
+                if d[k].__doc__ and type (d[k]) == type (lambda x: x)]
+    commands.sort ()
+
+    global src_dir
+    src_dir = ''
+    if not os.path.exists ('patches'):
+        src_dir = '../'
+    os.environ['PATH'] = src_dir + '/bin:' + os.environ['PATH']
+
+    for (command, doc) in commands:
+        p.usage += '    %s - %s\n' % (re.sub ('_', '-', command), doc)
+
+    def get (option):
+        return p.get_option ('--' + option.replace ('-', '_')).default
+
+    setup_workspace, setup_milestone = Setup ().get ('CVSTAG', 'dev300-m19').split ('-m')
+
+    p.add_option ('--workspace',
+                  dest='workspace',
+                  default=setup_workspace,
+                  metavar='STRING',
+                  help='set master workspace')
+    p.add_option ('--milestone',
+                  dest='milestone',
+                  default=setup_milestone,
+                  metavar='STRING',
+                  help='set milestone')
+    p.add_option ('--distro',
+                  action='append',
+                  dest='distros',
+                  default=[],
+                  metavar='DISTRO',
+                  help='add distribution')
+    p.add_option ('--build-dir',
+                  default=src_dir + 'build/' + get ('workspace') + '-m' + get ('milestone'),
+                  dest='build_dir',
+                  metavar='DIR',
+                  help='build (/git) directory')
+    p.add_option ('--apply-dir',
+                  default=src_dir + 'patches/' + get ('workspace'),
+                  dest='apply_dir',
+                  metavar='DIR',
+                  help='directory with APPLY file')
+    p.add_option ('--patched',
+                  default='patched',
+                  dest='patched',
+                  metavar='NAME',
+                  help='''use NAME as patched 'master' branch name''')
+    p.add_option ('--dir-branch',
+                  default=[],
+                  dest='dir_branch',
+                  metavar='DIR',
+                  help='aggregate patches in directory DIR into one branch')
+    p.add_option ('--fuzz',
+                  default='40', # FIXME: 40 = magic sweet spot for dev300-m21
+                  dest='fuzz',
+                  metavar='INT',
+                  help='use FUZZ as fuzz factor for patch overlap')
+    p.add_option ('--force', action='store_true', dest='force', default=False)
+    p.add_option ('--split', action='store_true', dest='split', default=False)
+    p.add_option ('--topgit', action='store_true', dest='topgit', default=False)
+    p.add_option ('-v', '--verbose', action='count', dest='verbose', default=1)
+    p.add_option ('-q', '--quiet', action='count', dest='quiet', default=0)
+    return p
+
+def parse_options ():
+    p = get_cli_parser ()
+    (options, arguments) = p.parse_args ()
+
+    options.command = ''
+    options.arguments = []
+    if arguments:
+        options.command = re.sub ('-', '_', arguments.pop (0))
+    options.arguments = arguments
+
+    if options.command in Command.__dict__:
+        return options
+    if options.command:
+        sys.stderr.write ('no such command: ' + options.command)
+        sys.stderr.write ('\n\n')
+    p.print_help ()
+    sys.exit (2)
+
+def set_option_defaults (options):
+    options.flat_apply_dir = '.git/apply-dir'
+    options.verbose -= options.quiet
+    options.apply_dir = (options.apply_dir
+                         .replace ('ooo300', 'dev300')
+                         .replace ('ooo310', 'dev300')
+                         .replace ('ooo320', 'dev300')
+                         )
+    if not options.distros:
+        options.distros = ['SUSE']
+    if not options.dir_branch:
+        options.dir_branch = filter (lambda x: x not in ['.', '..', '.svn', '64bit', 'dev300', 'hotfixes'], list_dirs (options.apply_dir + '/..'))
+        too_dispersed = ['cairo', 'vba']
+        options.dir_branch = filter (lambda x: x not in too_dispersed, options.dir_branch)
+    return options
+
+options = None
+def main ():
+    global options
+    options = set_option_defaults (parse_options ())
+    apply_file = options.apply_dir + '/apply'
+    apply = Apply (apply_file, options.workspace, options.milestone)
+    Command.__dict__[options.command] (Command (apply, options))
+
+if __name__ == '__main__':
+    main ()
diff --git a/bin/gob.in b/bin/gob.in
deleted file mode 100755
index 627c9c6..0000000
--- a/bin/gob.in
+++ /dev/null
@@ -1,1070 +0,0 @@
-#!@PYTHON@
-
-# gob.py - ooo-build to GIT conversion:  dump gob branch description files
-#          and create branched git
-#
-# Usage: python bin/gob --help
-
-import optparse
-import operator
-import os
-import re
-import sys
-import shutil
-
-class SystemFailed (Exception):
-    pass
-
-def log (s, threshold=1):
-    if options.verbose > threshold:
-        print >> sys.stderr, s
-
-def info (s):
-    log (s, threshold=0)
-
-def exception_string (exception=Exception ('no message')):
-    import traceback
-    return traceback.format_exc (None)
-
-def filter_out (predicate, lst):
-    return filter (lambda x: not predicate (x), lst)
-
-def makedirs (dir):
-    log ('mkdir %(dir)s' % locals ())
-    os.makedirs (dir)
-
-def symlink (src, dest):
-    log ('ln -s %(src)s %(dest)s' % locals ())
-    os.symlink (src, dest)
-
-def rename (src, dest):
-    log ('mv %(src)s %(dest)s' % locals ())
-    os.rename (src, dest)
-
-def rmdir (dir):
-    log ('rmdir %(dir)s' % locals ())
-    os.rmdir (dir)
-
-def system (command, raise_on_error=True):
-    if options.verbose > 1:
-        log ('executing: %(command)s' % locals ())
-    if options.verbose < 3:
-        command = '(%(command)s) > gob.log 2>&1' % locals ()
-    status = os.system (command)
-    if status and raise_on_error:
-        info (command)
-        info (file ('gob.log').read ())
-        raise SystemFailed ('Command failed: %(command)s' % locals ())
-    return status
-
-def read_pipe (command, raise_on_error=True):
-    log ('executing: %(command)s' % locals ())
-    if options.verbose < 3:
-        command = '(%(command)s) 2> gob.log' % locals ()
-    pipe = os.popen (command)
-    output = pipe.read ()
-    log ('pipe-output:\n%(output)s)s' % locals (), threshold=2)
-    if pipe.close () and raise_on_error:
-        info (command)
-        info (file ('gob.log').read ())
-        raise SystemFailed ('Pipe failed: %(command)s' % locals ())
-    return output
-
-def list_dirs (dir, allow_link=True):
-    return filter (lambda x: (os.path.isdir (os.path.join (dir, x))
-                              and (allow_link
-                                   or not os.path.islink (os.path.join (dir, x)))),
-                   os.listdir (dir))
-
-def find_file (root, path, name):
-    for dir in path:
-        file_name = os.path.abspath (os.path.join (root, dir, name))
-        if os.path.isfile (file_name):
-            return file_name
-    return None
-
-def _apply_patch (dir, patch):
-    system ('patch -l -p0 -d %(dir)s < %(patch)s' % locals ())
-
-def apply_patch (dir, patch):
-    if not options.split:
-        return _apply_patch (dir, patch)
-    apply_dir = os.path.join (dir, options.flat_apply_dir)
-    _apply_patch (apply_dir, patch)
-    for module in list_dirs (apply_dir, allow_link=False):
-        rename (os.path.join (apply_dir, module), os.path.join (dir, module))
-
-def get_srcpack2_dict ():
-    def modules_line (x):
-        e = x.split ("=")
-        return e[0], e[1].split (',')
-    return dict (map (modules_line, file (src_dir + 'bin/modules2.txt').readlines ()))
-
-def for_each (func, lst):
-    for i in lst:
-        func (i)
-
-def move (src):
-    src2 = get_srcpack2_dict ()
-    def move_pack (pack):
-        pack_dir = os.path.join (src, pack)
-        def move_module (module):
-            module_dir = src + '/' + module
-            pack_module_dir = pack_dir + '-/' + module
-            if os.path.exists (module_dir):
-                rename (module_dir, pack_module_dir)
-        makedirs (pack_dir + '-')
-        for_each (move_module, src2[pack])
-        rename (pack_dir + '-', pack_dir)
-    for_each (move_pack, src2.keys ())
-
-def move_back (src):
-    src2 = get_srcpack2_dict ()
-    def move_pack (pack):
-        pack_dir = os.path.join (src, pack)
-        def move_module (module):
-            print 'renaming:', module
-            module_dir = src + '/' + module
-            pack_module_dir = pack_dir + '-/' + module
-            if os.path.exists (pack_module_dir):
-                rename (pack_module_dir, module_dir)
-            else:
-                print 'no such dir:', pack_module_dir
-        rename (pack_dir, pack_dir + '-')
-        for_each (move_module, src2[pack])
-        rmdir (pack_dir + '-')
-    for_each (move_pack, src2.keys ())
-
-def setup_flat_apply_dir (src):
-    src2 = get_srcpack2_dict ()
-    apply_dir = os.path.join (src, options.flat_apply_dir)
-    shutil.rmtree (apply_dir, ignore_errors=True)
-    makedirs (apply_dir)
-    missing = ['mdbtools', 'libwpg', 'libwps', 'xalan']
-    for pack in src2.keys ():
-        for module in src2[pack]:
-            symlink (os.path.join ('..', '..', pack, module), os.path.join (apply_dir, module))
-    for pack in missing:
-        symlink (os.path.join ('..', '..', pack), os.path.join (apply_dir, pack))
-
-def patch_get_branch (patch):
-    patch_file = patch.file_name
-    if not patch_file:
-        return None
-
-    if 'vba' in options.dir_branch and int (options.milestone) > 19:
-        m = re.search ('(cws-scsheetprotection02|sc-autofilter-empty-nonempty|sc-copy-source-border|sc-datapilot|sc-move-from-origin|sc-paste-on-enter|sc-save-password-minlength|scroll-accel|xl-import-formradiobutton)', patch_file)
-        if m:
-            return 'vba'
-
-    # Prevent from going into ooxml
-    m = re.search ('(writerfilter-qnametostr-NOOPTFILES)', patch_file)
-    if m:
-        return m.group (1)
-
-    dir = os.path.basename (os.path.dirname  (patch_file))
-    base = os.path.splitext (os.path.basename (patch_file))[0]
-
-    module_re = None
-    if not module_re:
-        modules = list_dirs (options.build_dir)
-        if options.split:
-            modules = list_dirs (os.path.join (options.build_dir, options.flat_apply_dir))
-        module_re = '|'.join (modules)
-
-    # Patches with a simple digit suffix are aggregated into one branch
-    if (not re.search ('%(module_re)s$|\d\d+$' % locals (), base)
-        and re.search ('\d$', base)):
-        base = re.sub ('-*\d$', '', base)
-
-    # Patches in a separated may be aggregated into one branch
-    if dir in options.dir_branch:
-        return dir
-
-    # Pathes with a branch_prefix are aggregated into one branch
-    branch_prefix = [
-        'cjk-character-units',
-        'cws-layoutdialogs',
-        'cws-scsheetprotection02',
-        'emf+',
-        'fpicker-kde',
-        'jvmfwk-gij',
-        'lockfile',
-        'mono',
-        'sal-strintern-speed',
-        'sc-dataform',
-        'sc-datapilot',
-        'speed-configmgr',
-        'svg-import',
-        'system-lpsolve',
-        'tools-urlobj-smb-scheme',
-        'transogl',
-        'unittesting',
-        'unxsplash',
-        'vba',
-        'wpgimporter',
-        'writerfiltery'
-        ]
-
-    branch_prefix_re = '^(' + '|'.join (branch_prefix).replace ('+', '\+') + ')'
-    m = re.search (branch_prefix_re, base)
-    if m:
-        def assert_dir_group (m, s):
-            return s in options.dir_branch or m.group (1) != s
-        if (assert_dir_group (m, 'vba')
-            and assert_dir_group (m, 'emf+')
-            and assert_dir_group (m, 'unittesting')):
-            return m.group (1)
-
-    # Some patches are declared in the middle of a branch [another
-    # series of patches that form a branch] which depends on that
-    # patch, but have derogatory naming.  These patches must be
-    # categorised explicitly.  The ASSIMILATE warning helps to detect
-    # these.
-    if 'emf+' in options.dir_branch and re.search ('^(cairocanvas-alpha-pixmap-rewrite|vcl-grey-alpha-unix-sal-bitmap)', base):
-        return 'emf+'
-
-    if 'ooxml' in options.dir_branch and re.search ('^(win32-installer-register-moox-types)', base):
-        return 'ooxml'
-
-    if 'vba' in options.dir_branch and re.search ('^(default-autotext-and-form-name|sc-toggle-merge-center)', base):
-        return 'vba'
-
-    if re.search ('^(fix-linkoo|linkoo-)', base):
-        return 'linkoo'
-
-    if re.search ('^(fpicker-common-scp2)', base):
-        return 'fpicker-kde'
-
-    # Remove workspace and milestone suffixes
-    workspace = options.workspace
-    milestone = options.milestone
-    base = re.sub ('-%(workspace)s' % locals (), '', base)
-    base = re.sub ('-m%(milestone)s' % locals (), '', base)
-
-    # Patches with a -localize suffix are aggregated into one branch
-    base = re.sub ('-localize$' % locals (), '', base)
-
-    # Patches with a module suffix are aggregated into one branch
-    base = re.sub ('-(%(module_re)s)$' % locals (), '', base)
-
-    # git does not like dots in branch names
-    base = base.replace('.','-')
-
-    return base
-
-# Hard handy work for m19 gets quickly bit rotten
-# Use patch dependency calculation instead
-manual_m19_branch_dependencies = {
-    'buildfix-layoutdialogs': ['cws-layoutdialogs'],
-    'cairocanvas-fix-image-cache': ['cairo'],
-    'cws-scsheetprotection02': ['sc-datapilot', 'sc-paste-on-enter'],
-    'emf+': ['link-as-needed'],
-    'forms-radio-button-group-names': ['form-control-visibility'],
-    'layout-plugin': ['cws-layoutdialogs'],
-    'layout-tab': ['layout-plugin'],
-    'linkwarn-svtools-miscopts-bits': ['novell-win32-odma'],
-    'ooo59127.vcl.honourcairofont': ['ooo64508.vcl.honourfontconfighinting'],
-    'oosplash-etc-openoffice-sofficerc': ['unxsplash'],
-    'ooxml': ['lwp-filter-component'],
-    'sc-copy-on-merged-cells': ['sc-dataform'],
-    'sc-dataform': ['sc-hrc-ooo-build-resources'],
-    'sc-datapilot': ['sc-dataform'],
-    'sc-dp-gridlayout': ['sc-datapilot'],
-    'sc-export-shape-hlink-bindings': ['sc-export-shape-macro-bindings'],
-    'sc-simple-sort-include-format-header': ['sc-natural-sort'],
-    'sc-toggle-merge-center': ['vba'],
-    'sfx2-pre-and-postprocess-crash-fix': ['sfx2-pre-and-postprocess-during-save-load'],
-    'sfx2-pre-and-postprocess-during-save-load': ['sfx2-remove-check-update-on-fileload'],
-    'speed-bdirect': ['speed-symbolic-functions'],
-    'speed-store-lck': ['store-core'],
-    'static-libs-use-_pic': ['system-lpsolve'],
-    'ui-desktop-integration': ['linkwarn-svtools-miscopts-bits'],
-    'unittesting': ['tools-qa-urlobj-unittest', 'gnome-vfs-late-init'],
-    'vba': ['cws-npower10', 'cws-pflin10', 'cws-npower11'],
-    'vcl-linking-randr': ['autocorrect-accidental-caps-lock', 'internal-mesa-headers'],
-    'wpgimporter': ['wpsimport'],
-}
-
-def range_union (a, b, fuzz=0):
-    u = (max (a[0], b[0]) - fuzz, min (a[1], b[1]) + fuzz, a[2], b[2])
-    if u[0] > u[1]:
-        return None
-    return u
-
-class File:
-    def __init__ (self, s):
-        self.string = s
-        self.ranges = None
-        self.name = None
-        if self.string.find ('\n+++ ') >= 0:
-            self.name = re.search ('\n[+]{3}\s+([.]/)?([^\s]+)', self.string).group (2)
-    def __repr__ (self):
-        return '<File: %(name)s>' % self.__dict__
-    def get_ranges (self):
-        if not self.ranges:
-            self.numbers = re.findall ('\n(@@ -(\d+),(\d+) [+](\d+),(\d+) @@(.|\n[^@])*)', self.string)
-            self.ranges = map (lambda x: (min (int (x[1]), int (x[3])), max (int (x[1]) + int (x[2]), int (x[3]) + int (x[4])), x[0][:160]), self.numbers)
-        return self.ranges
-
-def patch_depend (p, q):
-    files = []
-    for file_name in p.files.keys ():
-        if file_name in q.files.keys ():
-            for a in p.files[file_name].get_ranges ():
-                for b in q.files[file_name].get_ranges ():
-                    union = range_union (a, b, int (options.fuzz))
-                    if union:
-                        return union
-    return False
-
-def patch_get_dependencies (patches, patch):
-    dependencies = ['pristine']
-    for p in patches:
-        if p == patch:
-            break
-        if patch_depend (patch, p):
-            dependencies += [p.name]
-    return dependencies
-
-def branch_get_dependencies (branches, patches, branch):
-    patch_dependencies = {}
-    patch_overlaps = []
-    first_patch = None
-    for patch in patches:
-        if patch in branches[branch]:
-            first_patch = patch
-            break
-    last_patch = None
-    for patch in reversed (patches):
-        if patch in branches[branch]:
-            last_patch = patch
-            break
-    for patch in branches[branch]:
-        assimilate = False
-        for p in patches:
-            if p == last_patch:
-                name = p.name
-                break
-            if p == first_patch:
-                name = p.name
-                # We cannot have a branch pre-depend on a patch/branch
-                # that does not exist yet.  FIXME: if it is really
-                # needed, it should be auto-assimilated by the branch.
-                # This is now done manually in patch_get_branch ().
-                assimilate = True
-            o = patch_depend (patch, p)
-            if assimilate and o and p not in branches[branch]:
-                name = p.name
-                ab = patch_get_branch (p)
-                print 'ASSIMILATE[%(branch)s]: %(name)s [%(ab)s]' % locals ()
-                continue
-            if o:
-                patch_dependencies[p] = p
-                patch_overlaps += [o]
-    branch_dependencies = {}
-    for patch in patch_dependencies.values ():
-        b = patch_get_branch (patch)
-        if b != branch:
-            branch_dependencies[b] = b
-    if not branch_dependencies:
-        return ['pristine']
-    return branch_dependencies.values ()
-
-# No overrides are necessary when using fuzz >= 40
-branch_override_dependencies = {
-    }
-
-def branch_get_dependencies_with_override (branches, patches, branch):
-    return branch_override_dependencies.get (branch, branch_get_dependencies (branches, patches, branch))
-
-GitFailed = SystemFailed
-
-gitignores = '''
-*-
-*-HEAD
-*-git
-*-patched
-*-pristine
-*.bak
-*.cxx-*
-*.deps
-*.git
-*.hxx-*
-*.log
-*.orig
-*.patched
-*.pristine
-*.pyc
-*.rej
-*~
-.\#*
-/Linux*Env.Set*
-/bootstrap
-/makefile.mk
-/solver
-CVS
-TAGS
-\#*
-xxx-have-in-patches-now:localize.sdf
-unxlng*.pro
-autom4te.cache/
-config.log
-config.parms
-config.status
-configure
-set_soenv
-tmon.out
-visibility.cxx
-visibility.s
-warn
-default_images/introabout/intro-save.bmp
-dmake/Makefile
-dmake/config.h
-dmake/config.log
-dmake/config.status
-dmake/dmake
-dmake/*.o
-dmake/dmakeroot.h
-dmake/stamp-h1
-dmake/startup/Makefile
-dmake/startup/config.mk
-dmake/startup/unix/Makefile
-dmake/startup/unix/cygwin/Makefile
-dmake/startup/unix/linux/Makefile
-dmake/startup/unix/macosx/Makefile
-dmake/startup/unix/solaris/Makefile
-dmake/startup/unix/sysvr4/Makefile
-dmake/startup/winnt/Makefile
-dmake/startup/winnt/mingw/Makefile
-dmake/startup/winnt/msvc6/Makefile
-dmake/tests/Makefile
-dmake/unix/.dirstamp
-instsetoo_native/res/banner_nld.bmp
-instsetoo_native/res/banner_ooop.bmp
-instsetoo_native/res/nologoinstall_nld.bmp
-instsetoo_native/res/nologoinstall_ooop.bmp
-instsetoo_native/util/OpenOffice
-sd/xml/transitions-ogl.xml
-setup_native/source/win32/nsis/ooobanner_nld.bmp
-setup_native/source/win32/nsis/ooobanner_ooop.bmp
-setup_native/source/win32/nsis/ooobitmap_nld.bmp
-setup_native/source/win32/nsis/ooobitmap_ooop.bmp
-setup_native/source/win32/nsis/ooosetup_nld.ico
-solenv/unxlng*/
-svx/res
-'''
-keep = '''
-default_images/introabout/intro-save.bmp
-default_images/introabout/intro.bmp
-default_images/svx/res/openabout_ark.png
-default_images/svx/res/openabout_translateorgza.png
-default_images/sw/res/go-oo-team.png
-'''
-
-def create_gitignores (dir):
-    for i in filter_out (operator.not_, gitignores.split ('\n')):
-        if options.split:
-            i = i.replace ('/bootstrap', '/bootstrap/bootstrap')
-        if i[0] == '/':
-            file (dir + '/.gitignore', 'a').write (i + '\n')
-        else:
-            slash = ''
-            if i[-1] == '/':
-                i = i[:-1]
-                slash = '/'
-            file (dir + '/' + os.path.dirname (i) + '/.gitignore', 'a').write (os.path.basename (i) + slash + '\n')
-
-class Setup:
-    string = None
-    vars = {}
-    def __init__ (self, file_name='config.log'):
-        if not self.string and os.path.exists (file_name):
-            self.string = file (file_name).read ()
-    def get (self, key, default=None):
-        return self.vars.get (key, self.read_ (key, default))
-    def read_ (self, key, default):
-        m = re.search ('''%(key)s=['"*]([^*"']*)''' % locals (), self.string)
-        if m:
-            self.vars[key] = m.group (1)
-        else:
-            self.vars[key] = default
-        return self.vars[key]
-
-def get_svn_revision ():
-    return re.search ('\nRevision: ([0-9]+)', read_pipe ('svn info')).group (1)
-
-def get_git_committish ():
-    return re.search ('([^ ]+)', read_pipe ('git log --pretty=oneline -1')).group (1)
-
-class Git:
-    def __init__ (self, dir, patched, clean=False):
-        self.dir = dir
-        self.patched = patched
-        self.scratch = 'work/scratch'
-        self.workspace = options.workspace
-        self.milestone = options.milestone
-        self.pristine = 'upstream/%(workspace)s-m%(milestone)s' % self.__dict__
-        self.commits = {}
-        self.log = {}
-        if not os.path.exists (self.dir):
-            drink = Setup ().get ('DRINK', 'tea')
-            info ('Unpacking source tree - [ go and have some %(drink)s ] ...' % locals ())
-            system ('cd bin && ./unpack')
-            create_gitignores (dir)
-            if options.split:
-                move (self.dir)
-                setup_flat_apply_dir (self.dir)
-            self.system ('touch unpack')
-        if not os.path.isdir (dir + '/.git/refs'):
-            drink = Setup ().get ('DRINK')
-            info ('Creating GIT archive - [ go and have some %(drink)s ] ...' % locals ())
-            self.system ('git init')
-            #svn_revision = get_svn_revision ()
-            #self.commit ('Initial svn:r%(svn_revision)s unpatched.' % locals ())
-            git_committish = get_git_committish ()
-            self.commit ('Initial ooo-build: %(git_committish)s unpatched.' % locals ())
-            self.system ('git branch %(pristine)s' % self.__dict__)
-            self.system ('git tag gob-%(workspace)s-%(milestone)s %(pristine)s' % self.__dict__)
-            self.system ('git branch pristine')
-            self.system ('git gc')
-        if clean:
-            if self.is_modified ():
-                self.system ('git reset --hard HEAD')
-                self.system ('git clean -df')
-        if self.has_branch (self.patched):
-            self.checkout (self.patched)
-        else:
-            self.system ('git checkout -b %(patched)s pristine' % self.__dict__)
-        if self.has_branch (self.scratch):
-            self.system ('git branch -D %(scratch)s' % self.__dict__)
-    def pipe (self, command, raise_on_error=True):
-        dir = self.dir
-        return read_pipe ('cd %(dir)s && %(command)s' % locals (), raise_on_error)
-    def system (self, command, raise_on_error=True):
-        dir = self.dir
-        return system ('cd %(dir)s && %(command)s' % locals (), raise_on_error)
-    def get_branches (self):
-        return filter_out (operator.not_,
-                           self.pipe ('git branch')
-                           .replace ('*', '')
-                           .replace (' ', '').split ('\n'))
-    def get_log (self, branch=''):
-        commit = self.get_current_commit (branch)
-        self.log[commit] = self.log.get (commit, self.pipe ('git log --pretty=oneline %(branch)s --' % locals ()))
-        return self.log[commit]
-    def get_current_commit (self, branch=''):
-        if not branch:
-            branch = 'HEAD'
-        return self.pipe ('git rev-parse %(branch)s' % locals ())[:-1]
-    def get_commit (self, patch):
-        if not self.commits:
-            log = self.get_log (self.patched)
-            def grok_log_line (s):
-                m = re.match ('([^ ]+) Apply.*/([^/]+[.](diff|patch))', s)
-                if not m:
-                    info ('Skipping line:%(s)s:' % locals ())
-                    return None, None
-                return m.group (2), m.group (1)
-            self.commits = dict (map (grok_log_line, log.split ('\n')[:-2]))
-        return self.commits.get (patch, None)
-    def commit (self, message):
-        self.system ('git add .')
-        self.system ('git add -u .')
-        self.system ('''git commit -m '%(message)s' ''' % locals ())
-    def is_modified (self):
-        return re.sub ('# On branch.*\nnothing to commit \(working directory clean\)\n', '',
-                       self.pipe ('git status', raise_on_error=False))
-    def assert_clean (self):
-        dir = self.dir
-        pending = self.is_modified ()
-        if pending:
-            raise GitFailed ('working directory unclean: %(dir)s\n%(pending)s' % locals ())
-    def checkout (self, branch):
-        if not self.is_on_branch (branch):
-            self.system ('git checkout %(branch)s' % locals ())
-    def get_current_branch (self):
-        return self.pipe ('git symbolic-ref HEAD', raise_on_error=False)[len ('refs/heads/'):-1]
-    def is_on_branch (self, branch):
-        return branch == self.get_current_branch ()
-    def has_branch (self, branch):
-        return branch in self.get_branches ()
-    def apply_patch (self, branches, patches, patch):
-        branch = patch_get_branch (patch)
-        info ('Applying patch[%(branch)s]: ' % locals () + patch.name)
-        patched = self.get_current_branch ()
-        apply_patch (self.dir, patch.file_name)
-        base = os.path.basename (patch.file_name)
-        self.commit ('Apply %(base)s.' % locals ())
-        if options.milestone == '19':
-            dependencies = manual_m19_branch_dependencies.get (branch, ['pristine'])
-        else:
-            dependencies = branch_get_dependencies_with_override (branches, patches, branch)
-        if not self.has_branch (branch):
-            if not options.topgit:
-                base_depend = dependencies[0]
-                self.system ('git checkout -b %(branch)s %(base_depend)s' % locals ())
-                for dependency in dependencies[1:]:
-                    self.system ('git rebase %(dependency)s' % locals ())
-            else:
-                depend_str = ' '.join (dependencies)
-                self.system ('tg create %(branch)s %(depend_str)s' % locals ())
-                self.system ('git commit -am "topgit branch info %(branch)s"' % locals ())
-        else:
-            self.checkout (branch)
-        log = self.get_log (patched)
-        commit = log[:log.index (' ')]
-        self.system ('git cherry-pick -x %(commit)s' % locals ())
-    def before_ (self):
-        self.assert_clean ()
-        self.system ('git checkout -b %(scratch)s %(patched)s' % self.__dict__)
-    def after_ (self):
-        self.system ('git push . %(scratch)s:%(patched)s' % self.__dict__)
-        self.checkout (self.patched)
-        self.system ('git branch -D %(scratch)s' % self.__dict__)
-    def pick_patch (self, patch, commit):
-        branch = patch_get_branch (patch)
-        info ('Picking patch[%(branch)s]: ' % locals () + patch.name)
-        self.system ('git cherry-pick -x %(commit)s' % locals ())
-    def add_patch (self, branches, patches, patch):
-        if patch.name in self.get_log ():
-            info ('patch already applied, skipping: ' + patch.name)
-            return
-        if file (patch.file_name).read ().find ('\n+++ ') == -1:
-            info ('patch is empty, skipping: ' + patch.name)
-            return
-        commit = None
-        branch = patch_get_branch (patch)
-        if self.has_branch (branch):
-            name = patch.name.replace ('+', '\+')
-            m = re.search ('(^|\n)([^\s]+)\s+.*(\s|/)%(name)s' % locals (), self.get_log (branch))
-            if m:
-                commit = m.group (2)
-        self.before_ ()
-        if commit:
-            self.pick_patch (patch, commit)
-        else:
-            self.apply_patch (branches, patches, patch)
-        self.after_ ()
-    def dump_gob (self, branches, patches, branch):
-        gob_dir = self.dir + '/.git/refs/gob'
-        if not os.path.exists (gob_dir):
-            makedirs (gob_dir)
-        branch_patches = branches.get (branch, [])
-        if not branch_patches:
-            return
-        owner = ''
-        for patch in branch_patches:
-            owner = patch.owner
-            if owner:
-                break
-        issues = []
-        for patch in branch_patches:
-            issues += patch.issues
-        issue_string = ', '.join (issues)
-        dependencies = filter (lambda x: x != 'pristine', branch_get_dependencies (branches, patches, branch))
-        dependencies_string = ', '.join (dependencies)
-        commit = self.get_current_commit ()
-        gob_file_name = os.path.join (gob_dir, branch)
-        info ('Writing: ' + gob_file_name)
-        file (gob_file_name, 'w').write ('''%(commit)s
-state: stable
-issue: %(issue_string)s
-owner: %(owner)s
-depend: %(dependencies_string)s
-''' % locals ())
-
-class Patch:
-    def __init__ (self, file_name):
-        self.file_name = file_name
-        if self.file_name:
-            self.set_files ()
-        self.file_name = None
-    def set_files (self):
-        self.files = dict (map (lambda x: (x.name, x), map (File, ('\n' + file (self.file_name).read ()).split ('\n---')[1:])))
-    def __repr__ (self):
-        return '<Patch: ' + str (map (str, self.files.values ())) + ' >'
-
-class Apply_patch (Patch):
-    def __init__ (self, s, section, owner, issue):
-        Patch.__init__ (self, None)
-        self.string = s
-        self.section = section
-        self.owner = owner
-        m = re.search (', (\w\w+)', self.string)
-        if m:
-            self.owner = m.group (1)
-        m = re.match ('^\s*(([^#\s].*).(diff|patch))(.*)', self.string)
-        self.name = m.group (1)
-        self.base = m.group (2)
-        self.issues = map (lambda x: x[0], re.findall ('((i|n)#[0-9]+)', self.string))
-        if issue:
-            self.issues.append (issue)
-    def __repr__ (self):
-        return '<Patch: %(file_name)s [%(section)s] %(owner)s %(issues)s>' % self.__dict__
-    def set_file_name (self, dir, path):
-        self.file_name = find_file (dir, path, self.name)
-        self.set_files ()
-        return self
-
-class Section:
-    def __init__ (self, s):
-        self.string = s
-        m = re.match ('[[\s]*(.*[^\s])\s*\]', self.string)
-        self.tag = m.group (1).replace (' ', '')
-        self.name = re.sub ('[^\w].*', '', self.tag)
-        m = re.search ('\n(SectionOwner)\s*=>\s*(.*[^\s])', self.string)
-        self.owner = ''
-        if m:
-            self.owner = m.group (2)
-        m = re.search ('\n(SectionIssue)\s*=>\s*(.*[^\s])', self.string)
-        self.issue = ''
-        if m:
-            self.issue = m.group (2)
-    def __repr__ (self):
-        return '<Section: %(tag)s %(owner)s %(issue)s>' % self.__dict__
-    def get_patches (self):
-        def create_patch (s):
-            return Apply_patch (s[0], self.tag, self.owner, self.issue)
-        return map (create_patch, re.findall ('\n\s*([^#\s].*.(diff|patch).*)', self.string))
-
-class Apply:
-    def __init__ (self, apply_file, workspace, milestone):
-        self.workspace = workspace
-        self.milestone = milestone
-        self.string = file (apply_file).read ()
-        first_section = self.string.index ('\n[')
-        self.distros_string = self.string[:first_section]
-        self.sections_string = self.string[first_section:]
-        self.path = re.search ('\nPATCHPATH=(.*)', self.string).group (1).split (':')
-        self.distro = {}
-        self.master = {}
-        self.distros_string = re.sub ('\s*\\\s*\n\s*', '', self.distros_string)
-        for distro in re.findall ('\n\s*([^#=\s:]+)\s*:\s*(.*)', self.distros_string):
-            lst = distro[1].replace (' ', '').split (',')
-            expanded = []
-            for i in lst:
-                if i in self.master.keys ():
-                    del self.master[i]
-                expanded += self.distro.get (i, [i])
-            self.master[distro[0]] = self.distro[distro[0]] = expanded
-        # convenience: add sections as distro
-        #self.distro.update (dict (map (lambda x: (x.name, x.name), self.get_sections ())))
-    def get_section_strings (self):
-        return map (lambda x: '[' + x, self.sections_string.split ('\n[')[1:])
-    def get_sections (self):
-        return map (Section, self.get_section_strings ())
-    def get_distro (self, distro_name):
-        def section_in_distro (section):
-            if distro_name not in self.distro.keys ():
-                return distro_name == section.name
-            m = re.search ('(\w+).*(<=|<|==|!=|>=|>)%(workspace)s-m([0-9]+)'
-            % self.__dict__, section.tag)
-            if m:
-                name = m.group (1)
-                if not name in self.distro[distro_name]:
-                    return False
-                left_milestone = self.milestone
-                operator = m.group (2)
-                right_milestone = int (m.group (3))
-                return eval ('%(left_milestone)s %(operator)s %(right_milestone)s' % locals ())
-            else:
-                return section.tag in self.distro[distro_name]
-        return filter (section_in_distro, self.get_sections ())
-
-class Command:
-    def __init__ (self, apply, options):
-        self.options = options
-        self.apply = apply
-        self.patches_ = []
-        self.branches_ = {}
-    def patches (self):
-        '''list patches'''
-        print '\n'.join (map (str, self.get_patches ()))
-    def sections (self):
-        '''list sections'''
-        print '\n'.join (map (str, self.get_sections ()))
-    def distros (self):
-        '''list distros'''
-        print '\n'.join (map (str, self.apply.distro.keys ()))
-    def masters (self):
-        '''list masters'''
-        print '\n'.join (map (str, self.apply.master.keys ()))
-    def branches (self):
-        '''list branches'''
-        print '\n'.join (map (str, self.get_branches ().keys ()))
-    def get_branches (self):
-        if not self.branches_:
-            for patch in self.get_patches ():
-                branch = patch_get_branch (patch)
-                self.branches_[branch] = self.branches_.get (branch, []) + [patch]
-        return self.branches_
-    def dump_gobs (self):
-        '''dump gob files'''
-        branches = self.get_branches ()
-        patches = self.get_patches ()
-        git = Git (self.options.build_dir, self.options.patched)
-        for branch in git.get_branches ():
-            git.dump_gob (branches, patches, branch)
-    def checkout (self):
-        '''checkout patched ('master') branch'''
-        git = Git (self.options.build_dir, self.options.patched)
-    def git_export (self):
-        '''export to GIT with branches'''
-        git = Git (self.options.build_dir, self.options.patched, clean=True)
-        patches = self.get_patches ()
-        branches = self.get_branches ()
-        for patch in self.get_patches ():
-            git.add_patch (branches, patches, patch)
-        git.system ('git gc')
-    def get_patches_for_distro (self, distro):
-        patches = reduce (operator.add, map (lambda section: section.get_patches (), self.get_sections_for_distro (distro)))
-        for patch in patches:
-            patch.set_file_name (self.options.apply_dir, self.apply.path)
-        return patches
-    def get_patches (self):
-        if not self.patches_:
-            self.patches_ = reduce (operator.add, map (self.get_patches_for_distro, self.options.distros))
-        return self.patches_
-    def get_sections_for_distro (self, distro):
-        return self.apply.get_distro (distro)
-    def get_sections (self):
-        return reduce (operator.add, map (self.get_sections_for_distro, self.options.distros))
-    def prepare (self):
-        '''prepare ooo-build dir for use with GIT'''
-        git = Git (self.options.build_dir, self.options.patched)
-    def postpare (self):
-        '''update ooo-build dir GIT after patching'''
-        git = Git (self.options.build_dir, self.options.patched)
-        #svn_revision = get_svn_revision ()
-        #git.commit ('Update to svn:r%(svn_revision)s patched.' % locals ())
-        git_committish = get_git_committish ()
-        git.commit ('Update to ooo-build: %(git_committish)s patched.' % locals ())
-        git.system ('git rebase patched')
-    def dependencies (self):
-        '''list branch dependencies'''
-        patches = self.get_patches ()
-        branches = self.get_branches ()
-        independent = 0
-        for branch in branches:
-            dependencies = sorted (branch_get_dependencies (branches, patches, branch))
-            if dependencies == ['pristine']:
-                independent += 1
-            print 'BRANCH:', branch, '->', dependencies
-        print 'INDEPENDENT:', independent
-    def patch_dependencies (self):
-        '''list patch dependencies'''
-        branches = self.get_branches ()
-        patches = self.get_patches ()
-        for patch in patches:
-            branch = patch_get_branch (patch)
-            name = patch.name
-            print 'PATCH[%(branch)s]: %(name)s -> ' % locals (), patch_get_dependencies (patches, patch)
-    def bump (self):
-        '''bump BRANCH TAG-NAME - bump current branch (BRANCH=new upstream)'''
-        if len (self.options.arguments) != 2:
-            print 'Usage: gob bump BRANCH TAG-NAME'
-            print 'BRANCH: new upstream'
-            print 'Example:'
-            print '    gob bump upstream/dev300-m21 my-21-update'
-            sys.exit (2)
-        branch = self.options.arguments[0]
-        tag = self.options.arguments[1]
-        git_dir = self.options.build_dir
-        system ('cd %(git_dir)s && gob-bump %(branch)s %(tag)s' % locals ())
-    def update (self):
-        '''update BRANCH - update current branch (BRANCH='master')'''
-        if len (self.options.arguments) != 1:
-            print 'Usage: gob update BRANCH'
-            print '''BRANCH: the 'master' branch'''
-            print 'Example: '
-            print '    gob update distro/SUSE'
-            sys.exit (2)
-        branch = self.options.arguments[0]
-        git_dir = self.options.build_dir
-        system ('cdi %(git_dir)s && gob-update %(branch)s' % locals ())
-    def reset (self):
-        '''reset - set GIT tree to pristine and remove all branches'''
-        git = Git (self.options.build_dir, self.options.patched)
-        git.system ('git checkout -f %(patched)s' % git.__dict__)
-        git.system ('git reset --hard pristine')
-        git.system ('git clean -df')
-        git.system ('rm -rf .git/refs/top-bases')
-        cmd = 'xargs git branch -D'
-        if options.split:
-            git.system ('''git branch | grep -Ev '/|master|patched|pristine|upstream|%(patched)s' | xargs tg delete -f ''' % git.__dict__)
-        git.system ('''git branch | grep -Ev '/|master|patched|pristine|upstream|%(patched)s' | xargs git branch -D''' % git.__dict__)
-    def patch_depend (self):
-        '''patch-depend PATCH-1 PATCH-2 - show overlap between patches'''
-        if len (self.options.arguments) != 2:
-            print 'Usage: patch-depend PATCH-1 PATCH-2'
-            sys.exit (2)
-        union = patch_depend (Patch (self.options.arguments[0]), Patch (self.options.arguments[1]))
-        if union:
-            print union[0], '--', union[1]
-            print union[2]
-            print '<<<<<<<<<<<<<<<<<<<<<<<<<=========================>>>>>>>>>>>>>>>>>>>>>>>>>'
-            print union[3]
-            sys.exit (1)
-    def statistics (self):
-        ### not advertised
-        ### show some statistics on dependensies
-        patches = self.get_patches ()
-        branches = self.get_branches ()
-        full_match = 0
-        match = 0
-        fail = 0
-        extra = 0
-        independent = 0
-        for branch in branches:
-            manual_dependencies = sorted (manual_m19_branch_dependencies.get (branch, ['pristine']))
-            auto_dependencies = sorted (branch_get_dependencies (branches, patches, branch))
-            missing = False
-            for m in manual_dependencies:
-                if m != 'pristine' and not m in auto_dependencies:
-                    missing = True
-                    break
-            if missing:
-                fail += 1
-                print
-                print 'BRANCH:', branch
-                print 'MANUAL:', manual_dependencies
-                print 'AUTO:', auto_dependencies
-                #dependencies 'OVERLAPS:', overlaps
-            if auto_dependencies == ['pristine']:
-                independent += 1
-            elif auto_dependencies == manual_dependencies:
-                full_match += 1
-            elif manual_dependencies == ['pristine']:
-                extra += 1
-                #print 'BRANCH:', branch
-                #print 'EXTRA:', auto_dependencies
-            elif not missing:
-                match += 1
-        print
-        print 'FAIL:', fail
-        print 'FULL_MATCH:', full_match
-        print 'MATCH:', match
-        print 'EXTRA:', extra
-        print 'INDEPENDENT:', independent
-    def move (self):
-        move (options.build_dir)
-        setup_flat_apply_dir (options.build_dir)
-    def move_back (self):
-        move_back (options.build_dir)
-
-def get_cli_parser ():
-    p = optparse.OptionParser ()
-
-    p.usage = '%prog [OPTION]... COMMAND\n\nCommands:\n'
-    d = Command.__dict__
-    commands = [(k, d[k].__doc__) for k in d.keys ()
-                if d[k].__doc__ and type (d[k]) == type (lambda x: x)]
-    commands.sort ()
-
-    global src_dir
-    src_dir = ''
-    if not os.path.exists ('patches'):
-        src_dir = '../'
-    os.environ['PATH'] = src_dir + '/bin:' + os.environ['PATH']
-
-    for (command, doc) in commands:
-        p.usage += '    %s - %s\n' % (re.sub ('_', '-', command), doc)
-
-    def get (option):
-        return p.get_option ('--' + option.replace ('-', '_')).default
-
-    setup_workspace, setup_milestone = Setup ().get ('CVSTAG', 'dev300-m19').split ('-m')
-
-    p.add_option ('--workspace',
-                  dest='workspace',
-                  default=setup_workspace,
-                  metavar='STRING',
-                  help='set master workspace')
-    p.add_option ('--milestone',
-                  dest='milestone',
-                  default=setup_milestone,
-                  metavar='STRING',
-                  help='set milestone')
-    p.add_option ('--distro',
-                  action='append',
-                  dest='distros',
-                  default=[],
-                  metavar='DISTRO',
-                  help='add distribution')
-    p.add_option ('--build-dir',
-                  default=src_dir + 'build/' + get ('workspace') + '-m' + get ('milestone'),
-                  dest='build_dir',
-                  metavar='DIR',
-                  help='build (/git) directory')
-    p.add_option ('--apply-dir',
-                  default=src_dir + 'patches/' + get ('workspace'),
-                  dest='apply_dir',
-                  metavar='DIR',
-                  help='directory with APPLY file')
-    p.add_option ('--patched',
-                  default='patched',
-                  dest='patched',
-                  metavar='NAME',
-                  help='''use NAME as patched 'master' branch name''')
-    p.add_option ('--dir-branch',
-                  default=[],
-                  dest='dir_branch',
-                  metavar='DIR',
-                  help='aggregate patches in directory DIR into one branch')
-    p.add_option ('--fuzz',
-                  default='40', # FIXME: 40 = magic sweet spot for dev300-m21
-                  dest='fuzz',
-                  metavar='INT',
-                  help='use FUZZ as fuzz factor for patch overlap')
-    p.add_option ('--force', action='store_true', dest='force', default=False)
-    p.add_option ('--split', action='store_true', dest='split', default=False)
-    p.add_option ('--topgit', action='store_true', dest='topgit', default=False)
-    p.add_option ('-v', '--verbose', action='count', dest='verbose', default=1)
-    p.add_option ('-q', '--quiet', action='count', dest='quiet', default=0)
-    return p
-
-def parse_options ():
-    p = get_cli_parser ()
-    (options, arguments) = p.parse_args ()
-
-    options.command = ''
-    options.arguments = []
-    if arguments:
-        options.command = re.sub ('-', '_', arguments.pop (0))
-    options.arguments = arguments
-
-    if options.command in Command.__dict__:
-        return options
-    if options.command:
-        sys.stderr.write ('no such command: ' + options.command)
-        sys.stderr.write ('\n\n')
-    p.print_help ()
-    sys.exit (2)
-
-def set_option_defaults (options):
-    options.flat_apply_dir = '.git/apply-dir'
-    options.verbose -= options.quiet
-    options.apply_dir = (options.apply_dir
-                         .replace ('ooo300', 'dev300')
-                         .replace ('ooo310', 'dev300')
-                         .replace ('ooo320', 'dev300')
-                         )
-    if not options.distros:
-        options.distros = ['SUSE']
-    if not options.dir_branch:
-        options.dir_branch = filter (lambda x: x not in ['.', '..', '.svn', '64bit', 'dev300', 'hotfixes'], list_dirs (options.apply_dir + '/..'))
-        too_dispersed = ['cairo', 'vba']
-        options.dir_branch = filter (lambda x: x not in too_dispersed, options.dir_branch)
-    return options
-
-options = None
-def main ():
-    global options
-    options = set_option_defaults (parse_options ())
-    apply_file = options.apply_dir + '/apply'
-    apply = Apply (apply_file, options.workspace, options.milestone)
-    Command.__dict__[options.command] (Command (apply, options))
-
-if __name__ == '__main__':
-    main ()
diff --git a/configure.in b/configure.in
index 90500e4..b1df923 100644
--- a/configure.in
+++ b/configure.in
@@ -1630,7 +1630,6 @@ AC_SUBST(OOO_ADDITIONAL_SECTIONS)
 
 
 AC_CONFIG_FILES([bin/font-munge], [chmod +x bin/font-munge])
-AC_CONFIG_FILES([bin/gob], [chmod +x bin/gob])
 AC_CONFIG_FILES([bin/help-font-munge], [chmod +x bin/help-font-munge])
 AC_CONFIG_FILES([download], [chmod +x download])
 AC_CONFIG_FILES([scratch/place], [chmod +x scratch/place])


More information about the ooo-build-commit mailing list