title: Offline installation of a list of packages: getting dependencies in order
body: <p>I've got the source files for a bunch of packages and their dependencies that I want to install on computers that have no internet access. I want to install all of these on other computers using as USB stick, but the install fails for some packages because the dependencies are not installing before the packages. How can I get the dependencies to be installed in order, before the packages that needs them?</p>
  
  <p>Here's my current method to obtain the packages, their dependencies, and get them in the correct order:</p>
  
  <pre><code># find the dependencies for the packages I want
  # from http://stackoverflow.com/a/15650828/1036500
  getPackages &lt;- function(packs){
    packages &lt;- unlist(
      tools::package_dependencies(packs, available.packages(),
                                  which=c("Depends", "Imports"), recursive=TRUE)
    )
    packages &lt;- union(packages, packs)
    packages
  }
  
  # packages I want 
  my_packages &lt;- c('stringr', 'devtools', 'ggplot2', 'dplyr', 'tidyr', 'rmarkdown', 'knitr', 'reshape2', 'gdata')
  
  # get names of dependencies and try to get them in the right order, this seems ridiculous... 
  my_packages_and_dependencies &lt;- getPackages(my_packages)
  dependencies_only &lt;- setdiff(my_packages_and_dependencies, my_packages)
  deps_of_deps &lt;- getPackages(dependencies_only)
  deps_of_deps_of_deps &lt;- getPackages(deps_of_deps)
  my_packages_and_dependencies &lt;- unique(c(deps_of_deps_of_deps, deps_of_deps, dependencies_only, my_packages))
  
  # where to keep the source?
  local_CRAN &lt;- paste0(getwd(), "/local_CRAN")
  
  # get them from CRAN, source files
  download.packages(pkgs = my_packages_and_dependencies, destdir = local_CRAN, type = "source")
  # note that 'tools', 'methods', 'utils, 'stats', etc. art not on CRAN, but are part of base
  
  # from http://stackoverflow.com/a/10841614/1036500
  library(tools)
  write_PACKAGES(local_CRAN)
  </code></pre>
  
  <p>Now assume I'm on another computer with a fresh install of R and RStudio (and Rtools or Xcode) and no internet connection, I plug in the USB stick, open the RProj file to set the working directory, and run this script:</p>
  
  <pre><code>#############################################################
  
  ## Install from source (Windows/OSX/Linux)
  
  # What do I want to install?
  my_packages_and_dependencies &lt;- c("methods", "tools", "bitops", "stats", "colorspace", "graphics", 
                                    "tcltk", "Rcpp", "digest", "jsonlite", "mime", "RCurl", "R6", 
                                    "stringr", "brew", "grid", "RColorBrewer", "dichromat", "munsell", 
                                    "plyr", "labeling", "grDevices", "utils", "httr", "memoise", 
                                    "whisker", "evaluate", "rstudioapi", "roxygen2", "gtable", "scales", 
                                    "proto", "MASS", "assertthat", "magrittr", "lazyeval", "DBI", 
                                    "stringi", "yaml", "htmltools", "caTools", "formatR", "highr", 
                                    "markdown", "gtools", "devtools", "ggplot2", "dplyr", "tidyr", 
                                    "rmarkdown", "knitr", "reshape2", "gdata")
  
  # where are the source files? 
  local_CRAN &lt;- paste0(getwd(), "/local_CRAN")
  
  # scan all packages and get files names of wanted source pckgs
  # I've got other things in this dir also
  wanted_package_source_filenames &lt;- list.files(local_CRAN, pattern = "tar.gz", full.names = TRUE)
  
  # put them in order to make sure deps go first, room for improvement here...
  trims &lt;- c(local_CRAN, "/",  "tar.gz")
  x1 &lt;- gsub(paste(trims, collapse = "|"), "", wanted_package_source_filenames)
  x2 &lt;- sapply( strsplit(x1, "_"), "[[", 1)
  idx &lt;- match(my_packages_and_dependencies, x2)
  wanted_package_source_filenames &lt;- na.omit(wanted_package_source_filenames[idx])
  
  install.packages(wanted_package_source_filenames, 
                   repos = NULL, 
                   dependencies = TRUE, 
                   contrib.url = local_CRAN, # I thought this would take care of getting dependencies automatically...
                   type  = "source" )
  </code></pre>
  
  <p>This works reasonably well, but still some packages fail to install:</p>
  
  <pre><code>sapply(my_packages_and_dependencies, require, character.only = TRUE) 
  
   methods        tools       bitops        stats 
          TRUE         TRUE         TRUE         TRUE 
    colorspace     graphics        tcltk         Rcpp 
          TRUE         TRUE         TRUE         TRUE 
        digest     jsonlite         mime        RCurl 
          TRUE         TRUE         TRUE        FALSE 
            R6      stringr         brew         grid 
          TRUE         TRUE         TRUE         TRUE 
  RColorBrewer    dichromat      munsell         plyr 
          TRUE         TRUE         TRUE         TRUE 
      labeling    grDevices        utils         httr 
          TRUE         TRUE         TRUE        FALSE 
       memoise      whisker     evaluate   rstudioapi 
          TRUE         TRUE         TRUE         TRUE 
      roxygen2       gtable       scales        proto 
          TRUE         TRUE         TRUE         TRUE 
          MASS   assertthat     magrittr     lazyeval 
          TRUE         TRUE         TRUE         TRUE 
           DBI      stringi         yaml    htmltools 
          TRUE         TRUE         TRUE         TRUE 
       caTools      formatR        highr     markdown 
          TRUE         TRUE         TRUE         TRUE 
        gtools     devtools      ggplot2        dplyr 
          TRUE        FALSE        FALSE         TRUE 
         tidyr    rmarkdown        knitr     reshape2 
         FALSE        FALSE         TRUE         TRUE 
         gdata 
          TRUE 
  Warning messages:
  1: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
    there is no package called ‘RCurl’
  2: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
    there is no package called ‘httr’
  3: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
    there is no package called ‘devtools’
  4: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
    there is no package called ‘ggplot2’
  5: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
    there is no package called ‘tidyr’
  6: In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
    there is no package called ‘rmarkdown’
  </code></pre>
  
  <p>Seems that knitr must come before rmarkdown, reshape2 before tidyr and ggplot2, etc. etc. </p>
  
  <p>There must be a simpler and more complete solution to the problem of getting the list of source files in the very specific order needed the put all the dependencies in the right order. What's the simplest way to do that (without using any contributed packages)?</p>
  
  <p>This is the system I am currently working on, I'm using the source versions of packages in an attempt to prepare for anything with the offline computers (OSX/Linux/Windows):</p>
  
  <pre><code>&gt; sessionInfo()
  R version 3.1.2 (2014-10-31)
  Platform: x86_64-w64-mingw32/x64 (64-bit)
  
  locale:
  [1] LC_COLLATE=English_United States.1252 
  [2] LC_CTYPE=English_United States.1252   
  [3] LC_MONETARY=English_United States.1252
  [4] LC_NUMERIC=C                          
  [5] LC_TIME=English_United States.1252    
  
  attached base packages:
   [1] tcltk     grid      tools     stats     graphics 
   [6] grDevices utils     datasets  methods   base     
  
  other attached packages:
   [1] gdata_2.13.3       reshape2_1.4.1    
   [3] knitr_1.9          dplyr_0.4.1       
   [5] gtools_3.4.1       markdown_0.7.4    
   [7] highr_0.4          formatR_1.0       
   [9] caTools_1.17.1     htmltools_0.2.6   
  [11] yaml_2.1.13        stringi_0.4-1     
  [13] DBI_0.3.1          lazyeval_0.1.10   
  [15] magrittr_1.5       assertthat_0.1    
  [17] proto_0.3-10       scales_0.2.4      
  [19] gtable_0.1.2       roxygen2_4.1.0    
  [21] rstudioapi_0.2     evaluate_0.5.5    
  [23] whisker_0.3-2      memoise_0.2.1     
  [25] labeling_0.3       plyr_1.8.1        
  [27] munsell_0.4.2      dichromat_2.0-0   
  [29] RColorBrewer_1.1-2 brew_1.0-6        
  [31] stringr_0.6.2      R6_2.0.1          
  [33] mime_0.2           jsonlite_0.9.14   
  [35] digest_0.6.8       Rcpp_0.11.4       
  [37] colorspace_1.2-5   bitops_1.0-6      
  [39] MASS_7.3-35       
  
  loaded via a namespace (and not attached):
  [1] parallel_3.1.2
  </code></pre>
  
  <p><strong>EDIT</strong> following Andrie's helpful comment, I've had a go with miniCRAN, the bit that's missing from the vignette is how to actually install the packages from the local repo. This is what I've tried:</p>
  
  <pre><code>library("miniCRAN")
  
  # Specify list of packages to download
  pkgs &lt;- c('stringr', 'devtools', 'ggplot2', 'dplyr', 'tidyr', 'rmarkdown', 'knitr', 'reshape2', 'gdata')
  
  # Make list of package URLs
  revolution &lt;- c(CRAN="http://cran.revolutionanalytics.com")
  pkgList &lt;- pkgDep(pkgs, repos=revolution, type="source" )
  pkgList
  
  # Set location to store source files 
  local_CRAN &lt;- paste0(getwd(), "/local_CRAN")
  
  # Make repo for source
  makeRepo(pkgList, path = local_CRAN, repos = revolution, type = "source")
  
  # install...
  install.packages(pkgs, 
                   repos = local_CRAN, # do I really need "file:///"?
                   dependencies = TRUE, 
                   contrib.url = local_CRAN,
                   type  = "source" )
  </code></pre>
  
  <p>And the result is:</p>
  
  <pre><code>Installing packages into ‘C:/emacs/R/win-library/3.1’
  (as ‘lib’ is unspecified)
  Warning in install.packages :
    unable to access index for repository C:/Users/.../local_CRAN/src/contrib
  Warning in install.packages :
    packages ‘stringr’, ‘devtools’, ‘ggplot2’, ‘dplyr’, ‘tidyr’, ‘rmarkdown’, ‘knitr’, ‘reshape2’, ‘gdata’ are not available (for R version 3.1.2)
  </code></pre>
  
  <p>What am I missing here?</p>
  
  <p><strong>EDIT</strong> Yes, I was missing proper use of <code>file:///</code>, which should be like this:</p>
  
  <pre><code>install.packages(pkgs, 
                   repos = paste0("file:///", local_CRAN),
                   type = "source")
  </code></pre>
  
  <p>That's moved me along heaps, it all basically works as expected now. Thanks very much. Now I just have this to look in to: <code>fatal error: curl/curl.h: No such file or directory</code>, which is stopping RCurl and httr from installing. </p>