Skip to content

Commit 27612c6

Browse files
authored
Improve R Package Dependency Resolution and Script Execution Time (#99)
* When resolving dependencies, consolidation of duplicates keeps binary pkgs. Dependency Calculation doesn't fetch linkingTo packages for binary pkgs. * Comment style for function now consistent. Updated comment phrasing * Removed hardcoded cran repo check and add proper data.frame row count check. Added tests for LinkingTo package inclusion for binary vs source. * Spacing consistency with connectionString argument * Adjust test for purpose of checking source package installed due to successful compilation from source
1 parent f27e8f1 commit 27612c6

2 files changed

Lines changed: 200 additions & 36 deletions

File tree

R/R/sqlPackage.R

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ sqlRemoteExecuteFun <- function(connection, FUN, ..., useRemoteFun = FALSE, asus
548548
{
549549
result <- FALSE
550550
}
551-
551+
552552
if (!is.null(output))
553553
{
554554
for(o in output)
@@ -1155,7 +1155,35 @@ getDependentPackagesToInstall <- function(pkgs, availablePackages, installedPack
11551155
write(sprintf("%s Resolving package dependencies for (%s)...", pkgTime(), paste(pkgs, collapse = ', ')), stdout())
11561156
}
11571157

1158-
dependencies <- tools::package_dependencies(packages = pkgs, db = availablePackages, recursive = TRUE, verbose = FALSE)
1158+
dependencies <- NULL
1159+
repos <- getOption("repos")
1160+
contribWinBinaryUrl <- utils::contrib.url(repos = repos, type = "win.binary")
1161+
1162+
#
1163+
# Build list of dependencies
1164+
#
1165+
for (package in pkgs)
1166+
{
1167+
currentPackageDependencies <- NULL
1168+
dependencyTypes <- c("Depends","Imports")
1169+
1170+
#
1171+
# Determine if package is available as a binary package
1172+
#
1173+
packageProperties <- availablePackages[availablePackages$Package == package & availablePackages$Repository == contribWinBinaryUrl, ]
1174+
1175+
#
1176+
# When only a source package is available, add LinkingTo dependencies
1177+
#
1178+
if ( nrow(packageProperties) < 1)
1179+
{
1180+
append(dependencyTypes, c("LinkingTo"))
1181+
}
1182+
1183+
currentPackageDependencies <- tools::package_dependencies(packages = pkgs, db = availablePackages, which = dependencyTypes, recursive = TRUE, verbose = FALSE)
1184+
1185+
dependencies <- append(dependencies, currentPackageDependencies)
1186+
}
11591187

11601188
#
11611189
# get combined dependency closure w/o base packages
@@ -1255,7 +1283,7 @@ prunePackagesToInstallExtLib <- function(dependentPackages, topMostPackages, ins
12551283
}
12561284

12571285
# if the available package is being requested as a top-level package we check
1258-
# if the top-leve attribute on the package is set to false we will have to update it to true
1286+
# if the top-level attribute on the package is set to false we will have to update it to true
12591287
#
12601288
if ('Attributes' %in% colnames(installedPackages))
12611289
{
@@ -1590,11 +1618,16 @@ sqlInstallPackagesExtLib <- function(connectionString,
15901618
binaryPackages <- if (serverVersion$serverIsWindows) utils::available.packages(contribWinBinary, type = "win.binary") else NULL
15911619
row.names(binaryPackages) <- NULL
15921620

1593-
pkgsUnison <- data.frame(rbind(sourcePackages, binaryPackages), stringsAsFactors = FALSE)
1621+
# Concatenate list source packages to the list of binary packages available within configured CRAN repo.
1622+
#
1623+
pkgsUnison <- data.frame(rbind(binaryPackages, sourcePackages), stringsAsFactors = FALSE)
1624+
1625+
# For packages available as binary and source types, prune the source packages.
1626+
#
15941627
pkgsUnison <- pkgsUnison[!duplicated(pkgsUnison$Package),,drop=FALSE]
15951628
row.names(pkgsUnison) <- pkgsUnison$Package
15961629

1597-
# check for missing packages
1630+
# check for missing packages (Package(s) requested to be installed, but not available on configured CRAN repo.)
15981631
#
15991632
missingPkgs <- pkgs[!(pkgs %in% pkgsUnison$Package) ]
16001633

@@ -1603,7 +1636,7 @@ sqlInstallPackagesExtLib <- function(connectionString,
16031636
stop(sprintf("Cannot find specified packages (%s) to install", paste(missingPkgs, collapse = ', ')), call. = FALSE)
16041637
}
16051638

1606-
# get all installed packages
1639+
# get list of all installed packages on the server
16071640
#
16081641
installedPackages <- sql_installed.packages(connectionString,
16091642
fields = NULL,

R/tests/testthat/test.sqlPackage.dependencies.R

Lines changed: 161 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ test_that("single package install and removal with no dependencies",
1515

1616
connectionStringDBO <- helper_getSetting("connectionStringDBO")
1717
packageName <- c("glue")
18-
18+
1919
tryCatch({
2020
#
2121
# check package management is installed
@@ -32,29 +32,29 @@ test_that("single package install and removal with no dependencies",
3232
sql_remove.packages(connectionStringDBO, packageName, verbose = TRUE, scope = scope)
3333
}
3434

35-
helper_checkPackageStatusRequire( connectionStringDBO, packageName, FALSE)
35+
helper_checkPackageStatusRequire(connectionStringDBO, packageName, FALSE)
3636

3737
#
3838
# install single package (package has no dependencies)
3939
#
40-
output <- try(capture.output(sql_install.packages( connectionStringDBO, packageName, verbose = TRUE, scope = scope)))
40+
output <- try(capture.output(sql_install.packages(connectionStringDBO, packageName, verbose = TRUE, scope = scope)))
4141
print(output)
4242
expect_true(!inherits(output, "try-error"))
4343
expect_equal(1, sum(grepl("Successfully installed packages on SQL server", output)))
4444

45-
helper_checkPackageStatusRequire( connectionStringDBO, packageName, TRUE)
45+
helper_checkPackageStatusRequire(connectionStringDBO, packageName, TRUE)
4646
helper_checkSqlLibPaths(connectionStringDBO, 2)
4747

4848
#
4949
# remove the installed package and check again they are gone
5050
#
5151
cat("\nINFO:removing package...\n")
52-
output <- try(capture.output(sql_remove.packages( connectionStringDBO, packageName, verbose = TRUE, scope = scope)))
52+
output <- try(capture.output(sql_remove.packages(connectionStringDBO, packageName, verbose = TRUE, scope = scope)))
5353
print(output)
5454
expect_true(!inherits(output, "try-error"))
5555
expect_equal(1, sum(grepl("Successfully removed packages from SQL server", output)))
5656

57-
helper_checkPackageStatusRequire( connectionStringDBO, packageName, FALSE)
57+
helper_checkPackageStatusRequire(connectionStringDBO, packageName, FALSE)
5858
}, finally={
5959
helper_cleanAllExternalLibraries(connectionStringDBO)
6060
})
@@ -64,58 +64,58 @@ test_that( "package install and uninstall with dependency",
6464
{
6565
connectionStringAirlineUserdbowner <- helper_getSetting("connectionStringAirlineUserdbowner")
6666
scope <- "private"
67-
67+
6868
tryCatch({
6969
#
7070
# check package management is installed
7171
#
7272
cat("\nINFO: checking remote lib paths...\n")
7373
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 1)
74-
74+
7575
packageName <- c("A3")
7676
dependentPackageName <- "xtable"
77-
77+
7878
#
7979
# remove old packages if any and verify they aren't there
8080
#
8181
if (helper_remote.require(connectionStringAirlineUserdbowner, packageName) == TRUE)
8282
{
8383
cat("\nINFO: removing package:", packageName,"\n")
84-
sql_remove.packages( connectionStringAirlineUserdbowner, c(packageName), verbose = TRUE, scope = scope)
84+
sql_remove.packages(connectionStringAirlineUserdbowner, c(packageName), verbose = TRUE, scope = scope)
8585
}
86-
86+
8787
if (helper_remote.require(connectionStringAirlineUserdbowner, dependentPackageName) == TRUE)
8888
{
8989
cat("\nINFO: removing package:", dependentPackageName,"\n")
90-
sql_remove.packages( connectionStringAirlineUserdbowner, c(dependentPackageName), verbose = TRUE, scope = scope)
90+
sql_remove.packages(connectionStringAirlineUserdbowner, c(dependentPackageName), verbose = TRUE, scope = scope)
9191
}
92-
93-
helper_checkPackageStatusRequire( connectionStringAirlineUserdbowner, packageName, FALSE)
94-
helper_checkPackageStatusRequire( connectionStringAirlineUserdbowner, dependentPackageName, FALSE)
95-
92+
93+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, FALSE)
94+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, dependentPackageName, FALSE)
95+
9696
#
9797
# install the package with its dependencies and check if its present
9898
#
99-
output <- try(capture.output(sql_install.packages( connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
99+
output <- try(capture.output(sql_install.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
100100
print(output)
101101
expect_true(!inherits(output, "try-error"))
102102
expect_equal(1, sum(grepl("Successfully installed packages on SQL server", output)))
103-
104-
helper_checkPackageStatusRequire( connectionStringAirlineUserdbowner, packageName, TRUE)
105-
helper_checkPackageStatusRequire( connectionStringAirlineUserdbowner, dependentPackageName, TRUE)
103+
104+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, TRUE)
105+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, dependentPackageName, TRUE)
106106
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 2)
107-
107+
108108
#
109109
# remove the installed packages and check again they are gone
110110
#
111111
cat("\nINFO: removing packages...\n")
112-
output <- try(capture.output(sql_remove.packages( connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
112+
output <- try(capture.output(sql_remove.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
113113
print(output)
114114
expect_true(!inherits(output, "try-error"))
115115
expect_equal(1, sum(grepl("Successfully removed packages from SQL server", output)))
116-
117-
helper_checkPackageStatusRequire( connectionStringAirlineUserdbowner, packageName, FALSE)
118-
helper_checkPackageStatusRequire( connectionStringAirlineUserdbowner, dependentPackageName, FALSE)
116+
117+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, FALSE)
118+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, dependentPackageName, FALSE)
119119
}, finally={
120120
helper_cleanAllExternalLibraries(connectionStringAirlineUserdbowner)
121121
})
@@ -132,22 +132,153 @@ test_that( "Installing a package that is already in use",
132132
#
133133
cat("\nINFO: checking remote lib paths...\n")
134134
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 1)
135-
136-
135+
136+
137137
packageName <- c("lattice") # usually already attached in an R session.
138-
138+
139139
installedPackages <- sql_installed.packages(connectionStringAirlineUserdbowner, fields = NULL, scope = scope)
140140
if (!packageName %in% installedPackages)
141141
{
142142
sql_install.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)
143143
}
144-
144+
145145
#
146146
# install the package again and check if it fails with the correct message.
147147
#
148-
output <- capture.output(sql_install.packages( connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope))
148+
output <- capture.output(sql_install.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope))
149149
expect_true(TRUE %in% (grepl("already installed", output)))
150150
}, finally={
151151
helper_cleanAllExternalLibraries(connectionStringAirlineUserdbowner)
152152
})
153153
})
154+
155+
#
156+
# 'iptools' is available as source and binary. This test validates that the LinkingTo package 'BH' is not installed.
157+
# If 'BH' is installed, that means that the 'iptools' source package was chosen,
158+
# because LinkingTo packages are required when building from source.
159+
#
160+
test_that( "Binary Package install with LinkingTo dependency",
161+
{
162+
connectionStringAirlineUserdbowner <- helper_getSetting("connectionStringAirlineUserdbowner")
163+
scope <- "private"
164+
165+
tryCatch({
166+
#
167+
# check package management is installed
168+
#
169+
cat("\nINFO: checking remote lib paths...\n")
170+
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 1)
171+
172+
packageName <- c("iptools")
173+
linkingToPackageName <- "BH"
174+
175+
#
176+
# remove old packages if any and verify they aren't there
177+
#
178+
if (helper_remote.require(connectionStringAirlineUserdbowner, packageName) == TRUE)
179+
{
180+
cat("\nINFO: removing package:", packageName,"\n")
181+
sql_remove.packages(connectionStringAirlineUserdbowner, c(packageName), verbose = TRUE, scope = scope)
182+
}
183+
184+
if (helper_remote.require(connectionStringAirlineUserdbowner, linkingToPackageName) == TRUE)
185+
{
186+
cat("\nINFO: removing package:", linkingToPackageName,"\n")
187+
sql_remove.packages(connectionStringAirlineUserdbowner, c(linkingToPackageName), verbose = TRUE, scope = scope)
188+
}
189+
190+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, FALSE)
191+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, linkingToPackageName, FALSE)
192+
193+
#
194+
# install the package with its dependencies and validate that the LinkingTo package was not installed
195+
#
196+
output <- try(capture.output(sql_install.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
197+
print(output)
198+
expect_true(!inherits(output, "try-error"))
199+
expect_equal(1, sum(grepl("Successfully installed packages on SQL server", output)))
200+
201+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, TRUE)
202+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, linkingToPackageName, FALSE)
203+
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 1)
204+
205+
#
206+
# remove the installed packages and check again they are gone
207+
#
208+
cat("\nINFO: removing packages...\n")
209+
output <- try(capture.output(sql_remove.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
210+
print(output)
211+
expect_true(!inherits(output, "try-error"))
212+
expect_equal(1, sum(grepl("Successfully removed packages from SQL server", output)))
213+
214+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, FALSE)
215+
}, finally={
216+
helper_cleanAllExternalLibraries(connectionStringAirlineUserdbowner)
217+
})
218+
})
219+
220+
#
221+
# Source packages need the LinkingTo dependencies to be resolved and used for package compilation. This tests checks
222+
# that a source package is installed (successfully built) and it exists on the target server.
223+
#
224+
test_that( "Source Package install with LinkingTo dependency",
225+
{
226+
connectionStringAirlineUserdbowner <- helper_getSetting("connectionStringAirlineUserdbowner")
227+
scope <- "private"
228+
229+
tryCatch({
230+
#
231+
# check package management is installed
232+
#
233+
cat("\nINFO: checking remote lib paths...\n")
234+
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 1)
235+
236+
packageName <- c("spacefillr")
237+
linkingToPackageName <- "Rcpp"
238+
239+
#
240+
# remove old packages if any and verify they aren't there
241+
#
242+
if (helper_remote.require(connectionStringAirlineUserdbowner, packageName) == TRUE)
243+
{
244+
cat("\nINFO: removing package:", packageName,"\n")
245+
sql_remove.packages(connectionStringAirlineUserdbowner, c(packageName), verbose = TRUE, scope = scope)
246+
}
247+
248+
if (helper_remote.require(connectionStringAirlineUserdbowner, linkingToPackageName) == TRUE)
249+
{
250+
cat("\nINFO: removing package:", linkingToPackageName,"\n")
251+
sql_remove.packages(connectionStringAirlineUserdbowner, c(linkingToPackageName), verbose = TRUE, scope = scope)
252+
}
253+
254+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, FALSE)
255+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, linkingToPackageName, FALSE)
256+
257+
#
258+
# install the package with its dependencies and validate that the LinkingTo package was installed
259+
#
260+
output <- try(capture.output(sql_install.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
261+
print(output)
262+
expect_true(!inherits(output, "try-error"))
263+
expect_equal(1, sum(grepl("Successfully installed packages on SQL server", output)))
264+
265+
#
266+
# Source package built and then successfully installed on the server.
267+
#
268+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, TRUE)
269+
helper_checkSqlLibPaths(connectionStringAirlineUserdbowner, 1)
270+
271+
#
272+
# remove the installed packages and check again they are gone
273+
#
274+
cat("\nINFO: removing packages...\n")
275+
output <- try(capture.output(sql_remove.packages(connectionStringAirlineUserdbowner, packageName, verbose = TRUE, scope = scope)))
276+
print(output)
277+
expect_true(!inherits(output, "try-error"))
278+
expect_equal(1, sum(grepl("Successfully removed packages from SQL server", output)))
279+
280+
helper_checkPackageStatusRequire(connectionStringAirlineUserdbowner, packageName, FALSE)
281+
}, finally={
282+
helper_cleanAllExternalLibraries(connectionStringAirlineUserdbowner)
283+
})
284+
})

0 commit comments

Comments
 (0)