---
title: "why would you need srcpkgs?"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{why would you need srcpkgs?}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, echo = FALSE, results='hide'}
# suppressPackageStartupMessages(library(srcpkgs))

# setup a temp dir
root_dir <- tempfile()
dir.create(root_dir)
file.copy('srcpkgs_lotr_demo', root_dir, recursive = TRUE)
workdir <- file.path(root_dir, 'srcpkgs_lotr_demo')
knitr::opts_knit$set(root.dir = workdir) # set directory for other chunks
```

I will demonstrate srcpkgs using a dummy collection of source packages: https://github.com/kforner/srcpkgs_lotr_demo

## overview of the srcpkgs_lotr_demo collection

It consists currently in 11 related packages, with a tree structure:

  - lotr - the highest level package
    * elves
      * legolas
      * galadriel
    * hobbits
      * bilbo
      * frodo
    * gimli
    * aragorn
    * gandalf
    * elrond

N.B: `lotr` depends on all other packages, except for `elrond` (not yet).

The dependencies are implemented by a mix of Imports, Imports with namespace imports and Depends.

## using devtools


```{r devtools_setup, results = 'hide'}
suppressPackageStartupMessages(library(devtools))
pkgs <- c('bilbo', 'frodo', 'hobbits', 'legolas', 'galadriel', 'elves', 'gimli', 'aragorn', 'gandalf', 'lotr')
```

### loading

`devtools` is designed to manage a single source package. Let's use it to load our `lotr` source package:

```{r devtools_load, error = TRUE}
load_all('lotr')
```

--> devtools can NOT load `lotr` since it can not possibly find the `hobbits` package, which is a dependency.

Let's help him:
```{r devtools_load2, error = TRUE}
load_all('hobbits')
```

--> same problem

Here is how we must load the packages, following the dependencies order.
Note that we also need to roxygenize them (using `document()`)
```{r devtools_load3, message = FALSE}
document('frodo')
load_all('frodo')
document('bilbo')
load_all('frodo')
document('hobbits')
load_all('hobbits')

document('legolas')
load_all('legolas')
document('galadriel')
load_all('galadriel')
document('elves')
load_all('elves')

document('gimli')
load_all('gimli')
document('aragorn')
load_all('aragorn')
document('gandalf')
load_all('gandalf')
```


and finally we can load it
```{r devtools_load_final}
document('lotr')
load_all('lotr')

# use it
str(lotr())
```


### editing and reloading

Let's modify one of the direct dependency of `lotr`, e.g. the `hobbits` package. 
Currently:

```{r devtools_edit1}
names(lotr()$hobbits)
```


```{r devtools_edit2}
lines <- readLines('hobbits/R/main.R')
cat(lines, sep = '\n')
```

Edit `hobbits/R/main.R` and comment out bilbo, which comes from the `bilbo` package in **Depends**.

```{r devtools_edit3}
edited_lines <- grep('bilbo', lines, invert = TRUE, value = TRUE)
writeLines(edited_lines, 'hobbits/R/main.R')
```

Let's try to apply our changes:

```{r devtools_edit4}
load_all('lotr')
names(lotr()$hobbits)
```
--> `load_all()` can not properly reload our package, since it does not know that 
a dependency has been modified.

To apply the changes:
```{r devtools_edit5}
load_all('hobbits')
names(lotr()$hobbits)
```
--> now it works. Note that this is because `load_all()` is now able to force the unload of a package
even though it is needed by another package:


```{r devtools_edit6, error = TRUE}
unloadNamespace('hobbits')
```

But:
```{r devtools_edit7}
devtools::unload('hobbits')
```

Note that now `lotr` is **broken**:
```{r devtools_edit8, error = TRUE}
lotr()
```

Let's fix it
```{r devtools_edit9, error = TRUE}
load_all('hobbits')
names(lotr())
```

## using srcpkgs

```{r srcpkgs_setup}
library(srcpkgs)
old <- options(width = 200)
print(get_srcpkgs())
```

### unloading

the `srcpkgs::pkg_unload()` takes into account the dependencies between the source packages.

```{r srcpkgs_unload1}
plan <- pkg_unload('bilbo')
print(plan)
```

unload all our packages to start from a clean state. We will also 
```{r srcpkgs_unload2}
for (pkg in get_srcpkgs()) pkg_unload(pkg)
```


### loading

`srcpkgs::pkg_load()` takes care of everything: it roxygenizes the packages if needed, and load them 
in the appropriate order:

```{r srcpkgs_load1}
plan <- pkg_load('lotr')
print(plan)
print(names(lotr()))
```

### editing and reloading

Let's edit the `frodo` package, and change the weapon from `sting` to `sword`:

```{r srcpkgs_edit1}
lotr()$hobbits$frodo

lines <- readLines('frodo/R/main.R')
cat(lines, sep = '\n')

edited_lines <- sub('sting', 'sword', lines)
writeLines(edited_lines, 'frodo/R/main.R')
```

Now let's ask `srcpkgs` to make sure the `lotr` package is up-to-date: 

```{r srcpkgs_edit2}
plan <- pkg_load('lotr')
print(plan)
```

--> It figured out that `frodo` was modified, and needed to be reloaded, and for that 
all its dependents needed to be also properly unloaded and re-loaded.

```{r srcpkgs_edit3}
lotr()$hobbits$frodo$weapons
```

```{r cleanup, include = FALSE}
options(old)
```

