├── debian ├── compat ├── source │ └── format ├── dirs ├── watch ├── changelog ├── rules ├── control └── copyright ├── _pkgdown.yml ├── LICENSE ├── .gitignore ├── docs ├── slides │ ├── img │ │ ├── R.png │ │ ├── cran.png │ │ ├── crying.jpg │ │ ├── tweet1.jpg │ │ ├── tweet2.jpg │ │ ├── needcomp.png │ │ ├── geospatial.jpg │ │ ├── tidyverse.jpg │ │ ├── cran-rstanarm.png │ │ ├── RSPMvsFedoraBSPM.webm │ │ ├── fascinating-so-whats-the-problem.jpg │ │ └── fedora.svg │ └── lib │ │ ├── macros.js │ │ ├── remark-css-0.0.1 │ │ ├── metropolis-fonts.css │ │ ├── default.css │ │ └── metropolis.css │ │ ├── header-attrs-2.11 │ │ └── header-attrs.js │ │ └── styles.css ├── reference │ ├── Rplot001.png │ ├── bspm-scripts.html │ ├── index.html │ ├── bspm-options.html │ ├── bspm-package.html │ └── shadowed_packages.html ├── pkgdown.yml ├── deps │ ├── bootstrap-5.3.1 │ │ └── fonts │ │ │ ├── S6uyw4BMUTPHjx4wXg.woff2 │ │ │ ├── 4iCs6KVjbNBYlgoKfw72.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu4mxK.woff2 │ │ │ ├── S6u8w4BMUTPHjxsAXC-q.woff2 │ │ │ ├── S6uyw4BMUTPHjxAwXjeu.woff2 │ │ │ ├── XRXV3I6Li01BKofINeaB.woff2 │ │ │ ├── q5uGsou0JOdh94bfvQlt.woff2 │ │ │ ├── 1Ptug8zYS_SKggPNyC0ITw.woff2 │ │ │ ├── 4iCs6KVjbNBYlgoKcQ72j00.woff2 │ │ │ ├── 4iCs6KVjbNBYlgoKcg72j00.woff2 │ │ │ ├── 4iCs6KVjbNBYlgoKcw72j00.woff2 │ │ │ ├── 4iCs6KVjbNBYlgoKew72j00.woff2 │ │ │ ├── 4iCs6KVjbNBYlgoKfA72j00.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu4WxKOzY.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu5mxKOzY.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu72xKOzY.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu7GxKOzY.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu7WxKOzY.woff2 │ │ │ ├── KFOmCnqEu92Fr1Mu7mxKOzY.woff2 │ │ │ ├── S6u8w4BMUTPHjxsAUi-qJCY.woff2 │ │ │ ├── S6u9w4BMUTPHh6UVSwiPGQ.woff2 │ │ │ ├── S6u9w4BMUTPHh7USSwiPGQ.woff2 │ │ │ ├── XRXV3I6Li01BKofIMeaBXso.woff2 │ │ │ ├── XRXV3I6Li01BKofIO-aBXso.woff2 │ │ │ ├── XRXV3I6Li01BKofIOOaBXso.woff2 │ │ │ ├── XRXV3I6Li01BKofIOuaBXso.woff2 │ │ │ ├── q5uGsou0JOdh94bfuQltOxU.woff2 │ │ │ ├── 1Ptug8zYS_SKggPNyCAIT5lu.woff2 │ │ │ ├── 1Ptug8zYS_SKggPNyCIIT5lu.woff2 │ │ │ ├── 1Ptug8zYS_SKggPNyCMIT5lu.woff2 │ │ │ ├── 1Ptug8zYS_SKggPNyCkIT5lu.woff2 │ │ │ ├── 4iCv6KVjbNBYlgoCxCvjsGyN.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fBBc4.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fBBc4.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfBBc4.woff2 │ │ │ ├── S6u9w4BMUTPHh6UVSwaPGR_p.woff2 │ │ │ ├── S6u9w4BMUTPHh7USSwaPGR_p.woff2 │ │ │ ├── 4iCv6KVjbNBYlgoCxCvjs2yNL4U.woff2 │ │ │ ├── 4iCv6KVjbNBYlgoCxCvjtGyNL4U.woff2 │ │ │ ├── 4iCv6KVjbNBYlgoCxCvjvGyNL4U.woff2 │ │ │ ├── 4iCv6KVjbNBYlgoCxCvjvWyNL4U.woff2 │ │ │ ├── 4iCv6KVjbNBYlgoCxCvjvmyNL4U.woff2 │ │ │ ├── CSR64z1Qlv-GDxkbKVQ_fO4KTet_.woff2 │ │ │ ├── CSR64z1Qlv-GDxkbKVQ_fOAKTQ.woff2 │ │ │ ├── JTUSjIg1_i6t8kCHKm459W1hyzbi.woff2 │ │ │ ├── JTUSjIg1_i6t8kCHKm459WRhyzbi.woff2 │ │ │ ├── JTUSjIg1_i6t8kCHKm459WZhyzbi.woff2 │ │ │ ├── JTUSjIg1_i6t8kCHKm459Wdhyzbi.woff2 │ │ │ ├── JTUSjIg1_i6t8kCHKm459Wlhyw.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 │ │ │ ├── KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 │ │ │ ├── QGYpz_kZZAGCONcK2A4bGOj8mNhN.woff2 │ │ │ ├── CSR54z1Qlv-GDxkbKVQ_dFsvWNReuQ.woff2 │ │ │ ├── 07d40e985ad7c747025dabb9f22142c4.woff2 │ │ │ ├── 1f5e011d6aae0d98fc0518e1a303e99a.woff2 │ │ │ ├── 626330658504e338ee86aec8e957426b.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2 │ │ │ ├── CSR54z1Qlv-GDxkbKVQ_dFsvWNpeudwk.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlPevW.woff2 │ │ │ ├── c2f002b3a87d3f9bfeebb23d32cfd9f8.woff2 │ │ │ ├── ee91700cdbf7ce16c054c2bb8946c736.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDI.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2 │ │ │ ├── 6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvUlMI.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlM-vWjMY.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlMOvWjMY.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlMevWjMY.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlMuvWjMY.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlOevWjMY.woff2 │ │ │ ├── HI_SiYsKILxRpg3hIP6sJ7fM7PqlPuvWjMY.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7jsDJT9g.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7ksDJT9g.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7osDJT9g.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7psDJT9g.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7qsDJT9g.woff2 │ │ │ ├── 6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7rsDJT9g.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdu.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdu.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvQlMIXxw.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvXlMIXxw.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvYlMIXxw.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvZlMIXxw.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvalMIXxw.woff2 │ │ │ ├── HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvblMIXxw.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwkxduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlBduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmBduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmRduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmhduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmxduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwkxduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlBduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmBduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmRduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmhduz8A.woff2 │ │ │ ├── 6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmxduz8A.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2 │ │ │ ├── UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2 │ │ │ ├── memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2 │ │ │ ├── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2 │ │ │ └── memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2 │ └── data-deps.txt ├── link.svg ├── sitemap.xml ├── bootstrap-toc.css ├── docsearch.js ├── pkgdown.js ├── LICENSE-text.html ├── bootstrap-toc.js ├── 404.html └── authors.html ├── inst ├── tinytest │ ├── db.rds │ ├── teardown.R │ ├── test_manager.R │ ├── test_scripts.R │ ├── setup.R │ ├── test_manager_ci.R │ ├── test_integration.R │ └── test_utils.R ├── service │ ├── dbus.service.in │ ├── dbus-paths │ ├── dbus.conf.in │ ├── backend │ │ ├── __init__.py │ │ ├── _utils.py │ │ ├── apt.py │ │ ├── dnf.py │ │ └── alpm.py │ └── bspm.py └── scripts │ └── mass_move.sh ├── .github ├── FUNDING.yml └── workflows │ └── build.yml ├── cleanup ├── tests ├── tinytest.R └── r2u.sh ├── .Rbuildignore ├── NAMESPACE ├── cran-comments.md ├── bspm.Rproj ├── man ├── bspm-scripts.Rd ├── bspm-package.Rd ├── bspm-options.Rd ├── shadowed_packages.Rd ├── integration.Rd └── manager.Rd ├── .Rprofile ├── configure ├── DESCRIPTION ├── R ├── options.R ├── scripts.R ├── integration.R ├── bridge.R ├── manager.R └── utils.R └── NEWS.md /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | template: 2 | bootstrap: 5 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2020 2 | COPYRIGHT HOLDER: Iñaki Ucar 3 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/share/dbus-1/system-services 2 | etc/dbus-1/system.d -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | __pycache__ 5 | *.pref 6 | *.excl 7 | -------------------------------------------------------------------------------- /docs/slides/img/R.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/R.png -------------------------------------------------------------------------------- /inst/tinytest/db.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/inst/tinytest/db.rds -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Enchufa2 4 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | https://cloud.r-project.org/src/contrib/bspm_([-\d\.]*)\.tar.gz 3 | -------------------------------------------------------------------------------- /inst/tinytest/teardown.R: -------------------------------------------------------------------------------- 1 | if (exists("unmock_all")) 2 | unmock_all() 3 | options(mock=NULL) 4 | -------------------------------------------------------------------------------- /docs/slides/img/cran.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/cran.png -------------------------------------------------------------------------------- /docs/slides/img/crying.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/crying.jpg -------------------------------------------------------------------------------- /docs/slides/img/tweet1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/tweet1.jpg -------------------------------------------------------------------------------- /docs/slides/img/tweet2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/tweet2.jpg -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/slides/img/needcomp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/needcomp.png -------------------------------------------------------------------------------- /docs/slides/img/geospatial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/geospatial.jpg -------------------------------------------------------------------------------- /docs/slides/img/tidyverse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/tidyverse.jpg -------------------------------------------------------------------------------- /docs/slides/img/cran-rstanarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/cran-rstanarm.png -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.3 2 | pkgdown: 2.0.7 3 | pkgdown_sha: ~ 4 | articles: {} 5 | last_built: 2024-04-10T13:54Z 6 | 7 | -------------------------------------------------------------------------------- /docs/slides/img/RSPMvsFedoraBSPM.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/RSPMvsFedoraBSPM.webm -------------------------------------------------------------------------------- /inst/service/dbus.service.in: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=@BUS_NAME@ 3 | Exec=@R_LIBRARY_DIR@/bspm/service/bspm.py 4 | User=root 5 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f inst/service/bspm.pref inst/service/bspm.excl inst/service/nodiscover 4 | find . -name __pycache__ -exec rm -rf {} \; 5 | -------------------------------------------------------------------------------- /docs/slides/img/fascinating-so-whats-the-problem.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/slides/img/fascinating-so-whats-the-problem.jpg -------------------------------------------------------------------------------- /inst/service/dbus-paths: -------------------------------------------------------------------------------- 1 | OPATH="/org/r_project/linux1/PackageManager" 2 | IFACE="org.r_project.linux1.PackageManager" 3 | BUS_NAME="org.r_project.linux1" 4 | -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6uyw4BMUTPHjx4wXg.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6uyw4BMUTPHjx4wXg.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKfw72.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKfw72.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu4mxK.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu4mxK.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6u8w4BMUTPHjxsAXC-q.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6u8w4BMUTPHjxsAXC-q.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6uyw4BMUTPHjxAwXjeu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6uyw4BMUTPHjxAwXjeu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofINeaB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofINeaB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/q5uGsou0JOdh94bfvQlt.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/q5uGsou0JOdh94bfvQlt.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyC0ITw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyC0ITw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKcQ72j00.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKcQ72j00.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKcg72j00.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKcg72j00.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKcw72j00.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKcw72j00.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKew72j00.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKew72j00.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKfA72j00.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCs6KVjbNBYlgoKfA72j00.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu4WxKOzY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu4WxKOzY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu5mxKOzY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu5mxKOzY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu72xKOzY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu72xKOzY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu7GxKOzY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu7GxKOzY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu7WxKOzY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu7WxKOzY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu7mxKOzY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOmCnqEu92Fr1Mu7mxKOzY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6u8w4BMUTPHjxsAUi-qJCY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6u8w4BMUTPHjxsAUi-qJCY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh6UVSwiPGQ.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh7USSwiPGQ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh7USSwiPGQ.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIMeaBXso.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIMeaBXso.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIO-aBXso.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIO-aBXso.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIOOaBXso.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIOOaBXso.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIOuaBXso.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/XRXV3I6Li01BKofIOuaBXso.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/q5uGsou0JOdh94bfuQltOxU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/q5uGsou0JOdh94bfuQltOxU.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCAIT5lu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCAIT5lu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCIIT5lu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCIIT5lu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCMIT5lu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCMIT5lu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCkIT5lu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/1Ptug8zYS_SKggPNyCkIT5lu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjsGyN.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjsGyN.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fBBc4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fBBc4.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fBBc4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fBBc4.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfBBc4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfBBc4.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh6UVSwaPGR_p.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh6UVSwaPGR_p.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh7USSwaPGR_p.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/S6u9w4BMUTPHh7USSwaPGR_p.woff2 -------------------------------------------------------------------------------- /tests/tinytest.R: -------------------------------------------------------------------------------- 1 | if (requireNamespace("tinytest", quietly=TRUE)) { 2 | home <- identical(Sys.getenv("CI"), "true") 3 | tinytest::test_package("bspm", at_home=home) 4 | } 5 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.github$ 4 | ^docs$ 5 | ^_pkgdown.yml$ 6 | ^cran-comments\.md$ 7 | ^CRAN-RELEASE$ 8 | ^debian 9 | ^CRAN-SUBMISSION$ 10 | -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjs2yNL4U.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjs2yNL4U.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjtGyNL4U.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjtGyNL4U.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjvGyNL4U.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjvGyNL4U.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjvWyNL4U.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjvWyNL4U.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjvmyNL4U.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/4iCv6KVjbNBYlgoCxCvjvmyNL4U.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/CSR64z1Qlv-GDxkbKVQ_fO4KTet_.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/CSR64z1Qlv-GDxkbKVQ_fO4KTet_.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/CSR64z1Qlv-GDxkbKVQ_fOAKTQ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/CSR64z1Qlv-GDxkbKVQ_fOAKTQ.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459W1hyzbi.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459W1hyzbi.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459WRhyzbi.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459WRhyzbi.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459WZhyzbi.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459WZhyzbi.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459Wdhyzbi.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459Wdhyzbi.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459Wlhyw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/JTUSjIg1_i6t8kCHKm459Wlhyw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fABc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fBxc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fCBc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fCRc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fChc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmEU9fCxc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fABc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fBxc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fCBc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fCRc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fChc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmSU5fCxc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfABc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfBxc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfCBc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfCRc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfChc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/KFOlCnqEu92Fr1MmWUlfCxc4EsA.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/QGYpz_kZZAGCONcK2A4bGOj8mNhN.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/QGYpz_kZZAGCONcK2A4bGOj8mNhN.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/CSR54z1Qlv-GDxkbKVQ_dFsvWNReuQ.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/CSR54z1Qlv-GDxkbKVQ_dFsvWNReuQ.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/07d40e985ad7c747025dabb9f22142c4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/07d40e985ad7c747025dabb9f22142c4.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/1f5e011d6aae0d98fc0518e1a303e99a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/1f5e011d6aae0d98fc0518e1a303e99a.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/626330658504e338ee86aec8e957426b.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/626330658504e338ee86aec8e957426b.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/CSR54z1Qlv-GDxkbKVQ_dFsvWNpeudwk.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/CSR54z1Qlv-GDxkbKVQ_dFsvWNpeudwk.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPevW.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPevW.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/c2f002b3a87d3f9bfeebb23d32cfd9f8.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/c2f002b3a87d3f9bfeebb23d32cfd9f8.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/ee91700cdbf7ce16c054c2bb8946c736.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/ee91700cdbf7ce16c054c2bb8946c736.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDI.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7nsDI.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvUlMI.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvUlMI.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlM-vWjMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlM-vWjMY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMOvWjMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMOvWjMY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMevWjMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMevWjMY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMuvWjMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlMuvWjMY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlOevWjMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlOevWjMY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPuvWjMY.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_SiYsKILxRpg3hIP6sJ7fM7PqlPuvWjMY.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7jsDJT9g.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7jsDJT9g.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7ksDJT9g.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7ksDJT9g.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7osDJT9g.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7osDJT9g.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7psDJT9g.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7psDJT9g.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7qsDJT9g.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7qsDJT9g.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7rsDJT9g.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPZ7rsDJT9g.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlxdu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdu.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlxdu.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvQlMIXxw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvQlMIXxw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvXlMIXxw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvXlMIXxw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvYlMIXxw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvYlMIXxw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvZlMIXxw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvZlMIXxw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvalMIXxw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvalMIXxw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvblMIXxw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/HI_QiYsKILxRpg3hIP6sJ7fM7PqlONvblMIXxw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1ZL7.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwkxduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwkxduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlBduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwlBduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmBduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmBduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmRduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmRduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmhduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmhduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmxduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmxduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwkxduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwkxduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlBduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwlBduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmBduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmBduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmRduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmRduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmhduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmhduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmxduz8A.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/6xKydSBYKcSV-LCoeQqfX1RYOo3ik4zwmxduz8A.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa0ZL7SUc.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa1pL7SUc.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa25L7SUc.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2JL7SUc.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2ZL7SUc.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/UcC73FwrK3iLTeHuS_fvQtMwCp50KnMa2pL7SUc.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS-muw.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuU6F.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTS2mu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSCmu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSGmu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSKmu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSOmu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSumu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTSymu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTUGmu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memvYaGs126MiZpBA-UvWbX2vVnXBbObj2OVTVOmu1aB.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqW106F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWt06F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtE6F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtU6F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWtk6F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWu06F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWuk6F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWvU6F15M.woff2 -------------------------------------------------------------------------------- /docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/bspm/HEAD/docs/deps/bootstrap-5.3.1/fonts/memtYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWqWxU6F15M.woff2 -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(available_sys) 4 | export(disable) 5 | export(discover) 6 | export(enable) 7 | export(install_sys) 8 | export(moveto_sys) 9 | export(remove_sys) 10 | export(shadowed_packages) 11 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Patch release 2 | Several fixes and improvements. 3 | 4 | ## Test environments 5 | - local up-to-date R installation 6 | - debian:latest, fedora:latest, ubuntu:latest on GitHub 7 | 8 | ## R CMD check results 9 | 0 errors | 0 warnings | 0 notes 10 | -------------------------------------------------------------------------------- /docs/deps/data-deps.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | r-cran-bspm (0.3.1-2) unstable; urgency=medium 2 | 3 | * Second build 4 | 5 | -- Dirk Eddelbuettel Sun, 12 Jul 2020 06:52:01 -0500 6 | 7 | r-cran-bspm (0.3.1-1) unstable; urgency=low 8 | 9 | * Initial build 10 | 11 | -- Dirk Eddelbuettel Sat, 11 Jul 2020 09:34:00 -0500 12 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # debian/rules file for the Debian/GNU Linux r-cran-bspm package 4 | # Copyright 2003 - 2020 by Dirk Eddelbuettel 5 | 6 | ## the configure script uses BUILD_ROOT 7 | export BUILD_ROOT = $(CURDIR)/debian/r-cran-bspm 8 | 9 | %: 10 | dh $@ --buildsystem R 11 | -------------------------------------------------------------------------------- /inst/service/dbus.conf.in: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /bspm.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /docs/slides/lib/macros.js: -------------------------------------------------------------------------------- 1 | remark.macros.scale = function (percentage) { 2 | var url = this; 3 | return ''; 4 | }; 5 | 6 | document.addEventListener("DOMContentLoaded", function(event) { 7 | var video = document.getElementById("video"); 8 | video.addEventListener("click", function(event) { 9 | if (video.paused == true) 10 | video.play(); 11 | else video.pause(); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /docs/slides/lib/remark-css-0.0.1/metropolis-fonts.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Fira+Sans:300,300i,400,400i,500,500i,700,700i); 2 | @import url(https://cdn.rawgit.com/tonsky/FiraCode/1.204/distr/fira_code.css); 3 | 4 | body { 5 | font-family: 'Fira Sans','Droid Serif', 'Palatino Linotype', 'Book Antiqua', Palatino, 'Microsoft YaHei', 'Songti SC', serif; 6 | } 7 | 8 | .remark-code, .remark-inline-code { 9 | font-family: 'Fira Code', 'Lucida Console', Monaco, monospace; 10 | font-size: 80%; 11 | } 12 | -------------------------------------------------------------------------------- /inst/service/backend/__init__.py: -------------------------------------------------------------------------------- 1 | libnames = ["dnf", "apt", "alpm"] 2 | attrs = ["discover", "available", "install", "remove"] 3 | 4 | for libname in libnames: 5 | try: 6 | lib = __import__("backend." + libname, globals(), locals(), attrs, 0) 7 | for attr in attrs: 8 | globals()[attr] = getattr(lib, attr) 9 | del globals()[libname] 10 | break 11 | except: 12 | pass 13 | 14 | if attrs[0] not in globals(): 15 | raise ImportError("no suitable backend found") 16 | 17 | del lib, libname, libnames, attr, attrs 18 | -------------------------------------------------------------------------------- /man/bspm-scripts.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/scripts.R 3 | \name{bspm-scripts} 4 | \alias{bspm-scripts} 5 | \title{Call Internal Scripts} 6 | \description{ 7 | Internal scripts can be called via \code{Rscript} (see examples). 8 | } 9 | \examples{ 10 | \dontrun{ 11 | # get a list of available scripts with descriptions 12 | Rscript -e bspm:::scripts 13 | 14 | # see a script's help 15 | Rscript -e bspm:::scripts -h 16 | 17 | # run a script 18 | Rscript -e bspm:::scripts [args] 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /.Rprofile: -------------------------------------------------------------------------------- 1 | # avoid parsing examples in scripts 2 | setHook(packageEvent("pkgdown", "onLoad"), function(...) { 3 | assignInNamespace("can_parse", function (x) TRUE, "pkgdown") 4 | }) 5 | 6 | # avoid highlighting errors in scripts 7 | setHook(packageEvent("pkgdown", "onLoad"), function(...) { 8 | fun <- getFromNamespace("highlight_examples", asNamespace("pkgdown")) 9 | assignInNamespace("highlight_examples", function (code, topic, env) { 10 | if (topic == "bspm-scripts") 11 | pkgdown:::highlight_text(code) 12 | else fun(code, topic, env) 13 | }, "pkgdown") 14 | }) 15 | -------------------------------------------------------------------------------- /docs/slides/lib/header-attrs-2.11/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /inst/tinytest/test_manager.R: -------------------------------------------------------------------------------- 1 | source("setup.R") 2 | 3 | mock_available <- function(...) readRDS("db.rds") 4 | 5 | mock_call <- function(method, pkgs=NULL) { 6 | available <- c("Rcpp", "magrittr") 7 | installed <<- c(installed, intersect(pkgs, available)) 8 | setdiff(pkgs, available) 9 | } 10 | 11 | # mock functions 12 | mock("available.packages", mock_available, "utils") 13 | mock("backend_call", mock_call, "bspm") 14 | 15 | installed <- NULL 16 | pkgs <- install_sys(c("Rcpp", "simmer")) 17 | expect_equal(pkgs, "simmer") 18 | expect_equal(installed, "Rcpp") 19 | 20 | source("teardown.R") 21 | -------------------------------------------------------------------------------- /inst/tinytest/test_scripts.R: -------------------------------------------------------------------------------- 1 | call_scripts <- function(args=NULL) { 2 | cmd <- paste(R.home("bin/Rscript"), "-e bspm:::scripts", args, "2>&1") 3 | system(cmd, intern=TRUE) 4 | } 5 | 6 | ## list scripts 7 | expect_silent(x <- call_scripts()) 8 | expect_true(any(grepl("mass_move # Call moveto_sys", x))) 9 | 10 | ## script not found 11 | expect_warning(x <- call_scripts("asdf")) 12 | expect_true(any(grepl("not found", x))) 13 | 14 | ## script found, no arguments 15 | expect_warning(x <- call_scripts("mass_move")) 16 | expect_true(any(grepl("Error: no user or library", x))) 17 | 18 | ## script found, help 19 | expect_silent(x <- call_scripts("mass_move -h")) 20 | expect_true(any(grepl("Usage: mass_move", x))) 21 | -------------------------------------------------------------------------------- /inst/tinytest/setup.R: -------------------------------------------------------------------------------- 1 | mock <- function(fun, new, pkg, envir=getOption("mock")) { 2 | stopifnot(is.function(new)) 3 | ns <- asNamespace(pkg) 4 | assign(paste(pkg, fun), get(fun, ns), envir) 5 | unlockBinding(fun, ns) 6 | assign(fun, new, ns) 7 | lockBinding(fun, ns) 8 | } 9 | 10 | unmock <- function(fun, pkg, envir=getOption("mock")) { 11 | stopifnot(is.function(old <- get0(paste(pkg, fun), envir))) 12 | ns <- asNamespace(pkg) 13 | unlockBinding(fun, ns) 14 | assign(fun, old, ns) 15 | lockBinding(fun, ns) 16 | rm(list=paste(pkg, fun), envir=envir) 17 | } 18 | 19 | unmock_all <- function(envir=getOption("mock")) { 20 | for (name in strsplit(ls(envir), " ")) 21 | unmock(name[2], name[1], envir=envir) 22 | } 23 | 24 | options(mock=new.env(parent=emptyenv())) 25 | reg.finalizer(getOption("mock"), unmock_all) 26 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /tests/r2u.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | eval $(cat /etc/os-release) 5 | RVER=$(Rscript -e 'cat(as.character(getRversion()))') 6 | 7 | # Tests for fast path 8 | echo "options(bspm.version.check=FALSE)" >> /etc/R/Rprofile.site 9 | 10 | echo "TEST: install GitHub package" 11 | installGithub.r MangoTheCat/visualTest 12 | 13 | echo "TEST: install Bioc package" 14 | install.r BiocParallel 15 | 16 | echo "TEST: install binary deps + binary from r-universe" 17 | REPO_URL="https://eddelbuettel.r-universe.dev/bin/linux/$VERSION_CODENAME/${RVER%.*}" 18 | install2.r -r $REPO_URL RcppKalman 19 | 20 | # Tests for default path 21 | echo "options(bspm.version.check=TRUE)" >> /etc/R/Rprofile.site 22 | echo "options(install.packages.compile.from.source='never')" >> /etc/R/Rprofile.site 23 | 24 | echo "TEST: install suggested packages overlapping the requested ones" 25 | install2.r -d TRUE units dplyr 26 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: r-cran-bspm 2 | Section: gnu-r 3 | Priority: optional 4 | Maintainer: Dirk Eddelbuettel 5 | Build-Depends: debhelper (>= 10), r-base-dev (>= 4.0.0), dh-r, python3-apt, python3-dbus, python3-gi 6 | Standards-Version: 4.5.0 7 | Vcs-Browser: https://salsa.debian.org/edd/r-cran-bspm 8 | Vcs-Git: https://salsa.debian.org/edd/r-cran-bspm.git 9 | Homepage: https://cran.r-project.org/package=bspm 10 | 11 | Package: r-cran-bspm 12 | Architecture: all 13 | Depends: ${misc:Depends}, ${R:Depends}, python3-apt, python3-dbus, python3-gi 14 | Description: GNU R package offering a bridge to the system package managers 15 | The package enables binary package installations on Linux distributions 16 | without administrative privileges. Provides functions to manage packages 17 | via the distribution's package manager. Also provides transparent 18 | integration with R's 'install.packages' and a fallback mechanism. 19 | -------------------------------------------------------------------------------- /man/bspm-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bridge.R 3 | \docType{package} 4 | \name{bspm-package} 5 | \alias{bspm} 6 | \alias{bspm-package} 7 | \title{\pkg{bspm}: Bridge to System Package Manager} 8 | \description{ 9 | Enables binary package installations on Linux distributions. 10 | Provides functions to manage packages via the distribution's package 11 | manager. Also provides transparent integration with R's \code{install.packages} 12 | and a fallback mechanism. When installed as a system package, interacts 13 | with the system's package manager without requiring administrative 14 | privileges via an integrated D-Bus service; otherwise, uses sudo. 15 | Currently, the following backends are supported: DNF, APT, ALPM. 16 | } 17 | \references{ 18 | \url{https://cran4linux.github.io/bspm/} 19 | } 20 | \seealso{ 21 | \code{\link{manager}}, \code{\link{integration}}, 22 | \code{\link{bspm-scripts}}, \code{\link{bspm-options}} 23 | } 24 | \author{ 25 | Iñaki Ucar 26 | } 27 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /404.html 5 | 6 | 7 | /LICENSE-text.html 8 | 9 | 10 | /authors.html 11 | 12 | 13 | /index.html 14 | 15 | 16 | /news/index.html 17 | 18 | 19 | /reference/bspm-options.html 20 | 21 | 22 | /reference/bspm-package.html 23 | 24 | 25 | /reference/bspm-scripts.html 26 | 27 | 28 | /reference/index.html 29 | 30 | 31 | /reference/integration.html 32 | 33 | 34 | /reference/manager.html 35 | 36 | 37 | /reference/shadowed_packages.html 38 | 39 | 40 | /slides/20210709-useR2021_talk.html 41 | 42 | 43 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ "$(uname -s)" = "Linux" ] && { 4 | [ $(id -u) -eq 0 ] || [ "$BUILD_ROOT" != "" ] 5 | } && true || exit 0 6 | 7 | . inst/service/dbus-paths 8 | 9 | subst() { 10 | echo "* installing $3" 11 | DIR=`pwd` 12 | cd $1 && cat $2 | 13 | sed "s @BUS_NAME@ $BUS_NAME g" | 14 | sed "s @R_LIBRARY_DIR@ ${R_LIBRARY_DIR#"$BUILD_ROOT"} g" > $3 15 | cd $DIR 16 | } 17 | 18 | if [ ! -z "$PKG_PREF" ]; then 19 | for pref in $PKG_PREF; do echo $pref; done > inst/service/bspm.pref 20 | for excl in $PKG_EXCL; do echo $excl; done > inst/service/bspm.excl 21 | touch inst/service/nodiscover 22 | sed -i '/discover/d' NAMESPACE 23 | fi 24 | 25 | if [ "$1" != "--without-dbus-service" ]; then 26 | SERVICE_DIR="$BUILD_ROOT/usr/share/dbus-1/system-services" 27 | SYSCONF_DIR="$BUILD_ROOT/etc/dbus-1/system.d" 28 | mkdir -p $SERVICE_DIR $SYSCONF_DIR || exit 1 29 | subst inst/service dbus.service.in $SERVICE_DIR/$BUS_NAME.service 30 | subst inst/service dbus.conf.in $SYSCONF_DIR/$BUS_NAME.conf 31 | fi 32 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: bspm 2 | Type: Package 3 | Title: Bridge to System Package Manager 4 | Version: 0.5.7.2 5 | Authors@R: c( 6 | person("Iñaki", "Ucar", email="iucar@fedoraproject.org", 7 | role=c("aut", "cph", "cre"), comment=c(ORCID="0000-0001-6403-5550"))) 8 | Description: Enables binary package installations on Linux distributions. 9 | Provides functions to manage packages via the distribution's package 10 | manager. Also provides transparent integration with R's install.packages() 11 | and a fallback mechanism. When installed as a system package, interacts 12 | with the system's package manager without requiring administrative 13 | privileges via an integrated D-Bus service; otherwise, uses sudo. 14 | Currently, the following backends are supported: DNF, APT, ALPM. 15 | License: MIT + file LICENSE 16 | Encoding: UTF-8 17 | OS_type: unix 18 | SystemRequirements: systemd, dbus-python, PyGObject, python-(dnf|apt|alpm) 19 | Suggests: tinytest 20 | URL: https://cran4linux.github.io/bspm/ 21 | BugReports: https://github.com/cran4linux/bspm/issues 22 | RoxygenNote: 7.3.2 23 | Roxygen: list(old_usage = TRUE) 24 | -------------------------------------------------------------------------------- /R/options.R: -------------------------------------------------------------------------------- 1 | #' Package Options 2 | #' 3 | #' List of \code{\link{options}()} supported to configure \pkg{bspm}'s behavior. 4 | #' In general, these should be set \emph{before} calling any package function. 5 | #' 6 | #' @section Options specific to \pkg{bspm}: 7 | #' \describe{ 8 | #' \item{\code{bspm.backend.check}:}{logical, default \code{TRUE}. If false, 9 | #' the initial check on \code{\link{enable}()} is not performed.} 10 | #' \item{\code{bspm.version.check}:}{logical, default \code{TRUE}. If false, 11 | #' as many binaries are installed as possible without any version check, 12 | #' and then installation from source is used as a fallback.} 13 | #' \item{\code{bspm.sudo.autodetect}:}{logical, default \code{FALSE}. If true, 14 | #' enables autodetection and selection of password-less \code{sudo}.} 15 | #' \item{\code{bspm.sudo}:}{logical, default \code{FALSE}. If true, forces 16 | #' \code{sudo} unconditionally as the preferred mechanism.} 17 | #' } 18 | #' 19 | #' @section Options from base \R: 20 | #' These are used in the same way as in base \R. See \code{\link{options}} for 21 | #' a detailed description. 22 | #' \itemize{ 23 | #' \item{\code{askYesNo}} 24 | #' \item{\code{install.packages.compile.from.source}} 25 | #' } 26 | #' 27 | #' @name bspm-options 28 | NULL 29 | -------------------------------------------------------------------------------- /man/bspm-options.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/options.R 3 | \name{bspm-options} 4 | \alias{bspm-options} 5 | \title{Package Options} 6 | \description{ 7 | List of \code{\link{options}()} supported to configure \pkg{bspm}'s behavior. 8 | In general, these should be set \emph{before} calling any package function. 9 | } 10 | \section{Options specific to \pkg{bspm}}{ 11 | 12 | \describe{ 13 | \item{\code{bspm.backend.check}:}{logical, default \code{TRUE}. If false, 14 | the initial check on \code{\link{enable}()} is not performed.} 15 | \item{\code{bspm.version.check}:}{logical, default \code{TRUE}. If false, 16 | as many binaries are installed as possible without any version check, 17 | and then installation from source is used as a fallback.} 18 | \item{\code{bspm.sudo.autodetect}:}{logical, default \code{FALSE}. If true, 19 | enables autodetection and selection of password-less \code{sudo}.} 20 | \item{\code{bspm.sudo}:}{logical, default \code{FALSE}. If true, forces 21 | \code{sudo} unconditionally as the preferred mechanism.} 22 | } 23 | } 24 | 25 | \section{Options from base \R}{ 26 | 27 | These are used in the same way as in base \R. See \code{\link{options}} for 28 | a detailed description. 29 | \itemize{ 30 | \item{\code{askYesNo}} 31 | \item{\code{install.packages.compile.from.source}} 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /docs/slides/lib/styles.css: -------------------------------------------------------------------------------- 1 | .footnote { 2 | bottom: 1em; 3 | } 4 | 5 | .pull-left-33 { 6 | float: left; 7 | width: 33%; 8 | } 9 | 10 | .pull-right-66 { 11 | float: right; 12 | width: 63%; 13 | } 14 | 15 | .badge { 16 | display: inline-block; 17 | padding: .25em .4em; 18 | font-size: 75%; 19 | font-weight: 700; 20 | line-height: 1; 21 | text-align: center; 22 | white-space: nowrap; 23 | vertical-align: baseline; 24 | border-radius: .25rem; 25 | color: #fff; 26 | background-color: #28a745; 27 | } 28 | 29 | .vcenter { 30 | margin: 0; 31 | position: absolute; 32 | top: 50%; 33 | -ms-transform: translate(0%, -50%); 34 | transform: translate(0%, -50%); 35 | } 36 | 37 | .pros ul, .cons ul { 38 | list-style: none; 39 | } 40 | 41 | .pros li:before, .cons li:before { 42 | padding-right: 3px; 43 | margin-left: -1em; 44 | } 45 | 46 | .pros li:before { 47 | content: "✔"; 48 | color: green; 49 | } 50 | 51 | .cons li:before { 52 | content: "✗"; 53 | color: red; 54 | } 55 | 56 | .heart { 57 | fill: red; 58 | position: relative; 59 | top: 5px; 60 | width: 50px; 61 | animation: pulse 1s ease infinite; 62 | } 63 | 64 | @keyframes pulse { 65 | 0% { transform: scale(1); } 66 | 50% { transform: scale(1.3); } 67 | 100% { transform: scale(1); } 68 | } 69 | 70 | .fedora code { 71 | background: #3c6eb411 !important; 72 | } 73 | .debian code { 74 | background: #CE005611 !important; 75 | } 76 | .opensuse code { 77 | background: #73BA2511 !important; 78 | } 79 | -------------------------------------------------------------------------------- /man/shadowed_packages.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{shadowed_packages} 4 | \alias{shadowed_packages} 5 | \title{Find Shadowed Packages} 6 | \usage{ 7 | shadowed_packages(lib.loc = NULL) 8 | } 9 | \arguments{ 10 | \item{lib.loc}{character vector describing the location of the \R library 11 | trees to search through, or \code{NULL} for all known trees 12 | (see \code{\link{.libPaths}}).} 13 | } 14 | \value{ 15 | A \code{data.frame} with one row per package, row names the package 16 | names and column names (currently) "Package", "LibPath", "Version", 17 | "Shadow.LibPath", "Shadow.Version", "Shadow.Newer". 18 | } 19 | \description{ 20 | Find packages that are \emph{shadowed} by others in library locations 21 | with a higher priority. 22 | } 23 | \details{ 24 | \R supports setting several locations for library trees. This is a 25 | powerful feature, but many times packages end up installed in multiple 26 | locations, and in such cases \R silently uses the one in the path with the 27 | highest priority (appearing first in \code{\link{.libPaths}}), thus 28 | \emph{shadowing} packages in locations with a lower priority. 29 | 30 | For \pkg{bspm} installations, this means that outdated user packages may 31 | break system libraries. This utility reports packages that are shadowed 32 | (one per row) with information on which location ("Shadow.LibPath") 33 | and version ("Shadow.Version") has priority over it. 34 | The \code{\link{moveto_sys}} method is a great complement to move such 35 | outdated versions to the system libraries. 36 | } 37 | \seealso{ 38 | \code{\link{moveto_sys}} 39 | } 40 | -------------------------------------------------------------------------------- /R/scripts.R: -------------------------------------------------------------------------------- 1 | #' Call Internal Scripts 2 | #' 3 | #' Internal scripts can be called via \code{Rscript} (see examples). 4 | #' 5 | #' @examples 6 | #' \dontrun{ 7 | #' # get a list of available scripts with descriptions 8 | #' Rscript -e bspm:::scripts 9 | #' 10 | #' # see a script's help 11 | #' Rscript -e bspm:::scripts -h 12 | #' 13 | #' # run a script 14 | #' Rscript -e bspm:::scripts [args] 15 | #' } 16 | #' 17 | #' @name bspm-scripts 18 | NULL 19 | 20 | scripts <- function(x, ...) { 21 | exit <- function(status, msg) { 22 | if (!missing(msg)) message("Error: ", msg) 23 | quit(status=status) 24 | } 25 | 26 | ## Borrowed with love from docopt.R: coexist with littler 27 | if (exists("argv", where = .GlobalEnv, inherits = FALSE)) { # nocov start 28 | argv <- get("argv", envir = .GlobalEnv) 29 | if (is.null(argv)) argv <- character() 30 | } else { # nocov end 31 | argv <- commandArgs(TRUE) 32 | } 33 | 34 | scrp <- list.files(system.file("scripts", package="bspm"), full.names=TRUE) 35 | names(scrp) <- tools::file_path_sans_ext(basename(scrp)) 36 | 37 | if (interactive() || !length(argv)) { 38 | for (i in names(scrp)) 39 | cat(paste(i, readLines(scrp[i])[2]), fill=TRUE) 40 | return(invisible()) 41 | } 42 | 43 | if (!argv[1] %in% names(scrp)) 44 | exit(-1, paste0("script '", argv[1], "' not found")) 45 | else exit(system2(scrp[argv[1]], argv[-1])) 46 | } 47 | 48 | class(scripts) <- "bspm cli" 49 | 50 | .onLoad <- function(libname, pkgname) { 51 | registerS3method("print", "bspm cli", scripts, asNamespace(pkgname)) # nocov 52 | } 53 | -------------------------------------------------------------------------------- /docs/slides/lib/remark-css-0.0.1/default.css: -------------------------------------------------------------------------------- 1 | a, a > code { 2 | color: rgb(249, 38, 114); 3 | text-decoration: none; 4 | } 5 | .footnote { 6 | position: absolute; 7 | bottom: 3em; 8 | padding-right: 4em; 9 | font-size: 90%; 10 | } 11 | .remark-code-line-highlighted { background-color: #ffff88; } 12 | 13 | .inverse { 14 | background-color: #272822; 15 | color: #d6d6d6; 16 | text-shadow: 0 0 20px #333; 17 | } 18 | .inverse h1, .inverse h2, .inverse h3 { 19 | color: #f3f3f3; 20 | } 21 | /* Two-column layout */ 22 | .left-column { 23 | color: #777; 24 | width: 20%; 25 | height: 92%; 26 | float: left; 27 | } 28 | .left-column h2:last-of-type, .left-column h3:last-child { 29 | color: #000; 30 | } 31 | .right-column { 32 | width: 75%; 33 | float: right; 34 | padding-top: 1em; 35 | } 36 | .pull-left { 37 | float: left; 38 | width: 47%; 39 | } 40 | .pull-right { 41 | float: right; 42 | width: 47%; 43 | } 44 | .pull-right + * { 45 | clear: both; 46 | } 47 | img, video, iframe { 48 | max-width: 100%; 49 | } 50 | blockquote { 51 | border-left: solid 5px lightgray; 52 | padding-left: 1em; 53 | } 54 | .remark-slide table { 55 | margin: auto; 56 | border-top: 1px solid #666; 57 | border-bottom: 1px solid #666; 58 | } 59 | .remark-slide table thead th { border-bottom: 1px solid #ddd; } 60 | th, td { padding: 5px; } 61 | .remark-slide thead, .remark-slide tfoot, .remark-slide tr:nth-child(even) { background: #eee } 62 | 63 | @page { margin: 0; } 64 | @media print { 65 | .remark-slide-scaler { 66 | width: 100% !important; 67 | height: 100% !important; 68 | transform: scale(1) !important; 69 | top: 0 !important; 70 | left: 0 !important; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /inst/service/backend/_utils.py: -------------------------------------------------------------------------------- 1 | from contextlib import suppress 2 | from pathlib import Path 3 | from os import path 4 | import time, re 5 | 6 | CACHE_INVALIDATION_TIME = 5 # minutes 7 | 8 | def mark(method, prefixes, pkgs, exclusions, trans=None, post=None): 9 | processed = [] 10 | for pkg in pkgs: 11 | for prefix in prefixes: 12 | pkgname = prefix + pkg 13 | if trans is not None: 14 | pkgname = getattr(pkgname, trans)() 15 | if pkgname in exclusions: 16 | continue 17 | with suppress(Exception): 18 | method(pkgname) 19 | processed.append(pkg) 20 | if post is not None: 21 | with suppress(Exception): 22 | post(pkgname) 23 | break 24 | return list(set(pkgs) - set(processed)) 25 | 26 | def cache_update(method, force=False): 27 | cache_file = path.dirname(path.realpath(__file__)) + "/_cache" 28 | try: 29 | cache_time = path.getmtime(cache_file) 30 | except: 31 | cache_time = 0 32 | if force or time.time() - cache_time > CACHE_INVALIDATION_TIME * 60: 33 | method() 34 | Path(cache_file).touch() 35 | 36 | def pkg_strip(prefixes, name): 37 | for prefix in sorted(prefixes, reverse=True): 38 | name = name.replace(prefix, "") 39 | return name 40 | 41 | def ver_strip(version): 42 | version = list(reversed(version.split(":", 1)))[0] 43 | version = version.rsplit("-", 1)[0] 44 | version = version.rsplit("+")[0] 45 | # remove things like .r79, see r-cran-rniftilib 46 | version = re.sub(r"\.r[0-9]+$", "", version) 47 | return version 48 | 49 | def pkg_record(prefixes, name, version, repo): 50 | return ";".join([ 51 | pkg_strip(prefixes, name), 52 | ver_strip(version), 53 | repo.replace(" ", "_") 54 | ]) 55 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This is the Debian GNU/Linux r-cran-bspm package of bspm. The 2 | bspm package offers convolution-type smoothed quantile regression. 3 | It was written by Iñaki Ucar. 4 | 5 | This package was created by Dirk Eddelbuettel . 6 | The sources were downloaded from the main CRAN site 7 | https://cran.r-project.org/src/contrib/ 8 | and are also available from all CRAN mirrors as e.g. 9 | https://cran.us.r-project.org/src/contrib/ 10 | 11 | The package was renamed from its upstream name 'bspm' to 12 | 'r-cran-bspm' to fit the pattern of CRAN (and non-CRAN) 13 | packages for R. 14 | 15 | Files: * 16 | Copyright: 2020 - Iñaki Ucar 17 | License: MIT 18 | 19 | Files: debian/* 20 | Copyright: 2020 Dirk Eddelbuettel 21 | License: GPL-2+ 22 | 23 | On a Debian GNU/Linux system, the GPL license (version 2) is included 24 | in the file /usr/share/common-licenses/GPL-2. 25 | 26 | For reference, the upstream DESCRIPTION file is included below: 27 | 28 | Package: bspm 29 | Type: Package 30 | Title: R Bridge to System Package Manager 31 | Version: 0.3.1 32 | Authors@R: c( 33 | person("Iñaki", "Ucar", email="iucar@fedoraproject.org", 34 | role=c("aut", "cph", "cre"), comment=c(ORCID="0000-0001-6403-5550"))) 35 | Description: Enables binary package installations on Linux distributions 36 | without administrative privileges. Provides functions to manage packages 37 | via the distribution's package manager. Also provides transparent 38 | integration with R's 'install.packages' and a fallback mechanism. 39 | License: MIT + file LICENSE 40 | Encoding: UTF-8 41 | OS_type: unix 42 | SystemRequirements: systemd, python3-dbus, python3-gobject, 43 | python bindings for your distro's package manager 44 | URL: https://github.com/cran4linux/bspm 45 | BugReports: https://github.com/cran4linux/bspm/issues 46 | RoxygenNote: 7.1.1 47 | Roxygen: list(old_usage = TRUE) 48 | 49 | The file LICENSE is included as well: 50 | 51 | YEAR: 2020 52 | COPYRIGHT HOLDER: Iñaki Ucar 53 | 54 | 55 | -------------------------------------------------------------------------------- /inst/tinytest/test_manager_ci.R: -------------------------------------------------------------------------------- 1 | if (!at_home() || !bspm:::root()) 2 | exit_file("not in a CI environment") 3 | 4 | sudo.avail <- unname(nchar(Sys.which("sudo")) > 0) 5 | in.toolbox <- file.exists("/run/.toolboxenv") 6 | if (sudo.avail || in.toolbox) { 7 | expect_true(bspm:::sudo_available()) 8 | } else { 9 | expect_false(bspm:::sudo_available()) 10 | file.create("/run/.toolboxenv") 11 | expect_true(bspm:::sudo_available()) 12 | } 13 | 14 | if (requireNamespace("Rcpp", quietly=TRUE)) 15 | exit_file("not in a clean environment") 16 | 17 | test_methods <- function() { 18 | bspm.pref <- system.file("service/bspm.pref", package="bspm") 19 | bspm.excl <- system.file("service/bspm.excl", package="bspm") 20 | expect_true(all(c(bspm.pref, bspm.excl) == "")) 21 | 22 | discover() 23 | bspm.pref <- system.file("service/bspm.pref", package="bspm") 24 | bspm.excl <- system.file("service/bspm.excl", package="bspm") 25 | expect_true(all(c(bspm.pref, bspm.excl) != "")) 26 | 27 | pkgs <- available_sys() 28 | expect_inherits(pkgs, "matrix") 29 | expect_equal(colnames(pkgs), c("Package", "Version", "Repository")) 30 | expect_true(length(grep("Rcpp", rownames(pkgs), ignore.case=TRUE)) > 0) 31 | 32 | pkgs <- install_sys(c("Rcpp", "NOTAPACKAGE")) 33 | expect_true(requireNamespace("Rcpp", quietly=TRUE)) 34 | expect_equal(pkgs, "NOTAPACKAGE") 35 | 36 | unloadNamespace("Rcpp") 37 | pkgs <- remove_sys(c("Rcpp", "NOTAPACKAGE")) 38 | expect_false(requireNamespace("Rcpp", quietly=TRUE)) 39 | expect_equal(pkgs, "NOTAPACKAGE") 40 | 41 | unlink(c(bspm.pref, bspm.excl)) 42 | } 43 | 44 | test_methods() 45 | 46 | if (!nchar(Sys.which("dbus-daemon")) || !nchar(Sys.which("busctl"))) 47 | exit_file("dbus tools not available") 48 | 49 | dir.create("/run/dbus") 50 | dbus <- system2("dbus-daemon", c("--system", "--print-pid"), stdout=TRUE) 51 | trace(bspm:::backend_call, print=FALSE, tracer=quote(root <- function() FALSE)) 52 | 53 | test_methods() 54 | 55 | untrace(bspm:::backend_call) 56 | tools::pskill(dbus) 57 | unlink("/run/dbus", recursive=TRUE) 58 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /man/integration.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/integration.R 3 | \name{integration} 4 | \alias{integration} 5 | \alias{enable} 6 | \alias{disable} 7 | \title{Enable/Disable Bridge to System Package Manager} 8 | \usage{ 9 | enable() 10 | 11 | disable() 12 | } 13 | \description{ 14 | Functions to enable or disable the integration of \code{\link{install_sys}} 15 | into \code{\link{install.packages}}. When enabled, packages are installed 16 | transparently from system repositories if available, including dependencies, 17 | and from the configured \R repositories if not. 18 | } 19 | \details{ 20 | To enable \pkg{bspm} system-wide by default, include the following: 21 | 22 | \code{suppressMessages(bspm::enable())} 23 | 24 | into the \code{Rprofile.site} file. To enable it just for a particular user, 25 | move that line to the user's \code{~/.Rprofile} instead. 26 | 27 | By default, enabling \pkg{bspm} triggers a check of the backend, and a 28 | warning is raised if the system service is required but not available. To 29 | avoid this check, \code{options(bspm.backend.check=FALSE)} can be set. 30 | 31 | Enabling \pkg{bspm} sets default installation \code{type} to \code{"both"}, 32 | which means 'use binary if available and current, otherwise try source'. 33 | The action if there are source packages which are preferred is controlled by 34 | \code{getOption("install.packages.compile.from.source")}. Set this option to 35 | \code{"never"} to always prefer binaries over source packages, with an 36 | informative message about newer versions available from source. 37 | 38 | If binaries are always preferred and no message is required, a special 39 | \emph{fast} mode can be enabled via \code{options(bspm.version.check=FALSE)}, 40 | (true by default) which completely skips version checking. 41 | } 42 | \examples{ 43 | \dontrun{ 44 | # install 'units' and all its dependencies from the system repos 45 | bspm::enable() 46 | install.packages("units") 47 | 48 | # install packages again from CRAN 49 | bspm::disable() 50 | install.packages("errors") 51 | } 52 | 53 | } 54 | \seealso{ 55 | \code{\link{manager}}, \code{\link{bspm-options}} 56 | } 57 | -------------------------------------------------------------------------------- /inst/scripts/mass_move.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # Call moveto_sys for a list of users and/or libraries (requires sudo access) 3 | 4 | set -e 5 | 6 | usage() { 7 | printf "Usage: $(basename ${0%.*}) [options] user|library ...\n" 8 | printf "\n" 9 | printf "Options:\n" 10 | printf " -r|--run\tMake changes, instead of a dry run\n" 11 | printf " -y|--yes\tAnswer yes for all questions\n" 12 | printf " -h|--help\tPrint this help\n" 13 | exit 0 14 | } 15 | 16 | proceed() { 17 | read -rp "Proceed? [y/n/c] " 18 | [[ ${REPLY,,} =~ ^(c|cancel)$ ]] && exit 1 19 | [[ ${REPLY,,} =~ ^(y|yes)$ ]] 20 | return 21 | } 22 | 23 | while [ ! -z "$1" ]; do 24 | case "$1" in 25 | --run|-r) RUN=true ;; 26 | --yes|-y) YES=true ;; 27 | --help|-h) usage ;; 28 | -*) echo "Error: wrong option '$1'" && exit 1 ;; 29 | *) [ -d "$1" ] && LIBS+=("$1") || USERS+=("$1") ;; 30 | esac 31 | shift 32 | done 33 | 34 | if [ ${#USERS[@]} -eq 0 ] && [ ${#LIBS[@]} -eq 0 ]; then 35 | echo "Error: no user or library provided, use -h for help" 36 | exit 1 37 | fi 38 | 39 | if [ "$RUN" != true ] ; then 40 | echo "NOTE: no changes will be made unless '--run' is specified" 41 | fi 42 | 43 | echo "Gaining sudo access..." 44 | sudo true 45 | 46 | for user in "${USERS[@]}"; do 47 | # check user exists 48 | id $user > /dev/null 2>&1 || continue 49 | # retrieve user library and append if exists 50 | lib=$(sudo -u $user Rscript -e "cat(bspm:::user_lib(), fill=TRUE)") 51 | sudo -u $user [ -d "$lib" ] && LIBS+=("$lib") 52 | done 53 | 54 | for lib in "${LIBS[@]}"; do 55 | # get library owner and report 56 | user=$(sudo ls -ld "$lib" | cut -d" " -f3) 57 | n_before=$(sudo -u $user ls "$lib" | wc -l) 58 | echo "Found $n_before packages in $user's $lib" 59 | # proceed only if run flag was specified 60 | if [ "$RUN" = true ] ; then 61 | # ask user by default 62 | [ "$YES" != true ] && { proceed || continue; } 63 | # move, count again, and report 64 | sudo -u $user Rscript -e "bspm::moveto_sys('$lib')" > /dev/null 65 | n_after=$(sudo -u $user ls "$lib" | wc -l) 66 | echo "Moved $(($n_before-$n_after)) ($n_after left) from $user's $lib" 67 | fi 68 | done 69 | -------------------------------------------------------------------------------- /inst/service/backend/apt.py: -------------------------------------------------------------------------------- 1 | from ._utils import mark, cache_update, pkg_record 2 | from functools import partial 3 | import re 4 | import apt 5 | 6 | # workaround for Ubuntu 18.04 7 | # https://github.com/cran4linux/bspm/issues/15 8 | import os 9 | if not os.getenv("PATH"): 10 | os.environ["PATH"] = "/usr/bin:/usr/sbin:/bin:/sbin" 11 | 12 | def discover(): 13 | aprogress = apt.progress.text.AcquireProgress() 14 | cache = apt.Cache() 15 | cache_update(partial(cache.update, aprogress), force=True) 16 | cache.open() 17 | 18 | pkgs = [x for x in cache.keys() if re.match("^r-(.*)-(.*)", x)] 19 | prefixes = {"-".join(x.split("-")[0:2]) + "-" for x in pkgs} 20 | 21 | cache.close() 22 | 23 | return { 24 | "prefixes": list(prefixes - {"r-doc-", "r-base-"}), 25 | "exclusions": [] 26 | } 27 | 28 | def available(prefixes, exclusions): 29 | aprogress = apt.progress.text.AcquireProgress() 30 | cache = apt.Cache() 31 | cache_update(partial(cache.update, aprogress)) 32 | cache.open() 33 | 34 | q = [x for x in cache.keys() if re.match("|".join(prefixes), x)] 35 | pkgs = [] 36 | for pkg in q: 37 | if pkg in exclusions: 38 | continue 39 | pkgs.append(pkg_record( 40 | prefixes, 41 | cache[pkg].candidate.source_name, 42 | cache[pkg].candidate.version, 43 | cache[pkg].candidate.origins[0].origin 44 | )) 45 | 46 | cache.close() 47 | 48 | return pkgs 49 | 50 | def operation(op, prefixes, pkgs, exclusions): 51 | def cc(cache, method): 52 | def wrapper(pkgname): 53 | getattr(cache[pkgname], "mark_" + method)() 54 | return wrapper 55 | 56 | oprogress = apt.progress.text.OpProgress() 57 | aprogress = apt.progress.text.AcquireProgress() 58 | 59 | cache = apt.Cache(oprogress) 60 | cache_update(partial(cache.update, aprogress)) 61 | cache.open(oprogress) 62 | 63 | notavail = mark(cc(cache, op), prefixes, pkgs, exclusions, trans="lower") 64 | 65 | cache.commit(aprogress) 66 | cache.close() 67 | 68 | return notavail 69 | 70 | def install(prefixes, pkgs, exclusions): 71 | return operation("install", prefixes, pkgs, exclusions) 72 | 73 | def remove(prefixes, pkgs, exclusions): 74 | return operation("delete", prefixes, pkgs, exclusions) 75 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /inst/service/backend/dnf.py: -------------------------------------------------------------------------------- 1 | from ._utils import mark, pkg_record 2 | import sys 3 | import dnf 4 | import dnf.cli.progress 5 | import dnf.cli.output 6 | 7 | def discover(): 8 | progress = dnf.cli.progress.MultiFileProgressMeter(fo=sys.stdout) 9 | base = dnf.Base() 10 | base.conf.read() 11 | base.read_all_repos() 12 | base.repos.all().set_progress_bar(progress) 13 | base.fill_sack() 14 | 15 | q = base.sack.query() 16 | pkgs = q.available().filterm(name__glob="R-*[!-debuginfo][!-devel]") 17 | prefixes = {"-".join(x.name.split("-")[:-1]) + "-" for x in pkgs} 18 | 19 | base.close() 20 | 21 | return { 22 | "prefixes": sorted(list(prefixes - {"R-TH-"})), 23 | "exclusions": ["R-core", "R-core-devel", "R-devel", "R-java", 24 | "R-java-devel", "R-rpm-macros"] 25 | } 26 | 27 | def available(prefixes, exclusions): 28 | progress = dnf.cli.progress.MultiFileProgressMeter(fo=sys.stdout) 29 | base = dnf.Base() 30 | base.conf.read() 31 | base.read_all_repos() 32 | base.repos.all().set_progress_bar(progress) 33 | base.update_cache() 34 | base.fill_sack() 35 | 36 | q = base.sack.query().available().latest() 37 | q = q.filterm(name__glob=[_ + "*" for _ in prefixes]) 38 | pkgs = [] 39 | for pkg in q: 40 | if not pkg.source_name or pkg.name in exclusions: 41 | continue 42 | pkgs.append(pkg_record( 43 | prefixes, 44 | pkg.source_name, 45 | pkg.version, 46 | pkg.reponame 47 | )) 48 | pkgs = list(dict.fromkeys(pkgs)) 49 | 50 | base.close() 51 | 52 | return pkgs 53 | 54 | def install(prefixes, pkgs, exclusions): 55 | progress = dnf.cli.progress.MultiFileProgressMeter(fo=sys.stdout) 56 | base = dnf.Base() 57 | base.conf.read() 58 | base.read_all_repos() 59 | base.repos.all().set_progress_bar(progress) 60 | base.update_cache() 61 | base.fill_sack() 62 | 63 | notavail = mark(base.install, prefixes, pkgs, exclusions, post=base.upgrade) 64 | 65 | base.resolve() 66 | base.download_packages(base.transaction.install_set, progress) 67 | base.do_transaction(dnf.cli.output.CliTransactionDisplay()) 68 | base.close() 69 | 70 | return notavail 71 | 72 | def remove(prefixes, pkgs, exclusions): 73 | base = dnf.Base() 74 | base.conf.read() 75 | base.fill_sack() 76 | 77 | notavail = mark(base.remove, prefixes, pkgs, exclusions) 78 | 79 | base.resolve(True) 80 | base.do_transaction(dnf.cli.output.CliTransactionDisplay()) 81 | base.close() 82 | 83 | return notavail 84 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | if: ${{ !contains(github.event.head_commit.message, '[ci skip]') }} 7 | runs-on: ubuntu-latest 8 | name: ${{ matrix.config.image }}:${{ matrix.config.tag }} 9 | container: 10 | image: ${{ matrix.config.image }}:${{ matrix.config.tag }} 11 | 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | config: 16 | - {image: 'fedora', tag: 'latest'} 17 | - {image: 'debian', tag: 'latest'} 18 | - {image: 'ubuntu', tag: 'latest'} 19 | 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - name: Install dependencies (Fedora) 28 | if: ${{ matrix.config.image == 'fedora' }} 29 | run: | 30 | echo "install_weak_deps=False" >> /etc/dnf/dnf.conf 31 | dnf install -y R-core-devel devscripts-checkbashisms python3-dnf \ 32 | systemd python3-gobject python3-dbus dbus-daemon 33 | 34 | - name: Install dependencies (Debian, Ubuntu) 35 | if: ${{ matrix.config.image != 'fedora' }} 36 | env: 37 | DEBIAN_FRONTEND: noninteractive 38 | run: | 39 | apt update && apt install -y --no-install-recommends \ 40 | r-base-core devscripts python3-apt \ 41 | python3-gi python3-dbus && apt install -y systemd dbus-daemon 42 | 43 | - name: Check 44 | env: 45 | _R_CHECK_CRAN_INCOMING_REMOTE_: false 46 | run: | 47 | export LANG=$(locale -a | grep utf8 | head -n1) 48 | Rscript -e 'install.packages("tinytest", repos="https://cran.r-project.org")' 49 | R CMD build . && mkdir check 50 | R CMD check bspm_*.tar.gz --no-manual -o check 51 | 52 | - name: Upload check results 53 | if: ${{ failure() }} 54 | uses: actions/upload-artifact@master 55 | with: 56 | name: r-${{ matrix.config.image }}-${{ matrix.config.tag }}-results 57 | path: check 58 | 59 | - name: Test coverage 60 | if: ${{ success() && matrix.config.image == 'fedora' }} 61 | run: | 62 | dnf -y install R-covr 63 | Rscript -e 'covr::codecov()' 64 | 65 | r2u: 66 | needs: build 67 | name: r2u tests 68 | runs-on: ubuntu-latest 69 | container: 70 | image: rocker/r2u:jammy 71 | env: 72 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 73 | steps: 74 | - uses: actions/checkout@v3 75 | - name: Install development version 76 | run: R CMD INSTALL . 77 | - name: Run tests 78 | run: ./tests/r2u.sh 79 | -------------------------------------------------------------------------------- /docs/slides/img/fedora.svg: -------------------------------------------------------------------------------- 1 | 2 | 10 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | -------------------------------------------------------------------------------- /inst/service/backend/alpm.py: -------------------------------------------------------------------------------- 1 | from ._utils import mark, pkg_record 2 | from functools import partial 3 | import pycman 4 | 5 | _db_sync = False 6 | _target = None 7 | 8 | def discover(): 9 | # TBD 10 | return { 11 | "prefixes": ["r-"], 12 | "exclusions": [] 13 | } 14 | 15 | def _get_handle(): 16 | def _cb_dl(filename, tx, total): 17 | global _db_sync, _target 18 | if _db_sync: 19 | if tx == 3: 20 | print(" %s" % filename.split(".")[0]) 21 | else: 22 | if filename != _target: 23 | _target = filename 24 | print(" %s" % filename.split(".pkg.")[0]) 25 | 26 | def _cb_event(id, msg): 27 | global _target 28 | if id == 9: 29 | print(":: Processing package changes...") 30 | elif id == 21: 31 | _target = None 32 | print(":: Retrieving packages...") 33 | 34 | def _cb_progress(target, percent, n, i): 35 | global _target 36 | if len(target) > 0 and target != _target: 37 | _target = target 38 | print("(%d/%d) %s" % (i, n, target)) 39 | 40 | args = pycman.action_sync.parse_options([]) 41 | handle = pycman.config.init_with_config_and_options(args) 42 | 43 | handle.dlcb = _cb_dl 44 | handle.eventcb = _cb_event 45 | handle.progresscb = _cb_progress 46 | 47 | return handle 48 | 49 | def _update(handle): 50 | global _db_sync 51 | print(":: Synchronizing package databases...") 52 | _db_sync = True 53 | for db in handle.get_syncdbs(): 54 | db.update(False) 55 | _db_sync = False 56 | 57 | def _install(handle, t, repos, name): 58 | ok, pkg = pycman.action_sync.find_sync_package(name, repos) 59 | t.add_pkg(pkg) 60 | 61 | def _remove(handle, t, repos, name): 62 | pkg = handle.get_localdb().get_pkg(name) 63 | t.remove_pkg(pkg) 64 | 65 | def available(prefixes, exclusions): 66 | handle = _get_handle() 67 | 68 | q = [] 69 | for db in handle.get_syncdbs(): 70 | for prefix in prefixes: 71 | q += [_ for _ in db.search(prefix) if _.name.startswith(prefix)] 72 | pkgs = [] 73 | for pkg in q: 74 | if pkg.name in exclusions: 75 | continue 76 | pkgs.append(pkg_record( 77 | prefixes, 78 | pkg.name, 79 | pkg.version, 80 | pkg.db.name 81 | )) 82 | 83 | return pkgs 84 | 85 | def operation(op, prefixes, pkgs, exclusions): 86 | handle = _get_handle() 87 | repos = dict((db.name, db) for db in handle.get_syncdbs()) 88 | t = handle.init_transaction() 89 | _update(handle) 90 | 91 | fun = partial(op, handle, t, repos) 92 | notavail = mark(fun, prefixes, pkgs, exclusions, trans="lower") 93 | 94 | try: 95 | t.prepare() 96 | t.commit() 97 | except: 98 | pass 99 | t.release() 100 | 101 | return notavail 102 | 103 | def install(prefixes, pkgs, exclusions): 104 | return operation(_install, prefixes, pkgs, exclusions) 105 | 106 | def remove(prefixes, pkgs, exclusions): 107 | return operation(_remove, prefixes, pkgs, exclusions) 108 | -------------------------------------------------------------------------------- /man/manager.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/manager.R 3 | \name{manager} 4 | \alias{manager} 5 | \alias{install_sys} 6 | \alias{remove_sys} 7 | \alias{moveto_sys} 8 | \alias{available_sys} 9 | \alias{discover} 10 | \title{Manage Packages from System Repositories} 11 | \usage{ 12 | install_sys(pkgs) 13 | 14 | remove_sys(pkgs) 15 | 16 | moveto_sys(lib, newer = FALSE) 17 | 18 | available_sys() 19 | 20 | discover() 21 | } 22 | \arguments{ 23 | \item{pkgs}{character vector of names of packages.} 24 | 25 | \item{lib}{a character vector giving the library directories to remove the 26 | packages from. If missing, defaults to the first element in \code{R_LIBS_USER}.} 27 | 28 | \item{newer}{whether to move newer packages from the user library. 29 | The special value \code{"ask"} is also supported.} 30 | } 31 | \value{ 32 | Functions \code{install_sys}, \code{remove_sys}, and \code{moveto_sys} 33 | return, invisibly, a character vector of the names of packages not available 34 | in the system. 35 | 36 | Function \code{available_sys} returns a matrix with one row per 37 | package. Row names are the package names, and column names include 38 | \code{"Package"}, \code{"Version"}, \code{"Repository"}. 39 | } 40 | \description{ 41 | Talk to the system package manager to install/remove... packages from system 42 | repositories (see details for further options). 43 | } 44 | \details{ 45 | If \R runs with root privileges (e.g., in a docker container), these 46 | functions talk directly to the system package manager. Regular users are also 47 | able to install/remove packages without any administrative permission via the 48 | accompanying D-Bus service if \pkg{bspm} is installed as a system package. 49 | If not, these methods fall back on using \code{sudo} to elevate permissions 50 | (or \code{pkexec} in GUIs such as RStudio) in interactive sessions. Note 51 | that, if you want to fall back to \code{sudo} in a non-interactive session, 52 | you need to set \code{options(bspm.sudo=TRUE)}. 53 | 54 | If \code{options(bspm.sudo.autodetect=TRUE)}, \pkg{bspm} tries to detect 55 | whether it is running in an environment where password-less \code{sudo} can 56 | be used (e.g., in a containerized environment such as a Fedora Toolbox) for 57 | every call, and then uses \code{sudo} accordingly. 58 | 59 | The \code{moveto_sys} method moves existing user packages to the 60 | system library to avoid \emph{package shadowing} (i.e., installs the 61 | available system packages and removes copies from the user library; 62 | see \code{\link{shadowed_packages}}). 63 | This provides a mechanism to easily deploy \pkg{bspm} on an existing R 64 | installation with a populated user library. 65 | 66 | The \code{discover} method is only needed when e.g. a new repository 67 | is added that contains packages with different prefixes (for example, your 68 | system repositories may provide packages called \code{r-cran-*} and 69 | \code{r-bioc-*} and then you add a new repository that provides packages 70 | called \code{r-github-*}). Otherwise, it will not have any effect besides 71 | regenerating the internal configuration files. 72 | } 73 | \examples{ 74 | \dontrun{ 75 | # install 'units' and all its dependencies from the system repos 76 | bspm::install_sys("units") 77 | 78 | # now remove it 79 | bspm::remove_sys("units") 80 | 81 | # get available packages 82 | bspm::available_sys() 83 | } 84 | 85 | } 86 | \seealso{ 87 | \code{\link{integration}}, \code{\link{bspm-scripts}} 88 | } 89 | -------------------------------------------------------------------------------- /inst/tinytest/test_integration.R: -------------------------------------------------------------------------------- 1 | source("setup.R") 2 | 3 | # enable / disable ---- 4 | 5 | suppressMessages(untrace(utils::install.packages)) 6 | expect_false(inherits(utils::install.packages, "functionWithTrace")) 7 | 8 | suppressWarnings(expect_message(enable())) 9 | expect_true(inherits(utils::install.packages, "functionWithTrace")) 10 | expect_equal(getOption("pkgType"), "both") 11 | 12 | tracer <- paste(body(utils::install.packages), collapse="") 13 | expect_true(sum(grepl("bspm", tracer, fixed=TRUE)) > 0) 14 | 15 | expect_message(disable()) 16 | expect_false(inherits(utils::install.packages, "functionWithTrace")) 17 | expect_equal(getOption("pkgType"), "source") 18 | 19 | # shim ---- 20 | 21 | test_shim <- function(pkgs, repos = "https://cran.r-project.org", 22 | contriburl = contrib.url(repos, type), method, 23 | dependencies = NA, type = getOption("pkgType"), ...) { 24 | eval(body(bspm:::shim)) 25 | list(pkgs=pkgs, type=type) 26 | } 27 | 28 | expect_error(test_shim(), "no packages") 29 | 30 | ## no return 31 | mock_install <- function(msg) function(...) { warning(msg); character(0) } 32 | mock("install_both", mock_install("both"), "bspm") 33 | mock("install_sys", mock_install("sys"), "bspm") 34 | mock("install_fast", mock_install("fast"), "bspm") 35 | 36 | expect_silent(res <- test_shim("pkg", repos=NULL, type="both")) 37 | expect_equal(res, list(pkgs="pkg", type="source")) 38 | expect_silent(res <- test_shim("pkg", type="source")) 39 | expect_equal(res, list(pkgs="pkg", type="source")) 40 | 41 | expect_warning(res <- test_shim("pkg", type="both"), "both") 42 | expect_equal(res, list(pkgs=character(0), type="source")) 43 | expect_warning(res <- test_shim("pkg", type="binary"), "sys") 44 | expect_equal(res, list(pkgs=character(0), type="source")) 45 | expect_warning(res <- test_shim("pkg", type="binary-source"), "fast") 46 | expect_equal(res, list(pkgs=character(0), type="source")) 47 | 48 | options(bspm.version.check=FALSE) 49 | expect_warning(res <- test_shim("pkg", type="both"), "fast") 50 | expect_equal(res, list(pkgs=character(0), type="source")) 51 | options(bspm.version.check=NULL) 52 | 53 | unmock_all() 54 | 55 | ## return 56 | mock_install <- function(pkgs, contriburl, ...) { 57 | expect_inherits(contriburl, "character") 58 | "notavail" 59 | } 60 | mock("install_both", mock_install, "bspm") 61 | mock("install_sys", function(...) "notavail", "bspm") 62 | mock("install_fast", mock_install, "bspm") 63 | 64 | res <- test_shim("pkg", type="both") 65 | expect_equal(res, list(pkgs="notavail", type="source")) 66 | res <- test_shim("pkg", type="binary") 67 | expect_equal(res, list(pkgs="notavail", type="binary")) 68 | res <- test_shim("pkg", type="binary-source") 69 | expect_equal(res, list(pkgs="notavail", type="source")) 70 | 71 | unmock_all() 72 | 73 | # install functions ---- 74 | 75 | pkgs_sys <- c("BH", "Rcpp", "another") 76 | db <- readRDS("db.rds") 77 | 78 | mock("available.packages", function(...) db, "utils") 79 | mock("installed.packages", pkg="utils", function(...) 80 | matrix(1, dimnames=list(c("codetools"), NULL))) 81 | mock("install_sys", function(pkgs) setdiff(pkgs, pkgs_sys), "bspm") 82 | mock("available_sys", pkg="bspm", function() matrix( 83 | c(pkgs_sys, "1.81.0.0", "1.0.10", "1"), ncol=2, 84 | dimnames=list(tolower(pkgs_sys), c("Package", "Version")) 85 | )) 86 | 87 | pkgs <- c("another", "simmer", "rticles") 88 | deps <- c(unname(unlist(tools::package_dependencies(pkgs, recursive=TRUE))), pkgs) 89 | deps <- setdiff(deps, bspm:::available_sys()[, "Package"]) 90 | deps <- setdiff(deps, rownames(utils::installed.packages())) 91 | 92 | expect_equal(bspm:::install_both(pkgs, dependencies=NA), deps) 93 | expect_equal(bspm:::install_fast(pkgs, dependencies=NA), c("simmer", "rticles")) 94 | 95 | unmock_all() 96 | 97 | source("teardown.R") 98 | -------------------------------------------------------------------------------- /inst/tinytest/test_utils.R: -------------------------------------------------------------------------------- 1 | source("setup.R") 2 | 3 | # shadowed_packages ---- 4 | 5 | df <- shadowed_packages() 6 | expect_inherits(df, "data.frame") 7 | expect_equal(colnames(df), c("Package", "LibPath", "Version", 8 | "Shadow.LibPath", "Shadow.Version", "Shadow.Newer")) 9 | expect_equal(df$Version < df$Shadow.Version, df$Shadow.Newer) 10 | 11 | # pkg_deps, hard_deps ---- 12 | 13 | mock("installed.packages", pkg="utils", function(...) 14 | matrix(1:2, dimnames=list(c("codetools", "rticles"), NULL))) 15 | 16 | pkgs <- c("simmer", "simmer", "utils") 17 | db <- readRDS("db.rds") 18 | 19 | deps <- c("Rcpp", "magrittr", "utils", "methods", "BH") 20 | expect_equal(sort(bspm:::pkg_deps(pkgs, NA, db, all=FALSE)), sort(deps)) 21 | deps <- c(deps[-length(deps)], "simmer") 22 | expect_equal(sort(bspm:::pkg_deps(pkgs, NA, db, all=TRUE)), sort(deps)) 23 | deps <- c(deps, "simmer.plot", "parallel", "testthat", "knitr", "rmarkdown") 24 | expect_equal(sort(bspm:::pkg_deps(pkgs, TRUE, db, all=TRUE)), sort(deps)) 25 | expect_equal(sort(bspm:::pkg_deps(pkgs, "Suggests", db, all=TRUE)), sort(deps)) 26 | 27 | deps <- bspm:::pkg_deps(pkgs, NA, db, all=TRUE) 28 | expect_equal(bspm:::hard_deps(list(bins=deps), db, FALSE), NULL) 29 | expect_equal(bspm:::hard_deps(list(bins=deps), db, TRUE), "BH") 30 | 31 | unmock_all() 32 | 33 | # check_versions ---- 34 | 35 | mock("available_sys", pkg="bspm", function() { 36 | matrix(c("1.81.0.0", "1.0.10", "1"), 37 | dimnames=list(c("bh", "Rcpp", "another"), "Version")) 38 | }) 39 | 40 | pkgs <- c("another", "Rcpp", "BH", "simmer") 41 | db <- readRDS("db.rds") 42 | 43 | out <- bspm:::check_versions(pkgs, db) 44 | expect_equal(out$bins, c("another", "Rcpp", "BH")) 45 | expect_equal(out$srcs, "simmer") 46 | expect_equal(out$binvers, c(another="1", rcpp="1.0.10", bh="1.81.0.0")) 47 | expect_equal(out$srcvers, c(another="0", Rcpp="1.0.10", BH="1.81.0-1")) 48 | # expect_equal(out$later, c(another=FALSE, rcpp=FALSE, bh=TRUE)) 49 | # R >= 4.3 seems to drop names in this case, bug? 50 | expect_equal(unname(out$later), c(FALSE, FALSE, TRUE)) 51 | 52 | unmock_all() 53 | 54 | # remotes_as_newer ---- 55 | 56 | mock("packageDescription", pkg="utils", function(bin, lib, field) { 57 | if (field != "RemoteSha") stop("wrong field") 58 | switch(bin, sha="sha", NA) 59 | }) 60 | 61 | pkgs <- list( 62 | binvers = as.character(c(1, 1, 1)), 63 | srcvers = as.character(c(2, 1, 1)), 64 | bins = c("a", "a", "sha"), 65 | later = c(FALSE, FALSE, FALSE) 66 | ) 67 | expect_equal(bspm:::remotes_as_newer(pkgs)$later, c(FALSE, FALSE, TRUE)) 68 | 69 | unmock_all() 70 | 71 | # ask_user ---- 72 | 73 | ## prefer later sources (default) 74 | options(install.packages.compile.from.source="bypass interactive") 75 | 76 | x <- c(FALSE, FALSE) 77 | expect_silent(later <- bspm:::ask_user(x, c("a", "b"), c(1, 1), c(1, 1))) 78 | expect_equal(later, x) 79 | 80 | x <- c(TRUE, FALSE) 81 | expect_stdout(later <- bspm:::ask_user(x, c("a", "b"), c(1, 1), c(2, 1)), 82 | "available but the source") 83 | expect_equal(later, x) 84 | 85 | x <- c(TRUE, TRUE) 86 | expect_stdout(later <- bspm:::ask_user(x, c("a", "b"), c(1, 1), c(2, 2)), 87 | "available but the source") 88 | expect_equal(later, x) 89 | 90 | ## prefer binaries 91 | options(install.packages.compile.from.source="never") 92 | 93 | x <- c(FALSE, FALSE) 94 | expect_silent(later <- bspm:::ask_user(x, c("a", "b"), c(1, 1), c(1, 1))) 95 | expect_equal(later, x) 96 | 97 | x <- c(TRUE, FALSE) 98 | expect_stdout(later <- bspm:::ask_user(x, c("a", "b"), c(1, 1), c(2, 1)), 99 | "Binaries will be preferred") 100 | expect_equal(later, FALSE) 101 | 102 | x <- c(TRUE, TRUE) 103 | expect_stdout(later <- bspm:::ask_user(x, c("a", "b"), c(1, 1), c(2, 2)), 104 | "Binaries will be preferred") 105 | expect_equal(later, FALSE) 106 | 107 | source("teardown.R") 108 | -------------------------------------------------------------------------------- /R/integration.R: -------------------------------------------------------------------------------- 1 | #' Enable/Disable Bridge to System Package Manager 2 | #' 3 | #' Functions to enable or disable the integration of \code{\link{install_sys}} 4 | #' into \code{\link{install.packages}}. When enabled, packages are installed 5 | #' transparently from system repositories if available, including dependencies, 6 | #' and from the configured \R repositories if not. 7 | #' 8 | #' @details To enable \pkg{bspm} system-wide by default, include the following: 9 | #' 10 | #' \code{suppressMessages(bspm::enable())} 11 | #' 12 | #' into the \code{Rprofile.site} file. To enable it just for a particular user, 13 | #' move that line to the user's \code{~/.Rprofile} instead. 14 | #' 15 | #' By default, enabling \pkg{bspm} triggers a check of the backend, and a 16 | #' warning is raised if the system service is required but not available. To 17 | #' avoid this check, \code{options(bspm.backend.check=FALSE)} can be set. 18 | #' 19 | #' Enabling \pkg{bspm} sets default installation \code{type} to \code{"both"}, 20 | #' which means 'use binary if available and current, otherwise try source'. 21 | #' The action if there are source packages which are preferred is controlled by 22 | #' \code{getOption("install.packages.compile.from.source")}. Set this option to 23 | #' \code{"never"} to always prefer binaries over source packages, with an 24 | #' informative message about newer versions available from source. 25 | #' 26 | #' If binaries are always preferred and no message is required, a special 27 | #' \emph{fast} mode can be enabled via \code{options(bspm.version.check=FALSE)}, 28 | #' (true by default) which completely skips version checking. 29 | #' 30 | #' @seealso \code{\link{manager}}, \code{\link{bspm-options}} 31 | #' 32 | #' @examples 33 | #' \dontrun{ 34 | #' # install 'units' and all its dependencies from the system repos 35 | #' bspm::enable() 36 | #' install.packages("units") 37 | #' 38 | #' # install packages again from CRAN 39 | #' bspm::disable() 40 | #' install.packages("errors") 41 | #' } 42 | #' 43 | #' @name integration 44 | #' @export 45 | enable <- function() { 46 | if (getOption("bspm.backend.check", TRUE)) 47 | backend_check() 48 | options(pkgType="both") 49 | trace(utils::install.packages, print=FALSE, tracer=body(shim)) 50 | invisible() 51 | } 52 | 53 | #' @name integration 54 | #' @export 55 | disable <- function() { 56 | options(pkgType="source") 57 | untrace(utils::install.packages) 58 | invisible() 59 | } 60 | 61 | shim <- function() { 62 | if (missing(pkgs)) stop("no packages were specified") 63 | 64 | if (type == "both" && !getOption("bspm.version.check", TRUE)) 65 | type <- "binary-source" 66 | 67 | if (is.null(repos)) { 68 | type <- "source" 69 | } else if (type == "both") { # regular install, with version check 70 | pkgs <- utils::getFromNamespace("install_both", asNamespace("bspm"))( 71 | pkgs, contriburl, method, dependencies, ...) 72 | type <- "source" 73 | } else if (type == "binary") { # install binaries and fail otherwise 74 | if (!length(pkgs <- bspm::install_sys(pkgs))) 75 | type <- "source" 76 | } else if (type == "binary-source") { # fast path, no version check 77 | type <- "both" # restore 78 | pkgs <- utils::getFromNamespace("install_fast", asNamespace("bspm"))( 79 | pkgs, contriburl, method, ...) 80 | type <- "source" 81 | } 82 | } 83 | 84 | formals(shim) <- formals(utils::install.packages) 85 | utils::globalVariables("contrib.url") # argument 86 | 87 | # install binaries with checks for newer versions from source 88 | install_both <- function(pkgs, contriburl, method, dependencies, ...) { 89 | db <- utils::available.packages(contriburl=contriburl, method=method, ...) 90 | pkgs <- pkg_deps(pkgs, dependencies, db, all=TRUE) 91 | pkgs <- check_versions(pkgs, db) 92 | mask <- ask_user(pkgs$later, pkgs$bins, pkgs$binvers, pkgs$srcvers) 93 | hard <- hard_deps(pkgs, db, mask) 94 | pkgs <- c(install_sys(c(pkgs$bins[!mask], hard)), pkgs$bins[mask], pkgs$srcs) 95 | pkgs 96 | } 97 | 98 | # install as many binaries as possible and fallback to source 99 | install_fast <- function(pkgs, contriburl, method, ...) { 100 | if (length(pkgs <- install_sys(pkgs))) { 101 | db <- utils::available.packages(contriburl=contriburl, method=method, ...) 102 | install_sys(pkg_deps(pkgs, NA, db=db, all=FALSE)) 103 | } 104 | pkgs 105 | } 106 | -------------------------------------------------------------------------------- /docs/slides/lib/remark-css-0.0.1/metropolis.css: -------------------------------------------------------------------------------- 1 | .remark-slide-content { 2 | background-color: #FAFAFA; 3 | border-top: 80px solid #23373B; 4 | font-size: 20px; 5 | font-weight: 300; 6 | line-height: 1.5; 7 | padding: 1em 2em 1em 2em 8 | } 9 | 10 | .title-slide .inverse .remark-slide-content { 11 | background-color: #FAFAFA; 12 | } 13 | 14 | .inverse { 15 | background-color: #23373B; 16 | text-shadow: none; 17 | } 18 | 19 | /* Removes colored bar from top of the slide resulting in a clear slide */ 20 | .clear{ 21 | border-top: 0px solid #FAFAFA; 22 | } 23 | 24 | h1 { 25 | font-weight: normal; 26 | margin-top: -95px; 27 | margin-left: -00px; 28 | color: #FAFAFA; 29 | } 30 | 31 | h2, h3, h4 { 32 | padding-top: -15px; 33 | padding-bottom: 00px; 34 | color: #1A292C; 35 | text-shadow: none; 36 | font-weight: 400; 37 | text-align: left; 38 | margin-left: 00px; 39 | margin-bottom: -10px; 40 | } 41 | 42 | .remark-slide-content h1 { 43 | font-size: 45px; 44 | } 45 | 46 | .remark-slide-content h2 { 47 | font-size: 35px; 48 | } 49 | 50 | .remark-slide-content h3 { 51 | font-size: 30px; 52 | } 53 | 54 | .left-column h2, .left-column h3, .left-column h4 { 55 | color: #777; 56 | } 57 | 58 | .left-column h2:last-of-type, .left-column h3:last-child { 59 | color: #1A292C; 60 | } 61 | 62 | .title-slide { 63 | background-color: #FAFAFA; 64 | border-top: 80px solid #FAFAFA; 65 | } 66 | 67 | .title-slide h1 { 68 | color: #1A292C; 69 | font-size: 40px; 70 | text-shadow: none; 71 | font-weight: 400; 72 | text-align: left; 73 | margin-left: 15px; 74 | padding-top: 80px; 75 | } 76 | .title-slide h2 { 77 | margin-top: -25px; 78 | padding-bottom: -20px; 79 | color: #1A292C; 80 | text-shadow: none; 81 | font-weight: 300; 82 | font-size: 35px; 83 | text-align: left; 84 | margin-left: 15px; 85 | } 86 | .title-slide h3 { 87 | color: #1A292C; 88 | text-shadow: none; 89 | font-weight: 300; 90 | font-size: 25px; 91 | text-align: left; 92 | margin-left: 15px; 93 | margin-bottom: -30px; 94 | } 95 | 96 | hr, .title-slide h2::after, .mline h1::after { 97 | content: ''; 98 | display: block; 99 | border: none; 100 | background-color: #EB811B; 101 | color: #EB811B; 102 | height: 1px; 103 | } 104 | 105 | hr, .mline h1::after { 106 | margin: 1em 15px 0 15px; 107 | } 108 | 109 | .title-slide h2::after { 110 | margin: 10px 15px 35px 0; 111 | } 112 | 113 | .mline h1::after { 114 | margin: 10px 15px 0 15px; 115 | } 116 | 117 | .remark-slide-number { 118 | font-size: 13pt; 119 | color: #272822; 120 | opacity: 1; 121 | } 122 | .inverse .remark-slide-number { 123 | font-size: 13pt; 124 | color: #FAFAFA; 125 | opacity: 1; 126 | } 127 | 128 | /* turns off slide numbers for title page: https://github.com/gnab/remark/issues/298 */ 129 | .title-slide .remark-slide-number { 130 | display: none; 131 | } 132 | 133 | .remark-inline-code { 134 | /* background: #F5F5F5; /* lighter */ 135 | background: #e7e8e2; /* darker */ 136 | border-radius: 3px; 137 | padding: 4px; 138 | } 139 | 140 | .code10 .remark-code { 141 | font-size: 10%; 142 | } 143 | 144 | .code20 .remark-code { 145 | font-size: 20%; 146 | } 147 | 148 | .code30 .remark-code { 149 | font-size: 30%; 150 | } 151 | 152 | .code40 .remark-code { 153 | font-size: 40%; 154 | } 155 | 156 | .code50 .remark-code { 157 | font-size: 50%; 158 | } 159 | 160 | .code60 .remark-code { 161 | font-size: 60%; 162 | } 163 | 164 | .code70 .remark-code { 165 | font-size: 70%; 166 | } 167 | 168 | .code80 .remark-code { 169 | font-size: 80%; 170 | } 171 | 172 | .code90 .remark-code { 173 | font-size: 90%; 174 | } 175 | 176 | .code100 .remark-code { 177 | font-size: 100%; 178 | } 179 | 180 | .font10 { 181 | font-size: 10%; 182 | } 183 | 184 | .font20 { 185 | font-size: 20%; 186 | } 187 | 188 | .font30 { 189 | font-size: 30%; 190 | } 191 | 192 | .font40 { 193 | font-size: 40%; 194 | } 195 | 196 | .font50 { 197 | font-size: 50%; 198 | } 199 | 200 | .font60 { 201 | font-size: 60%; 202 | } 203 | 204 | .font70 { 205 | font-size: 70%; 206 | } 207 | 208 | .font80 { 209 | font-size: 80%; 210 | } 211 | 212 | .font90 { 213 | font-size: 90%; 214 | } 215 | 216 | .font100 { 217 | font-size: 100%; 218 | } 219 | 220 | .font110 { 221 | font-size: 110%; 222 | } 223 | 224 | .font120 { 225 | font-size: 120%; 226 | } 227 | 228 | .font130 { 229 | font-size: 130%; 230 | } 231 | 232 | .font140 { 233 | font-size: 140%; 234 | } 235 | 236 | .font150 { 237 | font-size: 150%; 238 | } 239 | 240 | .font160 { 241 | font-size: 160%; 242 | } 243 | .font170 { 244 | font-size: 170%; 245 | } 246 | .font180 { 247 | font-size: 180%; 248 | } 249 | .font190 { 250 | font-size: 190%; 251 | } 252 | .font200 { 253 | font-size: 200%; 254 | } 255 | -------------------------------------------------------------------------------- /R/bridge.R: -------------------------------------------------------------------------------- 1 | #' \pkg{bspm}: Bridge to System Package Manager 2 | #' 3 | #' Enables binary package installations on Linux distributions. 4 | #' Provides functions to manage packages via the distribution's package 5 | #' manager. Also provides transparent integration with R's \code{install.packages} 6 | #' and a fallback mechanism. When installed as a system package, interacts 7 | #' with the system's package manager without requiring administrative 8 | #' privileges via an integrated D-Bus service; otherwise, uses sudo. 9 | #' Currently, the following backends are supported: DNF, APT, ALPM. 10 | #' 11 | #' @author Iñaki Ucar 12 | #' 13 | #' @references \url{https://cran4linux.github.io/bspm/} 14 | #' 15 | #' @name bspm-package 16 | #' 17 | #' @seealso \code{\link{manager}}, \code{\link{integration}}, 18 | #' \code{\link{bspm-scripts}}, \code{\link{bspm-options}} 19 | "_PACKAGE" 20 | 21 | utils::globalVariables(c("BUS_NAME", "OPATH", "IFACE")) 22 | 23 | system2nowarn <- function(...) suppressWarnings(system2(...)) 24 | 25 | backend_check <- function() { 26 | if (!root() && !sudo_preferred() && !dbus_service_alive()) 27 | warning(call.=FALSE, paste( 28 | sep="\n\n", "D-Bus service not found!", 29 | paste0(collapse="\n", strwrap(exdent=2, paste( 30 | "- If you are in a container environment, please consider adding", 31 | "the following to your configuration to silence this warning:" 32 | ))), 33 | " options(bspm.sudo = TRUE)", 34 | paste0(collapse="\n", strwrap(exdent=2, paste( 35 | "- If you are in a desktop/server environment, please remove any", 36 | "'bspm' installation from the user library and force a new system", 37 | "installation as follows:" 38 | ))), 39 | " $ sudo Rscript --vanilla -e 'install.packages(\"bspm\", repos=\"https://cran.r-project.org\")'" 40 | )) 41 | } 42 | 43 | backend_call <- function(method, pkgs) { 44 | if (!missing(pkgs) && !length(pkgs)) 45 | return(invisible()) 46 | 47 | if (root()) 48 | return(root_call(method, pkgs)) 49 | 50 | if (sudo_preferred()) 51 | return(sudo_call(method, pkgs, force=TRUE)) 52 | 53 | if (dbus_service_alive()) 54 | return(dbus_call(method, pkgs)) 55 | 56 | if (interactive()) 57 | return(sudo_call(method, pkgs)) 58 | 59 | stop("cannot connect to the system package manager", call.=FALSE) 60 | } 61 | 62 | root <- function() { 63 | Sys.info()["effective_user"] == "root" 64 | } 65 | 66 | root_call <- function(method, pkgs, sudo=NULL) { 67 | tmp <- tmp2 <- tempfile() 68 | # workaround, see #13 69 | if (length(strsplit(tmp2, "/")[[1]]) == 3) { 70 | dir.create(tmp) 71 | tmp <- paste0(tmp, tempfile(tmpdir="")) 72 | } 73 | file.create(tmp) 74 | on.exit(unlink(tmp2, recursive=TRUE, force=TRUE)) 75 | 76 | cmd <- system.file("service/bspm.py", package="bspm") 77 | args <- c(method, "-o", tmp) 78 | if (!missing(pkgs)) 79 | args <- c(args, pkgs) 80 | if (!is.null(sudo)) { 81 | args <- c(cmd, args) 82 | cmd <- sudo 83 | } 84 | out <- system2nowarn(cmd, args, stderr=FALSE) 85 | tmp <- readLines(tmp) 86 | 87 | if (out != 0) 88 | stop(paste(tmp, collapse="\n"), call.=FALSE) 89 | tmp 90 | } 91 | 92 | dbus_service_alive <- function() { 93 | source(system.file("service/dbus-paths", package="bspm"), local=TRUE) 94 | 95 | cmd <- Sys.which("busctl") 96 | args <- c("list", "--no-pager") 97 | out <- try(system2nowarn(cmd, args, stdout=TRUE, stderr=TRUE), silent=TRUE) 98 | 99 | if (inherits(out, "try-error") || !any(grepl(BUS_NAME, out))) 100 | return(FALSE) 101 | return(TRUE) 102 | } 103 | 104 | dbus_call <- function(method, pkgs) { 105 | source(system.file("service/dbus-paths", package="bspm"), local=TRUE) 106 | 107 | cmd <- Sys.which("busctl") 108 | args <- c("call", "--timeout=1h", BUS_NAME, OPATH, IFACE, method) 109 | if (!missing(pkgs)) 110 | args <- c(args, "ias", Sys.getpid(), length(pkgs), pkgs) 111 | else args <- c(args, "i", Sys.getpid()) 112 | out <- system2nowarn(cmd, args, stdout=TRUE, stderr=TRUE) 113 | 114 | if (!length(out)) 115 | return(out) 116 | status <- attr(out, "status") 117 | if (!is.null(status) && status != 0) 118 | stop("dbus: ", out, call.=FALSE) 119 | cat("\n") 120 | 121 | out <- gsub('"', "", out) 122 | out <- strsplit(out, " ")[[1]][-(1:2)] 123 | out 124 | } 125 | 126 | sudo_call <- function(method, pkgs, force=FALSE) { 127 | if (!isatty(stdin()) && !force) 128 | cmd <- "pkexec" 129 | else cmd <- "sudo" 130 | 131 | sudo <- Sys.which(cmd) 132 | if (!nchar(sudo)) 133 | stop(cmd, " command not found", call.=FALSE) 134 | 135 | root_call(method, pkgs, sudo=sudo) 136 | } 137 | 138 | sudo_available <- function() { 139 | nopass <- !system2nowarn("sudo", c("-n", "true"), stdout=FALSE, stderr=FALSE) 140 | toolbox <- file.exists("/run/.toolboxenv") # see #27 141 | nopass || toolbox 142 | } 143 | 144 | sudo_preferred <- function() { 145 | sudo <- getOption("bspm.sudo.autodetect", FALSE) && sudo_available() 146 | sudo || getOption("bspm.sudo", FALSE) 147 | } 148 | -------------------------------------------------------------------------------- /R/manager.R: -------------------------------------------------------------------------------- 1 | #' Manage Packages from System Repositories 2 | #' 3 | #' Talk to the system package manager to install/remove... packages from system 4 | #' repositories (see details for further options). 5 | #' 6 | #' @param pkgs character vector of names of packages. 7 | #' @return Functions \code{install_sys}, \code{remove_sys}, and \code{moveto_sys} 8 | #' return, invisibly, a character vector of the names of packages not available 9 | #' in the system. 10 | #' 11 | #' @details If \R runs with root privileges (e.g., in a docker container), these 12 | #' functions talk directly to the system package manager. Regular users are also 13 | #' able to install/remove packages without any administrative permission via the 14 | #' accompanying D-Bus service if \pkg{bspm} is installed as a system package. 15 | #' If not, these methods fall back on using \code{sudo} to elevate permissions 16 | #' (or \code{pkexec} in GUIs such as RStudio) in interactive sessions. Note 17 | #' that, if you want to fall back to \code{sudo} in a non-interactive session, 18 | #' you need to set \code{options(bspm.sudo=TRUE)}. 19 | #' 20 | #' If \code{options(bspm.sudo.autodetect=TRUE)}, \pkg{bspm} tries to detect 21 | #' whether it is running in an environment where password-less \code{sudo} can 22 | #' be used (e.g., in a containerized environment such as a Fedora Toolbox) for 23 | #' every call, and then uses \code{sudo} accordingly. 24 | #' 25 | #' @seealso \code{\link{integration}}, \code{\link{bspm-scripts}} 26 | #' 27 | #' @examples 28 | #' \dontrun{ 29 | #' # install 'units' and all its dependencies from the system repos 30 | #' bspm::install_sys("units") 31 | #' 32 | #' # now remove it 33 | #' bspm::remove_sys("units") 34 | #' 35 | #' # get available packages 36 | #' bspm::available_sys() 37 | #' } 38 | #' 39 | #' @name manager 40 | #' @export 41 | install_sys <- function(pkgs) invisible(backend_call("install", pkgs)) 42 | 43 | #' @name manager 44 | #' @export 45 | remove_sys <- function(pkgs) invisible(backend_call("remove", pkgs)) 46 | 47 | #' @param lib a character vector giving the library directories to remove the 48 | #' packages from. If missing, defaults to the first element in \code{R_LIBS_USER}. 49 | #' @param newer whether to move newer packages from the user library. 50 | #' The special value \code{"ask"} is also supported. 51 | #' 52 | #' @details The \code{moveto_sys} method moves existing user packages to the 53 | #' system library to avoid \emph{package shadowing} (i.e., installs the 54 | #' available system packages and removes copies from the user library; 55 | #' see \code{\link{shadowed_packages}}). 56 | #' This provides a mechanism to easily deploy \pkg{bspm} on an existing R 57 | #' installation with a populated user library. 58 | #' 59 | #' @name manager 60 | #' @export 61 | moveto_sys <- function(lib, newer=FALSE) { 62 | stopifnot(is.logical(newer) || newer == "ask") 63 | if (missing(lib)) lib <- user_lib() 64 | if (!dir.exists(lib)) return(invisible()) 65 | 66 | if (isTRUE(newer)) { 67 | pkgs <- utils::installed.packages(lib)[, "Package"] 68 | notavail <- install_sys(pkgs) 69 | utils::remove.packages(setdiff(pkgs, notavail), lib) 70 | invisible(notavail) 71 | } else { 72 | db <- utils::installed.packages(lib) 73 | pkgs <- row.names(db) 74 | pkgs <- remotes_as_newer(check_versions(pkgs, db), lib) 75 | later <- pkgs$later; if (interactive() && newer == "ask") 76 | later <- ask_user(pkgs$later, pkgs$bins, pkgs$binvers, pkgs$srcvers) 77 | install_sys(pkgs$bins[!later]) 78 | utils::remove.packages(pkgs$bins[!later], lib) 79 | invisible(c(pkgs$bins[later], pkgs$srcs)) 80 | } 81 | } 82 | 83 | user_lib <- function() 84 | unlist(strsplit(Sys.getenv("R_LIBS_USER"), .Platform$path.sep))[1L] 85 | 86 | #' @return Function \code{available_sys} returns a matrix with one row per 87 | #' package. Row names are the package names, and column names include 88 | #' \code{"Package"}, \code{"Version"}, \code{"Repository"}. 89 | #' 90 | #' @name manager 91 | #' @export 92 | available_sys <- function() { 93 | pkgs <- do.call(rbind, strsplit(backend_call("available"), ";")) 94 | colnames(pkgs) <- c("Package", "Version", "Repository") 95 | pkgs[, "Version"] <- gsub("_", "-", pkgs[, "Version"], fixed=TRUE) #71 Arch 96 | 97 | vers <- package_version(pkgs[, "Version"]) 98 | pkgs <- pkgs[order(pkgs[, "Package"], vers, decreasing=TRUE), ] 99 | pkgs <- pkgs[!duplicated(pkgs[, "Package"]), ] 100 | pkgs <- pkgs[order(pkgs[, "Package"]), ] 101 | 102 | rownames(pkgs) <- pkgs[, 1] 103 | pkgs 104 | } 105 | 106 | #' @details The \code{discover} method is only needed when e.g. a new repository 107 | #' is added that contains packages with different prefixes (for example, your 108 | #' system repositories may provide packages called \code{r-cran-*} and 109 | #' \code{r-bioc-*} and then you add a new repository that provides packages 110 | #' called \code{r-github-*}). Otherwise, it will not have any effect besides 111 | #' regenerating the internal configuration files. 112 | #' 113 | #' @name manager 114 | #' @export 115 | discover <- function() invisible(backend_call("discover")) 116 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('nav.navbar').headroom(); 6 | 7 | Toc.init({ 8 | $nav: $("#toc"), 9 | $scope: $("main h2, main h3, main h4, main h5, main h6") 10 | }); 11 | 12 | if ($('#toc').length) { 13 | $('body').scrollspy({ 14 | target: '#toc', 15 | offset: $("nav.navbar").outerHeight() + 1 16 | }); 17 | } 18 | 19 | // Activate popovers 20 | $('[data-bs-toggle="popover"]').popover({ 21 | container: 'body', 22 | html: true, 23 | trigger: 'focus', 24 | placement: "top", 25 | sanitize: false, 26 | }); 27 | 28 | $('[data-bs-toggle="tooltip"]').tooltip(); 29 | 30 | /* Clipboard --------------------------*/ 31 | 32 | function changeTooltipMessage(element, msg) { 33 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 34 | element.setAttribute('data-original-title', msg); 35 | $(element).tooltip('show'); 36 | element.setAttribute('data-original-title', tooltipOriginalTitle); 37 | } 38 | 39 | if(ClipboardJS.isSupported()) { 40 | $(document).ready(function() { 41 | var copyButton = ""; 42 | 43 | $("div.sourceCode").addClass("hasCopyButton"); 44 | 45 | // Insert copy buttons: 46 | $(copyButton).prependTo(".hasCopyButton"); 47 | 48 | // Initialize tooltips: 49 | $('.btn-copy-ex').tooltip({container: 'body'}); 50 | 51 | // Initialize clipboard: 52 | var clipboard = new ClipboardJS('[data-clipboard-copy]', { 53 | text: function(trigger) { 54 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 55 | } 56 | }); 57 | 58 | clipboard.on('success', function(e) { 59 | changeTooltipMessage(e.trigger, 'Copied!'); 60 | e.clearSelection(); 61 | }); 62 | 63 | clipboard.on('error', function() { 64 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 65 | }); 66 | 67 | }); 68 | } 69 | 70 | /* Search marking --------------------------*/ 71 | var url = new URL(window.location.href); 72 | var toMark = url.searchParams.get("q"); 73 | var mark = new Mark("main#main"); 74 | if (toMark) { 75 | mark.mark(toMark, { 76 | accuracy: { 77 | value: "complementary", 78 | limiters: [",", ".", ":", "/"], 79 | } 80 | }); 81 | } 82 | 83 | /* Search --------------------------*/ 84 | /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ 85 | // Initialise search index on focus 86 | var fuse; 87 | $("#search-input").focus(async function(e) { 88 | if (fuse) { 89 | return; 90 | } 91 | 92 | $(e.target).addClass("loading"); 93 | var response = await fetch($("#search-input").data("search-index")); 94 | var data = await response.json(); 95 | 96 | var options = { 97 | keys: ["what", "text", "code"], 98 | ignoreLocation: true, 99 | threshold: 0.1, 100 | includeMatches: true, 101 | includeScore: true, 102 | }; 103 | fuse = new Fuse(data, options); 104 | 105 | $(e.target).removeClass("loading"); 106 | }); 107 | 108 | // Use algolia autocomplete 109 | var options = { 110 | autoselect: true, 111 | debug: true, 112 | hint: false, 113 | minLength: 2, 114 | }; 115 | var q; 116 | async function searchFuse(query, callback) { 117 | await fuse; 118 | 119 | var items; 120 | if (!fuse) { 121 | items = []; 122 | } else { 123 | q = query; 124 | var results = fuse.search(query, { limit: 20 }); 125 | items = results 126 | .filter((x) => x.score <= 0.75) 127 | .map((x) => x.item); 128 | if (items.length === 0) { 129 | items = [{dir:"Sorry 😿",previous_headings:"",title:"No results found.",what:"No results found.",path:window.location.href}]; 130 | } 131 | } 132 | callback(items); 133 | } 134 | $("#search-input").autocomplete(options, [ 135 | { 136 | name: "content", 137 | source: searchFuse, 138 | templates: { 139 | suggestion: (s) => { 140 | if (s.title == s.what) { 141 | return `${s.dir} >
${s.title}
`; 142 | } else if (s.previous_headings == "") { 143 | return `${s.dir} >
${s.title}
> ${s.what}`; 144 | } else { 145 | return `${s.dir} >
${s.title}
> ${s.previous_headings} > ${s.what}`; 146 | } 147 | }, 148 | }, 149 | }, 150 | ]).on('autocomplete:selected', function(event, s) { 151 | window.location.href = s.path + "?q=" + q + "#" + s.id; 152 | }); 153 | }); 154 | })(window.jQuery || window.$) 155 | 156 | 157 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | License • bspm 6 | Skip to contents 7 | 8 | 9 |
41 |
42 |
46 | 47 |
YEAR: 2020
48 | COPYRIGHT HOLDER: Iñaki Ucar
49 | 
50 | 51 |
52 | 53 | 54 |
57 | 58 | 61 | 62 |
63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page not found (404) • bspm 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | Skip to contents 21 | 22 | 23 |
    60 |
    61 |
    65 | 66 | Content not found. Please use links in the navbar. 67 | 68 |
    69 |
    70 | 71 | 72 |
    76 | 77 | 81 | 82 |
    83 |
    84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /inst/service/bspm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from os import path 4 | WDIR = path.dirname(path.realpath(__file__)) 5 | exec(open(WDIR + "/dbus-paths").read()) 6 | 7 | def read_conf(force_discover=False): 8 | global PREF, EXCL 9 | pref = WDIR + "/bspm.pref" 10 | excl = WDIR + "/bspm.excl" 11 | 12 | force_discover = force_discover and not path.exists(WDIR + "/nodiscover") 13 | if force_discover or not path.exists(pref) or not path.exists(excl): 14 | import backend 15 | conf = backend.discover() 16 | with open(pref, "w") as fpref, open(excl, "w") as fexcl: 17 | for i in conf["prefixes"]: 18 | print(i, file=fpref) 19 | for i in conf["exclusions"]: 20 | print(i, file=fexcl) 21 | with open(pref) as fpref, open(excl) as fexcl: 22 | PREF = [line.rstrip() for line in fpref] 23 | EXCL = [line.rstrip() for line in fexcl] 24 | 25 | def call_backend(cmd, pkgs=None, root=False): 26 | import backend 27 | msg = cmd.capitalize() + " system packages" 28 | if root: 29 | msg = msg + " as root" 30 | msg = msg + "..." 31 | print(msg, flush=True) 32 | if pkgs: 33 | return getattr(backend, cmd)(PREF, pkgs, EXCL) 34 | return getattr(backend, cmd)(PREF, EXCL) 35 | 36 | def run_as_service(): 37 | from gi.repository import GLib 38 | 39 | import dbus 40 | import dbus.service 41 | import dbus.mainloop.glib 42 | 43 | from functools import wraps 44 | from contextlib import redirect_stdout 45 | import signal 46 | 47 | class PackageManagerException(dbus.DBusException): 48 | _dbus_error_name = IFACE + ".PackageManagerException" 49 | 50 | def stderr(pid): 51 | return open("/proc/" + str(pid) + "/fd/2", "w") 52 | 53 | def redirect_output(fn): 54 | @wraps(fn) 55 | def wrapper(self, pid, *args, **kw): 56 | with stderr(pid) as f, redirect_stdout(f): 57 | return fn(self, pid, *args, **kw) 58 | return wrapper 59 | 60 | def handle_exceptions(timeout): 61 | def _handle_exceptions(fn): 62 | @wraps(fn) 63 | def wrapper(*args, **kw): 64 | signal.alarm(0) 65 | try: 66 | out = fn(*args, **kw) 67 | except Exception as err: 68 | raise PackageManagerException(str(err)) 69 | finally: 70 | signal.alarm(timeout) 71 | return out 72 | return wrapper 73 | return _handle_exceptions 74 | 75 | class PackageManager(dbus.service.Object): 76 | 77 | @dbus.service.method(IFACE, in_signature="i", out_signature="") 78 | @handle_exceptions(10) 79 | @redirect_output 80 | def discover(self, pid): 81 | read_conf(True) 82 | return 83 | 84 | @dbus.service.method(IFACE, in_signature="i", out_signature="as") 85 | @handle_exceptions(10) 86 | @redirect_output 87 | def available(self, pid): 88 | return call_backend("available") 89 | 90 | @dbus.service.method(IFACE, in_signature="ias", out_signature="as") 91 | @handle_exceptions(10) 92 | @redirect_output 93 | def install(self, pid, pkgs): 94 | return call_backend("install", pkgs) 95 | 96 | @dbus.service.method(IFACE, in_signature="ias", out_signature="as") 97 | @handle_exceptions(10) 98 | @redirect_output 99 | def remove(self, pid, pkgs): 100 | return call_backend("remove", pkgs) 101 | 102 | def sigterm_handler(_signo, _stack_frame): 103 | mainloop.quit() 104 | 105 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 106 | signal.signal(signal.SIGINT, sigterm_handler) 107 | signal.signal(signal.SIGTERM, sigterm_handler) 108 | signal.signal(signal.SIGALRM, sigterm_handler) 109 | 110 | bus = dbus.SystemBus() 111 | bus.request_name(BUS_NAME) 112 | pm = PackageManager(bus, OPATH) 113 | 114 | mainloop = GLib.MainLoop() 115 | mainloop.run() 116 | 117 | def run_as_root(args): 118 | try: 119 | if args.cmd == "discover": 120 | read_conf(True) 121 | return 122 | read_conf() 123 | pkgs = None 124 | if hasattr(args, "pkg"): 125 | pkgs = args.pkg 126 | pkgs = call_backend(args.cmd, pkgs, root=True) 127 | if args.o is not None: 128 | with open(args.o, "a") as f: 129 | for pkg in pkgs: 130 | print(pkg, file=f) 131 | else: 132 | print("Result:", pkgs) 133 | except Exception as err: 134 | if args.o is not None: 135 | with open(args.o, "a") as f: 136 | print(str(err), file=f) 137 | raise err 138 | 139 | if __name__ == "__main__": 140 | import argparse 141 | 142 | parser = argparse.ArgumentParser() 143 | subparser = parser.add_subparsers(dest="cmd") 144 | parser_discover = subparser.add_parser("discover", aliases=["available"]) 145 | parser_discover.add_argument("-o", metavar="file", type=str, help="output file") 146 | parser_install = subparser.add_parser("install", aliases=["remove"]) 147 | parser_install.add_argument("pkg", type=str, nargs="+") 148 | parser_install.add_argument("-o", metavar="file", type=str, help="output file") 149 | 150 | args = parser.parse_args() 151 | if args.cmd is None: 152 | read_conf() 153 | run_as_service() 154 | else: 155 | run_as_root(args) 156 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | #' Find Shadowed Packages 2 | #' 3 | #' Find packages that are \emph{shadowed} by others in library locations 4 | #' with a higher priority. 5 | #' 6 | #' @param lib.loc character vector describing the location of the \R library 7 | #' trees to search through, or \code{NULL} for all known trees 8 | #' (see \code{\link{.libPaths}}). 9 | #' @return A \code{data.frame} with one row per package, row names the package 10 | #' names and column names (currently) "Package", "LibPath", "Version", 11 | #' "Shadow.LibPath", "Shadow.Version", "Shadow.Newer". 12 | #' 13 | #' @details \R supports setting several locations for library trees. This is a 14 | #' powerful feature, but many times packages end up installed in multiple 15 | #' locations, and in such cases \R silently uses the one in the path with the 16 | #' highest priority (appearing first in \code{\link{.libPaths}}), thus 17 | #' \emph{shadowing} packages in locations with a lower priority. 18 | #' 19 | #' For \pkg{bspm} installations, this means that outdated user packages may 20 | #' break system libraries. This utility reports packages that are shadowed 21 | #' (one per row) with information on which location ("Shadow.LibPath") 22 | #' and version ("Shadow.Version") has priority over it. 23 | #' The \code{\link{moveto_sys}} method is a great complement to move such 24 | #' outdated versions to the system libraries. 25 | #' 26 | #' @seealso \code{\link{moveto_sys}} 27 | #' @export 28 | shadowed_packages <- function(lib.loc=NULL) { 29 | if (is.null(lib.loc)) lib.loc <- .libPaths() 30 | 31 | fields <- c("Package", "LibPath", "Version") 32 | sfields <- paste("Shadow", fields, sep=".") 33 | shadow <- data.frame(matrix(nrow=0, ncol=5)) 34 | colnames(shadow) <- c(fields, sfields[-1]) 35 | 36 | pkgs <- data.frame(utils::installed.packages(lib.loc)[, fields]) 37 | pkgs <- split(pkgs, factor(pkgs$LibPath, levels=lib.loc)) 38 | 39 | idx <- seq_along(pkgs) 40 | for (i in idx) { 41 | colnames(pkgs[[i]]) <- sfields 42 | for (j in idx[-seq_len(i)]) { 43 | hidden <- merge(pkgs[[j]], pkgs[[i]], by.x=fields[1], by.y=sfields[1]) 44 | shadow <- rbind(shadow, hidden) 45 | } 46 | } 47 | 48 | row.names(shadow) <- shadow[, "Package"] 49 | shadow$Version <- as.package_version(shadow$Version) 50 | shadow$Shadow.Version <- as.package_version(shadow$Shadow.Version) 51 | newer <- shadow[, "Version"] < shadow[, "Shadow.Version"] 52 | shadow <- cbind(shadow, Shadow.Newer = newer) 53 | shadow 54 | } 55 | 56 | list_inst <- function() { 57 | libs <- unique(c(.Library.site, .Library)) 58 | inst <- unique(row.names(utils::installed.packages(libs))) 59 | inst 60 | } 61 | 62 | list_deps <- function(packages, db, which, recursive) { 63 | deps <- tools::package_dependencies(packages, db, which, recursive) 64 | deps <- unique(unlist(deps, use.names=FALSE)) 65 | deps 66 | } 67 | 68 | # get package dependencies 69 | pkg_deps <- function(pkgs, dependencies, db, all=TRUE) { 70 | pkgs <- unique(pkgs) 71 | deps <- list_deps(pkgs, db, c("Depends", "Imports"), recursive=TRUE) 72 | if (!all) 73 | deps <- c(deps, list_deps(pkgs, db, "LinkingTo", recursive=FALSE)) 74 | if (isTRUE(dependencies) || "Suggests" %in% dependencies) 75 | deps <- c(deps, list_deps(pkgs, db, "Suggests", recursive=FALSE)) 76 | if ("Enhances" %in% dependencies) 77 | deps <- c(deps, list_deps(pkgs, db, "Enhances", recursive=FALSE)) 78 | deps <- unique(c(setdiff(deps, list_inst()), if (all) pkgs)) 79 | deps 80 | } 81 | 82 | # get LinkingTo-only dependencies for src packages 83 | hard_deps <- function(pkgs, db, mask) { 84 | srcs <- c(pkgs$bins[mask], pkgs$srcs) 85 | deps <- list_deps(srcs, db, "LinkingTo", recursive=FALSE) 86 | deps <- setdiff(deps, c(list_inst(), pkgs$bins, pkgs$srcs)) 87 | deps 88 | } 89 | 90 | # adapted from install.packages 91 | # get available binaries and pkgs with later versions available 92 | check_versions <- function(pkgs, db) { 93 | dbb <- available_sys() 94 | row.names(dbb) <- tolower(row.names(dbb)) 95 | 96 | bins <- pkgs[tolower(pkgs) %in% row.names(dbb)] 97 | srcs <- pkgs[! pkgs %in% bins] 98 | 99 | binvers <- dbb[tolower(bins), "Version"] 100 | srcvers <- sapply(bins, function(bin) # may not be in db 101 | if (bin %in% row.names(db)) db[bin, "Version"] else "0") 102 | 103 | later <- as.numeric_version(binvers) < srcvers 104 | 105 | list(bins=bins, srcs=srcs, binvers=binvers, srcvers=srcvers, later=later) 106 | } 107 | 108 | # consider as "later" packages with the same version installed from remotes 109 | remotes_as_newer <- function(pkgs, lib) { 110 | for (i in which(as.numeric_version(pkgs$binvers) == pkgs$srcvers)) 111 | if (!is.na(utils::packageDescription(pkgs$bins[i], lib, "RemoteSha"))) 112 | pkgs$later[i] <- TRUE 113 | pkgs 114 | } 115 | 116 | # adapted from install.packages 117 | # determine whether later versions should be preferred 118 | ask_user <- function(later, bins, binvers, srcvers) { 119 | if (!any(later)) return(later) 120 | 121 | msg <- ngettext( 122 | sum(later), 123 | "There is a binary version available but the source version is later", 124 | "There are binary versions available but the source versions are later") 125 | cat("\n", paste(strwrap(msg, indent = 2, exdent = 2), collapse = "\n"), 126 | ":\n", sep = "") 127 | print(data.frame(`binary` = binvers, `source` = srcvers, 128 | row.names = bins, check.names = FALSE)[later, ]) 129 | cat("\n") 130 | action <- getOption("install.packages.compile.from.source", "interactive") 131 | if (action == "interactive" && interactive()) { 132 | msg <- gettext("Do you prefer later versions from sources?") 133 | res <- utils::askYesNo(msg) 134 | if (is.na(res)) stop("Cancelled by user") 135 | if (!isTRUE(res)) later <- FALSE 136 | } else if (action == "never") { 137 | cat(" Binaries will be preferred\n") 138 | later <- FALSE 139 | } 140 | 141 | later 142 | } 143 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # bspm devel 2 | 3 | - Fix "invalid escape sequence" SyntaxWarning (@pekkarr in #84). 4 | - Catch and show early errors (e.g. no backend found) in root mode. 5 | 6 | # bspm 0.5.7 7 | 8 | - Restrict D-Bus service configuration to installations in Linux machines 9 | with admininistrative privileges. 10 | 11 | # bspm 0.5.6 12 | 13 | - Move to cran4linux org on GitHub, update URLs. 14 | - Try binary installation of build-only dependencies for source packages 15 | (#82 addressing #81). 16 | 17 | # bspm 0.5.5 18 | 19 | - Fix test to feed character input to `numeric_version`. 20 | 21 | # bspm 0.5.4 22 | 23 | - Fix DNF backend to ensure that the system configuration is used (228407a). 24 | - Minor documentation improvements. 25 | 26 | # bspm 0.5.3 27 | 28 | - Add workaround for underscores in Arch package versions (#71). 29 | - Fix BioArchLinux instructions in README. 30 | - Fix discovery of installed system packages in Arch (#73). 31 | 32 | # bspm 0.5.2 33 | 34 | - Fix package deduplication in dependency getter (#68 addressing #67). 35 | - Rename scripts manual page to `bspm-scripts`. 36 | 37 | # bspm 0.5.1 38 | 39 | - Add support for littler in scripts (@eddelbuettel in #64). 40 | - Refactor + fixes + improve testing (#66 addressing #63). 41 | 42 | # bspm 0.5.0 43 | 44 | - New function `moveto_sys()` moves existing user packages to the system 45 | library to avoid _package shadowing_; the associated script `mass_move` 46 | enables mass-calling this function for several users and/or libraries to 47 | facilitate `bspm` deployment in multitenant servers (#60 addressing #59). 48 | - New function `shadowed_packages()` analyzes the library tree and reports 49 | which packages, one per row, are shadowed by others (#62 addressing #58). 50 | - Add new `options(bspm.version.check=FALSE)` (true by default) to globally 51 | enable `binary-source` installation type (#61). 52 | - Add a specific manual page `bspm-options` documenting all supported options. 53 | - Add support for the installation of binary Suggests and Enhances if they are 54 | supplied to the `dependencies` argument of `install.packages`. 55 | `LinkingTo` now is omitted for binary packages as documented (#32). 56 | 57 | # bspm 0.4.2 58 | 59 | - Fix error forwarding in root mode (#54). 60 | - Fix installation error when `type="binary-source"` is set and 61 | a package without binary version available is requested (#56). 62 | - Fix installation error in `options(pkgType="both")` mode (default) when an 63 | available binary is not available as source (#57). 64 | 65 | # bspm 0.4.1 66 | 67 | - New `type="binary-source"` option (or _fast mode_) tries to install as many 68 | binaries as possible (requested packages and dependencies), and then falls 69 | back to source installation (per @eddelbuettel's wish). 70 | - Fix the call to `available.packages()` when the `repos` argument is specified 71 | (#52 addressing #51). 72 | 73 | # bspm 0.4.0 74 | 75 | - New function `available_sys()` returns a matrix of available packages with 76 | `"Package"`, `"Version"`, and `"Repository"` (#47 addressing #41). 77 | - Honor `type` option, set by default to `"both"`, which means 'use binary 78 | if available and current, otherwise try source' (#48 addressing #46). 79 | As a consequence, the option `bspm.always.install.deps` has been removed. 80 | 81 | # bspm 0.3.10 82 | 83 | - Check backend availability on `enable()`, and trigger a warning if the 84 | service is required but not found. This check can be disabled by setting 85 | `options(bspm.backend.check=FALSE)` (#40). 86 | 87 | # bspm 0.3.9 88 | 89 | - Force `sudo` unconditionally also with autodetection (#27, #28). 90 | - Call `update_cache` in DNF install transactions (#29). 91 | - Add ALPM backend (#35 addressing #34). 92 | - Fix repeated installation issue in APT backend (#36). 93 | 94 | # bspm 0.3.8 95 | 96 | - Fix spurious error with `options(bspm.always.install.deps=TRUE)` (#25). 97 | - Ensure that `options(bspm.sudo=TRUE)` forces `sudo` unconditionally (#28). 98 | - Add new `options(bspm.sudo.autodetect=TRUE)` (not set by default) to enable 99 | passwordless `sudo` autodetection on every call (#27). 100 | 101 | # bspm 0.3.7 102 | 103 | - Fix spurious error with `options(bspm.always.install.deps=TRUE)` (#24). 104 | 105 | # bspm 0.3.6 106 | 107 | - Make APT call fail if there are unmet dependencies (#20). 108 | - Add new `options(bspm.always.install.deps=TRUE)` (not set by default) to 109 | always try to install recursive hard dependencies of packages from system 110 | repositories even if the requested package is not available (#14, #23). 111 | - Add a note about SELinux (#19). 112 | 113 | # bspm 0.3.5 114 | 115 | - Fix noise when `busctl` is installed but there's no system bus (docker) (#12). 116 | - Workaround issue with file permissions under `/tmp` (#13). 117 | - Fix compatibility with Python 3.6 (#16 addressing #15). 118 | - Workaround PATH for old versions of APT/dpkg (#17 addressing #15). 119 | - Prioritize `options(bspm.sudo=TRUE)` over DBus calls (as part of #16), so that 120 | any DBus error or incompatibility can be at least bypassed with `sudo`. 121 | 122 | # bspm 0.3.4 123 | 124 | - Fix installation issue reported by CRAN on Solaris. 125 | 126 | # bspm 0.3.3 127 | 128 | - Cosmetic changes suggested by CRAN. 129 | - Small configure fix. 130 | 131 | # bspm 0.3.2 132 | 133 | - Implement functions to discover new prefixes dynamically (#3). 134 | - Fall back to `sudo` if no root permissions nor D-Bus service are available. 135 | - More documentation, some examples, and testing. 136 | 137 | # bspm 0.3.1 138 | 139 | - Simplified installation, because D-Bus files are always in the same place. 140 | - Support for multiple prefixes and exclusions (#1). 141 | - Improve APT cache management (#4). 142 | - Fix newlines in APT output (#5). 143 | - Load D-Bus variables locally instead of in the global environment (#6). 144 | 145 | # bspm 0.3.0 146 | 147 | - New package name, as suggested by @eddelbuettel; improved title & description. 148 | - Allow root user to talk directly to the system package manager, without D-Bus. 149 | 150 | # PackageManager 0.2.1 151 | 152 | - Add APT backend. 153 | 154 | # PackageManager 0.2.0 155 | 156 | - Initial fork from cran2copr project, reworked to make it extensible. 157 | - Currently, only DNF backend supported. 158 | -------------------------------------------------------------------------------- /docs/reference/bspm-scripts.html: -------------------------------------------------------------------------------- 1 | 2 | Call Internal Scripts — bspm-scripts • bspm 6 | Skip to contents 7 | 8 | 9 |
    41 |
    42 |
    47 | 48 |
    49 |

    Internal scripts can be called via Rscript (see examples).

    50 |
    51 | 52 | 53 | 54 |
    55 |

    Examples

    56 |
    if (FALSE) {
    57 | # get a list of available scripts with descriptions
    58 | Rscript -e bspm:::scripts
    59 | 
    60 | # see a script's help
    61 | Rscript -e bspm:::scripts <script_name> -h
    62 | 
    63 | # run a script
    64 | Rscript -e bspm:::scripts <script_name> [args]
    65 | }
    66 | 
    67 | 
    68 |
    69 |
    70 | 71 | 72 |
    75 | 76 | 79 | 80 |
    81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | Authors and Citation • bspm 6 | Skip to contents 7 | 8 | 9 |
    41 |
    42 |
    45 | 46 |
    47 |

    Authors

    48 | 49 |
    • 50 |

      Iñaki Ucar. Author, copyright holder, maintainer. 51 |

      52 |
    • 53 |
    54 | 55 |
    56 |

    Citation

    57 |

    Source: DESCRIPTION

    58 | 59 |

    Ucar I (2024). 60 | bspm: Bridge to System Package Manager. 61 | R package version 0.5.7, https://cran4linux.github.io/bspm/. 62 |

    63 |
    @Manual{,
    64 |   title = {bspm: Bridge to System Package Manager},
    65 |   author = {Iñaki Ucar},
    66 |   year = {2024},
    67 |   note = {R package version 0.5.7},
    68 |   url = {https://cran4linux.github.io/bspm/},
    69 | }
    70 |
    71 |
    73 | 74 | 75 |
    78 | 79 | 82 | 83 |
    84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | Function reference • bspm 6 | Skip to contents 7 | 8 | 9 |
    41 |
    42 |
    45 | 46 |
    47 |

    All functions

    48 | 49 | 50 | 51 | 52 |
    53 | 54 | 55 | 56 | 57 |
    58 | 59 | bspm-options 60 |
    61 |
    Package Options
    62 |
    63 | 64 | bspm-package 65 |
    66 |
    bspm: Bridge to System Package Manager
    67 |
    68 | 69 | bspm-scripts 70 |
    71 |
    Call Internal Scripts
    72 |
    73 | 74 | enable() disable() 75 |
    76 |
    Enable/Disable Bridge to System Package Manager
    77 |
    78 | 79 | install_sys() remove_sys() moveto_sys() available_sys() discover() 80 |
    81 |
    Manage Packages from System Repositories
    82 |
    83 | 84 | shadowed_packages() 85 |
    86 |
    Find Shadowed Packages
    87 |
    88 |
    89 | 90 | 91 |
    94 | 95 | 98 | 99 |
    100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /docs/reference/bspm-options.html: -------------------------------------------------------------------------------- 1 | 2 | Package Options — bspm-options • bspm 8 | Skip to contents 9 | 10 | 11 |
    43 |
    44 |
    49 | 50 |
    51 |

    List of options() supported to configure bspm's behavior. 52 | In general, these should be set before calling any package function.

    53 |
    54 | 55 | 56 |
    57 |

    Options specific to bspm

    58 | 59 | 60 |
    bspm.backend.check:
    61 |

    logical, default TRUE. If false, 62 | the initial check on enable() is not performed.

    63 | 64 |
    bspm.version.check:
    65 |

    logical, default TRUE. If false, 66 | as many binaries are installed as possible without any version check, 67 | and then installation from source is used as a fallback.

    68 | 69 |
    bspm.sudo.autodetect:
    70 |

    logical, default FALSE. If true, 71 | enables autodetection and selection of password-less sudo.

    72 | 73 |
    bspm.sudo:
    74 |

    logical, default FALSE. If true, forces 75 | sudo unconditionally as the preferred mechanism.

    76 | 77 | 78 |
    79 |
    80 |

    Options from base R

    81 | 82 | 83 |

    These are used in the same way as in base R. See options for 84 | a detailed description.

    • askYesNo

    • 85 |
    • install.packages.compile.from.source

    • 86 |
    87 | 88 |
    90 | 91 | 92 |
    95 | 96 | 99 | 100 |
    101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docs/reference/bspm-package.html: -------------------------------------------------------------------------------- 1 | 2 | bspm: Bridge to System Package Manager — bspm-package • bspm 18 | Skip to contents 19 | 20 | 21 |
    53 |
    54 |
    59 | 60 |
    61 |

    Enables binary package installations on Linux distributions. 62 | Provides functions to manage packages via the distribution's package 63 | manager. Also provides transparent integration with R's install.packages 64 | and a fallback mechanism. When installed as a system package, interacts 65 | with the system's package manager without requiring administrative 66 | privileges via an integrated D-Bus service; otherwise, uses sudo. 67 | Currently, the following backends are supported: DNF, APT, ALPM.

    68 |
    69 | 70 | 71 |
    72 |

    References

    73 |

    https://cran4linux.github.io/bspm/

    74 |
    75 |
    76 |

    See also

    77 | 79 |
    80 |
    81 |

    Author

    82 |

    Iñaki Ucar

    83 |
    84 | 85 |
    87 | 88 | 89 |
    92 | 93 | 96 | 97 |
    98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/reference/shadowed_packages.html: -------------------------------------------------------------------------------- 1 | 2 | Find Shadowed Packages — shadowed_packages • bspm 8 | Skip to contents 9 | 10 | 11 |
    43 |
    44 |
    49 | 50 |
    51 |

    Find packages that are shadowed by others in library locations 52 | with a higher priority.

    53 |
    54 | 55 |
    56 |

    Usage

    57 |
    shadowed_packages(lib.loc = NULL)
    58 |
    59 | 60 |
    61 |

    Arguments

    62 |
    lib.loc
    63 |

    character vector describing the location of the R library 64 | trees to search through, or NULL for all known trees 65 | (see .libPaths).

    66 | 67 |
    68 |
    69 |

    Value

    70 | 71 | 72 |

    A data.frame with one row per package, row names the package 73 | names and column names (currently) "Package", "LibPath", "Version", 74 | "Shadow.LibPath", "Shadow.Version", "Shadow.Newer".

    75 |
    76 |
    77 |

    Details

    78 |

    R supports setting several locations for library trees. This is a 79 | powerful feature, but many times packages end up installed in multiple 80 | locations, and in such cases R silently uses the one in the path with the 81 | highest priority (appearing first in .libPaths), thus 82 | shadowing packages in locations with a lower priority.

    83 |

    For bspm installations, this means that outdated user packages may 84 | break system libraries. This utility reports packages that are shadowed 85 | (one per row) with information on which location ("Shadow.LibPath") 86 | and version ("Shadow.Version") has priority over it. 87 | The moveto_sys method is a great complement to move such 88 | outdated versions to the system libraries.

    89 |
    90 |
    91 |

    See also

    92 | 93 |
    94 | 95 |
    97 | 98 | 99 |
    108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | --------------------------------------------------------------------------------