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 support for --new, --copy, --edit and --show #2665

Open
wants to merge 21 commits into
base: develop
Choose a base branch
from

Conversation

boegel
Copy link
Member

@boegel boegel commented Nov 18, 2018

  • --new: create new easyconfig file based on specified information
  • --copy: copy easyconfig file to specified location (or current directory)
  • --edit: open easyconfig file with editor command specified via --editor-command-template
  • --show: print contents of easyconfig file

This PR is mostly about adding the support for --new. The idea here is that you can basically just throw stuff at it that should be included in a new easyconfig file. The implementation uses a bunch of heuristics to figure out what the provided information likely represents. As such, it certainly won't be perfect in all possible situations, but I'm confident it will be very useful in practice.

The other options (--copy, --edit and --show) are intended to be used together with either --new or --search, and have a pretty straightforward implementation.

Example usage (docs update coming up later):

$ eb --new example 1.2.3 foss/2018a ConfigureMake files:bin/example "This an example description" homepage=https://example.com https://files/example.com/example-1.2.3.tar.gz moduleclass=tools --show
== temporary log file in case of crash /tmp/eb-rHjhuK/easybuild-uKEQ4P.log
== Contents of easyconfig file ./example-1.2.3-foss-2018a.eb:

easyblock = 'ConfigureMake'

name = 'example'
version = '1.2.3'

homepage = {'https': '//example.com'}
description = "This an example description"

toolchain = {'name': 'foss', 'version': '2018a'}

source_urls = ['https://files/%(name)s.com']
sources = [SOURCE_TAR_GZ]


sanity_check_paths = {
    'files': ['bin/%(name)s'],
    'dirs': [],
}

moduleclass = 'tools'

== easyconfig file ./example-1.2.3-foss-2018a.eb created!

…ile + leverage build_option in main.py to clean up code a bit
@boegel boegel added this to the 3.8.0 milestone Nov 18, 2018
Copy link
Member

@damianam damianam left a comment

Choose a reason for hiding this comment

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

Haven't reviewed the tests yet. My biggest concern/comment is that this PR is very flexible, which complicates the code and can leave lots of situations potentially mishandled if the heuristics don't get it right. Shouldn't it make more sense being more strict in how the parameters are passed in the command line? Making unnecessary assumptions got me in troubles in the past :-P

easyblock_names = [e['class'] for e in avail_easyblocks().values()]

# regular expression to recognise a version
version_regex = re.compile('^[0-9][0-9.-]')
Copy link
Member

Choose a reason for hiding this comment

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

Why this hyperrestrictive pattern?

Copy link
Member Author

Choose a reason for hiding this comment

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

The assumption here is that a version always starts with a digit, and is followed by either another digit or a . or -.

Is that too restrictive? I can loosen it up, but I think that would fit most versions out there?

You can always use eb --new-pr example version=1.2.3, that bypasses this heuristic entirely...

Copy link
Member

Choose a reason for hiding this comment

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

Well, maybe "hyperrestrictive" is a stretch. But we have a couple of cases where version is a single digit, or a digit followed by a dash (-). I guess we can consider those corner cases not considered in the heuristic?

# regular expression to recognise a version
version_regex = re.compile('^[0-9][0-9.-]')

# first check whether easyconfig parameter name is specfied as '<param_name>=<value>'
Copy link
Member

Choose a reason for hiding this comment

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

Typo

@@ -699,3 +701,187 @@ def avail_easyblocks():
easyblock_mod_name, easyblocks[easyblock_mod_name]['loc'], path)

return easyblocks


def parse_param_value(string):
Copy link
Member

Choose a reason for hiding this comment

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

There is 0 logging in the method. Maybe add some? It is important to know what the heuristics are doing

Copy link
Member Author

Choose a reason for hiding this comment

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

Very good point, thanks, I'll look into that.

value[item_key] = []
if item_val:
value[item_key].append(item_val)
elif isinstance(item_val, tuple):
Copy link
Member

Choose a reason for hiding this comment

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

Can't item_val be a list as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, because ; is used as a separator between different <key>:<value> entries in a dict value. And , is the separator for tuples (see below).

; is also the separator for lists, but since anything that starts with [a-z_]+: is considered a dict value, it'll get split on ; to separate different <key>=<value> entries, and hence you can never have a list-type value anymore... :)

Example: files:bin/example,lib/libexample.a;dirs:include gets parsed as:

{
  'files': ['bin/example', 'lib/libexample.a'],
  'dirs': ['include'],
}

; can not be used as a separator between bin/example and lib/libexample.a

@@ -173,6 +173,73 @@ def run_contrib_style_checks(ecs, check_contrib, check_style):
return check_contrib or check_style


def handle_cat_copy_edit(filepaths, target=None, copy=None):
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand why this returns an empty list in all cases except if --copy is used. Wouldn't it make sense to have fp appended in --edit as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

The result of handle_cat_copy_edit is only used to print a message mentioning which files have been copied.

If you only use --edit, it'll open the file for editing in place, without copying it.

So you can go eb --search foo=1.2.3 --edit (--edit & co work together with both the added --new and the existing --search).

@boegel
Copy link
Member Author

boegel commented Nov 21, 2018

@damianam W.r.t. your concern about flexibility: you can always bypass the heuristics by always passing <param>=<value> style arguments, which get preference over anything else.

For anything that doesn't match this pattern, there are a number of very reasonable heuristics.

One thing I should also clarify is that eb --new only generates an easyconfig file, it does not start the actual build afterwards. So, you're supposed to check the generated easyconfig file before using it, not use it blindly...

@boegel
Copy link
Member Author

boegel commented Nov 22, 2018

@damianam Please re-review?

easyblock_names = [e['class'] for e in avail_easyblocks().values()]

# regular expression to recognise a version
version_regex = re.compile('^[0-9][0-9.-]')
Copy link
Member

Choose a reason for hiding this comment

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

Well, maybe "hyperrestrictive" is a stretch. But we have a couple of cases where version is a single digit, or a digit followed by a dash (-). I guess we can consider those corner cases not considered in the heuristic?

self.assertEqual(parse_param_value(''), (None, ''))
self.assertEqual(parse_param_value('test123'), (None, 'test123'))

self.assertEqual(parse_param_value("this is a description"), ('description', "this is a description"))
Copy link
Member

Choose a reason for hiding this comment

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

Have a test where "description" is not part of the string?


self.assertEqual(parse_param_value("this is a description"), ('description', "this is a description"))

self.assertEqual(parse_param_value('1.2.3'), ('version', '1.2.3'))
Copy link
Member

Choose a reason for hiding this comment

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

Test different versions? 1.0, 22.0, 1.2a....


# names of source tarballs are recognized
for ext in ['tar.gz', 'gz', 'tar.bz2', 'bz2', 'zip']:
self.assertEqual(parse_param_value('toy-0.0.' + ext), ('sources', 'toy-0.0.' + ext))
Copy link
Member

Choose a reason for hiding this comment

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

What if the file is toy_0.0.zip or toy0.0.tar?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants