-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Major improvements to spack create #2707
Conversation
version_lines = "\n".join([ | ||
" version('{0}', {1}'{2}')".format( | ||
v, ' ' * (max_len - len(str(v))), h) for v, h in version_hashes | ||
]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, spack checksum tau
would result in:
version('2.26', '2af91f02ad26d5bf0954146c56a8cdfa')
version('2.25.2', 'f5e542d41eb4a7daa6241e5472f49fd7')
version('2.25.1.1', 'f2baae27c5c024937566f33339826d7c')
version('2.25.1', 'b9783f9bbe2862254bfdd208735241b6')
version('2.25', '46cd48fa3f3c4ce0197017b3158a2b43')
while
$ spack create --force https://www.cs.uoregon.edu/research/tau/tau_releases/tau-2.25.tar.gz
would result in:
version('2.26' , '2af91f02ad26d5bf0954146c56a8cdfa')
version('2.25.2' , 'f5e542d41eb4a7daa6241e5472f49fd7')
version('2.25.1.1', 'f2baae27c5c024937566f33339826d7c')
version('2.25.1' , 'b9783f9bbe2862254bfdd208735241b6')
version('2.25' , '46cd48fa3f3c4ce0197017b3158a2b43')
The latter isn't even PEP 8 compliant, and would raise problems during the flake8 tests. Now, both result in:
version('2.26', '2af91f02ad26d5bf0954146c56a8cdfa')
version('2.25.2', 'f5e542d41eb4a7daa6241e5472f49fd7')
version('2.25.1.1', 'f2baae27c5c024937566f33339826d7c')
version('2.25.1', 'b9783f9bbe2862254bfdd208735241b6')
version('2.25', '46cd48fa3f3c4ce0197017b3158a2b43')
# Make sure the user provided a package and not a URL | ||
if not valid_fully_qualified_module_name(args.package): | ||
tty.die("`spack checksum` accepts package names, not URLs. " | ||
"Use `spack md5 <url>` instead.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I accidentally do this all the time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you know what the user wants, why not just do it instead of quitting with an error message? Do we need spack md5
at all, or can its functionality be folded into spack checksum
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to rename spack checksum
? We will not always use md5
, and it would be nice if spack checksum
gave you whatever the current recommended checksum of a file/url was. Should spack checksum
be called spack find-new-versions
or spack-spider-versions
or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean rename spack md5
or rename spack checksum
? I don't have any particular preference. Let's leave that for another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean:
spack checksum
->spack find-new-versions
or some better name.spack md5
->spack checksum
(and it might spit out asha256
)
Another PR sounds good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, there's a lot of overlap between spack versions/checksum/md5
. We can work on that during the switch to sha256 or whatever we decide on.
format = " version(%%-%ds, '%%s')" % (max_len + 2) | ||
return '\n'.join( | ||
format % ("'%s'" % v, h) for v, h in self.version_hash_tuples | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now done in spack checksum
. No need to duplicate the effort.
'-f', '--force', action='store_true', dest='force', | ||
help="Overwrite any existing package file with the same name.") | ||
|
||
setup_parser.subparser = subparser |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this line is necessary? I don't see it in any other cmd.
subparser.add_argument( | ||
'-N', '--namespace', | ||
help="Specify a namespace for the package. Must be the namespace of " | ||
"a repository registered with Spack.") | ||
help="namespace for the package") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can someone test --repo
and --namespace
for me? I don't use either, so I can't really test whether or not the behavior has changed.
|
||
sorted_versions = sorted(versions.keys(), reverse=True) | ||
sorted_urls = [versions[v] for v in sorted_versions] | ||
return sorted_versions[:archives_to_fetch], sorted_urls[:archives_to_fetch] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all duplicated in spack checksum
, so I un-duplicated it.
@@ -328,65 +353,169 @@ def __call__(self, stage, url): | |||
|
|||
# Determine the build system based on the files contained | |||
# in the archive. | |||
build_system = 'unknown' | |||
build_system = 'default' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on unknown
vs. default
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about 'generic' for the regular old Package
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the name is only presented to the user in 2 scenarios. One, as a help option for spack create --template
, and two, when it prints out "This package looks like it uses the {0} build system". I think --template generic
makes more sense, but I also think the generic build system
doesn't make much sense. I could reword it of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of just special casing the method to something like "couldn't detect a build system -- using generic package", since that gives the user more information anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I would suggest a grammar of
spack create [options] <package>
, since that is consistent with other Spack commands. The demo you shared would then become:
$ spack create
# create an example package
$ spack create foobar
# create a package called foobar
$ spack create --template cmake
# create an example CMake package
$ spack create --force --template python numpy
$ spack create --force --template python py-numpy
# create a python package, both commands create the same package
$ spack create --template autotools <url>
# convenient when the tarball doesn't contain a configure script and autoreconf needs to be run
- Where was the code deduplicated, and where is it now?
# Make sure the user provided a package and not a URL | ||
if not valid_fully_qualified_module_name(args.package): | ||
tty.die("`spack checksum` accepts package names, not URLs. " | ||
"Use `spack md5 <url>` instead.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you know what the user wants, why not just do it instead of quitting with an error message? Do we need spack md5
at all, or can its functionality be folded into spack checksum
?
'scons': SconsGuess, | ||
'bazel': BazelGuess, | ||
'python': PythonGuess, | ||
'R': RGuess, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's please merge #2475 before doing this.
@@ -188,7 +188,7 @@ | |||
__all__ += spack.util.executable.__all__ | |||
|
|||
# User's editor from the environment | |||
editor = Executable(os.environ.get("EDITOR", "vi")) | |||
editor = Executable(os.environ.get("EDITOR", "vim")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vi
is not present on newer distributions like Fedora, and when both are present, vi
generally enables legacy mode. How common are distributions that only come with vi
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. But maybe some embedded or stripped down ones (e.g. for containers)? What about:
if "EDITOR" in os.environ:
editor = Executable(os.environ.get("EDITOR"))
else:
editor = which('vim')
if not editor:
editor = Executable('vi')
I'm an emacs
user -- I just picked vi
as the default because it's more likely to be installed, so I guess we should do best effort here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me back out this change and make it in a different PR, just to keep things simple.
|
||
spack.editor(path) | ||
|
||
|
||
def setup_parser(subparser): | ||
subparser.add_argument( | ||
'-f', '--force', dest='force', action='store_true', | ||
help="Open a new file in $EDITOR even if package doesn't exist.") | ||
help='deprecated, use `spack create` instead') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this deprecated enough for now? Honestly, I would be fine with ripping it out completely in this PR, but I can wait.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think taking it out is fine if the docs reflect it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do!
I think this is good to go now. We should merge #2475 before this though. I'll rebase on that after it's merged. Let me know if there are any other places in the documentation or code that reference |
That's the plan. But in a separate PR, as that change was more controversial and I don't want it to hold up these changes.
Here and here. It is in |
5dee821
to
6d8a824
Compare
@tgamblin Can you look this over at some point? I have a |
Ping @tgamblin |
Ping ping @tgamblin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adamjstewart: mostly minor questions/comments. This looks really good to me. See below.
Comments/questions:
- Now that the build system guessers are getting complex, does it make sense to make a subpackage for the different kinds, like
build_systems
,cmd
, etc.? - We'll need to figure out whether to merge this or documentation: build-system phases + build-time tests #2780 first.
|
||
Include how many checksums in the package file? (default is 5, q to abort) | ||
How many would you like to checksum? (default is 1, q to abort) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh good! I keep thinking to change this to 1.
|
||
# FIXME: Add dependencies if this package requires them. | ||
# depends_on("foo") | ||
# FIXME: Add dependencies if required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a note here for autotools packages, that most autotools packages will not need m4, autoconf, automake, libtool, etc.? I think it was confusing for at least one person. Also does m4 need to be here? It's brought in transitively through the other three.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about the m4 question. One thing I was considering doing was to create 2 separate build system guessers, one for Autotools with a configure script and one for Autotools without. I presume there are pretty tell-tale filenames that should make it obvious that the package uses Autotools even if it doesn't have a configure script?
Autotools without configure would automatically create an empty autoreconf method and add those 3-4 deps. Autotools with configure wouldn't add those deps, so no one would get confused.
If you can give me a list of tell-tale filenames that would indicate a package uses Autotools without a configure script, I can do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm kind of tempted to say we should just not bother at that point. I think it'll be confusing to have two autotools packages, and the existing one already has an autoreconf
phase. Also, I think it's complicated to do this generically. Some packages use automake
but not autoconf
, some do it the other way around, and some may or may not use libtool
. The particular dependencies you want are going to depend on that stuff, so I don't think it's unreasonable to require the packager to straighten this stuff out for packages that don't ship with a proper configure script.
I think we should be mindful of making the common case easy and the special cases possible. This accomplishes that very well, and we go a step further by automating a number of important build systems. I think helping people beyond that is outside the scope of what we should have to maintain in Spack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't mean creating a second AutotoolsPackage
, just a second AutotoolsPackageTemplate
. Both would subclass AutotoolsPackage
, but one would have additional dependencies and an additional method to override in the body. BuildSystemGuesser
would choose between the two based on whether or not a configure
script is present.
But if we don't want to do that, I think I'll just remove these dependencies. I agree that it is confusing. Also, the only way we can detect that it uses the Autotools build system is if there is a configure script, and if there is a configure script, we definitely won't need these.
# depends_on('autoconf', type='build') | ||
# depends_on('automake', type='build') | ||
# depends_on('libtool', type='build') | ||
# depends_on('foo') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe separate this from the autotools-related build deps and add a comment to the template saying to add library/other dependencies here?
make("install") | ||
def configure_args(self): | ||
# FIXME: Add arguments other than --prefix | ||
# FIXME: If not needed delete the function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"this function"
|
||
#. Get the ``install()`` method working. | ||
#. Get the installation working. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can remove this particular line from my changes and we can discuss it in #2780.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it will be good at some point to review the documentation as a whole, maybe before the next major release. The information is there, but rearranging it to make the important bits more prominent or rewording parts to make the style more homogeneous across sections may be worth it.
@@ -188,7 +188,7 @@ | |||
__all__ += spack.util.executable.__all__ | |||
|
|||
# User's editor from the environment | |||
editor = Executable(os.environ.get("EDITOR", "vi")) | |||
editor = Executable(os.environ.get("EDITOR", "vim")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. But maybe some embedded or stripped down ones (e.g. for containers)? What about:
if "EDITOR" in os.environ:
editor = Executable(os.environ.get("EDITOR"))
else:
editor = which('vim')
if not editor:
editor = Executable('vi')
I'm an emacs
user -- I just picked vi
as the default because it's more likely to be installed, so I guess we should do best effort here.
# Make sure the user provided a package and not a URL | ||
if not valid_fully_qualified_module_name(args.package): | ||
tty.die("`spack checksum` accepts package names, not URLs. " | ||
"Use `spack md5 <url>` instead.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to rename spack checksum
? We will not always use md5
, and it would be nice if spack checksum
gave you whatever the current recommended checksum of a file/url was. Should spack checksum
be called spack find-new-versions
or spack-spider-versions
or something?
@@ -328,65 +353,169 @@ def __call__(self, stage, url): | |||
|
|||
# Determine the build system based on the files contained | |||
# in the archive. | |||
build_system = 'unknown' | |||
build_system = 'default' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about 'generic' for the regular old Package
?
|
||
spack.editor(path) | ||
|
||
|
||
def setup_parser(subparser): | ||
subparser.add_argument( | ||
'-f', '--force', dest='force', action='store_true', | ||
help="Open a new file in $EDITOR even if package doesn't exist.") | ||
help='deprecated, use `spack create` instead') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think taking it out is fine if the docs reflect it.
I think it would make sense to move a lot of this logic to
I actually think our PRs don't overlap that much. My changes to the Packaging Guide mostly affect the beginning, where we introduce |
@tgamblin I believe this is ready for a second review now. |
@adamjstewart: some stuff is still missing but we can add it later. |
Thanks for getting this into 0.10! Let me know what is still missing and I'll add it to a new PR. |
This is a first stab at fulfilling #1108.
spack create
previously required a URL. If one was not present, or could not be parsed or fetched, it was useless. This resulted in many users being forced to usespack edit -f
or manually copy packages by hand. I wanted to draw a line between the two commands.spack create
is used to create new packages,spack edit
is used to edit existing packages. In order to removespack edit -f
, I needed to allowspack create
to work even if a URL does not exist.The following commands demonstrate the new abilities of
spack create
:I noticed a lot of duplicated code between
spack create
andspack checksum
. For example, all of the logic that searches for available versions, displays them and asks the user how many they would like to checksum, and formats the output versions was duplicated. I un-duplicated them.spack create
andspack checksum
--template
flag tospack create
spack create
to work even if a URL is not specifiedspack create
spack edit --force
We can change the UI from
spack create --name <name> <url>
tospack create --url <url> <name>
in another PR, as that seemed like a more controversial change.