diff --git a/Project.toml b/Project.toml index 3d0edeb..805aca6 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "LocalRegistry" uuid = "89398ba2-070a-4b16-a995-9893c55d93cf" authors = ["Gunnar Farnebäck "] -version = "0.5.6" +version = "0.5.7" [deps] Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/docs/register.md b/docs/register.md index d58a8bb..9bbc231 100644 --- a/docs/register.md +++ b/docs/register.md @@ -7,7 +7,7 @@ The full set of arguments to `register` is ``` register(package = nothing; registry, commit, push, repo, ignore_reregistration, - gitconfig, create_gitlab_mr) + allow_package_dirty, gitconfig, create_gitlab_mr) ``` although in many cases a no-argument `register()` call is sufficient. @@ -42,8 +42,8 @@ Notes: start Julia with the `--project` flag. * The package must be stored as a git working copy, e.g. having been - cloned with `Pkg.develop`, and must not contain un-committed - changes. + cloned with `Pkg.develop`, and must not contain un-committed changes + (but also see the `allow_package_dirty` keyword argument). * The package must have a `Project.toml` or `JuliaProject.toml` file. This must include `name`, `uuid`, and `version` fields. @@ -121,6 +121,21 @@ informational message. **Note: The default will likely be changed to `true` in a future update.** +`allow_package_dirty::Bool`: + +LocalRegistry only registers what has been committed to the +package's repository, by nature of how Julia registries work. If the +package has local modifications which have not been committed, there +is a disconnect between the files on disk and what gets registered. By +default this gives an error but if you understand the consequences you +can override it by setting `allow_package_dirty` to `true` instead of +the default `false`. + +An exception is if `Project.toml` (or `JuliaProject.toml` if +that is used) itself is dirty. This still gives an error, because +critical information like the version number is read from disk, and +could be different to what is in the project file being registered. + `git_config::Dict{<:AbstractString, <:AbstractString}`: Optional configuration parameters for the `git` command. For diff --git a/src/LocalRegistry.jl b/src/LocalRegistry.jl index bd41cf0..3454bea 100644 --- a/src/LocalRegistry.jl +++ b/src/LocalRegistry.jl @@ -164,8 +164,9 @@ will be used to perform the registration. In this case `push` must be *Keyword arguments* register(package; registry = nothing, commit = true, push = true, - branch = nothing, repo = nothing, ignore_reregistration = false, allow_package_dirty = false, - gitconfig = Dict(), create_gitlab_mr = false) + branch = nothing, repo = nothing, ignore_reregistration = false, + allow_package_dirty = false, gitconfig = Dict(), + create_gitlab_mr = false) * `registry`: Name, path, or URL of registry. * `commit`: If `false`, only make the changes to the registry but do not commit. Additionally the registry is allowed to be dirty in the `false` case. @@ -173,7 +174,7 @@ will be used to perform the registration. In this case `push` must be * `branch`: Branch name to use for the registration. * `repo`: Specify the package repository explicitly. Otherwise looked up as the `git remote` of the package the first time it is registered. * `ignore_reregistration`: If `true`, do not raise an error if a version has already been registered (with different content), only an informational message. Defaults to `false` but may be changed to `true` in the future. -* `allow_package_dirty`: If `true`, do not raise an error if the package directory is dirty, only show an informational message. Defaults to `false`. +* `allow_package_dirty`: If `true`, do not raise an error if the package directory is dirty, unless the Project file itself is dirty. Instead show an informational message. Defaults to `false`. * `gitconfig`: Optional configuration parameters for the `git` command. * `create_gitlab_mr`: If `true` sends git push options to create a GitLab merge request. Requires `commit` and `push` to be true. """ @@ -189,15 +190,18 @@ end # and true if something new was registered. function do_register(package, registry; commit = true, push = true, branch = nothing, - repo = nothing, ignore_reregistration = false, allow_package_dirty = false, - gitconfig::Dict = Dict(), create_gitlab_mr = false) + repo = nothing, ignore_reregistration = false, + allow_package_dirty = false, gitconfig::Dict = Dict(), + create_gitlab_mr = false) # Find and read the `Project.toml` for the package. First look for # the alternative `JuliaProject.toml`. package_path = find_package_path(package) local pkg + local project_file_name for project_file in Base.project_names pkg = Project(joinpath(package_path, project_file)) if !isnothing(pkg.name) + project_file_name = project_file break end end @@ -215,12 +219,25 @@ function do_register(package, registry; error("$(package) is not a valid package (no src/$(pkg_filename))") end - # If the package directory is dirty, a different version could be - # present in Project.toml. + # If the package directory is dirty, what is committed to git + # would be registered rather than what is in the files. + # + # Especially problematic is if Project.toml is dirty, when it + # could be a mismatch between e.g. the version we read from the + # file on disk and what gets registered with the committed + # file. This gives an error also when allow_package_dirty is + # enabled. if is_dirty(package_path, gitconfig) - !allow_package_dirty ? - error("Package directory is dirty. Stash or commit files.") : + if allow_package_dirty && !is_dirty(package_path, gitconfig, + project_file_name) @info "Note: package directory is dirty." + else + if allow_package_dirty + error("$(project_file_name) is dirty. Stash or commit it.") + else + error("Package directory is dirty. Stash or commit files.") + end + end end registry_path = find_registry_path(registry, pkg) @@ -358,11 +375,11 @@ end # This does the same thing as `LibGit2.isdirty(LibGit2.GitRepo(path))` # but also works when `path` is a subdirectory of a git # repository. Only dirt within the subdirectory is considered. -function is_dirty(path, gitconfig) +function is_dirty(path, gitconfig, relative_path = ".") git = gitcmd(path, gitconfig) # TODO: There should be no need for the `-u` option but without it # a bogus diff is reported in the tests. - return !isempty(read(`$git diff-index -u HEAD -- .`)) + return !isempty(read(`$git diff-index -u HEAD -- $(relative_path)`)) end # If the package is omitted, diff --git a/test/register.jl b/test/register.jl index 5340632..9c42bd6 100644 --- a/test/register.jl +++ b/test/register.jl @@ -161,12 +161,34 @@ with_empty_registry() do registry_dir, packages_dir registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false) + + # Error can be overridden with allow_package_dirty... register(joinpath(packages_dir, "Flux"), registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false, allow_package_dirty = true) @test isfile(joinpath(registry_dir, "F", "Flux", "Package.toml")) + + # ...but not if Project.toml is dirty. + project = joinpath(packages_dir, "Flux", "Project.toml") + write(project, replace(read(project, String), "0.8.3" => "0.8.4")) + @test_throws ErrorException register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false, + allow_package_dirty = true) + + if VERSION >= v"1.8" + # Check that we get the expected source of error. + @test_throws "Project.toml is dirty" begin + register(joinpath(packages_dir, "Flux"), + registry = registry_dir, + gitconfig = TEST_GITCONFIG, + push = false, + allow_package_dirty = true) + end + end end # Dirty the registry repository and try to register a package.