-
-
Notifications
You must be signed in to change notification settings - Fork 100
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
Install executables #126
Install executables #126
Conversation
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 realise this is a WIP PR but I thought I would note some things regardless.
src/validator.cr
Outdated
end | ||
|
||
module Validate | ||
macro error(message) |
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 this have to be a macro?
src/validator.cr
Outdated
end | ||
|
||
unless version =~ /\A[0-9.]+(-[-_a-z.])?\Z/ | ||
warning "version should follow semantic versioning" |
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.
Mention calver?
test/integration/install_test.cr
Outdated
} | ||
|
||
with_shard(metadata) do | ||
puts run("shards install --no-color", capture: true) |
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.
Debug puts
378bc16
to
85f7e9c
Compare
@RX14 bad commit, the |
SPEC.md
Outdated
A list of executables to be linked by the shared (Array). | ||
|
||
The executables can be of any type or language (e.g., shell, binary, ruby), they | ||
must have the executable bit set (POSIX platforms) and they must exit in the |
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.
exit
-> exist
d6bb426
to
4adb052
Compare
5300e03
to
9460a40
Compare
I'm changing my point of view, again. We should have stubs instead of copying the executables, in order to have some environments variables about the project, namely This will require a |
I'm now unconvinced by binstubs 😖 I really prefer simply copying executables into the For @bcardiff scenario: the executable can assume (or require) to be run from the project's top directory (e.g. |
@ysbaddaden What are the disadvantages of binstubs? It doesn't seem like all too much more code. |
@@ -44,7 +44,7 @@ module Shards | |||
end | |||
end | |||
|
|||
protected def install_path | |||
def install_path |
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 have to test this method if you are turning it public #justsaying
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.
No. Writing unit tests for details would merely duplicate the integration test.
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 agree. If you are creating something public you have to guarantee it is correct and the way to do that is automated tests.
But it is up to you.
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 an application, not a library. You may use it as a library, but at your own risk: I don't guarantee the internal API to be stable.
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.
Good to know that you don't guarantee the internal API to be stable for you or for those who one day would contribute.
Like I said: it is up to you.
Just a workaround before crystal-lang/shards#126 becomes live.
src/package.cr
Outdated
Shards.logger.debug "Install bin/#{name}" | ||
source = File.join(resolver.install_path, "bin", name) | ||
dest = File.join(bin_path, name) | ||
FileUtils.cp(source, dest) |
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.
Why not symlink?
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.
Because bin
should assume to have binaries? Thus, to prepare a package for example, I can cp bin/foo dist/bin/
rather than cp $(realpath bin/foo) dist/bin/
or digging cp lib/foo/bin/foo dist/bin
because bin/foo
can't be relied upon?
Maybe we could hardlink?
I agree with @ysbaddaden that executables should just assume they're run from the project root. Both |
src/commands/update.cr
Outdated
@@ -14,6 +14,7 @@ module Shards | |||
Shards.logger.info "Installing #{package.name} (#{package.version})" | |||
package.install | |||
end | |||
package.install_executables |
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.
Hum, executables haven't been rebuilt if the dependency was already installed, why bother reinstalling it? Or maybe a loose version (reinstall if missing?)
455aaa1
to
7393ee4
Compare
Reworked. It now creates a hardlink on POSIX systems, unless the same executable was already installed (i.e. same inode). On Windows it just copies the executable. |
src/package.cr
Outdated
next if File.stat(destination).ino == File.stat(source).ino | ||
File.delete(destination) | ||
end | ||
File.link(source, destination) |
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.
Just because not being executed on windows doesn't mean the file system necessarily supports hard links. There should be a fallback in case File.link
does not work.
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.
windows supports hard links though
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.
Sorry, I'm blinded. To me 1. Windows is stuck on FAT32 file systems, and 2. anything else is POSIX and supports hard links (or we're talking embedded systems and they're out-of-scope).
I'll remove the Windows check and assume POSIX until someone with better win32 knowledge ports shards.
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.
POSIX generally supports hard links, but not every supported filesystem does. That can be an issue for example with remote file systems.
I typically use crystal in a linux VM which mounts the windows host's file system. Creating hard links is not possible on such a file system.
There are probably other issues as well but the main point is: it doesn't need to be a hard link, a symlink or copy work as well (allthough with minor drawbacsk). Hard links are not 100% supported everywhere, so there should be an alternative as fallback.
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.
Sigh.
src/package.cr
Outdated
FileUtils.cp(source, destination) | ||
{% else %} | ||
if File.exists?(destination) | ||
next if File.stat(destination).ino == File.stat(source).ino |
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'd just take this out, and either:
- always replace
- always ignore if it exists.
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.
We can't ignore: updating a shard may build a new executable, if shards made the hardlink, we're all set (no need to copy), but if the destination was changed for some reason, then we should delete/link again.
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.
Well inodes are going to be removed from File::Info
because they're platform-specific so there's little point in having this check just to remove it later.
Let's just always try hardlinking, and on an exception try copying. It works on every platform and is simple.
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.
Sigh.
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 just make File::Info have mtime, file? and directory?. Let's drop everything else. Not cross platform, useless or whatever else. I'll use stat(2)
directly to get anything done 😭
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.
Well:
File.link("foo", "bar") # => 0
File.link("foo", "bar") # => Error creating link from foo to bar: File exists (Errno)
The only solutions are:
- delete/copy all the time (stupid, waste);
- check inodes, delete + link if they're different (smart, efficient).
I'm sorry, but I won't remove the inode check. You'll have to add File::Info#inode
for systems that support it, so we have a compile time error on windows, for example.
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.
No, the correct solution is to hide the inode and supply a File::Info#same?(File::Info)
. On unix it will check if device and inode are equal (but those fields are still hidden). On windows it does whatever. I suppose I should implement this.
src/package.cr
Outdated
File.link(source, destination) | ||
{% end %} | ||
rescue Errno : ex | ||
if ex.errno == Errno::EPERM |
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 hurt to try regardless of the error? Stuff like EXDEV
... (extremely unlikely)
Apart from the above incredibly tiny nitpick i'm 👍 to merge. |
OK, the discussion has branched quite a bit since 'executables' was mentioned for the first time. Personally, I think a simple way of installing binaries is of primary importance. Crystal programs, being, by and large, dependency free self contained libraries, are a perfect fit for small command line utilities. Being able to run Is #124 still blocking this? |
Would be nice to get this in for next release. Could help avoid things like rails cli being global in crystal. |
Uses (hard) links on POSIX systems to install the executable, taking care to verify whether the destination isn't already the source (i.e. same inode). On Windows we just copy the file. closes #95
Some filesystems don't support hard links which is reported with the EPERM errno, or we try to link across mounted file systems. These cases are edge cases, but let's avoid errors and merely copy the executable.
ee1dd1f
to
8304e2e
Compare
What's the flow of installing executables specified in # shard.yml
# ...
targets:
foo:
main: src/cli.cr
scripts:
postinstall: shards build --no-debug
executables:
- foo Great to see this merged btw! 🎉 |
Yes, but transitive dependencies will prevent building your executable. See #124. |
BTW: don't use |
Uses (hard) links on POSIX systems to install the executable, taking care to verify whether the destination isn't already the source (i.e. same inode). On Windows we just copy the file. Some filesystems don't support hard links which is reported with the EPERM errno, or we try to link across mounted file systems. These cases are edge cases, but we fallback to copy the executable to avoid errors.
Uses (hard) links on POSIX systems to install the executable, taking care to verify whether the destination isn't already the source (i.e. same inode). On Windows we just copy the file. Some filesystems don't support hard links which is reported with the EPERM errno, or we try to link across mounted file systems. These cases are edge cases, but we fallback to copy the executable to avoid errors.
WIP to implement #95 as per #95 (comment)
blocked by
#123and maybe #124