Warning, /edpm/README.md is written in an unsupported language. File is not indexed.
0001 # edpm
0002
0003 **edpm** stands for **E**IC **d**evelopment **p**acket ~~**m**anager~~ helper
0004
0005 **The goal** of edpm is to provide esier experience of building EIC simulation and reconstruction
0006 framework and supporting packages on a user machine with development reasons.
0007
0008 ### Table of contents:
0009 * [Motivation](#motivation)
0010 * [edpm installation](#installation)
0011 * [Get eicrecon installed](#get-eicrecon-installed)
0012 * [Manage environment](#environment)
0013 * [Troubleshooting](#installation-troubleshooting)
0014 * [Manual or devel installation](#manual-or-development-installation)
0015 * [Adding a package](#adding-a-package)
0016 * [Adding Git+Cmake package example](#adding-git-cmake-package)
0017
0018
0019 ***Cheat sheet:***
0020
0021 Install edpm:
0022
0023 ```bash
0024 # install edpm
0025 sudo python -m pip install edpm
0026
0027 # OR without sudo: add --user flag and ensure ~/.local/bin is in your PATH
0028 python -m pip install --user -U edpm
0029 ```
0030
0031 > JLab machines with certificate problems - add these flags to the command above:
0032 > --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --trusted-host pypi.org
0033 > see [Troubleshooting](#installation-troubleshooting) chapter for details
0034
0035
0036 Install everything else
0037
0038 ```bash
0039
0040 # install prerequesties
0041 edpm req centos eicrecon # get list of OS packets required to build jana and deps
0042 sudo yum install ... # install whatever 'edpm req' shows
0043
0044 # setup installation dir and existing packets, introspect
0045 edpm --top-dir=<where-to> # Directory where packets will be installed
0046 edpm # To see how edpm is configured
0047 edpm install eicrecon --explain # To see what is to be installed
0048 edpm set root `$ROOTSYS` # if you have CERN.ROOT. Or skip this step
0049 edpm set <packet> <path> # set other existing packets. Or skip this step!!!
0050 edpm config global cxx_standard=17 # It is recommended if compiler supports C++17
0051
0052
0053 # Build and install the rest
0054 edpm install eicrecon # install eicrecon and dependencies (like genfit, jana and rave)
0055 edpm install g4e # install Geant-4-Eic and dependencies (Geant4, etc)
0056
0057 # Set environment
0058 source<(edpm env) # set environment variables
0059 edpm env csh > your.csh # if you are still on CSH
0060
0061 # If that worked don't read the next...
0062 ```
0063
0064 > (!) If you use your version of ROOT, all packages depending on ROOT should be
0065 > installed with the same C++ standard flags as root. So it it was C++11 or C++17, it should be used
0066 > everywhere. To set it in edpm
0067 > ```edpm config global cxx_standard=17```
0068 >
0069
0070
0071 # Motivation
0072
0073 ***TL;DR;*** Major HEP and NP scientific packages are not supported by some major distros and
0074 usually are crappy (at least in terms of dependency requirements). Everybody have to reinvent the wheel to include
0075 such packages in their software chains and make users' lives easier. And we do.
0076
0077 ***Longer reading***
0078
0079 **edpm** is here as there is no standard convention in HEP and NP of how to distribute and install software packages
0080 with its dependencies. Some packages (like eigen, xerces, etc.) are usually supported by
0081 OS maintainers, while others (Cern ROOT, Geant4, Rave) are usually built by users or
0082 other packet managers and could be located anywhere. We also praise "version hell" (e.g. when GenFit doesn't compile
0083 with CLHEP from ubuntu repo) and lack of software manpower (e.g. to sufficiently and continuously maintain packages
0084 for major distros or even to fix some simple issues on GitHub).
0085
0086 What about Spack? - Spack works and shines on clusters with supervision of experts.
0087 In failed countless times when the task was to install something working for students.
0088 Spack requires to know Spack and its concepts to debug its deep dependencies failures
0089
0090 At this points **edpm** tries to unify experience and make it simple to deploy eicrecon for:
0091
0092 - Users on RHEL 7 and CentOS
0093 - Users on Ubutnu (and Windows with WSL)
0094 - Docker and other containers
0095
0096
0097 **Design features**
0098
0099 * Essentials:
0100 * edpm is written in pure python (2 and 3 compatible) with minimum dependencies
0101 * it is shipped by pip (python official repo), so can be installed with one command on all major platforms
0102 * CLI (command line interface) - provides users with commands to manipulate packets
0103 * JSON database stores the current state and packets locations
0104 * It makes easy to... rebuild packets, deploy missing packets, continue after fail, etc.
0105
0106 * Under the hood:
0107 * Each packet has a single python file that defines how it will be installed and configured
0108 * Each such file is easy to read and modify by ***inexperienced*** users in case they would love to
0109 * Installation steps written in a style close to Dockerfile (same command names, etc)
0110
0111
0112
0113 **Alternatives**
0114
0115 Is there something existing? What others do? - Simple bash build scripts quickly get bloated and complex.
0116 Dockerfiles and similar stuff are too-tool-related. Build systems like scons or cmake also too centric on compiling
0117 something rather than managing packets chains. Full featured package managers and tools like Homebrew are pretty
0118 complex to tame (for dealing with just 5 deps).
0119
0120 So edpm is something more advanced than build scripts, but less cumbersome than real packet managers,
0121 it is in pure python, and being focused on our specific problems.
0122
0123
0124 ***edpm* is not**:
0125
0126 1. It is not a real package manager which automatically solves dependency trees
0127 2. **edpm is not a requirment** for e<sup>JANA</sup>. It is not a part of e<sup>JANA</sup>
0128 build system and one can compile and install e<sup>JANA</sup> without edpm
0129
0130
0131 Users are pretty much encouraged to change the code and everything is done here to be user-change-friendly
0132
0133
0134 <br><br>
0135
0136 ## Installation
0137
0138 ***TL;DR;***
0139
0140 ```bash
0141 sudo pip install --upgrade edpm # system level installation
0142 pip install --user --upgrade edpm # User level. $HOME/.local/bin should be in $PATH
0143 ```
0144
0145 If you have certificate problems on JLab machines: ([more options on certificates](#jlab-certificate-problems)):
0146 ```bash
0147 # System level copy-paste:
0148 sudo python -m pip install --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --trusted-host pypi.org -U edpm
0149 # User level copy-paste:
0150 python -m pip install --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --trusted-host pypi.org --user -U edpm
0151 ```
0152
0153 More on this:
0154
0155 * See [INSTALLATION TROUBLESHOOTING](#installation-troubleshooting) If you don't have pip or right python version.
0156 * See [Jlab root certificate problems](#jlab-certificate-problems) and how to solve them
0157 * See [Manual or development installation](#manual-or-development-installation) to use this repo directly, develop edpm or don't want to mess with pip at all?
0158
0159
0160 <br><br>
0161
0162 ## Get eicrecon installed
0163
0164 (or crash course to edpm)
0165
0166 ***TL;DR;*** example for CentOS/RHEL7
0167 ```bash
0168 edpm req centos eicrecon # get list of OS packets required to build jana and deps
0169 sudo yum install ... # install watever 'edpm req' shows
0170 edpm --top-dir=<where-to> # Directory where packets will be installed
0171 edpm set root `$ROOTSYS` # if you have CERN.ROOT. Or skip this step
0172 edpm install eicrecon --missing # install eicrecon and dependencies (like genfit, jana and rave)
0173 source<(edpm env) # set environment variables
0174 ```
0175
0176
0177 **Step by step explained instruction**:
0178
0179 1. Install (or check) required packages form OS:
0180
0181 ```bash
0182 edpm req ubuntu # for all packets that edpm knows
0183 edpm req centos eicrecon # for eicrecon and its dependencies only
0184 ```
0185
0186 At this point only ***'ubuntu'*** and ***'centos'*** are known words for ```req``` command. Put:
0187 * ```ubuntu``` for debian family
0188 * ```centos``` for RHEL and CentOS systems.
0189
0190 > In future macOS and more detailed os-versions will be supported
0191
0192 2. Set <b><blue>top-dir</blue></b>. This is where all missing packets will be installed.
0193
0194 ```bash
0195 edpm --top-dir=<where-to-install-all>
0196 ```
0197
0198 3. You may have CERN.ROOT installed (req. version >= 6.14.00). Run this:
0199 ```bash
0200 edpm set root `$ROOTSYS`
0201 ```
0202
0203 You may set paths for other installed dependencies combining:
0204 ```bash
0205 edpm install eicrecon --missing --explain # to see missing dependencies
0206 edpm set <name> <path> # to set dependency path
0207 edpm set jana <path to jana2 install> # JANA2 as an example
0208 ```
0209
0210 Or you may skip this step and just get everything installed by edpm
0211
0212 4. Then you can install edpm and all missing dependencies:
0213
0214 ```bash
0215 edpm install eicrecon
0216 ```
0217
0218 5. Set right environment variables (right in the next section)
0219
0220
0221 <br><br>
0222
0223 ## Environment
0224
0225 ***TL;DR;*** Just source it like:
0226 ```bash
0227 source <(edpm env)
0228 # or
0229 source ~/.local/share/edpm/env.sh # .csh for CSH/TCSH
0230 edpm env # To generate env & regenerate env files
0231 ```
0232
0233 ```edpm_DATA_PATH``` - sets the path where the configuration db.json and env.sh, env.csh are located
0234
0235 ***longer reading:***
0236
0237 Every time configuration is changed (something installed or deleted) or
0238 ***edpm env*** command is called, edpm creates
0239 2 environment files with the current environment:
0240
0241 ```bash
0242 ~/.local/share/edpm/env.sh # bash
0243 ~/.local/share/edpm/env.csh # bash
0244 ```
0245
0246 There is a command to print our the environement. One can then redirect it to a file
0247 or feed to source directly (examples are below)
0248
0249 ```bash
0250 edpm env # type with --help for options
0251 ```
0252
0253 Examples:
0254
0255 1. Dynamically source output of ```edpm env``` command (recommended)
0256
0257 ```bash
0258 source <(edpm env) # works on bash
0259 ```
0260 2. Save output of ```edpm env``` command to a file (can be useful)
0261
0262 ```bash
0263 edpm env sh > your-file.sh # get environment for bash or compatible shells
0264 edpm env csh > your-file.csh # get environment for CSH/TCSH
0265 ```
0266 3. Use edpm generated ```env.sh``` and ```env.csh``` files (lazy and convenient)
0267
0268 ```bash
0269 $HOME/.local/share/edpm/env.sh # bash and compatible
0270 $HOME/.local/share/edpm/env.csh # for CSH/TCSH
0271 ```
0272 (!) The files are regenerated each time ```edpm``` changes something.
0273 If you change ```db.json``` by yourself, edpm doesn't track it automatically, so call ```edpm env```
0274 to regenerate these 2 files
0275
0276
0277 ## Configuration
0278
0279 edpm stores the states in ``db.json``` file. There are certain parameters relevant for
0280 all/most of the packages such as cxx_standard or a number of compilation threads.
0281 Then there are parameters to configure each package installation.
0282
0283 To view and change those configuration:
0284
0285 ```
0286 edpm config <packet name> <config name> = <new value>
0287 ```
0288
0289 examples:
0290
0291 ```bash
0292 edpm config # edpm config global
0293 edpm config global # Show global configs
0294 edpm config root # Show configs for packet root
0295
0296 edpm config global cxx_standard=14 # Set globally to use C++14 for all new packages
0297 # (if that is not overwritten by the package config)
0298
0299 edpm config acts cxx_standard=17 # Set cxx standard for root (overwrites global level)
0300 ```
0301
0302 Config allows
0303
0304
0305
0306
0307
0308
0309 **Where edpm data is stored:**
0310
0311 There are standard directories for users data for each operating system. edpm use them to store
0312 db.json and generated environment files (edpm doesnt use the files by itself).
0313
0314 For linux it is XDG_DATA_HOME\*:
0315
0316 ```
0317 ~/.local/share/edpm/env.sh # sh version
0318 ~/.local/share/edpm/env.csh # csh version
0319 ~/.local/share/edpm/db.json # open it, edit it, love it
0320 ```
0321
0322 > \* - XDG is the standard POSIX paths to store applications data, configs, etc.
0323
0324
0325 **```edpm_DATA_PATH```** - You can control where edpm stores data by setting ```edpm_DATA_PATH``` environment variable.
0326
0327
0328 <br><br>
0329
0330 ## INSTALLATION TROUBLESHOOTING
0331
0332
0333
0334 ***But... there is no pip:***
0335 Install it!
0336 ```
0337 sudo easy_install pip # system level
0338 easy_install pip --user # user level
0339 ```
0340
0341 For JLab lvl1&2 machines, there is a python installations that have ```pip``` :
0342 ```bash
0343 /apps/python/ # All pythons there have pip and etc
0344 /apps/anaconda/ # Moreover, there is anaconda (python with all major math/physics libs)
0345 ```
0346
0347 ***But there is no 'pip' command?***
0348 If ```easy_install``` installed something, but ```pip``` command is not found after, do:
0349
0350 1. If ```--user``` flag was used, make sure ```~/.local/bin``` is in your ```$PATH``` variable
0351 2. you can fallback to ```python -m pip``` instead of using ```pip``` command:
0352 ```bash
0353 python -m pip install --user --upgrade edpm
0354 ```
0355
0356
0357
0358 ***But... there is no easy_install!***
0359 Install it!
0360 ```bash
0361 sudo yum install python-setuptools python-setuptools-devel # centos and RHEL/CentOS
0362 sudo apt-get install python-setuptools # Ubuntu and Debian
0363 # Gentoo. I should not write this for its users, right?
0364 ```
0365
0366 For python3 it is ```easy_install3``` and ```python3-setuptools```
0367
0368 ***I dont have sudo privileges!***
0369
0370 Add "--user" flag both for pip and easy_install for this.
0371 [Read SO here](https://stackoverflow.com/questions/15912804/easy-install-or-pip-as-a-limited-user)
0372
0373
0374
0375 ### JLab certificate problems
0376
0377 If you get errors like:
0378 ```
0379 Retrying (...) after connection broken by 'SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED]...
0380 ```
0381
0382 The problem is that ```pip``` is trustworthy enough to use secure connection to get packages.
0383 And JLab is helpful enough to put its root level certificates in the middle.
0384
0385 1. The easiest solution is to declare PiPy sites as trusted:
0386 ```bash
0387 python -m pip install --trusted-host pypi.python.org --trusted-host files.pythonhosted.org --trusted-host pypi.org edpm
0388 ```
0389 2. Or to permanently add those sites as trusted in pip.config
0390 ```
0391 [global]
0392 trusted-host=
0393 pypi.python.org
0394 pypi.org
0395 files.pythonhosted.org
0396 ```
0397 ([The link where to find pip.config on your system](https://pip.pypa.io/en/stable/user_guide/#config-file))
0398 3. You may want to be a hero and kill the dragon. The quest is to take [JLab certs](https://cc.jlab.org/JLabCAs).
0399 Then [Convert them to pem](https://stackoverflow.com/questions/991758/how-to-get-pem-file-from-key-and-crt-files).
0400 Then [add certs to pip](https://stackoverflow.com/questions/25981703/pip-install-fails-with-connection-error-ssl-certificate-verify-failed-certi).
0401 Then **check it really works** on JLab machines. And bring the dragon's head back (i.e. please, add the exact instruction to this file)
0402
0403 <br><br>
0404 ### Manual or development installation:
0405 ***TL;DR;*** Get edpm, install requirements, ready:
0406 ```bash
0407 git clone https://gitlab.com/eic/edpm.git
0408 pip install -r edpm/requirements.txt
0409
0410 # OR clone and add edpm/bin to your PATH
0411 export PATH=`pwd`/edpm/bin:$PATH
0412 ```
0413
0414
0415 **requirments**:
0416
0417 ```Click``` and ```appdirs``` are the only requirements. If you have pip do:
0418
0419 ```bash
0420 pip install --upgrade click appdirs
0421 ```
0422 > If for some reason you don't have pip, you don't know python well enough
0423 and don't want to mess with it, pips, shmips and doh...
0424 Just download and add to ```PYTHONPATH```:
0425 [this 'click' folder](https://pypi.org/project/click/)
0426 and some folder with [appdirs.py](https://github.com/ActiveState/appdirs/blob/master/appdirs.py)
0427
0428
0429 <br>
0430
0431 ## Adding a package
0432
0433 Each packet is represented by a single python file - a recipe which has instructions
0434 of how to get and build the package. Usually it provides:
0435 - download/clone command
0436 - build command
0437 - setup of environment variables
0438 - system dependencies (which can be installed by OS packet managers: yum, apt)
0439
0440
0441 For simplicity (at this point) all recipes are located in a folder inside this repo:
0442 [edpm/recipes](edpm/recipes).
0443
0444
0445 ### Adding Git-CMake package
0446
0447 The most of packages served now by edpm use git to get source code and cmake to build
0448 the package. As git + cmake became a 'standard' there is a basic recipe class which makes
0449 adding new git+cmake packets straight forward.
0450
0451 As a dive-in example of adding packets,
0452 lets look on how to add such packet using Genfit as a copy-paste example.
0453
0454
0455 [edpm/recipes/genfit.py](edpm/recipes/genfit.py)
0456
0457
0458 **1. Set packet name and where to clone from**
0459
0460 One should change 3 lines:
0461
0462 ```python
0463 class GenfitRecipe(GitCmakeRecipe):
0464 def __init__(self):
0465 """Installs Genfit track fitting framework"""
0466
0467 # This name is used in edpm commands like 'edpm install genfit'
0468 super(GenfitRecipe, self).__init__('genfit')
0469
0470 # The branch or tag to be cloned (-b flag)
0471 self.config['branch'] = 'master'
0472
0473 # Repo address
0474 self.config['repo_address'] = 'https://github.com/GenFit/GenFit'
0475 ```
0476
0477 Basically that is enough to build the package and one can test:
0478
0479 ```bash
0480 edpm install yourpacket
0481 ```
0482
0483 **2. Set environment variables**
0484
0485 This is a done in `gen_env` function. By using this function edpm generates environments for
0486 csh/tcsh, bash and python*. So 3 commands to be used in this function:
0487
0488 * `Set(name, value)` - equals `export name=value` in bash
0489 * `Append(name, value)` - equals `export name=$name:value` in bash
0490 * `Prepend(name, value)` - equals `export name=value:$name` in bash
0491
0492 ```python
0493 @staticmethod
0494 def gen_env(data):
0495 path = data['install_path'] # data => installation information
0496
0497 yield Set('GENFIT_HOME', path)
0498
0499 # add bin to PATH
0500 yield Prepend('PATH', os.path.join(path, 'bin'))
0501
0502 # add lib to LD_LIBRARY_PATH
0503 yield Append('LD_LIBRARY_PATH', os.path.join(path, 'lib'))
0504 ```
0505
0506 One can test gen_env with:
0507
0508 ```bash
0509 edpm env
0510 ```
0511
0512 > \* - if other python packages use edpm programmatically to build something
0513
0514
0515 **3. System requirments**
0516
0517 If packet has some dependencies that can be installed by OS packet managers such as apt, one can
0518 add them to os_dependencies array.
0519
0520 ```python
0521 os_dependencies = {
0522 'required': {
0523 'ubuntu': "libboost-dev libeigen3-dev",
0524 'centos': "boost-devel eigen3-devel"
0525 },
0526 'optional': {
0527 'ubuntu': "",
0528 'centos': ""
0529 },
0530 }
0531 ```
0532
0533 > (!) don't remove any sections from the map, leave them blank
0534
0535 To test it one can run:
0536
0537 ```python
0538 edpm req ubuntu
0539 edpm req centos
0540 ```
0541
0542 ### Adding a custom package
0543
0544 Compared to the previous example, several more functions should be added:
0545
0546 - `setup` - configures the package
0547 - `step_clone`, `step_build`, `step_install` - execute commands to perform the step
0548
0549 **1. Setup**
0550
0551 Setup should provide all values, that are going to be used later in 'step_xxx' functions.
0552 Usually it is just 3 things:
0553
0554 ```python
0555 def setup(self):
0556 #
0557 # use_common_dirs_scheme() sets standard package variables:
0558 # source_path = {app_path}/src/{branch} # Where the sources for the current version are located
0559 # build_path = {app_path}/build/{branch} # Where sources are built. Kind of temporary dir
0560 # install_path = {app_path}/root-{branch} # Where the binary installation is
0561 self.use_common_dirs_scheme()
0562
0563 # Git download link. Clone with shallow copy
0564 self.clone_command = "git clone --depth 1 -b {branch} {repo_address} {source_path}".format(**self.config)
0565
0566 # make command:
0567 self.build_command = './configure && make -j{build_threads} install'.format(**self.config)
0568
0569 ```
0570
0571
0572 **2. Step functions**
0573
0574 3 docker alike functions that helps to execute stuff:
0575
0576 * `run(command)` - executes the console command
0577 * `workdir(dir)` - changes the working directory
0578 * `env(name, value)` - sets an environment variable
0579
0580
0581 ```python
0582 run(self.clone_command) # Execute git clone command
0583 workdir(self.source_path) # Go to our build directory
0584 run('./bootstrap') # This command required to run by rave once...
0585 env('RAVEPATH', self.install_path)
0586 ```