summaryrefslogtreecommitdiff
path: root/g_cran
diff options
context:
space:
mode:
authorAuke Booij (tulcod) <auke@tulcod.com>2010-06-26 00:38:21 +0200
committerAuke Booij (tulcod) <auke@tulcod.com>2010-06-26 00:38:21 +0200
commitc8d93826d032d7e55d10e4b82d5a2b8bba211320 (patch)
tree5f459e5bf26e1acad406d410211a8ccb536fafd3 /g_cran
parentWhat a shameful commit, putting my home directory out there just like that. (diff)
downloadg-cran-c8d93826d032d7e55d10e4b82d5a2b8bba211320.tar.gz
g-cran-c8d93826d032d7e55d10e4b82d5a2b8bba211320.tar.bz2
g-cran-c8d93826d032d7e55d10e4b82d5a2b8bba211320.zip
Prepare for packaging with distutils
Diffstat (limited to 'g_cran')
-rw-r--r--g_cran/__init__.py0
-rw-r--r--g_cran/cran_read.py89
-rw-r--r--g_cran/ebuild.py25
-rw-r--r--g_cran/filetricks.py15
-rw-r--r--g_cran/g_cran.py86
-rw-r--r--g_cran/phases.py48
-rw-r--r--g_cran/settings.py5
7 files changed, 268 insertions, 0 deletions
diff --git a/g_cran/__init__.py b/g_cran/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/g_cran/__init__.py
diff --git a/g_cran/cran_read.py b/g_cran/cran_read.py
new file mode 100644
index 0000000..30afc8a
--- /dev/null
+++ b/g_cran/cran_read.py
@@ -0,0 +1,89 @@
+import re, os
+from ebuild import *
+from filetricks import *
+from settings import *
+
+def pmsify_package_version(version_str):
+ return version_str.replace('-','.') #some CRAN-style versions have the form 0.1-1, which we transform into 0.1.1
+
+def pmsify_package_list(package_list):
+ #note: the following returns a list of tuples
+ matches=re.findall(r'\s*(([^,]+\([^()]+?\))|([^,]+))\s*',package_list) #split into packages + versions
+ packages=[]
+ for package_part in matches: #process each package match
+ if len(package_part[1])>len(package_part[2]): #versioned package identifier
+ parse=re.match(r'([^,]+)\(([^()]+?)\)',package_part[1])
+ pkg_name=parse.group(1).strip()
+ versions=parse.group(2)
+ #fixme version specifiers
+ if pkg_name=='R':
+ category='dev-lang'
+ else:
+ category='dev-R'
+ packages.append(category+'/'+pkg_name)
+ else:
+ pkg_name=package_part[2].strip()
+ if pkg_name=='R':
+ category='dev-lang'
+ else:
+ category='dev-R' #assume it's a CRAN package
+ packages.append(category+'/'+pkg_name)
+ return packages
+
+#Parse package options into values we can work with in accordance with PMS
+def pmsify_package_data(data,remote_repository):
+ pms_pkg=Ebuild()
+ pms_pkg.cran_data=data
+ e_vars=pms_pkg.ebuild_vars
+ #fix settings:
+ if 'package' not in data:
+ e_vars['pn']='test'
+ else:
+ e_vars['pn']=data['package']
+ if not re.match('[a-zA-Z0-9+_].*',e_vars['pn']): #package name may not be valid according to PMS
+ e_vars['pn']='_'+e_vars.pn
+ if re.match('.*-[0-9]+',e_vars['pn']):
+ e_vars['pn']=e_vars.pn+'_'
+ if 'version' not in data: #set a version even if we have none
+ e_vars['pv']='0'
+ else:
+ e_vars['pv']=pmsify_package_version(data['version'])
+ if 'depends' in data:
+ deps=pmsify_package_list(data['depends'])
+ else: #some packages don't set dependencies, so force dependency on R
+ deps=['dev-lang/R',]
+ e_vars['depend']=deps
+ e_vars['pdepend']=deps
+ e_vars['rdepend']=deps
+
+ e_vars['iuse']="doc"
+ e_vars['keywords']="~x86 ~amd64"
+ if 'description' in data:
+ e_vars['description']=data['description'].strip().replace('\n',' ')
+ else:
+ e_vars['description']=e_vars['pn']
+ if 'license' in data: #fixme parse license data
+ e_vars['license']=data['license'].strip()
+
+ e_vars['src_uri']=remote_repository+'/src/contrib/'+data['package']+'_'+data['version']+'.tar.gz'
+ return pms_pkg
+
+def read_packages(package_filename,local_repository):
+ packages_file=open(package_filename,"r")
+ file_parts=EmptyLinesFile(packages_file) #this is where we split the PACKAGES file into several file parts
+ packages=[]
+ import rfc822
+ repository_file=open(os.path.join(local_repository,REPO_MYDIR,'remote_uri'),'r')
+ remote_uri=repository_file.read().strip()
+ while not file_parts.eof:
+ cran_package=dict(rfc822.Message(file_parts).items()) #read part of PACKAGES file
+ pms_package=pmsify_package_data(cran_package,remote_uri) #fix values
+ packages.append(pms_package) #store in dict
+ return packages
+
+def find_package(repo_location,package_name):
+ packages=read_packages(os.path.join(repo_location,REPO_MYDIR,'PACKAGES'),repo_location)
+ for package in packages:
+ if package.ebuild_vars['pn']==package_name:
+ return package
+ raise ValueError("Package not found")
diff --git a/g_cran/ebuild.py b/g_cran/ebuild.py
new file mode 100644
index 0000000..14d6af8
--- /dev/null
+++ b/g_cran/ebuild.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+#Class for PMS-style packages
+class Ebuild():
+ def __init__(self):
+ #todo add needed variables as __init__ arguments
+ self.ebuild_vars={
+ 'pn':'',
+ 'pv':'',
+ 'description':'',
+ 'homepage':'',
+ 'iuse':'',
+ 'keywords':'',
+ 'license':'',
+ 'slot':'0',
+ 'src_uri':'',
+ 'eapi':'3',
+ 'depend':[],
+ 'pdepend':[],
+ 'rdepend':[],
+ 'provide':[],
+ 'restrict':[],
+ 'properties':'',
+ }
+ self.cran_data={}
+
diff --git a/g_cran/filetricks.py b/g_cran/filetricks.py
new file mode 100644
index 0000000..e42e059
--- /dev/null
+++ b/g_cran/filetricks.py
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+class EmptyLinesFile:
+ def __init__(self,myfile):
+ self.file=myfile
+ self.eof=False
+ self.lines=self.generate_lines()
+ def generate_lines(self,size=-1):
+ for line in self.file:
+ yield line
+ self.eof=True
+ def readline(self):
+ try:
+ return self.lines.next()
+ except StopIteration:
+ return ''
diff --git a/g_cran/g_cran.py b/g_cran/g_cran.py
new file mode 100644
index 0000000..0b84813
--- /dev/null
+++ b/g_cran/g_cran.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+import getopt, sys, os, string, urllib, re
+from ebuild import *
+import phases
+from cran_read import *
+from settings import *
+
+__doc__="Usage: "+sys.argv[0]+" <local repository directory> <action> [<action arguments>...]"
+
+def action_sync(repo_location,remote_uri):
+ if not os.path.isdir(os.path.join(repo_location, REPO_MYDIR)):
+ if os.path.isdir(repo_location):
+ os.mkdir(os.path.join(repo_location,REPO_MYDIR))
+ packages_filename=os.path.join(repo_location, REPO_MYDIR, 'PACKAGES')
+ urllib.urlretrieve(remote_uri+'/src/contrib/PACKAGES',packages_filename)
+ repo_file=open(os.path.join(repo_location,REPO_MYDIR,'remote_uri'),'w')
+ repo_file.write(remote_uri)
+
+def list_categories(repo_location):
+ print "dev-R"
+
+def list_packages(repo_location):
+ packages=read_packages(os.path.join(repo_location,REPO_MYDIR,'PACKAGES'),repo_location)
+ for package in packages:
+ print 'dev-R/'+package.ebuild_vars['pn'],package.ebuild_vars['pv']
+
+def action_package(repo_location,package_name):
+ defined_phases=[]
+ package=find_package(repo_location,package_name[package_name.find('/')+1:])
+ #output data
+ for key,value in package.ebuild_vars.iteritems():
+ if key=='pn' or key=='pv': #readonly vars, we cannot set these in ebuilds
+ continue
+ if isinstance(value,str): #if string
+ print key.upper()+'='+value.replace('\n','')
+ elif isinstance(value,list): #list, concat items
+ print key.upper()+'='+' '.join(value).replace('\n','')
+ for pms_func in pms_phases:
+ if hasattr(phases,pms_func):
+ defined_phases.append(pms_func)
+ print 'GCOMMON_PHASES='+' '.join(defined_phases)
+
+def usage():
+ print __doc__
+
+def main():
+ arguments=sys.argv[1:]
+ #print options, arguments
+ if len(arguments)<2: #we need at least a local repository location and an action
+ usage()
+ sys.exit(0)
+ action=arguments[1]
+ repo_location=os.path.abspath(arguments[0])
+ if action=='sync':
+ if len(arguments)<3:
+ print "The 'sync' action takes the following parameters:"
+ print " * remote_repository_uri"
+ sys.exit(1)
+ remote_repo=arguments[2]
+ action_sync(repo_location,remote_repo)
+ elif action=='list-categories':
+ list_categories(repo_location)
+ elif action=='list-packages':
+ list_packages(repo_location)
+ elif action=='package':
+ if len(arguments)<3:
+ print "The 'package' action takes the following parameters:"
+ print " * category/package_name"
+ print " * [version]"
+ sys.exit(1)
+ package_name=arguments[2]
+ action_package(repo_location,package_name)
+ elif action=='usage':
+ usage()
+ elif action in pms_phases and hasattr(phases,action):
+ getattr(phases,action)(os.environ,repo_location)
+ elif action in actions_wanted:
+ raise NotImplementedError
+ else:
+ usage()
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()
+
+
diff --git a/g_cran/phases.py b/g_cran/phases.py
new file mode 100644
index 0000000..6915979
--- /dev/null
+++ b/g_cran/phases.py
@@ -0,0 +1,48 @@
+import os
+import cran_read
+
+R_PLATFORM="ignoreplatform"
+
+def verbose_system(command):
+ print command
+ return os.system(command)
+
+#This function actually creates a binary package (a tarball) from the source package
+#this way, we cleanly split up R package installing into a compile and install phase
+def src_compile(env,local_repository):
+ #verbose_system("R CMD INSTALL --build ")
+ package=cran_read.find_package(local_repository,env['PN'])
+ os.putenv('R_PLATFORM',R_PLATFORM) #force predictable package name
+ os.chdir(env['WORKDIR'])
+ returnval=verbose_system("R CMD build --binary "+env['WORKDIR']+'/'+package.cran_data['package'])
+ if returnval:
+ raise RuntimeError("R build failed")
+
+def src_install(env,local_repository):
+ package=cran_read.find_package(local_repository,env['PN'])
+ os.putenv('R_PLATFORM',R_PLATFORM)
+ tarname=env['WORKDIR']+'/'+package.cran_data['package']+'_'+package.cran_data['version']+'_R_'+R_PLATFORM+'.tar.gz' #assume always gzip
+ r_home=os.getenv('R_HOME')
+ if len(r_home)==0: #R home isn't set, try to read /etc/env.d/99R
+ envfile=open('/etc/env.d/99R','r')
+ for line in envfile:
+ if line[:len('R_HOME')]=='R_HOME':
+ r_home=line[line.find('=')+1:].strip()
+ break
+ else:
+ raise RuntimeError("Could not deduce R_HOME")
+ r_library=env['D']+r_home+"/library"
+ if not os.path.exists(r_library):
+ os.makedirs(r_library)
+ #install the binary package without documentation (excluding documentation doesn't seem to work)
+ returnval=verbose_system("R CMD INSTALL --debug --no-docs --no-html "+tarname+" -l "+r_library)
+ if returnval:
+ raise RuntimeError("R install failed")
+ #todo install HTML help
+ doc_dir=env['D']+'/usr/share/doc/'+env['PVR']
+
+ if 'doc' in package.ebuild_vars['iuse'] and 'doc' in env['USE']:
+ pass
+ #not implemented
+
+
diff --git a/g_cran/settings.py b/g_cran/settings.py
new file mode 100644
index 0000000..1da3a16
--- /dev/null
+++ b/g_cran/settings.py
@@ -0,0 +1,5 @@
+
+pms_phases=['pkg_pretend','pkg_setup','src_unpack','src_prepare','src_configure','src_compile',
+ 'src_test','src_install','pkg_preinst','pkg_postinst','pkg_prerm','pkg_postrm','pkg_config','pkg_info','pkg_nofetch']
+actions_wanted=['usage','sync','list-categories','list-packages','package']+pms_phases
+REPO_MYDIR=".g-cran"