summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaakov M. Nemoy <loupgaroublond@gmail.com>2009-01-08 16:43:14 -0500
committerYaakov M. Nemoy <loupgaroublond@gmail.com>2009-01-08 16:43:14 -0500
commitc27ff3ce07de79215b58f5fd10ff175424cba7cb (patch)
treed7ab5511655050adf4905468b2b7e9ff15afde47
parent3bcae770792afe5d5fff2af127cad2c1d0d59d57 (diff)
downloadfedora-devshell-c27ff3ce07de79215b58f5fd10ff175424cba7cb.tar.gz
fedora-devshell-c27ff3ce07de79215b58f5fd10ff175424cba7cb.tar.xz
fedora-devshell-c27ff3ce07de79215b58f5fd10ff175424cba7cb.zip
adds 135 kilocraps of documentation
135 kilocraps = 1 metric craptonne
-rw-r--r--modules/build.py60
-rw-r--r--modules/cabal.py79
-rw-r--r--modules/darcs.py67
-rw-r--r--modules/directory.py35
-rw-r--r--modules/dirfactory.py2
-rw-r--r--modules/mock.py9
-rw-r--r--modules/package.py15
-rw-r--r--modules/profile.py19
-rw-r--r--modules/revisioncontrol.py2
-rw-r--r--modules/sourceball.py10
10 files changed, 275 insertions, 23 deletions
diff --git a/modules/build.py b/modules/build.py
index 7fcc1b0..93b2056 100644
--- a/modules/build.py
+++ b/modules/build.py
@@ -36,8 +36,16 @@ from modules.package import Package
from modules.profile import Profile
class Build(Directory):
+ '''A wrapper around rpmbuild functions
+ '''
_type = 'build'
def setup_source(self, package):
+ '''Given a package, set's it up in the buildroot for being built with rpmbuild
+
+ package is a directory name to a Package (Directory).
+
+ returns nothing
+ '''
pkg = DirFactory(package)
with pwd(pkg.dir):
symlink(pkg.spec_file,
@@ -49,12 +57,47 @@ class Build(Directory):
symlink(patch, join(self.dir, 'SOURCES', patch))
def build_quick_rpm(self, package, profile=None):
+ '''Builds an rpm on the local system using rpmbuild (aka no clean chroots)
+
+ This method may be useful in determining the difference between
+ a chroot and the working system. It can also help make sure the
+ package can be built in the first place, and quickly.
+
+ package is a directory name to a Package (Directory).
+ profile is a Profile object, this parameter should only be used internally
+
+ returns nothing
+ '''
self.rpmbuild('-ba', package, profile)
def build_source_rpm(self, package, profile=None):
+ '''Builds an source rpm on the local system using rpmbuild
+
+ This method is necessary to build SRPMs for many other modules.
+ The user may find that certain dist related macros in the RPM are
+ set to the system wide defaults. The parameter 'profile' is used heavily
+ internally to mimic aspects of the Fedora Build system in order
+ override the defaults. Without the assistance of other modules
+ that are profile aware, profile makes no sense here.
+
+ package is a directory name to a Package (Directory).
+ profile is a Profile object, this parameter should only be used internally
+
+ returns nothing
+ '''
self.rpmbuild('-bs', package, profile)
def rpmbuild(self, param, package, profile=None):
+ '''The work horse of building rpms
+
+ Given a directive param for rpmbuild, the package, and a possible
+ profile, it runs rpmbuild appropriatly.
+
+ package is a directory name to a Package (Directory).
+ profile is a Profile object, this parameter should only be used internally
+
+ returns nothing
+ '''
pkg = DirFactory(package)
if profile:
defines = join_defines(profile.dist_defines,
@@ -75,6 +118,15 @@ class Build(Directory):
log.debug(p.returncode)
def fetch_rpms(self, target_dir):
+ '''fetches all rpm files from the buildroot to another target directory
+
+ As a module author, it is a good idea to use this to clean up
+ afterwards. This module pulls all RPMs said module may have made
+ as well as any other RPMs from earlier incantations of other modules.
+ Please be courteous to other module authors and run this liberally.
+
+ target_dir is a path to the destination for all the rpms
+ '''
with pwd(self.dir):
for path, dirs, files in walk('.'):
for f in files:
@@ -82,6 +134,14 @@ class Build(Directory):
move(join(path, f), join(target_dir, f))
def fetch_build(self, package):
+ '''fetches the built source tree from the execution of rpmbuild for review
+
+ This is usefull to see if rpmbuild did anything funny in execution
+ of the spec file. Hopefully you'll never need this. The results
+ end up in the top level directory of the given package
+
+ package is a directory name to a Package (Directory).
+ '''
pkg = DirFactory(package)
with pwd(self.dir):
source = pkg.cfg['source']
diff --git a/modules/cabal.py b/modules/cabal.py
index 529b023..59c8d48 100644
--- a/modules/cabal.py
+++ b/modules/cabal.py
@@ -36,7 +36,17 @@ from modules.dirfactory import DirFactory
from modules.sourceball import SourceBall
class Cabal(Module):
+ '''A wrapper around common cabal operations
+
+ This provides a useful api for other modules around the cabal build system
+ '''
def __init__(self, name, root='~/haskell'):
+ '''creates a new cabal module
+
+ this api is deprecated, because it should be more autodetecting
+
+ name is a Package (Directory) that uses cabal for its build system
+ '''
self.name = name
self.root = expanduser(root)
with pwd(self.root):
@@ -45,18 +55,32 @@ class Cabal(Module):
self.compiler = haskell_compiler
def copy_in(self, tarball):
+ '''copies a tarball into the package
+
+ tarball is a path to some tarball
+ '''
tarball = abspath(tarball)
with pwd(self.root):
self.package.add_sourceball(tarball)
def darcs_get(self, url, tgt):
+ '''creates a darcs variant of a cabal package using darcs source
+
+ url is a url to some darcs repo
+ tgt is the local name of the darcs repo
+ '''
self.package.checkout(tgt, url)
def find_setup(self, orig=''):
+ '''returns the name of the Setup.?hs script for cabal.
+ '''
setup_re = compile("Setup\.l?hs")
- return one(listdir(getcwd()), setup_re.search)
+ with pwd(self.package.dir):
+ return one(listdir(getcwd()), setup_re.search)
def compile_setup(self, orig=''):
+ '''compiles the setup script for faster execution
+ '''
log.debug('dir is ' + self.package.dir)
with pwd(self.package.dir):
with log_file('ghc.log') as ghc_out:
@@ -70,6 +94,14 @@ class Cabal(Module):
p.communicate()
def configure(self, target='home', orig=''):
+ '''runs the configure stage of cabal
+
+ target is either 'home' or 'root' and will configure the package to
+ install either to the user's home directory, or to the system
+ wide haskell.
+
+ Some help is needed making this more flexible
+ '''
user = True if target == 'home' else False
self.compile_setup(orig)
with pwd(self.package.dir):
@@ -83,7 +115,12 @@ class Cabal(Module):
p.wait()
def build(self, orig=''):
- '''This is not safe to run on an unconfigured source dir'''
+ '''runs the build stage of cabal
+
+ This is not safe to run on an unconfigured source dir, because
+ this module does not track the state of cabal systems. The user
+ must do this on their own.
+ '''
self.compile_setup(orig)
with pwd(self.package.dir):
with log_file('cabal.log') as cabal_out:
@@ -94,7 +131,12 @@ class Cabal(Module):
p.wait()
def install(self, orig=''):
- '''This is not safe to run on an unconfigured source dir'''
+ '''runs the install stage of cabal
+
+ This is not safe to run on an unconfigured source dir, because
+ this module does not track the state of cabal systems. The user
+ must do this on their own.
+ '''
self.compile_setup(orig)
with pwd(self.package.dir):
with log_file('cabal.log') as cabal_out:
@@ -105,40 +147,62 @@ class Cabal(Module):
p.wait()
def install_tag(self, tag):
+ '''assuming a package that supports tagging, install a specific tag
+
+ tag is the name of the tag in the DVCS
+ '''
with pwd(self.package.dir):
with self.package.tag(tag):
self.install()
def install_source(self, target='home', orig=''):
+ '''perform configure, build, and install steps in one
+ '''
self.configure(target, orig)
self.build(orig)
self.install(orig)
def install_sourceball(self, tarball, target='home'):
+ '''given a tarball, copy it in and install it
+ '''
self.copy_in(tarball)
self.install_source(target, '')
def get_from_hackage(self, pkg, ver):
+ '''get a specific package from hackage
+
+ pkg is the name of the package desired
+ ver is the version wanted
+ '''
sb_file = self.hackage_url(pkg, ver)
self.copy_in(sb_file)
def get_latest(self, pkg):
+ '''get the latest version of a package from hackage
+
+ pkg is the package desired
+ '''
ver = self.latest_version(pkg)
self.get_from_hackage(pkg, ver)
def install_from_hackage(self, pkg, ver, target='home'):
+ '''get and install a specific package from hackage
+
+ pkg is the desired package
+ ver is the version wanted
+ target is the location to install to, either 'home' or 'root'
+ '''
self.get_from_hackage(pkg, ver)
self.install_source(target, '')
def install_latest(self, pkg, target='home'):
+ '''get and install the latest version of a package from hackage'''
self.get_latest(pkg)
self.install_source(target, '')
- def source_dir(self, *args):
- with pwd(self.package.dir):
- return abspath(self.package.cfg['source'] + (self.orig_src_dir if original else ""))
-
def latest_version(self, pkg):
+ '''download information from hackage to find out the latest version of a package
+ '''
hackage_title = compile(r'<title.*?>HackageDB: (.*)-(.*)</title.*?>', DOTALL)
site = 'http://hackage.haskell.org/cgi-bin/hackage-scripts/package/' + pkg
u = urlopen(site)
@@ -152,6 +216,7 @@ class Cabal(Module):
raise ExecutionException("package does not match package name, can't determine version, sorry")
def hackage_url(self, pkg, ver):
+ '''returns the url for tarball for a hackage package'''
return 'http://hackage.haskell.org/packages/archive/' + \
pkg + '/' + ver + '/' + pkg + '-' + ver + '.tar.gz'
diff --git a/modules/darcs.py b/modules/darcs.py
index dddaee2..8bee4a4 100644
--- a/modules/darcs.py
+++ b/modules/darcs.py
@@ -32,29 +32,47 @@ hash_re = re.compile(r'hash=\'(\w|-|.*?)\'', re.MULTILINE)
date_re = re.compile(r'date=\'(\d*?)\'', re.MULTILINE)
class Darcs(RevisionControl):
+ '''manages single source packages where the primary source is darcs
+ '''
_type = 'darcs'
- def load_dir(self, dir):
- super(RevisionControl, self).load_dir(dir)
-
@property
def vc_url(self):
+ '''the url where the source was fetched from originally
+
+ this may be moved to revision control in the future
+ '''
return self.cfg['vc_url']
@property
def hackage_name(self):
+ '''assuming this package is a haskell package, what is the canonical name
+
+ this name may be changed in the future
+ '''
return self.cfg['hackage_name']
def source(self, *args):
+ '''the name of the directory where the source is being kept currently
+
+ hackage_name is the canonical name of the package, this is
+ just for handling branching and other nasty devilish tricks
+ '''
return self.cfg['source']
@contextmanager
def src_dir(self, *args):
+ '''executes a code block inside a specific branch and or checkout
+ '''
with src(*args):
with pwd(self.cfg['source']):
yield
@contextmanager
def src(self, *args):
+ '''executes a code block with a particular branch or checkout
+
+ if there are no args, this block is executed in the raw
+ '''
if args:
old_src = self.cfg['source']
self.set_cur_to(*args)
@@ -66,6 +84,14 @@ class Darcs(RevisionControl):
def get(self, src, tgt, *args):
+ '''sets up a branch given arguments, taken from a source with a target
+
+ the idioms of branching in different VCSes vary, and a common
+ api for this in devshell has not yet been realized
+
+ currently, this creates a new temporary local branch in darcs
+ and sets the source to it
+ '''
with pwd(self.dir):
self.cfg['source'] = tgt
with log_file('darcs.log') as darcs_out:
@@ -76,11 +102,25 @@ class Darcs(RevisionControl):
self.set_current_head()
def checkout(self, tgt, url, *args):
+ '''checks out source from an upstream url
+
+ the difference between this and get is that it reflects an initial pull
+ idiom found in other VCSes. It also handles setting vc_url and the
+ canonical name, based on tgt
+ '''
self.cfg['vc_url'] = url
self.cfg['hackage_name'] = split(tgt)[1]
self.get(url, tgt, *args)
def set_current_head(self):
+ '''sets the current internal state to reflect the current head
+
+ chances are, the user should rarely mess with this.
+
+ this may change, because rather than using .patch files for rpm
+ handling, we may ask the user to commit all the changes to darcs,
+ and then have devshell generate .patch files automatically instead
+ '''
log.debug(getcwd())
with pwd(self.cfg['source']):
p = Popen(['darcs', 'changes', '--xml-output', '--last=1'],
@@ -91,48 +131,57 @@ class Darcs(RevisionControl):
self.cfg['head'] = (hash, date)
def set_cur_to(self, *args):
+ '''passes arbitrary args to darcs get and makes a branch out of it
+
+ this is not really optimal, because it only does things temporary,
+ we need to look at as systematic way to handle branching.
+ looking at a potential git and a potential cvs module may help
+ '''
cur_src_dir = self.cfg['source']
new_src_dir = cur_src_dir + '_tmp'
self.get(cur_src_dir, new_src_dir, *args)
def set_cur_to_patch(self, hash):
+ '''sets the current branch to fork off a particular hash'''
self.set_cur_to('--to-match', 'hash ' + hash)
def set_cur_to_tag(self, tag):
+ '''sets the current branch to fork off a particular tag'''
self.set_cur_to('--tag', tag)
@property
def date(self):
+ '''get's the timestamp of the latest patch on HEAD of the current branch'''
return self.cfg['head'][1]
@property
def hash(self):
+ '''gets the hash of the latest patch on HEAD of the current branch'''
return self.cfg['head'][0]
def print_date(self):
+ '''prints the timestamp of the latest patch on HEAD of the current branch'''
log.info('The timestamp is ' + self.date)
def print_hash(self):
+ '''prints the hash of the latest patch on HEAD of the current branch'''
log.info('The hash is ' + self.hash)
- def set_cur_to_patch(self, hash):
- self.set_cur_to('--to-match', 'hash ' + hash)
-
- def set_cur_to_tag(self, tag):
- self.set_cur_to('--tag', tag)
-
@contextmanager
def patch(self, hash):
+ '''executes a block of code on top a particular patch'''
with self.src('--to-match', 'hash ' + hash):
yield
@contextmanager
def tag(self, tag):
+ '''executes a particular block of code on top of a particular tag'''
with self.src('--tag', tag):
yield
def setup_sourceball(self):
+ '''gets darcs to spit out a sourceball to be used in rpm making by other modules'''
log.debug('someone set us up the bomb')
with pwd(self.dir):
with pwd(self.source_dir()):
diff --git a/modules/directory.py b/modules/directory.py
index 139a2c9..16e5a58 100644
--- a/modules/directory.py
+++ b/modules/directory.py
@@ -29,8 +29,17 @@ from base.util import pwd, copytree
from modules.dirfactory import DirFactory
class Directory(Module):
+ '''a generic base class for any module that has to maintain state
+ on the file system in a directory
+ '''
_type = 'directory'
def __init__(self, name=None):
+ ''' initializer
+
+ name is a path to the directory we are loading, if not given
+ name is gleaned by assuming the current directory is the
+ package desired
+ '''
if not name:
log.debug('no name with directory')
cwd = getcwd()
@@ -50,6 +59,8 @@ class Directory(Module):
self.make_dir(dir)
def is_sysdir_dir(self, dir):
+ '''given a directory, determine if the system directory is
+ already a directory or not'''
with pwd(dir):
cfg = ConfigObj('.devshell')
try:
@@ -62,6 +73,7 @@ class Directory(Module):
return False
def load_dir(self, dir):
+ '''presuming dir is a directory, load it's state'''
log.debug('directory.load_dir')
with pwd(dir):
parent, name = split(getcwd())
@@ -75,10 +87,12 @@ class Directory(Module):
pass
def make_dir(self, dir):
+ '''since dir is not a directory, make it into one'''
log.debug('directory.make_dir')
with pwd(dir):
self.cfg = ConfigObj('.devshell')
parent, name = split(getcwd())
+ # type is defined by the subclass
self.cfg['type'] = self._type
self.cfg['name'] = name
self.parent = parent
@@ -86,34 +100,55 @@ class Directory(Module):
@property
def name(self):
+ ''' the name of the directory/module as defined by the user
+ '''
return self.cfg['name']
@property
def parent(self):
+ ''' the parent directory holding the directory on the file system
+
+ this is determined at run time, and used to build absolute path names
+ out of elements of the directory
+ '''
return self.cfg['parent']
@property
def dir(self):
+ '''absolute pathname to the directory where it is held on the file system'''
return join(self.parent, self.name)
def close(self):
+ '''called by devshell, closes the open objects'''
log.debug('writing self.cfg for directory')
with pwd(self.dir):
self.cfg.write()
def rename(self, new_name):
+ '''renames the directory internally, assuming it's been renamed
+ on the file system
+
+ subclass authors take note, this must be reimplemented, and the
+ superclass version called when any property or state depends on
+ self.name in any way shape or form.
+ '''
self.cfg['name'] = new_name
def move(self, new_loc):
+ '''given a new location, moves everything there, and renames'''
new_loc = abspath(new_loc)
new_parent, new_name = split(new_loc)
old_dir = self.dir
copytree(self.dir, new_loc)
self.parent = new_parent
self.rename(new_name)
+ with pwd(self.dir):
+ self.cfg.write()
rm(old_dir)
def copy(self, new_loc):
+ '''makes a copy of the contents in a new location, renames,
+ and returns a reference to a new object rpresenting the new directory'''
new_loc = abspath(new_loc)
new_parent, new_name = split(new_loc)
copytree(self.dir, new_loc)
diff --git a/modules/dirfactory.py b/modules/dirfactory.py
index 30d5e59..1c2e5a2 100644
--- a/modules/dirfactory.py
+++ b/modules/dirfactory.py
@@ -40,6 +40,7 @@ foo = dict(foo)
dirs = dict([[key.lower(), val] for key, val in foo.iteritems() if isclass(val) and issubclass(val, Directory)])
class DirFactory(Module):
+ '''creates a new object of type defined by a directory's .devshell file'''
def __new__(cls, name=None):
if not name:
log.debug('no name with dirfactory')
@@ -58,6 +59,7 @@ class DirFactory(Module):
return foo
def whatis_sysdir(dir):
+ ''' given a dir, determine it's type'''
with pwd(dir):
cfg = ConfigObj('.devshell')
try:
diff --git a/modules/mock.py b/modules/mock.py
index e15a063..d7cf00d 100644
--- a/modules/mock.py
+++ b/modules/mock.py
@@ -30,11 +30,18 @@ from modules.package import Package
from modules.profile import Profile
class Mock(Module):
+ '''wrapper around mock for integrating with profiles and packages'''
def __init__(self, profile, build):
+ '''initializer
+
+ profile is a path to a profile directory
+ build is a path to a buildroot directory
+ '''
self.build = Build(build)
self.profile = Profile(profile)
def build_rpm(self, package):
+ '''builds an rpm from some package'''
pkg = DirFactory(package)
self.build.build_source_rpm(package, self.profile)
@@ -49,7 +56,7 @@ class Mock(Module):
log.debug('config_dir is ' + config_dir)
cmd = ['mock', '-r', mock_cfg,
'--configdir=%s' % config_dir,
- '--resultdir=%s' % result_dir,
+ '--resultdir=%s' % result_dir,
srpm_name]
log.debug('cmd is ' + str(cmd))
with pwd(result_dir):
diff --git a/modules/package.py b/modules/package.py
index c697067..af0a48e 100644
--- a/modules/package.py
+++ b/modules/package.py
@@ -38,6 +38,9 @@ class Package(Directory):
super(Package, self).make_dir(dir)
def add_spec(self, spec_file):
+ '''add's a spec file to the package, and sets the canonical package
+ name based on the spec file, possibly renaming the spec file to match
+ within fedora guidelines'''
log.debug('spec_file is %s' % spec_file)
log.debug('spec_file_name is %s' % self.name + '.spec')
#TODO: get the spec file name, copy
@@ -55,30 +58,38 @@ class Package(Directory):
@property
def spec_file(self):
+ '''returns the name of the spec file as it should be accordingto
+ fedora guidelines, good for double checking'''
return self.pkg_name + '.spec'
@property
def pkg_name(self):
+ '''canonical name of the package in a source repository'''
return self.cfg['pkg_name']
def get_srpm_name(self, profile):
+ '''given a profile, determines that the source rpm should be called'''
with pwd(self.dir):
ver, rel = ver_rel(self.spec_file, profile.dist_defines)
return '%s-%s-%s.src.rpm' % (self.pkg_name, ver, rel)
def ver(self, profile=None):
+ '''given a profile, determines the version of the current spec file'''
with pwd(self.dir):
ver, rel = ver_rel(self.spec_file, profile.dist_defines if profile else '')
return ver
def source_dir(self, *args):
- return join(self.dir, self.source(*args)
-
+ '''provides an absolute pathname for where the primary source is unpacked'''
+ return join(self.dir, self.source(*args))
+
def source(self, *args):
+ '''base method that should return where the source is kept to some yet unknown criteria'''
raise NotImplementedError
@property
def sourceball(self):
+ '''the current sourceball in use, for building packages'''
return self.cfg['sourceball']
__all__ = ['Package']
diff --git a/modules/profile.py b/modules/profile.py
index 56639cb..dc4d44a 100644
--- a/modules/profile.py
+++ b/modules/profile.py
@@ -27,6 +27,7 @@ from base.vars import MOCK_CFG_DIR
from modules.directory import Directory
class Profile(Directory):
+ '''a profile module to resemble various architectures, branches, build targets, etc...'''
_type = 'profile'
@property
def dist(self):
@@ -36,39 +37,51 @@ class Profile(Directory):
@property
def distvar(self):
- 'eg: fedora or rhel'
+ '''eg: fedora or rhel'''
return self.cfg['distvar']
@property
def distval(self):
- 'eg: 10 or 3 (string form)'
+ '''eg: 10 or 3 (string form)'''
return self.cfg['distval']
@property
def koji_target(self):
- 'eg: dist-f11'
+ '''eg: dist-f11'''
return self.cfg['koji_target']
@property
def dist_defines(self):
+ '''a list of parameters for an rpm aware function to redefine
+ certain macros to match the profile'''
return dist_defines(self.dist, self.distvar, self.distval)
# i'm not sure this is 100% relevant, mock cfg's might be named only after the arch used
@property
def mock_cfg(self):
+ '''the name of the mock config/profile to be used to compile packages for this profile
+
+ this will probably change once we figure out how to handle branches and build targets better
+ '''
# TODO: buildarchs need to be handled somehow
# yes i'm lame and i did this i386 only for now
return get_mock_cfg(self.distvar, self.distval, 'i386')
@property
def mock_cfg_dir(self):
+ '''directory where profile wide mock settings are kept'''
return join(self.dir, 'mock')
@property
def result_dir(self):
+ '''where to store results from mock'''
return self.dir
def configure_from_system(self, branch):
+ '''sets up a profile based on system profiles
+
+ branch is a branch name from the fedora-cvs
+ '''
self.cfg['branch'] = branch
d = distro[branch]
self.cfg['koji_target'] = d[TARGET]
diff --git a/modules/revisioncontrol.py b/modules/revisioncontrol.py
index 0e87065..80efaa2 100644
--- a/modules/revisioncontrol.py
+++ b/modules/revisioncontrol.py
@@ -19,7 +19,7 @@
from modules.package import Package
class RevisionControl(Package):
-
+ '''base class for any module that implements a VCS system and wraps it for getting source for packages'''
pass
__all__ = ['RevisionControl']
diff --git a/modules/sourceball.py b/modules/sourceball.py
index 4a39e94..ac306cc 100644
--- a/modules/sourceball.py
+++ b/modules/sourceball.py
@@ -30,17 +30,27 @@ from base.util import pwd, copy
from modules.package import Package
class SourceBall(Package):
+ '''a type of package that is a single sourceball, a spec file, and some patches'''
_type = 'sourceball'
def orig_dir(self, dir):
+ '''where is the original source kept
+
+ use for making patches against modified source'''
return dir + '_orig'
def source(self, *args):
+ '''gives source directory
+
+ first parameter, if 'orig' gives the original source, otherwise
+ you get the modified source
+ '''
if args[0] == 'orig':
return self.orig_dir(self.cfg['source'])
else:
return self.cfg['source']
def add_sourceball(self, sourceball_name, extract_dir=None):
+ '''given a path to a sourceball, set it up here'''
log.debug('addincg sourceball with dir ' + self.dir)
with pwd(self.dir):
try: