From: blundellc Date: Sat, 13 Sep 2008 15:56:25 +0000 (+0000) Subject: multisys: support for multiple os-arch configurations (preliminary) X-Git-Url: https://git.donarmstrong.com/?p=cran2deb.git;a=commitdiff_plain;h=413d9e15b7bd5f8f36685c2cccbb9bbed3a3a0b9 multisys: support for multiple os-arch configurations (preliminary) git-svn-id: svn://svn.r-forge.r-project.org/svnroot/cran2deb@152 edb9625f-4e0d-4859-8d74-9fd3b1da38cb --- diff --git a/branch/multisys/DESCRIPTION b/branch/multisys/DESCRIPTION new file mode 100644 index 0000000..d591695 --- /dev/null +++ b/branch/multisys/DESCRIPTION @@ -0,0 +1,11 @@ +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, RSQLite, DBI, digest +SystemRequirements: littler, rc, pbuilder, debian toolchain, web server, mini-dinstall, curl +Description: Convert CRAN packages into Debian packages, mostly unassisted, easily + subverting the R package system. +License: GPL-3 diff --git a/branch/multisys/R/build.R b/branch/multisys/R/build.R new file mode 100644 index 0000000..4ca1923 --- /dev/null +++ b/branch/multisys/R/build.R @@ -0,0 +1,149 @@ + +build <- function(name,extra_deps,force=F) { + # can't, and hence don't need to, build base packages + if (name %in% base_pkgs) { + return(T) + } + log_clear() + dir <- setup() + + # obtain the Debian version-to-be + version <- try(new_build_version(name)) + if (inherits(version,'try-error')) { + error('failed to build',name) + return(NULL) + } + + result <- try((function() { + if (!force && !needs_build(name,version)) { + notice('skipping build of',name) + return(NULL) + } + + pkg <- prepare_new_debian(prepare_pkg(dir,name),extra_deps) + if (pkg$debversion != version) { + fail('expected Debian version',version,'not equal to actual version',pkg$debversion) + } + # 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 = log_system('umask 002;mini-dinstall --batch -c',dinstall_config) + if (ret != 0) { + fail('failed to create archive') + } + + # pull in all the R dependencies + notice('R dependencies:',paste(pkg$depends$r,collapse=', ')) + for (dep in pkg$depends$r) { + if (pkgname_as_debian(dep) %in% debian_pkgs) { + notice('using Debian package of',dep) + next + } + # otherwise, convert to source package name + srcdep = pkgname_as_debian(dep,binary=F) + + notice('uploading',srcdep) + ret = log_system('umask 002;dput','-c',shQuote(dput_config),'local' + ,changesfile(srcdep)) + if (ret != 0) { + fail('upload of dependency failed! maybe you did not build it first?') + } + } + build_debian(pkg) + + # upload the package + ret = log_system('umask 002;dput','-c',shQuote(dput_config),'local' + ,changesfile(pkg$srcname,pkg$debversion)) + if (ret != 0) { + fail('upload failed!') + } + + # delete the current archive (XXX: assumes mini-dinstall) + # this is handy for group operation + for (subdir in c('mini-dinstall','unstable')) { + path = file.path(dinstall_archive,subdir) + if (file.exists(path)) { + unlink(path,recursive=T) + } + } + + return(pkg$debversion) + })()) + cleanup(dir) + if (is.null(result)) { + # nothing was done so escape asap. + return(result) + } + + # otherwise record progress + failed = inherits(result,'try-error') + if (failed) { + error('failure of',name,'means these packages will fail:' + ,paste(r_dependency_closure(name,forward_arcs=F),collapse=', ')) + } + db_record_build(name, version, log_retrieve(), !failed) + return(!failed) +} + +needs_build <- function(name,version) { + # see if the last build was successful + build <- db_latest_build(name) + if (!is.null(build) && build$success) { + # then something must have changed for us to attempt this + # build + if (build$r_version == version_upstream(version) && + build$deb_epoch == version_epoch(version) && + build$db_version == db_get_version()) { + return(F) + } + } else { + # always rebuild on failure or no record + return(T) + } + # see if it has already been built + srcname <- pkgname_as_debian(name,binary=F) + debname <- pkgname_as_debian(name,binary=T) + if (file.exists(changesfile(srcname, version))) { + notice('already built',srcname,'version',version) + return(F) + } + + # XXX: what about building newer versions of Debian packages? + if (debname %in% debian_pkgs) { + notice(srcname,' exists in Debian (perhaps a different version)') + return(F) + } + + rm(debname,srcname) + return(T) +} + +build_debian <- function(pkg) { + wd <- getwd() + setwd(pkg$path) + notice('building Debian package' + ,pkg$debname + ,paste('(',pkg$debversion,')',sep='') + ,'...') + + cmd = paste('pdebuild --configfile',shQuote(pbuilder_config)) + if (version_revision(pkg$debversion) > 2) { + cmd = paste(cmd,'--debbuildopts','-sd') + notice('build should exclude original source') + } + ret = log_system(cmd) + setwd(wd) + if (ret != 0) { + fail('Failed to build package.') + } +} + diff --git a/branch/multisys/R/db.R b/branch/multisys/R/db.R new file mode 100644 index 0000000..5c9836d --- /dev/null +++ b/branch/multisys/R/db.R @@ -0,0 +1,374 @@ + +db_start <- function() { + drv <- dbDriver('SQLite') + con <- dbConnect(drv, dbname=file.path(cache_root,'cran2deb.db')) + if (!dbExistsTable(con,'sysreq_override')) { + dbGetQuery(con,paste('CREATE TABLE sysreq_override (' + ,' depend_alias TEXT NOT NULL' + ,',r_pattern TEXT PRIMARY KEY NOT NULL' + ,')')) + } + if (!dbExistsTable(con,'debian_dependency')) { + dbGetQuery(con,paste('CREATE TABLE debian_dependency (' + ,' id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL' + ,',alias TEXT NOT NULL' + ,',build INTEGER NOT NULL' + ,',debian_pkg TEXT NOT NULL' + ,',UNIQUE (alias,build,debian_pkg)' + ,')')) + } + if (!dbExistsTable(con,'forced_depends')) { + dbGetQuery(con,paste('CREATE TABLE forced_depends (' + ,' r_name TEXT NOT NULL' + ,',depend_alias TEXT NOT NULL' + ,',PRIMARY KEY (r_name,depend_alias)' + ,')')) + } + if (!dbExistsTable(con,'license_override')) { + dbGetQuery(con,paste('CREATE TABLE license_override (' + ,' name TEXT PRIMARY KEY NOT NULL' + ,',accept INT NOT NULL' + ,')')) + } + if (!dbExistsTable(con,'license_hashes')) { + dbGetQuery(con,paste('CREATE TABLE license_hashes (' + ,' name TEXT NOT NULL' + ,',sha1 TEXT PRIMARY KEY NOT NULL' + ,')')) + } + if (!dbExistsTable(con,'database_versions')) { + dbGetQuery(con,paste('CREATE TABLE database_versions (' + ,' version INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL' + ,',version_date INTEGER NOT NULL' + ,',base_epoch INTEGER NOT NULL' + ,')')) + db_add_version(con,1,0) + } + if (!dbExistsTable(con,'packages')) { + dbGetQuery(con,paste('CREATE TABLE packages (' + ,' package TEXT PRIMARY KEY NOT NULL' + ,',latest_r_version TEXT' + ,')')) + } + if (!dbExistsTable(con,'builds')) { + dbGetQuery(con,paste('CREATE TABLE builds (' + ,' id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL' + ,',package TEXT NOT NULL' + ,',r_version TEXT NOT NULL' + ,',deb_epoch INTEGER NOT NULL' + ,',deb_revision INTEGER NOT NULL' + ,',db_version INTEGER NOT NULL' + ,',date_stamp TEXT NOT NULL' + ,',git_revision TEXT NOT NULL' # legacy: really scm_revision + ,',success INTEGER NOT NULL' + ,',log TEXT' + ,',UNIQUE(package,r_version,deb_epoch,deb_revision,db_version)' + ,')')) + } + return(con) +} + +db_stop <- function(con,bump=F) { + if (bump) { + db_bump(con) + } + dbDisconnect(con) +} + +db_quote <- function(text) { + return(paste('\'', gsub('([\'"])','\\1\\1',text),'\'',sep='')) +} + +db_now <- function() { + return(as.integer(gsub('-','',Sys.Date()))) +} + +db_cur_version <- function(con) { + return(as.integer(dbGetQuery(con, 'SELECT max(version) FROM database_versions')[[1]])) +} + +db_base_epoch <- function(con) { + return(as.integer(dbGetQuery(con, + paste('SELECT max(base_epoch) FROM database_versions' + ,'WHERE version IN (SELECT max(version) FROM database_versions)'))[[1]])) +} + +db_get_base_epoch <- function() { + con <- db_start() + v <- db_base_epoch(con) + db_stop(con) + return(v) +} + +db_get_version <- function() { + con <- db_start() + v <- db_cur_version(con) + db_stop(con) + return(v) +} + +db_add_version <- function(con, version, epoch) { + dbGetQuery(con,paste('INSERT INTO database_versions (version,version_date,base_epoch)' + ,'VALUES (',as.integer(version),',',db_now(),',',as.integer(epoch),')')) +} + +db_bump <- function(con) { + db_add_version(con,db_cur_version(con)+1, db_base_epoch(con)) +} + +db_bump_epoch <- function(con) { + db_add_version(con,db_cur_version(con)+1, db_base_epoch(con)+1) +} + +db_sysreq_override <- function(sysreq_text) { + con <- db_start() + results <- dbGetQuery(con,paste( + 'SELECT DISTINCT depend_alias FROM sysreq_override WHERE' + ,db_quote(tolower(sysreq_text)),'LIKE r_pattern')) + db_stop(con) + if (length(results) == 0) { + return(NULL) + } + return(results$depend_alias) +} + +db_add_sysreq_override <- function(pattern,depend_alias) { + con <- db_start() + results <- dbGetQuery(con,paste( + 'INSERT OR REPLACE INTO sysreq_override' + ,'(depend_alias, r_pattern) VALUES (' + ,' ',db_quote(tolower(depend_alias)) + ,',',db_quote(tolower(pattern)) + ,')')) + db_stop(con,TRUE) +} + +db_sysreq_overrides <- function() { + con <- db_start() + overrides <- dbGetQuery(con,paste('SELECT * FROM sysreq_override')) + db_stop(con) + return(overrides) +} + +db_get_depends <- function(depend_alias,build=F) { + con <- db_start() + results <- dbGetQuery(con,paste( + 'SELECT DISTINCT debian_pkg FROM debian_dependency WHERE' + ,db_quote(tolower(depend_alias)),'= alias' + ,'AND',as.integer(build),'= build')) + db_stop(con) + return(results$debian_pkg) +} + +db_add_depends <- function(depend_alias,debian_pkg,build=F) { + con <- db_start() + results <- dbGetQuery(con,paste( + 'INSERT OR REPLACE INTO debian_dependency' + ,'(alias, build, debian_pkg) VALUES (' + ,' ',db_quote(tolower(depend_alias)) + ,',',as.integer(build) + ,',',db_quote(tolower(debian_pkg)) + ,')')) + db_stop(con,TRUE) +} + +db_depends <- function() { + con <- db_start() + depends <- dbGetQuery(con,paste('SELECT * FROM debian_dependency')) + db_stop(con) + return(depends) +} + +db_get_forced_depends <- function(r_name) { + con <- db_start() + forced_depends <- dbGetQuery(con, + paste('SELECT depend_alias FROM forced_depends WHERE' + ,db_quote(r_name),'= r_name')) + db_stop(con) + return(forced_depends$depend_alias) +} + +db_add_forced_depends <- function(r_name, depend_alias) { + if (!length(db_get_depends(depend_alias,build=F)) && + !length(db_get_depends(depend_alias,build=T))) { + fail('Debian dependency alias',depend_alias,'is not know,' + ,'yet trying to force a dependency on it?') + } + con <- db_start() + dbGetQuery(con, + paste('INSERT OR REPLACE INTO forced_depends (r_name, depend_alias)' + ,'VALUES (',db_quote(r_name),',',db_quote(depend_alias),')')) + db_stop(con,TRUE) +} + +db_forced_depends <- function() { + con <- db_start() + depends <- dbGetQuery(con,paste('SELECT * FROM forced_depends')) + db_stop(con) + return(depends) +} + +db_license_override_name <- function(name) { + con <- db_start() + results <- dbGetQuery(con,paste( + 'SELECT DISTINCT accept FROM license_override WHERE' + ,db_quote(tolower(name)),'= name')) + db_stop(con) + if (length(results) == 0) { + return(NULL) + } + return(as.logical(results$accept)) +} + +db_add_license_override <- function(name,accept) { + notice('adding',name,'accept?',accept) + if (accept != TRUE && accept != FALSE) { + fail('accept must be TRUE or FALSE') + } + con <- db_start() + results <- dbGetQuery(con,paste( + 'INSERT OR REPLACE INTO license_override' + ,'(name, accept) VALUES (' + ,' ',db_quote(tolower(name)) + ,',',as.integer(accept) + ,')')) + db_stop(con,TRUE) +} + +db_license_override_hash <- function(license_sha1) { + con <- db_start() + results <- dbGetQuery(con,paste( + 'SELECT DISTINCT accept FROM license_override' + ,'INNER JOIN license_hashes' + ,'ON license_hashes.name = license_override.name WHERE' + ,db_quote(tolower(license_sha1)),'= license_hashes.sha1')) + db_stop(con) + if (length(results) == 0) { + return(NULL) + } + return(as.logical(results$accept)) +} + +db_license_overrides <- function() { + con <- db_start() + overrides <- dbGetQuery(con,paste('SELECT * FROM license_override')) + hashes <- dbGetQuery(con,paste('SELECT * FROM license_hashes')) + db_stop(con) + return(list(overrides=overrides,hashes=hashes)) +} + +db_add_license_hash <- function(name,license_sha1) { + if (is.null(db_license_override_name(name))) { + fail('license',name,'is not know, yet trying to add a hash for it?') + } + notice('adding hash',license_sha1,'for',name) + con <- db_start() + dbGetQuery(con,paste( + 'INSERT OR REPLACE INTO license_hashes' + ,'(name, sha1) VALUES (' + ,' ',db_quote(tolower(name)) + ,',',db_quote(tolower(license_sha1)) + ,')')) + db_stop(con,TRUE) +} + + +db_update_package_versions <- function() { + con <- db_start() + for (package in available[,'Package']) { + dbGetQuery(con, paste('INSERT OR REPLACE INTO packages (package,latest_r_version)' + ,'VALUES (',db_quote(package) + ,',',db_quote(available[package,'Version']),')')) + } + db_stop(con) +} + +db_record_build <- function(package, deb_version, log, success=F) { + con <- db_start() + dbGetQuery(con,paste('INSERT OR REPLACE INTO builds' + ,'(package,r_version,deb_epoch,deb_revision,db_version,success,date_stamp,git_revision,log)' + ,'VALUES' + ,'(',db_quote(package) + ,',',db_quote(version_upstream(deb_version)) + ,',',db_quote(version_epoch(deb_version)) + ,',',db_quote(version_revision(deb_version)) + ,',',db_cur_version(con) + ,',',as.integer(success) + ,',',db_quote(format(Sys.time(),'%a, %d %b %Y %H:%M:%S %z')) + ,',',db_quote(scm_revision) + ,',',db_quote(paste(log, collapse='\n')) + ,')')) + db_stop(con) +} + +db_builds <- function(pkgname) { + # returns all successful builds + con <- db_start() + build <- dbGetQuery(con, paste('SELECT * FROM builds' + ,'WHERE success = 1' + ,'AND package =',db_quote(pkgname))) + db_stop(con) + if (length(build) == 0) { + return(NULL) + } + build$success <- as.logical(build$success) + return(build) +} + +db_latest_build <- function(pkgname) { + con <- db_start() + build <- dbGetQuery(con, paste('SELECT * FROM builds' + ,'NATURAL JOIN (SELECT package,max(id) AS max_id FROM builds' + , 'GROUP BY package) AS last' + ,'WHERE id = max_id' + ,'AND builds.package =',db_quote(pkgname))) + db_stop(con) + if (length(build) == 0) { + return(NULL) + } + build$success <- as.logical(build$success) + return(build) +} + +db_latest_build_version <- function(pkgname) { + build <- db_latest_build(pkgname) + if (is.null(build)) { + return(NULL) + } + return(version_new(build$r_version, build$deb_revision, build$deb_epoch)) +} + +db_latest_build_status <- function(pkgname) { + build <- db_latest_build(pkgname) + if (is.null(build)) { + return(NULL) + } + return(list(build$success,build$log)) +} + +db_outdated_packages <- function() { + con <- db_start() + packages <- dbGetQuery(con,paste('SELECT packages.package FROM packages' + ,'LEFT OUTER JOIN (' + # extract the latest attempt at building each package + , 'SELECT * FROM builds' + , 'NATURAL JOIN (SELECT package,max(id) AS max_id FROM builds' + , 'GROUP BY package) AS last' + , 'WHERE id = max_id) AS build' + ,'ON build.package = packages.package' + # outdated iff: + # - there is no latest build + ,'WHERE build.package IS NULL' + # - the database has changed since last build + ,'OR build.db_version < (SELECT max(version) FROM database_versions)' + # - the debian epoch has been bumped up + ,'OR build.deb_epoch < (SELECT max(base_epoch) FROM database_versions' + , 'WHERE version IN (' + , 'SELECT max(version) FROM database_versions))' + # - the latest build is not of the latest R version + ,'OR build.r_version != packages.latest_r_version' + ))$package + db_stop(con) + return(packages) +} + diff --git a/branch/multisys/R/debcontrol.R b/branch/multisys/R/debcontrol.R new file mode 100644 index 0000000..84d9933 --- /dev/null +++ b/branch/multisys/R/debcontrol.R @@ -0,0 +1,167 @@ +get_dependencies <- function(pkg,extra_deps) { + # determine dependencies + dependencies <- r_dependencies_of(description=pkg$description) + depends <- list() + # these are used for generating the Depends fields + as_deb <- function(r,build) { + return(pkgname_as_debian(paste(dependencies[r,]$name) + ,version=dependencies[r,]$version + ,repopref=pkg$repo + ,build=build)) + } + depends$bin <- lapply(rownames(dependencies), as_deb, build=F) + depends$build <- lapply(rownames(dependencies), as_deb, build=T) + # add the command line dependencies + depends$bin = c(extra_deps$deb,depends$bin) + depends$build = c(extra_deps$deb,depends$build) + # add the system requirements + if ('SystemRequirements' %in% colnames(pkg$description)) { + sysreq <- sysreqs_as_debian(pkg$description[1,'SystemRequirements']) + depends$bin = c(sysreq$bin,depends$bin) + depends$build = c(sysreq$build,depends$build) + } + + forced <- forced_deps_as_debian(pkg$name) + if (length(forced)) { + notice('forced build dependencies:',paste(forced$build, collapse=', ')) + notice('forced binary dependencies:',paste(forced$bin, collapse=', ')) + depends$bin = c(forced$bin,depends$bin) + depends$build = c(forced$build,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',build=T)) + depends$bin = c(depends$bin, pkgname_as_debian('R',version='>= 2.7.0',build=F)) + } + # also include stuff to allow tcltk to build (suggested by Dirk) + depends$build = c(depends$build,'xvfb','xauth','xfonts-base') + + # make all bin dependencies build dependencies. + depends$build = c(depends$build, depends$bin) + + # 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 = r_dependency_closure(dependencies) + # append command line dependencies + depends$r = c(extra_deps$r, depends$r) + return(depends) +} + +sysreqs_as_debian <- function(sysreq_text) { + # form of this field is unspecified (ugh) but most people seem to stick + # with this + aliases <- c() + sysreq_text <- gsub('[[:space:]]and[[:space:]]',' , ',tolower(sysreq_text)) + for (sysreq in strsplit(sysreq_text,'[[:space:]]*,[[:space:]]*')[[1]]) { + startreq = sysreq + # constant case + sysreq = tolower(sysreq) + # drop version information/comments for now + sysreq = gsub('[[][^])]*[]]','',sysreq) + sysreq = gsub('\\([^)]*\\)','',sysreq) + sysreq = gsub('[[][^])]*[]]','',sysreq) + sysreq = gsub('version','',sysreq) + sysreq = gsub('from','',sysreq) + sysreq = gsub('[<>=]*[[:space:]]*[[:digit:]]+[[:digit:].+:~-]*','',sysreq) + # byebye URLs + sysreq = gsub('(ht|f)tps?://[[:alnum:]!?*"\'(),%$_@.&+/=-]*','',sysreq) + # squish out space + sysreq = chomp(gsub('[[:space:]]+',' ',sysreq)) + alias <- db_sysreq_override(sysreq) + if (is.null(alias)) { + error('do not know what to do with SystemRequirement:',sysreq) + error('original SystemRequirement:',startreq) + fail('unmet system requirement') + } + notice('mapped SystemRequirement',startreq,'onto',alias,'via',sysreq) + aliases = c(aliases,alias) + } + return(map_aliases_to_debian(aliases)) +} + +forced_deps_as_debian <- function(r_name) { + aliases <- db_get_forced_depends(r_name) + return(map_aliases_to_debian(aliases)) +} + +map_aliases_to_debian <- function(aliases) { + if (!length(aliases)) { + return(aliases) + } + debs <- list() + debs$bin = unlist(sapply(aliases, db_get_depends)) + debs$build = unlist(sapply(aliases, db_get_depends, build=T)) + debs$bin = debs$bin[debs$bin != 'build-essential'] + debs$build = debs$build[debs$build != 'build-essential'] + return(debs) +} + +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 +# # unnecessary for now; cran2deb converts R bundles itself +# 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))) +# ,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'] + } + + if (length(long_descr) < 1) { + # bypass lintian extended-description-is-empty for which we care not. + long_descr <- paste('The author/maintainer of this package' + ,'did not care to enter a longer 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) +} + diff --git a/branch/multisys/R/debiannaming.R b/branch/multisys/R/debiannaming.R new file mode 100644 index 0000000..83c0ab5 --- /dev/null +++ b/branch/multisys/R/debiannaming.R @@ -0,0 +1,52 @@ +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') + } + fail('unknown repository',url) +} + +pkgname_as_debian <- function(name,repopref=NULL,version=NULL,binary=T,build=F) { + # 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) { + if (build) { + debname='r-base-dev' + } else { + debname='r-base-core' + } + } else { + debname='R' + } + } 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.null(bundle)) { + name <- bundle + } + } + debname = tolower(name) + if (binary) { + if (name %in% rownames(available)) { + repopref <- tolower(repourl_as_debian(available[name,'Repository'])) + } else if (is.null(repopref)) { + repopref <- 'unknown' + } + debname = paste('r',repopref,debname,sep='-') + } + } + if (!is.null(version) && length(version) > 1) { + debname = paste(debname,' (',version,')',sep='') + } + return(debname) +} + diff --git a/branch/multisys/R/debianpkg.R b/branch/multisys/R/debianpkg.R new file mode 100644 index 0000000..f2aa115 --- /dev/null +++ b/branch/multisys/R/debianpkg.R @@ -0,0 +1,144 @@ +append_build_from_pkg <- function(pkg, builds) { + pkg_build <- data.frame(id = -1 # never used + ,package = pkg$name + ,r_version = version_upstream(pkg$debversion) + ,deb_epoch = version_epoch(pkg$debversion) + ,deb_revision = version_revision(pkg$debversion) + ,db_version = db_get_version() + ,date_stamp = pkg$date_stamp + ,git_revision = scm_revision + ,success = 1 # never used + ,log = '' # never used + ) + return(cbind(data.frame(srcname=pkg$srcname), rbind(builds, pkg_build))) +} + +generate_changelog <- function(pkg) { + # TODO: ``Writing R extensions'' mentions that a package may also have + # {NEWS,ChangeLog} files. + builds <- append_build_from_pkg(pkg, db_builds(pkg$name)) + sapply(rev(rownames(builds)), function(b, changelog) generate_changelog_entry(builds[b,], changelog), pkg$debfile('changelog.in')) +} + +generate_changelog_entry <- function(build, changelog) { + # TODO: should say 'New upstream release' when necessary + debversion <- version_new(build$r_version, build$deb_revision, build$deb_epoch) + cat(paste(paste(build$srcname,' (',debversion,') unstable; urgency=low',sep='') + ,'' ,paste(' * cran2deb ',build$git_revision + ,' with DB version ',as.integer(build$db_version),'.',sep='') + ,'',paste(' --',maintainer,'',build$date_stamp) + ,'','','',sep='\n'),file=changelog, append=TRUE) +} + +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 + + # if maintainer is missing then try to use author + if (!('Maintainer' %in% colnames(pkg$description))) { + if ('Author' %in% colnames(pkg$description)) { + maintainer = pkg$description[1,'Author'] + } else { + fail('Maintainer and Author not defined in R DESCRIPTION') + } + } else { + maintainer = pkg$description[1,'Maintainer'] + } + # likewise if author is missing then try to use maintainer + if (!('Author' %in% colnames(pkg$description))) { + author = maintainer + } else { + author = pkg$description[1,'Author'] + } + + 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') + ,author + ,'and possibly others.' + ,'' + ,'The original GNU R package is maintained by' + ,maintainer,'and was obtained from:' + ,'' + ,pkg$repoURL + ,'' + ,'' + ,'The GNU R package DESCRIPTION offers a' + ,'Copyright licenses under the terms of the license:' + ,pkg$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$debversion = new_build_version(pkg$name) + + # 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) + + # convert text to utf8 (who knows what the original character set is -- + # let's hope iconv DTRT). + for (file in c('control','changelog','copyright')) { + log_system('iconv -o ',shQuote(pkg$debfile(file)) + ,' -t utf8 -c ' + ,shQuote(pkg$debfile(paste(file,'in',sep='.')))) + file.remove(pkg$debfile(paste(file,'in',sep='.'))) + } + return(pkg) +} diff --git a/branch/multisys/R/getrpkg.R b/branch/multisys/R/getrpkg.R new file mode 100644 index 0000000..5273a1f --- /dev/null +++ b/branch/multisys/R/getrpkg.R @@ -0,0 +1,172 @@ +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() +} + +download_pkg <- function(dir, pkgname) { + # download pkgname into dir, and construct some metadata + + # record some basic information + pkg <- pairlist() + pkg$date_stamp = format(Sys.time(),'%a, %d %b %Y %H:%M:%S %z') + pkg$name = pkgname + pkg$repoURL = available[pkgname,'Repository'] + pkg$repo = repourl_as_debian(pkg$repoURL) + if (!length(grep('^[A-Za-z0-9][A-Za-z0-9+.-]+$',pkg$name))) { + fail('Cannot convert package name into a Debian name',pkg$name) + } + pkg$srcname = pkgname_as_debian(pkg$name,binary=F) + pkg$debname = pkgname_as_debian(pkg$name,repo=pkg$repo) + pkg$version <- available[pkgname,'Version'] + + # see if we have already built this release and uploaded it. + debfn <- file.path(pbuilder_results, paste(pkg$srcname, '_', pkg$version, '.orig.tar.gz', sep='')) + pkg$need_repack = FALSE + if (file.exists(debfn)) { + # if so, use the existing archive. this is good for three reasons: + # 1. it saves downloading the archive again + # 2. the repacking performed below changes the MD5 sum of the archive + # which upsets some Debian archive software. + # 3. why repack more than once? + pkg$archive <- file.path(dir, basename(debfn)) + file.copy(debfn,pkg$archive) + pkg$path = file.path(dir, paste(pkg$srcname ,pkg$version ,sep='-')) + } else { + # see if we have a local mirror in /srv/R + use_local = FALSE + if (pkg$repo == 'cran') { + localfn = file.path('/srv/R/Repositories/CRAN/src/contrib',paste(pkg$name,'_',pkg$version,'.tar.gz',sep='')) + use_local = file.exists(localfn) + } else if (pkg$repo == 'bioc') { + localfn = file.path('/srv/R/Repositories/Bioconductor/release/bioc/src/contrib',paste(pkg$name,'_',pkg$version,'.tar.gz',sep='')) + use_local = file.exists(localfn) + } + + fn <- paste(pkgname, '_', pkg$version, '.tar.gz', sep='') + archive <- file.path(dir, fn) + + if (use_local) { + file.copy(localfn, archive) + } else { + # use this instead of download.packages as it is more resilient to + # dodgy network connections (hello BT 'OpenWorld', bad ISP) + url <- paste(available[pkgname,'Repository'], fn, sep='/') + # don't log the output -- we don't care! + ret <- system(paste('curl','-o',shQuote(archive),'-m 720 --retry 5',shQuote(url))) + if (ret != 0) { + fail('failed to download',url) + } + # end of download.packages replacement + } + + if (length(grep('\\.\\.',archive)) || normalizePath(archive) != archive) { + fail('funny looking path',archive) + } + pkg$path = sub("_\\.(zip|tar\\.gz)", "" + ,gsub(.standard_regexps()$valid_package_version, "" + ,archive)) + pkg$archive = archive + # this is not a Debian conformant archive + pkg$need_repack = TRUE + } + return(pkg) +} + +repack_pkg <- function(pkg) { + # 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 + # BUT EXCLUDE configure and cleanup + log_system('find',shQuote(basename(pkg$path)) + ,'-type f -a ' + , '! \\( -name configure -o -name cleanup \\)' + ,'-exec chmod -x {} \\;') + # tar it all back up + log_system('tar -czf',shQuote(debarchive),shQuote(basename(pkg$path))) + setwd(wd) + file.remove(pkg$archive) + pkg$archive = debarchive + pkg$need_repack = FALSE + return(pkg) +} + +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 + + # 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.null(bundle)) { + fail('package',pkgname,'is unavailable') + } + pkgname <- bundle + } + + # grab the archive and some metadata + pkg <- download_pkg(dir, pkgname) + + # now extract the archive + if (!length(grep('\\.tar\\.gz',pkg$archive))) { + fail('archive is not tarball') + } + wd <- getwd() + setwd(dir) + ret = log_system('tar','xzf',shQuote(pkg$archive)) + setwd(wd) + if (ret != 0) { + fail('Extraction of archive',pkg$archive,'failed.') + } + + # if necessary, repack the archive into Debian-conformant format + if (pkg$need_repack) { + pkg <- repack_pkg(pkg) + } + if (!file.info(pkg$path)[,'isdir']) { + fail(pkg$path,'is not a directory and should be.') + } + + # extract the DESCRIPTION file, which contains much metadata + pkg$description = read.dcf(file.path(pkg$path,'DESCRIPTION')) + + # ensure consistency of version numbers + if ('Version' %in% names(pkg$description[1,])) { + if (pkg$description[1,'Version'] != available[pkg$name,'Version']) { + # should never happen since available is the basis upon which the + # package is retrieved. + error('available version:',available[pkg$name,'Version']) + error('package version:',pkg$description[1,'Version']) + fail('inconsistency between R package version and cached R 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)) { + fail('package name mismatch') + } + return(pkg) +} + diff --git a/branch/multisys/R/license.R b/branch/multisys/R/license.R new file mode 100644 index 0000000..846cf56 --- /dev/null +++ b/branch/multisys/R/license.R @@ -0,0 +1,155 @@ +is_acceptable_license <- function(license) { + # determine if license text is acceptable + + if (length(grep('^file ',license))) { + # skip file licenses + return(FALSE) + } + license <- license_text_reduce(license) + action = db_license_override_name(license) + if (!is.null(action)) { + return(action) + } + license <- license_text_further_reduce(license) + action = db_license_override_name(license) + if (!is.null(action)) { + warn('Accepting/rejecting wild license as',license,'. FIX THE PACKAGE!') + return(action) + } + license <- license_text_extreme_reduce(license) + action = db_license_override_name(license) + if (!is.null(action)) { + warn('Accepting/rejecting wild license as',license,'. FIX THE PACKAGE!') + return(action) + } + error('Wild license',license,'did not match classic rules; rejecting') + return(F) +} + +license_text_reduce <- function(license) { + # these reduction steps are sound for all conformant R license + # specifications. + + # compress spaces into a single space + license = gsub('[[:space:]]+',' ',license) + # make all characters lower case + license = tolower(license) + # don't care about versions of licenses + license = chomp(sub('\\( ?[<=>!]+ ?[0-9.-]+ ?\\)','' + ,sub('-[0-9.-]+','',license))) + # remove any extra space introduced + license = chomp(gsub('[[:space:]]+',' ',license)) + return(license) +} + +license_text_further_reduce <- function(license) { + # these reduction steps are heuristic and may lead to + # in correct acceptances, if care is not taken. + + # uninteresting urls + license = gsub('http://www.gnu.org/[[:alnum:]/._-]*','',license) + license = gsub('http://www.x.org/[[:alnum:]/._-]*','',license) + license = gsub('http://www.opensource.org/[[:alnum:]/._-]*','',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)) + return(license) +} + +license_text_extreme_reduce <- function(license) { + # remove everything that may or may not be 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)) + return(license) +} + +license_text_hash_reduce <- function(text) { + # reduction of license text, suitable for hashing. + return(chomp(tolower(gsub('[[:space:]]+',' ',text)))) +} + +get_license <- function(pkg,license) { + license <- chomp(gsub('[[:space:]]+',' ',license)) + if (length(grep('^file ',license))) { + if (length(grep('^file LICEN[CS]E$',license))) { + file = gsub('file ','',license) + path = file.path(pkg$path, file) + if (file.exists(path)) { + license <- license_text_reduce(readChar(path,file.info(path)$size)) + } else { + path = file.path(pkg$path, 'inst', file) + if (file.exists(path)) { + license <- license_text_reduce(readChar(path,file.info(path)$size)) + } else { + error('said to look at a license file but license file is missing') + } + } + } else { + error('invalid license file specification',license) + return(NA) + } + } + return(license) +} + +get_license_hash <- function(pkg,license) { + return(digest(get_license(pkg,license),algo='sha1',serialize=FALSE)) +} + +is_acceptable_hash_license <- function(pkg,license) { + license_sha1 <- get_license_hash(pkg,license) + if (is.null(license_sha1)) { + return(FALSE) + } + action = db_license_override_hash(license_sha1) + if (is.null(action)) { + action = FALSE + } + if (action) { + warn('Wild license',license,'accepted via hash',license_sha1) + } + return(action) +} + + +accept_license <- function(pkg) { + # check the license + if (!('License' %in% names(pkg$description[1,]))) { + fail('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_acceptable_hash_license(pkg,license)) { + accept=license + break + } + } + if (is.null(accept)) { + fail('No acceptable license:',pkg$description[1,'License']) + } else { + notice('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/branch/multisys/R/log.R b/branch/multisys/R/log.R new file mode 100644 index 0000000..2a9be4e --- /dev/null +++ b/branch/multisys/R/log.R @@ -0,0 +1,65 @@ +log_messages <- list() + +log_clear <- function() { + assign('log_messages',list(),envir=.GlobalEnv) +} + +log_add <- function(text,print=T) { + if (print) { + message(text) + } + assign('log_messages',c(log_messages, text),envir=.GlobalEnv) +} + +log_retrieve <- function() { + return(log_messages) +} + +notice <- function(...) { + log_add(paste('N:',...)) +} + +warn <- function(...) { + log_add(paste('W:',...)) +} + +error <- function(...) { + log_add(paste('E:',...)) +} + +fail <- function(...) { + txt <- paste('E:',...) + log_add(txt) + stop(txt) +} + +log_system <- function(...) { + r <- try((function() { + # pipe() does not appear useful here, since + # we want the return value! + # XXX: doesn't work with ; or | ! + tmp <- tempfile('log_system') + on.exit(unlink(tmp)) + cmd <- paste(...) + # unfortunately this destroys ret + #cmd <- paste(cmd,'2>&1','| tee',tmp) + cmd <- paste(cmd,'>',tmp,'2>&1') + ret <- system(cmd) + f <- file(tmp) + output <- readLines(f) + close(f) + unlink(tmp) + return(list(ret,output)) + })()) + if (inherits(r,'try-error')) { + fail('system failed on:',paste(...)) + } + for (line in r[[2]]) { + if (!length(grep('^[WENI]:',line))) { + line = paste('I:',line) + } + log_add(line) #,print=F) + } + return(r[[1]]) +} + diff --git a/branch/multisys/R/rdep.R b/branch/multisys/R/rdep.R new file mode 100644 index 0000000..141453b --- /dev/null +++ b/branch/multisys/R/rdep.R @@ -0,0 +1,155 @@ + +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(NULL) +} + +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.null(bundle)) { + name = bundle + names <- c(names,bundle) + } + } + if (name %in% rownames(available) && !is.na(available[name,'Contains'])) { + names <- c(names,r_bundle_contains(name)) + } + } + # approximately prune first into a smaller availability + candidates <- rownames(available)[sapply(rownames(available) + ,function(name) + length(grep(paste(names,collapse='|') + ,available[name,r_depend_fields])) > 0)] + 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(available[name,field]) + ,'[[:space:]]*,[[:space:]]*') + ,dep_matches)) + + for (field in r_depend_fields) { + matches = sapply(candidates, any_dep_matches, field=field) + if (length(matches) > 0) { + prereq = c(prereq,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)) { + fail('must specify either a description or a name.') + } + if (is.null(description)) { + if (!(name %in% rownames(available))) { + bundle <- r_bundle_of(name) + if (!is.null(bundle)) { + name <- bundle + } else { + # unavailable packages don't depend upon anything + return(data.frame()) + } + } + 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))) { + fail('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.null(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 <- as.list(fringe$name) + } + fun = function(x) 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 (src == 'R') { + next + } + newdeps <- fun(top) + closure=c(closure,top) + fringe=c(fringe,newdeps) + } + # build order + return(rev(unique(closure,fromLast=T))) +} + diff --git a/branch/multisys/R/util.R b/branch/multisys/R/util.R new file mode 100644 index 0000000..68401fd --- /dev/null +++ b/branch/multisys/R/util.R @@ -0,0 +1,20 @@ +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))) +} + +err <- function(...) { + error(...) + exit() +} + +exit <- function() { + q(save='no') +} diff --git a/branch/multisys/R/version.R b/branch/multisys/R/version.R new file mode 100644 index 0000000..184ec23 --- /dev/null +++ b/branch/multisys/R/version.R @@ -0,0 +1,92 @@ +version_new <- function(rver,debian_revision=1, debian_epoch=db_get_base_epoch()) { + # 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))) { + fail('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))) { + fail('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)) = base_epoch + +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, prev_success) { + # return the next debian package version + prev_rver <- version_upstream(prev_pkgver) + if (prev_rver == rver) { + # increment the Debian revision if the previous build was successful + inc = 0 + if (prev_success) { + inc = 1 + } + return(version_new(rver + ,debian_revision = version_revision(prev_pkgver)+inc + ,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) + )) +} + +new_build_version <- function(pkgname) { + if (!(pkgname %in% rownames(available))) { + bundle <- r_bundle_of(pkgname) + if (is.null(bundle)) { + fail('tried to discover new version of',pkgname,'but it does not appear to be available') + } + name <- bundle + } + db_ver <- db_latest_build_version(pkgname) + db_succ <- db_latest_build_status(pkgname)[[1]] + latest_r_ver <- available[pkgname,'Version'] + if (!is.null(db_ver)) { + return(version_update(latest_r_ver, db_ver, db_succ)) + } + return(version_new(latest_r_ver)) +} + diff --git a/branch/multisys/R/zzz.R b/branch/multisys/R/zzz.R new file mode 100644 index 0000000..ffb09ad --- /dev/null +++ b/branch/multisys/R/zzz.R @@ -0,0 +1,28 @@ +.First.lib <- function(libname, pkgname) { + global <- function(name,value) assign(name,value,envir=.GlobalEnv) + which_sys <- Sys.getenv('CRAN2DEB_SYS','debian-amd64') + if (!length(grep('^[a-z]+-[a-z0-9]+$',which_sys))) { + stop('Invalid system specification: must be of the form name-arch') + } + global("host_arch", gsub('^[a-z]+-','',which_sys)) + global("maintainer", 'cran2deb autobuild ') + global("root", system.file(package='cran2deb')) + global("cache_root", '/var/cache/cran2deb') + global("pbuilder_results", file.path('/var/cache/cran2deb/results',which_sys)) + global("pbuilder_config", file.path('/etc/cran2deb/sys',which_sys,'pbuilderrc')) + global("dput_config", file.path('/etc/cran2deb/sys',which_sys,'dput.cf') + global("dinstall_config", file.path('/etc/cran2deb/sys',which_sys,'mini-dinstall.conf') + global("dinstall_archive", file.path('/etc/cran2deb/archive',which_sys)) + global("r_depend_fields", c('Depends','Imports')) # Suggests, Enhances + global("scm_revision", 'svn:$Id$') + global("changesfile", function(srcname,version='*') { + return(file.path(pbuilder_results + ,paste(srcname,'_',version,'_' + ,host_arch(),'.changes',sep=''))) + }) + + cache <- file.path(cache_root,'cache.rda') + if (file.exists(cache)) { + load(cache,envir=.GlobalEnv) + } +} diff --git a/branch/multisys/README b/branch/multisys/README new file mode 120000 index 0000000..a6047ac --- /dev/null +++ b/branch/multisys/README @@ -0,0 +1 @@ +inst/doc/README \ No newline at end of file diff --git a/branch/multisys/data/populate_depend_aliases b/branch/multisys/data/populate_depend_aliases new file mode 100644 index 0000000..d7dc09a --- /dev/null +++ b/branch/multisys/data/populate_depend_aliases @@ -0,0 +1,75 @@ +alias_build boost libboost-dev +alias_build boost libboost-graph-dev +alias_build ggobi ggobi +alias_run ggobi ggobi +alias_build glade libglade2-dev +alias_run glade libglade2-0 +alias_build glib libglib2.0-dev +alias_run glib libglib2.0-0 +alias_build glu libglu1-mesa-dev +alias_run glu libglu1-mesa +alias_build gmp libgmp3-dev +alias_run gmp libgmp3c2 +alias_build gsl libgsl0-dev +alias_run gsl libgsl0ldbl +alias_build ignore build-essential +alias_build java openjdk-6-jdk +alias_build java libgcj9-dev +alias_run java openjdk-6-jre +alias_build libatk libatk1.0-dev +alias_run libatk libatk1.0-0 +alias_build libcairo libcairo2-dev +alias_run libcairo libcairo2 +alias_run libcurl libcurl3 +alias_build libcurl libcurl4-openssl-dev +alias_build libdieharder libdieharder-dev +alias_run libdieharder libdieharder2 +alias_build libfontconfig libfontconfig1-dev +alias_run libfontconfig libfontconfig1 +alias_build libfreetype libfreetype6-dev +alias_run libfreetype libfreetype6 +alias_build libgdal libgdal1-dev +alias_run libgdal libgdal1-1.5.0 +alias_build libgd libgd2-noxpm-dev +alias_run libgd libgd2-noxpm +alias_build libgraphviz libgraphviz-dev +alias_run libgraphviz libgraphviz4 +alias_build libgtk libgtk2.0-dev +alias_run libgtk libgtk2.0-0 +alias_build libjpeg libjpeg62-dev +alias_run libjpeg libjpeg62 +alias_build libmagick libmagick9-dev +alias_run libmagick libmagick9 +alias_build libpango libpango1.0-dev +alias_run libpango libpango1.0-0 +alias_build libpng libpng12-dev +alias_run libpng libpng12-0 +alias_build libxml libxml2-dev +alias_run libxml libxml2 +alias_build msttcorefonts msttcorefonts +alias_run msttcorefonts msttcorefonts +alias_run netcdf libnetcdf4 +alias_build netcdf libnetcdf-dev +alias_build opengl libgl1-mesa-dev +alias_run opengl libgl1-mesa-glx +alias_build pari-gp pari-gp +alias_run pari-gp pari-gp +alias_build proj proj +alias_run proj proj +alias_build quantlib libquantlib0-dev +alias_run quantlib libquantlib-0.9.6 +alias_run sqlite libsqlite3-0 +alias_build sqlite libsqlite3-dev +alias_build zlib zlib1g-dev +alias_run zlib zlib1g +alias_build cshell tcsh|csh|c-shell +alias_run cshell tcsh|csh|c-shell +alias_build autotools autotools-dev +alias_build tcl tcl8.4-dev +alias_build tk tk8.4-dev +alias_build odbc unixodbc-dev +alias_build mysql libmysqlclient15-dev +alias_build mpi libopenmpi-dev +alias_build pvm pvm-dev +alias_build hdf5 libhdf5-serial-dev +alias_build sprng libsprng2-dev diff --git a/branch/multisys/data/populate_forcedep b/branch/multisys/data/populate_forcedep new file mode 100644 index 0000000..799d286 --- /dev/null +++ b/branch/multisys/data/populate_forcedep @@ -0,0 +1,18 @@ +force java rJava +force autotools rJava +force sqlite RSQLite +force sqlite SQLiteDF +force boost RBGL +force netcdf ncdf +force cshell dse +force libgtk cairoDevice +force tcl tkrplot +force tk tkrplot +force mysql RMySQL +force mpi Rmpi +force pvm rpvm +force hdf5 hdf5 +force libgtk rggobi +force libxml rggobi +force sprng rsprng +force gmp rsprng diff --git a/branch/multisys/data/populate_licenses b/branch/multisys/data/populate_licenses new file mode 100644 index 0000000..ad791bd --- /dev/null +++ b/branch/multisys/data/populate_licenses @@ -0,0 +1,99 @@ +accept AGPL +accept APACHE +accept ARTISTIC +accept BSD +accept CeCILL +accept CPL +accept GPL +accept GPLQA +accept GPL+QHULL +accept LGPL +accept MIT +accept MPL +accept TCLTK2 +accept UNLIMITED +accept X11 +reject distrib-noncomm +reject GPL+ACM +reject MCLUST +reject UNCLEAR +hash APACHE /usr/share/common-licenses/Apache-2.0 +hash ARTISTIC /usr/share/common-licenses/Artistic +hash BSD /usr/share/common-licenses/BSD +hash GPL /usr/share/common-licenses/GPL-2 +hash GPL /usr/share/common-licenses/GPL-3 +hash LGPL /usr/share/common-licenses/LGPL-2 +hash LGPL /usr/share/common-licenses/LGPL-2.1 +hash LGPL /usr/share/common-licenses/LGPL-3 +pkg BSD minpack.lm +pkg CeCILL LLAhclust +pkg CPL lmom +pkg distrib-noncomm Bhat +pkg distrib-noncomm conf.design +pkg distrib-noncomm gpclib +pkg distrib-noncomm mlbench +pkg distrib-noncomm poplab +pkg distrib-noncomm PredictiveRegression +pkg distrib-noncomm PTAk +pkg distrib-noncomm siggenes +pkg GPL+ACM akima +pkg GPL+ACM tripack +pkg GPL degreenet +pkg GPL ergm +pkg GPL gmodels +pkg GPL ICE +pkg GPL latentnet +pkg GPL network +pkg GPL networksis +pkg GPL pastecs +pkg GPL pbatR +pkg GPL PKtools +pkg GPL+QHULL geometry +pkg GPL reldist +pkg GPL RXshrink +pkg GPL snpMatrix +pkg GPL splancs +pkg GPL statnet +pkg GPL uroot +pkg LGPL R.huge +pkg MCLUST mclust +pkg TCLTK2 tcltk2 +pkg UNCLEAR adapt +pkg UNCLEAR cat +pkg UNCLEAR cosmo +pkg UNCLEAR mix +pkg UNCLEAR mlmm +pkg UNCLEAR norm +pkg UNCLEAR pan +pkg UNCLEAR titecrm +pkg UNCLEAR tlnise +pkg UNLIMITED boolean +pkg GPLQA regtest +pkg GPL gllm +pkg GPL rake +pkg GPL Rigroup +pkg GPL ICEinfer +pkg GPL partsm +pkg GPL timsac +pkg GPL HTMLapplets +pkg GPL moc +pkg GPL ibdreg +pkg AGPL accuracy +pkg AGPL Zelig +pkg GPL TWIX +pkg GPL aplpack +accept distrib-noncomm +accept GPL+ACM +accept MCLUST +accept UNCLEAR +accept acepack +accept ff +pkg acepack acepack +pkg ff ff +pkg AGPL AIS +pkg AGPL BARD +accept NISTnls +pkg NISTnls NISTnls +pkg GPL NMMAPSlite +pkg GPL PET +pkg distrib-noncomm RLadyBug diff --git a/branch/multisys/data/populate_sysreq b/branch/multisys/data/populate_sysreq new file mode 100644 index 0000000..b8f4b3e --- /dev/null +++ b/branch/multisys/data/populate_sysreq @@ -0,0 +1,37 @@ +sysreq ignore gcc +sysreq ignore gnu make +sysreq ignore % if present +sysreq ignore none +sysreq libcurl curl +sysreq ggobi ggobi +sysreq libatk atk +sysreq libcairo cairo +sysreq libdieharder dieharder% +sysreq libfontconfig fontconfig +sysreq libfreetype freetype +sysreq libfreetype %freetype +sysreq libgd libgd +sysreq libgdal %gdal% +sysreq opengl opengl +sysreq glade %glade +sysreq glib glib +sysreq glu glu library +sysreq gmp gmp +sysreq libgraphviz graphviz +sysreq gsl gnu gsl% +sysreq gsl gnu scientific library +sysreq libgtk gtk% +sysreq libjpeg libjpeg% +sysreq libmagick imagemagick +sysreq libpango pango +sysreq libpng libpng +sysreq quantlib quantlib% +sysreq libxml libxml% +sysreq msttcorefonts msttcorefonts +sysreq pari-gp pari/gp +sysreq proj proj% +sysreq zlib zlib +sysreq java java +sysreq odbc %odbc% +sysreq ignore drivers. see readme. +sysreq ignore r must be compiled with --enable-r-shlib if the server is to be built diff --git a/branch/multisys/data/quit b/branch/multisys/data/quit new file mode 100644 index 0000000..ff60466 --- /dev/null +++ b/branch/multisys/data/quit @@ -0,0 +1 @@ +quit diff --git a/branch/multisys/exec/autobuild b/branch/multisys/exec/autobuild new file mode 100755 index 0000000..0b24cba --- /dev/null +++ b/branch/multisys/exec/autobuild @@ -0,0 +1,15 @@ +#!/usr/bin/env r +## DOC: cran2deb autobuild +## DOC: automatically builds all out of date packages. +## DOC: +suppressMessages(library(cran2deb)) + +if (exists('argv')) { # check for littler + db_update_package_versions() + outdated <- db_outdated_packages() + build_order <- r_dependency_closure(outdated) + notice('build order',paste(build_order,collapse=', ')) + for (pkg in build_order) { + build(pkg,c()) + } +} diff --git a/branch/multisys/exec/build b/branch/multisys/exec/build new file mode 100755 index 0000000..b875e60 --- /dev/null +++ b/branch/multisys/exec/build @@ -0,0 +1,43 @@ +#!/usr/bin/env r +## DOC: cran2deb build [-D extra_dep1,extra_dep2,...] package1 package2 ... +## DOC: builds a particular package. +## DOC: +suppressMessages(library(cran2deb)) + +if (exists('argv')) { # check for littler + argc <- length(argv) + extra_deps = list() + extra_deps$deb = c() + extra_deps$r = c() + opts = c('-D','-R') + # first argument is the root --- this is dealt with elsewhere. + for (i in 2:argc) { + if (!(argv[i] %in% opts)) { + if (argc >= i) { + argv <- argv[i:argc] + } else { + argv <- list() + } + argc = argc - i + 1 + break + } + if (i == argc) { + err('missing argument') + } + 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) { + err('usage: cran2deb [-D extra_dep1,extra_dep2,...] package package ...') + } + build_order <- r_dependency_closure(c(extra_deps$r,argv)) + notice('build order',paste(build_order,collapse=', ')) + for (pkg in build_order) { + build(pkg,extra_deps,force=pkg %in% argv) + } +} diff --git a/branch/multisys/exec/build_ctv b/branch/multisys/exec/build_ctv new file mode 100755 index 0000000..1e39e04 --- /dev/null +++ b/branch/multisys/exec/build_ctv @@ -0,0 +1,14 @@ +#!/bin/sh +## DOC: cran2deb build_ctv +## DOC: build all CRAN TaskViews. warning and error logs in ./ctv/ +## DOC: + +for ctv in $(cran2deb cran_pkgs query); do + echo task view $ctv... + if [ ! -e "ctv/$ctv" ]; then + cran2deb build_some "$ctv" + mkdir -p "ctv/$ctv" + mv warn fail "ctv/$ctv" + fi +done + diff --git a/branch/multisys/exec/build_some b/branch/multisys/exec/build_some new file mode 100755 index 0000000..f02af9d --- /dev/null +++ b/branch/multisys/exec/build_some @@ -0,0 +1,37 @@ +#!/usr/bin/rc +## DOC: cran2deb build_some [taskview1 taskview2 ...] +## DOC: build some packages, logging warnings into ./warn/$package +## DOC: and failures into ./fail/$package. with no arguments a random +## DOC: sample of packages is built. the file ./all_pkgs overrides this +## DOC: behaviour and is expected to be a list of packages to build. +## DOC: + +mkdir -p warn fail +shift +if [ ! -e all_pkgs ]; then + cran2deb cran_pkgs $* >all_pkgs +fi + +for pkg in $(cat all_pkgs); do + if (~ $pkg *..* */*) { + echo bad name $pkg >>fail/ERROR + } else if ([ -e warn/$pkg ]) { + echo skipping $pkg... + } else if ([ -e fail/$pkg ]) { + echo skipping failed $pkg... + } else { + echo -n .. package $pkg + fail=0 + cran2deb build $pkg >fail/$pkg >[2=1] || fail=1 + if (~ $fail 0) { + echo success + grep '^[WE]:' fail/$pkg >warn/$pkg +# if (~ `{stat -c '%s' warn/$pkg} 0) { +# rm -f warn/$pkg +# } + rm -f fail/$pkg + } else { + echo FAILED + } + } +done diff --git a/branch/multisys/exec/copy_find b/branch/multisys/exec/copy_find new file mode 100755 index 0000000..eebcec1 --- /dev/null +++ b/branch/multisys/exec/copy_find @@ -0,0 +1,33 @@ +#!/usr/bin/rc +## DOC: cran2deb copy_find path +## DOC: a tool for finding (heuristically) some copyright notices. +## DOC: +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/branch/multisys/exec/cran2deb b/branch/multisys/exec/cran2deb new file mode 100755 index 0000000..7efedc7 --- /dev/null +++ b/branch/multisys/exec/cran2deb @@ -0,0 +1,10 @@ +#!/bin/sh +umask 002 +root=$(r -e 'suppressMessages(library(cran2deb));cat(system.file(package="cran2deb"),file=stdout())') +cmd=$1 +shift +if [ ! -x "$root/exec/$cmd" ]; then + echo unknown command $cmd + exit 1 +fi +"$root/exec/$cmd" "$root" $* diff --git a/branch/multisys/exec/cran_pkgs b/branch/multisys/exec/cran_pkgs new file mode 100755 index 0000000..b8a2dcb --- /dev/null +++ b/branch/multisys/exec/cran_pkgs @@ -0,0 +1,28 @@ +#!/usr/bin/env r +## DOC: cran2deb cran_pkgs +## DOC: print a list of 800 packages picked at random +## DOC: cran2deb cran_pkgs query +## DOC: print the names of all CRAN TaskViews +## DOC: cran2deb cran_pkgs taskview1 taskview2 ... +## DOC: print the names of all packages in a particular CRAN TaskView +## DOC: + +library(cran2deb) + +if (length(argv) == 1) { + writeLines(sample(dimnames(available)[[1]],800)) +} else { + argv = argv[2:length(argv)] + 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/branch/multisys/exec/depend b/branch/multisys/exec/depend new file mode 100755 index 0000000..2552d8f --- /dev/null +++ b/branch/multisys/exec/depend @@ -0,0 +1,95 @@ +#!/usr/bin/env r +## DOC: cran2deb depend +## DOC: add dependency aliases, system requirements and forced dependencies +## DOC: + +suppressPackageStartupMessages(library(cran2deb)) +suppressPackageStartupMessages(library(digest)) + +exec_cmd <- function(argc, argv) { + usage <- function() + message(paste('usage: alias ' + ,' alias_run ' + ,' alias_build ' + ,' sysreq ' + ,' force ' + ,' ls [aliases|force|sysreq]' + ,' quit' + ,sep='\n')) + + if (argc < 1) { + return() + } + cmd = argv[1] + + if (cmd == 'alias') { + if (argc < 3) { + usage() + return() + } + alias = argv[2] + pkg = argv[3] + db_add_depends(alias, pkg, build=T) + pkg = gsub('-dev$','',pkg) + db_add_depends(alias, pkg, build=F) + } else if (cmd == 'alias_run' || cmd == 'alias_build') { + if (argc < 3) { + usage() + return() + } + db_add_depends(argv[2], argv[3], cmd == 'alias_build') + } else if (cmd == 'sysreq') { + if (argc < 3) { + usage() + return() + } + sysreq = paste(argv[3:argc],collapse=' ') + db_add_sysreq_override(sysreq,argv[2]) + } else if (cmd == 'force') { + if (argc < 3) { + usage() + return() + } + db_add_forced_depends(argv[3],argv[2]) + } else if (cmd == 'ls') { + if (argc < 2 || argv[2] == 'aliases') { + aliases <- db_depends() + for (i in rownames(aliases)) { + type = 'alias_run' + if (as.logical(aliases[i,'build'])) { + type = 'alias_build' + } + cat(paste(type,aliases[i,'alias'],aliases[i,'debian_pkg'],'\n')) + } + } else if (argv[2] == 'sysreq') { + sysreqs <- db_sysreq_overrides() + for (i in rownames(sysreqs)) { + cat(paste('sysreq',sysreqs[i,'depend_alias'],sysreqs[i,'r_pattern'],'\n')) + } + } else if (argv[2] == 'force') { + forced <- db_forced_depends() + for (i in rownames(forced)) { + cat(paste('force',forced[i,'depend_alias'],forced[i,'r_name'],'\n')) + } + } else { + usage() + return() + } + } else if (cmd == 'quit') { + exit() + } else if (cmd == '#') { + } else { + usage() + return() + } +} + +argc <- length(argv) +if (argc > 1) { + exec_cmd(argc-1,argv[c(2:argc)]) +} else { + while(T) { + argv <- strsplit(readline('depend> '),'[[:space:]]+')[[1]] + exec_cmd(length(argv),argv) + } +} diff --git a/branch/multisys/exec/diagnose b/branch/multisys/exec/diagnose new file mode 100755 index 0000000..3740b50 --- /dev/null +++ b/branch/multisys/exec/diagnose @@ -0,0 +1,72 @@ +#!/usr/bin/rc + +success=`{ls /var/cache/cran2deb/results/*.deb | wc -l} +echo $success successful packages +total=$success + +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='do not know what to do with SystemRequirement:' +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} +total=`{hoc -e $total-$nfaillic-$nfailspc} +succrate=`{hoc -e $success/'('$total')*100'} +echo $succrate% success rate with exclusions '('$total' total)' +grep -EL $other fail/* /dev/null | xargs tail -n 20 + diff --git a/branch/multisys/exec/diagnose_ctv b/branch/multisys/exec/diagnose_ctv new file mode 100755 index 0000000..5e7ef03 --- /dev/null +++ b/branch/multisys/exec/diagnose_ctv @@ -0,0 +1,2 @@ +#!/bin/sh +(for x in ctv/*; do echo;echo;echo "$x: "; cd "$x" && cran2deb diagnose && cd ../..; done) >ctv.results diff --git a/branch/multisys/exec/get_base_pkgs b/branch/multisys/exec/get_base_pkgs new file mode 100755 index 0000000..d08d625 --- /dev/null +++ b/branch/multisys/exec/get_base_pkgs @@ -0,0 +1,4 @@ +#!/usr/bin/env r +for (pkg in rownames(installed.packages())) { + message(pkg) +} diff --git a/branch/multisys/exec/help b/branch/multisys/exec/help new file mode 100755 index 0000000..3eeabab --- /dev/null +++ b/branch/multisys/exec/help @@ -0,0 +1,6 @@ +#!/bin/sh +echo usage: cran2deb ' [args ...]' +echo where '' is one of +grep '## [D]OC:' $1/exec/* | sed -e 's/.*[D]OC://' +echo +echo installation root is: $1 diff --git a/branch/multisys/exec/latest_log b/branch/multisys/exec/latest_log new file mode 100644 index 0000000..055991a --- /dev/null +++ b/branch/multisys/exec/latest_log @@ -0,0 +1,11 @@ +#!/usr/bin/env r +## DOC: cran2deb latest_log package1 package2 ... +## DOC: show the latest log output for +suppressMessages(library(cran2deb)) + +if (exists('argv')) { + for (pkg in argv) { + cat(db_latest_build(pkg)$log) + cat('\n') + } +} diff --git a/branch/multisys/exec/license b/branch/multisys/exec/license new file mode 100755 index 0000000..74e01a5 --- /dev/null +++ b/branch/multisys/exec/license @@ -0,0 +1,126 @@ +#!/usr/bin/env r +## DOC: cran2deb license +## DOC: add licenses and change acceptance/rejection of licenses +## DOC: + +suppressPackageStartupMessages(library(cran2deb)) +suppressPackageStartupMessages(library(digest)) + +exec_cmd <- function(argc, argv) { + usage <- function() + message(paste('usage: accept ' + ,' reject ' + ,' hash (|)' + ,' pkg ' + ,' view ' + ,' ls' + ,' quit' + ,sep='\n')) + + if (argc < 1) { + exit() + } + cmd = argv[1] + + if (cmd == 'accept' || cmd == 'reject') { + if (argc != 2) { + usage() + return() + } + action = (cmd == 'accept') + db_add_license_override(argv[2],action) + } else if (cmd == 'hash') { + if (argc != 3) { + usage() + return() + } + license = argv[2] + path = argv[3] + if (is.null(db_license_override_name(license))) { + error('license',license,'is not known; add it first') + return() + } + if (file.exists(path)) { + license_sha1 = digest(readChar(path,file.info(path)$size) + ,algo='sha1', serialize=FALSE) + } else if (length(grep('^[0-9a-f]{40}$',path))) { + license_sha1 = path + } else { + error(path,'does not exist and does not look like an SHA1 hash') + return() + } + db_add_license_hash(license,license_sha1) + } else if (cmd == 'pkg') { + if (argc != 3) { + usage() + return() + } + license <- argv[2] + pkg_name <- argv[3] + current_action <- db_license_override_name(license) + if (is.null(current_action)) { + notice('license',license,'is not known; add it') + return() + } + action = 'accept' + if (!current_action) { + action = 'reject' + } + notice('in future, will',action,'the package',pkg_name,'under license',license) + tmp <- setup() + success <- try((function() { + pkg <- prepare_pkg(tmp,pkg_name) + if (!('License' %in% names(pkg$description[1,]))) { + error('package',pkg$name,'has no License: field in DESCRIPTION') + return() + } + first_license = (strsplit(chomp(pkg$description[1,'License']) + ,'[[:space:]]*\\|[[:space:]]*')[[1]])[1] + license_sha1 <- get_license_hash(pkg,first_license) + db_add_license_hash(license,license_sha1) + })()) + cleanup(tmp) + if (inherits(success,'try-error')) { + return() + } + } else if (cmd == 'view') { + if (argc != 2) { + usage() + return() + } + pkg_name <- argv[2] + tmp <- setup() + success <- try((function() { + pkg <- prepare_pkg(tmp,pkg_name) + if (!('License' %in% names(pkg$description[1,]))) { + error('package',pkg$name,'has no License: field in DESCRIPTION') + return() + } + first_license = (strsplit(chomp(pkg$description[1,'License']) + ,'[[:space:]]*\\|[[:space:]]*')[[1]])[1] + first_license = get_license(pkg,first_license) + cat(strwrap(first_license),file='|less') + })()) + cleanup(tmp) + if (inherits(success,'try-error')) { + return() + } + } else if (cmd == 'ls') { + for (x in db_license_overrides()) print(x) + } else if (cmd == 'help') { + usage() + return() + } else if (cmd == 'quit') { + exit() + } +} + +argc <- length(argv) +if (argc > 1) { + exec_cmd(argc-1,argv[c(2:argc)]) +} else { + while(T) { + argv <- strsplit(readline('license> '),'[[:space:]]+')[[1]] + exec_cmd(length(argv),argv) + } +} diff --git a/branch/multisys/exec/repopulate b/branch/multisys/exec/repopulate new file mode 100755 index 0000000..ab3ea60 --- /dev/null +++ b/branch/multisys/exec/repopulate @@ -0,0 +1,24 @@ +#!/bin/sh +## DOC: cran2deb repopulate +## DOC: repopulate the cran2deb database and configurations from a new cran2deb release +## DOC: + +umask 002 +root=$1 +shift +for x in $(find /etc/cran2deb/ -type f -name '*.in'); do + y=$(echo $x | sed -e 's,.in$,,') + sed -e "s:@ROOT@:$root:g" <"$x" >"$y" +done + +# now do an update to reflect any config changes +"$root/exec/update" "$root" + +(for fn in populate_licenses quit; do + cat "$root/data/$fn" +done) | "$root/exec/license" "$root" + +(for fn in populate_depend_aliases populate_sysreq populate_forcedep quit; do + cat "$root/data/$fn" +done) | "$root/exec/depend" "$root" + diff --git a/branch/multisys/exec/root b/branch/multisys/exec/root new file mode 100755 index 0000000..3133778 --- /dev/null +++ b/branch/multisys/exec/root @@ -0,0 +1,2 @@ +#!/bin/sh +echo $1 diff --git a/branch/multisys/exec/update b/branch/multisys/exec/update new file mode 100755 index 0000000..7bcc78f --- /dev/null +++ b/branch/multisys/exec/update @@ -0,0 +1,29 @@ +#!/usr/bin/rc +## DOC: cran2deb update +## DOC: update the cran2deb cache and database +## DOC: cran2deb update full +## DOC: force a full update of the cran2deb cache and database +## DOC: + +umask 002 +root=$1 +shift +mkdir -p /var/cache/cran2deb/results || exit 1 +mini-dinstall --batch -c /etc/cran2deb/mini-dinstall.conf || exit 1 +update_period=10800 +if (~ $1 full || ![ -e /var/cache/cran2deb/cache.rda ] ) { + delta=`{awk 'END{print '^$update_period^'+1}' &1 >/dev/null <' + ,shQuote(file.path(root,'exec/get_base_pkgs')) + ,'| grep -v ^W:'))) + +message('updating list of existing Debian packages...') +debian_pkgs <- readLines(pipe('apt-cache rdepends r-base-core | sed -e "/^ r-cran/{s/^[[:space:]]*r/r/;p}" -e d | sort -u')) + +save(debian_pkgs, base_pkgs, available, ctv.available, file=file.path(cache_root,'cache.rda'),eval.promises=T) + +message('synchronising database...') +db_update_package_versions() diff --git a/branch/multisys/inst/doc/DB_NOTES b/branch/multisys/inst/doc/DB_NOTES new file mode 100644 index 0000000..0960026 --- /dev/null +++ b/branch/multisys/inst/doc/DB_NOTES @@ -0,0 +1,81 @@ +this file documents some of R/db.R -- the DB interface code. + + +table: sysreq_override +fields: depend_alias TEXT, r_pattern TEXT + +SystemRequirements LIKE r_pattern are mapped onto the dependency alias +depend_alias (this is a foreign key in debian_dependency). + +table: debian_dependency +fields: id INTEGER PRIMARY KEY AUTOINCREMENT, + alias TEXT, + build INTEGER NOT NULL, + debian_pkg TEXT NOT NULL, + UNIQUE (alias,build,debian_pkg) + +sets up a dependency alias. each row is a Debian dependency entry, debian_pkg, which +may be added to Depends: (and Build-Depends: if build = 1). + +table: forced_depends +fields: r_name TEXT. + depend_alias TEXT, + PRIMARY KEY (r_name,depend_alias)' + +forces the R package r_name to have the dependencies implied by depend_alias (a foriegn +key in debian_dependency). + +table: license_override +fields: name TEXT PRIMARY KEY, + accept INT NOT NULL + +specifies whether the license, name, is accepted or rejected. + +table: license_hashes +fields: name TEXT + sha1 TEXT PRIMARY KEY + +matches an SHA1 hash of the LICEN[CS]E file or part of the License: field to +a particular license name (a foreign key in license_override). + +table: database_versions +fields: version INTEGER PRIMARY KEY AUTOINCREMENT, + version_date INTEGER, + base_epoch INTEGER + +a version of the database. each time one of the above tables (but not the below +tables) is updated, a new record is added to this table, indicating significant +changes to the database. version_date indicates when this change occurred +(seconds since UNIX epoch) and base_epoch is the Debian version epoch. + +in future, all of the above fields should be versioned and somehow linked to +the packages that used them, so we only rebuild what is necessary. + +table: packages +fields: package TEXT PRIMARY KEY, + latest_r_version TEXT + +a package, and its latest R version. this is a copy of the 'available' +structure in the cran2deb R cache, and it is here as it allows queries on the +'builds' table to be much simpler (and perhaps faster). + +table: builds +fields: id INTEGER PRIMARY KEY AUTOINCREMENT, + package TEXT, + r_version TEXT, + deb_epoch INTEGER, + deb_revision INTEGER, + db_version INTEGER, + date_stamp TEXT, + git_revision TEXT, + success INTEGER, + log TEXT, + UNIQUE(package,r_version,deb_epoch,deb_revision,db_version) + +Each time a 'package' is built, its 'success' is logged, along with the +particular database, cran2deb, R and Debian version information (db_version, +git_revision, r_version, deb_epoch, deb_revision) and the current date +(date_stamp). 'log' contains the output of the build process. + +A new 'deb_revision' is assigned to each successful build. + diff --git a/branch/multisys/inst/doc/DEPENDS b/branch/multisys/inst/doc/DEPENDS new file mode 100644 index 0000000..471f240 --- /dev/null +++ b/branch/multisys/inst/doc/DEPENDS @@ -0,0 +1,33 @@ +A dependency alias (created in populated_depend_aliases) is some name (such as +java) and some associated run and build time dependencies, specified like this: + + alias_build java openjdk-6-jdk + alias_build java libgcj9-dev + alias_run java openjdk-6-jre + +So when cran2deb needs to use the 'java' build dependency, it will add +"openjdk-6-jdk, libgcj9-dev" to the Build-Depends:. alias_run deals with +Depends: only. +Since in Debian you cannot Build-Depend: upon build-essential, there is a +special 'ignore' dependency alias (this can be handy for dropping unnecessary +system requirements) + + alias_build ignore build-essential + +populate_forcedep contains like: + + force java rJava + +which forces the R package rJava to use the dependency alias 'java'. This is +for cases where there is no SystemRequirement. + +Finally, populate_sysreq has lines like: + + sysreq quantlib quantlib% + +This says, whenever a part of a SystemRequirement matches the SQL LIKE pattern +'quantlib%', use the dependency alias. SystemRequirements are converted to +lower case and messed around with; details are in R/debcontrol.R in the +sysreqs_as_debian function. R/debcontrol.R contains pretty much all of the code +for dependencies (the database interface code is in R/db.R). + diff --git a/branch/multisys/inst/doc/INSTALL_NOTES b/branch/multisys/inst/doc/INSTALL_NOTES new file mode 100644 index 0000000..4d47890 --- /dev/null +++ b/branch/multisys/inst/doc/INSTALL_NOTES @@ -0,0 +1,56 @@ +git clone git://github.com/blundellc/cran2deb.git + +apt-get system requirements from DESCRIPTION +apt-get install cdbs + +# install a web server +apt-get install thttpd + +# add a group for cran2deb people +addgroup cran2deb +usermod -a -G cran2deb cb +usermod -a -G cran2deb edd + +# set up web space +mkdir /var/www/cran2deb +chgrp cran2deb /var/www/cran2deb +chmod 3775 /var/www/cran2deb + +# install prereq R packages +r -e "install.packages(c('ctv','RSQLite','DBI','digest'))" +R CMD INSTALL cran2deb + +# set up cran2deb space, as per README +cp /usr/local/lib/R/site-library/cran2deb/exec/cran2deb /usr/local/bin +root=$(cran2deb root) +mkdir /etc/cran2deb +chgrp cran2deb /etc/cran2deb +chmod 3775 /etc/cran2deb +copy ROOT/etc/* to /etc/cran2deb +ln -s /var/www/cran2deb/ /etc/cran2deb/archive +edit /etc/cran2deb/pbuilder.in: +OTHERMIRROR='deb http://localhost/users/cb/cran2deb/ unstable/$(ARCH)/ | deb http://localhost/users/cb/cran2deb/ unstable/all/' +MIRRORSITE='http://ftp.debian.org/debian/' +to +OTHERMIRROR='deb http://localhost/cran2deb/ unstable/$(ARCH)/ | deb http://localhost/cran2deb/ unstable/all/' +MIRRORSITE='http://ftp.at.debian.org/debian/' + +# fix permissions for group usage. +mkdir /var/cache/cran2deb +chgrp cran2deb /var/cache/cran2deb +chmod 3775 /var/cache/cran2deb +chgrp -R cran2deb $root +chmod 3775 $root +chmod -R g+w $root + +(log out then log in to get gid cran2deb) + +# build pbuilder archive, initialise database +cran2deb update + +# check it works +cran2deb build zoo + +# is handy +apt-get install sqlite3 + diff --git a/branch/multisys/inst/doc/PKG b/branch/multisys/inst/doc/PKG new file mode 100644 index 0000000..de0a4b2 --- /dev/null +++ b/branch/multisys/inst/doc/PKG @@ -0,0 +1,23 @@ +One of the key data structures using by cran2deb is commonly called 'pkg'. +It is constructed in R/getrpkg.R by prepare_pkg. prepare_pkg obtains +an R package and converts the source package into something suitable for use +with Debian. + +If a particular upstream version has already been used to create a Debian +package, then the source tarball of that upstream version is expected to be +available locally, and is used for building. In this case no conversion is +performed, so the archive does not change. In future it may be desirable to +obtain the source tarball from some central archive but this is not done at the +moment. + +download_pkg in R/getrpkg.R obtains the tarball (archive) of the R package, either +from the previous Debian build, or from the R archive. The field pkg$need_repack +indicates if the obtained archive must be repacked into a form acceptable +as a Debian source archive. This repacking, if necessary, is performed by +repack_pkg in R/getrpkg.R + + +Most of the creation of pkg is done by R/getrpkg.R. However some more build +specific operations (such as determining the new build version pkg$debversion) +are performed by R/debianpkg.R. + diff --git a/branch/multisys/inst/doc/README b/branch/multisys/inst/doc/README new file mode 100644 index 0000000..b521da0 --- /dev/null +++ b/branch/multisys/inst/doc/README @@ -0,0 +1,34 @@ +To install: + +$ cd .. +$ R CMD INSTALL cran2deb + +copy cran2deb/exec/cran2deb into somewhere in your executable path (e.g., +/usr/local/bin, $home/bin) + + + +To configure: + +1. You need a web server serving from say, /var/www/cran2deb/ + +Let ROOT be the value returned by running: cran2deb root + +2. create /etc/cran2deb + a. copy ROOT/etc/* into /etc/cran2deb + b. /etc/cran2deb/archive should be a symlink pointing to /var/www/cran2deb/ + + $ ln -s /var/www/cran2deb/ /etc/cran2deb/archive + + c. modify OTHERMIRROR of /etc/cran2deb/pbuilderrc.in to point to your webserver + +3. cran2deb needs a persistent cache outside of R's control. therefore, create + /var/cache/cran2deb, writable by whichever user(s) will run cran2deb. +4. run: cran2deb update +5. Try building a simple package: cran2deb build zoo + (The result will be in /var/cache/cran2deb/results) + + +$ cran2deb help +will display a short summary of help for each cran2deb command. + diff --git a/branch/multisys/inst/etc/dput.cf.in b/branch/multisys/inst/etc/dput.cf.in new file mode 100644 index 0000000..8ae0ca6 --- /dev/null +++ b/branch/multisys/inst/etc/dput.cf.in @@ -0,0 +1,8 @@ +[local] +method = local +incoming = /etc/cran2deb/archive/mini-dinstall/incoming +allow_non-us_software = 1 +run_dinstall = 0 +run_lintian = 1 +post_upload_command = /usr/bin/mini-dinstall --batch -c /etc/cran2deb/mini-dinstall.conf +allow_unsigned_uploads = 1 diff --git a/branch/multisys/inst/etc/hook/A80rjava b/branch/multisys/inst/etc/hook/A80rjava new file mode 100755 index 0000000..1d37c8b --- /dev/null +++ b/branch/multisys/inst/etc/hook/A80rjava @@ -0,0 +1,4 @@ +if [ -n "$(which java)" ] +then + R CMD javareconf +fi diff --git a/branch/multisys/inst/etc/hook/B90lintian b/branch/multisys/inst/etc/hook/B90lintian new file mode 100755 index 0000000..57fcfc4 --- /dev/null +++ b/branch/multisys/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/branch/multisys/inst/etc/hook/B91dpkg-i b/branch/multisys/inst/etc/hook/B91dpkg-i new file mode 100755 index 0000000..ee031bb --- /dev/null +++ b/branch/multisys/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/branch/multisys/inst/etc/hook/B92test-pkg b/branch/multisys/inst/etc/hook/B92test-pkg new file mode 100755 index 0000000..7372ca0 --- /dev/null +++ b/branch/multisys/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/branch/multisys/inst/etc/hook/D70aptupdate b/branch/multisys/inst/etc/hook/D70aptupdate new file mode 100755 index 0000000..4d42b3d --- /dev/null +++ b/branch/multisys/inst/etc/hook/D70aptupdate @@ -0,0 +1 @@ +/usr/bin/apt-get update diff --git a/branch/multisys/inst/etc/mini-dinstall.conf.in b/branch/multisys/inst/etc/mini-dinstall.conf.in new file mode 100644 index 0000000..56cd938 --- /dev/null +++ b/branch/multisys/inst/etc/mini-dinstall.conf.in @@ -0,0 +1,12 @@ +[DEFAULT] +architectures = all, i386, amd64 +use_dnotify = 0 +verify_sigs = 0 +mail_on_success = 0 +archive_style = simple-subdir +mail_log_level = NONE +archivedir = /etc/cran2deb/archive +logfile = @ROOT@/mini-dinstall.log + +[unstable] + diff --git a/branch/multisys/inst/etc/pbuilderrc.in b/branch/multisys/inst/etc/pbuilderrc.in new file mode 100644 index 0000000..076ee17 --- /dev/null +++ b/branch/multisys/inst/etc/pbuilderrc.in @@ -0,0 +1,12 @@ +BASETGZ=/var/cache/pbuilder/base-cran2deb.tgz +HOOKDIR=/etc/cran2deb/hook +BUILDRESULT=/var/cache/cran2deb/results +EXTRAPACKAGES='debhelper r-base-dev cdbs r-base-core lintian xvfb xauth xfonts-base' +REMOVEPACKAGES='lilo libldap-2.4-2 libopencdk10 libsasl2-2' +# don't actually need aptitude, but pbuilder insists... +#REMOVEPACKAGES+='aptitude libcwidget3 libept0 libncursesw5 libsigc++-2.0-0c2a libxapian15' +DISTRIBUTION=unstable +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'