11# !/usr/bin/env Rscript
2+
3+ # This script can be used to generate the .json file for a given R package set
4+ # that is part of the `rPackages` tree
5+ #
6+ # See R section of the nixpkgs manual for an example of how to use this script
7+
28library(data.table )
39library(parallel )
410library(BiocManager )
5- cl <- makeCluster(10 )
11+ library(jsonlite )
12+
13+ # always order strings according to POSIX ordering
14+ locale <- Sys.setlocale(locale = " C" )
615
716biocVersion <- BiocManager ::: .version_map()
817biocVersion <- biocVersion [biocVersion $ R == getRversion()[, 1 : 2 ],c(" Bioc" , " BiocStatus" )]
@@ -20,21 +29,25 @@ mirrorUrls <- list( bioc=paste0("http://bioconductor.org/packages/", biocVersion
2029
2130mirrorType <- commandArgs(trailingOnly = TRUE )[1 ]
2231stopifnot(mirrorType %in% names(mirrorUrls ))
23- packagesFile <- paste(mirrorType , ' packages.nix' , sep = ' -' )
24- readFormatted <- as.data.table(read.table(skip = 8 , sep = ' "' , text = head(readLines(packagesFile ), - 1 )))
32+
33+ packagesFile <- paste(mirrorType , ' packages.json' , sep = ' -' )
34+ prevPkgs <- fromJSON(packagesFile )$ packages
2535
2636write(paste(" downloading package lists" ), stderr())
27- knownPackages <- lapply(mirrorUrls , function (url ) as.data.table(available.packages(url , filters = c(" R_version" , " OS_type" , " duplicates" )), method = " libcurl" ))
28- pkgs <- knownPackages [mirrorType ][[1 ]]
29- setkey(pkgs , Package )
30- knownPackages <- c(unique(do.call(" rbind" , knownPackages )$ Package ))
31- knownPackages <- sapply(knownPackages , gsub , pattern = " ." , replacement = " _" , fixed = TRUE )
37+ pkgTables <- lapply(mirrorUrls , function (url ) as.data.table(available.packages(url , filters = c(" R_version" , " OS_type" , " duplicates" )), method = " libcurl" ))
38+ knownPackageNames <- c(unique(do.call(" rbind" , pkgTables )$ Package ))
3239
40+ pkgTable <- pkgTables [mirrorType ][[1 ]]
3341mirrorUrl <- mirrorUrls [mirrorType ][[1 ]]
42+
43+ escapeName <- function (name ) {
44+ gsub(" ." , " _" , switch (name , " import" = " r_import" , " assert" = " r_assert" , name ), fixed = TRUE )
45+ }
46+
3447nixPrefetch <- function (name , version ) {
35- prevV <- readFormatted $ V2 == name & readFormatted $ V4 == version
36- if (sum( prevV ) == 1 )
37- as.character( readFormatted $ V6 [ prevV ])
48+ prevPkg <- prevPkgs [[escapeName( name )]]
49+ if (! is.null( prevPkg ) && prevPkg $ version == version )
50+ prevPkg $ sha256
3851
3952 else {
4053 # avoid nix-prefetch-url because it often fails to fetch/hash large files
@@ -53,12 +66,7 @@ nixPrefetch <- function(name, version) {
5366
5467}
5568
56- escapeName <- function (name ) {
57- switch (name , " import" = " r_import" , " assert" = " r_assert" , name )
58- }
59-
6069formatPackage <- function (name , version , sha256 , depends , imports , linkingTo ) {
61- attr <- gsub(" ." , " _" , escapeName(name ), fixed = TRUE )
6270 options(warn = 5 )
6371 depends <- paste( if (is.na(depends )) " " else gsub(" [ \t\n ]+" , " " , depends )
6472 , if (is.na(imports )) " " else gsub(" [ \t\n ]+" , " " , imports )
@@ -67,48 +75,44 @@ formatPackage <- function(name, version, sha256, depends, imports, linkingTo) {
6775 )
6876 depends <- unlist(strsplit(depends , split = " ," , fixed = TRUE ))
6977 depends <- lapply(depends , gsub , pattern = " ([^ \t\n (]+).*" , replacement = " \\ 1" )
70- depends <- lapply(depends , gsub , pattern = " ." , replacement = " _" , fixed = TRUE )
71- depends <- depends [depends %in% knownPackages ]
78+ depends <- depends [depends %in% knownPackageNames ]
7279 depends <- lapply(depends , escapeName )
7380 depends <- paste(depends )
74- depends <- paste( sort(unique(depends )), collapse = " " )
75- paste0( " " , attr , " = derive2 { name=\" " , name , " \" ; version=\" " , version , " \" ; sha256=\" " , sha256 , " \" ; depends=[ " , depends , " ]; }; " )
81+ depends <- sort(unique(depends ))
82+ list ( name = unbox( name ), version = unbox( version ), sha256 = unbox( sha256 ), depends = depends )
7683}
7784
78- clusterExport(cl , c(" nixPrefetch" ," readFormatted" , " mirrorUrl" , " mirrorType" , " knownPackages" ))
79-
80- pkgs <- pkgs [order(Package )]
85+ cl <- makeCluster(10 )
86+ clusterExport(cl , c(" escapeName" , " nixPrefetch" , " prevPkgs" , " mirrorUrl" , " mirrorType" , " knownPackageNames" ))
8187
8288write(paste(" updating" , mirrorType , " packages" ), stderr())
83- pkgs $ sha256 <- parApply(cl , pkgs , 1 , function (p ) nixPrefetch(p [1 ], p [2 ]))
84- nix <- apply(pkgs , 1 , function (p ) formatPackage(p [1 ], p [2 ], p [18 ], p [4 ], p [5 ], p [6 ]))
85- write(" done" , stderr())
89+ pkgTable $ sha256 <- parApply(cl , pkgTable , 1 , function (p ) nixPrefetch(p [1 ], p [2 ]))
90+
91+ stopCluster(cl )
92+
93+ pkgs <- lapply(1 : nrow(pkgTable ), function (i ) with(pkgTable [i ,], formatPackage(Package , Version , sha256 , Depends , Imports , LinkingTo )))
94+ names(pkgs ) <- lapply(pkgs , function (p ) escapeName(p $ name ))
8695
8796# Mark deleted packages as broken
88- setkey(readFormatted , V2 )
89- markBroken <- function (name ) {
90- str <- paste0(readFormatted [name ], collapse = ' "' )
91- if (sum(grep(" broken = true;" , str )))
92- return (str )
93- write(paste(" marked" , name , " as broken" ), stderr())
94- gsub(" };$" , " broken = true; };" , str )
97+ brokenPkgs <- lapply(prevPkgs [setdiff(names(prevPkgs ), names(pkgs ))], function (p )
98+ list (name = unbox(p $ name ),
99+ version = unbox(p $ version ),
100+ sha256 = unbox(p $ sha256 ),
101+ depends = p $ depends ,
102+ broken = unbox(T )))
103+
104+ # sort packages by their non-escaped names
105+ pkgs <- pkgs [order(sapply(pkgs , function (p ) p $ name ))]
106+ brokenPkgs <- brokenPkgs [order(sapply(brokenPkgs , function (p ) p $ name ))]
107+
108+ # empty named list
109+ extraArgs = setNames(list (), character (0 ))
110+
111+ if (mirrorType != " cran" ) {
112+ extraArgs = list (biocVersion = unbox(paste(biocVersion )))
95113}
96- broken <- lapply(setdiff(readFormatted [[2 ]], pkgs [[1 ]]), markBroken )
97-
98- cat(" # This file is generated from generate-r-packages.R. DO NOT EDIT.\n " )
99- cat(" # Execute the following command to update the file.\n " )
100- cat(" #\n " )
101- cat(paste(" # Rscript generate-r-packages.R" , mirrorType , " >new && mv new" , packagesFile ))
102- cat(" \n\n " )
103- cat(" { self, derive }:\n " )
104- cat(" let derive2 = derive " )
105- if (mirrorType == " cran" ) { cat(" { }" )
106- } else if (mirrorType == " irkernel" ) { cat(" {}" )
107- } else { cat(" { biocVersion = \" " , biocVersion , " \" ; }" , sep = " " ) }
108- cat(" ;\n " )
109- cat(" in with self; {\n " )
110- cat(paste(nix , collapse = " \n " ), " \n " , sep = " " )
111- cat(paste(broken , collapse = " \n " ), " \n " , sep = " " )
112- cat(" }\n " )
113114
114- stopCluster(cl )
115+ cat(toJSON(list (extraArgs = extraArgs , packages = c(pkgs , brokenPkgs )), pretty = TRUE ))
116+ cat(" \n " )
117+ write(" done" , stderr())
118+
0 commit comments