#! /usr/bin/bash # ------------------------------------------------------------------- Debug # COOKIE=$(mcookie|cut -c-8); grep -v V_GREP_ME $0 > /dev/shm/runme-$COOKIE.sh ; sleep 0.3; exec bash /dev/shm/runme-$COOKIE.sh # TESTING=1 # ---------------------------------------------------------------- Preamble PKG=fragpipe VERSION=22.0 BUILD=0 # some pipeline parts need python PYTHONVER=3.11.11 set -e umask 022 PATH=/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/package/bin PREFIX=/pkg/$PKG-$VERSION-$BUILD if [ -n "$TESTING" ]; then PREFIX=/scratch/local2/$PKG-$VERSION-$BUILD ; fi mkdir -p $PREFIX cat >$PREFIX/profile <<-EOF . /pkg/openjdk-21.0.0.35-0/profile PATH=$PREFIX/bin:\$PATH # avoid interference with the package/pkg python if [ -z "\$PYTHONUSERBASE" ]; then export PYTHONUSERBASE=\$HOME/.local/fragpipe-python ; fi if [ -d $PREFIX/.compatlibs ]; then export LD_LIBRARY_PATH=$PREFIX/.compatlibs\${LD_LIBRARY_PATH:+:}\$LD_LIBRARY_PATH ; fi EOF source $PREFIX/profile BUILD_TMPDIR=/scratch/local2/$PKG-$VERSION-$BUILD.$USER.build.tmp # keep pip's download cache when testing test -z "$TESTING" && test -d $BUILD_TMPDIR && ( chmod -R u+rwx $BUILD_TMPDIR || true ; rm -rf $BUILD_TMPDIR ) mkdir -p $BUILD_TMPDIR/home # embedded patches, copy script to an accessible location cp $0 $BUILD_TMPDIR; ME="$BUILD_TMPDIR/$(basename $0)" export TMPDIR=$BUILD_TMPDIR export HOME=$BUILD_TMPDIR/home NPROC=$(( $(nproc) * 4 / 5 + 1 )) BUILDDIR=$PREFIX/build mkdir -p $BUILDDIR cd $BUILDDIR # ---------------------------------------------------------------- fragpipe # the complete installable archive, but permissions are a mess! # orig: https://github.com/Nesvilab/FragPipe/releases/download/22.0/FragPipe-22.0.zip BEEHIVE=https://beehive.molgen.mpg.de/e30d93e6c0ef1e2aadd51e732f343451/FragPipe-22.0.zip test -e FragPipe-$VERSION.zip || wget -nv $BEEHIVE test -d fragpipe || bsdtar -xf FragPipe-$VERSION.zip mv fragpipe/bin .. mv fragpipe/lib .. # 'libjava' would be smart, but fp uses lib in lookup routines :/ mv fragpipe/tools .. mv fragpipe/workflows ../workflows_dist # reset executable attribute in the obvious cases, nerve ... # some *.py have a shebang, and some ... (you guessed) # this is safer then accidentally 'defusing' linux binaries within tools for ext in bat dll exe ico jar obo txt tsv ifl gdb pdb xml json glyc fasta workflow params; do find $PREFIX -type f -name "*.$ext" -exec chmod -c 0644 {} \+ done find $PREFIX -type d -exec chmod -c 0755 {} \+ # set jar mtimes according to content (btw. I didn't know that java was already around in 1980 :) rm -vf jarredater sed -ne '/^#Epatch:jarredater/ s/^#Epatch:\S* // p' $ME | patch -p0 --verbose find $PREFIX -name '*.jar' -exec python jarredater {} \+ ( # get rid of the way distracting console warning "No interface org.openide.util.spi.SVGLoader instance found" cd ../lib mkdir -p fixup cd fixup bsdtar -xf ../org-netbeans-swing-outline-RELEASE200.jar rm -v ./org/netbeans/swing/etable/columns.svg # the root cause jar -M -c -f org-netbeans-swing-outline-RELEASE200.jar META-INF org # alternative ... # mv META-INF/MANIFEST.MF . # jar -c -f org-netbeans-swing-outline-RELEASE200.jar -m MANIFEST.MF META-INF org mv -v org-netbeans-swing-outline-RELEASE200.jar .. cd .. rm -r fixup ) # the source archive , some bigger libs missing (diann torch_cpu), permissions here are again messed up # 'FragPipe-22.0.tar.gz' -> '/src/mariux/md5repo/bfaae508143e0a67b28a6393cbb7b2fb/FragPipe-22.0.tar.gz' # orig: https://github.com/Nesvilab/FragPipe/archive/refs/tags/22.0.tar.gz BEEHIVE=https://beehive.molgen.mpg.de/bfaae508143e0a67b28a6393cbb7b2fb/FragPipe-22.0.tar.gz test -e FragPipe-$VERSION.tar.gz || wget -nv $BEEHIVE test -d FragPipe-$VERSION || tar -xf FragPipe-$VERSION.tar.gz cd FragPipe-$VERSION # -------------------------------------------------------------- patch time # several GUI patches, some are cosmetic, some are related # to the fact that the installation directory is read only cd ./MSFragger-GUI # okay, we have them, so we also like to use them ... sed -i -e '/^\s\s*public static final int maxProcessors/ s/= 128;/= 256;/' \ src/com/dmtavt/fragpipe/tabs/TabWorkflow.java # ... and please do not call home on every start sed -i \ -e "/raw.githubusercontent.com/ s|https.*PATH_BUNDLE|file://$PREFIX/etc/Bundle.properties\"|" \ -e '/^\s\s*+ ".properties"\s*$/ d' \ src/com/dmtavt/fragpipe/params/ThisAppProps.java sed -ne '/^#Epatch:FragpipeLocations / s/^#Epatch:\S* // p' $ME | patch -p2 --verbose sed -ne '/^#Epatch:Fragpipe / s/^#Epatch:\S* // p' $ME | patch -p2 --verbose # ------------------------------------------------------------- compile now # a full build, but it will not help with the file attributes, s.a. :/ # result: build/github-release/FragPipe-22.0.zip # #> ./gradlew makeReleaseZipNoJre # debug/devel builds for fragpipe-22.0.jar # #> ./gradlew jar --rerun # only the recompiled gui is needed ... # result: build/libs/fragpipe-22.0.jar ./gradlew --console plain --max-workers $NPROC jar mv -v build/libs/fragpipe-22.0.jar $PREFIX/lib ./gradlew --stop # since it is a 'daemon' # ---------------------------------------------------------- finish install cd $PREFIX mkdir -p etc ltools updates workflows # the file that is supposed to be downloaded from git-hub cp -v build/FragPipe-22.0/MSFragger-GUI/src/com/dmtavt/fragpipe/Bundle.properties etc # this works w/o further installing logging jars: # JAVA_OPTS=-Dlogback.configurationFile=/package/fragpipe/etc/logback.xml fragpipe rm -vf etc/logback.xml sed -ne '/^#Epatch:logback/ s/^#Epatch:\S* // p' $ME | patch -p0 --verbose # the academic license was acquired by H. Schmidt, some of the tools seem to # talk with google analytics, just in case you wonder :) REPO_LICENSED_SOFTWARE=/package/fragpipe/src cd ltools cp -p $REPO_LICENSED_SOFTWARE/2024-417_Academic_Research_Use_License_05142024.pdf . bsdtar -xf $REPO_LICENSED_SOFTWARE/MSFragger-4.1.zip bsdtar -xf $REPO_LICENSED_SOFTWARE/IonQuant-1.10.27.zip bsdtar -xf $REPO_LICENSED_SOFTWARE/diaTracer-1.1.5.zip # create a neater launcher, but also keep the funny one bundled cat > $PREFIX/bin/mxfragpipe <<- EOF #! /usr/bin/bash set -e # populate ~/.config/FragPipe/fragpipe/workflows on first start XDG_CONFIG_HOME="\${XDG_CONFIG_HOME:-\$HOME/.config}" export XDG_CONFIG_HOME WORKFLOWDIR="\$XDG_CONFIG_HOME/FragPipe/fragpipe/workflows" if [ ! -d "\$WORKFLOWDIR" ] ; then # assume first run ... mkdir -vp "\$WORKFLOWDIR" cp --preserve=timestamps /package/fragpipe/workflows.dist/* "\$WORKFLOWDIR" echo 'fragpipe-config.tools-folder=$PREFIX/ltools' >> "\$XDG_CONFIG_HOME/FragPipe/fragpipe/fragpipe-ui.cache" fi # avoid stumbling over our filerunner or doublecommander apps # grep -l inode/directory /usr/share/applications/*.desktop if [ ! -e \$XDG_CONFIG_HOME/FragPipe/no_check_filemanager ]; then FILEMANAGER=\$(xdg-mime query default inode/directory) if [[ "\$FILEMANAGER" =~ 'doublecmd' || "\$FILEMANAGER" =~ 'filerunner' ]]; then echo "# ===========================================================================" echo "#" echo "# NOTE: Your default filemanager application is set to \$FILEMANAGER ..." echo "#" echo "# to fix this issue and switch to thunar, enter:" echo "# #> xdg-mime default thunar.desktop inode/directory" echo "#" echo "# to inhibit this message enter:" echo "# #> touch \$XDG_CONFIG_HOME/FragPipe/no_check_filemanager" echo "#" echo "# ===========================================================================" sleep 5 echo "# launching fragpipe now ..." sleep 1 fi fi # -classpath '/foobar/lib/*' only adds *.jar files - ohh, what a surprise :) exec java \$FRAGPIPE_OPTS \$JAVA_OPTS \\ -classpath '$PREFIX/lib/*' \\ com.dmtavt.fragpipe.FragPipeMain \\ "\${@+\$@}" EOF chmod +x $PREFIX/bin/mxfragpipe echo '# Fragpipe install is done ...' # ------------------------------------------------------------------ python cd $BUILDDIR # -------------------------------------- Use git to track package evolution test -d .git && rm -rf .git git init -q; echo -e '[user]\n name = none\n email = of_your_business...' >> .git/config echo '*' > .gitignore function piplist() { pip list | awk '{ printf("%-36s %s\n", $1,$2) }' | grep -v '\----' > GameOfVersions } function track() { if [ -d .git ]; then if git add -f GameOfVersions; then git commit -q -n -m "Package: '$*'" || /bin/true fi fi } function install() { echo "# ::INST:: # '${@+$@}'" # no-color is nice, but doesn't work when dependencies are installed, so (mis-)use a pipe pip install --no-color --compile --cache-dir=$HOME/.cache/pip --prefix=$PREFIX "${@+$@}" | cat piplist track $* } # ---------------------------------------- Build Python & support libraries ( # orig: https://www.python.org/ftp/python/3.11.11/Python-3.11.11.tgz BEEHIVE=https://beehive.molgen.mpg.de/9a5b43fcc06810b8ae924b0a080e6569/Python-3.11.11.tgz test -e Python-$PYTHONVER.tgz || wget -nv $BEEHIVE test -d Python-$PYTHONVER || tar -xf Python-$PYTHONVER.tgz cd Python-$PYTHONVER # BerkeleyDB, the undead ... # Newer libgdbm_compat.so versions pull libgdbm.so on their own, our libgdbm_compat.so is older ... # So, let setup.py create '-lgdbm -lgdbm_compat' instead of a sole '-lgdbm_compat' # verbatim: ndbm_libs = ['gdbm_compat'] => ndbm_libs = ['gdbm','gdbm_compat'] sed -i -e "/ndbm_libs = / s/_compat'/','gdbm_compat'/" setup.py # leave further hints in the log sed -i -e '/db_setup_debug = False/ s/False/True/' \ -e '/dbm_setup_debug = False/ s/False/True/' setup.py # These may come handy if the Python build needs exclusive stuff from $PREFIX # INCLUDEDIR=$PREFIX/include \ # LIBDIR=$PREFIX/lib \ LDFLAGS="-Wl,-rpath=$PREFIX/lib" \ ./configure \ --prefix=$PREFIX \ --enable-shared make -j $NPROC make install # it might come to happen that something down the line may just call 'python', defuse ... test -e $PREFIX/bin/python || ln -s python3 $PREFIX/bin/python python -m ensurepip pip3 install --prefix=$PREFIX -I pip ( # fix 'please update' noise from pip cd $PREFIX/lib/python*/site-packages sed -ne '/^#Epatch:pip/ s/^#Epatch:\S* // p' $ME | patch -p1 --verbose ) # I hate to do this ... ln -s lib $PREFIX/lib64 ) install setuptools piplist; track START install Cython install numpy==1.26.4 # The EasyPQP author nailed numpy to this version (needlessly of course, <2 is the right way ...) install numba==0.60.0 install wheel PACKAGES=$(sed -e s/#.*$// <<- __PKGLIST__ pyopenms==3.2.0 easypqp==0.1.50 lxml==5.3.0 __PKGLIST__ ) for PKG in $PACKAGES; do install $PKG done # ------------------------------------------------------------ Sanity check echo "# --------- *** SANITY CHECKS *** ---------" # I guess it makes sense that files can be read by all users ... echo "# 1) Check for unreadable files ..." cd $PREFIX for D in bin include lib share; do find $D \! -perm -004 -exec chmod -c a+r {} + done # a cheap one :) echo "# 2) Running pip check" pip check # load all packages, see warnings and spot installation errors echo "# 3) Module load test." export NUMEXPR_MAX_THREADS=1 python -c 'help("modules")' echo "# Note: reached end of load test" echo "For Deeper checks:" echo "cd ${BUILDDIR} ; git log --patch | grep ^[\+\-][^\+\-]" exit # -------------------------------------------------------- Included patches #Epatch:pip # Operation 'Forever young', disable version-check per default. #Epatch:pip # The option needs to be kept, because some tools make use of #Epatch:pip # it and would cause pip to fail. #Epatch:pip --- a/pip/_internal/cli/cmdoptions.py 2022-08-09 17:29:15.853442948 +0200 #Epatch:pip +++ b/pip/_internal/cli/cmdoptions.py 2022-08-10 10:31:35.124945154 +0200 #Epatch:pip @@ -892,7 +892,6 @@ #Epatch:pip dest="disable_pip_version_check", #Epatch:pip action="store_true", #Epatch:pip - default=False, #Epatch:pip - help="Don't periodically check PyPI to determine whether a new version " #Epatch:pip - "of pip is available for download. Implied with --no-index.", #Epatch:pip + default=True, #Epatch:pip + help="Ignore this option, the version check IS disabled.", #Epatch:pip ) #Epatch:jarredater --- jarredater #Epatch:jarredater +++ jarredater #Epatch:jarredater @@ -0,0 +1,13 @@ #Epatch:jarredater +import os, sys, time, zipfile #Epatch:jarredater + #Epatch:jarredater +dt_list = [] #Epatch:jarredater +if len(sys.argv) > 1: #Epatch:jarredater + for f in sys.argv[1:]: #Epatch:jarredater + dt_list.clear() #Epatch:jarredater + zf = zipfile.ZipFile(f, 'r') #Epatch:jarredater + for i in zf.infolist(): dt_list.append(i.date_time) #Epatch:jarredater + zf.close() #Epatch:jarredater + maxtime = max( dt_list ) #Epatch:jarredater + print('# touching', f, '->', maxtime) #Epatch:jarredater + epo = time.mktime( maxtime + (0,0,0) ) #Epatch:jarredater + os.utime(f, (epo, epo)) #Epatch:logback --- etc/logback.xml #Epatch:logback +++ etc/logback.xml #Epatch:logback @@ -0,0 +1,12 @@ #Epatch:logback +<configuration> #Epatch:logback + <!-- enable: JAVA_OPTS=-Dlogback.configurationFile=/path/to/logback.xml fragpipe --> #Epatch:logback + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> #Epatch:logback + <encoder> #Epatch:logback + <pattern>%d %-5level %-42logger{42} - %msg%n</pattern> #Epatch:logback + </encoder> #Epatch:logback + </appender> #Epatch:logback + <logger name="com.dmtavt.fragpipe.api.FragpipeCacheUtils" level="error" /> #Epatch:logback + <root level="debug"> #Epatch:logback + <appender-ref ref="STDOUT" /> #Epatch:logback + </root> #Epatch:logback +</configuration> ### ========================================================================================= ### VERY CAREFUL NOW, we are patchin WinDos files, lookout for '<cr>' / '^M' in your editor ! ### ========================================================================================= #Epatch:FragpipeLocations diff --git a/MSFragger-GUI/src/com/dmtavt/fragpipe/FragpipeLocations.java b/MSFragger-GUI/src/com/dmtavt/fragpipe/FragpipeLocations.java #Epatch:FragpipeLocations index 6f14590e..58f56d5f 100644 #Epatch:FragpipeLocations --- a/MSFragger-GUI/src/com/dmtavt/fragpipe/FragpipeLocations.java #Epatch:FragpipeLocations +++ b/MSFragger-GUI/src/com/dmtavt/fragpipe/FragpipeLocations.java #Epatch:FragpipeLocations @@ -106,8 +106,9 @@ public class FragpipeLocations { #Epatch:FragpipeLocations tools = dir.resolve(Paths.get("../tools")); #Epatch:FragpipeLocations } #Epatch:FragpipeLocations #Epatch:FragpipeLocations - Path workflows = dir.resolve("../workflows"); #Epatch:FragpipeLocations - Path longTermStorage = CacheUtils.getTempDir(); #Epatch:FragpipeLocations + // Path workflows = dir.resolve("../workflows"); #Epatch:FragpipeLocations + Path workflows = dir.resolve( CacheUtils.getTempDir().toString() + "/workflows" ); #Epatch:FragpipeLocations + Path longTermStorage = CacheUtils.getTempDir(); // well this yields to > XDG_CONFIG_HOME + "/FragPipe" < #Epatch:FragpipeLocations #Epatch:FragpipeLocations // create locations if they don't yet exist #Epatch:FragpipeLocations List<Path> paths = Arrays.asList(dir, cache, tools, workflows, longTermStorage); #Epatch:Fragpipe diff --git a/MSFragger-GUI/src/com/dmtavt/fragpipe/Fragpipe.java b/MSFragger-GUI/src/com/dmtavt/fragpipe/Fragpipe.java #Epatch:Fragpipe index 16fd82ec..64696321 100644 #Epatch:Fragpipe --- a/MSFragger-GUI/src/com/dmtavt/fragpipe/Fragpipe.java #Epatch:Fragpipe +++ b/MSFragger-GUI/src/com/dmtavt/fragpipe/Fragpipe.java #Epatch:Fragpipe @@ -289,22 +289,36 @@ public class Fragpipe extends JFrameHeadless { #Epatch:Fragpipe log.debug("Saving ui cache: collected {} properties from UI. Size after merging with cached object: {}.", #Epatch:Fragpipe tabsAsProps.size(), cache.propsUiState.size()); #Epatch:Fragpipe try { #Epatch:Fragpipe - cache.propsUiState.setPath(FragpipeLocations.get().getPathUiCache(false)); #Epatch:Fragpipe - cache.propsUiState.save(); #Epatch:Fragpipe + // when we fail here (lib/../cache), the other one will not be written out :/ #Epatch:Fragpipe + //cache.propsUiState.setPath(FragpipeLocations.get().getPathUiCache(false)); #Epatch:Fragpipe + //cache.propsUiState.save(); #Epatch:Fragpipe cache.propsUiState.setPath(FragpipeLocations.get().getPathUiCache(true)); #Epatch:Fragpipe cache.propsUiState.save(); #Epatch:Fragpipe } catch (IOException ex) { #Epatch:Fragpipe - log.error("Error saving ui cache. It won't affect the results."); #Epatch:Fragpipe + log.error("Error saving ui cache. It won't affect the results." + " (" + #Epatch:Fragpipe + FragpipeLocations.get().getPathUiCache(true) + ")" #Epatch:Fragpipe + ); #Epatch:Fragpipe } #Epatch:Fragpipe try { #Epatch:Fragpipe - cache.propsRuntime.setPath(FragpipeLocations.get().getPathRuntimeCache(false)); #Epatch:Fragpipe - cache.propsRuntime.save(); #Epatch:Fragpipe + // when we fail here (lib/../cache), the other one will not be written out :/ #Epatch:Fragpipe + //cache.propsRuntime.setPath(FragpipeLocations.get().getPathRuntimeCache(false)); #Epatch:Fragpipe + //cache.propsRuntime.save(); #Epatch:Fragpipe cache.propsRuntime.setPath(FragpipeLocations.get().getPathRuntimeCache(true)); #Epatch:Fragpipe cache.propsRuntime.save(); #Epatch:Fragpipe } catch (IOException ex) { #Epatch:Fragpipe - log.error("Error saving runtime cache. It won't affect the results."); #Epatch:Fragpipe + log.error("Error saving runtime cache. It won't affect the results." + " (" + #Epatch:Fragpipe + FragpipeLocations.get().getPathRuntimeCache(true) + ")" #Epatch:Fragpipe + ); #Epatch:Fragpipe } #Epatch:Fragpipe #Epatch:Fragpipe + /* #Epatch:Fragpipe + #Epatch:Fragpipe + -- skipping this for the moment -- #Epatch:Fragpipe + #Epatch:Fragpipe + - copy the existing workflows on first start (done by the starter script) #Epatch:Fragpipe + - then use the users XDG_CONFIG_HOME/FragPipe/fragpipe/workflows directory #Epatch:Fragpipe + as the sole source for workflows #Epatch:Fragpipe + #Epatch:Fragpipe // saving workflows #Epatch:Fragpipe Path dirWorkflows = FragpipeLocations.get().getDirWorkflows(); #Epatch:Fragpipe Path lts = FragpipeLocations.get().getPathLongTermStorage().resolve(dirWorkflows.getFileName()); #Epatch:Fragpipe @@ -315,6 +329,8 @@ public class Fragpipe extends JFrameHeadless { #Epatch:Fragpipe log.error("Error saving workflows between sessions."); #Epatch:Fragpipe throw new IllegalStateException(e); #Epatch:Fragpipe } #Epatch:Fragpipe + */ #Epatch:Fragpipe + #Epatch:Fragpipe } #Epatch:Fragpipe #Epatch:Fragpipe public static FormEntry.Builder fe(JComponent comp, String compName) { #Epatch:Fragpipe @@ -385,9 +401,11 @@ public class Fragpipe extends JFrameHeadless { #Epatch:Fragpipe System.exit(1); #Epatch:Fragpipe } #Epatch:Fragpipe #Epatch:Fragpipe + /* why are linux users forced to use 'Nimbus' ? #Epatch:Fragpipe if (!headless) { #Epatch:Fragpipe SwingUtils.setLaf(); #Epatch:Fragpipe } #Epatch:Fragpipe + */ #Epatch:Fragpipe #Epatch:Fragpipe FragpipeLoader fragpipeLoader = new FragpipeLoader(); #Epatch:Fragpipe Bus.register(fragpipeLoader);