reorganized component and repository code into separate modules
[matrix.git] / matrix / matrix.py
index 347f499..0534127 100644 (file)
@@ -4,14 +4,12 @@
 #          Kalle Vahlman <kalle.vahlman@movial.fi>
 #          Tuomas Kulve <tuomas.kulve@movial.fi>
 
-import glob
 import os
-import re
 import sys
-import tarfile
 from sets import Set as set
 
 import cache
+import components
 import config
 import git
 import log
@@ -35,7 +33,7 @@ def main():
        if not os.path.exists(config.cache_dir):
                os.makedirs(config.cache_dir)
 
-       all_targets = update_components()
+       all_targets = components.init()
 
        for name in targets:
                if name not in config.components:
@@ -45,17 +43,17 @@ def main():
                targets = all_targets
 
        if command == 'install':
-               build_components(targets, **params)
+               build(targets, **params)
        elif command == 'clone':
-               clone_components(targets)
+               clone(targets)
        elif command == 'clean':
-               clean_components(targets)
+               clean(targets)
        elif command == 'rebase':
-               rebase_components(targets)
+               rebase(targets)
        elif command == 'pull':
-               pull_components(targets)
+               pull(targets)
        elif command == 'source-dist':
-               source_dist_components(targets)
+               source_dist(targets)
        elif command == 'rootfs':
                build_rootfs(**params)
        else:
@@ -170,100 +168,6 @@ def parse_config(path):
                print 'Reading', path
                execfile(path, config.__dict__, config.__dict__)
 
-def update_components():
-       targets = []
-       packages = {}
-
-       for c in config.components.itervalues():
-               update_component_url(c)
-               clone_metadata(c)
-               update_component_packages(c, targets, packages)
-               c.active_depends = []
-
-       update_component_depends(packages)
-
-       return targets
-
-def update_component_url(c):
-       update_repository_url(c.repo)
-       update_repository_url(c.meta)
-
-def update_repository_url(repo):
-       if git.contains_database(repo.path):
-               url = git.getvar(repo.path, 'remote.origin.url')
-               if url:
-                       repo.active_url = url
-                       if config.debug:
-                               print 'Using', repo.active_url
-                       return
-
-       for root in config.roots:
-               for suffix in ('.git', ''):
-                       url = '%s/%s%s' % (root, repo.name, suffix)
-
-                       if config.debug:
-                               print 'Trying', url
-
-                       if not git.peek_remote(url, quiet=True):
-                               continue
-
-                       repo.active_url = url
-                       if config.debug:
-                               print 'Found', repo.active_url
-                       return
-
-       raise Error('Failed to locate repository: ' + repo.name)
-
-def update_component_depends(packages):
-       for pkg in packages.itervalues():
-               for spec in pkg.depends.split():
-                       depname = Depend(spec).name
-                       deppkg = packages.get(depname)
-
-                       if not deppkg:
-                               log.error('Package %s depends on ' \
-                                         'non-existent package %s' % \
-                                         (pkg.name, depname))
-                               continue
-
-                       if deppkg.component == pkg.component:
-                               continue
-
-                       pkg.component.active_depends.append(deppkg.component)
-
-       fail = False
-       for pkg in packages.itervalues():
-               for spec in pkg.depends.split():
-                       if not Depend(spec).check(packages):
-                               fail = True
-                               log.error('Dependency %s failed for %s' % \
-                                         (spec, pkg.name))
-
-               for spec in pkg.conflicts.split():
-                       if Depend(spec).check(packages):
-                               fail = True
-                               log.error('Package %s conflicts with %s' % \
-                                         (pkg.name, spec))
-
-       if fail:
-               raise Error('Invalid component tree')
-
-class Depend(object):
-       regex = re.compile(r'([@]?)([^\s:]+)[:]?([<>=]*)([^\s:]*)[:]?(.*)')
-
-       def __init__(self, spec):
-               match = self.regex.match(spec)
-               if not match:
-                       raise Error('Bad dependency specification: ' + spec)
-
-               self.build, self.name, self.tag_op, self.tag, flags \
-                       = match.groups()
-               self.flags = flags.split()
-
-       def check(self, packages):
-               # TODO: check version and flags
-               return self.name in packages
-
 def execute(args):
        if config.debug:
                print 'Executing:', ' '.join(args)
@@ -274,17 +178,14 @@ def execute(args):
 def remove_tree(path):
        execute(['rm', '-rf', path])
 
-def clone_components(targets):
-       if not targets:
-               targets = config.components.keys()
-
+def clone(targets):
        for name in targets:
                c = config.components[name]
                clone_component(c)
 
 def clone_component(c, overwrite=False):
-       have_repo = git.contains_database(c.repo.path)
-       have_meta = git.contains_database(c.meta.path)
+       have_repo = c.repo.exists()
+       have_meta = c.meta.exists()
 
        if not overwrite and have_repo and have_meta:
                return
@@ -297,77 +198,11 @@ def clone_component(c, overwrite=False):
                have_meta = False
 
        if not have_repo:
-               clone_repository(c.repo)
-               git.exclude(c.repo.path, 'meta')
-
+               c.repo.clone()
        if not have_meta:
-               clone_repository(c.meta)
-
-def clone_metadata(c):
-       if not git.contains_database(c.meta.path):
-               clone_repository(c.meta)
-
-def clone_repository(repo):
-       print 'Cloning', repo.path
-
-       if os.path.exists(repo.path):
-               tmp = os.path.join(repo.path, 'tmp')
-               git.clone(tmp, repo.active_url, checkout=False)
-               try:
-                       tmpdb = os.path.join(tmp, '.git')
-                       repodb = os.path.join(repo.path, '.git')
-                       if config.debug:
-                               print 'Renaming "%s" as "%s"' % (tmpdb, repodb)
-                       os.rename(tmpdb, repodb)
-               finally:
-                       os.rmdir(tmp)
-       else:
-               git.clone(repo.path, repo.active_url, checkout=False)
-
-       git.reset(repo.path, repo.get_commit(), hard=True)
-
-def update_component_packages(c, targets, packages):
-       c.active_packages = {}
-
-       for path in glob.glob(os.path.join(c.meta.path, '*.package')):
-               name = os.path.basename(path)[:-8]
-
-               pkg = parse_package(name, c, path)
-               if not pkg:
-                       continue
+               c.meta.clone()
 
-               c.active_packages[name] = pkg
-               packages[name] = pkg
-
-               if config.debug:
-                       print 'Component', c.name, 'provides', name
-
-       if c.active_packages:
-               targets.append(c.name)
-       elif config.debug:
-               print 'Component', c.name, 'does not provide any packages'
-
-class Package(object):
-       def __init__(self, name, component):
-               self.name = name
-               self.component = component
-
-               self.depends = []
-               self.conflicts = []
-               self.architectures = None
-
-def parse_package(name, component, path):
-       pkg = Package(name, component)
-       execfile(path, pkg.__dict__, pkg.__dict__)
-
-       if pkg.architectures:
-               arch = config.boards[config.board].arch
-               if arch not in pkg.architectures:
-                       return None
-
-       return pkg
-
-def build_components(targets, build_jobs=1, make_jobs=1):
+def build(targets, build_jobs=1, make_jobs=1):
        selected = set([config.components[i] for i in targets])
 
        depends = None
@@ -375,122 +210,74 @@ def build_components(targets, build_jobs=1, make_jobs=1):
                depends = set()
 
                for c in selected:
-                       for dep in c.active_depends:
+                       for dep in c.depends:
                                if dep not in selected:
                                        depends.add(dep)
 
                selected |= depends
 
-       components = list(selected)
-       components.sort()
-
        if config.debug:
                print 'Building components:'
-               for c in components:
+
+               sorted = list(selected)
+               sorted.sort(key=lambda c: c.name)
+
+               for c in sorted:
                        print '\t' + c.name
 
-       builder = Builder(components, build_jobs, make_jobs)
+       builder = Builder(selected, build_jobs, make_jobs)
        builder.run()
 
-def clean_components(targets):
-       if not targets:
-               targets = config.components.keys()
-
+def clean(targets):
        for name in targets:
                c = config.components[name]
-               print 'Cleaning', c.repo.path
-
+               c.repo.clean()
                cache.remove(c)
 
-               files = git.ls_files(c.repo.path, ['-o'])
-               paths = [os.path.join(c.repo.path, i) for i in files]
-               paths.sort()
-               paths.reverse()
-
-               for path in paths:
-                       if git.contains_database(path):
-                               continue
-
-                       if config.debug:
-                               print 'Removing', path
-
-                       if os.path.islink(path) or not os.path.isdir(path):
-                               os.remove(path)
-                       else:
-                               remove_tree(path)
-
                for repo in (c.repo, c.meta):
-                       files = git.ls_files(repo.path, ['-m', '-d'])
-                       if files:
+                       if repo.dirty_files():
                                log.error('Dirty files left in %s' % repo.path)
 
 def for_each_repository(func, targets=None):
-       if not targets:
-               targets = config.components.keys()
-
        for name in targets:
                c = config.components[name]
-               if git.contains_database(c.repo.path):
+               if c.repo.exists():
                        func(c.repo)
                func(c.meta)
 
-def rebase_components(targets):
-       for_each_repository(rebase_repository, targets)
-
-def pull_components(targets):
-       for_each_repository(pull_repository, targets)
+def rebase(targets):
+       for_each_repository(lambda repo: repo.rebase(), targets)
 
-def rebase_repository(repo):
-       print 'Rebasing', repo.path
-       git.remote_update(repo.path)
-       git.rebase(repo.path)
+def pull(targets):
+       for_each_repository(lambda repo: repo.pull(), targets)
 
-def pull_repository(repo):
-       print 'Pulling', repo.path
-       git.pull(repo.path)
-
-def source_dist_components(targets):
-       if not targets:
-               targets = config.components.keys()
+def source_dist(targets):
+       location = 'dist'
+       if not os.path.exists(location):
+               os.makedirs(location)
 
        for name in targets:
                c = config.components[name]
-               generate_component_changes(c, 'dist')
-               package_component_sources(c, 'dist')
-
-def generate_component_changes(c, location):
-       print 'Generating change log for', c.repo.path
+               dist_changes(c, location)
+               dist_sources(c, location)
 
+def dist_changes(c, location):
        path = os.path.join(location, c.name) + '.changes'
+       c.repo.dump_log(path)
 
-       pathdir = os.path.dirname(path)
-       if not os.path.exists(pathdir):
-               os.makedirs(pathdir)
-
-       fd = os.open(path, os.O_WRONLY | os.O_CREAT, 0644)
-       git.log(c.repo.path, [c.repo.get_commit()], fd=fd)
-       os.close(fd)
-
-def package_component_sources(c, location):
-       print 'Archiving', c.repo.path
-
-       rev = git.describe(c.repo.path)
+def dist_sources(c, location):
+       rev = c.repo.describe()
        if rev:
                rev = '_' + rev
        else:
                rev = ''
 
-       path = os.path.join(location, c.name) + rev + '.tar.bz2'
+       name = c.name + rev
+       path = os.path.join(location, name) + '.tar.bz2'
        if os.path.exists(path):
                os.remove(path)
 
-       pathdir = os.path.dirname(path)
-       if not os.path.exists(pathdir):
-               os.makedirs(pathdir)
-
-       git.archive(c.repo.path, path,
-                   prefix=os.path.basename(c.name) + '/',
-                   treeish=c.repo.get_commit())
+       c.repo.archive(name, path)
 
 def build_rootfs(clean=True, rootfs_only=False, jffs2_only=False, devrootfs_only=False):
        parse_config('rootfs')