-
Notifications
You must be signed in to change notification settings - Fork 190
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
Project-local package dirs with precedence #131
Comments
Copying a discussion from another thread here where it belongs: josephwecker:
dom96:
josephwecker:
josephwecker:
|
I think the current way to develop (dependency) packages is good enough (TM). Clone the dependency repo. Work on it. Then run |
Ah, yes. Is there anyway of setting a "temporary" version / dev-version or something then - so it doesn't shadow the "legit" version of it? (The sandboxing we so dearly want) So, if working on dep "foo" of version "0.4.7" - I don't wanna do the version bumping - it's up to upstream, but I don't want it to shadow foo@0.4.7, so I want my changes at foo@0.4.8 (patch-version +1), but without affecting the source... What do you thing, some idea? |
If you don't want it to overwrite the older non-dev version then you will need to bump the version. |
But could be better. Let's make it better. @ozra and @josephwecker, the new This is pretty easy to do. The first step is this change, which was rejected. It's worth reconsidering. For now, I'll experiment with my temporary fork, but I will continue to hope that it can eventually be merged back into nimble. I'm very tired and maybe not thinking clearly enough. Has anybody else used Go? I think its build-system is impressively flexible. We can borrow ideas from there. An environment variable like |
So, in addition to That's something I would be willing to implement, as it plays nicely with and will create a beautiful trifecta of I still feel like I don't understand the advantage this brings. Do you want to have multiple copies of the same git repository on your system, updating each separately as-needed, developing the copy that you want to test via some other package? |
Yes, multiple copies of git-repos. These are separate workspaces. I don't want to litter my "normal" Nim installation with any WIP. I also think a local
I can use different shells for different workspaces. That's good enough for me. So I guess I don't know anything about
However, I prefer this simpler logic:
I don't see a value in |
Oh, I see. In #80, some people want nimble packages to come from multiple installations, particularly including the system root, |
I would prefer not to have Nimble search any parent directories. I think that searching for a directory called
|
I prefer command line flags over PATH. But I'd really prefer the local .nimble conf. That way "nimble install" wouldn't accidentally overwrite system wide version if I'm tired and do the wrong thing (which incidentally does happen from time to time). This way deps stay stable system wide, while the WPC version is sandboxed and only "installed" project locally. It makes sense. It could require it to be in cwd (aka, calling nimble when in src/ dir won't work - no parent searching..) [ed: - would this make |
I suppose I have the same question for you as I asked here: #80 (comment)
i.e. how can Nimble disambiguate the local package vs. the system package? |
@dom96, Let's establish how to deal with multiple, unrelated workspaces first. The issue of precedence is better discussed in #80, in relation to system installations. (With Go, only standard packages are in GOROOT. If you want to edit them, you kinda need to check-out the entire Go compiler. I think that's fine.) @ozra, A local nimble-conf file is an interesting solution for telling nimble where to install. However, if it contains absolute paths, then it cannot be in the repository. Also, if it doesn't look at parent directories, why not simply install in the CWD? I think this really gets at the fundamental problem with today's nimble. It's way too complicated (in different ways than we need). If I run With GOPATH, a workspace contains:
The repositories are in If you want to remove a repo, then remove it manually. Nimble does not need to clone into |
@cdunn2001 In your example, isn't |
It would be equivalent if the repos are in If the package is checked out in NIMBLE_DIR/src, then I don't want nimble to examine packages.json from the web. Use my repositories whenever possible! And I want nimble to infer the NIMBLE_DIR if I run from a sub-dir of a valid NIMBLE_DIR. |
If I understand you correctly then that is what Nimble already does (as long as the package that you're building doesn't depend on a newer package than is available in |
If there could be some way to flag to nimble that a repo is locally deved - and so get a warning on How could this best be solved? |
But if I have checked out the repo into 2 places, they will each install into |
I'm assuming you want to avoid installation since it's not required in Go (you just add the repo to your $GOPATH). So isn't this something to implement in the Nim compiler then? |
What do you mean by "installation"? I want to build this package and all dependencies in my workspace, automatically pulling from the web whatever is missing. Isn't that what nimble is supposed to do? |
Nimble already does that. It doesn't pull dependencies into your workspace but into |
That is the problem! It over-writes the contents of
I'm not sure that explains it well enough, but maybe you can get some idea of the complexity of my work. I need the filesystem to help me keep track of various ongoing tasks. Please tell nimble to use the current workspace unless explicitly told otherwise. Please add the concept of a workspace. It's needed. |
That describes a not to uncommon scenario! Which is the same reason I want the "sand boxing".. |
@cdunn2001 What you describe was pretty much my motivation to suggest this. In my opinion the cleanest solution is to move away from installing and switching packages altogether -- also because these are low level primitives. In general, package installation should not be a "global state". What I have proposed is the Maven/SBT/Ivy/Cargo-like solution: I would make |
@bluenote10, Great discussion at that link. @Jehan says:
@dom96 says:
Yes,
See the problem? I'm not sure Cargo handles this either. gobuild handles it easily. @bluenote says:
"Non-issue"? That is not true! Diamond-dependencies make that system an absolute nightmare! An installation needs precisely one contour of packages, or nobody will have any idea what's going on. @Varriount says:
Using Nim to build Nim is an interesting idea, per @Araq's comments. But that all distracts from the need for workspaces. |
Hello, I think you have me mixed up with someone else. I think this is another "Jehan" in this forum you linked (or else I have big memory holes! :p) |
@cdunn2001 I fully agree, what I was trying to say was: It is mainly an issue because it is "in scope" by default. I currently don't see the issue if the build tool assembles the build path individually. Let's consider the following fictitious syntax in your example. Project A's build definition before edit:
Since the version specifier is a plain version string, running
The build tool now could follow the rule: If the version specifier is a local path, use the package from the local path. Running Wouldn't such a behavior solve your issue? Or are you referring to the problem of conflicting transitive dependencies (e.g. B depends on "C @ 0.9")? This is obviously a much more difficult problem. |
Sorry, Jehan! I hope you can unwatch this somehow. Or maybe dom can remove you from the list in the sidebar. |
👍 And a vote for some sort of lockfile. E.g. like ruby gemfile.lock does. |
Yes, I am familiar with Cabal hell. I think that Nimble is just different enough to not suffer from Cabal's hellish problems. For example, in the scenario described here: http://stackoverflow.com/a/25870174/492186
The key difference here is that Cabal will build each installed package (including libraries), whereas Nimble will not. As long as
I'm not so sure. I have read plenty of complaints about Go's lack of sophistication with package management. From @bluenote10's quote, the 19 other tools seems excessive already and shows that people are not happy. @ozra If I understand you correctly then number 3 is already done. Number 1 & 2 I can do. Number 4 I'm still not convinced of. I'm starting to consider allowing file paths in dependency lists: [Deps]
Requires: "file:///home/dom/myprojects/jester" |
Everyone seems to be missing my point: Workspaces are more important than versioning. There will never be 100% agreement on how to do versioning, so decouple it. Go uses a 2-step process. That is a very, very good idea. @bluenote10, "Cabal hell" refers to diamond dependencies, which is a result of explicit versioning. At my last company (a major IT firm), the original designers of the build system added versioning everywhere. Later, that was deprecated because it made updates impractical. Versioning is an enticing idea, but ultimately what you really need are tests. You should be willing to substitute in any version as long as your tests pass. Once they pass, you need to lock down the contour of commits. Forking is one way to do that. ("Go itself recommends to 'vendor' packages, i.e., copy all dependencies to the project itself." Yes. That is forking, not explicit versioning.) Another way is to store the contour in a separate system, specific to your project. (I have an example at https://github.com/pb-cdunn/FALCON-modules, and I'm happy to explain what I've done there.) A lockfile is another way. But you need to distinguish "versioning" (where a package identifies its own version) from "hash-tagging" (where the version is implicit, equivalent to a copy). Those are different things. @dom96 says:
Good! But I'm saying it should generally work that way. As soon as people name specific versions, they will prevent others from updating diamon-dependency A, which is bad. They is why we need to let people use their own systems for versioning. We need to decouple package-dependencies from version-dependencies.
:-) That seems like a very good idea to me. But I need workspaces first. And workspaces are trivial. |
@cdunn2001 - you seem to miss the point that semver allows specifying a version range that will cause no problems, while still allowing all upgrades that stay within the limits of the semantics. This is not a specific version, but a specific range of "level" of allowed changes. (Only non-breaking changes for instance). This complements tests. And you can simply ignore using the versioning if you want. (Thereby allowing breaking change updates of modules, and if you're tests are exhaustive and you trust them, the breaking changes might be outside of your use case, etc.) I find this very important, and it's just a matter of declaring this officially, it is like coding style conventions, but for versioning, it's a matter of trust on the module contributors to follow the official recommendation, so it's no implementation cost. Your need for workspaces first might not be the same for everyone else. But I must admit I'm not sure if I understand your workspace notion completely: I don't see a case I couldn't solve with the local ".nimble/" dir, or if must, specifying it with paths in the proj nimble conf (more unnecessary work imo). @cdunn2001: What is it that you can't solve with those simple constructs? To narrow your use case down a little, so we all can converge a bit on the matter. There's of course one additional, helpful feature for the local packages: 5. With a command line option, nimble could help in installing a dependency in the local dir, @dom96: Regarding 4 - the pro of the local dir (apart from 5 above), is that one does not have to change the conf. If for a while I need to tightly develop a dependency with my using app/module, I can simply git clone it, or symlink to it (if machine local), or use 5 above to get it into my local '.nimble/' dir in the project. I know I'm repeating some things said earlier by different parts, just trying to converge.. |
@ozra What about my idea to support filesystem paths in dependency lists? It's more flexible IMO.
@cdunn2001 hrm, so you still want workspaces. Wouldn't filesystem path support in dependency lists be enough? |
@dom96 - it's just the simple fact that the placing in .nimble/ makes the intention clear. Having to edit/un-edit it in the file is an extra step. That said, I think the paths idea is great as a complement! But I would survive with the path thing. Is there a specific reason you're uncertain of the idea of first looking for, and in, a "{cwd}/.nimble/" dir before searching the global? |
I clone everything into I think that this would be a more flexible solution, and just as convenient. Unless I am mistaken once again about the use case that you guys have for workspaces. |
@dom96 I have quite a bit longer paths, and structure things different from that, so there will be more typing, but that's not so much of an issue. |
Are you talking about implementing workspaces or file paths in dependency lists? |
@dom96 wrote:
It's useful in its own right, but it doesn't address my use-case. I want two overlapping contours of different package trees in my filesystem simultaneously. (Do you understand what I mean by "contour"? It's my word for a specific set of SHA1s for a specific set of repositories.) If these trees are kuldged into the same directory (~/.nimble), then we have the diamond-dependency problem, and it's unresolvable because I am actually using different SHA1s for this parallel development. @ozra wrote:
I know what you're saying. I thought the same thing when I got to Amazon. But Cary Hall, a Principal at Amazon, set me straight. It is not easy to see the problem caused by versioning, and version ranges have even more subtle problems. For one thing, it doesn't scale. (Your system must handle many thousands of packages.) For another, people will tend to say "> 3.4", but what about 4.0? That's bigger, but a major-version-bump means all bets are off. It's better to use software from people who try very, very hard to maintain backward-compatibility (as we do for jsoncpp), and to test as much as you can. Aside from major version numbers, semantic versioning should be a hint for the human integration-manager, but not a contract for the automated package-manager.
Besides, part of the problem I'm explaining is the difficulty of knowing what goes with what when everything is shoved into a single nimble-dir. In a workspace, there is only one version of any piece of software. When you examine the directory, you know exactly what you've got. |
@cdunn2001 - so I still don't see how fully local copies of the deps (in "$CWD/.nimble/") would not suffice? Then it is essentially your workspace? What am I missing? @dom96 - I will repose my question, since I didn't get an answer, if you don't mind: What would be the downside of implementing a "cwd nimble-dir check first" in Nimble? |
Yes, that would be a workspace. That's fine, as long as I can continue to commit and push in repos in either $CWD or in $CWD/.nimble/packages, or whatever. |
Right, that was the idea: for package/app A, requiring B and C: if package B is in "A/.nimble/B/" - (it may simply be a git repo. local, symlinked, what not) - "nimble build" will see it and use it in build, but C is not there, so that is used from "~/.nimble/". So, yeah, I still feel the possible local .nimble/ dir is more or less a must have. |
Here is a nice discussion which mentions Python, Go, and Ruby, all of which have gone through several iterations of package-management. It's worth reading: |
fwiw ... as a nim newbie, having developed in at least half a dozen language ecosystems over the years, npm is by far my favorite package manager: workspaced is the way to go, falling back on "local" (user) and global locations if not installed locally. Semver is good but should be optional. For one thing you are at the mercy of someone else doing it right. As a consultant, I often have libraries lie fallow for years, and come back to them when I have a related project. Having everything local in the workspace is brilliant: it will still work no matter what has happened outside (well, modulo changes in the language itself or the os, etc...). Non-workspace-based package management should be seen as an optimization. EDIT: Another way to see this: when you decide to use a package in a project, you want to decide just that: "should I use (the current version) of package X in project Y?". Semver lets you specify parameters on what future version you are prepared to accept; (accepting future versions means you trust the package developer). Making your choice implicitly affect your other projects is a memory leak. |
Some discussion about vendoring in Go in this post: https://hackernoon.com/gos-alias-proposal-and-all-my-concerns-of-google-controlling-go-a39f6c6046aa#.shw6iaqgc Looks like the implication is that it was a bad idea. |
Good blogpost. It mentions an idea for Go interfaces which is simply not a problem in Nim. Go-vendoring is meant to ameliorate the problem of storing a copy of an external library within your project, but I don't think it's a very helpful solution. The vendored package is still difficult to update with revision-control. I would prefer relative imports, plus a solution to the interface problem in the link above. |
I heaven't read the whole thread, but it makes me sad that this seems to have not progress in almost a year. TLDR; I fully Agree with SeanC above. Please, please, please don't make the mistake of python & PHP & Java & R and end up having to redo packaging several ways over the years. They all started with Global level dependencies and came to realize they were wrong or forked communities. Get it right from the start like Node/npm. Global level dependencies are a constant headache in a sufficiently complex ecosystem, doubly so in a microservices environment. Project-level is the only reasonable thing to do in a world where disk space is so cheap as to be a non-issue. |
@matt2000 I still don't think I get the issues that we will run into if we use a global workspace. Can you shed some light on this? |
I'm tracking the proposal for this feature here. Appreciate all feedback to help finalize the design. |
I have a working PR #834 for this that implements the proposal from November last year. Looking for feedback. Effectively,
After that, all nimble commands will use the local directory for dependencies and avoid all use of any other nimble locations. Note that Nim is not aware of |
Having worked a couple of years with iojs for the money, I really enjoyed the modularity of projects vs the C++ world.
I've already had several problems with Nim, while hacking the compiler etc. that ~./.nimble/.. pkgs and global nim stdlibs are preferred over the ones from the dir I'm working in.
This is mostly a nim mod-lookup issue, and partly nimble.
Basically a project-local mod deps dir - like "node_modules/" in iojs/nodejs - it should have precedance. Also, those package dirs, should easily be pure github checkouts, for deving on deps, hand in hand with a project.
This way version matched packages can be stored per project - they could still be cached in home-dir/nimble. I'd prefer 'proj-local' pkgs as default. But an option would be ok, "nimble install local..."
#114 (comment)
nim-lang/Nim#2819 (comment)
nim-lang/Nim#2819 (comment)
As for the module lookup, I guess that's in nim's domain.
The text was updated successfully, but these errors were encountered: