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

Use shards version in crystal init tool #5428

Closed

Conversation

RX14
Copy link
Contributor

@RX14 RX14 commented Dec 21, 2017

Use the shards version command introduced by crystal-lang/shards#148 to populate the VERSION constant inside generated projects with crystal init.

I moved the VERSION constant into the main "example.cr" file, instead of a version.cr file too. I guess that will be a divisive change, but I don't think a seperate version.cr gains us anything.

@Sija
Copy link
Contributor

Sija commented Dec 21, 2017

I'm against merging version.cr into the main module. Keeping it a separate file is IMO cleaner and would be compatible with Ruby convention which does the same (see rails' version.rb). I see no need to clutter main module with declarations having great time in their own company.

@luislavena
Copy link
Contributor

Hello @RX14, thank you for adding this to crystal init. I completely forgot about that feature and sending the PR to use it 🤦‍♂️

I would personally disagree on moving the VERSION constant within the main module code. I believe it adds value beyond the file location itself, but also some orientation in relation to code structure (ie. hey, you can place the files inside src/name/... and will be loaded by require)

Cheers.

@straight-shoota
Copy link
Member

@RX14 could you reduce this PR to using shards version? version.cr has it's pros and cons and should probably be discussed separately.

@Fryguy
Copy link
Contributor

Fryguy commented Dec 21, 2017

One nice thing about the lib/project/version.rb in Ruby is that the version file can be loaded independently of the full library if all you want is the version. This is especially used in many .gemspec files. Not sure that applies to Crystal projects or not.

@RX14
Copy link
Contributor Author

RX14 commented Dec 21, 2017

In my view version.cr is much more cluttered than just adding a line in your main file. Ruby convention has it separate only because the gemspec depends on the version.cr - in Crystal we have it the other way around so we can merge it back in.

Additionally it means we don't enforce an opinion between

src/
├── example.cr
└── example/
    ├── foo.cr
    └── bar.cr

vs

src/
├── example.cr
├── foo.cr
└── bar.cr

@luislavena
Copy link
Contributor

Hello @RX14, thank you for your response.

I think you're basing your opinion in comments like this and this?

(Refs from #2788 and #2690).

If that is the logic that is driving your change, will be great if you can add those details in the commit message, so future developers will be able to find the logic of that decision.

Thank you.

@straight-shoota
Copy link
Member

@Wulfklaue please keep this discussion focused on the PR. You could open a new issue for your comment.
But keep in mind: nobody needs to use crystal init, you can bootstrap a new project easily by hand. It's just a tool to get you started with a set of opinionated defaults.

@RX14 RX14 force-pushed the feature/template-shards-version branch from 97ffdc7 to 66104cf Compare December 24, 2017 16:53
@RX14
Copy link
Contributor Author

RX14 commented Dec 24, 2017

Updated with a new longer commit message.

@straight-shoota
Copy link
Member

@RX14 The sentence We can use it here to automatically generate the version constant for libraries directory from shard.yml, meaning it will never be out of sync. looks a bit off. It seems like something is missing - or libraries directory is just not a great term. The linebreak after We should be removed.

@RX14
Copy link
Contributor Author

RX14 commented Dec 25, 2017

It's a typo: directly instead of directory

@RX14 RX14 force-pushed the feature/template-shards-version branch from 66104cf to 5ad8bdc Compare December 26, 2017 00:05
@RX14
Copy link
Contributor Author

RX14 commented Dec 26, 2017

Fixed typo.

veelenga added a commit to crystal-ameba/ameba that referenced this pull request Dec 26, 2017
veelenga added a commit to crystal-ameba/ameba that referenced this pull request Dec 26, 2017
@RX14 RX14 mentioned this pull request Dec 26, 2017
@RX14 RX14 force-pushed the feature/template-shards-version branch from 5ad8bdc to 8245d94 Compare December 30, 2017 12:44
@RX14
Copy link
Contributor Author

RX14 commented Dec 30, 2017

Rebased to fix travis, hope this can get reviewed.

# TODO: Write documentation for `<%= module_name %>`
module <%= module_name %>
VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }}
Copy link
Member

Choose a reason for hiding this comment

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

You can't just assume that shards is available, let alone in PATH. This defeats the whole point of decentralization. Do you really think Crystal libraries should literally not work if shards is not in PATH?

Copy link
Member

@oprypin oprypin Jan 1, 2018

Choose a reason for hiding this comment

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

In case it wasn't clear, this literally puts the line VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }} into all new projects. It's not a dependency of crystal init, it's a dependency of every library.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not particularly fond of hard dependency on shards either, here it is IMHO justified.
crystal init is perhaps the first real compiler command run by novice developers following a Crystal tutorial. It should have all batteries included and provide an easy way into the Crystal ecosystem which includes shards.
The init command is opinionated but dedicated to provide an easy tool for developers to make them happy. If that doesn't fit with specific needs, don't use it. For the vast majority of users this is probably the best thing. And it's good for the ecosystem if people use shards so it doesn't hurt to advocate it.

Copy link
Member

Choose a reason for hiding this comment

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

In case it wasn't clear, this literally puts the line VERSION = {{ `shards version #{__DIR__}`.chomp.stringify }} into all new projects. It's not a dependency of crystal init, it's a dependency of every library.

Copy link
Member

Choose a reason for hiding this comment

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

I know, this is a considerable downside. Maybe a better long-term solution would be to include a simple parser for shards.yml in the standard library (maybe even directly as a macro method). I've already suggested that idea in #4754 to provide metadata about the project for the docs generator. This way it wouldn't depend on the executable but read shards.yml directly.

@straight-shoota
Copy link
Member

@RX14 With example/version.cr removed it is questionable if the require "./example/*" should stay in example.cr, considering it advocates against a flat file structure.

@asterite
Copy link
Member

asterite commented Jan 2, 2018

I initially thought that this meant shards version would be executed once for each shard, but this is only true if the VERSION constant is actually referred and used in code, because of the laziness of constants. That laziness might disappear one day, though.

That said, I don't know how much time it takes to run, say, 100 or 200 of those shell commands (we should profile this). Maybe it's negligible.

I personally don't think keeping the version in shards.yml and VERSION such a hard task. So I have mixed feelings regarding this change.

@RX14
Copy link
Contributor Author

RX14 commented Jan 2, 2018

@asterite this is a macro, surely the constant laziness doesn't apply here? (only runtime)

Personally, I've thought about this some more and I think VERSION constants actually aren't that useful. I've never used a VERSION constant in somebody else's library, though I can see how it's useful.

I think a much better system to provide would be to provide shards get-version shard_name. That way, applications that actually need the version of a shard can retrieve it using macros, but that burden is on the user of the version information, not the provider.

Another option is just to generate by default a spec similar to this one.

@straight-shoota
Copy link
Member

I like the idea of simply having a spec for the version. Essentially, it moves reading shard.yml from every build to only on (full) spec suite runs.

@asterite
Copy link
Member

asterite commented Jan 2, 2018

@RX14 What I mean with constant laziness is that the value of constants aren't typed unless used. Try this:

ONE = 1 + 'a'
TWO = {{ 1 + 'a' }}

it compiles. It's only when you refer to those constants in code that you'll get an error.

@RX14
Copy link
Contributor Author

RX14 commented Jan 2, 2018

@asterite I wouldn't have thought that that worked with macros, I would have assumed that TWO = {{ 1 + 'a' }} would be a top-level macro exactly equivalent to

{% begin %}
  TWO = {{ 1 + 'a' }}
{% end %}

I thought macros are always done in a pass before we even know which constants are used, so they'd just be evaluated all the time. I understand that 1 + 'a' won't be typed and will never fail, but wouldn't have thought that macro evaulation behaved the same way.

Appears i'm incorrect.

`shards version` is a new shards command which finds a `shard.yml` in the
directory tree above the path given and returns the version specified in it. We
can use it here to automatically generate the version constant for libraries
directly from shard.yml, meaning it will never be out of sync.

The `VERSION` constant is also moved into the main library file, instead of
being placed in a separate `version.cr`. The old `version.cr` convention
persisted from ruby due to the need for gemspec files to require only the
version constant from the library.
@RX14 RX14 force-pushed the feature/template-shards-version branch from 8245d94 to 8fbe24f Compare January 5, 2018 17:04
@RX14
Copy link
Contributor Author

RX14 commented Jan 5, 2018

Rebased onto master to fix merge conflict.

Anything left to do here if this doesn't pose a performance impact?

@oprypin
Copy link
Member

oprypin commented Jan 5, 2018

Relying on subprocesses at compile time is bad.
Relying on external executables is bad.
Relying on PATH is horrible.
Putting this monstrosity in every library's code is a pandora's box.

@straight-shoota
Copy link
Member

Yeah I think we should rather keep it as is for now instead of introducing a feature into potentially many libraries that might prove to pose more trouble than anything.

I think it would be more feasible if the compiler would read the data directly from the shard.yml but should not rely on shards CLI being available in PATH.

But I like the idea of removing the extra file for the version constant.

@straight-shoota
Copy link
Member

straight-shoota commented Dec 10, 2018

Can't we just use a makeshift "YAML parser" like this?

File.read_lines("#{__DIR__}/../shard.yml").find(&.starts_with?("version:")).try &.byte_slice(8).partition('#')[0].delete(%("')).strip

Maybe put in a method Crystal.shards_version with some additional logic to correctly resolve shard.yml path relative to calling file.

@j8r
Copy link
Contributor

j8r commented Dec 10, 2018

I'll vote to close: as said in my comment, moving crystal init to the existing shards init will prevent us from a mess resulting from a mutual dependence of crystal <=> shards

@straight-shoota
Copy link
Member

@j8r that's a different path and probably a good idea, but both changes are not mutually exclusive. It doesn't make a difference if the file is created by crystal init or shards init, extracting the version from shard.yml (on every compilation) shouldn't depend on the shards command anyway.

@j8r j8r mentioned this pull request Jan 3, 2019
@jhass
Copy link
Member

jhass commented Jun 11, 2019

It seems this got stalled on a dispute on whether we should make all new projects generated with crystal init depend on the shards command being available.

While one could argue that's already the case as soon as you add a single dependency, I can see the point. Given this doesn't seem to really fix a pain point as evidenced by the lack of discussion and voting on this and no issues referencing this, I'll close this for now.

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

Successfully merging this pull request may close these issues.

None yet

9 participants