-
Notifications
You must be signed in to change notification settings - Fork 518
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
Add --offline option and REBAR_OFFLINE environment variable #2643
Conversation
I don't know that this is actually a good idea or a proper way to make this work. The original post and issue mentions that ideally the offline mode would need to be done via mirroring of hex packages. This, for example, comes with no tests (how does this work and error out on global plugins that have dependencies?), but also does not cover any of the other resources like git dependencies or custom resources that can be plugin-defined, which are fetched entirely differently. I understand this is the simplest way to get the thing you need going, but this sounds like a real tricky and difficult thing to maintain in the future and ensure is working fine in the long run. _checkout dependencies were specifically intended to work on deps locally, not as a feature that should just become a de-facto offline mode and vendoring mechanism. For one, it's really bad at that because it moves the dependencies to be top-level apps and re-analyzes them on every build step, but it also removes entries from lockfiles which can lead to weird unexpected behaviours if an app is published using this feature and a non-offline app requires it. I don't think we should accept this PR moving forwards. Given Rebar3 has to maintain backwards and forwards compatibility for years, this needs to be properly designed, and co-opting unrelated features for a partial (untested) implementation like that is unlikely to reach a mergeable state. |
I wanted to push something forward and see where the discussion leads. I understand that you need to push the breaks. I'd be happy for any clues on a way forward though. Regarding tests, I'd be happy to add some once we know where we're going. I'm trying to keep the two things separate: (1) Use local deps over remote ones and (2) prevent fetching online resources. I hope you agree on the distinction.
|
About the local hex index, it's more about re-packaging the local cache (which is by default in ~/.cache/rebar3, containing tarballs and a copy of the hex index) in another directory (say vendored/) with only the deps required so that we wouldn't hit the network even if we could. This could possibly be done by having a This would also not take care of git dependencies, but I'd prefer a plan going in that direction. It's possible that adding such a feature would require no new resource callbacks (https://rebar3.org/docs/extending/custom_dep_resources/) if that mode changes where we call I don't know if @tsloughter had different ideas, but if you're serious about putting the implementation time into it, we should have a talk. |
The original issue seems to contain a few different use cases. One of them seems to be for calling rebar3 from mix. Our use case is different.
I can try to implement this if you want. Is the idea to create a symlink to "local/path" under "_build/*/" then or would it be tar files from hex to be fetched from the vendored directory instead of being downloaded? What about vendored deps as a dep resource? Since deps are resolved by level-order traversal (breath first), specifying them all as vendored deps in the toplevel rebar.config would override any hex or git sub-dependecies, right? IIUC, the https://github.com/benoitc/rebar3_path_deps plugin already provides this, doesn't it? Example: {deps, [{cowboy, {path, "vendored/cowboy"}},
{cowlib, {path, "vendored/cowlib"}}]}. If this works, it seems much better for our use case. We can't use packages strait from hex or github anyway so I can't see how The remaining problem is to provide vendored deps to the bootstrapping script. |
Yeah the risk of supporting path-based vendoring is figuring out how we handle/error out when you call to a dependency that requires them, and how that bubbles out into the ecosystem. |
I don't see what you mean. If a dependency is missing, I'll get a build error, look at the logs and see some failed attemt to download something (or if we have an offline mode, some others error message). Then I can file a request to get the missing 3rd party dependency approved (or whatever manual verification) and then make another build. Or do you mean version mismatch? It can happen already with nested deps. |
the specific edge case here is to prevent users from doing things like publishing hex packages or even getting to build an app that can't be used as a dep when they publish it on github. It's something we want to capture to help people properly publish apps aimed to be used by other people and to avoid the whole release cycle of "someone publishes an app that doesn't build for anybody else". The sort of question I'm asking is what do we show the user who tries to use a dep that uses vendoring, or what do we tweak as a behaviour so that someone knows their app making use of vendoring isn't going to work for others. The scenario I want to avoid is a case where someone goes "to install this dep, install this other dep somewhere and add this one config" and then everyone down the entire call chain ends up having a separate set of garbage localpath deps that prevent the stack from working otherwise. I'd rather instead give rebar3 the ability to go "this dependency you're declaring depends on a localpath/vendored dependency and is therefore not intended to be used as a dependency", and constrain vendoring to be a top-level, final release concern. |
OK, I understand why path-deps can cause trouble to published apps. We only need vendoring on the top-level anyway, which I think it a good restriction. I think we can drop the path-deps idea. It's not better than checkouts anyway (which works in the meantime for everything except bootstrapping). We also use Go and apparently the dependency and vendoring handling for Go modules works very well for us. I think it can be used as an inspiration. Details: https://golang.org/ref/mod#vendoring. In short:
If we design a vendoring system which is similar, it would mean that |
If rebar3 differentiate between which dependencies (name and version) and where to fetch the dependencies the rebar.config in published packages could have pointers to hex or github for convenient use but it should only be treated as a hint which could easily be overridden with by the user. The user should not need to edit rebar.config from published packages. |
Note that anything can already be overriden with the But also, only We specifically designed packages to not have the repository or org (a feature of hex.pm which is really just a repo, but also sort of note a repo...) declared with the dependency in |
@tsloughter Overrides seems to be "meant to allow quick fixes and workarounds". Also Besides, |
But it is not possible to tell it to look in the local file system. It requires a running server adhering to the hex.pm protocol I assume? |
@zuiderkwast right. Just giving a full landscape and design goals we had. |
Actually, hm. So first, the idea we had, @ferd correct me if I'm wrong, isn't to have a local server running the protocol, but to have a local index which is where the location of the packages is stored. That index does have to adhere to the hex format, but its not a server, it is just saying that the place to store the location of the local file system copy is in an index file. But now that I think about it again I do wonder if the resource type couldn't be "overridden". Right now the You can already supply your own resource providers (there are a number out there, some for vendoring and pointing to the local filesystem) but that requires manually setting the dep to use them because the match for That said... I think the local index is likely the best and possibly even less work since so much is kept from the |
My current ideas for vendoring were:
This is still all sorts of hand-wavy but feels like it's the most simple sort of approach that composes with the rest of features. |
If it is based on setting the hex index to use it should work with global and local plugins. There isn't an app to load/start it is just a configuration setting to point to a specific hex index. |
@potatosalad this feels horribly familiar, how good of an idea it would be to open source your work? (given that we rename "third-party" to ".vendor", or even make it configurable). @ferd one caveat we ran into is how to do the actual vendoring. So far, IIRC, we create We also have hex package index saved in that folder, @potatosalad is the best to explain what's happening there. |
In an EEF meeting ~1 month ago with @ferd, @jhogberg and @KennethL, we concluded that Ericsson's vendoring needs can be fulfilled by putting all deps under |
@ferd (in another PR)
I'm replying here. Yeah, it's a best effort. If we cover what's shipped with rebar3 by default, that's good enough, i.e. hex, git and mercurial. I grepped for "http" and "git" and followed the code backwards. Apart from |
@tsloughter it is unclear to me what you mean with:
By default this syntax of the dependencies means that they are to be fetched from Hex (as I understand it).
For each dep it is then possible to override the location where it is fetched from. The location can be a tar file fetched from github or a local git repo or many other alternatives. Note that these overrides does not should not be part of the export to hex. I don't know if this is kind of already possible with overrides but I can't read that from the documentation. |
I'm not sure if there is an issue of discussing bootstrapping and regular dependencies at the same time. What you describe with the deps example and In case it isn't about bootstrap but about general rebar3 usage then what you describe is basically possibly but not by dropping in a file, it is done by an So if you have a project that depends on say
|
I don't think we've discussed having a global option to use whatever is in the code path first? Meaning the user could just set It is "dangerous" since it won't be verifying anything besides the name and maybe the version, but I guess left up to the user to handle that if they want to tell rebar3 to just use whats on disk. I still prefer a general vendor solution that will populate an ets table registry cache, then write it to disk, that includes only the dependencies of the project (and only the versions used). This file could then even be committed in the repo of the project. |
As @max-au mentioned, we implemented something similar to this within WhatsApp by using a custom We did this by having our plugin "wrap" or override the builtin I should note that this was a "get the job done for now" solution, and a general vendoring solution would be preferred. Similar to what @tsloughter described with an ets cache, we dump the flat file version of the resource into a directory (like By default, our overriding Having an "offline-first" option would be a nice-to-have as part of a Also, as @tsloughter mentioned:
Having some sort of standardized way to vendor dependencies and check for tampering would definitely fit our use-case. My vote would be for something more plain-text-like (similar to |
@tsloughter It seems you're responding to my post in the bootstrap PR: #2642 (comment). It's hard since they're related. What if a project has rebar3 as a dependency? Then it may want to override one of rebar3's deps (e.g. erlware_commons) with another versions or even with a vendored one under |
Good point about plain text. Could be a file of Erlang terms. |
My intention was that the
I then think it is hard to read the documentation and understand that overrides can be used this way.
is overriding what deps Having these type of location overrrides in a special file would assure that a project/package is not exported to hex with local dependencies since the type of resources used as location don't necessarily are supported in the ordinary I think the cruical point is to see the deps as names and versions of the dependencies and the location to fetch them from is just a hint used as default if nothing else is specified by the user. Of course I still want an offline flag which makes rebar3 refuse to fetch anything which is not local or explicitly specified in the separate location overrides. |
@zuiderkwast we shouldn't override the files in the
I think that with these, it'll circumvent most possible attempts to call the outside world, including for git deps or plugin-based fetches. |
If --offline or REBAR_OFFLINE=1 is given, inets is not started and all calls to httpc:request/N are prevented. If any online resource is needed, an error occurs rather than trying to fetch the online resource.
@ferd Done. Is there anything you think I should revert, such as intercepting httpc calls in Should I store the offline flag in |
Yeah storing it in the state would actually speed up a lot of lookups. The httpc adapter currently does not take a state however, though I'm not sure how costly that one would be given everything else that's resource heavy should be covered. I think this looks closer to mergeable, though I'll probably have to take it for a spin rather than just review. |
Heads up, I've gotten the vendoring ready for the experimental provider. Once this is ready to review and merge, I think we can cut 3.19.0. I'll then start moving rebar3 to an umbrella structure where it uses its own vendoring mechanisms and we can close the loop on this whole ordeal. |
@zuiderkwast is this ready to review or still in draft mode for good reason? |
Feel free to review. No tests have been added (yet). I haven't grasped how to set up suitable test cases. Perhaps you can comment what you think we need here. |
I'll probably test it by hand tomorrow and consider that good enough for the bootstrap process at least, then will start seeing what a rebar3 with its own vendor structure looks like and aim for tests on that structure instead. |
That's awesome. (It'd be quite complex to test that rebar3 doesn't connect to a fake Hex server. We'd need to setup a TCP listener and fail the test case if SUT connects to it.) |
New features: - [Add --offline option and REBAR_OFFLINE environment variable](#2643) - [Add support for project-local plugins](#2697) - [Add eunit --test flag](#2684) Experimental features for which we promise no backwards compatibility in the near future: - [Experimental vendoring provider](#2689) - [Support plugins in experimental vendor provider](#2702) Other changes: - [Support OTP 23..25 inclusively](#2706) - [Bump Relx to 4.7.0](#2718) - [Use `erlexec` directly in relx helper functions](erlware/relx#902) - [Make rlx_util:parse_vsn parse integer versions](erlware/relx#913) - [fix awk script check_name() in extended_bin](erlware/relx#915) - [avoid crash when overlay is malformed](erlware/relx#916) - [keep attributes when stripping beams](erlware/relx#906) - [Fix {include_erts,true} in Windows releases](erlware/relx#914) - [ensure the erl file is writable before copying dyn_erl to it](erlware/relx#903) - Various tests added - [Properly carry overlay_vars settings for files in relx](#2711) - [Track mib compilation artifacts](#2709) - [Attempt to find apps in git subdirs (sparse checkouts)](#2687) - [Do not discard parameters --system_libs and --include-erts when duplicate values exist](#2695) - [Use default `depth` parameter for SSL](#2690) - [Fix global cache config overriding](#2683) - [Error out on unknown templates in 'new' command](#2676) - [Fix a typo](#2674) - [Bump certifi to 2.9.0](#2673) - [add a debug message in internal dependency fetching code](#2672) - [Use SPDX id for license in template and test](#2668) - [Use default branch for git and git_subdir resources with no revision](#2663) Signed-off-by: Fred Hebert <[email protected]>
If --offline or REBAR_OFFLINE=1 is given, inets is not started and
all calls to httpc:request/N are prevented. If any online resource
is needed, an error occurs rather than trying to fetch the online
resource.
The purpose is described in #1281 and #2640.
Combined with placing the dependencies in
_checkouts
, I think it makes it possible to build using dependencies provided manually (which is what's required in the scenario that all dependencies need to be separately reviewed and verified legally and security wise). When combined with #2642, even rebar3 itself can be built in this way.