From: blundellc Date: Sat, 13 Sep 2008 13:16:48 +0000 (+0000) Subject: cran2deb: make into an R package. X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=86055c81b378b4629c33aa1c588deb5637e32975;p=cran2deb.git cran2deb: make into an R package. not complete. mostly seems to work, but certain parts are broken: e.g., updating the availability lists. git-svn-id: svn://svn.r-forge.r-project.org/svnroot/cran2deb@47 edb9625f-4e0d-4859-8d74-9fd3b1da38cb --- diff --git a/pkg/trunk/DESCRIPTION b/pkg/trunk/DESCRIPTION new file mode 100644 index 0000000..1bfa413 --- /dev/null +++ b/pkg/trunk/DESCRIPTION @@ -0,0 +1,10 @@ +Package: cran2deb +Version: 0.0 +Date: 2008-07-14 +Title: Convert CRAN packages into Debian packages +Author: Charles Blundell , with assistance from Dirk Eddelbuettel <> +Maintainer: Charles Blundell +Depends: ctv, utils +Description: Convert CRAN packages into Debian packages, mostly unassisted, easily + subverting the R package system. +License: GPL-3 diff --git a/pkg/trunk/R/debcontrol.R b/pkg/trunk/R/debcontrol.R new file mode 100644 index 0000000..ea25962 --- /dev/null +++ b/pkg/trunk/R/debcontrol.R @@ -0,0 +1,100 @@ +get.dependencies <- function(pkg,extra_deps) { + if ('SystemRequirements' %in% colnames(pkg$description)) { + stop(paste('Unsupported SystemRequirements:',pkg$description[1,'SystemRequirements'])) + } + + # determine dependencies + dependencies <- r.dependencies.of(description=pkg$description) + depends <- list() + # these are used for generating the Depends fields + as.deb <- function(r,binary) { + return(pkgname.as.debian(paste(dependencies[r,]$name) + ,version=dependencies[r,]$version + ,repopref=pkg$repo + ,binary=binary)) + } + depends$bin <- lapply(rownames(dependencies), as.deb, binary=T) + depends$build <- lapply(rownames(dependencies), as.deb, binary=F) + # add the command line dependencies + depends$bin = c(extra_deps$deb,depends$bin) + depends$build = c(extra_deps$deb,depends$build) + + # make sure we depend upon R in some way... + if (!length(grep('^r-base',depends$build))) { + depends$build = c(depends$build,pkgname.as.debian('R',version='>= 2.7.0',binary=F)) + depends$bin = c(depends$bin, pkgname.as.debian('R',version='>= 2.7.0',binary=T)) + } + # also include stuff to allow tcltk to build (suggested by Dirk) + depends$build = c(depends$build,'xvfb','xauth','xfont-base') + + # remove duplicates + depends <- lapply(depends,unique) + + # append the Debian dependencies + depends$build=c(depends$build,'debhelper (>> 4.1.0)','cdbs') + if (pkg$archdep) { + depends$bin=c(depends$bin,'${shlibs:Depends}') + } + + # the names of dependent source packages (to find the .changes file to + # upload via dput). these can be found recursively. + depends$r = lapply(r.dependency.closure(dependencies) + ,tolower) + # append command line dependencies + depends$r = c(extra_deps$r, depends$r) + return(depends) +} + +generate.control <- function(pkg) { + # construct control file + control = data.frame() + control[1,'Source'] = pkg$srcname + control[1,'Section'] = 'math' + control[1,'Priority'] = 'optional' + control[1,'Maintainer'] = maintainer + control[1,'Build-Depends'] = paste(pkg$depends$build,collapse=', ') + control[1,'Standards-Version'] = '3.8.0' + + control[2,'Package'] = pkg$debname + control[2,'Architecture'] = 'all' + if (pkg$archdep) { + control[2,'Architecture'] = 'any' + } + control[2,'Depends'] = paste(pkg$depends$bin,collapse=', ') + + # bundles provide virtual packages of their contents + if (pkg$is_bundle) { + control[2,'Provides'] = paste( + lapply(r.bundle.contains(pkg$name) + ,function(name) return(pkgname.as.debian(paste(name) + ,repopref=pkg$repo + ,binary=T))) + ,collapse=', ') + } + + # generate the description + descr = 'GNU R package "' + if ('Title' %in% colnames(pkg$description)) { + descr = paste(descr,pkg$description[1,'Title'],sep='') + } else { + descr = paste(descr,pkg$name,sep='') + } + if (pkg$is_bundle) { + long_descr <- pkg$description[1,'BundleDescription'] + } else { + long_descr <- pkg$description[1,'Description'] + } + # using \n\n.\n\n is not very nice, but is necessary to make sure + # the longer description does not begin on the synopsis line --- R's + # write.dcf does not appear to have a nicer way of doing this. + descr = paste(descr,'"\n\n', long_descr, sep='') + if ('URL' %in% colnames(pkg$description)) { + descr = paste(descr,'\n\nURL: ',pkg$description[1,'URL'],sep='') + } + control[2,'Description'] = descr + + # Debian policy says 72 char width; indent minimally + write.dcf(control,file=pkg$debfile('control.in'),indent=1,width=72) + write.dcf(control,indent=1,width=72) +} + diff --git a/pkg/trunk/R/debiannaming.R b/pkg/trunk/R/debiannaming.R new file mode 100644 index 0000000..08c3f84 --- /dev/null +++ b/pkg/trunk/R/debiannaming.R @@ -0,0 +1,49 @@ +# sudo pbuilder --execute r -e 'rownames(installed.packages())' +# XXX: has to be a better way of doing this +base_pkgs=c('base', 'datasets','grDevices','graphics','grid', 'methods' + ,'splines','stats', 'stats4', 'tcltk', 'tools','utils') +# found in R source directory: +# 'profile', 'datasets' + +repourl.as.debian <- function(url) { + # map the url to a repository onto its name in debian package naming + if (length(grep('cran',url))) { + return('cran') + } + if (length(grep('bioc',url))) { + return('bioc') + } + stop(paste('unknown repository',url)) +} + +pkgname.as.debian <- function(name,repopref=NULL,version=NULL,binary=T) { + # generate the debian package name corresponding to the R package name + if (name %in% base_pkgs) { + name = 'R' + } + if (name == 'R') { + # R is special. + if (binary) { + debname='r-base-core' + } else { + debname='r-base-dev' + } + } else { + # XXX: data.frame rownames are unique, so always override repopref for + # now. + if (!(name %in% rownames(available))) { + bundle <- r.bundle.of(name) + if (is.na(bundle)) { + stop(paste('package',name,'is not available')) + } + name <- bundle + } + repopref <- repourl.as.debian(available[name,'Repository']) + debname = paste('r',tolower(repopref),tolower(name),sep='-') + } + if (!is.null(version) && length(version) > 1) { + debname = paste(debname,' (',version,')',sep='') + } + return(debname) +} + diff --git a/pkg/trunk/R/debianpkg.R b/pkg/trunk/R/debianpkg.R new file mode 100644 index 0000000..3b9ca62 --- /dev/null +++ b/pkg/trunk/R/debianpkg.R @@ -0,0 +1,153 @@ +generate.changelog <- function(pkg) { + # construct a dummy changelog + # TODO: ``Writing R extensions'' mentions that a package may also have + # {NEWS,ChangeLog} files. + cat(paste(paste(pkg$srcname,' (',pkg$debversion,') unstable; urgency=low',sep='') + ,'' ,' * Initial release.','' + ,paste(' --',maintainer,'',format(Sys.time(),'%a, %d %b %Y %H:%M:%S %z')) + ,'',sep='\n'),file=pkg$debfile('changelog.in')) +} + +generate.rules <- function(pkg) { + cat(paste('#!/usr/bin/make -f' + ,paste('debRreposname :=',pkg$repo) + ,'include /usr/share/R/debian/r-cran.mk' + ,'',sep='\n') + ,file=pkg$debfile('rules')) + Sys.chmod(pkg$debfile('rules'),'0700') +} + +generate.copyright <- function(pkg) { + # generate copyright file; we trust DESCRIPTION + writeLines(strwrap( + paste('This Debian package of the GNU R package',pkg$name + ,'was generated automatically using cran2deb by' + ,paste(maintainer,'.',sep='') + ,'' + ,'The original GNU R package is Copyright (C) ' + # TODO: copyright start date, true copyright date + ,format(Sys.time(),'%Y') + ,pkg$description[1,'Author'] + ,'and possibly others.' + ,'' + ,'The original GNU R package is maintained by' + ,pkg$description[1,'Maintainer'],'and was obtained from:' + ,'' + ,pkg$repoURL + ,'' + ,'' + ,'The GNU R package DESCRIPTION offers a' + ,'Copyright licenses under the terms of the',pkg$license + ,'license. On a Debian GNU/Linux system, common' + ,'licenses are included in the directory' + ,'/usr/share/common-licenses/.' + ,'' + ,'The DESCRIPTION file for the original GNU R package ' + ,'can be found in ' + ,file.path('/usr/lib/R/site-library' + ,pkg$debname + ,'DESCRIPTION' + ) + ,sep='\n'), width=72), con=pkg$debfile('copyright.in')) +} + +prepare.new.debian <- function(pkg,extra_deps) { + # generate Debian version and name + pkg$repo = repourl.as.debian(pkg$repoURL) + pkg$debversion = version.new(pkg$version) + if (!length(grep('^[A-Za-z0-9][A-Za-z0-9+.-]+$',pkg$name))) { + stop(paste('Cannot convert package name into a Debian name',pkg$name)) + } + pkg$srcname = tolower(pkg$name) + pkg$debname = pkgname.as.debian(pkg$name,repo=pkg$repo) + + if (!length(grep('\\.tar\\.gz',pkg$archive))) { + stop('archive is not tarball') + } + + # re-pack into a Debian-named archive with a Debian-named directory. + debpath = file.path(dirname(pkg$archive) + ,paste(pkg$srcname,'-' + ,pkg$version + ,sep='')) + file.rename(pkg$path, debpath) + pkg$path = debpath + debarchive = file.path(dirname(pkg$archive) + ,paste(pkg$srcname,'_' + ,pkg$version,'.orig.tar.gz' + ,sep='')) + wd <- getwd() + setwd(dirname(pkg$path)) + # remove them pesky +x files + system(paste('find',shQuote(basename(pkg$path)) + ,'-type f -exec chmod -x {} \\;')) + # tar it all back up + system(paste('tar -czf',shQuote(debarchive),shQuote(basename(pkg$path)))) + setwd(wd) + file.remove(pkg$archive) + pkg$archive = debarchive + + # make the debian/ directory + debdir <- file.path(pkg$path,'debian') + pkg$debfile <- function(x) { file.path(debdir,x) } + unlink(debdir,recursive=T) + dir.create(debdir) + + # see if this is an architecture-dependent package. + # heuristic: if /src/ exists in pkg$path, then this is an + # architecture-dependent package. + # CRAN2DEB.pm is a bit fancier about this but ``Writing R extensions'' + # says: ``The sources and headers for the compiled code are in src, plus + # optionally file Makevars or Makefile.'' It seems unlikely that + # architecture independent code would end up here. + if (pkg$is_bundle) { + # if it's a bundle, check each of the packages + pkg$archdep = F + for (pkgname in r.bundle.contains(pkg$name)) { + pkg$archdep = file.exists(file.path(pkg$path,pkgname,'src')) + if (pkg$archdep) { + break + } + } + } else { + pkg$archdep = file.exists(file.path(pkg$path,'src')) + } + pkg$arch <- 'all' + if (pkg$archdep) { + pkg$arch <- host.arch() + } + + pkg$license <- accept.license(pkg) + pkg$depends <- get.dependencies(pkg,extra_deps) + generate.changelog(pkg) + generate.rules(pkg) + generate.copyright(pkg) + generate.control(pkg) + + # TODO: debian/watch from pkg$repoURL + + # convert text to utf8 (who knows what the original character set is -- + # let's hope iconv DTRT). + for (file in c('control','changelog','copyright')) { + system(paste('iconv -o ',shQuote(pkg$debfile(file)) + ,' -t utf8 ' + ,shQuote(pkg$debfile(paste(file,'in',sep='.'))))) + file.remove(pkg$debfile(paste(file,'in',sep='.'))) + } + return(pkg) +} + +build.debian <- function(pkg) { + wd <- getwd() + setwd(pkg$path) + message(paste('N: building Debian package' + ,pkg$debname + ,paste('(',pkg$debversion,')',sep='') + ,'...')) + ret = system(paste('pdebuild --configfile',pbuilder_config)) + setwd(wd) + if (ret != 0) { + stop('Failed to build package.') + } +} + diff --git a/pkg/trunk/R/getrpkg.R b/pkg/trunk/R/getrpkg.R new file mode 100644 index 0000000..45fbe6d --- /dev/null +++ b/pkg/trunk/R/getrpkg.R @@ -0,0 +1,68 @@ + +setup <- function() { + # set up the working directory + tmp <- tempfile('cran2deb') + dir.create(tmp) + return (tmp) +} + +cleanup <- function(dir) { + # remove the working directory + unlink(dir,recursive=T) + invisible() +} + +prepare.pkg <- function(dir, pkgname) { + # download and extract an R package named pkgname + # OR the bundle containing pkgname + + # based loosely on library/utils/R/packages2.R::install.packages + # should do nothing Debian specific + + # first a little trick; change pkgname if pkgname is contained in a bundle + if (!(pkgname %in% rownames(available))) { + bundle <- r.bundle.of(pkgname) + if (is.na(bundle)) { + stop(paste('package',pkgname,'is unavailable')) + } + pkgname <- bundle + } + archive <- download.packages(pkgname, dir, available=available, repos='', type="source")[1,2] + if (length(grep('\\.\\.',archive)) || normalizePath(archive) != archive) { + stop(paste('funny looking path',archive)) + } + wd <- getwd() + setwd(dir) + if (length(grep('\\.zip$',archive))) { + cmd = paste('unzip',shQuote(archive)) + } else if (length(grep('\\.tar\\.gz$',archive))) { + cmd = paste('tar','xzf',shQuote(archive)) + } else { + stop(paste('Type of archive',archive,'is unknown.')) + } + ret = system(cmd) + setwd(wd) + if (ret != 0) { + stop(paste('Extraction of archive',archive,'failed.')) + } + pkg <- pairlist() + pkg$name = pkgname + pkg$archive = archive + pkg$path = sub("_\\.(zip|tar\\.gz)", "" + ,gsub(.standard_regexps()$valid_package_version, "" + ,archive)) + if (!file.info(pkg$path)[,'isdir']) { + stop(paste(pkg$path,'is not a directory and should be.')) + } + pkg$description = read.dcf(file.path(pkg$path,'DESCRIPTION')) + pkg$repoURL = available[pkgname,'Repository'] + pkg$version = pkg$description[1,'Version'] + pkg$is_bundle = 'Bundle' %in% names(pkg$description[1,]) + # note subtly of short circuit operators (no absorption) + if ((!pkg$is_bundle && pkg$description[1,'Package'] != pkg$name) || + ( pkg$is_bundle && pkg$description[1,'Bundle'] != pkg$name)) { + stop(paste('package name mismatch')) + } + return(pkg) +} + diff --git a/pkg/trunk/R/license.R b/pkg/trunk/R/license.R new file mode 100644 index 0000000..7112572 --- /dev/null +++ b/pkg/trunk/R/license.R @@ -0,0 +1,77 @@ +debian_ok_licenses=c('GPL','LGPL','AGPL','ARTISTIC' #,'UNLIMITED' + ,'BSD','MIT','APACHE','X11','MPL') + +is_acceptable_license <- function(license) { + # determine if license is acceptable + + # compress spaces into a single space + license = gsub('[[:blank:]]+',' ',license) + # make all characters upper case + license = toupper(license) + # don't care about versions of licenses + license = chomp(sub('\\( ?[<=>!]+ ?[0-9.-]+ ?\\)','' + ,sub('-[0-9.-]+','',license))) + if (license %in% debian_ok_licenses) { + return(T) + } + # uninteresting urls + license = gsub('HTTP://WWW.GNU.ORG/[A-Z/._-]*','',license) + license = gsub('HTTP://WWW.X.ORG/[A-Z/._-]*','',license) + license = gsub('HTTP://WWW.OPENSOURCE.ORG/[A-Z/._-]*','',license) + # remove all punctuation + license = gsub('[[:punct:]]+','',license) + # remove any extra space introduced + license = chomp(gsub('[[:space:]]+',' ',license)) + # redundant + license = gsub('THE','',license) + license = gsub('SEE','',license) + license = gsub('STANDARD','',license) + license = gsub('LICEN[SC]E','',license) + license = gsub('(GNU )?(GPL|GENERAL PUBLIC)','GPL',license) + license = gsub('(MOZILLA )?(MPL|MOZILLA PUBLIC)','MPL',license) + # remove any extra space introduced + license = chomp(gsub('[[:space:]]+',' ',license)) + if (license %in% debian_ok_licenses) { + message(paste('W: Accepted wild license as',license,'. FIX THE PACKAGE!')) + return(T) + } + # remove everything that looks like a version specification + license = gsub('(VER?SION|V)? *[0-9.-]+ *(OR *(HIGHER|LATER|NEWER|GREATER|ABOVE))?','' + ,license) + # remove any extra space introduced + license = chomp(gsub('[[:space:]]+',' ',license)) + if (license %in% debian_ok_licenses) { + message(paste('W: Accepted wild license as',license,'. FIX THE PACKAGE!')) + return(T) + } + # TODO: put debian_ok_licenses in DB + # TODO: file {LICENSE,LICENCE} (+ maybe COPYING?) + message(paste('E: Wild license',license,'did not match')) + return(F) +} + +accept.license <- function(pkg) { + # check the license + if (!('License' %in% names(pkg$description[1,]))) { + stop('package has no License: field in description!') + } + accept=NULL + for (license in strsplit(chomp(pkg$description[1,'License']) + ,'[[:space:]]*\\|[[:space:]]*')[[1]]) { + if (is_acceptable_license(license)) { + accept=license + break + } + } + if (is.null(accept)) { + stop(paste('No acceptable license:',pkg$description[1,'License'])) + } else { + message(paste('N: Auto-accepted license',accept)) + } + if (accept == 'Unlimited') { + # definition of Unlimited from ``Writing R extensions'' + accept=paste('Unlimited (no restrictions on distribution or' + ,'use other than those imposed by relevant laws)') + } + return(accept) +} diff --git a/pkg/trunk/R/rdep.R b/pkg/trunk/R/rdep.R new file mode 100644 index 0000000..0af9451 --- /dev/null +++ b/pkg/trunk/R/rdep.R @@ -0,0 +1,152 @@ + +r.bundle.of <- function(pkgname) { + # returns the bundle containing pkgname or NA + bundles <- names(available[!is.na(available[, 'Bundle']), 'Contains']) + # use the first bundle + for (bundle in bundles) { + if (pkgname %in% r.bundle.contains(bundle)) { + return(bundle) + } + } + return(NA) +} + +r.bundle.contains <- function(bundlename) { + return(strsplit(available[bundlename,'Contains'],'[[:space:]]+')[[1]]) +} + +r.requiring <- function(names) { + for (name in names) { + if (!(name %in% base_pkgs) && !(name %in% rownames(available))) { + bundle <- r.bundle.of(name) + if (is.na(bundle)) { + stop(paste('package',name,'is not available')) + } + names <- c(names,r.bundle.contains(bundle)) + } + } + # approximately prune first into a smaller availability + candidates <- available[sapply(rownames(available) + ,function(name) + length(grep(paste(names,sep='|') + ,available[name,r_depend_fields])) > 0) + ,r_depend_fields + ,drop=F] + if (length(candidates) == 0) { + return(c()) + } + # find a logical index into available of every package/bundle + # whose dependency field contains at least one element of names. + # (this is not particularly easy to read---sorry---but is much faster than + # the alternatives i could think of) + prereq=c() + dep_matches <- function(dep) chomp(gsub('\\([^\\)]+\\)','',dep)) %in% names + any_dep_matches <- function(name,field=NA) + any(sapply(strsplit(chomp(candidates[name,field]) + ,'[[:space:]]*,[[:space:]]*') + ,dep_matches)) + + for (field in r_depend_fields) { + matches = sapply(rownames(candidates), any_dep_matches, field=field) + if (length(matches) > 0) { + prereq = c(prereq,rownames(candidates[matches,])) + } + } + return(unique(prereq)) +} + +r.dependencies.of <- function(name=NULL,description=NULL) { + # find the immediate dependencies (children in the dependency graph) of an + # R package + if (!is.null(name) && (name == 'R' || name %in% base_pkgs)) { + return(data.frame()) + } + if (is.null(description) && is.null(name)) { + stop('must specify either a description or a name.') + } + if (is.null(description)) { + if (!(name %in% rownames(available))) { + bundle <- r.bundle.of(name) + if (is.na(bundle)) { + stop(paste('package',name,'is not available')) + } + name <- bundle + } + description <- data.frame() + # keep only the interesting fields + for (field in r_depend_fields) { + if (!(field %in% names(available[name,]))) { + next + } + description[1,field] = available[name,field] + } + } + # extract the dependencies from the description + deps <- data.frame() + for (field in r_depend_fields) { + if (!(field %in% names(description[1,]))) { + next + } + new_deps <- lapply(strsplit(chomp(description[1,field]) + ,'[[:space:]]*,[[:space:]]*')[[1]] + ,r.parse.dep.field) + deps <- iterate(lapply(new_deps[!is.na(new_deps)],rbind),deps,rbind) + } + return (deps) +} + +r.parse.dep.field <- function(dep) { + if (is.na(dep)) { + return(NA) + } + # remove other comments + dep = gsub('(\\(\\)|\\([[:space:]]*[^<=>!].*\\))','',dep) + # squish spaces + dep = chomp(gsub('[[:space:]]+',' ',dep)) + # parse version + pat = '^([^ ()]+) ?(\\( ?([<=>!]+ ?[0-9.-]+) ?\\))?$' + if (!length(grep(pat,dep))) { + stop(paste('R dependency',dep,'does not appear to be well-formed')) + } + version = sub(pat,'\\3',dep) + dep = sub(pat,'\\1',dep) + if (!(dep %in% rownames(available))) { + depb <- r.bundle.of(dep) + if (!is.na(depb)) { + dep <- depb + } + } + return(list(name=dep,version=version)) +} + +r.dependency.closure <- function(fringe, forward_arcs=T) { + # find the transitive closure of the dependencies/prerequisites of some R + # packages + closure <- list() + if (is.data.frame(fringe)) { + fringe <- levels(fringe$name) + } + fun = function(x) levels(r.dependencies.of(name=x)$name) + if (!forward_arcs) { + fun = r.requiring + } + while(length(fringe) > 0) { + # pop off the top + top <- fringe[[1]] + if (length(fringe) > 1) { + fringe <- fringe[2:length(fringe)] + } else { + fringe <- list() + } + src <- pkgname.as.debian(top,binary=F) + if (!length(grep('^r-',src)) || length(grep('^r-base',src))) { + next + } + newdeps <- fun(top) + closure=c(closure,top) + fringe=c(fringe,newdeps) + } + # build order + return(rev(unique(closure,fromLast=T))) +} + diff --git a/pkg/trunk/R/util.R b/pkg/trunk/R/util.R new file mode 100644 index 0000000..35f6413 --- /dev/null +++ b/pkg/trunk/R/util.R @@ -0,0 +1,17 @@ +iterate <- function(xs,z,fun) { + y <- z + for (x in xs) + y <- fun(y,x) + return(y) +} + +chomp <- function(x) { + # remove leading and trailing spaces + return(sub('^[[:space:]]+','',sub('[[:space:]]+$','',x))) +} + +host.arch <- function() { + # return the host system architecture + system('dpkg-architecture -qDEB_HOST_ARCH',intern=T) +} + diff --git a/pkg/trunk/R/version.R b/pkg/trunk/R/version.R new file mode 100644 index 0000000..29c8c0e --- /dev/null +++ b/pkg/trunk/R/version.R @@ -0,0 +1,70 @@ +version.new <- function(rver,debian_revision=1, debian_epoch=0) { + # generate a string representation of the Debian version of an + # R version of a package + pkgver = rver + + # ``Writing R extensions'' says that the version consists of at least two + # non-negative integers, separated by . or - + if (!length(grep('^([0-9]+[.-])+[0-9]+$',rver))) { + stop(paste('Not a valid R package version',rver)) + } + + # Debian policy says that an upstream version should start with a digit and + # may only contain ASCII alphanumerics and '.+-:~' + if (!length(grep('^[0-9][A-Za-z0-9.+:~-]*$',rver))) { + stop(paste('R package version',rver + ,'does not obviously translate into a valid Debian version.')) + } + + # if rver contains a : then the Debian version must also have a colon + if (debian_epoch == 0 && length(grep(':',pkgver))) + debian_epoch = 1 + + # if the epoch is non-zero then include it + if (debian_epoch != 0) + pkgver = paste(debian_epoch,':',pkgver,sep='') + + # always add the '-1' Debian release; nothing is lost and rarely will R + # packages be Debian packages without modification. + return(paste(pkgver,'-',debian_revision,sep='')) +} + +version.epoch <- function(pkgver) { + # return the Debian epoch of a Debian package version + if (!length(grep(':',pkgver))) + return(0) + return(as.integer(sub('^([0-9]+):.*','\\1',pkgver))) +} +# version.epoch . version.new(x,y) = id +# version.epoch(version.new(x,y)) = 0 + +version.revision <- function(pkgver) { + # return the Debian revision of a Debian package version + return(as.integer(sub('.*-([0-9]+)$','\\1',pkgver))) +} +# version.revision . version.new(x) = id +# version.revision(version.new(x)) = 1 + +version.upstream <- function(pkgver) { + # return the upstream version of a Debian package version + return(sub('-[0-9]+$','',sub('^[0-9]+:','',pkgver))) +} +# version.upstream . version.new = id + +version.update <- function(rver, prev_pkgver) { + # return the next debian package version + prev_rver <- version.upstream(prev_pkgver) + if (prev_rver == rver) { + # increment the Debian revision + return(version.new(rver + ,debian_revision = version.revision(prev_pkgver)+1 + ,debian_epoch = version.epoch(prev_pkgver) + )) + } + # new release + # TODO: implement Debian ordering over version and then autoincrement + # Debian epoch when upstream version does not increment. + return(version.new(rver + ,debian_epoch = version.epoch(prev_pkgver) + )) +} diff --git a/pkg/trunk/R/zzz.R b/pkg/trunk/R/zzz.R new file mode 100644 index 0000000..a57cc3a --- /dev/null +++ b/pkg/trunk/R/zzz.R @@ -0,0 +1,20 @@ + +changesfile <- function(srcname,version='*') { + return(file.path(pbuilder_results + ,paste(srcname,'_',version,'_' + ,host.arch(),'.changes',sep=''))) +} + +maintainer <- 'cran2deb buildbot ' +root <- system.file('') +pbuilder_results <- file.path(root,'var/results') +pbuilder_config <- file.path(root,'etc/pbuilderrc') +dput_config <- file.path(root,'etc/dput.cf') +dinstall_config <- file.path(root,'etc/mini-dinstall.conf') +dinstall_archive <- file.path(root,'var/archive') +r_depend_fields <- c('Depends','Imports') # Suggests, Enhances + +# we cache the list of available packages +# should be pulled in already +#load(file.path(root,'var/cache/available.cache.Rd')) + diff --git a/pkg/trunk/build_ctv b/pkg/trunk/build_ctv deleted file mode 100755 index 754dd58..0000000 --- a/pkg/trunk/build_ctv +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env rc - -for (ctv in `{./cranpkgs query}) { - echo task view $ctv... - if (![ -e ctv/$ctv ]) { - ./build_some $ctv - mkdir -p ctv/$ctv - mv warn fail ctv/$ctv - } -} - diff --git a/pkg/trunk/build_some b/pkg/trunk/build_some deleted file mode 100755 index dd12c2d..0000000 --- a/pkg/trunk/build_some +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/rc - -mkdir -p warn fail -./cranpkgs $* >all_pkgs -for (pkg in `{cat all_pkgs}) { - if (~ $pkg *..* */*) { - echo bad name $pkg >>fail/ERROR - } else { - echo .. package $pkg - fail=0 - ./cran2deb $pkg >fail/$pkg >[2=1] || fail=1 - if (~ $fail 0) { - grep '^[WE]:' fail/$pkg >warn/$pkg - if (~ `{stat -c '%s' warn/$pkg} 0) { - rm -f warn/$pkg - } - rm -f fail/$pkg - } - } -} diff --git a/pkg/trunk/copy_find b/pkg/trunk/copy_find deleted file mode 100755 index fe3d619..0000000 --- a/pkg/trunk/copy_find +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/rc -kwords='copyright|warranty|redistribution|modification|patent|trademark|licen[cs]e|permission' -nl=`` () {printf '\n'} -ifs=$nl { - files=`{find $1 ! -path '*debian*' -type f} - lines=() - for (file in $files) { - notices=`{grep -H '(C)' $file} - notices=($notices `{grep -HEi $kwords $file}) - lines=($lines `{{for (notice in $notices) echo $notice} | sort -u}) - } - # let's hope no file has a : in it - ifs=() { seen_files=`{{for (line in $lines) echo $line} | cut -d: -f1} } - missing_copyright=() - for (file in $files) { - if (echo -n $seen_files | grep -q '^'^$file^'$') { - } else { - missing_copyright=($missing_copyright $file) - } - } - echo 'Suspect copyright notices:' - for (line in $lines) echo ' '$line - echo 'Files without *suspect* copyright notices:' - for (missing in $missing_copyright) { - echo ' '$missing - echo ' type: '`{file $missing} - echo ' chars: '`{wc -c $missing | awk '{print $1}'} - echo ' lines: '`{wc -l $missing | awk '{print $1}'} - } -} diff --git a/pkg/trunk/cran2deb b/pkg/trunk/cran2deb deleted file mode 100755 index 821d8a6..0000000 --- a/pkg/trunk/cran2deb +++ /dev/null @@ -1,798 +0,0 @@ -#!/usr/bin/env r - -maintainer <- 'cran2deb buildbot ' -root <- '/home/cb/work/gsoc/cran2deb' -pbuilder_results <- file.path(root,'var/results') -pbuilder_config <- file.path(root,'etc/pbuilderrc') -dput_config <- file.path(root,'etc/dput.cf') -dinstall_config <- file.path(root,'etc/mini-dinstall.conf') -dinstall_archive <- file.path(root,'var/archive') -r_depend_fields <- c('Depends','Imports') # Suggests, Enhances - -# we cache the list of available packages -load(file.path(root,'var/cache/available.cache.Rd')) - -version.new <- function(rver,debian_revision=1, debian_epoch=0) { - # generate a string representation of the Debian version of an - # R version of a package - pkgver = rver - - # ``Writing R extensions'' says that the version consists of at least two - # non-negative integers, separated by . or - - if (!length(grep('^([0-9]+[.-])+[0-9]+$',rver))) { - stop(paste('Not a valid R package version',rver)) - } - - # Debian policy says that an upstream version should start with a digit and - # may only contain ASCII alphanumerics and '.+-:~' - if (!length(grep('^[0-9][A-Za-z0-9.+:~-]*$',rver))) { - stop(paste('R package version',rver - ,'does not obviously translate into a valid Debian version.')) - } - - # if rver contains a : then the Debian version must also have a colon - if (debian_epoch == 0 && length(grep(':',pkgver))) - debian_epoch = 1 - - # if the epoch is non-zero then include it - if (debian_epoch != 0) - pkgver = paste(debian_epoch,':',pkgver,sep='') - - # always add the '-1' Debian release; nothing is lost and rarely will R - # packages be Debian packages without modification. - return(paste(pkgver,'-',debian_revision,sep='')) -} - -version.epoch <- function(pkgver) { - # return the Debian epoch of a Debian package version - if (!length(grep(':',pkgver))) - return(0) - return(as.integer(sub('^([0-9]+):.*','\\1',pkgver))) -} -# version.epoch . version.new(x,y) = id -# version.epoch(version.new(x,y)) = 0 - -version.revision <- function(pkgver) { - # return the Debian revision of a Debian package version - return(as.integer(sub('.*-([0-9]+)$','\\1',pkgver))) -} -# version.revision . version.new(x) = id -# version.revision(version.new(x)) = 1 - -version.upstream <- function(pkgver) { - # return the upstream version of a Debian package version - return(sub('-[0-9]+$','',sub('^[0-9]+:','',pkgver))) -} -# version.upstream . version.new = id - -version.update <- function(rver, prev_pkgver) { - # return the next debian package version - prev_rver <- version.upstream(prev_pkgver) - if (prev_rver == rver) { - # increment the Debian revision - return(version.new(rver - ,debian_revision = version.revision(prev_pkgver)+1 - ,debian_epoch = version.epoch(prev_pkgver) - )) - } - # new release - # TODO: implement Debian ordering over version and then autoincrement - # Debian epoch when upstream version does not increment. - return(version.new(rver - ,debian_epoch = version.epoch(prev_pkgver) - )) -} - -# sudo pbuilder --execute r -e 'rownames(installed.packages())' -# XXX: has to be a better way of doing this -base_pkgs=c('base', 'datasets','grDevices','graphics','grid', 'methods' - ,'splines','stats', 'stats4', 'tcltk', 'tools','utils') -# found in R source directory: -# 'profile', 'datasets' - -repourl.as.debian <- function(url) { - # map the url to a repository onto its name in debian package naming - if (length(grep('cran',url))) { - return('cran') - } - if (length(grep('bioc',url))) { - return('bioc') - } - stop(paste('unknown repository',url)) -} - -pkgname.as.debian <- function(name,repopref=NULL,version=NULL,binary=T) { - # generate the debian package name corresponding to the R package name - if (name %in% base_pkgs) { - name = 'R' - } - if (name == 'R') { - # R is special. - if (binary) { - debname='r-base-core' - } else { - debname='r-base-dev' - } - } else { - # XXX: data.frame rownames are unique, so always override repopref for - # now. - if (!(name %in% rownames(available))) { - bundle <- r.bundle.of(name) - if (is.na(bundle)) { - stop(paste('package',name,'is not available')) - } - name <- bundle - } - repopref <- repourl.as.debian(available[name,'Repository']) - debname = paste('r',tolower(repopref),tolower(name),sep='-') - } - if (!is.null(version) && length(version) > 1) { - debname = paste(debname,' (',version,')',sep='') - } - return(debname) -} - -setup <- function() { - # set up the working directory - tmp <- tempfile('cran2deb') - dir.create(tmp) - return (tmp) -} - -cleanup <- function(dir) { - # remove the working directory - unlink(dir,recursive=T) - invisible() -} - -r.bundle.of <- function(pkgname) { - # returns the bundle containing pkgname or NA - bundles <- names(available[!is.na(available[, 'Bundle']), 'Contains']) - # use the first bundle - for (bundle in bundles) { - if (pkgname %in% r.bundle.contains(bundle)) { - return(bundle) - } - } - return(NA) -} - -r.bundle.contains <- function(bundlename) { - return(strsplit(available[bundlename,'Contains'],'[[:space:]]+')[[1]]) -} - -prepare.pkg <- function(dir, pkgname) { - # download and extract an R package named pkgname - # OR the bundle containing pkgname - - # based loosely on library/utils/R/packages2.R::install.packages - # should do nothing Debian specific - - # first a little trick; change pkgname if pkgname is contained in a bundle - if (!(pkgname %in% rownames(available))) { - bundle <- r.bundle.of(pkgname) - if (is.na(bundle)) { - stop(paste('package',pkgname,'is unavailable')) - } - pkgname <- bundle - } - archive <- download.packages(pkgname, dir, available=available, repos='', type="source")[1,2] - if (length(grep('\\.\\.',archive)) || normalizePath(archive) != archive) { - stop(paste('funny looking path',archive)) - } - wd <- getwd() - setwd(dir) - if (length(grep('\\.zip$',archive))) { - cmd = paste('unzip',shQuote(archive)) - } else if (length(grep('\\.tar\\.gz$',archive))) { - cmd = paste('tar','xzf',shQuote(archive)) - } else { - stop(paste('Type of archive',archive,'is unknown.')) - } - ret = system(cmd) - setwd(wd) - if (ret != 0) { - stop(paste('Extraction of archive',archive,'failed.')) - } - pkg <- pairlist() - pkg$name = pkgname - pkg$archive = archive - pkg$path = sub("_\\.(zip|tar\\.gz)", "" - ,gsub(.standard_regexps()$valid_package_version, "" - ,archive)) - if (!file.info(pkg$path)[,'isdir']) { - stop(paste(pkg$path,'is not a directory and should be.')) - } - pkg$description = read.dcf(file.path(pkg$path,'DESCRIPTION')) - pkg$repoURL = available[pkgname,'Repository'] - pkg$version = pkg$description[1,'Version'] - pkg$is_bundle = 'Bundle' %in% names(pkg$description[1,]) - # note subtly of short circuit operators (no absorption) - if ((!pkg$is_bundle && pkg$description[1,'Package'] != pkg$name) || - ( pkg$is_bundle && pkg$description[1,'Bundle'] != pkg$name)) { - stop(paste('package name mismatch')) - } - return(pkg) -} - -debian_ok_licenses=c('GPL','LGPL','AGPL','ARTISTIC' #,'UNLIMITED' - ,'BSD','MIT','APACHE','X11','MPL') - -is_acceptable_license <- function(license) { - # determine if license is acceptable - - # compress spaces into a single space - license = gsub('[[:blank:]]+',' ',license) - # make all characters upper case - license = toupper(license) - # don't care about versions of licenses - license = chomp(sub('\\( ?[<=>!]+ ?[0-9.-]+ ?\\)','' - ,sub('-[0-9.-]+','',license))) - if (license %in% debian_ok_licenses) { - return(T) - } - # uninteresting urls - license = gsub('HTTP://WWW.GNU.ORG/[A-Z/._-]*','',license) - license = gsub('HTTP://WWW.X.ORG/[A-Z/._-]*','',license) - license = gsub('HTTP://WWW.OPENSOURCE.ORG/[A-Z/._-]*','',license) - # remove all punctuation - license = gsub('[[:punct:]]+','',license) - # remove any extra space introduced - license = chomp(gsub('[[:space:]]+',' ',license)) - # redundant - license = gsub('THE','',license) - license = gsub('SEE','',license) - license = gsub('STANDARD','',license) - license = gsub('LICEN[SC]E','',license) - license = gsub('(GNU )?(GPL|GENERAL PUBLIC)','GPL',license) - license = gsub('(MOZILLA )?(MPL|MOZILLA PUBLIC)','MPL',license) - # remove any extra space introduced - license = chomp(gsub('[[:space:]]+',' ',license)) - if (license %in% debian_ok_licenses) { - message(paste('W: Accepted wild license as',license,'. FIX THE PACKAGE!')) - return(T) - } - # remove everything that looks like a version specification - license = gsub('(VER?SION|V)? *[0-9.-]+ *(OR *(HIGHER|LATER|NEWER|GREATER|ABOVE))?','' - ,license) - # remove any extra space introduced - license = chomp(gsub('[[:space:]]+',' ',license)) - if (license %in% debian_ok_licenses) { - message(paste('W: Accepted wild license as',license,'. FIX THE PACKAGE!')) - return(T) - } - # TODO: put debian_ok_licenses in DB - # TODO: file {LICENSE,LICENCE} (+ maybe COPYING?) - message(paste('E: Wild license',license,'did not match')) - return(F) -} - -iterate <- function(xs,z,fun) { - y <- z - for (x in xs) - y <- fun(y,x) - return(y) -} - -chomp <- function(x) { - # remove leading and trailing spaces - return(sub('^[[:space:]]+','',sub('[[:space:]]+$','',x))) -} - -host.arch <- function() { - # return the host system architecture - system('dpkg-architecture -qDEB_HOST_ARCH',intern=T) -} - -r.requiring <- function(names) { - for (name in names) { - if (!(name %in% base_pkgs) && !(name %in% rownames(available))) { - bundle <- r.bundle.of(name) - if (is.na(bundle)) { - stop(paste('package',name,'is not available')) - } - names <- c(names,r.bundle.contains(bundle)) - } - } - # approximately prune first into a smaller availability - candidates <- available[sapply(rownames(available) - ,function(name) - length(grep(paste(names,sep='|') - ,available[name,r_depend_fields])) > 0) - ,r_depend_fields - ,drop=F] - if (length(candidates) == 0) { - return(c()) - } - # find a logical index into available of every package/bundle - # whose dependency field contains at least one element of names. - # (this is not particularly easy to read---sorry---but is much faster than - # the alternatives i could think of) - prereq=c() - dep_matches <- function(dep) chomp(gsub('\\([^\\)]+\\)','',dep)) %in% names - any_dep_matches <- function(name,field=NA) - any(sapply(strsplit(chomp(candidates[name,field]) - ,'[[:space:]]*,[[:space:]]*') - ,dep_matches)) - - for (field in r_depend_fields) { - matches = sapply(rownames(candidates), any_dep_matches, field=field) - if (length(matches) > 0) { - prereq = c(prereq,rownames(candidates[matches,])) - } - } - return(unique(prereq)) -} - -r.dependencies.of <- function(name=NULL,description=NULL) { - # find the immediate dependencies (children in the dependency graph) of an - # R package - if (!is.null(name) && (name == 'R' || name %in% base_pkgs)) { - return(data.frame()) - } - if (is.null(description) && is.null(name)) { - stop('must specify either a description or a name.') - } - if (is.null(description)) { - if (!(name %in% rownames(available))) { - bundle <- r.bundle.of(name) - if (is.na(bundle)) { - stop(paste('package',name,'is not available')) - } - name <- bundle - } - description <- data.frame() - # keep only the interesting fields - for (field in r_depend_fields) { - if (!(field %in% names(available[name,]))) { - next - } - description[1,field] = available[name,field] - } - } - # extract the dependencies from the description - deps <- data.frame() - for (field in r_depend_fields) { - if (!(field %in% names(description[1,]))) { - next - } - new_deps <- lapply(strsplit(chomp(description[1,field]) - ,'[[:space:]]*,[[:space:]]*')[[1]] - ,r.parse.dep.field) - deps <- iterate(lapply(new_deps[!is.na(new_deps)],rbind),deps,rbind) - } - return (deps) -} - -r.parse.dep.field <- function(dep) { - if (is.na(dep)) { - return(NA) - } - # remove other comments - dep = gsub('(\\(\\)|\\([[:space:]]*[^<=>!].*\\))','',dep) - # squish spaces - dep = chomp(gsub('[[:space:]]+',' ',dep)) - # parse version - pat = '^([^ ()]+) ?(\\( ?([<=>!]+ ?[0-9.-]+) ?\\))?$' - if (!length(grep(pat,dep))) { - stop(paste('R dependency',dep,'does not appear to be well-formed')) - } - version = sub(pat,'\\3',dep) - dep = sub(pat,'\\1',dep) - if (!(dep %in% rownames(available))) { - depb <- r.bundle.of(dep) - if (!is.na(depb)) { - dep <- depb - } - } - return(list(name=dep,version=version)) -} - -r.dependency.closure <- function(fringe, forward_arcs=T) { - # find the transitive closure of the dependencies/prerequisites of some R - # packages - closure <- list() - if (is.data.frame(fringe)) { - fringe <- levels(fringe$name) - } - fun = function(x) levels(r.dependencies.of(name=x)$name) - if (!forward_arcs) { - fun = r.requiring - } - while(length(fringe) > 0) { - # pop off the top - top <- fringe[[1]] - if (length(fringe) > 1) { - fringe <- fringe[2:length(fringe)] - } else { - fringe <- list() - } - src <- pkgname.as.debian(top,binary=F) - if (!length(grep('^r-',src)) || length(grep('^r-base',src))) { - next - } - newdeps <- fun(top) - closure=c(closure,top) - fringe=c(fringe,newdeps) - } - # build order - return(rev(unique(closure,fromLast=T))) -} - -accept.license <- function(pkg) { - # check the license - if (!('License' %in% names(pkg$description[1,]))) { - stop('package has no License: field in description!') - } - accept=NULL - for (license in strsplit(chomp(pkg$description[1,'License']) - ,'[[:space:]]*\\|[[:space:]]*')[[1]]) { - if (is_acceptable_license(license)) { - accept=license - break - } - } - if (is.null(accept)) { - stop(paste('No acceptable license:',pkg$description[1,'License'])) - } else { - message(paste('N: Auto-accepted license',accept)) - } - if (accept == 'Unlimited') { - # definition of Unlimited from ``Writing R extensions'' - accept=paste('Unlimited (no restrictions on distribution or' - ,'use other than those imposed by relevant laws)') - } - return(accept) -} - -get.dependencies <- function(pkg,extra_deps) { - if ('SystemRequirements' %in% colnames(pkg$description)) { - stop(paste('Unsupported SystemRequirements:',pkg$description[1,'SystemRequirements'])) - } - - # determine dependencies - dependencies <- r.dependencies.of(description=pkg$description) - depends <- list() - # these are used for generating the Depends fields - as.deb <- function(r,binary) { - return(pkgname.as.debian(paste(dependencies[r,]$name) - ,version=dependencies[r,]$version - ,repopref=pkg$repo - ,binary=binary)) - } - depends$bin <- lapply(rownames(dependencies), as.deb, binary=T) - depends$build <- lapply(rownames(dependencies), as.deb, binary=F) - # add the command line dependencies - depends$bin = c(extra_deps$deb,depends$bin) - depends$build = c(extra_deps$deb,depends$build) - - # make sure we depend upon R in some way... - if (!length(grep('^r-base',depends$build))) { - depends$build = c(depends$build,pkgname.as.debian('R',version='>= 2.7.0',binary=F)) - depends$bin = c(depends$bin, pkgname.as.debian('R',version='>= 2.7.0',binary=T)) - } - # also include stuff to allow tcltk to build (suggested by Dirk) - depends$build = c(depends$build,'xvfb','xauth','xfont-base') - - # remove duplicates - depends <- lapply(depends,unique) - - # append the Debian dependencies - depends$build=c(depends$build,'debhelper (>> 4.1.0)','cdbs') - if (pkg$archdep) { - depends$bin=c(depends$bin,'${shlibs:Depends}') - } - - # the names of dependent source packages (to find the .changes file to - # upload via dput). these can be found recursively. - depends$r = lapply(r.dependency.closure(dependencies) - ,tolower) - # append command line dependencies - depends$r = c(extra_deps$r, depends$r) - return(depends) -} - -generate.changelog <- function(pkg) { - # construct a dummy changelog - # TODO: ``Writing R extensions'' mentions that a package may also have - # {NEWS,ChangeLog} files. - cat(paste(paste(pkg$srcname,' (',pkg$debversion,') unstable; urgency=low',sep='') - ,'' ,' * Initial release.','' - ,paste(' --',maintainer,'',format(Sys.time(),'%a, %d %b %Y %H:%M:%S %z')) - ,'',sep='\n'),file=pkg$debfile('changelog.in')) -} - -generate.rules <- function(pkg) { - cat(paste('#!/usr/bin/make -f' - ,paste('debRreposname :=',pkg$repo) - ,'include /usr/share/R/debian/r-cran.mk' - ,'',sep='\n') - ,file=pkg$debfile('rules')) - Sys.chmod(pkg$debfile('rules'),'0700') -} - -generate.copyright <- function(pkg) { - # generate copyright file; we trust DESCRIPTION - writeLines(strwrap( - paste('This Debian package of the GNU R package',pkg$name - ,'was generated automatically using cran2deb by' - ,paste(maintainer,'.',sep='') - ,'' - ,'The original GNU R package is Copyright (C) ' - # TODO: copyright start date, true copyright date - ,format(Sys.time(),'%Y') - ,pkg$description[1,'Author'] - ,'and possibly others.' - ,'' - ,'The original GNU R package is maintained by' - ,pkg$description[1,'Maintainer'],'and was obtained from:' - ,'' - ,pkg$repoURL - ,'' - ,'' - ,'The GNU R package DESCRIPTION offers a' - ,'Copyright licenses under the terms of the',pkg$license - ,'license. On a Debian GNU/Linux system, common' - ,'licenses are included in the directory' - ,'/usr/share/common-licenses/.' - ,'' - ,'The DESCRIPTION file for the original GNU R package ' - ,'can be found in ' - ,file.path('/usr/lib/R/site-library' - ,pkg$debname - ,'DESCRIPTION' - ) - ,sep='\n'), width=72), con=pkg$debfile('copyright.in')) -} - -generate.control <- function(pkg) { - # construct control file - control = data.frame() - control[1,'Source'] = pkg$srcname - control[1,'Section'] = 'math' - control[1,'Priority'] = 'optional' - control[1,'Maintainer'] = maintainer - control[1,'Build-Depends'] = paste(pkg$depends$build,collapse=', ') - control[1,'Standards-Version'] = '3.8.0' - - control[2,'Package'] = pkg$debname - control[2,'Architecture'] = 'all' - if (pkg$archdep) { - control[2,'Architecture'] = 'any' - } - control[2,'Depends'] = paste(pkg$depends$bin,collapse=', ') - - # bundles provide virtual packages of their contents - if (pkg$is_bundle) { - control[2,'Provides'] = paste( - lapply(r.bundle.contains(pkg$name) - ,function(name) return(pkgname.as.debian(paste(name) - ,repopref=pkg$repo - ,binary=T))) - ,collapse=', ') - } - - # generate the description - descr = 'GNU R package "' - if ('Title' %in% colnames(pkg$description)) { - descr = paste(descr,pkg$description[1,'Title'],sep='') - } else { - descr = paste(descr,pkg$name,sep='') - } - if (pkg$is_bundle) { - long_descr <- pkg$description[1,'BundleDescription'] - } else { - long_descr <- pkg$description[1,'Description'] - } - # using \n\n.\n\n is not very nice, but is necessary to make sure - # the longer description does not begin on the synopsis line --- R's - # write.dcf does not appear to have a nicer way of doing this. - descr = paste(descr,'"\n\n', long_descr, sep='') - if ('URL' %in% colnames(pkg$description)) { - descr = paste(descr,'\n\nURL: ',pkg$description[1,'URL'],sep='') - } - control[2,'Description'] = descr - - # Debian policy says 72 char width; indent minimally - write.dcf(control,file=pkg$debfile('control.in'),indent=1,width=72) - write.dcf(control,indent=1,width=72) -} - -prepare.new.debian <- function(pkg,extra_deps) { - # generate Debian version and name - pkg$repo = repourl.as.debian(pkg$repoURL) - pkg$debversion = version.new(pkg$version) - if (!length(grep('^[A-Za-z0-9][A-Za-z0-9+.-]+$',pkg$name))) { - stop(paste('Cannot convert package name into a Debian name',pkg$name)) - } - pkg$srcname = tolower(pkg$name) - pkg$debname = pkgname.as.debian(pkg$name,repo=pkg$repo) - - if (!length(grep('\\.tar\\.gz',pkg$archive))) { - stop('archive is not tarball') - } - - # re-pack into a Debian-named archive with a Debian-named directory. - debpath = file.path(dirname(pkg$archive) - ,paste(pkg$srcname,'-' - ,pkg$version - ,sep='')) - file.rename(pkg$path, debpath) - pkg$path = debpath - debarchive = file.path(dirname(pkg$archive) - ,paste(pkg$srcname,'_' - ,pkg$version,'.orig.tar.gz' - ,sep='')) - wd <- getwd() - setwd(dirname(pkg$path)) - # remove them pesky +x files - system(paste('find',shQuote(basename(pkg$path)) - ,'-type f -exec chmod -x {} \\;')) - # tar it all back up - system(paste('tar -czf',shQuote(debarchive),shQuote(basename(pkg$path)))) - setwd(wd) - file.remove(pkg$archive) - pkg$archive = debarchive - - # make the debian/ directory - debdir <- file.path(pkg$path,'debian') - pkg$debfile <- function(x) { file.path(debdir,x) } - unlink(debdir,recursive=T) - dir.create(debdir) - - # see if this is an architecture-dependent package. - # heuristic: if /src/ exists in pkg$path, then this is an - # architecture-dependent package. - # CRAN2DEB.pm is a bit fancier about this but ``Writing R extensions'' - # says: ``The sources and headers for the compiled code are in src, plus - # optionally file Makevars or Makefile.'' It seems unlikely that - # architecture independent code would end up here. - if (pkg$is_bundle) { - # if it's a bundle, check each of the packages - pkg$archdep = F - for (pkgname in r.bundle.contains(pkg$name)) { - pkg$archdep = file.exists(file.path(pkg$path,pkgname,'src')) - if (pkg$archdep) { - break - } - } - } else { - pkg$archdep = file.exists(file.path(pkg$path,'src')) - } - pkg$arch <- 'all' - if (pkg$archdep) { - pkg$arch <- host.arch() - } - - pkg$license <- accept.license(pkg) - pkg$depends <- get.dependencies(pkg,extra_deps) - generate.changelog(pkg) - generate.rules(pkg) - generate.copyright(pkg) - generate.control(pkg) - - # TODO: debian/watch from pkg$repoURL - - # convert text to utf8 (who knows what the original character set is -- - # let's hope iconv DTRT). - for (file in c('control','changelog','copyright')) { - system(paste('iconv -o ',shQuote(pkg$debfile(file)) - ,' -t utf8 ' - ,shQuote(pkg$debfile(paste(file,'in',sep='.'))))) - file.remove(pkg$debfile(paste(file,'in',sep='.'))) - } - return(pkg) -} - -build.debian <- function(pkg) { - wd <- getwd() - setwd(pkg$path) - message(paste('N: building Debian package' - ,pkg$debname - ,paste('(',pkg$debversion,')',sep='') - ,'...')) - ret = system(paste('pdebuild --configfile',pbuilder_config)) - setwd(wd) - if (ret != 0) { - stop('Failed to build package.') - } -} - -changesfile <- function(srcname,version='*') { - return(file.path(pbuilder_results - ,paste(srcname,'_',version,'_' - ,host.arch(),'.changes',sep=''))) -} - -go <- function(name,extra_deps) { - dir <- setup() - pkg <- try((function() { - pkg <- prepare.new.debian(prepare.pkg(dir,name),extra_deps) - if (file.exists(changesfile(pkg$srcname,pkg$debversion))) { - message(paste('N: already built',pkg$srcname,'version',pkg$debversion)) - return(pkg) - } - - # delete the current archive (XXX: assumes mini-dinstall) - for (subdir in c('mini-dinstall','unstable')) { - path = file.path(dinstall_archive,subdir) - if (file.exists(path)) { - unlink(path,recursive=T) - } - } - - # delete notes of upload - file.remove(Sys.glob(file.path(pbuilder_results,'*.upload'))) - - # make mini-dinstall generate the skeleton of the archive - ret = system(paste('umask 022;mini-dinstall --batch -c',dinstall_config)) - if (ret != 0) { - stop('failed to create archive') - } - - # pull in all the R dependencies - message(paste('N: dependencies:',paste(pkg$depends$r,collapse=', '))) - for (dep in pkg$depends$r) { - message(paste('N: uploading',dep)) - ret = system(paste('umask 022;dput','-c',shQuote(dput_config),'local' - ,changesfile(dep))) - if (ret != 0) { - stop('upload of dependency failed! maybe you did not build it first?') - } - } - build.debian(pkg) - - # upload the package - ret = system(paste('umask 022;dput','-c',shQuote(dput_config),'local' - ,changesfile(pkg$srcname,pkg$debversion))) - if (ret != 0) { - stop('upload failed!') - } - - return(pkg) - })()) - cleanup(dir) - if (inherits(pkg,'try-error')) { - stop(call.=F) - } - return(pkg) -} - -if (exists('argv')) { # check for littler - argc <- length(argv) - extra_deps = list() - extra_deps$deb = c() - extra_deps$r = c() - opts = c('-D','-R') - for (i in 1:argc) { - if (!(argv[i] %in% opts)) { - if (argc >= i) { - argv <- argv[i:argc] - } else { - argv <- list() - } - argc = argc - i + 1 - break - } - if (i == argc) { - message('E: missing argument') - q(save='no') - } - if (argv[i] == '-D') { - extra_deps$deb = c(extra_deps$deb,strsplit(chomp(argv[i+1]),',')[[1]]) - } - if (argv[i] == '-R') { - extra_deps$r = c(extra_deps$r,strsplit(chomp(argv[i+1]),',')[[1]]) - extra_deps$deb = c(extra_deps$deb,lapply(extra_deps$r,pkgname.as.debian)) - } - } - if (argc == 0) { - message('E: usage: cran2deb [-D extra_dep1,extra_dep2,...] package package ...') - q(save='no') - } - build_order <- r.dependency.closure(c(extra_deps$r,argv)) - message(paste('N: build order',paste(build_order,collapse=', '))) - for (pkg in build_order) { - go(pkg,extra_deps) - } -} diff --git a/pkg/trunk/cranpkgs b/pkg/trunk/cranpkgs deleted file mode 100755 index 8fbe81f..0000000 --- a/pkg/trunk/cranpkgs +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env r - -root <- '/home/cb/work/gsoc/cran2deb' -# we cache the list of available packages -load(file.path(root,'var/cache/available.cache.Rd')) - -if (length(argv) == 0) { - writeLines(sample(dimnames(available)[[1]],800)) - #writeLines(dimnames(available)[[1]]) -} else { - if (argv[1] == 'query') { - for (ctv in ctv.available) { - writeLines(ctv$name) - } - q(save='no') - } - # list of task lists - for (ctv in ctv.available) { - if (ctv$name %in% argv) { - writeLines(ctv$packagelist$name) - } - } -} diff --git a/pkg/trunk/diagnose b/pkg/trunk/diagnose deleted file mode 100755 index 5f303e7..0000000 --- a/pkg/trunk/diagnose +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/rc - -#success=`{ls var/results/*.deb | wc -l} -#echo $success successful packages -#total=$success -total=0 - -fn count_dup { sort | uniq -c | sort -n}# | awk '$1 > 1{print}' } -fn collapse { a=`{echo $^* | sed -e 's/ | /|/g'}; echo $^a } -echo 'warnings:' -{for (x in (warn/* /dev/null)) cut -d: -f3- <$x | sort -u} | awk '{print $1}' | count_dup -echo - -faildep=('^Error: package ''.*'' could not be loaded' - '|' '^ERROR: lazy loading failed for package ''.*''' - '|' '^[[:space:]]*package .* is not available' - '|' 'there is no package called ''.*''') -faildeb='Unsupported SystemRequirements:' -faillic=('No acceptable license: ') -failspc=': No space left on device' -failhdr='error: .*\.hp?p?: No such file or directory' -faildep=`{collapse $faildep} -faildep=$^faildep -faillic=`{collapse $faillic} -faillic=$^faillic -other='' - -nfaildep=`{grep -El $faildep fail/* /dev/null | wc -l} -echo $nfaildep failed R dependencies. -grep -Eh $faildep fail/* | count_dup -other=$faildep -#total=$total+$nfaildep -echo - -nfaillic=`{grep -El $faillic `{grep -EL $other fail/*} /dev/null | wc -l} -echo $nfaillic failed licenses. -grep -Eh $faillic `{grep -EL $other fail/*} | count_dup -other=$other^'|'^$faillic -total=$total+$nfaillic -echo - -nfailspc=`{grep -El $failspc `{grep -EL $other fail/*} /dev/null | wc -l} -echo $nfailspc out of space -other=$other^'|'^$failspc -total=$total+$nfailspc -echo - -nfailhdr=`{grep -El $failhdr `{grep -EL $other fail/*} /dev/null | wc -l} -echo $nfailhdr missing C header -grep -Eh $failhdr `{grep -EL $other fail/* /dev/null} | count_dup -other=$other^'|'^$failhdr -total=$total+$nfailhdr -echo - -nfaildeb=`{grep -El $faildeb `{grep -EL $other fail/*} /dev/null | wc -l} -echo $nfaildeb system requirement failures. -grep -Eh $faildeb `{grep -EL $other fail/* /dev/null} | count_dup -other=$other^'|'^$faildeb -total=$total+$nfaildeb -echo - -nfailother=`{hoc -e `{grep -EL $other fail/* /dev/null | wc -l}^-1} -echo $nfailother other failures. - -#total=`{hoc -e $total} -#succrate=`{hoc -e $success/'('$total')*100'} -#echo $succrate% success rate '('$total' total)' -#total=`{hoc -e $total-$nfaillic-$nfailspc-$nfailhdr} -#succrate=`{hoc -e $success/'('$total')*100'} -#echo $succrate% success rate without licensing, space and Debian deps issues '('$total' total)' -grep -EL $other fail/* /dev/null | xargs tail -n 20 - diff --git a/pkg/trunk/diagnose_ctv b/pkg/trunk/diagnose_ctv deleted file mode 100755 index 665ff8c..0000000 --- a/pkg/trunk/diagnose_ctv +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env rc -{for (x in ctv/*) {echo;echo;echo $x: ; cd $x && ../../diagnose && cd ../..}} >ctv.results diff --git a/pkg/trunk/etc/dput.cf.in b/pkg/trunk/etc/dput.cf.in deleted file mode 100644 index 7d6b8d2..0000000 --- a/pkg/trunk/etc/dput.cf.in +++ /dev/null @@ -1,8 +0,0 @@ -[local] -method = local -incoming = @ROOT@/var/archive/mini-dinstall/incoming -allow_non-us_software = 1 -run_dinstall = 0 -run_lintian = 1 -post_upload_command = /usr/bin/mini-dinstall --batch -c @ROOT@/etc/mini-dinstall.conf -allow_unsigned_uploads = 1 diff --git a/pkg/trunk/etc/hook/B90lintian b/pkg/trunk/etc/hook/B90lintian deleted file mode 100755 index 57fcfc4..0000000 --- a/pkg/trunk/etc/hook/B90lintian +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# example file to be used with --hookdir -# -# run lintian on generated deb files -apt-get install -y --force-yes lintian -lintian /tmp/buildd/*.deb diff --git a/pkg/trunk/etc/hook/B91dpkg-i b/pkg/trunk/etc/hook/B91dpkg-i deleted file mode 100755 index ee031bb..0000000 --- a/pkg/trunk/etc/hook/B91dpkg-i +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -# example file to be used with --hookdir -# -# try to install the resulting debs. - -echo "Trying to install resulting packages and test upgrades" -set -ex - - -PKGNAMES=$(cd /tmp/buildd && ls -1 *.deb | sed 's/_.*$//' ) - -# install-remove check -dpkg -i /tmp/buildd/*.deb -dpkg --remove $PKGNAMES - -# install-purge check -dpkg -i /tmp/buildd/*.deb -dpkg --purge $PKGNAMES - -# upgrade-remove check -apt-get install -y --force-yes $PKGNAMES || true -dpkg -i /tmp/buildd/*.deb -dpkg --remove $PKGNAMES - -# upgrade-purge check -apt-get install -y --force-yes $PKGNAMES || true -dpkg -i /tmp/buildd/*.deb -dpkg --purge $PKGNAMES diff --git a/pkg/trunk/etc/hook/B92test-pkg b/pkg/trunk/etc/hook/B92test-pkg deleted file mode 100755 index 7372ca0..0000000 --- a/pkg/trunk/etc/hook/B92test-pkg +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -# example file to be used with --hookdir -# -# run tests. Current directory is top of source-code. -# -# 2005, 2007 Junichi Uekawa -# -set -e - -echo "Installing the prerequisites" -for PKG in $(ls /tmp/buildd/*.deb | sed -e's,.*/,,;s,_.*,,' ); do - apt-get install -y --force-yes "$PKG" || true - apt-get remove -y "$PKG" || true -done -# ignore the failures since they are not the prime interest - -dpkg -i /tmp/buildd/*.deb - -if chmod a+x /tmp/buildd/*/debian/pbuilder-test/*; then - : -else - echo "W: no pbuilder-test script found, skipping" - exit 0 -fi - -SUCCESS=0 -COUNT=0 -unset FAIL || true -NOFAIL=1 - -# The current directory is the top of the source-tree. -cd /tmp/buildd/*/debian/.. - -for SCRIPT in $(run-parts --test /tmp/buildd/*/debian/pbuilder-test) ; do - echo "--- BEGIN test: ${SCRIPT##*/}" - if "${SCRIPT}"; then - echo SUCCESS - ((SUCCESS=SUCCESS+1)) - else - echo FAIL - FAIL[${#FAIL[@]}]="${SCRIPT##*/}" - NOFAIL=0 - fi - echo "--- END test: ${SCRIPT##*/}" - ((COUNT=COUNT+1)) -done - -echo "Summary:" -echo "=== $SUCCESS out of $COUNT tests passed" -echo "${FAIL[@]/#/ failed }" -echo "-- end of testsuite." - diff --git a/pkg/trunk/etc/hook/D70aptupdate b/pkg/trunk/etc/hook/D70aptupdate deleted file mode 100755 index 4d42b3d..0000000 --- a/pkg/trunk/etc/hook/D70aptupdate +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/apt-get update diff --git a/pkg/trunk/etc/mini-dinstall.conf.in b/pkg/trunk/etc/mini-dinstall.conf.in deleted file mode 100644 index b75f1d7..0000000 --- a/pkg/trunk/etc/mini-dinstall.conf.in +++ /dev/null @@ -1,12 +0,0 @@ -[DEFAULT] -architectures = all, i386 -use_dnotify = 0 -verify_sigs = 0 -mail_on_success = 0 -archive_style = simple-subdir -mail_log_level = NONE -archivedir = @ROOT@/var/archive -logfile = @ROOT@/var/mini-dinstall.log - -[unstable] - diff --git a/pkg/trunk/etc/pbuilderrc.in b/pkg/trunk/etc/pbuilderrc.in deleted file mode 100644 index 1f99b77..0000000 --- a/pkg/trunk/etc/pbuilderrc.in +++ /dev/null @@ -1,8 +0,0 @@ -HOOKDIR=@ROOT@/etc/hook -BUILDRESULT=@ROOT@/var/results -EXTRAPACKAGES='debhelper r-base-dev cdbs r-base-core lintian xauth xfont-base xvfb' -DISTRIBUTION=lenny -OTHERMIRROR='deb http://localhost/users/cb/cran2deb/ unstable/$(ARCH)/ | deb http://localhost/users/cb/cran2deb/ unstable/all/' -MIRRORSITE='http://ftp.debian.org/debian/' -APTCACHE='' -PBUILDERSATISFYDEPENDSCMD='/usr/lib/pbuilder/pbuilder-satisfydepends-classic' diff --git a/pkg/trunk/exec/build_ctv b/pkg/trunk/exec/build_ctv new file mode 100755 index 0000000..754dd58 --- /dev/null +++ b/pkg/trunk/exec/build_ctv @@ -0,0 +1,11 @@ +#!/usr/bin/env rc + +for (ctv in `{./cranpkgs query}) { + echo task view $ctv... + if (![ -e ctv/$ctv ]) { + ./build_some $ctv + mkdir -p ctv/$ctv + mv warn fail ctv/$ctv + } +} + diff --git a/pkg/trunk/exec/build_some b/pkg/trunk/exec/build_some new file mode 100755 index 0000000..dd12c2d --- /dev/null +++ b/pkg/trunk/exec/build_some @@ -0,0 +1,20 @@ +#!/usr/bin/rc + +mkdir -p warn fail +./cranpkgs $* >all_pkgs +for (pkg in `{cat all_pkgs}) { + if (~ $pkg *..* */*) { + echo bad name $pkg >>fail/ERROR + } else { + echo .. package $pkg + fail=0 + ./cran2deb $pkg >fail/$pkg >[2=1] || fail=1 + if (~ $fail 0) { + grep '^[WE]:' fail/$pkg >warn/$pkg + if (~ `{stat -c '%s' warn/$pkg} 0) { + rm -f warn/$pkg + } + rm -f fail/$pkg + } + } +} diff --git a/pkg/trunk/exec/copy_find b/pkg/trunk/exec/copy_find new file mode 100755 index 0000000..fe3d619 --- /dev/null +++ b/pkg/trunk/exec/copy_find @@ -0,0 +1,30 @@ +#!/usr/bin/rc +kwords='copyright|warranty|redistribution|modification|patent|trademark|licen[cs]e|permission' +nl=`` () {printf '\n'} +ifs=$nl { + files=`{find $1 ! -path '*debian*' -type f} + lines=() + for (file in $files) { + notices=`{grep -H '(C)' $file} + notices=($notices `{grep -HEi $kwords $file}) + lines=($lines `{{for (notice in $notices) echo $notice} | sort -u}) + } + # let's hope no file has a : in it + ifs=() { seen_files=`{{for (line in $lines) echo $line} | cut -d: -f1} } + missing_copyright=() + for (file in $files) { + if (echo -n $seen_files | grep -q '^'^$file^'$') { + } else { + missing_copyright=($missing_copyright $file) + } + } + echo 'Suspect copyright notices:' + for (line in $lines) echo ' '$line + echo 'Files without *suspect* copyright notices:' + for (missing in $missing_copyright) { + echo ' '$missing + echo ' type: '`{file $missing} + echo ' chars: '`{wc -c $missing | awk '{print $1}'} + echo ' lines: '`{wc -l $missing | awk '{print $1}'} + } +} diff --git a/pkg/trunk/exec/cran2deb b/pkg/trunk/exec/cran2deb new file mode 100755 index 0000000..fc6c45c --- /dev/null +++ b/pkg/trunk/exec/cran2deb @@ -0,0 +1,94 @@ +#!/usr/bin/env r +library(cran2deb) +go <- function(name,extra_deps) { + dir <- setup() + pkg <- try((function() { + pkg <- prepare.new.debian(prepare.pkg(dir,name),extra_deps) + if (file.exists(changesfile(pkg$srcname,pkg$debversion))) { + message(paste('N: already built',pkg$srcname,'version',pkg$debversion)) + return(pkg) + } + + # delete the current archive (XXX: assumes mini-dinstall) + for (subdir in c('mini-dinstall','unstable')) { + path = file.path(dinstall_archive,subdir) + if (file.exists(path)) { + unlink(path,recursive=T) + } + } + + # delete notes of upload + file.remove(Sys.glob(file.path(pbuilder_results,'*.upload'))) + + # make mini-dinstall generate the skeleton of the archive + ret = system(paste('umask 022;mini-dinstall --batch -c',dinstall_config)) + if (ret != 0) { + stop('failed to create archive') + } + + # pull in all the R dependencies + message(paste('N: dependencies:',paste(pkg$depends$r,collapse=', '))) + for (dep in pkg$depends$r) { + message(paste('N: uploading',dep)) + ret = system(paste('umask 022;dput','-c',shQuote(dput_config),'local' + ,changesfile(dep))) + if (ret != 0) { + stop('upload of dependency failed! maybe you did not build it first?') + } + } + build.debian(pkg) + + # upload the package + ret = system(paste('umask 022;dput','-c',shQuote(dput_config),'local' + ,changesfile(pkg$srcname,pkg$debversion))) + if (ret != 0) { + stop('upload failed!') + } + + return(pkg) + })()) + cleanup(dir) + if (inherits(pkg,'try-error')) { + stop(call.=F) + } + return(pkg) +} + +if (exists('argv')) { # check for littler + argc <- length(argv) + extra_deps = list() + extra_deps$deb = c() + extra_deps$r = c() + opts = c('-D','-R') + for (i in 1:argc) { + if (!(argv[i] %in% opts)) { + if (argc >= i) { + argv <- argv[i:argc] + } else { + argv <- list() + } + argc = argc - i + 1 + break + } + if (i == argc) { + message('E: missing argument') + q(save='no') + } + if (argv[i] == '-D') { + extra_deps$deb = c(extra_deps$deb,strsplit(chomp(argv[i+1]),',')[[1]]) + } + if (argv[i] == '-R') { + extra_deps$r = c(extra_deps$r,strsplit(chomp(argv[i+1]),',')[[1]]) + extra_deps$deb = c(extra_deps$deb,lapply(extra_deps$r,pkgname.as.debian)) + } + } + if (argc == 0) { + message('E: usage: cran2deb [-D extra_dep1,extra_dep2,...] package package ...') + q(save='no') + } + build_order <- r.dependency.closure(c(extra_deps$r,argv)) + message(paste('N: build order',paste(build_order,collapse=', '))) + for (pkg in build_order) { + go(pkg,extra_deps) + } +} diff --git a/pkg/trunk/exec/cranpkgs b/pkg/trunk/exec/cranpkgs new file mode 100755 index 0000000..ba9e727 --- /dev/null +++ b/pkg/trunk/exec/cranpkgs @@ -0,0 +1,21 @@ +#!/usr/bin/env r + +library(cran2deb) + +if (length(argv) == 0) { + writeLines(sample(dimnames(available)[[1]],800)) + #writeLines(dimnames(available)[[1]]) +} else { + if (argv[1] == 'query') { + for (ctv in ctv.available) { + writeLines(ctv$name) + } + q(save='no') + } + # list of task lists + for (ctv in ctv.available) { + if (ctv$name %in% argv) { + writeLines(ctv$packagelist$name) + } + } +} diff --git a/pkg/trunk/exec/diagnose b/pkg/trunk/exec/diagnose new file mode 100755 index 0000000..5f303e7 --- /dev/null +++ b/pkg/trunk/exec/diagnose @@ -0,0 +1,72 @@ +#!/usr/bin/rc + +#success=`{ls var/results/*.deb | wc -l} +#echo $success successful packages +#total=$success +total=0 + +fn count_dup { sort | uniq -c | sort -n}# | awk '$1 > 1{print}' } +fn collapse { a=`{echo $^* | sed -e 's/ | /|/g'}; echo $^a } +echo 'warnings:' +{for (x in (warn/* /dev/null)) cut -d: -f3- <$x | sort -u} | awk '{print $1}' | count_dup +echo + +faildep=('^Error: package ''.*'' could not be loaded' + '|' '^ERROR: lazy loading failed for package ''.*''' + '|' '^[[:space:]]*package .* is not available' + '|' 'there is no package called ''.*''') +faildeb='Unsupported SystemRequirements:' +faillic=('No acceptable license: ') +failspc=': No space left on device' +failhdr='error: .*\.hp?p?: No such file or directory' +faildep=`{collapse $faildep} +faildep=$^faildep +faillic=`{collapse $faillic} +faillic=$^faillic +other='' + +nfaildep=`{grep -El $faildep fail/* /dev/null | wc -l} +echo $nfaildep failed R dependencies. +grep -Eh $faildep fail/* | count_dup +other=$faildep +#total=$total+$nfaildep +echo + +nfaillic=`{grep -El $faillic `{grep -EL $other fail/*} /dev/null | wc -l} +echo $nfaillic failed licenses. +grep -Eh $faillic `{grep -EL $other fail/*} | count_dup +other=$other^'|'^$faillic +total=$total+$nfaillic +echo + +nfailspc=`{grep -El $failspc `{grep -EL $other fail/*} /dev/null | wc -l} +echo $nfailspc out of space +other=$other^'|'^$failspc +total=$total+$nfailspc +echo + +nfailhdr=`{grep -El $failhdr `{grep -EL $other fail/*} /dev/null | wc -l} +echo $nfailhdr missing C header +grep -Eh $failhdr `{grep -EL $other fail/* /dev/null} | count_dup +other=$other^'|'^$failhdr +total=$total+$nfailhdr +echo + +nfaildeb=`{grep -El $faildeb `{grep -EL $other fail/*} /dev/null | wc -l} +echo $nfaildeb system requirement failures. +grep -Eh $faildeb `{grep -EL $other fail/* /dev/null} | count_dup +other=$other^'|'^$faildeb +total=$total+$nfaildeb +echo + +nfailother=`{hoc -e `{grep -EL $other fail/* /dev/null | wc -l}^-1} +echo $nfailother other failures. + +#total=`{hoc -e $total} +#succrate=`{hoc -e $success/'('$total')*100'} +#echo $succrate% success rate '('$total' total)' +#total=`{hoc -e $total-$nfaillic-$nfailspc-$nfailhdr} +#succrate=`{hoc -e $success/'('$total')*100'} +#echo $succrate% success rate without licensing, space and Debian deps issues '('$total' total)' +grep -EL $other fail/* /dev/null | xargs tail -n 20 + diff --git a/pkg/trunk/exec/diagnose_ctv b/pkg/trunk/exec/diagnose_ctv new file mode 100755 index 0000000..665ff8c --- /dev/null +++ b/pkg/trunk/exec/diagnose_ctv @@ -0,0 +1,2 @@ +#!/usr/bin/env rc +{for (x in ctv/*) {echo;echo;echo $x: ; cd $x && ../../diagnose && cd ../..}} >ctv.results diff --git a/pkg/trunk/exec/setup b/pkg/trunk/exec/setup new file mode 100755 index 0000000..011bd12 --- /dev/null +++ b/pkg/trunk/exec/setup @@ -0,0 +1,19 @@ +#!/usr/bin/rc +umask 022 +root=`{r -e 'library(cran2deb);cat(system.file('''',package=''cran2deb''),file=stdout())'} +for (x in `{find etc -type f -name '*.in'}) { + y=`{echo $x | sed -e 's,.in$,,'} + sed -e 's:@ROOT@:'^$root^':g' <$x >$y +} +mkdir -p var/results +if ([ ! -e var/archive ]) { + # I symbolically link this into /var/www/ + mkdir var/archive +} +mini-dinstall --batch -c $root/etc/mini-dinstall.conf || exit 1 +mode=create +if ([ -e /var/cache/pbuilder/base.tgz ]) { + mode=update +} +sudo pbuilder $mode --override-config --configfile $root/etc/pbuilderrc +./update_available diff --git a/pkg/trunk/exec/update_available b/pkg/trunk/exec/update_available new file mode 100755 index 0000000..11df8b0 --- /dev/null +++ b/pkg/trunk/exec/update_available @@ -0,0 +1,11 @@ +#!/usr/bin/env r +#mirror <- 'http://cran.uk.r-project.org/' +mirror <- 'http://cran.r-project.org/' +message('updating list of available R packages...') +available <- available.packages(contrib.url(mirror)) +available <- rbind(available,available.packages(contrib.url('http://www.bioconductor.org/'))) +message('updating list of available R task views...') +library(ctv) +ctv.available <- available.views(repo=mirror) +library(cran2deb) +save(available, ctv.available, file=system.file('R/sysdata.rda',package='cran2deb'),eval.promises=T) diff --git a/pkg/trunk/inst/etc/dput.cf.in b/pkg/trunk/inst/etc/dput.cf.in new file mode 100644 index 0000000..7d6b8d2 --- /dev/null +++ b/pkg/trunk/inst/etc/dput.cf.in @@ -0,0 +1,8 @@ +[local] +method = local +incoming = @ROOT@/var/archive/mini-dinstall/incoming +allow_non-us_software = 1 +run_dinstall = 0 +run_lintian = 1 +post_upload_command = /usr/bin/mini-dinstall --batch -c @ROOT@/etc/mini-dinstall.conf +allow_unsigned_uploads = 1 diff --git a/pkg/trunk/inst/etc/hook/B90lintian b/pkg/trunk/inst/etc/hook/B90lintian new file mode 100755 index 0000000..57fcfc4 --- /dev/null +++ b/pkg/trunk/inst/etc/hook/B90lintian @@ -0,0 +1,6 @@ +#!/bin/bash +# example file to be used with --hookdir +# +# run lintian on generated deb files +apt-get install -y --force-yes lintian +lintian /tmp/buildd/*.deb diff --git a/pkg/trunk/inst/etc/hook/B91dpkg-i b/pkg/trunk/inst/etc/hook/B91dpkg-i new file mode 100755 index 0000000..ee031bb --- /dev/null +++ b/pkg/trunk/inst/etc/hook/B91dpkg-i @@ -0,0 +1,28 @@ +#!/bin/bash +# example file to be used with --hookdir +# +# try to install the resulting debs. + +echo "Trying to install resulting packages and test upgrades" +set -ex + + +PKGNAMES=$(cd /tmp/buildd && ls -1 *.deb | sed 's/_.*$//' ) + +# install-remove check +dpkg -i /tmp/buildd/*.deb +dpkg --remove $PKGNAMES + +# install-purge check +dpkg -i /tmp/buildd/*.deb +dpkg --purge $PKGNAMES + +# upgrade-remove check +apt-get install -y --force-yes $PKGNAMES || true +dpkg -i /tmp/buildd/*.deb +dpkg --remove $PKGNAMES + +# upgrade-purge check +apt-get install -y --force-yes $PKGNAMES || true +dpkg -i /tmp/buildd/*.deb +dpkg --purge $PKGNAMES diff --git a/pkg/trunk/inst/etc/hook/B92test-pkg b/pkg/trunk/inst/etc/hook/B92test-pkg new file mode 100755 index 0000000..7372ca0 --- /dev/null +++ b/pkg/trunk/inst/etc/hook/B92test-pkg @@ -0,0 +1,52 @@ +#!/bin/bash +# example file to be used with --hookdir +# +# run tests. Current directory is top of source-code. +# +# 2005, 2007 Junichi Uekawa +# +set -e + +echo "Installing the prerequisites" +for PKG in $(ls /tmp/buildd/*.deb | sed -e's,.*/,,;s,_.*,,' ); do + apt-get install -y --force-yes "$PKG" || true + apt-get remove -y "$PKG" || true +done +# ignore the failures since they are not the prime interest + +dpkg -i /tmp/buildd/*.deb + +if chmod a+x /tmp/buildd/*/debian/pbuilder-test/*; then + : +else + echo "W: no pbuilder-test script found, skipping" + exit 0 +fi + +SUCCESS=0 +COUNT=0 +unset FAIL || true +NOFAIL=1 + +# The current directory is the top of the source-tree. +cd /tmp/buildd/*/debian/.. + +for SCRIPT in $(run-parts --test /tmp/buildd/*/debian/pbuilder-test) ; do + echo "--- BEGIN test: ${SCRIPT##*/}" + if "${SCRIPT}"; then + echo SUCCESS + ((SUCCESS=SUCCESS+1)) + else + echo FAIL + FAIL[${#FAIL[@]}]="${SCRIPT##*/}" + NOFAIL=0 + fi + echo "--- END test: ${SCRIPT##*/}" + ((COUNT=COUNT+1)) +done + +echo "Summary:" +echo "=== $SUCCESS out of $COUNT tests passed" +echo "${FAIL[@]/#/ failed }" +echo "-- end of testsuite." + diff --git a/pkg/trunk/inst/etc/hook/D70aptupdate b/pkg/trunk/inst/etc/hook/D70aptupdate new file mode 100755 index 0000000..4d42b3d --- /dev/null +++ b/pkg/trunk/inst/etc/hook/D70aptupdate @@ -0,0 +1 @@ +/usr/bin/apt-get update diff --git a/pkg/trunk/inst/etc/mini-dinstall.conf.in b/pkg/trunk/inst/etc/mini-dinstall.conf.in new file mode 100644 index 0000000..b75f1d7 --- /dev/null +++ b/pkg/trunk/inst/etc/mini-dinstall.conf.in @@ -0,0 +1,12 @@ +[DEFAULT] +architectures = all, i386 +use_dnotify = 0 +verify_sigs = 0 +mail_on_success = 0 +archive_style = simple-subdir +mail_log_level = NONE +archivedir = @ROOT@/var/archive +logfile = @ROOT@/var/mini-dinstall.log + +[unstable] + diff --git a/pkg/trunk/inst/etc/pbuilderrc.in b/pkg/trunk/inst/etc/pbuilderrc.in new file mode 100644 index 0000000..1f99b77 --- /dev/null +++ b/pkg/trunk/inst/etc/pbuilderrc.in @@ -0,0 +1,8 @@ +HOOKDIR=@ROOT@/etc/hook +BUILDRESULT=@ROOT@/var/results +EXTRAPACKAGES='debhelper r-base-dev cdbs r-base-core lintian xauth xfont-base xvfb' +DISTRIBUTION=lenny +OTHERMIRROR='deb http://localhost/users/cb/cran2deb/ unstable/$(ARCH)/ | deb http://localhost/users/cb/cran2deb/ unstable/all/' +MIRRORSITE='http://ftp.debian.org/debian/' +APTCACHE='' +PBUILDERSATISFYDEPENDSCMD='/usr/lib/pbuilder/pbuilder-satisfydepends-classic' diff --git a/pkg/trunk/setup b/pkg/trunk/setup deleted file mode 100755 index 03e441e..0000000 --- a/pkg/trunk/setup +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/rc -umask 022 -root=`pwd -for (x in `{find etc -type f -name '*.in'}) { - y=`{echo $x | sed -e 's,.in$,,'} - sed -e 's:@ROOT@:'^$root^':g' <$x >$y -} -mkdir -p var/results -if ([ ! -e var/archive ]) { - # I symbolically link this into /var/www/ - mkdir var/archive -} -mini-dinstall --batch -c $root/etc/mini-dinstall.conf || exit 1 -mode=create -if ([ -e /var/cache/pbuilder/base.tgz ]) { - mode=update -} -sudo pbuilder $mode --override-config --configfile $root/etc/pbuilderrc -./update_available diff --git a/pkg/trunk/update_available b/pkg/trunk/update_available deleted file mode 100755 index cc99376..0000000 --- a/pkg/trunk/update_available +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env r -#mirror <- 'http://cran.uk.r-project.org/' -mirror <- 'http://cran.r-project.org/' -message('updating list of available R packages...') -available <- available.packages(contrib.url(mirror)) -available <- rbind(available,available.packages(contrib.url('http://www.bioconductor.org/'))) -message('updating list of available R task views...') -library(ctv) -ctv.available <- available.views(repo=mirror) -save(available, ctv.available, file='var/cache/available.cache.Rd',eval.promises=T)