Back to home page

EIC code displayed by LXR

 
 

    


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 ```