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

Project-local package dirs with precedence #131

Closed
ozra opened this issue May 27, 2015 · 59 comments · Fixed by #834
Closed

Project-local package dirs with precedence #131

ozra opened this issue May 27, 2015 · 59 comments · Fixed by #834

Comments

@ozra
Copy link
Contributor

ozra commented May 27, 2015

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.

@josephwecker
Copy link

Copying a discussion from another thread here where it belongs:


josephwecker:

BTW- my comment glossed over nimble's package versioning. Aside from that though it does allow for nimble in the future (if desired) to optionally install packages local to a project and just have everything work as usual. It'soff-topic but it has been extremely useful to me in just about every language I've used- js, ruby (rails especially), c, erlang, ...


dom96:

@josephwecker In what way is that useful?


josephwecker:

@dom96 I don't want to hijack this thread- so warning: somewhat offtopic from this issue.

And it is a minority case compared to the semi-global package cache as nimble correctly implemented, but generally it is useful as a more clear & abrupt separation of a projects personal space vs shared space; an extension of the reason nimble probably uses ~/.nimble/... instead of /opt/nimble or /usr/include/nimble.

There are various deployment / replication / compiler-farm / multi-project-editing-workflows / debug scenarios where it's very useful to have all or some of the dependent packages that the package manager acquired right there in the main project's subdirectories- neither affecting nor being affected by anything else on that machine. npm, rebar (for erlang-OTP), and rails are the ones I've actively used in the past that come to mind right away that have the ability to optionally install local to the project. In C I've done essentially the same thing in order to experiment with different stdlib "overrides" for super-high-availability zero-copy servers back at twitch.tv etc.


josephwecker:

@dom96 similarly- Ruby, perl, and to a lesser degree python have rvm/perlbrew/virtualenv for allowing any project to have its own version of the VM/compiler as well as its own "package space"/gemset/etc. separate from the shared one...

@dom96
Copy link
Collaborator

dom96 commented Jun 4, 2015

I think the current way to develop (dependency) packages is good enough (TM).

Clone the dependency repo. Work on it. Then run nimble install in its directory. Switch to your project and test it.

@ozra
Copy link
Contributor Author

ozra commented Jun 4, 2015

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?

@dom96
Copy link
Collaborator

dom96 commented Jun 4, 2015

If you don't want it to overwrite the older non-dev version then you will need to bump the version.

@cdunn2001
Copy link
Contributor

I think the current way to develop (dependency) packages is good enough (TM).

But could be better. Let's make it better.

@ozra and @josephwecker, the new --nimbledir flag is a step in the right direction, but I don't want to have to type that every time I run nimble in a particular workspace directory. (A "workspace" may contain multiple git directories.) My idea is for nimble to search for the nimble.ini first in the current directory (and maybe in the parent) which would then serve to define a workspace. If not found, then it could look in $AppDir/nimble/.

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 GOPATH might be the way to go, rather than a configuration file.

@dom96
Copy link
Collaborator

dom96 commented Jun 5, 2015

So, in addition to --global (still to be implemented, install to /usr/lib/nimble, or somewhere more appropriate) and --local (default, install to ~/.nimble), you want to also have --project (install to $PWD/.nimble, or something like that)?

That's something I would be willing to implement, as it plays nicely with and will create a beautiful trifecta of --global, --local and --project.

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?

@dom96 dom96 added the RFC label Jun 5, 2015
@cdunn2001
Copy link
Contributor

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 nimble.ini file makes sense, to over-ride the global one in ~. That's how many tools work, including git itself. Or an environment variable could define the workspace, which is basically how GOPATH works. However, command-line flags are almost equivalent to environment variables since I can use an alias within a given shell:

alias nimble=\nimble --nimbledir=/my/local/workspace/path

I can use different shells for different workspaces. That's good enough for me. So I guess --nimbledir works for me after all.

I don't know anything about --local/--global... I guess that comes from #80. Well, I think those flags are confusing when --nimbledir exists. Do they over-ride it? Do they only alter a default? If so, what happens when I specify both? It's confusing. In UNIX, most installers rely on --prefix, which might be /usr by default. For local installs, people always specify the local prefix. I guess you don't want to type --nimbledir=~/.nimble all the time. So how about this:

  • If --nimbledir is provided, use that always.
  • If not, then look for any parent directory called .nimble. If found, use that.
  • Otherwise, use the global system default.

However, I prefer this simpler logic:

  • If --nimbledir is specified, use it always.
  • Otherwise, use ~/.nimble.

I don't see a value in --global. Explicit is better.

@cdunn2001
Copy link
Contributor

Oh, I see. In #80, some people want nimble packages to come from multiple installations, particularly including the system root, /usr/lib/nim or whatever. I'll comment there.

@dom96
Copy link
Collaborator

dom96 commented Jun 7, 2015

I would prefer not to have Nimble search any parent directories. I think that searching for a directory called .nimble will only create confusion.

--global will act like an alias for --nimbledir:/usr/lib/nimble, if the user specifies a --nimbledir then the global will be overriden.

@ozra
Copy link
Contributor Author

ozra commented Jun 9, 2015

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 nimble install still work, and thus cause the problem I mentioned, or does that too require to be 'in the right dir', yes?]

@dom96
Copy link
Collaborator

dom96 commented Jun 9, 2015

I suppose I have the same question for you as I asked here: #80 (comment)

What happens if I have the same package (of two different versions) in my GOPATH? How does Go resolve which one it is that I want?

i.e. how can Nimble disambiguate the local package vs. the system package?

@cdunn2001
Copy link
Contributor

@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 nimble install in ~/workspace/foo, it goes into ~/.nimble/.... That's counter-intuitive. ~/.nimble has source-code already. It should use only the repos in its own sub-dirs.

With GOPATH, a workspace contains:

GOPATH=/home/user/gocode

/home/user/gocode/
    src/
        foo/
            bar/               (go code in package bar)
                x.go
            quux/              (go code in package main)
                y.go
    bin/
        quux                   (installed command)
    pkg/
        linux_amd64/
            foo/
                bar.a          (installed package object)

The repositories are in src/. When it builds any given package, it builds into bin/ and pkg/. If something is needed from the web, goget will pull into src/ and then build into bin/ and pkg/OS/PKG. That's simple. It's very easy to understand what came from where.

If you want to remove a repo, then remove it manually. Nimble does not need to clone into /tmp/. Repos are way smaller than binaries.

@dom96
Copy link
Collaborator

dom96 commented Jun 9, 2015

@cdunn2001 In your example, isn't /home/user/gocode equivalent to /home/user/.nimble?

@cdunn2001
Copy link
Contributor

It would be equivalent if the repos are in ~/.nimble/src/mypkg/.git, e.g.

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.

@dom96
Copy link
Collaborator

dom96 commented Jun 9, 2015

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!

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 NIMBLE_DIR/src.

@ozra
Copy link
Contributor Author

ozra commented Jun 9, 2015

If there could be some way to flag to nimble that a repo is locally deved - and so get a warning on nim install without bumping version (that is, nimsuggests sees that an existing package will be installed over, and then it warns when it knows I'm doing install from local repo.

How could this best be solved?

@cdunn2001
Copy link
Contributor

But if I have checked out the repo into 2 places, they will each install into ~/.nimble, right? That's what we do not want. I need multiple workspaces.

@dom96
Copy link
Collaborator

dom96 commented Jun 10, 2015

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?

@cdunn2001
Copy link
Contributor

What do you mean by "installation"? go build installs into the workspace.

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?

@dom96
Copy link
Collaborator

dom96 commented Jun 10, 2015

Nimble already does that. It doesn't pull dependencies into your workspace but into ~/.nimble.

@cdunn2001
Copy link
Contributor

That is the problem! It over-writes the contents of ~/.nimble. I want to bounce between workspaces. My day might go like this:

  • Update a nim package. Build and test, integrated into a larger system. Let that run for a while. Do not modify it in the meantime.
  • Oops. Bug report came in. Create a new workspace for that bug. Fix and submit changes for code-review.
  • Get some basic work done. Use the stuff in ~/.nimble. Leave a long-running task running. Do not alter the ~/.nimble directory.
  • In the meantime, switch to a different set of nim packages. Build and test them.
  • Return to first set of packages. Oh, I see another crash. Fortunately, I can debug it because nothing has changed there.
  • I see responses on the code-review. Return to that workspace and alter that code based on those comments.

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.

@ozra
Copy link
Contributor Author

ozra commented Jun 11, 2015

That describes a not to uncommon scenario! Which is the same reason I want the "sand boxing"..
In my case 'workspaces' are just local git repos, they're all "re-synchronized" via my github origin, after these parallel dev situations.

@bluenote10
Copy link
Contributor

@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 --noNimblePath the default and in order to build against a certain version of a package the build tool has to bring in the appropriate path. If ProjectA needs LibX in version 0.1, ProjectB needs git hash 4e73f8 of LibX, while ProjectC needs a local modification of LibX -- no problem, you just declare these dependencies in their respective project build definitions. Running nimble build would take care of everything by assembling the build path in each case individually ("installing" a package if necessary). With global package installations / build paths such a scenario quickly becomes a mess. Switching between various nimbledirs is an ugly work-around since there is still "global state" (Example: Why is my build failing? Oh wait, I probably have to switch to another of my 7 nimbledirs...). There is a reason why most other build tools avoid this.

@cdunn2001
Copy link
Contributor

@bluenote10, Great discussion at that link.

@Jehan says:

The problem with "nimble build" is that currently it has a hardcoded -d:release and no way to pass options other than through a config file.

@dom96 says:

I have actually recently tried Cargo myself and was surprised by just how similar it is to Nimble.

Yes, nimble build is like cargo, and it's not bad. But I need to build A, B, and C, where:

  • A depends on B and C
  • B depends on C
  • I own A, and I am modifying A locally.
  • B and C are in the nim-lang nimble registry. (Or whatever it's called.)
  • I am modifying B locally.

See the problem? I'm not sure Cargo handles this either. gobuild handles it easily.

@bluenote says:

The "global" install of nimble is a non-issue. Nimble stores the packages in ~/.nimble/pkgs/_. If a project depends on a specific package version (could even be a git hash!) which does not yet exist, nimble will just create a new "global" copy.

"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:

@bluenote I definitely like where you are going with these ideas. I think, with a bit of planning and research, we could really make something!

Using Nim to build Nim is an interesting idea, per @Araq's comments. But that all distracts from the need for workspaces.

@Jehan
Copy link

Jehan commented Jun 12, 2015

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)
Just saying, since I received an automatic email and was wondering what this discussion I could not remember at al was about. ;-)

@bluenote10
Copy link
Contributor

"Non-issue"? That is not true!

@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:

deps += "B @ 0.1.2"
deps += "C @ 0.8"

Since the version specifier is a plain version string, running build now would pull the respective versions from the remote repositories (build path would contain e.g. ~/.nimble/pkgs/B_0.1.2/). If you want to use a local version of B in A, you can modify A's build definition to:

deps += "B @ /path/to/modification"
deps += "C @ 0.8"

The build tool now could follow the rule: If the version specifier is a local path, use the package from the local path. Running build now would not add any version from ~/.nimble/pkgs/B_*/ but just /path/to/modification to the build path.

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.

@cdunn2001
Copy link
Contributor

Sorry, Jehan! I hope you can unwatch this somehow. Or maybe dom can remove you from the list in the sidebar.

@yglukhov
Copy link
Member

👍 And a vote for some sort of lockfile. E.g. like ruby gemfile.lock does.

@dom96
Copy link
Collaborator

dom96 commented Jun 14, 2015

I see. Yes, Nimble is very similar to Cabal. But have you heard the phrase "Cabal hell"? And have you ever used "Cabal sandboxes"?

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

[...]

Scenario

Where both B and C depend on A. However, if they were installed at different times, they may depend on different versions of A. For example, A version 1 export type T = Int, but in version 2 it exports type T = Bool.

Only when you try to build D do you expose the problem that B and C were build against different >versions of A, and you can't compare T version 1 against T version 2.

The key difference here is that Cabal will build each installed package (including libraries), whereas Nimble will not.

As long as B and C do not depend on a specific version of A then Nimble will use the latest version of A it can find when building D.


Golang does it right. Very little else does.

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"

@dom96
Copy link
Collaborator

dom96 commented Jun 14, 2015

@yglukhov #127

@cdunn2001
Copy link
Contributor

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:

As long as B and C do not depend on a specific version of A then Nimble will use the latest version of A it can find when building D.

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.

I'm starting to consider allowing file paths in dependency lists.

:-) That seems like a very good idea to me.

But I need workspaces first. And workspaces are trivial.

@ozra
Copy link
Contributor Author

ozra commented Jun 14, 2015

@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, nimble ... --local ..

@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.
It will now automatically be used when building. When I'm satisfied, and don't need to co-develop the modules tightly, I can simply remove it when commited, done and published.
Now it goes back to automatically using the 'global' nimble cache.

I know I'm repeating some things said earlier by different parts, just trying to converge..

@dom96
Copy link
Collaborator

dom96 commented Jun 14, 2015

@ozra What about my idea to support filesystem paths in dependency lists? It's more flexible IMO.


:-) That seems like a very good idea to me.

@cdunn2001 hrm, so you still want workspaces. Wouldn't filesystem path support in dependency lists be enough?

@ozra
Copy link
Contributor Author

ozra commented Jun 14, 2015

@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!
Personally, I'd prefer symlinking from the .nimble/ dir to a certain path, rather than enter it in the conf.

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?

@dom96
Copy link
Collaborator

dom96 commented Jun 14, 2015

I clone everything into ~/git, so it makes more sense for me to add file://~/git/jester to my .nimble file than to copy the git repository to (or symlink it in) $CWD/.nimble.

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.

@ozra
Copy link
Contributor Author

ozra commented Jun 14, 2015

@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.
I would find it very helpful simply put. So what would be the downside of implementing it in nimble? (I could possibly make time to do it, if it's the effort)
(Opting out is as simple as not having a local .nimble-dir)

@dom96
Copy link
Collaborator

dom96 commented Jun 14, 2015

Are you talking about implementing workspaces or file paths in dependency lists?

@cdunn2001
Copy link
Contributor

@dom96 wrote:

@cdunn2001 hrm, so you still want workspaces. Wouldn't filesystem path support in dependency lists be enough?

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:

you seem to miss the point that semver allows specifying a version range that will cause no problems

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.

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.

nimble --nimbledir would suffice, but it's unreliable. I would have to set an alias, and then I have to worry about sub-shells not using my alias. It needs to be either an environment variable or something in the filesystem itself.

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.

@ozra
Copy link
Contributor Author

ozra commented Jun 14, 2015

@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?
Regarding the versioning, for your example, if 3.4 is minimum, a roof should be added too: "< 4". In reality though, if 3.4 is already out, and you enter "mod @ 3", you will get 3.4 or later, but not past major 3. Since nimble don't fetch older versions unless specifically asked for. So the '> 3.4' is not semver idiomatic.
Best practises for utilizing semver should be clearly and simply put in the manual. It doesn't take more than a few sentences to explain. And you still don't have to use it.

@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?

@cdunn2001
Copy link
Contributor

in "$CWD/.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.

@ozra
Copy link
Contributor Author

ozra commented Jun 14, 2015

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/".
If all packages used are in local nimb dir, they are all 'vendored' so to speak (if I got the term right). You maintain full control of pulling any version you want, local modifications, etc.

So, yeah, I still feel the possible local .nimble/ dir is more or less a must have.
I see no downsides to implementing it at all - for those who do not use it.

@cdunn2001
Copy link
Contributor

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:

@shaunc
Copy link

shaunc commented Feb 5, 2016

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.

@dom96
Copy link
Collaborator

dom96 commented Nov 7, 2016

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.

@cdunn2001
Copy link
Contributor

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.

@matt2000
Copy link

matt2000 commented Jan 28, 2017

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.

@dom96
Copy link
Collaborator

dom96 commented Jan 28, 2017

@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?

@genotrance
Copy link
Contributor

I'm tracking the proposal for this feature here. Appreciate all feedback to help finalize the design.

@FedericoCeratto FedericoCeratto changed the title Project-local package dirs with precedance Project-local package dirs with precedence Nov 4, 2019
@genotrance
Copy link
Contributor

I have a working PR #834 for this that implements the proposal from November last year. Looking for feedback.

Effectively, mkdir nimbledeps is all that's needed for nimble to know to use local deps mode. So:

git clone repo
cd repo
mkdir nimbledeps

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 nimbledeps so this is restricted to nimble at this time. Supporting local deps mode with Nim will be done by generating a nim.cfg in the future. That design is in the works and will be developed once this issue is resolved.

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

Successfully merging a pull request may close this issue.

10 participants