Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EGA-Cryptor #51108

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions recipes/ega-cryptor/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e -x
# set -eu -o pipefail

outdir=$PREFIX/share/$PKG_NAME-$PKG_VERSION-$PKG_BUILDNUM
mkdir -p $outdir
ln -s $PREFIX/share/$PKG_NAME-$PKG_VERSION-$PKG_BUILDNUM $PREFIX/share/$PKG_NAME
mkdir -p $PREFIX/bin
cp -Rf * $outdir/
mv $outdir/EGA-Cryptor-$PKG_VERSION/ega-cryptor-$PKG_VERSION.jar $outdir/ega-cryptor.jar
cp -f $RECIPE_DIR/ega-cryptor.py $outdir/ega-cryptor
chmod +x $outdir/ega-cryptor
ln -sf $outdir/ega-cryptor $PREFIX/bin
99 changes: 99 additions & 0 deletions recipes/ega-cryptor/ega-cryptor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env python
#
# Wrapper script for Java Conda packages that ensures that the java runtime
# is invoked with the right options. Adapted from the bash script (http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in/246128#246128).

#
# Program Parameters
#
import os
import subprocess
import sys
import shutil
from os import access
from os import getenv
from os import X_OK
jar_file = 'ega-cryptor-2.0.0.jar'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider making the jar file name configurable.

The jar file name is currently hardcoded. To improve flexibility and ease future updates, consider making this configurable. You could use an environment variable or a command-line argument.

Example implementation:

import os

jar_file = os.environ.get('EGA_CRYPTOR_JAR', 'ega-cryptor-2.0.0.jar')

This allows users to override the jar file name if needed, while maintaining the current default.


default_jvm_mem_opts = ['-Xms512m', '-Xmx1g']

# !!! End of parameter section. No user-serviceable code below this line !!!


def real_dirname(path):
"""Return the symlink-resolved, canonicalized directory-portion of path."""
return os.path.dirname(os.path.realpath(path))


def java_executable():
"""Return the executable name of the Java interpreter."""
java_home = getenv('JAVA_HOME')
java_bin = os.path.join('bin', 'java')

if java_home and access(os.path.join(java_home, java_bin), X_OK):
return os.path.join(java_home, java_bin)
else:
return 'java'


def jvm_opts(argv):
"""Construct list of Java arguments based on our argument list.

The argument list passed in argv must not include the script name.
The return value is a 3-tuple lists of strings of the form:
(memory_options, prop_options, passthrough_options)
"""
mem_opts = []
prop_opts = []
pass_args = []
exec_dir = None

for arg in argv:
if arg.startswith('-D') or arg.startswith('-XX'):
prop_opts.append(arg)
elif arg.startswith('-Xm'):
mem_opts.append(arg)
elif arg.startswith('--exec_dir='):
exec_dir = arg.split('=')[1].strip('"').strip("'")
if not os.path.exists(exec_dir):
shutil.copytree(real_dirname(sys.argv[0]), exec_dir, symlinks=False, ignore=None)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for shutil.copytree.

When copying files with shutil.copytree, it's good practice to handle potential exceptions that may occur, such as FileExistsError or OSError, to prevent the script from crashing unexpectedly.

Apply this diff to add exception handling:

             if not os.path.exists(exec_dir):
-                shutil.copytree(real_dirname(sys.argv[0]), exec_dir, symlinks=False, ignore=None)
+                try:
+                    shutil.copytree(real_dirname(sys.argv[0]), exec_dir, symlinks=False, ignore=None)
+                except Exception as e:
+                    sys.stderr.write(f"Error copying files to exec_dir: {e}\n")
+                    sys.exit(1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
shutil.copytree(real_dirname(sys.argv[0]), exec_dir, symlinks=False, ignore=None)
if not os.path.exists(exec_dir):
try:
shutil.copytree(real_dirname(sys.argv[0]), exec_dir, symlinks=False, ignore=None)
except Exception as e:
sys.stderr.write(f"Error copying files to exec_dir: {e}\n")
sys.exit(1)

Comment on lines +57 to +59
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve robustness of --exec_dir handling.

The current implementation of --exec_dir handling could be more robust. Consider adding error handling and validation for the directory path.

Example implementation:

elif arg.startswith('--exec_dir='):
    exec_dir = arg.split('=')[1].strip('"').strip("'")
    if not os.path.isabs(exec_dir):
        sys.stderr.write(f"Error: --exec_dir must be an absolute path\n")
        sys.exit(1)
    if not os.path.exists(exec_dir):
        try:
            shutil.copytree(real_dirname(sys.argv[0]), exec_dir, symlinks=False, ignore=None)
        except OSError as e:
            sys.stderr.write(f"Error creating exec_dir: {e}\n")
            sys.exit(1)

This implementation ensures that the path is absolute and handles potential errors during directory creation.

else:
pass_args.append(arg)

# In the original shell script the test coded below read:
# if [ "$jvm_mem_opts" == "" ] && [ -z ${_JAVA_OPTIONS+x} ]
# To reproduce the behaviour of the above shell code fragment
# it is important to explicitly check for equality with None
# in the second condition, so a null envar value counts as True!

if mem_opts == [] and getenv('_JAVA_OPTIONS') is None:
mem_opts = default_jvm_mem_opts

return (mem_opts, prop_opts, pass_args, exec_dir)
Comment on lines +39 to +72
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider refactoring jvm_opts function.

The jvm_opts function is quite long and handles multiple responsibilities. Consider splitting it into smaller, more focused functions to improve readability and maintainability.

You could split the function into:

  1. parse_jvm_args: Handle parsing of JVM-related arguments.
  2. handle_exec_dir: Process the --exec_dir argument.
  3. apply_default_memory_opts: Apply default memory options if necessary.

This would make the main jvm_opts function shorter and easier to understand.



def main():
java = java_executable()
"""
PeptideShaker updates files relative to the path of the jar file.
In a multiuser setting, the option --exec_dir="exec_dir"
can be used as the location for the peptide-shaker distribution.
If the exec_dir does not exist,
we copy the jar file, lib, and resources to the exec_dir directory.
"""
(mem_opts, prop_opts, pass_args, exec_dir) = jvm_opts(sys.argv[1:])
jar_dir = exec_dir if exec_dir else real_dirname(sys.argv[0])

jar_arg = '-cp' if pass_args and pass_args[0].startswith('eu') else '-jar'

jar_path = os.path.join(jar_dir, jar_file)

java_args = [java] + mem_opts + prop_opts + [jar_arg] + [jar_path] + pass_args

return_code = subprocess.call(java_args)
if return_code != 0:
sys.stderr.write(f"Java process exited with return code {return_code}\n")
sys.exit(return_code)
Comment on lines +93 to +96
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling for subprocess call.

The current error handling for the subprocess call could be more informative. Consider capturing and logging more details about the error.

Example implementation:

try:
    return_code = subprocess.call(java_args)
    if return_code != 0:
        sys.stderr.write(f"Java process exited with return code {return_code}\n")
        sys.exit(return_code)
except Exception as e:
    sys.stderr.write(f"Error executing Java process: {e}\n")
    sys.exit(1)

This will provide more context if there's an error in executing the Java process.


if __name__ == '__main__':
main()
38 changes: 38 additions & 0 deletions recipes/ega-cryptor/meta.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{% set version = "2.0.0" %}

package:
name: ega-cryptor
version: {{ version }}

build:
noarch: generic
number: 0
run_exports:
- {{ pin_compatible('ega-cryptor', max_pin="x.x.x") }}

source:
url: https://ega-archive.org/assets/files/EgaCryptor.zip
sha256: 402d9d1d5de8beea416d3e8dc8e10c3fd1e7548e4d6e29d503afe1fcbe11ff8a

requirements:
build:
- unzip
run:
- openjdk >=8
- python >=3.6

test:
commands:
- "ega-cryptor -h"

about:
home: https://ega-archive.org/submission/data/file-preparation/egacryptor/
summary: EGACryptor v.2.0.0
license: Apache-2.0
description: The EGACryptor v.2.0.0 is a JAVA-based application which enables submitters
to produce EGA compliant encrypted files along with files for the encrypted
and unencrypted md5sum for each file to be submitted. The application will
generate an output folder that will by default mirror the directory structure
containing the original files. This output folder can subsequently be uploaded
to the EGA FTP staging area via an FTP or Aspera client.
# Description extracted from the EGA-Cryptor website.
Loading