@platforma-sdk/r-builder 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,293 @@
1
+ #!/bin/bash
2
+ # Shell wrapper for R executable.
3
+
4
+ if [ -z "${R_HOME_DIR}" ]; then
5
+ echo "'R_HOME_DIR' environment variable is not set. R cannot work not knowing where its root"
6
+ exit 1
7
+ fi
8
+
9
+ if test -n "${R_HOME}" && \
10
+ test "${R_HOME}" != "${R_HOME_DIR}"; then
11
+ echo "WARNING: ignoring environment value of R_HOME"
12
+ fi
13
+
14
+ R_ROOT_DIR="${R_HOME_DIR}"
15
+ export R_ROOT_DIR
16
+
17
+ RHOME="${R_HOME_DIR}"
18
+ export RHOME
19
+ R_HOME="${R_HOME_DIR}"
20
+ export R_HOME
21
+
22
+ R_SHARE_DIR="${R_HOME_DIR}/share"
23
+ export R_SHARE_DIR
24
+ R_INCLUDE_DIR="${R_HOME_DIR}/include"
25
+ export R_INCLUDE_DIR
26
+ R_DOC_DIR="${R_HOME_DIR}/doc"
27
+ export R_DOC_DIR
28
+
29
+ # Since this script can be called recursively, we allow R_ARCH to
30
+ # be overridden from the environment.
31
+ # This script is shared by parallel installs, so nothing in it should
32
+ # depend on the sub-architecture except the default here.
33
+ : ${R_ARCH=}
34
+
35
+ usage="
36
+ Usage: R [options] [< infile] [> outfile]
37
+ or: R CMD command [arguments]
38
+
39
+ Start R, a system for statistical computation and graphics, with the
40
+ specified options, or invoke an R tool via the 'R CMD' interface.
41
+
42
+ Options:
43
+ -h, --help Print short help message and exit
44
+ --version Print version info and exit
45
+ --encoding=ENC Specify encoding to be used for stdin
46
+ --encoding ENC
47
+ RHOME Print path to R home directory and exit
48
+ --save Do save workspace at the end of the session
49
+ --no-save Don't save it
50
+ --no-environ Don't read the site and user environment files
51
+ --no-site-file Don't read the site-wide Rprofile
52
+ --no-init-file Don't read the user R profile
53
+ --restore Do restore previously saved objects at startup
54
+ --no-restore-data Don't restore previously saved objects
55
+ --no-restore-history Don't restore the R history file
56
+ --no-restore Don't restore anything
57
+ --vanilla Combine --no-save, --no-restore, --no-site-file,
58
+ --no-init-file and --no-environ
59
+ --no-readline Don't use readline for command-line editing
60
+ --max-ppsize=N Set max size of protect stack to N
61
+ --min-nsize=N Set min number of fixed size obj's (\"cons cells\") to N
62
+ --min-vsize=N Set vector heap minimum to N bytes; '4M' = 4 MegaB
63
+ -q, --quiet Don't print startup message
64
+ --silent Same as --quiet
65
+ -s, --no-echo Make R run as quietly as possible
66
+ --interactive Force an interactive session
67
+ --verbose Print more information about progress
68
+ -d, --debugger=NAME Run R through debugger NAME
69
+ --debugger-args=ARGS Pass ARGS as arguments to the debugger
70
+ -g TYPE, --gui=TYPE Use TYPE as GUI; possible values are 'X11' (default)
71
+ and 'Tk'.
72
+ --arch=NAME Specify a sub-architecture
73
+ --args Skip the rest of the command line
74
+ -f FILE, --file=FILE Take input from 'FILE'
75
+ -e EXPR Execute 'EXPR' and exit
76
+
77
+ FILE may contain spaces but not shell metacharacters.
78
+
79
+ Commands:
80
+ BATCH Run R in batch mode
81
+ COMPILE Compile files for use with R
82
+ SHLIB Build shared library for dynamic loading
83
+ INSTALL Install add-on packages
84
+ REMOVE Remove add-on packages
85
+ build Build add-on packages
86
+ check Check add-on packages
87
+ LINK Front-end for creating executable programs
88
+ Rprof Post-process R profiling files
89
+ Rdconv Convert Rd format to various other formats
90
+ Rd2pdf Convert Rd format to PDF
91
+ Rd2txt Convert Rd format to pretty text
92
+ Stangle Extract S/R code from Sweave documentation
93
+ Sweave Process Sweave documentation
94
+ Rdiff Diff R output ignoring headers etc
95
+ config Obtain configuration information about R
96
+ javareconf Update the Java configuration variables
97
+ rtags Create Emacs-style tag files from C, R, and Rd files
98
+
99
+ Please use 'R CMD command --help' to obtain further information about
100
+ the usage of 'command'.
101
+
102
+ Options --arch, --no-environ, --no-init-file, --no-site-file and --vanilla
103
+ can be placed between R and CMD, to apply to R processes run by 'command'
104
+
105
+ Report bugs at <https://bugs.R-project.org>."
106
+
107
+ ## some systems have a more portable sed, e.g. /usr/xpg4/bin/sed on Solaris,
108
+ ## so make sure that is used.
109
+ SED=/usr/bin/sed
110
+ export SED
111
+
112
+ error () {
113
+ echo "ERROR: $*" >&2
114
+ exit 1
115
+ }
116
+
117
+ ### Argument loop
118
+ args=
119
+ debugger=
120
+ debugger_args=
121
+ gui=
122
+ while test -n "${1}"; do
123
+ case ${1} in
124
+ RHOME|--print-home)
125
+ echo "${R_HOME}"; exit 0 ;;
126
+ CMD)
127
+ shift;
128
+ export R_ARCH
129
+ . "${R_HOME}/etc${R_ARCH}/ldpaths"
130
+ exec sh "${R_HOME}/bin/Rcmd" "${@}" ;;
131
+ -g|--gui)
132
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
133
+ gui="${2}"
134
+ args="${args} ${1} ${2}"
135
+ shift
136
+ else
137
+ error "option '${1}' requires an argument"
138
+ fi
139
+ ;;
140
+ --gui=*)
141
+ gui=`echo "${1}" | ${SED} -e 's/[^=]*=//'`
142
+ args="${args} ${1}"
143
+ ;;
144
+ -d|--debugger)
145
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
146
+ debugger="${2}"; shift
147
+ else
148
+ error "option '${1}' requires an argument"
149
+ fi
150
+ ;;
151
+ --debugger=*)
152
+ debugger=`echo "${1}" | ${SED} -e 's/[^=]*=//'` ;;
153
+ --debugger-args=*)
154
+ debugger_args=`echo "${1}" | ${SED} -e 's/[^=]*=//'` ;;
155
+ -h|--help)
156
+ echo "${usage}"; exit 0 ;;
157
+ --args)
158
+ break ;;
159
+ --arch)
160
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
161
+ R_ARCH="/${2}"
162
+ shift
163
+ else
164
+ error "option '${1}' requires an argument"
165
+ fi
166
+ ## check sub-architecture here for a better error message
167
+ if ! test -d ${R_HOME}/etc${R_ARCH}; then
168
+ error "sub-architecture '${1}' is not installed"
169
+ fi
170
+ ;;
171
+ --arch=*)
172
+ r_arch=`echo "${1}" | ${SED} -e 's/[^=]*=//'`
173
+ R_ARCH="/${r_arch}"
174
+ ## check sub-architecture here for a better error message
175
+ if ! test -d ${R_HOME}/etc${R_ARCH}; then
176
+ error "sub-architecture '${r_arch}' is not installed"
177
+ fi
178
+ ;;
179
+ -e)
180
+ TAB=`printf "\t"`
181
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
182
+ a=`(echo "${2}" && echo) | ${SED} -e 's/ /~+~/g' | \
183
+ ${SED} -e :a -e N -e '$!ba' -e 's/\n/~n~/g' -e 's/~n~$//g' -e "s/$TAB/~t~/g"`
184
+ shift
185
+ else
186
+ error "option '${1}' requires a non-empty argument"
187
+ fi
188
+ args="${args} -e $a"
189
+ ;;
190
+ -f)
191
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
192
+ a=`echo "${2}" | ${SED} -e 's/ /~+~/g'`; shift
193
+ else
194
+ error "option '${1}' requires a filename argument"
195
+ fi
196
+ args="${args} -f $a"
197
+ ;;
198
+ --file=*)
199
+ a=`echo "${1}" | ${SED} -e 's/[^=]*=//' | ${SED} -e 's/ /~+~/g'`
200
+ args="${args} --file=$a"
201
+ ;;
202
+ --no-environ)
203
+ R_ENVIRON=''
204
+ export R_ENVIRON
205
+ R_ENVIRON_USER=''
206
+ export R_ENVIRON_USER
207
+ args="${args} ${1}"
208
+ ;;
209
+ --no-site-file)
210
+ R_PROFILE=''
211
+ export R_PROFILE
212
+ args="${args} ${1}"
213
+ ;;
214
+ --no-init-file)
215
+ R_PROFILE_USER=''
216
+ export R_PROFILE_USER
217
+ args="${args} ${1}"
218
+ ;;
219
+ --vanilla)
220
+ R_ENVIRON=''
221
+ export R_ENVIRON
222
+ R_ENVIRON_USER=''
223
+ export R_ENVIRON_USER
224
+ R_PROFILE=''
225
+ export R_PROFILE
226
+ R_PROFILE_USER=''
227
+ export R_PROFILE_USER
228
+ args="${args} ${1}"
229
+ ;;
230
+ *)
231
+ args="${args} ${1}" ;;
232
+ esac
233
+ shift
234
+ done
235
+
236
+ . "${R_HOME}/etc${R_ARCH}/ldpaths"
237
+
238
+ R_binary="${R_HOME}/bin/exec${R_ARCH}/R"
239
+ export R_ARCH
240
+
241
+ case "${gui}" in
242
+ Tk|tk|X11|x11)
243
+ ;;
244
+ "")
245
+ ;;
246
+ *)
247
+ error "unknown GUI ${gui}"
248
+ esac
249
+
250
+ ## R_HOME may have moved, so check
251
+ if test -x "${R_HOME}"; then
252
+ :
253
+ else
254
+ error "R_HOME ('${R_HOME}') not found"
255
+ fi
256
+
257
+ ## Startup
258
+ if test -z "${debugger}"; then
259
+ exec "${R_binary}" ${args} "${@}"
260
+ else
261
+ ## Ideally, we would like the debugger to start R with additional
262
+ ## ('inferior') arguments, but not all debuggers can do this. We know
263
+ ## about valgrind and some versions of GDB , and deal with these.
264
+ ## Otherwise, to be on the safe side, we disregard non-debugger
265
+ ## command line args.
266
+ args_ok=no
267
+ case "`${debugger} --version 2>/dev/null`" in
268
+ "GNU gdb"*)
269
+ if ${debugger} --help 2>/dev/null | \
270
+ grep ' *--args' >/dev/null; then
271
+ args_ok=yes
272
+ debugger_args="${debugger_args} --args"
273
+ fi
274
+ ;;
275
+ valgrind*)
276
+ args_ok=yes
277
+ ;;
278
+ esac
279
+ if test -n "${args}${*}" && test "${args_ok}" = no; then
280
+ args=`expr "${args} ${*}" : " *\(.*\)"`
281
+ echo "*** Further command line arguments ('${args}') disregarded"
282
+ echo "*** (maybe use 'run ${args}' from *inside* ${debugger})"
283
+ echo ""
284
+ exec ${debugger} ${debugger_args} "${R_binary}"
285
+ else
286
+ exec ${debugger} ${debugger_args} "${R_binary}" ${args} "${@}"
287
+ fi
288
+ fi
289
+
290
+ ### Local Variables: ***
291
+ ### mode: sh ***
292
+ ### sh-indentation: 2 ***
293
+ ### End: ***
@@ -0,0 +1,290 @@
1
+ #!/bin/sh
2
+ # Shell wrapper for R executable.
3
+
4
+ if [ -z "${R_HOME_DIR}" ]; then
5
+ echo "'R_HOME_DIR' environment variable is not set. R cannot work not knowing where its root"
6
+ exit 1
7
+ fi
8
+
9
+ if test -n "${R_HOME}" && \
10
+ test "${R_HOME}" != "${R_HOME_DIR}"; then
11
+ echo "WARNING: ignoring environment value of R_HOME"
12
+ fi
13
+
14
+ RHOME="${R_HOME_DIR}" # this is for Rscript. It checks RHOME instead of R_HOME in some versions
15
+ export RHOME
16
+ R_HOME="${R_HOME_DIR}"
17
+ export R_HOME
18
+ R_SHARE_DIR="${R_HOME_DIR}/share"
19
+ export R_SHARE_DIR
20
+ R_INCLUDE_DIR="${R_HOME_DIR}/include"
21
+ export R_INCLUDE_DIR
22
+ R_DOC_DIR="${R_HOME_DIR}/doc"
23
+ export R_DOC_DIR
24
+
25
+ # Since this script can be called recursively, we allow R_ARCH to
26
+ # be overridden from the environment.
27
+ # This script is shared by parallel installs, so nothing in it should
28
+ # depend on the sub-architecture except the default here.
29
+ : ${R_ARCH=}
30
+
31
+ usage="
32
+ Usage: R [options] [< infile] [> outfile]
33
+ or: R CMD command [arguments]
34
+
35
+ Start R, a system for statistical computation and graphics, with the
36
+ specified options, or invoke an R tool via the 'R CMD' interface.
37
+
38
+ Options:
39
+ -h, --help Print short help message and exit
40
+ --version Print version info and exit
41
+ --encoding=ENC Specify encoding to be used for stdin
42
+ --encoding ENC
43
+ RHOME Print path to R home directory and exit
44
+ --save Do save workspace at the end of the session
45
+ --no-save Don't save it
46
+ --no-environ Don't read the site and user environment files
47
+ --no-site-file Don't read the site-wide Rprofile
48
+ --no-init-file Don't read the user R profile
49
+ --restore Do restore previously saved objects at startup
50
+ --no-restore-data Don't restore previously saved objects
51
+ --no-restore-history Don't restore the R history file
52
+ --no-restore Don't restore anything
53
+ --vanilla Combine --no-save, --no-restore, --no-site-file,
54
+ --no-init-file and --no-environ
55
+ --no-readline Don't use readline for command-line editing
56
+ --max-connections=N Set max number of connections to N
57
+ --max-ppsize=N Set max size of protect stack to N
58
+ --min-nsize=N Set min number of fixed size obj's (\"cons cells\") to N
59
+ --min-vsize=N Set vector heap minimum to N bytes; '4M' = 4 MegaB
60
+ -q, --quiet Don't print startup message
61
+ --silent Same as --quiet
62
+ -s, --no-echo Make R run as quietly as possible
63
+ --interactive Force an interactive session
64
+ --verbose Print more information about progress
65
+ -d, --debugger=NAME Run R through debugger NAME
66
+ --debugger-args=ARGS Pass ARGS as arguments to the debugger
67
+ -g TYPE, --gui=TYPE Use TYPE as GUI; possible values are 'X11' (default)
68
+ and 'Tk'.
69
+ --arch=NAME Specify a sub-architecture
70
+ --args Skip the rest of the command line
71
+ -f FILE, --file=FILE Take input from 'FILE'
72
+ -e EXPR Execute 'EXPR' and exit
73
+
74
+ FILE may contain spaces but not shell metacharacters.
75
+
76
+ Commands:
77
+ BATCH Run R in batch mode
78
+ COMPILE Compile files for use with R
79
+ SHLIB Build shared library for dynamic loading
80
+ INSTALL Install add-on packages
81
+ REMOVE Remove add-on packages
82
+ build Build add-on packages
83
+ check Check add-on packages
84
+ LINK Front-end for creating executable programs
85
+ Rprof Post-process R profiling files
86
+ Rdconv Convert Rd format to various other formats
87
+ Rd2pdf Convert Rd format to PDF
88
+ Rd2txt Convert Rd format to pretty text
89
+ Stangle Extract S/R code from Sweave documentation
90
+ Sweave Process Sweave documentation
91
+ Rdiff Diff R output ignoring headers etc
92
+ config Obtain configuration information about R
93
+ javareconf Update the Java configuration variables
94
+ rtags Create Emacs-style tag files from C, R, and Rd files
95
+
96
+ Please use 'R CMD command --help' to obtain further information about
97
+ the usage of 'command'.
98
+
99
+ Options --arch, --no-environ, --no-init-file, --no-site-file and --vanilla
100
+ can be placed between R and CMD, to apply to R processes run by 'command'
101
+
102
+ Report bugs at <https://bugs.R-project.org>."
103
+
104
+ ## some systems have a more portable sed, e.g. /usr/xpg4/bin/sed on Solaris,
105
+ ## so make sure that is used.
106
+ SED=/usr/bin/sed
107
+ export SED
108
+
109
+ error () {
110
+ echo "ERROR: $*" >&2
111
+ exit 1
112
+ }
113
+
114
+ ### Argument loop
115
+ args=
116
+ debugger=
117
+ debugger_args=
118
+ gui=
119
+ while test -n "${1}"; do
120
+ case ${1} in
121
+ RHOME|--print-home)
122
+ echo "${R_HOME}"; exit 0 ;;
123
+ CMD)
124
+ shift;
125
+ export R_ARCH
126
+ . "${R_HOME}/etc${R_ARCH}/ldpaths"
127
+ exec sh "${R_HOME}/bin/Rcmd" "${@}" ;;
128
+ -g|--gui)
129
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
130
+ gui="${2}"
131
+ args="${args} ${1} ${2}"
132
+ shift
133
+ else
134
+ error "option '${1}' requires an argument"
135
+ fi
136
+ ;;
137
+ --gui=*)
138
+ gui=`echo "${1}" | ${SED} -e 's/[^=]*=//'`
139
+ args="${args} ${1}"
140
+ ;;
141
+ -d|--debugger)
142
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
143
+ debugger="${2}"; shift
144
+ else
145
+ error "option '${1}' requires an argument"
146
+ fi
147
+ ;;
148
+ --debugger=*)
149
+ debugger=`echo "${1}" | ${SED} -e 's/[^=]*=//'` ;;
150
+ --debugger-args=*)
151
+ debugger_args=`echo "${1}" | ${SED} -e 's/[^=]*=//'` ;;
152
+ -h|--help)
153
+ echo "${usage}"; exit 0 ;;
154
+ --args)
155
+ break ;;
156
+ --arch)
157
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
158
+ R_ARCH="/${2}"
159
+ shift
160
+ else
161
+ error "option '${1}' requires an argument"
162
+ fi
163
+ ## check sub-architecture here for a better error message
164
+ if ! test -d ${R_HOME}/etc${R_ARCH}; then
165
+ error "sub-architecture '${1}' is not installed"
166
+ fi
167
+ ;;
168
+ --arch=*)
169
+ r_arch=`echo "${1}" | ${SED} -e 's/[^=]*=//'`
170
+ R_ARCH="/${r_arch}"
171
+ ## check sub-architecture here for a better error message
172
+ if ! test -d ${R_HOME}/etc${R_ARCH}; then
173
+ error "sub-architecture '${r_arch}' is not installed"
174
+ fi
175
+ ;;
176
+ -e)
177
+ TAB=`printf "\t"`
178
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
179
+ a=`(echo "${2}" && echo) | ${SED} -e 's/ /~+~/g' | \
180
+ ${SED} -e :a -e N -e '$!ba' -e 's/\n/~n~/g' -e 's/~n~$//g' -e "s/$TAB/~t~/g"`
181
+ shift
182
+ else
183
+ error "option '${1}' requires a non-empty argument"
184
+ fi
185
+ args="${args} -e $a"
186
+ ;;
187
+ -f)
188
+ if test -n "`echo ${2} | ${SED} 's/^-.*//'`"; then
189
+ a=`echo "${2}" | ${SED} -e 's/ /~+~/g'`; shift
190
+ else
191
+ error "option '${1}' requires a filename argument"
192
+ fi
193
+ args="${args} -f $a"
194
+ ;;
195
+ --file=*)
196
+ a=`echo "${1}" | ${SED} -e 's/[^=]*=//' | ${SED} -e 's/ /~+~/g'`
197
+ args="${args} --file=$a"
198
+ ;;
199
+ --no-environ)
200
+ R_ENVIRON=''
201
+ export R_ENVIRON
202
+ R_ENVIRON_USER=''
203
+ export R_ENVIRON_USER
204
+ args="${args} ${1}"
205
+ ;;
206
+ --no-site-file)
207
+ R_PROFILE=''
208
+ export R_PROFILE
209
+ args="${args} ${1}"
210
+ ;;
211
+ --no-init-file)
212
+ R_PROFILE_USER=''
213
+ export R_PROFILE_USER
214
+ args="${args} ${1}"
215
+ ;;
216
+ --vanilla)
217
+ R_ENVIRON=''
218
+ export R_ENVIRON
219
+ R_ENVIRON_USER=''
220
+ export R_ENVIRON_USER
221
+ R_PROFILE=''
222
+ export R_PROFILE
223
+ R_PROFILE_USER=''
224
+ export R_PROFILE_USER
225
+ args="${args} ${1}"
226
+ ;;
227
+ *)
228
+ args="${args} ${1}" ;;
229
+ esac
230
+ shift
231
+ done
232
+
233
+ . "${R_HOME}/etc${R_ARCH}/ldpaths"
234
+
235
+ R_binary="${R_HOME}/bin/exec${R_ARCH}/R"
236
+ export R_ARCH
237
+
238
+ case "${gui}" in
239
+ Tk|tk|X11|x11)
240
+ ;;
241
+ "")
242
+ ;;
243
+ *)
244
+ error "unknown GUI ${gui}"
245
+ esac
246
+
247
+ ## R_HOME may have moved, so check
248
+ if test -x "${R_HOME}"; then
249
+ :
250
+ else
251
+ error "R_HOME ('${R_HOME}') not found"
252
+ fi
253
+
254
+ ## Startup
255
+ if test -z "${debugger}"; then
256
+ exec "${R_binary}" ${args} "${@}"
257
+ else
258
+ ## Ideally, we would like the debugger to start R with additional
259
+ ## ('inferior') arguments, but not all debuggers can do this. We know
260
+ ## about valgrind and some versions of GDB , and deal with these.
261
+ ## Otherwise, to be on the safe side, we disregard non-debugger
262
+ ## command line args.
263
+ args_ok=no
264
+ case "`${debugger} --version 2>/dev/null`" in
265
+ "GNU gdb"*)
266
+ if ${debugger} --help 2>/dev/null | \
267
+ grep ' *--args' >/dev/null; then
268
+ args_ok=yes
269
+ debugger_args="${debugger_args} --args"
270
+ fi
271
+ ;;
272
+ valgrind*)
273
+ args_ok=yes
274
+ ;;
275
+ esac
276
+ if test -n "${args}${*}" && test "${args_ok}" = no; then
277
+ args=`expr "${args} ${*}" : " *\(.*\)"`
278
+ echo "*** Further command line arguments ('${args}') disregarded"
279
+ echo "*** (maybe use 'run ${args}' from *inside* ${debugger})"
280
+ echo ""
281
+ exec ${debugger} ${debugger_args} "${R_binary}"
282
+ else
283
+ exec ${debugger} ${debugger_args} "${R_binary}" ${args} "${@}"
284
+ fi
285
+ fi
286
+
287
+ ### Local Variables: ***
288
+ ### mode: sh ***
289
+ ### sh-indentation: 2 ***
290
+ ### End: ***
@@ -0,0 +1,96 @@
1
+ library(pkgdepends)
2
+
3
+ repo_root <- "."
4
+
5
+ cut_prefix <- function(str, prefix) {
6
+ if (startsWith(str, prefix)) {
7
+ return(substr(str, nchar(prefix) + 1, nchar(str)))
8
+ }
9
+
10
+ return(str)
11
+ }
12
+
13
+ ensure_parent_dir_exists <- function(target_file) {
14
+ if (file.exists(dirname(target_file))) {
15
+ return()
16
+ }
17
+
18
+ dir.create(dirname(target_file), recursive = TRUE)
19
+ }
20
+
21
+ get_path_depth <- function(target_file) {
22
+ path_depth <- 0
23
+ while (TRUE) {
24
+ parent_path <- dirname(target_file)
25
+ if (parent_path == target_file) {
26
+ return(path_depth)
27
+ }
28
+ target_file <- parent_path
29
+ path_depth <- path_depth + 1
30
+ }
31
+ }
32
+
33
+ get_package <- function(url, dest_name, ...) {
34
+ destfile <- file.path(repo_root, dest_name)
35
+ if (!file.exists(destfile)) {
36
+ ensure_parent_dir_exists(destfile)
37
+ download.file(url, destfile, ...)
38
+ }
39
+
40
+ return()
41
+ }
42
+
43
+ create_alias <- function(original_name, alias_name) {
44
+ if (file.exists(alias_name)) {
45
+ return()
46
+ }
47
+
48
+ ensure_parent_dir_exists(alias_name)
49
+ depth <- get_path_depth(alias_name)
50
+ depth <- depth - 1 # don't count file name it
51
+
52
+ relative <- "."
53
+ for (i in seq_len(depth)) {
54
+ relative <- file.path(relative, "..")
55
+ }
56
+
57
+ file.symlink(file.path(relative, original_name), alias_name)
58
+ }
59
+
60
+ pkgs <- commandArgs(trailingOnly = TRUE) # "openssl@2.2.2", "openssl@2.3.0"
61
+ print("Loading packages and their dependencies:")
62
+ print(pkgs)
63
+
64
+ pdl <- new_pkg_download_proposal(pkgs)
65
+ pdl$resolve()
66
+ deps <- pdl$get_resolution()
67
+
68
+ for (i in seq_len(nrow(deps))) {
69
+ urls <- deps$sources[i][[1]]
70
+ dest <- deps$target[i]
71
+ get_package(urls[1], dest)
72
+
73
+ if (length(urls) > 1) {
74
+ base_url <- deps$mirror[i]
75
+
76
+ for (i in 2:length(urls)) {
77
+ additional_url <- urls[i]
78
+ alias <- cut_prefix(additional_url, paste0(base_url, "/"))
79
+ create_alias(dest, alias)
80
+ }
81
+ }
82
+ }
83
+
84
+ repos <- unique(deps$repodir)
85
+ for (repo_name in repos) {
86
+ if (startsWith(repo_name, "bin/")) {
87
+ tools::write_PACKAGES(
88
+ file.path(repo_root, repo_name),
89
+ type = "mac.binary",
90
+ )
91
+ } else {
92
+ tools::write_PACKAGES(file.path(repo_root, repo_name))
93
+ }
94
+ }
95
+
96
+ warnings()
Binary file
package/package.json CHANGED
@@ -2,8 +2,9 @@
2
2
  "name": "@platforma-sdk/r-builder",
3
3
  "description": "Build R run environment for Platforma",
4
4
  "type": "module",
5
- "version": "0.0.1",
5
+ "version": "0.0.3",
6
6
  "files": [
7
+ "assets/",
7
8
  "scripts/"
8
9
  ],
9
10
  "bin": {
@@ -11,12 +12,10 @@
11
12
  },
12
13
  "license": "UNLICENSED",
13
14
  "dependencies": {
14
- "undici": "~7.2.3",
15
+ "undici": "~7.4.0",
15
16
  "fs-extra": "^11.2.0",
16
17
  "tar": "^7.4.3",
17
- "unzipper": "^0.12.3",
18
- "winston": "^3.17.0",
19
- "xz": "^2.0.2"
18
+ "winston": "^3.17.0"
20
19
  },
21
20
  "devDependencies": {
22
21
  "@milaboratories/eslint-config": "^1.0.1"
@@ -22,12 +22,6 @@ import * as windows from './lib/windows.js';
22
22
 
23
23
  export async function buildRDist(logger, version) {
24
24
  const currentOS = os.platform();
25
-
26
- const doneFile = `${version}.build-done`
27
- if (fs.existsSync(doneFile)) {
28
- logger.info(`Build of R is already done in this environment.\nTo force rebuild remove '${path.resolve(doneFile)}' file and run again.`)
29
- return
30
- }
31
25
 
32
26
  switch (currentOS) {
33
27
  case 'darwin': {
@@ -50,8 +44,6 @@ export async function buildRDist(logger, version) {
50
44
  process.exit(1);
51
45
  }
52
46
  }
53
-
54
- fs.writeFileSync(doneFile, '');
55
47
  }
56
48
 
57
49
  export async function buildRDeps(logger, version) {
@@ -7,6 +7,39 @@ import * as util from './util.js';
7
7
 
8
8
  const platformName = os.arch() === 'arm64' ? 'linux-aarch64' : `linux-x64`;
9
9
 
10
+ function useCaching(logger) {
11
+ if (util.isOK('which ccache')) {
12
+ useCCache(logger)
13
+ } else if (util.isOK('which sccache')) {
14
+ useSCCache(logger)
15
+ } else {
16
+ logger.warn('No caching tool found. Builds will be slow.')
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Setup current process environment to integrate with sccache
22
+ *
23
+ * @param {winston.Logger} logger
24
+ */
25
+ function useSCCache(logger) {
26
+ logger.info("Using sccache as build caching tool...")
27
+ process.env.SCCACHE_GHA_ENABLED = "true"
28
+ process.env.CC = `sccache gcc`
29
+ process.env.CXX = `sccache g++`
30
+ }
31
+
32
+ /**
33
+ * Setup current process environment to integrate with ccache
34
+ *
35
+ * @param {winston.Logger} logger
36
+ */
37
+ function useCCache(logger) {
38
+ logger.info("Using ccache as build caching tool...")
39
+ process.env.CC = `ccache gcc`
40
+ process.env.CXX = `ccache g++`
41
+ }
42
+
10
43
  async function installSystemPackages(logger) {
11
44
  const originalAptSources = '/etc/apt/sources.list';
12
45
  logger.info(`Analyzing '${originalAptSources}'`);
@@ -224,19 +257,6 @@ function patchBinElf(logger, binaryFile, rpath) {
224
257
  util.runInherit(`patchelf --remove-rpath '${binaryFile}'`);
225
258
  util.runInherit(`patchelf --set-rpath '${rpath}' '${binaryFile}'`);
226
259
  }
227
- /**
228
- * Setup current process environment to integrate with sccache
229
- *
230
- * @param {winston.Logger} logger
231
- */
232
- function useSCCache(logger) {
233
- if (util.isOK('which sccache')) {
234
- logger.info("Using sccache as build caching tool...")
235
- process.env.SCCACHE_GHA_ENABLED = "true"
236
- process.env.CC = `sccache gcc`
237
- process.env.CXX = `sccache g++`
238
- }
239
- }
240
260
 
241
261
  /**
242
262
  * Build portable R distribution and all required packages from sources
@@ -250,7 +270,7 @@ export async function buildR(logger, version) {
250
270
  process.exit(1);
251
271
  }
252
272
 
253
- useSCCache(logger)
273
+ useCaching(logger)
254
274
 
255
275
  const distDir = path.join(util.rDistDir, platformName);
256
276
 
@@ -267,6 +287,7 @@ export async function buildR(logger, version) {
267
287
 
268
288
  fs.renameSync(path.join(distDir, 'bin/R'), path.join(distDir, 'bin/R.orig'))
269
289
  fs.copyFileSync(pkg.asset('R.linux.sh'), path.join(distDir, 'bin/R'));
290
+ fs.chmodSync(path.join(distDir, 'bin/R'), 0o755)
270
291
 
271
292
  const gccVersion = getGCCMajorVersion()
272
293
  const gccUtilsPath = path.join('/usr/lib/gcc/x86_64-linux-gnu', gccVersion.toString())
@@ -280,7 +301,7 @@ export async function buildDeps(logger, version) {
280
301
  process.exit(1);
281
302
  }
282
303
 
283
- useSCCache(logger);
304
+ useCaching(logger);
284
305
 
285
306
  const distDir = path.join(util.rDistDir, platformName);
286
307
 
@@ -52,6 +52,7 @@ export async function buildR(logger, version) {
52
52
 
53
53
  fs.renameSync(path.join(distDir, 'bin/R'), path.join(distDir, 'bin/R.orig'))
54
54
  fs.copyFileSync(pkg.asset('R.macos.sh'), path.join(distDir, 'bin/R'))
55
+ fs.chmodSync(path.join(distDir, 'bin/R'), 0o755)
55
56
 
56
57
  util.installBasicRPackages(logger, distDir);
57
58
  }
@@ -2,10 +2,10 @@ import * as nodePath from 'node:path';
2
2
 
3
3
  const _root = nodePath.resolve(nodePath.join(import.meta.dirname, '..', '..'))
4
4
 
5
- export function path(p) {
5
+ export function path(...p) {
6
6
  return nodePath.join(_root, ...p);
7
7
  }
8
8
 
9
- export function asset(p) {
9
+ export function asset(...p) {
10
10
  return path('assets', ...p)
11
11
  }
@@ -20,7 +20,10 @@ export const downloadsDir = `${buildDir}/artifacts/dld`;
20
20
  export const artifactsDir = `${buildDir}/artifacts/pkg`;
21
21
 
22
22
  export const dependenciesDir = 'dependencies'; // where to search for dependencies specification (init.R or renv.lock)
23
- const renvDirName = 'renv-root' // directory with all renv cache stored inside final R run environment distribution
23
+
24
+ // directory with all renv cache stored inside final R run environment distribution.
25
+ // When changing this name, remember to update R preparation steps in workflow-tengo SDK.
26
+ const renvDirName = 'renv-root'
24
27
 
25
28
  const pipelineAsync = promisify(pipeline);
26
29
 
@@ -134,15 +137,10 @@ export async function download(logger, url, destination) {
134
137
  }
135
138
 
136
139
  export async function extractTarXz(archivePath, destination) {
137
- const archiveStream = fs.createReadStream(archivePath);
138
-
139
- const decompress = new xz.Decompressor();
140
-
141
- await pipelineAsync(
142
- archiveStream,
143
- decompress,
144
- tar.extract({ cwd: destination })
145
- );
140
+ if (!fs.existsSync(destination)) {
141
+ fs.mkdirSync(destination, { recursive: true });
142
+ }
143
+ runInherit(`tar -xJf '${archivePath}' -C '${destination}'`);
146
144
  }
147
145
 
148
146
  export async function extractTarGz(archivePath, destination) {
@@ -234,7 +232,9 @@ export function createLogger(level = 'debug') {
234
232
 
235
233
  format: winston.format.combine(
236
234
  winston.format.printf(({ level, message }) => {
237
- const indent = ' '.repeat(level.length + 2); // For ': ' after the level
235
+ const now = new Date();
236
+ const time = `[${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}]`;
237
+ const indent = ' '.repeat(time.length + 1 + level.length + 2); // For ': ' after the level
238
238
  const indentedMessage = message
239
239
  .split('\n')
240
240
  .map((line, index) => (index === 0 ? line : indent + line))
@@ -242,7 +242,7 @@ export function createLogger(level = 'debug') {
242
242
 
243
243
  const colorize = (l) => winston.format.colorize().colorize(l, l);
244
244
 
245
- return `${colorize(level)}: ${indentedMessage}`;
245
+ return `${time} ${colorize(level)}: ${indentedMessage}`;
246
246
  })
247
247
  ),
248
248
 
@@ -270,7 +270,7 @@ export function runR(logger, rRoot, args, opts = {}) {
270
270
  const cmdToRun = `${path.resolve(rRoot, 'bin/R')} ${args.join(' ')}`;
271
271
  const renvRoot = path.join(path.resolve(rRoot), renvDirName)
272
272
 
273
- env = {
273
+ const env = {
274
274
  RHOME: path.resolve(rRoot),
275
275
  R_HOME_DIR: path.resolve(rRoot),
276
276
  RENV_PATHS_ROOT: renvRoot,
@@ -403,22 +403,25 @@ export function buildRDependencies(
403
403
  '--no-echo',
404
404
  '-e', ...quote(`renv::restore( clean = TRUE )`),
405
405
  ], {
406
- wd: tempRenvDir,
406
+ wd: depsDir,
407
407
  paths: additionalPaths,
408
408
  })
409
409
 
410
+ } else if (fs.existsSync(path.join(depsDir, initFile))) {
411
+ runInRenv(logger, rRoot, ['--no-echo', `--file=${initFile}`], {
412
+ wd: depsDir,
413
+ paths: additionalPaths,
414
+ })
415
+
416
+ if (!fs.existsSync(path.join(depsDir, lockFile))) {
417
+ runInRenv(logger, rRoot, ['--no-echo', '-e', ...quote(`renv::snapshot()`)])
418
+ }
419
+
410
420
  } else {
411
- if (!fs.existsSync(path.join(depsDir, initFile))) {
412
421
  throw new Error(
413
422
  `directory ${depsDir} has no ${lockFile} or ${initFile}. No dependencies detected.\n`+
414
423
  `Create empty init.R file if you really need empty R run environment without any preinstalled dependencies`
415
424
  )
416
- }
417
-
418
- runInRenv(logger, rRoot, ['--no-echo', `--file=${initFile}`], {
419
- wd: tempRenvDir,
420
- paths: additionalPaths,
421
- })
422
425
  }
423
426
 
424
427
  const lockData = fs.readFileSync(lockPath, { encoding: 'utf-8' });
@@ -433,8 +436,12 @@ export function buildRDependencies(
433
436
  }
434
437
  }
435
438
 
436
- fs.rmSync(tempRenvDir, { recursive: true })
439
+ // Store resulting 'renv.lock' file in R installation root directory,
440
+ // so we can use it when preparing renv on Platforma Backend side (workflow-tengo SDK).
441
+ fs.copyFileSync(path.join(depsDir, lockFile), path.join(rRoot, renvDirName, lockFile))
442
+
437
443
  if (fs.existsSync(origProjectsFile)) {
444
+ // Restore original 'projects' file to not leave traces of environment preparation.
438
445
  fs.renameSync(origProjectsFile, projectsFile)
439
446
  }
440
447
 
@@ -474,6 +481,8 @@ function patchREnviron(
474
481
  envs = {},
475
482
  comment = "",
476
483
  ) {
484
+ logger.info(`Patching Renviron file in ${rRoot} directory`)
485
+
477
486
  let rEnvironPath = path.join(rRoot, 'etc', 'Renviron')
478
487
  if (!fs.existsSync(rEnvironPath)) {
479
488
  rEnvironPath = path.join(rRoot, 'etc', 'Renviron.site')
@@ -487,20 +496,7 @@ function patchREnviron(
487
496
  }
488
497
 
489
498
  for (const [envName, envValue] of Object.entries(envs)) {
490
- line = `${envName}=\${${envName}:-'${envValue}'}`
499
+ const line = `${envName}=\${${envName}:-'${envValue}'}`
491
500
  fs.appendFileSync(rEnvironPath, line + '\n', 'utf8');
492
501
  }
493
502
  }
494
-
495
- /**
496
- * Recreate directory by removing it and creating back.
497
- *
498
- * @param {string} dir - path to directory
499
- */
500
- function recreateDir(dir) {
501
- if (fs.existsSync(dir)) {
502
- fs.rmSync(dir, { recursive: true })
503
- }
504
- fs.mkdirSync(dir, { recursive: true })
505
-
506
- }
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import os from 'node:os';
3
- import fs from 'node:fs';
3
+ import fsextra from 'fs-extra';
4
4
 
5
5
  import * as pkg from './pkg.js';
6
6
  import * as util from './util.js';
@@ -17,12 +17,7 @@ export async function buildR(logger, version) {
17
17
 
18
18
  // Copy Windows R stub files to dist directory
19
19
  const stubDir = pkg.asset('windows-x64-stub');
20
- await fs.promises.cp(stubDir, distDir, {
21
- recursive: true,
22
- preserveTimestamps: true,
23
- force: true,
24
- errorOnExist: false
25
- });
20
+ await fsextra.copy(stubDir, distDir);
26
21
 
27
22
  // TODO: R for windows
28
23
  }