aboutsummaryrefslogblamecommitdiffstats
path: root/libbe/bugdir.py
blob: 7570bb37f9a632b58f571d28e915b45e059af3ae (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16















                                                                              


              
            
            
              

              
                           
                   
 
                          



                                                                 











                                                               
 
                                      

                                                           
                                       

                                         
                                                       

                                         



                                           
 




                                                                          
                       



                                           
                           



                                                                             
 




                                                                            





                                                                              
                              
       
                            


                                                                         





                                                            
       
                                    
        
                                      
                      




                                          
                 
                                         
                          

                                                                            
                                            
 




















                                                        



                                                       
            

                                                                                

                                                
                                                                                 

               
                                       
    
                            

                                                                           

                      
                                                                     




                                              
 


                                                                 
                   
                                      

                                    





                                

                                                       

                         


                                               
                      
 


                                 
                                                 

                                                      


                       
                               




                                                            
# Copyright (C) 2005 Aaron Bentley and Panometrics, Inc.
# <abentley@panoramicfeedback.com>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
import os
import os.path
import cmdutil
import errno
import names
import mapfile
import time
import utility
from rcs import rcs_by_name
from bug import Bug

class NoBugDir(Exception):
    def __init__(self, path):
        msg = "The directory \"%s\" has no bug directory." % path
        Exception.__init__(self, msg)
        self.path = path

 
def iter_parent_dirs(cur_dir):
    cur_dir = os.path.realpath(cur_dir)
    old_dir = None
    while True:
        yield cur_dir
        old_dir = cur_dir
        cur_dir = os.path.normpath(os.path.join(cur_dir, '..'))
        if old_dir == cur_dir:
            break;


def tree_root(dir, old_version=False):
    for rootdir in iter_parent_dirs(dir):
        versionfile=os.path.join(rootdir, ".be", "version")
        if os.path.exists(versionfile):
            if not old_version:
                test_version(versionfile)
            return BugDir(os.path.join(rootdir, ".be"))
        elif not os.path.exists(rootdir):
            raise NoRootEntry(rootdir)
        old_rootdir = rootdir
        rootdir=os.path.join('..', rootdir)
    
    raise NoBugDir(dir)

class BadTreeVersion(Exception):
    def __init__(self, version):
        Exception.__init__(self, "Unsupported tree version: %s" % version)
        self.version = version

def test_version(path):
    tree_version = file(path, "rb").read()
    if tree_version != TREE_VERSION_STRING:
        raise BadTreeVersion(tree_version)

def set_version(path, rcs):
    rcs.set_file_contents(os.path.join(path, "version"), TREE_VERSION_STRING)
    

TREE_VERSION_STRING = "Bugs Everywhere Tree 1 0\n"

class NoRootEntry(Exception):
    def __init__(self, path):
        self.path = path
        Exception.__init__(self, "Specified root does not exist: %s" % path)

class AlreadyInitialized(Exception):
    def __init__(self, path):
        self.path = path
        Exception.__init__(self, 
                           "Specified root is already initialized: %s" % path)

def create_bug_dir(path, rcs):
    """
    >>> import no_rcs, tests
    >>> create_bug_dir('/highly-unlikely-to-exist', no_rcs)
    Traceback (most recent call last):
    NoRootEntry: Specified root does not exist: /highly-unlikely-to-exist
    >>> test_dir = os.path.dirname(tests.bug_arch_dir().dir)
    >>> try:
    ...     create_bug_dir(test_dir, no_rcs)
    ... except AlreadyInitialized, e:
    ...     print "Already Initialized"
    Already Initialized
    """
    root = os.path.join(path, ".be")
    try:
        rcs.mkdir(root, paranoid=True)
    except OSError, e:
        if e.errno == errno.ENOENT:
            raise NoRootEntry(path)
        elif e.errno == errno.EEXIST:
            raise AlreadyInitialized(path)
        else:
            raise
    rcs.mkdir(os.path.join(root, "bugs"))
    set_version(root, rcs)
    mapfile.map_save(rcs,
                     os.path.join(root, "settings"), {"rcs_name": rcs.name})
    return BugDir(os.path.join(path, ".be"))


def setting_property(name, valid=None):
    def getter(self):
        value = self.settings.get(name) 
        if valid is not None:
            if value not in valid:
                raise InvalidValue(name, value)
        return value

    def setter(self, value):
        if valid is not None:
            if value not in valid and value is not None:
                raise InvalidValue(name, value)
        if value is None:
            del self.settings[name]
        else:
            self.settings[name] = value
        self.save_settings()
    return property(getter, setter)


class BugDir:
    def __init__(self, dir):
        self.dir = dir
        self.bugs_path = os.path.join(self.dir, "bugs")
        try:
            self.settings = mapfile.map_load(os.path.join(self.dir, "settings"))
        except mapfile.NoSuchFile:
            self.settings = {"rcs_name": "None"}

    rcs_name = setting_property("rcs_name", ("None", "bzr", "git", "Arch", "hg"))
    _rcs = None

    target = setting_property("target")
    
    def save_settings(self):
        mapfile.map_save(self.rcs,
                         os.path.join(self.dir, "settings"), self.settings)

    def get_rcs(self):
        if self._rcs is not None and self.rcs_name == self._rcs.name:
            return self._rcs
        self._rcs = rcs_by_name(self.rcs_name)
        return self._rcs

    rcs = property(get_rcs)

    def get_reference_bugdir(self, spec):
        return BugDir(self.rcs.path_in_reference(self.dir, spec))

    def list(self):
        for uuid in self.list_uuids():
            yield self.get_bug(uuid)

    def bug_map(self):
        bugs = {}
        for bug in self.list():
            bugs[bug.uuid] = bug
        return bugs

    def get_bug(self, uuid):
        return Bug(self.bugs_path, uuid, self.rcs_name)

    def list_uuids(self):
        for uuid in os.listdir(self.bugs_path):
            if (uuid.startswith('.')):
                continue
            yield uuid

    def new_bug(self, uuid=None):
        if uuid is None:
            uuid = names.uuid()
        path = os.path.join(self.bugs_path, uuid)
        self.rcs.mkdir(path)
        bug = Bug(self.bugs_path, None, self.rcs_name)
        bug.uuid = uuid
        return bug

class InvalidValue(ValueError):
    def __init__(self, name, value):
        msg = "Cannot assign value %s to %s" % (value, name)
        Exception.__init__(self, msg)
        self.name = name
        self.value = value