-
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
Locking of dependencies #127
Comments
Sounds like you finally want to use db_sqlite in Nimble. :P |
How does db_sqlite help in any way? |
I might be interested in working on this functionality. Here are a couple of thoughts in no particular order:
Do all these seem reasonable or am I wildly off the mark of how you would like this project to work? |
I must admit I haven't done much research into how other package managers do it yet, so I can't say much about how I think the implementation should be done. In regards to your last point, I do think that it might be a good idea to have an explicit |
But in general I think you're on the right track and I agree with your points. |
Regarding general research / information about other languages' package management, here's a great read: |
@aidansteele, lockfile would be really great!
Also as dom96 said, lockfile creation should not be bound to |
Yes, being able to override the path would be extremely useful. Ruby's bundler allows you to specify just the name (in which case it looks up in the central repository), a git repo (in which case it uses master), a git branch or specific SHA, or a local path. It would be good to support all of these options. @yglukhov Do you have an example of how you use nake? I'm still becoming familiar with Nim and would like to see what does / doesn't work well with the standard tools. |
@aidansteele, here's how I use nake currently. nakefile example: https://github.com/yglukhov/nimx/blob/master/nakefile.nim It imports naketools: Naketools basically defines a builder that knows how to build targets for different platforms, like current, js, android, ios, emscripten, etc. Creates bundles for ios and macos, codesigns, converts/packs resources, compiles SDL for selected target if necessary, and even launches a jester server to run JS or emscripten version. Also it's pretty configurable through command line, eg.
|
Some short insight into how Cargo handles this here: https://www.reddit.com/r/programming/comments/7q6ida/jai_libraries_discussion/dsnu9zc/ Another note: Cargo supports building software that depends on multiple versions of the same package: https://www.reddit.com/r/programming/comments/7q6ida/jai_libraries_discussion/dsnu6ls/ |
Our team is willing to impelement the following spec for Lock files if the Nimble project agrees to adopt it. Lock file contentsThe lock file uses the TOML format and includes an array of records with the following fields:
In other words, here is an example lock file:
The lock file will include all transitive dependencies of the project. New low-level operations
|
I implemented "lock files" 2 years ago for nawabs, here is the code https://github.com/Araq/nawabs/blob/master/recipes.nim#L52 I doubt it will be of much help since nawabs' internals are quite different from Nimble's, but I too generate Nim(script) code so it might provide some inspiration. |
Sounds mostly good, although I think your plan can be simplified.
You're implying that you want the lock files to be a valid nimscript file which IMO is a mistake. We want lock files to be parsed quickly and booting up the Nim VM is very slow, I also don't see any reason why the lock files shouldn't just be a flat data store. As such I think we should settle on a common format like ini, toml (what cargo uses), json or similar. If you really want this semi-nim syntax then that's okay with me, but we need to specify it accurately before implementation. In fact, I would like to see a spec even if we use json or similar.
In Nimble's world there already is a definition of what "develop mode" implies: a package which was linked into ~/.nimble/pkgs via a
I think creating a lock file whenever any compilation is performed is a good solution. This means Although, I just thought of something we need to consider: tests should probably have a separate lock file since there often is a need for different dependencies when testing. But we can worry about this later I think.
I think that our implementation of this could be much simpler for a first stab at this. We don't need to have this fancy detection of whether the lock file was updated or whether the .nimble file dependencies were. Just merge the deps in the lock file with the deps in the .nimble file every time and we can think about optimising it later, this shouldn't be too much of a bottleneck anyway since we're only doing this for the top-level package (as none of the transitive dependency's lock files are taken into account) |
a procedural approach to lock files seems strange
this looks like an anti-feature. versions are specified in the nimble file and follow a social contract - the purpose of a lock file is to take that socially agreed information and create a reproducible, secure and deterministic build out of it, where no outside action can affect it at all (without giving the developer an opportunity to explicitly review what has changed). You create a lock file explicitly when you don't want things to change. Neither a version nor a package name has any reasonable security properties - if time and code is spent on supporting this feature, it's only a matter of time before nimble will have its nodejs/npm moment and a high-profile package gets hijacked trivially like this (in the nodejs world, it sparked a separate pm to be developed.. everyone else, including
a secure hash solves all the problem above, and to keep it flexible one should make sure it's specified in a future-compatible way with other schemes than git (so we could have a number of supported and secure ways.. git sha1 for git repos, shaX-of-tarball for getting code from a tarball instead of git, some other hash for mercurial repos etc). Using versions is a really deprecated way of doing things, akin to sending plaint-text passwords over internet. Consider here that lock files typically get committed to git and stick around for years - I want to be able to securely reproduce my build 1, 2, 5 years after the fact as well, and this is not a problem you can fix retroactively after a breach - as a tool developer, you have to think about this for your users before they run into this issue. As far as security goes, this model is usually referred to as TOFU - it's not the most secure one out there, but you'll find it in places that value convenience over security (ssh, whatsapp etc).
If it's automated, it's no longer really useful as a lock file, for the above reasons - it should be called something else at that point to manage expectations and not provide a false sense of security - a dependency resolution cache or something similarly ephemeral, so it's clear it's just an optimization and ultimately garbage that can be safely removed at the tiny cost of a minimally increased build time. That said, I'd envision that an explicit create/update-lockfile command would make more sense in line with the TOFU model above - that's what I actually want as a developer, to make sure the rug is not pulled from under my feet, but also to have the convenience of a tool interpreting the social information that version numbers give (ideally slightly structured, like semver). I build much more often than I want my dependencies to be updated (unless I've chosen for a particular, tightly coupled project, to follow deps closely - but then it's also likely I want to use a monorepo, and relative-path dependencies without further versioning)
something like this could be useful regardless of lock files. I see 3 components here - a dependency resolver (for solving version constraints), an (optional?) lock file (for solving security, determinism, all that) and a cache for doing diffs since the last build. that said, it's also the least worry here, it seems.. if you already resolved version numbers to a hash, and have something that says that the code matches it (like git, or a directory name with the hash in it, for a tarball), it's usually really fast anyway for a dozen deps, so instead of having a global
with a lock file and path overrides, it looks like this feature can be deprecated / removed completely - it's a really odd feature that's tied to the current approach where global state affects local builds causing lots of problems, meaning that you can't run two projects or branches with different settings side-by-side. |
OK, I've incorporated feedback from here and other sources into the proposal above. The format of the lock file has been changed to TOML. |
There has been some heated debate regarding what is the most appropriate time to produce the lock file. I think this decision can be safely delayed until the low-level operations described above are fully implemented. I've now added few more notes clarifying what conditions will prevent updating the lock file and which packages are considered to be in "develop mode". Please note that the behavior of the |
Very good point which I totally missed. Totally agree.
👍
I think we'll need to discuss this separately, or perhaps we should discuss this here since we need to figure out how to handle local file paths in lock files. Any thoughts?
I know I've mentioned it in my list but if we are going to use something like that then IMO a better option is just .ini. The primary reason is that we've got a parser for it in the stdlib already. |
I would pick JSON as lockfiles are not for direct editing by humans and JSON has the most tooling available. Nim's .ini parser is non-standard (well back then there was no standard). |
I'm okay with JSON too. For reference, npm's lock files are also JSON. We could basically copy their format: https://docs.npmjs.com/files/package-lock.json |
The names of the "nimbledata.json" file and "pkgs" directory are changed correspondingly to "nimbledata2.json" and "pkgs2" in order to avoid the need of removing the Nimble cache when changing between the new and old Nimble versions. Related to nim-lang#127
In the Nimble packages list exists a package without description field which causes the tests to fail while executing the "list" command. In order to resolve the problem make the description field optional. Related to nim-lang#127
The part of the documentation about handling of transitive package dependencies was no longer correct since commit dfeed75. Now it is updated to describe the new behavior. Related to nim-lang#127
The field `checksum` in installation `ConfigData` is renamed to `pkgChecksum` and it is being set when parsing an installation `ini` file. Related to nim-lang/nimble#127
The field `checksum` in installation `ConfigData` is renamed to `nimblePkgChecksum` and it is being set when parsing an installation `ini` file. Related to nim-lang/nimble#127
Special versions are made a set of versions. Those are aliases with which a single package can be referred. For example, a package can be simultaneously versions: * 0.1.0 - the normal version from the Nimble file. * #head - the latest commit in the main branch * #master - the main branch name * 3c91b869 - part of the sha1 hash of the latest commit in the main branch When the same package is downloaded a second time (determined by the checksum) instead of proposing to replace it just print a warning that the package is already installed and merge the special version of the new package with a special version of the already installed one. Additionally this commit: - Removes some legacy code for supporting the old package format in the reverse dependencies. - The names of the packages in the reverse dependencies are written without converting to lower case. - The tests are fixed according to the new behavior. Related to nim-lang#127
Make `develop --with-dependencies` to skip already existing directories when cloning the repositories. This is useful when a second `develop --with-dependencies` is executed for another package and some of the dependencies are the same as in the first run. In that case, we don't want the entire command to fail because some package directories already exist. Related to nim-lang#127
Related to nim-lang#127
In the `toRevDep` procedure directly use the `basicInfo` tuple without constructing a new tuple from its fields. Related to nim-lang#127
When trying to execute `tar` to determine whether it is available catch an `OSError` raised when the path to the `tar` is invalid. Related to nim-lang#127
The parallel package downloads are removed, because the `asynctools` library for asynchronous processes, that is used is not production-ready. It has several hard-to-find bugs causing а crashing of Nimble. First, they must be fixed before using it. Related to nim-lang#127
Downloading of Nimble packages as tarballs when working with GitHub is now disabled by default. The option `--no-tarballs` for disabling it is removed and a new option `--tarballs` for explicitly enabling the feature is added instead. Related to nim-lang#127
Pass the requested branch to the `git` or `hg` command instead of the "branch" word. Related to nim-lang#127
Sometimes when downloading a package some symbolic links files cannot be open on Windows when Nimble is run as administrator. For this reason, add exception handling to the `open` procedure to avoid the crash and display a warning message that the file content will not be count in the calculation of the package's checksum. Related to nim-lang#127
When a file is a symbolic link to some other file the proper behavior when calculating the checksum of a package is to use the link path instead of the content of the pointed file. Additionally the `getPackageFileListWithoutVcs` procedure is fixed to return also the symbolic link files. Related to nim-lang#127
When cloning a Git repository on Windows Git puts the link file path as the content of an ordinary file. When downloading tarball the symbolic link files cannot be properly established and Tar writes empty files instead. This leads to different packages checksums compared to the case when the package is downloaded via Git or downloaded on Linux either via Git or via tarball. To fix the problem we parsed the content of the tarball and extract the link paths from there. After that, we write a link file with the link path in it overriding the empty file extracted by Tar. Additionally, the `getPackageFileListWithoutVcs` procedure is fixed to return relative paths to files with `/` character as directory separator even on Windows, because they are used in the package checksum calculation and we must have the same checksum for the same package regardless of the operating system or download method. Related to nim-lang#127
Related to nim-lang#127
The names of the "nimbledata.json" file and "pkgs" directory are changed correspondingly to "nimbledata2.json" and "pkgs2" in order to avoid the need of removing the Nimble cache when changing between the new and old Nimble versions. Related to nim-lang#127
In the Nimble packages list exists a package without description field which causes the tests to fail while executing the "list" command. In order to resolve the problem make the description field optional. Related to nim-lang#127
Implemented support for Nimble local cache with package directories with a checksum of the package at the end of their names. Now the compiler supports package paths in the form: * /path_to_nimble_cache_dir/pkgs/package_name-1.2.3- FEBADEAEA2345E777F0F6F8433F7F0A52EDD5D1B * /path_to_nimble_cache_dir/pkgs/package_name-#head- 042D4BE2B90ED0672E717D71850ABDB0A2D19CD2 * /path_to_nimble_cache_dir/pkgs/package_name-#branch-name- DBC1F902CB79946E990E38AF51F0BAD36ACFABD9 Related to nim-lang/nimble#127
Lock files have been delivered several months ago with #913. EDIT: Above, I meant Nimble 0.14 instead of 1.4, as pointed out in the comments below. |
Just to be clear: Nimble v0.14 not v1.4 |
it's as yet unreleased, you'd have to grab HEAD. Might be time to release it, but it is quite a major release so it would be nice if some of the community tested it before it's officially released. |
sat was made the default in pr nim-lang#127
When you build your package a nimble.lock file should be created.
This nimble.lock file should contain some metadata about the package as well as the dependencies which your package has been built with.
The text was updated successfully, but these errors were encountered: