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

Fix opam install on a local directory not updating pinned packages' metadata #6209

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions master_changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ users)
## Actions

## Install
* Fix `opam install <local_dir>` not updating and storing pinned packages' metadata [#6209 @kit-ty-kate - fix #5567]
* Fix `opam install --deps-only/--show-action <local_dir>` not updating (without storing) pinned packages' metadata [#6209 @kit-ty-kate - fix #5567]

## Build (package)

Expand Down Expand Up @@ -106,6 +108,7 @@ users)

## Reftests
### Tests
* Add a test showing the behaviour of opam install when a local opam file changes while being pinned [#6209 @kit-ty-kate]

### Engine

Expand Down
52 changes: 45 additions & 7 deletions src/client/opamAuxCommands.ml
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ let resolve_locals ?(quiet=false) ?locked ?recurse ?subpath
(OpamUrl.to_string nf.pin.pin_url))
duplicates)

let autopin_aux st ?quiet ?(for_view=false) ?recurse ?subpath ?locked
let autopin_aux st ?quiet ?recurse ?subpath ?locked
atom_or_local_list =
let to_pin, atoms =
resolve_locals ?quiet ?recurse ?subpath ?locked atom_or_local_list
Expand Down Expand Up @@ -303,16 +303,31 @@ let autopin_aux st ?quiet ?(for_view=false) ?recurse ?subpath ?locked
| _ -> false)
| None -> false)
&&
(* For `opam show`, we need to check does the opam file changed to
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It worth adding a test for opam show that highlights that there is no change in the behaviour

perform a simulated pin if so *)
(not for_view ||
Copy link
Collaborator

@rjbou rjbou Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change will trigger a OpamPinCommad.source_pin call that retrieves the whole surce, while what we want here is to update the opam file only.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed in a meeting, we need to have a repin, given the current code

match
(match
OpamSwitchState.opam_opt st pinned_pkg,
OpamFile.OPAM.read_opt nf.pin.pin_file
kit-ty-kate marked this conversation as resolved.
Show resolved Hide resolved
with
| Some opam0, Some opam ->
let opam = OpamFile.OPAM.with_locked_opt nf.pin.pin_locked opam in
OpamFile.OPAM.equal opam0 opam
let opam = OpamFile.OPAM.with_name nf.pin_name opam in
let opam =
match OpamFile.OPAM.version_opt opam with
| None ->
OpamFile.OPAM.with_version
(OpamPinCommand.default_version st nf.pin_name) opam
| Some _ -> opam
in
let opam =
OpamFile.OPAM.with_url
(OpamFile.URL.create ?subpath:nf.pin.pin_subpath nf.pin.pin_url)
opam
in
let opam =
(* This is required to avoid the case where locked opam files were
stored with the added `available: opam-version >= "2.1"` *)
OpamFile.OPAM.with_available (OpamFile.OPAM.available opam0) opam
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It worth adding a comment where these fields are added for the internal stored opam, in order to update this piece of code when it is changed.
I don't know if we can have a test to follow that, keep the consistency between these fields added, and the ones checked here.

in
OpamFile.OPAM.effectively_equal opam0 opam
| _, _ -> false)
with Not_found -> false)
to_pin
Expand Down Expand Up @@ -389,14 +404,37 @@ let simulate_local_pinnings ?quiet ?(for_view=false) st to_pin =
st.switch_global st.switch st.switch_config ~pinned
~opams:local_opams)
);
reinstall = lazy (
let open OpamPackage.Set.Op in
let installed_pinned = st.pinned %% st.installed in
OpamPackage.Set.fold (fun pinned_pkg reinstall ->
match
OpamPackage.Set.find_opt
(fun pkg ->
OpamPackage.Name.equal
(OpamPackage.name pinned_pkg)
(OpamPackage.name pkg))
local_packages
with
| None -> reinstall
| Some local_pkg ->
let old_opam = OpamPackage.Map.find pinned_pkg st.installed_opams in
let new_opam = OpamPackage.Map.find local_pkg local_opams in
if OpamFile.OPAM.effectively_equal old_opam new_opam then
reinstall
else
OpamPackage.Set.add local_pkg
(OpamPackage.Set.remove pinned_pkg reinstall))
installed_pinned (Lazy.force st.reinstall)
);
pinned;
} in
st, local_packages

let simulate_autopin st ?quiet ?(for_view=false) ?locked ?recurse ?subpath
atom_or_local_list =
let atoms, to_pin, obsolete_pins, already_pinned_set =
autopin_aux st ?quiet ~for_view ?recurse ?subpath ?locked atom_or_local_list
autopin_aux st ?quiet ?recurse ?subpath ?locked atom_or_local_list
in
if to_pin = [] then st, atoms else
let st =
Expand Down
3 changes: 0 additions & 3 deletions src/client/opamClient.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2207,9 +2207,6 @@ let install_t t ?ask ?(ignore_conflicts=false) ?(depext_only=false)
in
let pkg_reinstall =
if assume_built then OpamPackage.Set.of_list pkg_skip
else if deps_only then OpamPackage.Set.empty
(* NOTE: As we only install dependency packages, there are no intersections
between t.reinstall and pkg_skip *)
else Lazy.force t.reinstall %% OpamPackage.Set.of_list pkg_skip
in
(* Add the packages to the list of package roots and display a
Expand Down
102 changes: 102 additions & 0 deletions tests/reftests/pin.test
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,105 @@ echo GARBAGE>>"$1"
error 2: File format error: unsupported or missing file format version; should be 2.0 or older
[ERROR] No package named pin-at-future found.
# Return code 5 #
### : Make sure opam install works when the opam file changes and the package is pinned
### opam switch create --empty local-pin-pinned-packages
### <pkg:dependency.1>
kit-ty-kate marked this conversation as resolved.
Show resolved Hide resolved
opam-version: "2.0"
### <pkg:dependency.2>
opam-version: "2.0"
### <pkg:dependency.3>
opam-version: "2.0"
### mkdir pin-change
### git -C pin-change init -q --initial-branch=master
### git -C pin-change config core.autocrlf false
### <pin:pin-change/opam>
opam-version: "2.0"
### git -C pin-change add opam
### git -C pin-change commit -qm first-commit
### ::: behaviour when the package is not pinned
### opam install --deps-only --show ./pin-change
Nothing to do.
### <pin:pin-change/opam>
opam-version: "2.0"
depends: "dependency" {= "1"}
### opam install --deps-only --show ./pin-change
The following actions would be performed:
=== install 1 package
- install dependency 1 [required by pin-change]
### ::: behaviour when the package is pinned
### <pin:pin-change/opam>
opam-version: "2.0"
### opam install ./pin-change
Package pin-change does not exist, create as a NEW package? [y/n] y
pin-change is now pinned to git+file://${BASEDIR}/pin-change#master (version dev)
The following actions will be performed:
=== install 1 package
- install pin-change dev (pinned)

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> retrieved pin-change.dev (git+file://${BASEDIR}/pin-change#master)
-> installed pin-change.dev
Done.
### <pin:pin-change/opam>
opam-version: "2.0"
depends: "dependency" {= "1"}
### ::: behaviour when the package is not pinned
### opam install ./pin-change
pin-change is now pinned to git+file://${BASEDIR}/pin-change#master (version dev)
rjbou marked this conversation as resolved.
Show resolved Hide resolved
[NOTE] Ignoring uncommitted changes in ${BASEDIR}/pin-change (`--working-dir' not specified or specified with no argument).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have a more fine grained handling of pin update (opam file vs source update), we can even remove that note if only the uncommitted opam file is updated, as now we have the information.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as with https://github.com/ocaml/opam/pull/6209/files#r1815454356 i believe. I think those two improvements can be their own tickets to be fixed later.

[pin-change.dev] synchronised (no changes)
The following actions will be performed:
=== recompile 1 package
- recompile pin-change dev (pinned)
=== install 1 package
- install dependency 1 [required by pin-change]

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> installed dependency.1
-> retrieved pin-change.dev (no changes)
-> removed pin-change.dev
-> installed pin-change.dev
Done.
### <pin:pin-change/opam>
opam-version: "2.0"
depends: "dependency" {= "2"}
### opam install --deps-only ./pin-change
[NOTE] Ignoring uncommitted changes in ${BASEDIR}/pin-change (`--working-dir' not specified or specified with no argument).
[pin-change.dev] synchronised (no changes)
The following actions will be performed:
=== recompile 1 package
- recompile pin-change dev (pinned) [uses dependency]
=== upgrade 1 package
- upgrade dependency 1 to 2 [required by pin-change]

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> removed dependency.1
-> installed dependency.2
-> retrieved pin-change.dev (no changes)
-> removed pin-change.dev
-> installed pin-change.dev
Done.
### opam remove pin-change
The following actions will be performed:
=== remove 1 package
- remove pin-change dev (pinned)

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> removed pin-change.dev
Done.
### <pin:pin-change/opam>
opam-version: "2.0"
depends: "dependency" {= "3"}
### opam install --deps-only ./pin-change/opam
[NOTE] Ignoring uncommitted changes in ${BASEDIR}/pin-change (`--working-dir' not specified or specified with no argument).
[pin-change.dev] synchronised (no changes)
The following actions will be performed:
=== upgrade 1 package
- upgrade dependency 2 to 3 [required by pin-change]

<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
-> removed dependency.2
-> installed dependency.3
Done.
### opam pin
pin-change.dev (uninstalled) git git+file://${BASEDIR}/pin-change#master
6 changes: 5 additions & 1 deletion tests/reftests/working-dir.test
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,11 @@ Done.
opam-version: "2.0"
depends: ["qux" {= "1"}]
### opam install ./ongoing --working-dir --show-action
[NOTE] Package ongoing is already installed (current version is dev).
The following actions would be performed:
=== downgrade 1 package
- downgrade qux 4 to 1 [required by ongoing]
=== recompile 1 package
- recompile ongoing dev (pinned)
### opam reinstall ./ongoing --working-dir --show-action

<><> Synchronising pinned packages ><><><><><><><><><><><><><><><><><><><><><><>
Expand Down